summaryrefslogtreecommitdiff
path: root/gcc/builtins.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/builtins.c')
-rw-r--r--gcc/builtins.c291
1 files changed, 135 insertions, 156 deletions
diff --git a/gcc/builtins.c b/gcc/builtins.c
index 31969ca3e53..d79372cf268 100644
--- a/gcc/builtins.c
+++ b/gcc/builtins.c
@@ -119,7 +119,6 @@ static rtx expand_builtin_next_arg (void);
static rtx expand_builtin_va_start (tree);
static rtx expand_builtin_va_end (tree);
static rtx expand_builtin_va_copy (tree);
-static rtx expand_builtin_memcmp (tree, rtx, machine_mode);
static rtx expand_builtin_strcmp (tree, rtx);
static rtx expand_builtin_strncmp (tree, rtx, machine_mode);
static rtx builtin_memcpy_read_str (void *, HOST_WIDE_INT, machine_mode);
@@ -314,10 +313,9 @@ get_object_alignment_2 (tree exp, unsigned int *alignp,
/* The alignment of a CONST_DECL is determined by its initializer. */
exp = DECL_INITIAL (exp);
align = TYPE_ALIGN (TREE_TYPE (exp));
-#ifdef CONSTANT_ALIGNMENT
if (CONSTANT_CLASS_P (exp))
align = (unsigned) CONSTANT_ALIGNMENT (exp, align);
-#endif
+
known_alignment = true;
}
else if (DECL_P (exp))
@@ -393,10 +391,9 @@ get_object_alignment_2 (tree exp, unsigned int *alignp,
/* STRING_CST are the only constant objects we allow to be not
wrapped inside a CONST_DECL. */
align = TYPE_ALIGN (TREE_TYPE (exp));
-#ifdef CONSTANT_ALIGNMENT
if (CONSTANT_CLASS_P (exp))
align = (unsigned) CONSTANT_ALIGNMENT (exp, align);
-#endif
+
known_alignment = true;
}
@@ -1689,9 +1686,7 @@ expand_builtin_apply (rtx function, rtx arguments, rtx argsize)
emit_call_insn (targetm.gen_untyped_call (mem, result,
result_vector (1, result)));
}
- else
-#ifdef HAVE_call_value
- if (HAVE_call_value)
+ else if (targetm.have_call_value ())
{
rtx valreg = 0;
@@ -1702,19 +1697,18 @@ expand_builtin_apply (rtx function, rtx arguments, rtx argsize)
for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
if ((mode = apply_result_mode[regno]) != VOIDmode)
{
- gcc_assert (!valreg); /* HAVE_untyped_call required. */
+ gcc_assert (!valreg); /* have_untyped_call required. */
valreg = gen_rtx_REG (mode, regno);
}
- emit_call_insn (GEN_CALL_VALUE (valreg,
- gen_rtx_MEM (FUNCTION_MODE, function),
- const0_rtx, NULL_RTX, const0_rtx));
+ emit_insn (targetm.gen_call_value (valreg,
+ gen_rtx_MEM (FUNCTION_MODE, function),
+ const0_rtx, NULL_RTX, const0_rtx));
emit_move_insn (adjust_address (result, GET_MODE (valreg), 0), valreg);
}
else
-#endif
gcc_unreachable ();
/* Find the CALL insn we just emitted, and attach the register usage
@@ -3440,11 +3434,6 @@ expand_builtin_mempcpy_args (tree dest, tree src, tree len,
}
}
-#ifndef HAVE_movstr
-# define HAVE_movstr 0
-# define CODE_FOR_movstr CODE_FOR_nothing
-#endif
-
/* Expand into a movstr instruction, if one is available. Return NULL_RTX if
we failed, the caller should emit a normal call, otherwise try to
get the result in TARGET, if convenient. If ENDP is 0 return the
@@ -3459,7 +3448,7 @@ expand_movstr (tree dest, tree src, rtx target, int endp)
rtx dest_mem;
rtx src_mem;
- if (!HAVE_movstr)
+ if (!targetm.have_movstr ())
return NULL_RTX;
dest_mem = get_memory_rtx (dest, NULL);
@@ -3473,7 +3462,7 @@ expand_movstr (tree dest, tree src, rtx target, int endp)
create_output_operand (&ops[0], endp ? target : NULL_RTX, Pmode);
create_fixed_operand (&ops[1], dest_mem);
create_fixed_operand (&ops[2], src_mem);
- if (!maybe_expand_insn (CODE_FOR_movstr, 3, ops))
+ if (!maybe_expand_insn (targetm.code_for_movstr, 3, ops))
return NULL_RTX;
if (endp && target != const0_rtx)
@@ -3924,17 +3913,61 @@ expand_builtin_bzero (tree exp)
const0_rtx, VOIDmode, exp);
}
+/* Try to expand cmpstr operation ICODE with the given operands.
+ Return the result rtx on success, otherwise return null. */
+
+static rtx
+expand_cmpstr (insn_code icode, rtx target, rtx arg1_rtx, rtx arg2_rtx,
+ HOST_WIDE_INT align)
+{
+ machine_mode insn_mode = insn_data[icode].operand[0].mode;
+
+ if (target && (!REG_P (target) || HARD_REGISTER_P (target)))
+ target = NULL_RTX;
+
+ struct expand_operand ops[4];
+ create_output_operand (&ops[0], target, insn_mode);
+ create_fixed_operand (&ops[1], arg1_rtx);
+ create_fixed_operand (&ops[2], arg2_rtx);
+ create_integer_operand (&ops[3], align);
+ if (maybe_expand_insn (icode, 4, ops))
+ return ops[0].value;
+ return NULL_RTX;
+}
+
+/* Try to expand cmpstrn or cmpmem operation ICODE with the given operands.
+ ARG3_TYPE is the type of ARG3_RTX. Return the result rtx on success,
+ otherwise return null. */
+
+static rtx
+expand_cmpstrn_or_cmpmem (insn_code icode, rtx target, rtx arg1_rtx,
+ rtx arg2_rtx, tree arg3_type, rtx arg3_rtx,
+ HOST_WIDE_INT align)
+{
+ machine_mode insn_mode = insn_data[icode].operand[0].mode;
+
+ if (target && (!REG_P (target) || HARD_REGISTER_P (target)))
+ target = NULL_RTX;
+
+ struct expand_operand ops[5];
+ create_output_operand (&ops[0], target, insn_mode);
+ create_fixed_operand (&ops[1], arg1_rtx);
+ create_fixed_operand (&ops[2], arg2_rtx);
+ create_convert_operand_from (&ops[3], arg3_rtx, TYPE_MODE (arg3_type),
+ TYPE_UNSIGNED (arg3_type));
+ create_integer_operand (&ops[4], align);
+ if (maybe_expand_insn (icode, 5, ops))
+ return ops[0].value;
+ return NULL_RTX;
+}
+
/* Expand expression EXP, which is a call to the memcmp built-in function.
Return NULL_RTX if we failed and the caller should emit a normal call,
- otherwise try to get the result in TARGET, if convenient (and in mode
- MODE, if that's convenient). */
+ otherwise try to get the result in TARGET, if convenient. */
static rtx
-expand_builtin_memcmp (tree exp, ATTRIBUTE_UNUSED rtx target,
- ATTRIBUTE_UNUSED machine_mode mode)
+expand_builtin_memcmp (tree exp, rtx target)
{
- location_t loc ATTRIBUTE_UNUSED = EXPR_LOCATION (exp);
-
if (!validate_arglist (exp,
POINTER_TYPE, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE))
return NULL_RTX;
@@ -3942,78 +3975,66 @@ expand_builtin_memcmp (tree exp, ATTRIBUTE_UNUSED rtx target,
/* Note: The cmpstrnsi pattern, if it exists, is not suitable for
implementing memcmp because it will stop if it encounters two
zero bytes. */
-#if defined HAVE_cmpmemsi
- {
- rtx arg1_rtx, arg2_rtx, arg3_rtx;
- rtx result;
- rtx insn;
- tree arg1 = CALL_EXPR_ARG (exp, 0);
- tree arg2 = CALL_EXPR_ARG (exp, 1);
- tree len = CALL_EXPR_ARG (exp, 2);
+ insn_code icode = direct_optab_handler (cmpmem_optab, SImode);
+ if (icode == CODE_FOR_nothing)
+ return NULL_RTX;
- unsigned int arg1_align = get_pointer_alignment (arg1) / BITS_PER_UNIT;
- unsigned int arg2_align = get_pointer_alignment (arg2) / BITS_PER_UNIT;
- machine_mode insn_mode;
+ tree arg1 = CALL_EXPR_ARG (exp, 0);
+ tree arg2 = CALL_EXPR_ARG (exp, 1);
+ tree len = CALL_EXPR_ARG (exp, 2);
- if (HAVE_cmpmemsi)
- insn_mode = insn_data[(int) CODE_FOR_cmpmemsi].operand[0].mode;
- else
- return NULL_RTX;
+ unsigned int arg1_align = get_pointer_alignment (arg1) / BITS_PER_UNIT;
+ unsigned int arg2_align = get_pointer_alignment (arg2) / BITS_PER_UNIT;
- /* If we don't have POINTER_TYPE, call the function. */
- if (arg1_align == 0 || arg2_align == 0)
- return NULL_RTX;
+ /* If we don't have POINTER_TYPE, call the function. */
+ if (arg1_align == 0 || arg2_align == 0)
+ return NULL_RTX;
- /* Make a place to write the result of the instruction. */
- result = target;
- if (! (result != 0
- && REG_P (result) && GET_MODE (result) == insn_mode
- && REGNO (result) >= FIRST_PSEUDO_REGISTER))
- result = gen_reg_rtx (insn_mode);
+ machine_mode mode = TYPE_MODE (TREE_TYPE (exp));
+ location_t loc = EXPR_LOCATION (exp);
+ rtx arg1_rtx = get_memory_rtx (arg1, len);
+ rtx arg2_rtx = get_memory_rtx (arg2, len);
+ rtx arg3_rtx = expand_normal (fold_convert_loc (loc, sizetype, len));
- arg1_rtx = get_memory_rtx (arg1, len);
- arg2_rtx = get_memory_rtx (arg2, len);
- arg3_rtx = expand_normal (fold_convert_loc (loc, sizetype, len));
+ /* Set MEM_SIZE as appropriate. */
+ if (CONST_INT_P (arg3_rtx))
+ {
+ set_mem_size (arg1_rtx, INTVAL (arg3_rtx));
+ set_mem_size (arg2_rtx, INTVAL (arg3_rtx));
+ }
- /* Set MEM_SIZE as appropriate. */
- if (CONST_INT_P (arg3_rtx))
- {
- set_mem_size (arg1_rtx, INTVAL (arg3_rtx));
- set_mem_size (arg2_rtx, INTVAL (arg3_rtx));
- }
+ rtx result = expand_cmpstrn_or_cmpmem (icode, target, arg1_rtx, arg2_rtx,
+ TREE_TYPE (len), arg3_rtx,
+ MIN (arg1_align, arg2_align));
+ if (result)
+ {
+ /* Return the value in the proper mode for this function. */
+ if (GET_MODE (result) == mode)
+ return result;
- if (HAVE_cmpmemsi)
- insn = gen_cmpmemsi (result, arg1_rtx, arg2_rtx, arg3_rtx,
- GEN_INT (MIN (arg1_align, arg2_align)));
- else
- gcc_unreachable ();
+ if (target != 0)
+ {
+ convert_move (target, result, 0);
+ return target;
+ }
- if (insn)
- emit_insn (insn);
- else
- emit_library_call_value (memcmp_libfunc, result, LCT_PURE,
- TYPE_MODE (integer_type_node), 3,
- XEXP (arg1_rtx, 0), Pmode,
- XEXP (arg2_rtx, 0), Pmode,
- convert_to_mode (TYPE_MODE (sizetype), arg3_rtx,
- TYPE_UNSIGNED (sizetype)),
- TYPE_MODE (sizetype));
-
- /* Return the value in the proper mode for this function. */
- mode = TYPE_MODE (TREE_TYPE (exp));
- if (GET_MODE (result) == mode)
- return result;
- else if (target != 0)
- {
- convert_move (target, result, 0);
- return target;
- }
- else
return convert_to_mode (mode, result, 0);
- }
-#endif /* HAVE_cmpmemsi. */
+ }
- return NULL_RTX;
+ result = target;
+ if (! (result != 0
+ && REG_P (result) && GET_MODE (result) == mode
+ && REGNO (result) >= FIRST_PSEUDO_REGISTER))
+ result = gen_reg_rtx (mode);
+
+ emit_library_call_value (memcmp_libfunc, result, LCT_PURE,
+ TYPE_MODE (integer_type_node), 3,
+ XEXP (arg1_rtx, 0), Pmode,
+ XEXP (arg2_rtx, 0), Pmode,
+ convert_to_mode (TYPE_MODE (sizetype), arg3_rtx,
+ TYPE_UNSIGNED (sizetype)),
+ TYPE_MODE (sizetype));
+ return result;
}
/* Expand expression EXP, which is a call to the strcmp builtin. Return NULL_RTX
@@ -4026,15 +4047,15 @@ expand_builtin_strcmp (tree exp, ATTRIBUTE_UNUSED rtx target)
if (!validate_arglist (exp, POINTER_TYPE, POINTER_TYPE, VOID_TYPE))
return NULL_RTX;
-#if defined HAVE_cmpstrsi || defined HAVE_cmpstrnsi
- if (direct_optab_handler (cmpstr_optab, SImode) != CODE_FOR_nothing
- || direct_optab_handler (cmpstrn_optab, SImode) != CODE_FOR_nothing)
+ insn_code cmpstr_icode = direct_optab_handler (cmpstr_optab, SImode);
+ insn_code cmpstrn_icode = direct_optab_handler (cmpstrn_optab, SImode);
+ if (cmpstr_icode != CODE_FOR_nothing || cmpstrn_icode != CODE_FOR_nothing)
{
rtx arg1_rtx, arg2_rtx;
- rtx result, insn = NULL_RTX;
tree fndecl, fn;
tree arg1 = CALL_EXPR_ARG (exp, 0);
tree arg2 = CALL_EXPR_ARG (exp, 1);
+ rtx result = NULL_RTX;
unsigned int arg1_align = get_pointer_alignment (arg1) / BITS_PER_UNIT;
unsigned int arg2_align = get_pointer_alignment (arg2) / BITS_PER_UNIT;
@@ -4050,33 +4071,17 @@ expand_builtin_strcmp (tree exp, ATTRIBUTE_UNUSED rtx target)
arg1_rtx = get_memory_rtx (arg1, NULL);
arg2_rtx = get_memory_rtx (arg2, NULL);
-#ifdef HAVE_cmpstrsi
/* Try to call cmpstrsi. */
- if (HAVE_cmpstrsi)
- {
- machine_mode insn_mode
- = insn_data[(int) CODE_FOR_cmpstrsi].operand[0].mode;
-
- /* Make a place to write the result of the instruction. */
- result = target;
- if (! (result != 0
- && REG_P (result) && GET_MODE (result) == insn_mode
- && REGNO (result) >= FIRST_PSEUDO_REGISTER))
- result = gen_reg_rtx (insn_mode);
-
- insn = gen_cmpstrsi (result, arg1_rtx, arg2_rtx,
- GEN_INT (MIN (arg1_align, arg2_align)));
- }
-#endif
-#ifdef HAVE_cmpstrnsi
+ if (cmpstr_icode != CODE_FOR_nothing)
+ result = expand_cmpstr (cmpstr_icode, target, arg1_rtx, arg2_rtx,
+ MIN (arg1_align, arg2_align));
+
/* Try to determine at least one length and call cmpstrnsi. */
- if (!insn && HAVE_cmpstrnsi)
+ if (!result && cmpstrn_icode != CODE_FOR_nothing)
{
tree len;
rtx arg3_rtx;
- machine_mode insn_mode
- = insn_data[(int) CODE_FOR_cmpstrnsi].operand[0].mode;
tree len1 = c_strlen (arg1, 1);
tree len2 = c_strlen (arg2, 1);
@@ -4110,30 +4115,19 @@ expand_builtin_strcmp (tree exp, ATTRIBUTE_UNUSED rtx target)
len = len2;
/* If both arguments have side effects, we cannot optimize. */
- if (!len || TREE_SIDE_EFFECTS (len))
- goto do_libcall;
-
- arg3_rtx = expand_normal (len);
-
- /* Make a place to write the result of the instruction. */
- result = target;
- if (! (result != 0
- && REG_P (result) && GET_MODE (result) == insn_mode
- && REGNO (result) >= FIRST_PSEUDO_REGISTER))
- result = gen_reg_rtx (insn_mode);
-
- insn = gen_cmpstrnsi (result, arg1_rtx, arg2_rtx, arg3_rtx,
- GEN_INT (MIN (arg1_align, arg2_align)));
+ if (len && !TREE_SIDE_EFFECTS (len))
+ {
+ arg3_rtx = expand_normal (len);
+ result = expand_cmpstrn_or_cmpmem
+ (cmpstrn_icode, target, arg1_rtx, arg2_rtx, TREE_TYPE (len),
+ arg3_rtx, MIN (arg1_align, arg2_align));
+ }
}
-#endif
- if (insn)
+ if (result)
{
- machine_mode mode;
- emit_insn (insn);
-
/* Return the value in the proper mode for this function. */
- mode = TYPE_MODE (TREE_TYPE (exp));
+ machine_mode mode = TYPE_MODE (TREE_TYPE (exp));
if (GET_MODE (result) == mode)
return result;
if (target == 0)
@@ -4144,16 +4138,12 @@ expand_builtin_strcmp (tree exp, ATTRIBUTE_UNUSED rtx target)
/* Expand the library call ourselves using a stabilized argument
list to avoid re-evaluating the function's arguments twice. */
-#ifdef HAVE_cmpstrnsi
- do_libcall:
-#endif
fndecl = get_callee_fndecl (exp);
fn = build_call_nofold_loc (EXPR_LOCATION (exp), fndecl, 2, arg1, arg2);
gcc_assert (TREE_CODE (fn) == CALL_EXPR);
CALL_EXPR_TAILCALL (fn) = CALL_EXPR_TAILCALL (exp);
return expand_call (fn, target, target == const0_rtx);
}
-#endif
return NULL_RTX;
}
@@ -4174,12 +4164,12 @@ expand_builtin_strncmp (tree exp, ATTRIBUTE_UNUSED rtx target,
/* If c_strlen can determine an expression for one of the string
lengths, and it doesn't have side effects, then emit cmpstrnsi
using length MIN(strlen(string)+1, arg3). */
-#ifdef HAVE_cmpstrnsi
- if (HAVE_cmpstrnsi)
+ insn_code cmpstrn_icode = direct_optab_handler (cmpstrn_optab, SImode);
+ if (cmpstrn_icode != CODE_FOR_nothing)
{
tree len, len1, len2;
rtx arg1_rtx, arg2_rtx, arg3_rtx;
- rtx result, insn;
+ rtx result;
tree fndecl, fn;
tree arg1 = CALL_EXPR_ARG (exp, 0);
tree arg2 = CALL_EXPR_ARG (exp, 1);
@@ -4187,8 +4177,6 @@ expand_builtin_strncmp (tree exp, ATTRIBUTE_UNUSED rtx target,
unsigned int arg1_align = get_pointer_alignment (arg1) / BITS_PER_UNIT;
unsigned int arg2_align = get_pointer_alignment (arg2) / BITS_PER_UNIT;
- machine_mode insn_mode
- = insn_data[(int) CODE_FOR_cmpstrnsi].operand[0].mode;
len1 = c_strlen (arg1, 1);
len2 = c_strlen (arg2, 1);
@@ -4234,13 +4222,6 @@ expand_builtin_strncmp (tree exp, ATTRIBUTE_UNUSED rtx target,
if (arg1_align == 0 || arg2_align == 0)
return NULL_RTX;
- /* Make a place to write the result of the instruction. */
- result = target;
- if (! (result != 0
- && REG_P (result) && GET_MODE (result) == insn_mode
- && REGNO (result) >= FIRST_PSEUDO_REGISTER))
- result = gen_reg_rtx (insn_mode);
-
/* Stabilize the arguments in case gen_cmpstrnsi fails. */
arg1 = builtin_save_expr (arg1);
arg2 = builtin_save_expr (arg2);
@@ -4249,12 +4230,11 @@ expand_builtin_strncmp (tree exp, ATTRIBUTE_UNUSED rtx target,
arg1_rtx = get_memory_rtx (arg1, len);
arg2_rtx = get_memory_rtx (arg2, len);
arg3_rtx = expand_normal (len);
- insn = gen_cmpstrnsi (result, arg1_rtx, arg2_rtx, arg3_rtx,
- GEN_INT (MIN (arg1_align, arg2_align)));
- if (insn)
+ result = expand_cmpstrn_or_cmpmem (cmpstrn_icode, target, arg1_rtx,
+ arg2_rtx, TREE_TYPE (len), arg3_rtx,
+ MIN (arg1_align, arg2_align));
+ if (result)
{
- emit_insn (insn);
-
/* Return the value in the proper mode for this function. */
mode = TYPE_MODE (TREE_TYPE (exp));
if (GET_MODE (result) == mode)
@@ -4274,7 +4254,6 @@ expand_builtin_strncmp (tree exp, ATTRIBUTE_UNUSED rtx target,
CALL_EXPR_TAILCALL (fn) = CALL_EXPR_TAILCALL (exp);
return expand_call (fn, target, target == const0_rtx);
}
-#endif
return NULL_RTX;
}
@@ -6348,7 +6327,7 @@ expand_builtin (tree exp, rtx target, rtx subtarget, machine_mode mode,
case BUILT_IN_BCMP:
case BUILT_IN_MEMCMP:
- target = expand_builtin_memcmp (exp, target, mode);
+ target = expand_builtin_memcmp (exp, target);
if (target)
return target;
break;