#include "tm_p.h"
#include "target.h"
#include "langhooks.h"
+#include "basic-block.h"
#define CALLED_AS_BUILT_IN(NODE) \
(!strncmp (IDENTIFIER_POINTER (DECL_NAME (NODE)), "__builtin_", 10))
static tree fold_trunc_transparent_mathfn (tree);
static bool readonly_data_expr (tree);
static rtx expand_builtin_fabs (tree, rtx, rtx);
-static rtx expand_builtin_cabs (tree, rtx);
static rtx expand_builtin_signbit (tree, rtx);
static tree fold_builtin_cabs (tree, tree);
static tree fold_builtin_trunc (tree);
static tree fold_builtin_memcpy (tree);
static tree fold_builtin_mempcpy (tree);
static tree fold_builtin_memmove (tree);
-static tree fold_builtin_strcpy (tree);
-static tree fold_builtin_strncpy (tree);
+static tree fold_builtin_strchr (tree, bool);
static tree fold_builtin_memcmp (tree);
static tree fold_builtin_strcmp (tree);
static tree fold_builtin_strncmp (tree);
static tree fold_builtin_signbit (tree);
+static tree fold_builtin_copysign (tree, tree);
+static tree fold_builtin_isascii (tree);
+static tree fold_builtin_toascii (tree);
+static tree fold_builtin_isdigit (tree);
+static tree fold_builtin_fabs (tree, tree);
+static tree fold_builtin_abs (tree, tree);
+static tree fold_builtin_unordered_cmp (tree, enum tree_code, enum tree_code);
+static tree fold_builtin_1 (tree, bool);
-static tree simplify_builtin_memcmp (tree);
-static tree simplify_builtin_strcmp (tree);
-static tree simplify_builtin_strncmp (tree);
static tree simplify_builtin_strpbrk (tree);
static tree simplify_builtin_strstr (tree);
static tree simplify_builtin_strchr (tree);
HOST_WIDE_INT ch;
unsigned int i, j;
- if (GET_MODE_CLASS (mode) != MODE_INT)
- abort ();
+ gcc_assert (GET_MODE_CLASS (mode) == MODE_INT);
+
c[0] = 0;
c[1] = 0;
ch = 1;
&& GET_MODE_SIZE (mode) > UNITS_PER_WORD)
j = j + UNITS_PER_WORD - 2 * (j % UNITS_PER_WORD) - 1;
j *= BITS_PER_UNIT;
- if (j > 2 * HOST_BITS_PER_WIDE_INT)
- abort ();
+ gcc_assert (j <= 2 * HOST_BITS_PER_WIDE_INT);
+
if (ch)
ch = (unsigned char) str[i];
c[j / HOST_BITS_PER_WIDE_INT] |= ch << (j % HOST_BITS_PER_WIDE_INT);
buf_addr = force_reg (Pmode, force_operand (buf_addr, NULL_RTX));
- emit_queue ();
-
/* We store the frame pointer and the address of receiver_label in
the buffer and use the rest of it for the stack save area, which
is machine-dependent. */
emit_insn (gen_rtx_CLOBBER (VOIDmode, static_chain_rtx));
/* Now put in the code to restore the frame pointer, and argument
- pointer, if needed. The code below is from expand_end_bindings
- in stmt.c; see detailed documentation there. */
+ pointer, if needed. */
#ifdef HAVE_nonlocal_goto
if (! HAVE_nonlocal_goto)
#endif
if (!validate_arglist (arglist, POINTER_TYPE, VOID_TYPE))
return NULL_RTX;
- if (target == 0 || GET_CODE (target) != REG
+ if (target == 0 || !REG_P (target)
|| REGNO (target) < FIRST_PSEUDO_REGISTER)
target = gen_reg_rtx (TYPE_MODE (integer_type_node));
a second argument of 1, because that is what builtin_setjmp will
return. This also makes EH slightly more efficient, since we are no
longer copying around a value that we don't care about. */
- if (value != const1_rtx)
- abort ();
+ gcc_assert (value == const1_rtx);
current_function_calls_longjmp = 1;
internal exception handling use only. */
for (insn = get_last_insn (); insn; insn = PREV_INSN (insn))
{
- if (insn == last)
- abort ();
- if (GET_CODE (insn) == JUMP_INSN)
+ gcc_assert (insn != last);
+
+ if (JUMP_P (insn))
{
REG_NOTES (insn) = alloc_EXPR_LIST (REG_NON_LOCAL_GOTO, const0_rtx,
REG_NOTES (insn));
break;
}
- else if (GET_CODE (insn) == CALL_INSN)
+ else if (CALL_P (insn))
break;
}
}
t_save_area = TREE_VALUE (arglist);
r_label = expand_expr (t_label, NULL_RTX, VOIDmode, 0);
+ r_label = convert_memory_address (Pmode, r_label);
r_save_area = expand_expr (t_save_area, NULL_RTX, VOIDmode, 0);
+ r_save_area = convert_memory_address (Pmode, r_save_area);
r_fp = gen_rtx_MEM (Pmode, r_save_area);
r_sp = gen_rtx_MEM (STACK_SAVEAREA_MODE (SAVE_NONLOCAL),
plus_constant (r_save_area, GET_MODE_SIZE (Pmode)));
emit_insn (gen_rtx_CLOBBER (VOIDmode,
gen_rtx_MEM (BLKmode,
hard_frame_pointer_rtx)));
-
+
/* Restore frame pointer for containing function.
This sets the actual hard register used for the frame pointer
to the location of the function's incoming static chain info.
proper value and reload the argument pointer, if needed. */
emit_move_insn (hard_frame_pointer_rtx, r_fp);
emit_stack_restore (SAVE_NONLOCAL, r_sp, NULL_RTX);
-
+
/* USE of hard_frame_pointer_rtx added for consistency;
not clear if really needed. */
emit_insn (gen_rtx_USE (VOIDmode, hard_frame_pointer_rtx));
emit_insn (gen_rtx_USE (VOIDmode, stack_pointer_rtx));
emit_indirect_jump (r_label);
}
-
+
/* Search backwards to the jump insn and mark it as a
non-local goto. */
for (insn = get_last_insn (); insn; insn = PREV_INSN (insn))
{
- if (GET_CODE (insn) == JUMP_INSN)
+ if (JUMP_P (insn))
{
REG_NOTES (insn) = alloc_EXPR_LIST (REG_NON_LOCAL_GOTO,
const0_rtx, REG_NOTES (insn));
break;
}
- else if (GET_CODE (insn) == CALL_INSN)
+ else if (CALL_P (insn))
break;
}
if (TREE_CHAIN (TREE_CHAIN (arglist)))
arg2 = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
else
- arg2 = build_int_2 (3, 0);
+ arg2 = build_int_cst (NULL_TREE, 3);
}
else
{
arg1 = integer_zero_node;
- arg2 = build_int_2 (3, 0);
+ arg2 = build_int_cst (NULL_TREE, 3);
}
/* Argument 0 is an address. */
}
emit_insn (gen_prefetch (op0, op1, op2));
}
- else
#endif
- op0 = protect_from_queue (op0, 0);
+
/* Don't do anything with direct references to volatile memory, but
generate code to handle other side effects. */
- if (GET_CODE (op0) != MEM && side_effects_p (op0))
+ if (!MEM_P (op0) && side_effects_p (op0))
emit_insn (op0);
}
/* Get a MEM rtx for expression EXP which is the address of an operand
- to be used to be used in a string instruction (cmpstrsi, movstrsi, ..). */
+ to be used to be used in a string instruction (cmpstrsi, movmemsi, ..). */
static rtx
get_memory_rtx (tree exp)
{
mode = reg_raw_mode[regno];
- if (mode == VOIDmode)
- abort ();
+ gcc_assert (mode != VOIDmode);
align = GET_MODE_ALIGNMENT (mode) / BITS_PER_UNIT;
if (size % align != 0)
{
mode = reg_raw_mode[regno];
- if (mode == VOIDmode)
- abort ();
+ gcc_assert (mode != VOIDmode);
align = GET_MODE_ALIGNMENT (mode) / BITS_PER_UNIT;
if (size % align != 0)
chain current, so the code is placed at the start of the
function. */
push_topmost_sequence ();
- emit_insn_before (seq, NEXT_INSN (get_insns ()));
+ emit_insn_before (seq, NEXT_INSN (entry_of_function ()));
pop_topmost_sequence ();
return temp;
}
incoming_args, 0, OPTAB_LIB_WIDEN);
#endif
- /* Perform postincrements before actually calling the function. */
- emit_queue ();
-
/* Push a new argument block and copy the arguments. Do not allow
the (potential) memcpy call below to interfere with our stack
manipulations. */
rtx value = gen_reg_rtx (Pmode);
emit_move_insn (value, adjust_address (arguments, Pmode, size));
emit_move_insn (struct_value, value);
- if (GET_CODE (struct_value) == REG)
+ if (REG_P (struct_value))
use_reg (&call_fusage, struct_value);
size += GET_MODE_SIZE (Pmode);
}
for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
if ((mode = apply_result_mode[regno]) != VOIDmode)
{
- if (valreg)
- abort (); /* HAVE_untyped_call required. */
+ gcc_assert (!valreg); /* HAVE_untyped_call required. */
+
valreg = gen_rtx_REG (mode, regno);
}
}
else
#endif
- abort ();
+ gcc_unreachable ();
/* Find the CALL insn we just emitted, and attach the register usage
information. */
case BUILT_IN_NEARBYINTF:
case BUILT_IN_NEARBYINTL:
builtin_optab = nearbyint_optab; break;
+ case BUILT_IN_RINT:
+ case BUILT_IN_RINTF:
+ case BUILT_IN_RINTL:
+ builtin_optab = rint_optab; break;
default:
- abort ();
+ gcc_unreachable ();
}
/* Make a suitable register to place result in. */
op0 = expand_expr (arg, subtarget, VOIDmode, 0);
- emit_queue ();
start_sequence ();
/* Compute into TARGET.
rtx operand = XEXP (XEXP (XEXP (note, 0), 1), 0);
/* Check operand is a register with expected mode. */
if (operand
- && GET_CODE (operand) == REG
+ && REG_P (operand)
&& GET_MODE (operand) == mode)
{
/* Replace the REG_EQUAL note with a SQRT rtx. */
case BUILT_IN_DREML:
builtin_optab = drem_optab; break;
default:
- abort ();
+ gcc_unreachable ();
}
/* Make a suitable register to place result in. */
op0 = expand_expr (arg0, subtarget, VOIDmode, 0);
op1 = expand_expr (arg1, 0, VOIDmode, 0);
- emit_queue ();
start_sequence ();
/* Compute into TARGET.
case BUILT_IN_COSL:
builtin_optab = sincos_optab; break;
default:
- abort ();
+ gcc_unreachable ();
}
/* Make a suitable register to place result in. */
errno_set = false;
/* Check if sincos insn is available, otherwise fallback
- to sin or cos insn. */
+ to sin or cos insn. */
if (builtin_optab->handlers[(int) mode].insn_code == CODE_FOR_nothing) {
switch (DECL_FUNCTION_CODE (fndecl))
{
case BUILT_IN_COSL:
builtin_optab = cos_optab; break;
default:
- abort();
+ gcc_unreachable ();
}
}
op0 = expand_expr (arg, subtarget, VOIDmode, 0);
- emit_queue ();
start_sequence ();
/* Compute into TARGET.
Set TARGET to wherever the result comes back. */
if (builtin_optab == sincos_optab)
{
+ int result;
+
switch (DECL_FUNCTION_CODE (fndecl))
{
case BUILT_IN_SIN:
case BUILT_IN_SINF:
case BUILT_IN_SINL:
- if (!expand_twoval_unop (builtin_optab, op0, 0, target, 0))
- abort();
+ result = expand_twoval_unop (builtin_optab, op0, 0, target, 0);
break;
case BUILT_IN_COS:
case BUILT_IN_COSF:
case BUILT_IN_COSL:
- if (!expand_twoval_unop (builtin_optab, op0, target, 0, 0))
- abort();
+ result = expand_twoval_unop (builtin_optab, op0, target, 0, 0);
break;
default:
- abort();
+ gcc_unreachable ();
}
+ gcc_assert (result);
}
else
{
/* Make a place to write the result of the instruction. */
result = target;
if (! (result != 0
- && GET_CODE (result) == REG
+ && REG_P (result)
&& GET_MODE (result) == insn_mode
&& REGNO (result) >= FIRST_PSEUDO_REGISTER))
result = gen_reg_rtx (insn_mode);
/* New argument list transforming strstr(s1, s2) to
strchr(s1, s2[0]). */
- arglist =
- build_tree_list (NULL_TREE, build_int_2 (p2[0], 0));
+ arglist = build_tree_list (NULL_TREE,
+ build_int_cst (NULL_TREE, p2[0]));
arglist = tree_cons (NULL_TREE, s1, arglist);
return expand_expr (build_function_call_expr (fn, arglist),
target, mode, EXPAND_NORMAL);
/* New argument list transforming strpbrk(s1, s2) to
strchr(s1, s2[0]). */
- arglist =
- build_tree_list (NULL_TREE, build_int_2 (p2[0], 0));
+ arglist = build_tree_list (NULL_TREE,
+ build_int_cst (NULL_TREE, p2[0]));
arglist = tree_cons (NULL_TREE, s1, arglist);
return expand_expr (build_function_call_expr (fn, arglist),
target, mode, EXPAND_NORMAL);
{
const char *str = (const char *) data;
- if (offset < 0
- || ((unsigned HOST_WIDE_INT) offset + GET_MODE_SIZE (mode)
- > strlen (str) + 1))
- abort (); /* Attempt to read past the end of constant string. */
+ gcc_assert (offset >= 0
+ && ((unsigned HOST_WIDE_INT) offset + GET_MODE_SIZE (mode)
+ <= strlen (str) + 1));
return c_readstr (str + offset, mode);
}
return expand_builtin_memmove (newarglist, const0_rtx, VOIDmode);
}
+#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 0 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
+ destination pointer, if ENDP is 1 return the end pointer ala
+ mempcpy, and if ENDP is 2 return the end pointer minus one ala
+ stpcpy. */
+
+static rtx
+expand_movstr (tree dest, tree src, rtx target, int endp)
+{
+ rtx end;
+ rtx dest_mem;
+ rtx src_mem;
+ rtx insn;
+ const struct insn_data * data;
+
+ if (!HAVE_movstr)
+ return 0;
+
+ dest_mem = get_memory_rtx (dest);
+ src_mem = get_memory_rtx (src);
+ if (!endp)
+ {
+ target = force_reg (Pmode, XEXP (dest_mem, 0));
+ dest_mem = replace_equiv_address (dest_mem, target);
+ end = gen_reg_rtx (Pmode);
+ }
+ else
+ {
+ if (target == 0 || target == const0_rtx)
+ {
+ end = gen_reg_rtx (Pmode);
+ if (target == 0)
+ target = end;
+ }
+ else
+ end = target;
+ }
+
+ data = insn_data + CODE_FOR_movstr;
+
+ if (data->operand[0].mode != VOIDmode)
+ end = gen_lowpart (data->operand[0].mode, end);
+
+ insn = data->genfun (end, dest_mem, src_mem);
+
+ gcc_assert (insn);
+
+ emit_insn (insn);
+
+ /* movstr is supposed to set end to the address of the NUL
+ terminator. If the caller requested a mempcpy-like return value,
+ adjust it. */
+ if (endp == 1 && target != const0_rtx)
+ emit_move_insn (target, plus_constant (gen_lowpart (GET_MODE (target),
+ end), 1));
+
+ return target;
+}
+
/* Expand expression EXP, which is a call to the strcpy builtin. Return 0
if we failed the caller should emit a normal call, otherwise try to get
the result in TARGET, if convenient (and in mode MODE if that's
if (operand_equal_p (src, dst, 0))
return expand_expr (dst, target, mode, EXPAND_NORMAL);
- fn = implicit_built_in_decls[BUILT_IN_MEMCPY];
- if (!fn)
- return 0;
-
len = c_strlen (src, 1);
if (len == 0 || TREE_SIDE_EFFECTS (len))
+ return expand_movstr (TREE_VALUE (arglist),
+ TREE_VALUE (TREE_CHAIN (arglist)),
+ target, /*endp=*/0);
+
+ fn = implicit_built_in_decls[BUILT_IN_MEMCPY];
+ if (!fn)
return 0;
len = size_binop (PLUS_EXPR, len, ssize_int (1));
static rtx
expand_builtin_stpcpy (tree arglist, rtx target, enum machine_mode mode)
{
+ /* If return value is ignored, transform stpcpy into strcpy. */
+ if (target == const0_rtx)
+ {
+ tree fn = implicit_built_in_decls[BUILT_IN_STRCPY];
+ if (!fn)
+ return 0;
+
+ return expand_expr (build_function_call_expr (fn, arglist),
+ target, mode, EXPAND_NORMAL);
+ }
+
if (!validate_arglist (arglist, POINTER_TYPE, POINTER_TYPE, VOID_TYPE))
return 0;
else
{
- tree dst, src, len;
-
- /* If return value is ignored, transform stpcpy into strcpy. */
- if (target == const0_rtx)
- {
- tree fn = implicit_built_in_decls[BUILT_IN_STRCPY];
- if (!fn)
- return 0;
-
- return expand_expr (build_function_call_expr (fn, arglist),
- target, mode, EXPAND_NORMAL);
- }
+ tree dst, src, len, lenp1;
+ tree narglist;
+ rtx ret;
/* Ensure we get an actual string whose length can be evaluated at
compile-time, not an expression containing a string. This is
when used to produce the return value. */
src = TREE_VALUE (TREE_CHAIN (arglist));
if (! c_getstr (src) || ! (len = c_strlen (src, 0)))
- return 0;
+ return expand_movstr (TREE_VALUE (arglist),
+ TREE_VALUE (TREE_CHAIN (arglist)),
+ target, /*endp=*/2);
dst = TREE_VALUE (arglist);
- len = fold (size_binop (PLUS_EXPR, len, ssize_int (1)));
- arglist = build_tree_list (NULL_TREE, len);
- arglist = tree_cons (NULL_TREE, src, arglist);
- arglist = tree_cons (NULL_TREE, dst, arglist);
- return expand_builtin_mempcpy (arglist, target, mode, /*endp=*/2);
+ lenp1 = size_binop (PLUS_EXPR, len, ssize_int (1));
+ narglist = build_tree_list (NULL_TREE, lenp1);
+ narglist = tree_cons (NULL_TREE, src, narglist);
+ narglist = tree_cons (NULL_TREE, dst, narglist);
+ ret = expand_builtin_mempcpy (narglist, target, mode, /*endp=*/2);
+
+ if (ret)
+ return ret;
+
+ if (TREE_CODE (len) == INTEGER_CST)
+ {
+ rtx len_rtx = expand_expr (len, NULL_RTX, VOIDmode, 0);
+
+ if (GET_CODE (len_rtx) == CONST_INT)
+ {
+ ret = expand_builtin_strcpy (arglist, target, mode);
+
+ if (ret)
+ {
+ if (! target)
+ {
+ if (mode != VOIDmode)
+ target = gen_reg_rtx (mode);
+ else
+ target = gen_reg_rtx (GET_MODE (ret));
+ }
+ if (GET_MODE (target) != GET_MODE (ret))
+ ret = gen_lowpart (GET_MODE (target), ret);
+
+ ret = emit_move_insn (target,
+ plus_constant (ret,
+ INTVAL (len_rtx)));
+ gcc_assert (ret);
+
+ return target;
+ }
+ }
+ }
+
+ return expand_movstr (TREE_VALUE (arglist),
+ TREE_VALUE (TREE_CHAIN (arglist)),
+ target, /*endp=*/2);
}
}
/* Make a place to write the result of the instruction. */
result = target;
if (! (result != 0
- && GET_CODE (result) == REG && GET_MODE (result) == insn_mode
+ && REG_P (result) && GET_MODE (result) == insn_mode
&& REGNO (result) >= FIRST_PSEUDO_REGISTER))
result = gen_reg_rtx (insn_mode);
GEN_INT (MIN (arg1_align, arg2_align)));
else
#endif
- abort ();
+ gcc_unreachable ();
if (insn)
emit_insn (insn);
/* Make a place to write the result of the instruction. */
result = target;
if (! (result != 0
- && GET_CODE (result) == REG && GET_MODE (result) == insn_mode
+ && REG_P (result) && GET_MODE (result) == insn_mode
&& REGNO (result) >= FIRST_PSEUDO_REGISTER))
result = gen_reg_rtx (insn_mode);
return 0;
/* The actual new length parameter is MIN(len,arg3). */
- len = fold (build2 (MIN_EXPR, TREE_TYPE (len), len, arg3));
+ len = fold (build2 (MIN_EXPR, TREE_TYPE (len), len,
+ fold_convert (TREE_TYPE (len), arg3)));
/* If we don't have POINTER_TYPE, call the function. */
if (arg1_align == 0 || arg2_align == 0)
/* Make a place to write the result of the instruction. */
result = target;
if (! (result != 0
- && GET_CODE (result) == REG && GET_MODE (result) == insn_mode
+ && REG_P (result) && GET_MODE (result) == insn_mode
&& REGNO (result) >= FIRST_PSEUDO_REGISTER))
result = gen_reg_rtx (insn_mode);
is inside a start_sequence, make the outer-level insn chain current, so
the code is placed at the start of the function. */
push_topmost_sequence ();
- emit_insn_after (seq, get_insns ());
+ emit_insn_after (seq, entry_of_function ());
pop_topmost_sequence ();
return val;
int nwords = sizeof (CUMULATIVE_ARGS) / sizeof (int);
int *word_ptr = (int *) ¤t_function_args_info;
- if (sizeof (CUMULATIVE_ARGS) % sizeof (int) != 0)
- abort ();
+ gcc_assert (sizeof (CUMULATIVE_ARGS) % sizeof (int) == 0);
if (arglist != 0)
{
if (TREE_CODE (TREE_TYPE (valist)) == ARRAY_TYPE)
{
tree p1 = build_pointer_type (TREE_TYPE (va_list_type_node));
- tree p2 = build_pointer_type (va_list_type_node);
-
- valist = build1 (ADDR_EXPR, p2, valist);
- valist = fold_convert (p1, valist);
+ valist = build_fold_addr_expr_with_type (valist, p1);
}
}
else
if (TREE_SIDE_EFFECTS (valist))
valist = save_expr (valist);
- valist = fold (build1 (INDIRECT_REF, TREE_TYPE (TREE_TYPE (valist)),
- valist));
+ valist = build_fold_indirect_ref (valist);
}
return valist;
/* The "standard" implementation of va_arg: read the value from the
current (padded) address and increment by the (padded) size. */
-rtx
-std_expand_builtin_va_arg (tree valist, tree type)
+tree
+std_gimplify_va_arg_expr (tree valist, tree type, tree *pre_p, tree *post_p)
{
- tree addr_tree, t, type_size = NULL;
- tree align, alignm1;
- tree rounded_size;
- rtx addr;
- HOST_WIDE_INT boundary;
+ tree addr, t, type_size, rounded_size, valist_tmp;
+ unsigned HOST_WIDE_INT align, boundary;
+ bool indirect;
- /* Compute the rounded size of the type. */
- align = size_int (PARM_BOUNDARY / BITS_PER_UNIT);
- alignm1 = size_int (PARM_BOUNDARY / BITS_PER_UNIT - 1);
- boundary = FUNCTION_ARG_BOUNDARY (TYPE_MODE (type), type);
+#ifdef ARGS_GROW_DOWNWARD
+ /* All of the alignment and movement below is for args-grow-up machines.
+ As of 2004, there are only 3 ARGS_GROW_DOWNWARD targets, and they all
+ implement their own specialized gimplify_va_arg_expr routines. */
+ gcc_unreachable ();
+#endif
+
+ indirect = pass_by_reference (NULL, TYPE_MODE (type), type, false);
+ if (indirect)
+ type = build_pointer_type (type);
+
+ align = PARM_BOUNDARY / BITS_PER_UNIT;
+ boundary = FUNCTION_ARG_BOUNDARY (TYPE_MODE (type), type) / BITS_PER_UNIT;
+
+ /* Hoist the valist value into a temporary for the moment. */
+ valist_tmp = get_initialized_tmp_var (valist, pre_p, NULL);
/* va_list pointer is aligned to PARM_BOUNDARY. If argument actually
requires greater alignment, we must perform dynamic alignment. */
-
- if (boundary > PARM_BOUNDARY)
- {
- if (!PAD_VARARGS_DOWN)
- {
- t = build2 (MODIFY_EXPR, TREE_TYPE (valist), valist,
- build2 (PLUS_EXPR, TREE_TYPE (valist), valist,
- build_int_2 (boundary / BITS_PER_UNIT - 1, 0)));
- TREE_SIDE_EFFECTS (t) = 1;
- expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
- }
- t = build2 (MODIFY_EXPR, TREE_TYPE (valist), valist,
- build2 (BIT_AND_EXPR, TREE_TYPE (valist), valist,
- build_int_2 (~(boundary / BITS_PER_UNIT - 1), -1)));
- TREE_SIDE_EFFECTS (t) = 1;
- expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
- }
- if (type == error_mark_node
- || (type_size = TYPE_SIZE_UNIT (TYPE_MAIN_VARIANT (type))) == NULL
- || TREE_OVERFLOW (type_size))
- rounded_size = size_zero_node;
- else
+ if (boundary > align)
{
- rounded_size = fold (build2 (PLUS_EXPR, sizetype, type_size, alignm1));
- rounded_size = fold (build2 (TRUNC_DIV_EXPR, sizetype,
- rounded_size, align));
- rounded_size = fold (build2 (MULT_EXPR, sizetype,
- rounded_size, align));
+ t = fold_convert (TREE_TYPE (valist), size_int (boundary - 1));
+ t = build2 (MODIFY_EXPR, TREE_TYPE (valist), valist_tmp,
+ build2 (PLUS_EXPR, TREE_TYPE (valist), valist_tmp, t));
+ gimplify_and_add (t, pre_p);
+
+ t = fold_convert (TREE_TYPE (valist), size_int (-boundary));
+ t = build2 (MODIFY_EXPR, TREE_TYPE (valist), valist_tmp,
+ build2 (BIT_AND_EXPR, TREE_TYPE (valist), valist_tmp, t));
+ gimplify_and_add (t, pre_p);
}
+ /* Compute the rounded size of the type. */
+ type_size = size_in_bytes (type);
+ rounded_size = round_up (type_size, align);
+
+ /* Reduce rounded_size so it's sharable with the postqueue. */
+ gimplify_expr (&rounded_size, pre_p, post_p, is_gimple_val, fb_rvalue);
+
/* Get AP. */
- addr_tree = valist;
- if (PAD_VARARGS_DOWN && ! integer_zerop (rounded_size))
+ addr = valist_tmp;
+ if (PAD_VARARGS_DOWN && !integer_zerop (rounded_size))
{
/* Small args are padded downward. */
- addr_tree = fold (build2 (PLUS_EXPR, TREE_TYPE (addr_tree), addr_tree,
- fold (build3 (COND_EXPR, sizetype,
- fold (build2 (GT_EXPR, sizetype,
- rounded_size,
- align)),
- size_zero_node,
- fold (build2 (MINUS_EXPR,
- sizetype,
- rounded_size,
- type_size))))));
+ t = fold (build2 (GT_EXPR, sizetype, rounded_size, size_int (align)));
+ t = fold (build3 (COND_EXPR, sizetype, t, size_zero_node,
+ size_binop (MINUS_EXPR, rounded_size, type_size)));
+ t = fold_convert (TREE_TYPE (addr), t);
+ addr = fold (build2 (PLUS_EXPR, TREE_TYPE (addr), addr, t));
}
- addr = expand_expr (addr_tree, NULL_RTX, Pmode, EXPAND_NORMAL);
- addr = copy_to_reg (addr);
-
/* Compute new value for AP. */
- if (! integer_zerop (rounded_size))
+ t = fold_convert (TREE_TYPE (valist), rounded_size);
+ t = build2 (PLUS_EXPR, TREE_TYPE (valist), valist_tmp, t);
+ t = build2 (MODIFY_EXPR, TREE_TYPE (valist), valist, t);
+ gimplify_and_add (t, pre_p);
+
+ addr = fold_convert (build_pointer_type (type), addr);
+
+ if (indirect)
{
- t = build2 (MODIFY_EXPR, TREE_TYPE (valist), valist,
- build2 (PLUS_EXPR, TREE_TYPE (valist), valist,
- rounded_size));
- TREE_SIDE_EFFECTS (t) = 1;
- expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
+ addr = build_fold_indirect_ref (addr);
+ if (flag_mudflap) /* Don't instrument va_arg INDIRECT_REF. */
+ mf_mark (addr);
}
+ addr = build_fold_indirect_ref (addr);
+ if (flag_mudflap) /* Don't instrument va_arg INDIRECT_REF. */
+ mf_mark (addr);
+
return addr;
}
-/* Expand __builtin_va_arg, which is not really a builtin function, but
- a very special sort of operator. */
+/* Return a dummy expression of type TYPE in order to keep going after an
+ error. */
-rtx
-expand_builtin_va_arg (tree valist, tree type)
+static tree
+dummy_object (tree type)
+{
+ tree t = convert (build_pointer_type (type), null_pointer_node);
+ return build1 (INDIRECT_REF, type, t);
+}
+
+/* Gimplify __builtin_va_arg, aka VA_ARG_EXPR, which is not really a
+ builtin function, but a very special sort of operator. */
+
+enum gimplify_status
+gimplify_va_arg_expr (tree *expr_p, tree *pre_p, tree *post_p)
{
- rtx addr, result;
tree promoted_type, want_va_type, have_va_type;
+ tree valist = TREE_OPERAND (*expr_p, 0);
+ tree type = TREE_TYPE (*expr_p);
+ tree t;
/* Verify that valist is of the proper type. */
-
want_va_type = va_list_type_node;
have_va_type = TREE_TYPE (valist);
+
+ if (have_va_type == error_mark_node)
+ return GS_ERROR;
+
if (TREE_CODE (want_va_type) == ARRAY_TYPE)
{
/* If va_list is an array type, the argument may have decayed
have_va_type = TREE_TYPE (have_va_type);
}
}
+
if (TYPE_MAIN_VARIANT (want_va_type) != TYPE_MAIN_VARIANT (have_va_type))
{
error ("first argument to `va_arg' not of type `va_list'");
- addr = const0_rtx;
+ return GS_ERROR;
}
/* Generate a diagnostic for requesting data of a type that cannot
else if ((promoted_type = lang_hooks.types.type_promotes_to (type))
!= type)
{
- const char *name = "<anonymous type>", *pname = 0;
static bool gave_help;
- if (TYPE_NAME (type))
- {
- if (TREE_CODE (TYPE_NAME (type)) == IDENTIFIER_NODE)
- name = IDENTIFIER_POINTER (TYPE_NAME (type));
- else if (TREE_CODE (TYPE_NAME (type)) == TYPE_DECL
- && DECL_NAME (TYPE_NAME (type)))
- name = IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (type)));
- }
- if (TYPE_NAME (promoted_type))
- {
- if (TREE_CODE (TYPE_NAME (promoted_type)) == IDENTIFIER_NODE)
- pname = IDENTIFIER_POINTER (TYPE_NAME (promoted_type));
- else if (TREE_CODE (TYPE_NAME (promoted_type)) == TYPE_DECL
- && DECL_NAME (TYPE_NAME (promoted_type)))
- pname = IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (promoted_type)));
- }
-
/* Unfortunately, this is merely undefined, rather than a constraint
violation, so we cannot make this an error. If this call is never
executed, the program is still strictly conforming. */
- warning ("`%s' is promoted to `%s' when passed through `...'",
- name, pname);
+ warning ("`%T' is promoted to `%T' when passed through `...'",
+ type, promoted_type);
if (! gave_help)
{
gave_help = true;
- warning ("(so you should pass `%s' not `%s' to `va_arg')",
- pname, name);
+ warning ("(so you should pass `%T' not `%T' to `va_arg')",
+ promoted_type, type);
}
/* We can, however, treat "undefined" any way we please.
Call abort to encourage the user to fix the program. */
inform ("if this code is reached, the program will abort");
- expand_builtin_trap ();
+ t = build_function_call_expr (implicit_built_in_decls[BUILT_IN_TRAP],
+ NULL);
+ append_to_statement_list (t, pre_p);
/* This is dead code, but go ahead and finish so that the
mode of the result comes out right. */
- addr = const0_rtx;
+ *expr_p = dummy_object (type);
+ return GS_ALL_DONE;
}
else
{
/* Make it easier for the backends by protecting the valist argument
from multiple evaluations. */
- valist = stabilize_va_list (valist, 0);
-
-#ifdef EXPAND_BUILTIN_VA_ARG
- addr = EXPAND_BUILTIN_VA_ARG (valist, type);
-#else
- addr = std_expand_builtin_va_arg (valist, type);
-#endif
- }
-
- addr = convert_memory_address (Pmode, addr);
+ if (TREE_CODE (va_list_type_node) == ARRAY_TYPE)
+ {
+ /* For this case, the backends will be expecting a pointer to
+ TREE_TYPE (va_list_type_node), but it's possible we've
+ actually been given an array (an actual va_list_type_node).
+ So fix it. */
+ if (TREE_CODE (TREE_TYPE (valist)) == ARRAY_TYPE)
+ {
+ tree p1 = build_pointer_type (TREE_TYPE (va_list_type_node));
+ valist = build_fold_addr_expr_with_type (valist, p1);
+ }
+ gimplify_expr (&valist, pre_p, post_p, is_gimple_val, fb_rvalue);
+ }
+ else
+ gimplify_expr (&valist, pre_p, post_p, is_gimple_min_lval, fb_lvalue);
- result = gen_rtx_MEM (TYPE_MODE (type), addr);
- set_mem_alias_set (result, get_varargs_alias_set ());
+ if (!targetm.gimplify_va_arg_expr)
+ /* Once most targets are converted this should abort. */
+ return GS_ALL_DONE;
- return result;
+ *expr_p = targetm.gimplify_va_arg_expr (valist, type, pre_p, post_p);
+ return GS_OK;
+ }
}
/* Expand ARGLIST, from a call to __builtin_va_end. */
if (DECL_FUNCTION_CODE (fndecl) == BUILT_IN_FRAME_ADDRESS)
return tem;
- if (GET_CODE (tem) != REG
+ if (!REG_P (tem)
&& ! CONSTANT_P (tem))
tem = copy_to_mode_reg (Pmode, tem);
return tem;
Set TARGET to wherever the result comes back. */
target = expand_unop (TYPE_MODE (TREE_TYPE (TREE_VALUE (arglist))),
op_optab, op0, target, 1);
- if (target == 0)
- abort ();
+ gcc_assert (target);
return convert_to_mode (target_mode, target, 0);
}
{
/* New argument list transforming fputs(string, stream) to
fputc(string[0], stream). */
- arglist =
- build_tree_list (NULL_TREE, TREE_VALUE (TREE_CHAIN (arglist)));
- arglist =
- tree_cons (NULL_TREE, build_int_2 (p[0], 0), arglist);
+ arglist = build_tree_list (NULL_TREE,
+ TREE_VALUE (TREE_CHAIN (arglist)));
+ arglist = tree_cons (NULL_TREE,
+ build_int_cst (NULL_TREE, p[0]),
+ arglist);
fn = fn_fputc;
break;
}
break;
}
default:
- abort ();
+ gcc_unreachable ();
}
return expand_expr (build_function_call_expr (fn, arglist),
ret = get_insns ();
drop_through_label = get_last_insn ();
- if (drop_through_label && GET_CODE (drop_through_label) == NOTE)
+ if (drop_through_label && NOTE_P (drop_through_label))
drop_through_label = prev_nonnote_insn (drop_through_label);
- if (drop_through_label && GET_CODE (drop_through_label) != CODE_LABEL)
+ if (drop_through_label && !LABEL_P (drop_through_label))
drop_through_label = NULL_RTX;
end_sequence ();
{
rtx next = NEXT_INSN (insn);
- if (GET_CODE (insn) == JUMP_INSN && any_condjump_p (insn))
+ if (JUMP_P (insn) && any_condjump_p (insn))
{
rtx ifelse = SET_SRC (pc_set (insn));
rtx then_dest = XEXP (ifelse, 1);
/* Otherwise check where we drop through. */
else if (else_dest == pc_rtx)
{
- if (next && GET_CODE (next) == NOTE)
+ if (next && NOTE_P (next))
next = next_nonnote_insn (next);
- if (next && GET_CODE (next) == JUMP_INSN
+ if (next && JUMP_P (next)
&& any_uncondjump_p (next))
temp = XEXP (SET_SRC (pc_set (next)), 0);
else
}
else if (then_dest == pc_rtx)
{
- if (next && GET_CODE (next) == NOTE)
+ if (next && NOTE_P (next))
next = next_nonnote_insn (next);
- if (next && GET_CODE (next) == JUMP_INSN
+ if (next && JUMP_P (next)
&& any_uncondjump_p (next))
temp = XEXP (SET_SRC (pc_set (next)), 0);
else
return expand_abs (mode, op0, target, 0, safe_from_p (target, arg, 1));
}
-/* Expand a call to cabs, cabsf or cabsl with arguments ARGLIST.
- Return 0 if a normal call should be emitted rather than expanding
- the function inline. If convenient, the result should be placed
- in target. */
-
-static rtx
-expand_builtin_cabs (tree arglist, rtx target)
-{
- enum machine_mode mode;
- tree arg;
- rtx op0;
-
- if (arglist == 0 || TREE_CHAIN (arglist))
- return 0;
- arg = TREE_VALUE (arglist);
- if (TREE_CODE (TREE_TYPE (arg)) != COMPLEX_TYPE
- || TREE_CODE (TREE_TYPE (TREE_TYPE (arg))) != REAL_TYPE)
- return 0;
-
- mode = TYPE_MODE (TREE_TYPE (arg));
- op0 = expand_expr (arg, NULL_RTX, VOIDmode, 0);
- return expand_complex_abs (mode, op0, target, 0);
-}
-
/* Create a new constant string literal and return a char* pointer to it.
The STRING_CST value is the LEN characters at STR. */
static tree
t = build_string (len, str);
elem = build_type_variant (char_type_node, 1, 0);
- index = build_index_type (build_int_2 (len - 1, 0));
+ index = build_index_type (build_int_cst (NULL_TREE, len - 1));
type = build_array_type (elem, index);
TREE_TYPE (t) = type;
TREE_CONSTANT (t) = 1;
/* Given printf("c"), (where c is any one character,)
convert "c"[0] to an int and pass that to the replacement
function. */
- arg = build_int_2 (fmt_str[0], 0);
+ arg = build_int_cst (NULL_TREE, fmt_str[0]);
arglist = build_tree_list (NULL_TREE, arg);
fn = fn_putchar;
}
const0_rtx, VOIDmode, EXPAND_NORMAL);
if (target == const0_rtx)
return const0_rtx;
- exp = build_int_2 (strlen (fmt_str), 0);
- exp = fold_convert (integer_type_node, exp);
+ exp = build_int_cst (NULL_TREE, strlen (fmt_str));
return expand_expr (exp, target, mode, EXPAND_NORMAL);
}
/* If the format is "%s", use strcpy if the result isn't used. */
rtx this, which;
this = DECL_RTL (current_function_decl);
- if (GET_CODE (this) == MEM)
- this = XEXP (this, 0);
- else
- abort ();
+ gcc_assert (MEM_P (this));
+ this = XEXP (this, 0);
if (exitp)
which = profile_function_exit_libfunc;
bitpos = GET_MODE_BITSIZE (imode) - 1 - bitpos;
temp = copy_to_mode_reg (imode, temp);
temp = extract_bit_field (temp, 1, bitpos, 1,
- NULL_RTX, rmode, rmode,
- GET_MODE_SIZE (imode));
+ NULL_RTX, rmode, rmode);
}
else
{
break;
default:
- abort ();
+ gcc_unreachable ();
}
decl = build_decl (FUNCTION_DECL, id, TREE_TYPE (fn));
enum built_in_function fcode = DECL_FUNCTION_CODE (fndecl);
enum machine_mode target_mode = TYPE_MODE (TREE_TYPE (exp));
- /* Perform postincrements before expanding builtin functions. */
- emit_queue ();
-
if (DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_MD)
return targetm.expand_builtin (exp, target, subtarget, mode, ignore);
switch (fcode)
{
- case BUILT_IN_ABS:
- case BUILT_IN_LABS:
- case BUILT_IN_LLABS:
- case BUILT_IN_IMAXABS:
- /* build_function_call changes these into ABS_EXPR. */
- abort ();
-
case BUILT_IN_FABS:
case BUILT_IN_FABSF:
case BUILT_IN_FABSL:
return target;
break;
+ /* Just do a normal library call if we were unable to fold
+ the values. */
case BUILT_IN_CABS:
case BUILT_IN_CABSF:
case BUILT_IN_CABSL:
- if (flag_unsafe_math_optimizations)
- {
- target = expand_builtin_cabs (arglist, target);
- if (target)
- return target;
- }
break;
- case BUILT_IN_CONJ:
- case BUILT_IN_CONJF:
- case BUILT_IN_CONJL:
- case BUILT_IN_CREAL:
- case BUILT_IN_CREALF:
- case BUILT_IN_CREALL:
- case BUILT_IN_CIMAG:
- case BUILT_IN_CIMAGF:
- case BUILT_IN_CIMAGL:
- /* expand_tree_builtin changes these into CONJ_EXPR, REALPART_EXPR
- and IMAGPART_EXPR. */
- abort ();
-
case BUILT_IN_EXP:
case BUILT_IN_EXPF:
case BUILT_IN_EXPL:
case BUILT_IN_NEARBYINT:
case BUILT_IN_NEARBYINTF:
case BUILT_IN_NEARBYINTL:
+ case BUILT_IN_RINT:
+ case BUILT_IN_RINTF:
+ case BUILT_IN_RINTL:
target = expand_builtin_mathfn (exp, target, subtarget);
if (target)
return target;
case BUILT_IN_AGGREGATE_INCOMING_ADDRESS:
if (arglist != 0
|| ! AGGREGATE_TYPE_P (TREE_TYPE (TREE_TYPE (current_function_decl)))
- || GET_CODE (DECL_RTL (DECL_RESULT (current_function_decl))) != MEM)
+ || !MEM_P (DECL_RTL (DECL_RESULT (current_function_decl))))
return const0_rtx;
else
return XEXP (DECL_RTL (DECL_RESULT (current_function_decl)), 0);
return target;
break;
- case BUILT_IN_STACK_ALLOC:
- expand_stack_alloc (TREE_VALUE (arglist),
- TREE_VALUE (TREE_CHAIN (arglist)));
- return const0_rtx;
-
case BUILT_IN_STACK_SAVE:
return expand_stack_save ();
case BUILT_IN_FFS:
case BUILT_IN_FFSL:
case BUILT_IN_FFSLL:
+ case BUILT_IN_FFSIMAX:
target = expand_builtin_unop (target_mode, arglist, target,
subtarget, ffs_optab);
if (target)
case BUILT_IN_CLZ:
case BUILT_IN_CLZL:
case BUILT_IN_CLZLL:
+ case BUILT_IN_CLZIMAX:
target = expand_builtin_unop (target_mode, arglist, target,
subtarget, clz_optab);
if (target)
case BUILT_IN_CTZ:
case BUILT_IN_CTZL:
case BUILT_IN_CTZLL:
+ case BUILT_IN_CTZIMAX:
target = expand_builtin_unop (target_mode, arglist, target,
subtarget, ctz_optab);
if (target)
case BUILT_IN_POPCOUNT:
case BUILT_IN_POPCOUNTL:
case BUILT_IN_POPCOUNTLL:
+ case BUILT_IN_POPCOUNTIMAX:
target = expand_builtin_unop (target_mode, arglist, target,
subtarget, popcount_optab);
if (target)
case BUILT_IN_PARITY:
case BUILT_IN_PARITYL:
case BUILT_IN_PARITYLL:
+ case BUILT_IN_PARITYIMAX:
target = expand_builtin_unop (target_mode, arglist, target,
subtarget, parity_optab);
if (target)
break;
default: /* just do library call, if unknown builtin */
- if (!DECL_ASSEMBLER_NAME_SET_P (fndecl))
- error ("built-in function `%s' not currently supported",
- IDENTIFIER_POINTER (DECL_NAME (fndecl)));
+ break;
}
/* The switch statement above can drop through to cause the function
fold_builtin_classify_type (tree arglist)
{
if (arglist == 0)
- return build_int_2 (no_type_class, 0);
+ return build_int_cst (NULL_TREE, no_type_class);
- return build_int_2 (type_to_class (TREE_TYPE (TREE_VALUE (arglist))), 0);
+ return build_int_cst (NULL_TREE,
+ type_to_class (TREE_TYPE (TREE_VALUE (arglist))));
}
/* Fold a call to __builtin_inf or __builtin_huge_val. */
&& real_zerop (TREE_OPERAND (arg, 1)))
return fold (build1 (ABS_EXPR, type, TREE_OPERAND (arg, 0)));
- if (flag_unsafe_math_optimizations)
+ /* Don't do this when optimizing for size. */
+ if (flag_unsafe_math_optimizations
+ && optimize && !optimize_size)
{
tree sqrtfn = mathfn_built_in (type, BUILT_IN_SQRT);
real_round (&r, TYPE_MODE (ftype), &x);
REAL_VALUE_TO_INT (&lo, &hi, r);
- result = build_int_2 (lo, hi);
+ result = build_int_cst_wide (NULL_TREE, lo, hi);
if (int_fits_type_p (result, itype))
return fold_convert (itype, result);
}
{
HOST_WIDE_INT hi, width, result;
unsigned HOST_WIDE_INT lo;
- tree type, t;
+ tree type;
type = TREE_TYPE (arg);
width = TYPE_PRECISION (type);
break;
default:
- abort();
+ gcc_unreachable ();
}
- t = build_int_2 (result, 0);
- TREE_TYPE (t) = TREE_TYPE (exp);
- return t;
+ return build_int_cst (TREE_TYPE (exp), result);
}
return NULL_TREE;
return 0;
}
-/* Fold function call to builtin strcpy. Return
- NULL_TREE if no simplification can be made. */
+/* Fold function call to builtin strcpy. If LEN is not NULL, it represents
+ the length of the string to be copied. Return NULL_TREE if no
+ simplification can be made. */
-static tree
-fold_builtin_strcpy (tree exp)
+tree
+fold_builtin_strcpy (tree exp, tree len)
{
tree arglist = TREE_OPERAND (exp, 1);
- tree dest, src;
+ tree dest, src, fn;
if (!validate_arglist (arglist,
POINTER_TYPE, POINTER_TYPE, VOID_TYPE))
if (operand_equal_p (src, dest, 0))
return fold_convert (TREE_TYPE (exp), dest);
- return 0;
+ if (optimize_size)
+ return 0;
+
+ fn = implicit_built_in_decls[BUILT_IN_MEMCPY];
+ if (!fn)
+ return 0;
+
+ if (!len)
+ {
+ len = c_strlen (src, 1);
+ if (! len || TREE_SIDE_EFFECTS (len))
+ return 0;
+ }
+
+ len = size_binop (PLUS_EXPR, len, ssize_int (1));
+ arglist = build_tree_list (NULL_TREE, len);
+ arglist = tree_cons (NULL_TREE, src, arglist);
+ arglist = tree_cons (NULL_TREE, dest, arglist);
+ return fold_convert (TREE_TYPE (exp),
+ build_function_call_expr (fn, arglist));
}
-/* Fold function call to builtin strncpy. Return
- NULL_TREE if no simplification can be made. */
+/* Fold function call to builtin strncpy. If SLEN is not NULL, it represents
+ the length of the source string. Return NULL_TREE if no simplification
+ can be made. */
-static tree
-fold_builtin_strncpy (tree exp)
+tree
+fold_builtin_strncpy (tree exp, tree slen)
{
tree arglist = TREE_OPERAND (exp, 1);
- tree dest, src, len;
+ tree dest, src, len, fn;
if (!validate_arglist (arglist,
POINTER_TYPE, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE))
if (integer_zerop (len))
return omit_one_operand (TREE_TYPE (exp), dest, src);
- return 0;
-}
-
-/* Fold function call to builtin memcmp. Return
- NULL_TREE if no simplification can be made. */
+ /* We can't compare slen with len as constants below if len is not a
+ constant. */
+ if (len == 0 || TREE_CODE (len) != INTEGER_CST)
+ return 0;
-static tree
-fold_builtin_memcmp (tree exp)
-{
- tree arglist = TREE_OPERAND (exp, 1);
- tree arg1, arg2, len;
+ if (!slen)
+ slen = c_strlen (src, 1);
- if (!validate_arglist (arglist,
- POINTER_TYPE, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE))
+ /* Now, we must be passed a constant src ptr parameter. */
+ if (slen == 0 || TREE_CODE (slen) != INTEGER_CST)
return 0;
- arg1 = TREE_VALUE (arglist);
- arg2 = TREE_VALUE (TREE_CHAIN (arglist));
- len = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
-
- /* If the LEN parameter is zero, return zero. */
- if (integer_zerop (len))
- {
- tree temp = omit_one_operand (TREE_TYPE (exp), integer_zero_node, arg2);
- return omit_one_operand (TREE_TYPE (exp), temp, arg1);
- }
+ slen = size_binop (PLUS_EXPR, slen, ssize_int (1));
- /* If ARG1 and ARG2 are the same (and not volatile), return zero. */
- if (operand_equal_p (arg1, arg2, 0))
- return omit_one_operand (TREE_TYPE (exp), integer_zero_node, len);
+ /* We do not support simplification of this case, though we do
+ support it when expanding trees into RTL. */
+ /* FIXME: generate a call to __builtin_memset. */
+ if (tree_int_cst_lt (slen, len))
+ return 0;
- return 0;
+ /* OK transform into builtin memcpy. */
+ fn = implicit_built_in_decls[BUILT_IN_MEMCPY];
+ if (!fn)
+ return 0;
+ return fold_convert (TREE_TYPE (exp),
+ build_function_call_expr (fn, arglist));
}
-/* Fold function call to builtin strcmp. Return
- NULL_TREE if no simplification can be made. */
+/* Fold function call to builtin strchr and strrchr.
+ Return NULL_TREE if no simplification can be made. */
static tree
-fold_builtin_strcmp (tree exp)
+fold_builtin_strchr (tree exp, bool actually_strrchr)
{
tree arglist = TREE_OPERAND (exp, 1);
- tree arg1, arg2;
- const char *p1, *p2;
-
- if (!validate_arglist (arglist,
- POINTER_TYPE, POINTER_TYPE, VOID_TYPE))
+ if (!validate_arglist (arglist, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE))
return 0;
+ else
+ {
+ tree s1 = TREE_VALUE (arglist), s2 = TREE_VALUE (TREE_CHAIN (arglist));
+ const char *p1;
- arg1 = TREE_VALUE (arglist);
- arg2 = TREE_VALUE (TREE_CHAIN (arglist));
+ if (TREE_CODE (s2) != INTEGER_CST)
+ return 0;
- /* If ARG1 and ARG2 are the same (and not volatile), return zero. */
+ p1 = c_getstr (s1);
+ if (p1 != NULL)
+ {
+ char c;
+ const char *r;
+
+ if (target_char_cast (s2, &c))
+ return 0;
+
+ r = actually_strrchr ? strrchr (p1, c) : strchr (p1, c);
+
+ if (r == NULL)
+ return build_int_cst (TREE_TYPE (s1), 0);
+
+ /* Return an offset into the constant string argument. */
+ return fold (build2 (PLUS_EXPR, TREE_TYPE (s1),
+ s1, build_int_cst (TREE_TYPE (s1), r - p1)));
+ }
+
+ if (actually_strrchr)
+ {
+ tree fn;
+
+ if (!integer_zerop (s2))
+ return 0;
+
+ fn = implicit_built_in_decls[BUILT_IN_STRCHR];
+ if (!fn)
+ return 0;
+
+ /* Transform strrchr(s1, '\0') to strchr(s1, '\0'). */
+ return build_function_call_expr (fn, arglist);
+ }
+
+ return 0;
+ }
+}
+
+/* Fold function call to builtin memcmp. Return
+ NULL_TREE if no simplification can be made. */
+
+static tree
+fold_builtin_memcmp (tree arglist)
+{
+ tree arg1, arg2, len;
+ const char *p1, *p2;
+
+ if (!validate_arglist (arglist,
+ POINTER_TYPE, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE))
+ return 0;
+
+ arg1 = TREE_VALUE (arglist);
+ arg2 = TREE_VALUE (TREE_CHAIN (arglist));
+ len = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
+
+ /* If the LEN parameter is zero, return zero. */
+ if (integer_zerop (len))
+ return omit_two_operands (integer_type_node, integer_zero_node,
+ arg1, arg2);
+
+ /* If ARG1 and ARG2 are the same (and not volatile), return zero. */
+ if (operand_equal_p (arg1, arg2, 0))
+ return omit_one_operand (integer_type_node, integer_zero_node, len);
+
+ p1 = c_getstr (arg1);
+ p2 = c_getstr (arg2);
+
+ /* If all arguments are constant, and the value of len is not greater
+ than the lengths of arg1 and arg2, evaluate at compile-time. */
+ if (host_integerp (len, 1) && p1 && p2
+ && compare_tree_int (len, strlen (p1) + 1) <= 0
+ && compare_tree_int (len, strlen (p2) + 1) <= 0)
+ {
+ const int r = memcmp (p1, p2, tree_low_cst (len, 1));
+
+ if (r > 0)
+ return integer_one_node;
+ else if (r < 0)
+ return integer_minus_one_node;
+ else
+ return integer_zero_node;
+ }
+
+ /* If len parameter is one, return an expression corresponding to
+ (*(const unsigned char*)arg1 - (const unsigned char*)arg2). */
+ if (host_integerp (len, 1) && tree_low_cst (len, 1) == 1)
+ {
+ tree cst_uchar_node = build_type_variant (unsigned_char_type_node, 1, 0);
+ tree cst_uchar_ptr_node = build_pointer_type (cst_uchar_node);
+ tree ind1 = fold_convert (integer_type_node,
+ build1 (INDIRECT_REF, cst_uchar_node,
+ fold_convert (cst_uchar_ptr_node,
+ arg1)));
+ tree ind2 = fold_convert (integer_type_node,
+ build1 (INDIRECT_REF, cst_uchar_node,
+ fold_convert (cst_uchar_ptr_node,
+ arg2)));
+ return fold (build2 (MINUS_EXPR, integer_type_node, ind1, ind2));
+ }
+
+ return 0;
+}
+
+/* Fold function call to builtin strcmp. Return
+ NULL_TREE if no simplification can be made. */
+
+static tree
+fold_builtin_strcmp (tree arglist)
+{
+ tree arg1, arg2;
+ const char *p1, *p2;
+
+ if (!validate_arglist (arglist, POINTER_TYPE, POINTER_TYPE, VOID_TYPE))
+ return 0;
+
+ arg1 = TREE_VALUE (arglist);
+ arg2 = TREE_VALUE (TREE_CHAIN (arglist));
+
+ /* If ARG1 and ARG2 are the same (and not volatile), return zero. */
if (operand_equal_p (arg1, arg2, 0))
- return fold_convert (TREE_TYPE (exp), integer_zero_node);
+ return integer_zero_node;
p1 = c_getstr (arg1);
p2 = c_getstr (arg2);
if (p1 && p2)
{
- tree temp;
const int i = strcmp (p1, p2);
if (i < 0)
- temp = integer_minus_one_node;
+ return integer_minus_one_node;
else if (i > 0)
- temp = integer_one_node;
+ return integer_one_node;
else
- temp = integer_zero_node;
- return fold_convert (TREE_TYPE (exp), temp);
+ return integer_zero_node;
+ }
+
+ /* If the second arg is "", return *(const unsigned char*)arg1. */
+ if (p2 && *p2 == '\0')
+ {
+ tree cst_uchar_node = build_type_variant (unsigned_char_type_node, 1, 0);
+ tree cst_uchar_ptr_node = build_pointer_type (cst_uchar_node);
+ return fold_convert (integer_type_node,
+ build1 (INDIRECT_REF, cst_uchar_node,
+ fold_convert (cst_uchar_ptr_node,
+ arg1)));
+ }
+
+ /* If the first arg is "", return -*(const unsigned char*)arg2. */
+ if (p1 && *p1 == '\0')
+ {
+ tree cst_uchar_node = build_type_variant (unsigned_char_type_node, 1, 0);
+ tree cst_uchar_ptr_node = build_pointer_type (cst_uchar_node);
+ tree temp = fold_convert (integer_type_node,
+ build1 (INDIRECT_REF, cst_uchar_node,
+ fold_convert (cst_uchar_ptr_node,
+ arg2)));
+ return fold (build1 (NEGATE_EXPR, integer_type_node, temp));
}
return 0;
NULL_TREE if no simplification can be made. */
static tree
-fold_builtin_strncmp (tree exp)
+fold_builtin_strncmp (tree arglist)
{
- tree arglist = TREE_OPERAND (exp, 1);
tree arg1, arg2, len;
const char *p1, *p2;
/* If the LEN parameter is zero, return zero. */
if (integer_zerop (len))
- {
- tree temp = omit_one_operand (TREE_TYPE (exp), integer_zero_node, arg2);
- return omit_one_operand (TREE_TYPE (exp), temp, arg1);
- }
+ return omit_two_operands (integer_type_node, integer_zero_node,
+ arg1, arg2);
/* If ARG1 and ARG2 are the same (and not volatile), return zero. */
if (operand_equal_p (arg1, arg2, 0))
- return omit_one_operand (TREE_TYPE (exp), integer_zero_node, len);
+ return omit_one_operand (integer_type_node, integer_zero_node, len);
p1 = c_getstr (arg1);
p2 = c_getstr (arg2);
if (host_integerp (len, 1) && p1 && p2)
{
- tree temp;
const int i = strncmp (p1, p2, tree_low_cst (len, 1));
- if (i < 0)
- temp = integer_minus_one_node;
- else if (i > 0)
- temp = integer_one_node;
+ if (i > 0)
+ return integer_one_node;
+ else if (i < 0)
+ return integer_minus_one_node;
else
- temp = integer_zero_node;
- return fold_convert (TREE_TYPE (exp), temp);
+ return integer_zero_node;
+ }
+
+ /* If the second arg is "", and the length is greater than zero,
+ return *(const unsigned char*)arg1. */
+ if (p2 && *p2 == '\0'
+ && TREE_CODE (len) == INTEGER_CST
+ && tree_int_cst_sgn (len) == 1)
+ {
+ tree cst_uchar_node = build_type_variant (unsigned_char_type_node, 1, 0);
+ tree cst_uchar_ptr_node = build_pointer_type (cst_uchar_node);
+ return fold_convert (integer_type_node,
+ build1 (INDIRECT_REF, cst_uchar_node,
+ fold_convert (cst_uchar_ptr_node,
+ arg1)));
+ }
+
+ /* If the first arg is "", and the length is greater than zero,
+ return -*(const unsigned char*)arg2. */
+ if (p1 && *p1 == '\0'
+ && TREE_CODE (len) == INTEGER_CST
+ && tree_int_cst_sgn (len) == 1)
+ {
+ tree cst_uchar_node = build_type_variant (unsigned_char_type_node, 1, 0);
+ tree cst_uchar_ptr_node = build_pointer_type (cst_uchar_node);
+ tree temp = fold_convert (integer_type_node,
+ build1 (INDIRECT_REF, cst_uchar_node,
+ fold_convert (cst_uchar_ptr_node,
+ arg2)));
+ return fold (build1 (NEGATE_EXPR, integer_type_node, temp));
+ }
+
+ /* If len parameter is one, return an expression corresponding to
+ (*(const unsigned char*)arg1 - (const unsigned char*)arg2). */
+ if (host_integerp (len, 1) && tree_low_cst (len, 1) == 1)
+ {
+ tree cst_uchar_node = build_type_variant (unsigned_char_type_node, 1, 0);
+ tree cst_uchar_ptr_node = build_pointer_type (cst_uchar_node);
+ tree ind1 = fold_convert (integer_type_node,
+ build1 (INDIRECT_REF, cst_uchar_node,
+ fold_convert (cst_uchar_ptr_node,
+ arg1)));
+ tree ind2 = fold_convert (integer_type_node,
+ build1 (INDIRECT_REF, cst_uchar_node,
+ fold_convert (cst_uchar_ptr_node,
+ arg2)));
+ return fold (build2 (MINUS_EXPR, integer_type_node, ind1, ind2));
}
return 0;
return NULL_TREE;
}
+/* Fold function call to builtin copysign, copysignf or copysignl.
+ Return NULL_TREE if no simplification can be made. */
+
+static tree
+fold_builtin_copysign (tree arglist, tree type)
+{
+ tree arg1, arg2;
+
+ if (!validate_arglist (arglist, REAL_TYPE, REAL_TYPE, VOID_TYPE))
+ return NULL_TREE;
+
+ arg1 = TREE_VALUE (arglist);
+ arg2 = TREE_VALUE (TREE_CHAIN (arglist));
+
+ /* copysign(X,X) is X. */
+ if (operand_equal_p (arg1, arg2, 0))
+ return fold_convert (type, arg1);
+
+ /* If ARG1 and ARG2 are compile-time constants, determine the result. */
+ if (TREE_CODE (arg1) == REAL_CST
+ && TREE_CODE (arg2) == REAL_CST
+ && !TREE_CONSTANT_OVERFLOW (arg1)
+ && !TREE_CONSTANT_OVERFLOW (arg2))
+ {
+ REAL_VALUE_TYPE c1, c2;
+
+ c1 = TREE_REAL_CST (arg1);
+ c2 = TREE_REAL_CST (arg2);
+ real_copysign (&c1, &c2);
+ return build_real (type, c1);
+ c1.sign = c2.sign;
+ }
+
+ /* copysign(X, Y) is fabs(X) when Y is always non-negative.
+ Remember to evaluate Y for side-effects. */
+ if (tree_expr_nonnegative_p (arg2))
+ return omit_one_operand (type,
+ fold (build1 (ABS_EXPR, type, arg1)),
+ arg2);
+
+ return NULL_TREE;
+}
+
/* Fold a call to builtin isascii. */
static tree
{
/* Transform isascii(c) -> ((c & ~0x7f) == 0). */
tree arg = TREE_VALUE (arglist);
-
+
+ arg = build2 (BIT_AND_EXPR, integer_type_node, arg,
+ build_int_cst (NULL_TREE,
+ ~ (unsigned HOST_WIDE_INT) 0x7f));
arg = fold (build2 (EQ_EXPR, integer_type_node,
- build2 (BIT_AND_EXPR, integer_type_node, arg,
- build_int_2 (~ (unsigned HOST_WIDE_INT) 0x7f,
- ~ (HOST_WIDE_INT) 0)),
- integer_zero_node));
-
+ arg, integer_zero_node));
+
if (in_gimple_form && !TREE_CONSTANT (arg))
return NULL_TREE;
else
{
/* Transform toascii(c) -> (c & 0x7f). */
tree arg = TREE_VALUE (arglist);
-
+
return fold (build2 (BIT_AND_EXPR, integer_type_node, arg,
- build_int_2 (0x7f, 0)));
+ build_int_cst (NULL_TREE, 0x7f)));
}
}
tree arg = TREE_VALUE (arglist);
arg = fold_convert (unsigned_type_node, arg);
arg = build2 (MINUS_EXPR, unsigned_type_node, arg,
- fold_convert (unsigned_type_node,
- build_int_2 (TARGET_DIGIT0, 0)));
+ build_int_cst (unsigned_type_node, TARGET_DIGIT0));
arg = build2 (LE_EXPR, integer_type_node, arg,
- fold_convert (unsigned_type_node, build_int_2 (9, 0)));
+ build_int_cst (unsigned_type_node, 9));
arg = fold (arg);
if (in_gimple_form && !TREE_CONSTANT (arg))
return NULL_TREE;
}
}
-/* Used by constant folding to eliminate some builtin calls early. EXP is
- the CALL_EXPR of a call to a builtin function. */
+/* Fold a call to fabs, fabsf or fabsl. */
+
+static tree
+fold_builtin_fabs (tree arglist, tree type)
+{
+ tree arg;
+
+ if (!validate_arglist (arglist, REAL_TYPE, VOID_TYPE))
+ return 0;
+
+ arg = TREE_VALUE (arglist);
+ if (TREE_CODE (arg) == REAL_CST)
+ return fold_abs_const (arg, type);
+ return fold (build1 (ABS_EXPR, type, arg));
+}
+
+/* Fold a call to abs, labs, llabs or imaxabs. */
+
+static tree
+fold_builtin_abs (tree arglist, tree type)
+{
+ tree arg;
+
+ if (!validate_arglist (arglist, INTEGER_TYPE, VOID_TYPE))
+ return 0;
+
+ arg = TREE_VALUE (arglist);
+ if (TREE_CODE (arg) == INTEGER_CST)
+ return fold_abs_const (arg, type);
+ return fold (build1 (ABS_EXPR, type, arg));
+}
+
+/* Fold a call to __builtin_isnan(), __builtin_isinf, __builtin_finite.
+ EXP is the CALL_EXPR for the call. */
+
+static tree
+fold_builtin_classify (tree exp, int builtin_index)
+{
+ tree fndecl = get_callee_fndecl (exp);
+ tree arglist = TREE_OPERAND (exp, 1);
+ tree type = TREE_TYPE (TREE_TYPE (fndecl));
+ tree arg;
+ REAL_VALUE_TYPE r;
+
+ if (!validate_arglist (arglist, REAL_TYPE, VOID_TYPE))
+ {
+ /* Check that we have exactly one argument. */
+ if (arglist == 0)
+ {
+ error ("too few arguments to function `%s'",
+ IDENTIFIER_POINTER (DECL_NAME (fndecl)));
+ return error_mark_node;
+ }
+ else if (TREE_CHAIN (arglist) != 0)
+ {
+ error ("too many arguments to function `%s'",
+ IDENTIFIER_POINTER (DECL_NAME (fndecl)));
+ return error_mark_node;
+ }
+ else
+ {
+ error ("non-floating-point argument to function `%s'",
+ IDENTIFIER_POINTER (DECL_NAME (fndecl)));
+ return error_mark_node;
+ }
+ }
+
+ arg = TREE_VALUE (arglist);
+ switch (builtin_index)
+ {
+ case BUILT_IN_ISINF:
+ if (!MODE_HAS_INFINITIES (TYPE_MODE (TREE_TYPE (arg))))
+ return omit_one_operand (type, integer_zero_node, arg);
+
+ if (TREE_CODE (arg) == REAL_CST)
+ {
+ r = TREE_REAL_CST (arg);
+ if (real_isinf (&r))
+ return real_compare (GT_EXPR, &r, &dconst0)
+ ? integer_one_node : integer_minus_one_node;
+ else
+ return integer_zero_node;
+ }
+
+ return NULL_TREE;
+
+ case BUILT_IN_FINITE:
+ if (!MODE_HAS_NANS (TYPE_MODE (TREE_TYPE (arg)))
+ && !MODE_HAS_INFINITIES (TYPE_MODE (TREE_TYPE (arg))))
+ return omit_one_operand (type, integer_zero_node, arg);
+
+ if (TREE_CODE (arg) == REAL_CST)
+ {
+ r = TREE_REAL_CST (arg);
+ return real_isinf (&r) || real_isnan (&r)
+ ? integer_zero_node : integer_one_node;
+ }
+
+ return NULL_TREE;
+
+ case BUILT_IN_ISNAN:
+ if (!MODE_HAS_NANS (TYPE_MODE (TREE_TYPE (arg))))
+ return omit_one_operand (type, integer_zero_node, arg);
+
+ if (TREE_CODE (arg) == REAL_CST)
+ {
+ r = TREE_REAL_CST (arg);
+ return real_isnan (&r) ? integer_one_node : integer_zero_node;
+ }
+
+ arg = builtin_save_expr (arg);
+ return fold (build2 (UNORDERED_EXPR, type, arg, arg));
+
+ default:
+ gcc_unreachable ();
+ }
+}
+
+/* Fold a call to an unordered comparison function such as
+ __builtin_isgreater(). EXP is the CALL_EXPR for the call.
+ UNORDERED_CODE and ORDERED_CODE are comparison codes that give
+ the opposite of the desired result. UNORDERED_CODE is used
+ for modes that can hold NaNs and ORDERED_CODE is used for
+ the rest. */
+
+static tree
+fold_builtin_unordered_cmp (tree exp,
+ enum tree_code unordered_code,
+ enum tree_code ordered_code)
+{
+ tree fndecl = get_callee_fndecl (exp);
+ tree arglist = TREE_OPERAND (exp, 1);
+ tree type = TREE_TYPE (TREE_TYPE (fndecl));
+ enum tree_code code;
+ tree arg0, arg1;
+
+ if (!validate_arglist (arglist, REAL_TYPE, REAL_TYPE, VOID_TYPE))
+ {
+ enum tree_code code0, code1;
+ tree type0, type1;
+ tree cmp_type = 0;
+
+ /* Check that we have exactly two arguments. */
+ if (arglist == 0 || TREE_CHAIN (arglist) == 0)
+ {
+ error ("too few arguments to function `%s'",
+ IDENTIFIER_POINTER (DECL_NAME (fndecl)));
+ return error_mark_node;
+ }
+ else if (TREE_CHAIN (TREE_CHAIN (arglist)) != 0)
+ {
+ error ("too many arguments to function `%s'",
+ IDENTIFIER_POINTER (DECL_NAME (fndecl)));
+ return error_mark_node;
+ }
+
+ arg0 = TREE_VALUE (arglist);
+ arg1 = TREE_VALUE (TREE_CHAIN (arglist));
+
+ type0 = TREE_TYPE (arg0);
+ type1 = TREE_TYPE (arg1);
+
+ code0 = TREE_CODE (type0);
+ code1 = TREE_CODE (type1);
+
+ if (code0 == REAL_TYPE && code1 == REAL_TYPE)
+ /* Choose the wider of two real types. */
+ cmp_type = TYPE_PRECISION (type0) >= TYPE_PRECISION (type1)
+ ? type0 : type1;
+ else if (code0 == REAL_TYPE && code1 == INTEGER_TYPE)
+ cmp_type = type0;
+ else if (code0 == INTEGER_TYPE && code1 == REAL_TYPE)
+ cmp_type = type1;
+ else
+ {
+ error ("non-floating-point argument to function `%s'",
+ IDENTIFIER_POINTER (DECL_NAME (fndecl)));
+ return error_mark_node;
+ }
+
+ arg0 = fold_convert (cmp_type, arg0);
+ arg1 = fold_convert (cmp_type, arg1);
+ }
+ else
+ {
+ arg0 = TREE_VALUE (arglist);
+ arg1 = TREE_VALUE (TREE_CHAIN (arglist));
+ }
+
+ if (unordered_code == UNORDERED_EXPR)
+ {
+ if (!MODE_HAS_NANS (TYPE_MODE (TREE_TYPE (arg0))))
+ return omit_two_operands (type, integer_zero_node, arg0, arg1);
+ return fold (build2 (UNORDERED_EXPR, type, arg0, arg1));
+ }
+
+ code = MODE_HAS_NANS (TYPE_MODE (TREE_TYPE (arg0))) ? unordered_code
+ : ordered_code;
+ return fold (build1 (TRUTH_NOT_EXPR, type,
+ fold (build2 (code, type, arg0, arg1))));
+}
+
+/* Used by constant folding to simplify calls to builtin functions. EXP is
+ the CALL_EXPR of a call to a builtin function. IGNORE is true if the
+ result of the function call is ignored. This function returns NULL_TREE
+ if no simplification was possible. */
static tree
-fold_builtin_1 (tree exp)
+fold_builtin_1 (tree exp, bool ignore)
{
tree fndecl = get_callee_fndecl (exp);
tree arglist = TREE_OPERAND (exp, 1);
case BUILT_IN_FABS:
case BUILT_IN_FABSF:
case BUILT_IN_FABSL:
- if (validate_arglist (arglist, REAL_TYPE, VOID_TYPE))
- return fold (build1 (ABS_EXPR, type, TREE_VALUE (arglist)));
- break;
+ return fold_builtin_fabs (arglist, type);
+
+ case BUILT_IN_ABS:
+ case BUILT_IN_LABS:
+ case BUILT_IN_LLABS:
+ case BUILT_IN_IMAXABS:
+ return fold_builtin_abs (arglist, type);
+
+ case BUILT_IN_CONJ:
+ case BUILT_IN_CONJF:
+ case BUILT_IN_CONJL:
+ if (validate_arglist (arglist, COMPLEX_TYPE, VOID_TYPE))
+ return fold (build1 (CONJ_EXPR, type, TREE_VALUE (arglist)));
+ break;
+
+ case BUILT_IN_CREAL:
+ case BUILT_IN_CREALF:
+ case BUILT_IN_CREALL:
+ if (validate_arglist (arglist, COMPLEX_TYPE, VOID_TYPE))
+ return non_lvalue (fold (build1 (REALPART_EXPR, type,
+ TREE_VALUE (arglist))));
+ break;
+
+ case BUILT_IN_CIMAG:
+ case BUILT_IN_CIMAGF:
+ case BUILT_IN_CIMAGL:
+ if (validate_arglist (arglist, COMPLEX_TYPE, VOID_TYPE))
+ return non_lvalue (fold (build1 (IMAGPART_EXPR, type,
+ TREE_VALUE (arglist))));
+ break;
case BUILT_IN_CABS:
case BUILT_IN_CABSF:
if (flag_unsafe_math_optimizations && BUILTIN_ROOT_P (fcode))
{
tree powfn = mathfn_built_in (type, BUILT_IN_POW);
-
+
if (powfn)
{
tree arg0 = TREE_VALUE (TREE_OPERAND (arg, 1));
/* The inner root was either sqrt or cbrt. */
REAL_VALUE_TYPE dconstroot =
BUILTIN_SQRT_P (fcode) ? dconsthalf : dconstthird;
-
+
/* Adjust for the outer root. */
SET_REAL_EXP (&dconstroot, REAL_EXP (&dconstroot) - 1);
dconstroot = real_value_truncate (TYPE_MODE (type), dconstroot);
build_tree_list (NULL_TREE, tree_root));
return build_function_call_expr (powfn, arglist);
}
-
+
}
}
break;
case BUILT_IN_EXPF:
case BUILT_IN_EXPL:
return fold_builtin_exponent (exp, &dconste);
+
case BUILT_IN_EXP2:
case BUILT_IN_EXP2F:
case BUILT_IN_EXP2L:
return fold_builtin_exponent (exp, &dconst2);
+
case BUILT_IN_EXP10:
case BUILT_IN_EXP10F:
case BUILT_IN_EXP10L:
case BUILT_IN_POW10F:
case BUILT_IN_POW10L:
return fold_builtin_exponent (exp, &dconst10);
+
case BUILT_IN_LOG:
case BUILT_IN_LOGF:
case BUILT_IN_LOGL:
return fold_builtin_logarithm (exp, &dconste);
- break;
+
case BUILT_IN_LOG2:
case BUILT_IN_LOG2F:
case BUILT_IN_LOG2L:
return fold_builtin_logarithm (exp, &dconst2);
- break;
+
case BUILT_IN_LOG10:
case BUILT_IN_LOG10F:
case BUILT_IN_LOG10L:
return fold_builtin_logarithm (exp, &dconst10);
- break;
case BUILT_IN_TAN:
case BUILT_IN_TANF:
return fold_builtin_memmove (exp);
case BUILT_IN_STRCPY:
- return fold_builtin_strcpy (exp);
+ return fold_builtin_strcpy (exp, NULL_TREE);
case BUILT_IN_STRNCPY:
- return fold_builtin_strncpy (exp);
+ return fold_builtin_strncpy (exp, NULL_TREE);
+
+ case BUILT_IN_INDEX:
+ case BUILT_IN_STRCHR:
+ return fold_builtin_strchr (exp, false);
+
+ case BUILT_IN_RINDEX:
+ case BUILT_IN_STRRCHR:
+ return fold_builtin_strchr (exp, true);
case BUILT_IN_MEMCMP:
- return fold_builtin_memcmp (exp);
+ return fold_builtin_memcmp (arglist);
case BUILT_IN_STRCMP:
- return fold_builtin_strcmp (exp);
+ return fold_builtin_strcmp (arglist);
case BUILT_IN_STRNCMP:
- return fold_builtin_strncmp (exp);
+ return fold_builtin_strncmp (arglist);
case BUILT_IN_SIGNBIT:
case BUILT_IN_SIGNBITF:
case BUILT_IN_ISDIGIT:
return fold_builtin_isdigit (arglist);
+ case BUILT_IN_COPYSIGN:
+ case BUILT_IN_COPYSIGNF:
+ case BUILT_IN_COPYSIGNL:
+ return fold_builtin_copysign (arglist, type);
+
+ case BUILT_IN_FINITE:
+ case BUILT_IN_FINITEF:
+ case BUILT_IN_FINITEL:
+ return fold_builtin_classify (exp, BUILT_IN_FINITE);
+
+ case BUILT_IN_ISINF:
+ case BUILT_IN_ISINFF:
+ case BUILT_IN_ISINFL:
+ return fold_builtin_classify (exp, BUILT_IN_ISINF);
+
+ case BUILT_IN_ISNAN:
+ case BUILT_IN_ISNANF:
+ case BUILT_IN_ISNANL:
+ return fold_builtin_classify (exp, BUILT_IN_ISNAN);
+
+ case BUILT_IN_ISGREATER:
+ return fold_builtin_unordered_cmp (exp, UNLE_EXPR, LE_EXPR);
+ case BUILT_IN_ISGREATEREQUAL:
+ return fold_builtin_unordered_cmp (exp, UNLT_EXPR, LT_EXPR);
+ case BUILT_IN_ISLESS:
+ return fold_builtin_unordered_cmp (exp, UNGE_EXPR, GE_EXPR);
+ case BUILT_IN_ISLESSEQUAL:
+ return fold_builtin_unordered_cmp (exp, UNGT_EXPR, GT_EXPR);
+ case BUILT_IN_ISLESSGREATER:
+ return fold_builtin_unordered_cmp (exp, UNEQ_EXPR, EQ_EXPR);
+ case BUILT_IN_ISUNORDERED:
+ return fold_builtin_unordered_cmp (exp, UNORDERED_EXPR, NOP_EXPR);
+
+ case BUILT_IN_FPUTS:
+ return fold_builtin_fputs (arglist, ignore, false, NULL_TREE);
+
+ case BUILT_IN_FPUTS_UNLOCKED:
+ return fold_builtin_fputs (arglist, ignore, true, NULL_TREE);
+
default:
break;
}
}
/* A wrapper function for builtin folding that prevents warnings for
- "statement without effect" and the like, caused by removing the
+ "statement without effect" and the like, caused by removing the
call node earlier than the warning is generated. */
tree
-fold_builtin (tree exp)
+fold_builtin (tree exp, bool ignore)
{
- exp = fold_builtin_1 (exp);
+ exp = fold_builtin_1 (exp, ignore);
if (exp)
{
/* ??? Don't clobber shared nodes such as integer_zero_node. */
/* Make sure we call decl_readonly_section only for trees it
can handle (since it returns true for everything it doesn't
understand). */
- if (TREE_CODE (exp) == STRING_CST
+ if (TREE_CODE (exp) == STRING_CST
|| TREE_CODE (exp) == CONSTRUCTOR
|| (TREE_CODE (exp) == VAR_DECL && TREE_STATIC (exp)))
return decl_readonly_section (exp, 0);
switch (fcode)
{
case BUILT_IN_FPUTS:
- val = simplify_builtin_fputs (arglist, ignore, 0, NULL_TREE);
+ val = fold_builtin_fputs (arglist, ignore, false, NULL_TREE);
break;
case BUILT_IN_FPUTS_UNLOCKED:
- val = simplify_builtin_fputs (arglist, ignore, 1, NULL_TREE);
+ val = fold_builtin_fputs (arglist, ignore, true, NULL_TREE);
break;
case BUILT_IN_STRSTR:
val = simplify_builtin_strstr (arglist);
val = simplify_builtin_strrchr (arglist);
break;
case BUILT_IN_STRCPY:
- val = simplify_builtin_strcpy (arglist, NULL_TREE);
+ val = fold_builtin_strcpy (exp, NULL_TREE);
break;
case BUILT_IN_STRNCPY:
- val = simplify_builtin_strncpy (arglist, NULL_TREE);
+ val = fold_builtin_strncpy (exp, NULL_TREE);
break;
case BUILT_IN_STRCMP:
- val = simplify_builtin_strcmp (arglist);
+ val = fold_builtin_strcmp (arglist);
break;
case BUILT_IN_STRNCMP:
- val = simplify_builtin_strncmp (arglist);
+ val = fold_builtin_strncmp (arglist);
break;
case BUILT_IN_STRPBRK:
val = simplify_builtin_strpbrk (arglist);
break;
case BUILT_IN_BCMP:
case BUILT_IN_MEMCMP:
- val = simplify_builtin_memcmp (arglist);
+ val = fold_builtin_memcmp (arglist);
break;
case BUILT_IN_VA_START:
simplify_builtin_va_start (arglist);
static tree
simplify_builtin_strstr (tree arglist)
{
- if (!validate_arglist (arglist, POINTER_TYPE, POINTER_TYPE, VOID_TYPE))
- return 0;
- else
- {
- tree s1 = TREE_VALUE (arglist), s2 = TREE_VALUE (TREE_CHAIN (arglist));
- tree fn;
- const char *p1, *p2;
-
- p2 = c_getstr (s2);
- if (p2 == NULL)
- return 0;
-
- p1 = c_getstr (s1);
- if (p1 != NULL)
- {
- const char *r = strstr (p1, p2);
-
- if (r == NULL)
- return fold_convert (TREE_TYPE (s1), integer_zero_node);
-
- /* Return an offset into the constant string argument. */
- return fold (build2 (PLUS_EXPR, TREE_TYPE (s1),
- s1, fold_convert (TREE_TYPE (s1),
- ssize_int (r - p1))));
- }
-
- if (p2[0] == '\0')
- return s1;
-
- if (p2[1] != '\0')
- return 0;
-
- fn = implicit_built_in_decls[BUILT_IN_STRCHR];
- if (!fn)
- return 0;
-
- /* New argument list transforming strstr(s1, s2) to
- strchr(s1, s2[0]). */
- arglist = build_tree_list (NULL_TREE, build_int_2 (p2[0], 0));
- arglist = tree_cons (NULL_TREE, s1, arglist);
- return build_function_call_expr (fn, arglist);
- }
-}
-
-/* Simplify a call to the strstr builtin.
-
- Return 0 if no simplification was possible, otherwise return the
- simplified form of the call as a tree.
-
- The simplified form may be a constant or other expression which
- computes the same value, but in a more efficient manner (including
- calls to other builtin functions).
-
- The call may contain arguments which need to be evaluated, but
- which are not useful to determine the result of the call. In
- this case we return a chain of COMPOUND_EXPRs. The LHS of each
- COMPOUND_EXPR will be an argument which must be evaluated.
- COMPOUND_EXPRs are chained through their RHS. The RHS of the last
- COMPOUND_EXPR in the chain will contain the tree for the simplified
- form of the builtin function call. */
-
-static tree
-simplify_builtin_strchr (tree arglist)
-{
- if (!validate_arglist (arglist, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE))
- return 0;
- else
- {
- tree s1 = TREE_VALUE (arglist), s2 = TREE_VALUE (TREE_CHAIN (arglist));
- const char *p1;
-
- if (TREE_CODE (s2) != INTEGER_CST)
- return 0;
-
- p1 = c_getstr (s1);
- if (p1 != NULL)
- {
- char c;
- const char *r;
-
- if (target_char_cast (s2, &c))
- return 0;
-
- r = strchr (p1, c);
-
- if (r == NULL)
- return fold_convert (TREE_TYPE (s1), integer_zero_node);
-
- /* Return an offset into the constant string argument. */
- return fold (build2 (PLUS_EXPR, TREE_TYPE (s1),
- s1, fold_convert (TREE_TYPE (s1),
- ssize_int (r - p1))));
- }
-
- /* FIXME: Should use here strchrM optab so that ports can optimize
- this. */
- return 0;
- }
-}
-
-/* Simplify a call to the strrchr builtin.
-
- Return 0 if no simplification was possible, otherwise return the
- simplified form of the call as a tree.
-
- The simplified form may be a constant or other expression which
- computes the same value, but in a more efficient manner (including
- calls to other builtin functions).
-
- The call may contain arguments which need to be evaluated, but
- which are not useful to determine the result of the call. In
- this case we return a chain of COMPOUND_EXPRs. The LHS of each
- COMPOUND_EXPR will be an argument which must be evaluated.
- COMPOUND_EXPRs are chained through their RHS. The RHS of the last
- COMPOUND_EXPR in the chain will contain the tree for the simplified
- form of the builtin function call. */
-
-static tree
-simplify_builtin_strrchr (tree arglist)
-{
- if (!validate_arglist (arglist, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE))
- return 0;
- else
- {
- tree s1 = TREE_VALUE (arglist), s2 = TREE_VALUE (TREE_CHAIN (arglist));
- tree fn;
- const char *p1;
-
- if (TREE_CODE (s2) != INTEGER_CST)
- return 0;
-
- p1 = c_getstr (s1);
- if (p1 != NULL)
- {
- char c;
- const char *r;
-
- if (target_char_cast (s2, &c))
- return 0;
-
- r = strrchr (p1, c);
-
- if (r == NULL)
- return fold_convert (TREE_TYPE (s1), integer_zero_node);
-
- /* Return an offset into the constant string argument. */
- return fold (build2 (PLUS_EXPR, TREE_TYPE (s1),
- s1, fold_convert (TREE_TYPE (s1),
- ssize_int (r - p1))));
- }
-
- if (! integer_zerop (s2))
- return 0;
-
- fn = implicit_built_in_decls[BUILT_IN_STRCHR];
- if (!fn)
- return 0;
-
- /* Transform strrchr(s1, '\0') to strchr(s1, '\0'). */
- return build_function_call_expr (fn, arglist);
- }
-}
-
-/* Simplify a call to the strpbrk builtin.
-
- Return 0 if no simplification was possible, otherwise return the
- simplified form of the call as a tree.
-
- The simplified form may be a constant or other expression which
- computes the same value, but in a more efficient manner (including
- calls to other builtin functions).
-
- The call may contain arguments which need to be evaluated, but
- which are not useful to determine the result of the call. In
- this case we return a chain of COMPOUND_EXPRs. The LHS of each
- COMPOUND_EXPR will be an argument which must be evaluated.
- COMPOUND_EXPRs are chained through their RHS. The RHS of the last
- COMPOUND_EXPR in the chain will contain the tree for the simplified
- form of the builtin function call. */
-
-static tree
-simplify_builtin_strpbrk (tree arglist)
-{
- if (!validate_arglist (arglist, POINTER_TYPE, POINTER_TYPE, VOID_TYPE))
- return 0;
- else
- {
- tree s1 = TREE_VALUE (arglist), s2 = TREE_VALUE (TREE_CHAIN (arglist));
- tree fn;
- const char *p1, *p2;
-
- p2 = c_getstr (s2);
- if (p2 == NULL)
- return 0;
-
- p1 = c_getstr (s1);
- if (p1 != NULL)
- {
- const char *r = strpbrk (p1, p2);
-
- if (r == NULL)
- return fold_convert (TREE_TYPE (s1), integer_zero_node);
-
- /* Return an offset into the constant string argument. */
- return fold (build2 (PLUS_EXPR, TREE_TYPE (s1),
- s1, fold_convert (TREE_TYPE (s1),
- ssize_int (r - p1))));
- }
-
- if (p2[0] == '\0')
- /* strpbrk(x, "") == NULL.
- Evaluate and ignore s1 in case it had side-effects. */
- return omit_one_operand (TREE_TYPE (s1), integer_zero_node, s1);
-
- if (p2[1] != '\0')
- return 0; /* Really call strpbrk. */
-
- fn = implicit_built_in_decls[BUILT_IN_STRCHR];
- if (!fn)
- return 0;
-
- /* New argument list transforming strpbrk(s1, s2) to
- strchr(s1, s2[0]). */
- arglist =
- build_tree_list (NULL_TREE, build_int_2 (p2[0], 0));
- arglist = tree_cons (NULL_TREE, s1, arglist);
- return build_function_call_expr (fn, arglist);
- }
-}
-
-/* Simplify a call to the strcpy builtin.
-
- Return 0 if no simplification was possible, otherwise return the
- simplified form of the call as a tree.
-
- The simplified form may be a constant or other expression which
- computes the same value, but in a more efficient manner (including
- calls to other builtin functions).
-
- The call may contain arguments which need to be evaluated, but
- which are not useful to determine the result of the call. In
- this case we return a chain of COMPOUND_EXPRs. The LHS of each
- COMPOUND_EXPR will be an argument which must be evaluated.
- COMPOUND_EXPRs are chained through their RHS. The RHS of the last
- COMPOUND_EXPR in the chain will contain the tree for the simplified
- form of the builtin function call. */
-
-tree
-simplify_builtin_strcpy (tree arglist, tree len)
-{
- tree fn, src, dst;
-
- if (!validate_arglist (arglist, POINTER_TYPE, POINTER_TYPE, VOID_TYPE))
- return 0;
-
- fn = implicit_built_in_decls[BUILT_IN_MEMCPY];
- if (!fn)
- return 0;
-
- src = TREE_VALUE (TREE_CHAIN (arglist));
- dst = TREE_VALUE (arglist);
-
- if (!len)
- {
- len = c_strlen (src, 1);
- if (!len || TREE_SIDE_EFFECTS (len))
- return 0;
- }
-
- len = size_binop (PLUS_EXPR, len, ssize_int (1));
- arglist = build_tree_list (NULL_TREE, len);
- arglist = tree_cons (NULL_TREE, src, arglist);
- arglist = tree_cons (NULL_TREE, dst, arglist);
- return build_function_call_expr (fn, arglist);
-}
-
-/* Simplify a call to the strncpy builtin.
-
- Return 0 if no simplification was possible, otherwise return the
- simplified form of the call as a tree.
-
- The simplified form may be a constant or other expression which
- computes the same value, but in a more efficient manner (including
- calls to other builtin functions).
-
- The call may contain arguments which need to be evaluated, but
- which are not useful to determine the result of the call. In
- this case we return a chain of COMPOUND_EXPRs. The LHS of each
- COMPOUND_EXPR will be an argument which must be evaluated.
- COMPOUND_EXPRs are chained through their RHS. The RHS of the last
- COMPOUND_EXPR in the chain will contain the tree for the simplified
- form of the builtin function call. */
-
-tree
-simplify_builtin_strncpy (tree arglist, tree slen)
-{
- if (!validate_arglist (arglist,
- POINTER_TYPE, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE))
+ if (!validate_arglist (arglist, POINTER_TYPE, POINTER_TYPE, VOID_TYPE))
return 0;
else
{
- tree len = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
+ tree s1 = TREE_VALUE (arglist), s2 = TREE_VALUE (TREE_CHAIN (arglist));
tree fn;
+ const char *p1, *p2;
- /* We must be passed a constant len parameter. */
- if (TREE_CODE (len) != INTEGER_CST)
+ p2 = c_getstr (s2);
+ if (p2 == NULL)
return 0;
- /* If the len parameter is zero, return the dst parameter. */
- if (integer_zerop (len))
- /* Evaluate and ignore the src argument in case it has
- side-effects and return the dst parameter. */
- return omit_one_operand (TREE_TYPE (TREE_VALUE (arglist)),
- TREE_VALUE (arglist),
- TREE_VALUE (TREE_CHAIN (arglist)));
+ p1 = c_getstr (s1);
+ if (p1 != NULL)
+ {
+ const char *r = strstr (p1, p2);
- if (!slen)
- slen = c_strlen (TREE_VALUE (TREE_CHAIN (arglist)), 0);
+ if (r == NULL)
+ return build_int_cst (TREE_TYPE (s1), 0);
- /* Now, we must be passed a constant src ptr parameter. */
- if (slen == 0 || TREE_CODE (slen) != INTEGER_CST)
- return 0;
+ /* Return an offset into the constant string argument. */
+ return fold (build2 (PLUS_EXPR, TREE_TYPE (s1),
+ s1, build_int_cst (TREE_TYPE (s1), r - p1)));
+ }
- slen = size_binop (PLUS_EXPR, slen, ssize_int (1));
+ if (p2[0] == '\0')
+ return s1;
- /* We do not support simplification of this case, though we do
- support it when expanding trees into RTL. */
- /* FIXME: generate a call to __builtin_memset. */
- if (tree_int_cst_lt (slen, len))
+ if (p2[1] != '\0')
return 0;
- /* OK transform into builtin memcpy. */
- fn = implicit_built_in_decls[BUILT_IN_MEMCPY];
+ fn = implicit_built_in_decls[BUILT_IN_STRCHR];
if (!fn)
return 0;
+
+ /* New argument list transforming strstr(s1, s2) to
+ strchr(s1, s2[0]). */
+ arglist = build_tree_list (NULL_TREE,
+ build_int_cst (NULL_TREE, p2[0]));
+ arglist = tree_cons (NULL_TREE, s1, arglist);
return build_function_call_expr (fn, arglist);
}
}
-/* Simplify a call to the memcmp builtin.
+/* Simplify a call to the strstr builtin.
Return 0 if no simplification was possible, otherwise return the
simplified form of the call as a tree.
form of the builtin function call. */
static tree
-simplify_builtin_memcmp (tree arglist)
+simplify_builtin_strchr (tree arglist)
{
- tree arg1, arg2, len;
- const char *p1, *p2;
-
- if (!validate_arglist (arglist,
- POINTER_TYPE, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE))
+ if (!validate_arglist (arglist, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE))
return 0;
+ else
+ {
+ tree s1 = TREE_VALUE (arglist), s2 = TREE_VALUE (TREE_CHAIN (arglist));
+ const char *p1;
- arg1 = TREE_VALUE (arglist);
- arg2 = TREE_VALUE (TREE_CHAIN (arglist));
- len = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
+ if (TREE_CODE (s2) != INTEGER_CST)
+ return 0;
- /* If the len parameter is zero, return zero. */
- if (host_integerp (len, 1) && tree_low_cst (len, 1) == 0)
- {
- /* Evaluate and ignore arg1 and arg2 in case they have
- side-effects. */
- return build2 (COMPOUND_EXPR, integer_type_node, arg1,
- build2 (COMPOUND_EXPR, integer_type_node,
- arg2, integer_zero_node));
- }
+ p1 = c_getstr (s1);
+ if (p1 != NULL)
+ {
+ char c;
+ const char *r;
- p1 = c_getstr (arg1);
- p2 = c_getstr (arg2);
+ if (target_char_cast (s2, &c))
+ return 0;
- /* If all arguments are constant, and the value of len is not greater
- than the lengths of arg1 and arg2, evaluate at compile-time. */
- if (host_integerp (len, 1) && p1 && p2
- && compare_tree_int (len, strlen (p1) + 1) <= 0
- && compare_tree_int (len, strlen (p2) + 1) <= 0)
- {
- const int r = memcmp (p1, p2, tree_low_cst (len, 1));
+ r = strchr (p1, c);
- return (r < 0
- ? integer_minus_one_node
- : (r > 0 ? integer_one_node : integer_zero_node));
- }
+ if (r == NULL)
+ return build_int_cst (TREE_TYPE (s1), 0);
- /* If len parameter is one, return an expression corresponding to
- (*(const unsigned char*)arg1 - (const unsigned char*)arg2). */
- if (host_integerp (len, 1) && tree_low_cst (len, 1) == 1)
- {
- tree cst_uchar_node = build_type_variant (unsigned_char_type_node, 1, 0);
- tree cst_uchar_ptr_node = build_pointer_type (cst_uchar_node);
- tree ind1 =
- fold (build1 (CONVERT_EXPR, integer_type_node,
- build1 (INDIRECT_REF, cst_uchar_node,
- build1 (NOP_EXPR, cst_uchar_ptr_node, arg1))));
- tree ind2 =
- fold (build1 (CONVERT_EXPR, integer_type_node,
- build1 (INDIRECT_REF, cst_uchar_node,
- build1 (NOP_EXPR, cst_uchar_ptr_node, arg2))));
- return fold (build2 (MINUS_EXPR, integer_type_node, ind1, ind2));
- }
+ /* Return an offset into the constant string argument. */
+ return fold (build2 (PLUS_EXPR, TREE_TYPE (s1),
+ s1, build_int_cst (TREE_TYPE (s1), r - p1)));
+ }
- return 0;
+ /* FIXME: Should use here strchrM optab so that ports can optimize
+ this. */
+ return 0;
+ }
}
-/* Simplify a call to the strcmp builtin.
+/* Simplify a call to the strrchr builtin.
Return 0 if no simplification was possible, otherwise return the
simplified form of the call as a tree.
form of the builtin function call. */
static tree
-simplify_builtin_strcmp (tree arglist)
+simplify_builtin_strrchr (tree arglist)
{
- tree arg1, arg2;
- const char *p1, *p2;
-
- if (!validate_arglist (arglist, POINTER_TYPE, POINTER_TYPE, VOID_TYPE))
+ if (!validate_arglist (arglist, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE))
return 0;
+ else
+ {
+ tree s1 = TREE_VALUE (arglist), s2 = TREE_VALUE (TREE_CHAIN (arglist));
+ tree fn;
+ const char *p1;
- arg1 = TREE_VALUE (arglist);
- arg2 = TREE_VALUE (TREE_CHAIN (arglist));
+ if (TREE_CODE (s2) != INTEGER_CST)
+ return 0;
- /* If both arguments are equal (and not volatile), return zero. */
- if (operand_equal_p (arg1, arg2, 0))
- return integer_zero_node;
+ p1 = c_getstr (s1);
+ if (p1 != NULL)
+ {
+ char c;
+ const char *r;
- p1 = c_getstr (arg1);
- p2 = c_getstr (arg2);
+ if (target_char_cast (s2, &c))
+ return 0;
- if (p1 && p2)
- {
- const int i = strcmp (p1, p2);
- return (i < 0
- ? integer_minus_one_node
- : (i > 0 ? integer_one_node : integer_zero_node));
- }
+ r = strrchr (p1, c);
- /* If either arg is "", return an expression corresponding to
- (*(const unsigned char*)arg1 - (const unsigned char*)arg2). */
- if ((p1 && *p1 == '\0') || (p2 && *p2 == '\0'))
- {
- tree cst_uchar_node = build_type_variant (unsigned_char_type_node, 1, 0);
- tree cst_uchar_ptr_node = build_pointer_type (cst_uchar_node);
- tree ind1 =
- fold (build1 (CONVERT_EXPR, integer_type_node,
- build1 (INDIRECT_REF, cst_uchar_node,
- build1 (NOP_EXPR, cst_uchar_ptr_node, arg1))));
- tree ind2 =
- fold (build1 (CONVERT_EXPR, integer_type_node,
- build1 (INDIRECT_REF, cst_uchar_node,
- build1 (NOP_EXPR, cst_uchar_ptr_node, arg2))));
- return fold (build2 (MINUS_EXPR, integer_type_node, ind1, ind2));
- }
+ if (r == NULL)
+ return build_int_cst (TREE_TYPE (s1), 0);
- return 0;
+ /* Return an offset into the constant string argument. */
+ return fold (build2 (PLUS_EXPR, TREE_TYPE (s1),
+ s1, build_int_cst (TREE_TYPE (s1), r - p1)));
+ }
+
+ if (! integer_zerop (s2))
+ return 0;
+
+ fn = implicit_built_in_decls[BUILT_IN_STRCHR];
+ if (!fn)
+ return 0;
+
+ /* Transform strrchr(s1, '\0') to strchr(s1, '\0'). */
+ return build_function_call_expr (fn, arglist);
+ }
}
-/* Simplify a call to the strncmp builtin.
+/* Simplify a call to the strpbrk builtin.
Return 0 if no simplification was possible, otherwise return the
simplified form of the call as a tree.
form of the builtin function call. */
static tree
-simplify_builtin_strncmp (tree arglist)
+simplify_builtin_strpbrk (tree arglist)
{
- tree arg1, arg2, arg3;
- const char *p1, *p2;
-
- if (!validate_arglist (arglist,
- POINTER_TYPE, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE))
+ if (!validate_arglist (arglist, POINTER_TYPE, POINTER_TYPE, VOID_TYPE))
return 0;
+ else
+ {
+ tree s1 = TREE_VALUE (arglist), s2 = TREE_VALUE (TREE_CHAIN (arglist));
+ tree fn;
+ const char *p1, *p2;
- arg1 = TREE_VALUE (arglist);
- arg2 = TREE_VALUE (TREE_CHAIN (arglist));
- arg3 = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
+ p2 = c_getstr (s2);
+ if (p2 == NULL)
+ return 0;
- /* If the len parameter is zero, return zero. */
- if (integer_zerop (arg3))
- {
- /* Evaluate and ignore arg1 and arg2 in case they have
- side-effects. */
- return build2 (COMPOUND_EXPR, integer_type_node, arg1,
- build2 (COMPOUND_EXPR, integer_type_node,
- arg2, integer_zero_node));
- }
+ p1 = c_getstr (s1);
+ if (p1 != NULL)
+ {
+ const char *r = strpbrk (p1, p2);
- /* If arg1 and arg2 are equal (and not volatile), return zero. */
- if (operand_equal_p (arg1, arg2, 0))
- /* Evaluate and ignore arg3 in case it has side-effects. */
- return omit_one_operand (integer_type_node, integer_zero_node, arg3);
+ if (r == NULL)
+ return build_int_cst (TREE_TYPE (s1), 0);
- p1 = c_getstr (arg1);
- p2 = c_getstr (arg2);
+ /* Return an offset into the constant string argument. */
+ return fold (build2 (PLUS_EXPR, TREE_TYPE (s1),
+ s1, build_int_cst (TREE_TYPE (s1), r - p1)));
+ }
- /* If all arguments are constant, evaluate at compile-time. */
- if (host_integerp (arg3, 1) && p1 && p2)
- {
- const int r = strncmp (p1, p2, tree_low_cst (arg3, 1));
- return (r < 0
- ? integer_minus_one_node
- : (r > 0 ? integer_one_node : integer_zero_node));
- }
+ if (p2[0] == '\0')
+ /* strpbrk(x, "") == NULL.
+ Evaluate and ignore s1 in case it had side-effects. */
+ return omit_one_operand (TREE_TYPE (s1), integer_zero_node, s1);
- /* If len == 1 or (either string parameter is "" and (len >= 1)),
- return (*(const u_char*)arg1 - *(const u_char*)arg2). */
- if (host_integerp (arg3, 1)
- && (tree_low_cst (arg3, 1) == 1
- || (tree_low_cst (arg3, 1) > 1
- && ((p1 && *p1 == '\0') || (p2 && *p2 == '\0')))))
- {
- tree cst_uchar_node = build_type_variant (unsigned_char_type_node, 1, 0);
- tree cst_uchar_ptr_node = build_pointer_type (cst_uchar_node);
- tree ind1 =
- fold (build1 (CONVERT_EXPR, integer_type_node,
- build1 (INDIRECT_REF, cst_uchar_node,
- build1 (NOP_EXPR, cst_uchar_ptr_node, arg1))));
- tree ind2 =
- fold (build1 (CONVERT_EXPR, integer_type_node,
- build1 (INDIRECT_REF, cst_uchar_node,
- build1 (NOP_EXPR, cst_uchar_ptr_node, arg2))));
- return fold (build2 (MINUS_EXPR, integer_type_node, ind1, ind2));
- }
+ if (p2[1] != '\0')
+ return 0; /* Really call strpbrk. */
- return 0;
+ fn = implicit_built_in_decls[BUILT_IN_STRCHR];
+ if (!fn)
+ return 0;
+
+ /* New argument list transforming strpbrk(s1, s2) to
+ strchr(s1, s2[0]). */
+ arglist = build_tree_list (NULL_TREE,
+ build_int_cst (NULL_TREE, p2[0]));
+ arglist = tree_cons (NULL_TREE, s1, arglist);
+ return build_function_call_expr (fn, arglist);
+ }
}
/* Simplify a call to the strcat builtin.
/* If the requested length is zero, or the src parameter string
length is zero, return the dst parameter. */
if (integer_zerop (len) || (p && *p == '\0'))
- return build2 (COMPOUND_EXPR, TREE_TYPE (dst), src,
- build2 (COMPOUND_EXPR, integer_type_node, len, dst));
+ return omit_two_operands (TREE_TYPE (dst), dst, src, len);
/* If the requested len is greater than or equal to the string
length, call strcat. */
/* If either argument is "", return 0. */
if ((p1 && *p1 == '\0') || (p2 && *p2 == '\0'))
- {
- /* Evaluate and ignore both arguments in case either one has
- side-effects. */
- return build2 (COMPOUND_EXPR, integer_type_node, s1,
- build2 (COMPOUND_EXPR, integer_type_node,
- s2, integer_zero_node));
- }
+ /* Evaluate and ignore both arguments in case either one has
+ side-effects. */
+ return omit_two_operands (integer_type_node, integer_zero_node,
+ s1, s2);
return 0;
}
}
}
}
-/* Simplify a call to the fputs builtin.
-
- Return 0 if no simplification was possible, otherwise return the
- simplified form of the call as a tree.
-
- The simplified form may be a constant or other expression which
- computes the same value, but in a more efficient manner (including
- calls to other builtin functions).
-
- The call may contain arguments which need to be evaluated, but
- which are not useful to determine the result of the call. In
- this case we return a chain of COMPOUND_EXPRs. The LHS of each
- COMPOUND_EXPR will be an argument which must be evaluated.
- COMPOUND_EXPRs are chained through their RHS. The RHS of the last
- COMPOUND_EXPR in the chain will contain the tree for the simplified
- form of the builtin function call.
-
- If KNOWN_LEN is non-NULL, it represents the known length of the string.
- This is determined by SSA-CCP in cases where the string itself is not
- known to be constant but its length is always the same constant. */
+/* Fold a call to the fputs builtin. IGNORE is true if the value returned
+ by the builtin will be ignored. UNLOCKED is true is true if this
+ actually a call to fputs_unlocked. If LEN in non-NULL, it represents
+ the known length of the string. Return NULL_TREE if no simplification
+ was possible. */
tree
-simplify_builtin_fputs (tree arglist, int ignore, int unlocked, tree known_len)
+fold_builtin_fputs (tree arglist, bool ignore, bool unlocked, tree len)
{
- tree len, fn;
+ tree fn;
tree fn_fputc = unlocked ? implicit_built_in_decls[BUILT_IN_FPUTC_UNLOCKED]
: implicit_built_in_decls[BUILT_IN_FPUTC];
tree fn_fwrite = unlocked ? implicit_built_in_decls[BUILT_IN_FWRITE_UNLOCKED]
if (!validate_arglist (arglist, POINTER_TYPE, POINTER_TYPE, VOID_TYPE))
return 0;
- len = (known_len) ? known_len : c_strlen (TREE_VALUE (arglist), 0);
+ if (! len)
+ len = c_strlen (TREE_VALUE (arglist), 0);
/* Get the length of the string passed to fputs. If the length
can't be determined, punt. */
{
/* New argument list transforming fputs(string, stream) to
fputc(string[0], stream). */
- arglist =
- build_tree_list (NULL_TREE, TREE_VALUE (TREE_CHAIN (arglist)));
- arglist =
- tree_cons (NULL_TREE, build_int_2 (p[0], 0), arglist);
+ arglist = build_tree_list (NULL_TREE,
+ TREE_VALUE (TREE_CHAIN (arglist)));
+ arglist = tree_cons (NULL_TREE,
+ build_int_cst (NULL_TREE, p[0]),
+ arglist);
fn = fn_fputc;
break;
}
{
tree string_arg;
- /* If optimizing for size keep fputs. */
+ /* If optimizing for size keep fputs. */
if (optimize_size)
return 0;
string_arg = TREE_VALUE (arglist);
/* New argument list transforming fputs(string, stream) to
fwrite(string, 1, len, stream). */
- arglist = build_tree_list (NULL_TREE, TREE_VALUE (TREE_CHAIN (arglist)));
+ arglist = build_tree_list (NULL_TREE,
+ TREE_VALUE (TREE_CHAIN (arglist)));
arglist = tree_cons (NULL_TREE, len, arglist);
arglist = tree_cons (NULL_TREE, size_one_node, arglist);
arglist = tree_cons (NULL_TREE, string_arg, arglist);
break;
}
default:
- abort ();
+ gcc_unreachable ();
}
+ /* These optimizations are only performed when the result is ignored,
+ hence there's no need to cast the result to integer_type_node. */
return build_function_call_expr (fn, arglist);
}
arglist = tree_cons (NULL_TREE, dest, arglist);
call = build_function_call_expr (fn, arglist);
if (!ignored)
- retval = build_int_2 (strlen (fmt_str), 0);
+ retval = build_int_cst (NULL_TREE, strlen (fmt_str));
}
/* If the format is "%s", use strcpy if the result isn't used. */