static rtx expand_builtin_strcpy (tree, tree, rtx, enum machine_mode);
static rtx expand_builtin_strcpy_args (tree, tree, tree, rtx, enum machine_mode);
static rtx expand_builtin_stpcpy (tree, rtx, enum machine_mode);
-static rtx builtin_strncpy_read_str (void *, HOST_WIDE_INT, enum machine_mode);
static rtx expand_builtin_strncpy (tree, rtx, enum machine_mode);
static rtx builtin_memset_gen_str (void *, HOST_WIDE_INT, enum machine_mode);
static rtx expand_builtin_memset (tree, rtx, enum machine_mode);
static tree stabilize_va_list (tree, int);
static rtx expand_builtin_expect (tree, rtx);
static tree fold_builtin_constant_p (tree);
-static tree fold_builtin_expect (tree);
+static tree fold_builtin_expect (tree, tree);
static tree fold_builtin_classify_type (tree);
static tree fold_builtin_strlen (tree);
static tree fold_builtin_inf (tree, int);
/* Now restore our arg pointer from the address at which it
was saved in our stack frame. */
emit_move_insn (virtual_incoming_args_rtx,
- copy_to_reg (get_arg_pointer_save_area (cfun)));
+ copy_to_reg (get_arg_pointer_save_area ()));
}
}
#endif
not clear if really needed. */
emit_insn (gen_rtx_USE (VOIDmode, hard_frame_pointer_rtx));
emit_insn (gen_rtx_USE (VOIDmode, stack_pointer_rtx));
+
+ /* If the architecture is using a GP register, we must
+ conservatively assume that the target function makes use of it.
+ The prologue of functions with nonlocal gotos must therefore
+ initialize the GP register to the appropriate value, and we
+ must then make sure that this value is live at the point
+ of the jump. (Note that this doesn't necessarily apply
+ to targets with a nonlocal_goto pattern; they are free
+ to implement it in their own way. Note also that this is
+ a no-op if the GP register is a global invariant.) */
+ if ((unsigned) PIC_OFFSET_TABLE_REGNUM != INVALID_REGNUM
+ && fixed_regs[PIC_OFFSET_TABLE_REGNUM])
+ emit_insn (gen_rtx_USE (VOIDmode, pic_offset_table_rtx));
+
emit_indirect_jump (r_label);
}
tree fndecl = get_callee_fndecl (exp);
enum machine_mode mode;
bool errno_set = false;
- tree arg, narg;
+ tree arg;
if (!validate_arglist (exp, REAL_TYPE, VOID_TYPE))
return NULL_RTX;
/* Wrap the computation of the argument in a SAVE_EXPR, as we may
need to expand the argument again. This way, we will not perform
side-effects more the once. */
- narg = builtin_save_expr (arg);
- if (narg != arg)
- {
- arg = narg;
- exp = build_call_expr (fndecl, 1, arg);
- }
+ CALL_EXPR_ARG (exp, 0) = arg = builtin_save_expr (arg);
op0 = expand_expr (arg, subtarget, VOIDmode, EXPAND_NORMAL);
rtx op0, op1, insns;
int op1_type = REAL_TYPE;
tree fndecl = get_callee_fndecl (exp);
- tree arg0, arg1, narg;
+ tree arg0, arg1;
enum machine_mode mode;
bool errno_set = true;
- bool stable = true;
switch (DECL_FUNCTION_CODE (fndecl))
{
errno_set = false;
/* Always stabilize the argument list. */
- narg = builtin_save_expr (arg1);
- if (narg != arg1)
- {
- arg1 = narg;
- stable = false;
- }
- narg = builtin_save_expr (arg0);
- if (narg != arg0)
- {
- arg0 = narg;
- stable = false;
- }
-
- if (! stable)
- exp = build_call_expr (fndecl, 2, arg0, arg1);
+ CALL_EXPR_ARG (exp, 0) = arg0 = builtin_save_expr (arg0);
+ CALL_EXPR_ARG (exp, 1) = arg1 = builtin_save_expr (arg1);
op0 = expand_expr (arg0, subtarget, VOIDmode, EXPAND_NORMAL);
op1 = expand_normal (arg1);
rtx op0, insns;
tree fndecl = get_callee_fndecl (exp);
enum machine_mode mode;
- tree arg, narg;
+ tree arg;
if (!validate_arglist (exp, REAL_TYPE, VOID_TYPE))
return NULL_RTX;
/* Wrap the computation of the argument in a SAVE_EXPR, as we may
need to expand the argument again. This way, we will not perform
side-effects more the once. */
- narg = save_expr (arg);
- if (narg != arg)
- {
- arg = narg;
- exp = build_call_expr (fndecl, 1, arg);
- }
+ CALL_EXPR_ARG (exp, 0) = arg = builtin_save_expr (arg);
op0 = expand_expr (arg, subtarget, VOIDmode, EXPAND_NORMAL);
tree fndecl = get_callee_fndecl (exp);
enum machine_mode mode;
bool errno_set = false;
- tree arg, narg;
+ tree arg;
if (!validate_arglist (exp, REAL_TYPE, VOID_TYPE))
return NULL_RTX;
/* Wrap the computation of the argument in a SAVE_EXPR, as we may
need to expand the argument again. This way, we will not perform
side-effects more the once. */
- narg = builtin_save_expr (arg);
- if (narg != arg)
- {
- arg = narg;
- exp = build_call_expr (fndecl, 1, arg);
- }
+ CALL_EXPR_ARG (exp, 0) = arg = builtin_save_expr (arg);
op0 = expand_expr (arg, subtarget, VOIDmode, EXPAND_NORMAL);
enum built_in_function fallback_fn;
tree fallback_fndecl;
enum machine_mode mode;
- tree arg, narg;
+ tree arg;
if (!validate_arglist (exp, REAL_TYPE, VOID_TYPE))
gcc_unreachable ();
/* Wrap the computation of the argument in a SAVE_EXPR, as we may
need to expand the argument again. This way, we will not perform
side-effects more the once. */
- narg = builtin_save_expr (arg);
- if (narg != arg)
- {
- arg = narg;
- exp = build_call_expr (fndecl, 1, arg);
- }
+ CALL_EXPR_ARG (exp, 0) = arg = builtin_save_expr (arg);
op0 = expand_expr (arg, subtarget, VOIDmode, EXPAND_NORMAL);
convert_optab builtin_optab;
rtx op0, insns;
tree fndecl = get_callee_fndecl (exp);
- tree arg, narg;
+ tree arg;
enum machine_mode mode;
/* There's no easy way to detect the case we need to set EDOM. */
/* Wrap the computation of the argument in a SAVE_EXPR, as we may
need to expand the argument again. This way, we will not perform
side-effects more the once. */
- narg = builtin_save_expr (arg);
- if (narg != arg)
- {
- arg = narg;
- exp = build_call_expr (fndecl, 1, arg);
- }
+ CALL_EXPR_ARG (exp, 0) = arg = builtin_save_expr (arg);
op0 = expand_expr (arg, subtarget, VOIDmode, EXPAND_NORMAL);
|| n == 1))
{
tree call_expr = build_call_expr (fn, 1, narg0);
- op = expand_builtin (call_expr, NULL_RTX, subtarget, mode, 0);
+ /* Use expand_expr in case the newly built call expression
+ was folded to a non-call. */
+ op = expand_expr (call_expr, subtarget, mode, EXPAND_NORMAL);
if (n != 1)
{
op2 = expand_expr (narg0, subtarget, VOIDmode, EXPAND_NORMAL);
&& (tree_expr_nonnegative_p (arg0)
|| !HONOR_NANS (mode)))
{
+ REAL_VALUE_TYPE dconst3;
+ real_from_integer (&dconst3, VOIDmode, 3, 0, 0);
real_arithmetic (&c2, MULT_EXPR, &c, &dconst3);
real_round (&c2, mode, &c2);
n = real_to_integer (&c2);
if (GET_MODE (op1) != mode2)
op1 = convert_to_mode (mode2, op1, 0);
- target = emit_library_call_value (optab_handler (powi_optab, mode)->libfunc,
+ target = emit_library_call_value (optab_libfunc (powi_optab, mode),
target, LCT_CONST_MAKE_BLOCK, mode, 2,
op0, mode, op1, mode2);
&& GET_CODE (len_rtx) == CONST_INT
&& (unsigned HOST_WIDE_INT) INTVAL (len_rtx) <= strlen (src_str) + 1
&& can_store_by_pieces (INTVAL (len_rtx), builtin_memcpy_read_str,
- (void *) src_str, dest_align))
+ (void *) src_str, dest_align, false))
{
dest_mem = store_by_pieces (dest_mem, INTVAL (len_rtx),
builtin_memcpy_read_str,
- (void *) src_str, dest_align, 0);
+ (void *) src_str, dest_align, false, 0);
dest_mem = force_operand (XEXP (dest_mem, 0), NULL_RTX);
dest_mem = convert_memory_address (ptr_mode, dest_mem);
return dest_mem;
&& GET_CODE (len_rtx) == CONST_INT
&& (unsigned HOST_WIDE_INT) INTVAL (len_rtx) <= strlen (src_str) + 1
&& can_store_by_pieces (INTVAL (len_rtx), builtin_memcpy_read_str,
- (void *) src_str, dest_align))
+ (void *) src_str, dest_align, false))
{
dest_mem = get_memory_rtx (dest, len);
set_mem_align (dest_mem, dest_align);
dest_mem = store_by_pieces (dest_mem, INTVAL (len_rtx),
builtin_memcpy_read_str,
- (void *) src_str, dest_align, endp);
+ (void *) src_str, dest_align,
+ false, endp);
dest_mem = force_operand (XEXP (dest_mem, 0), NULL_RTX);
dest_mem = convert_memory_address (ptr_mode, dest_mem);
return dest_mem;
bytes from constant string DATA + OFFSET and return it as target
constant. */
-static rtx
+rtx
builtin_strncpy_read_str (void *data, HOST_WIDE_INT offset,
enum machine_mode mode)
{
if (!p || dest_align == 0 || !host_integerp (len, 1)
|| !can_store_by_pieces (tree_low_cst (len, 1),
builtin_strncpy_read_str,
- (void *) p, dest_align))
+ (void *) p, dest_align, false))
return NULL_RTX;
dest_mem = get_memory_rtx (dest, len);
store_by_pieces (dest_mem, tree_low_cst (len, 1),
builtin_strncpy_read_str,
- (void *) p, dest_align, 0);
+ (void *) p, dest_align, false, 0);
dest_mem = force_operand (XEXP (dest_mem, 0), NULL_RTX);
dest_mem = convert_memory_address (ptr_mode, dest_mem);
return dest_mem;
* We can't pass builtin_memset_gen_str as that emits RTL. */
c = 1;
if (host_integerp (len, 1)
- && !(optimize_size && tree_low_cst (len, 1) > 1)
&& can_store_by_pieces (tree_low_cst (len, 1),
- builtin_memset_read_str, &c, dest_align))
+ builtin_memset_read_str, &c, dest_align,
+ true))
{
val_rtx = force_reg (TYPE_MODE (unsigned_char_type_node),
val_rtx);
store_by_pieces (dest_mem, tree_low_cst (len, 1),
- builtin_memset_gen_str, val_rtx, dest_align, 0);
+ builtin_memset_gen_str, val_rtx, dest_align,
+ true, 0);
}
else if (!set_storage_via_setmem (dest_mem, len_rtx, val_rtx,
dest_align, expected_align,
if (c)
{
if (host_integerp (len, 1)
- && !(optimize_size && tree_low_cst (len, 1) > 1)
&& can_store_by_pieces (tree_low_cst (len, 1),
- builtin_memset_read_str, &c, dest_align))
+ builtin_memset_read_str, &c, dest_align,
+ true))
store_by_pieces (dest_mem, tree_low_cst (len, 1),
- builtin_memset_read_str, &c, dest_align, 0);
+ builtin_memset_read_str, &c, dest_align, true, 0);
else if (!set_storage_via_setmem (dest_mem, len_rtx, GEN_INT (c),
dest_align, expected_align,
expected_size))
nextarg = expand_builtin_next_arg ();
valist = stabilize_va_list (CALL_EXPR_ARG (exp, 0), 1);
-#ifdef EXPAND_BUILTIN_VA_START
- EXPAND_BUILTIN_VA_START (valist, nextarg);
-#else
- std_expand_builtin_va_start (valist, nextarg);
-#endif
+ if (targetm.expand_builtin_va_start)
+ targetm.expand_builtin_va_start (valist, nextarg);
+ else
+ std_expand_builtin_va_start (valist, nextarg);
return const0_rtx;
}
if (! gave_help)
{
gave_help = true;
- warning (0, "(so you should pass %qT not %qT to %<va_arg%>)",
+ inform ("(so you should pass %qT not %qT to %<va_arg%>)",
promoted_type, type);
}
return NULL_RTX;
arg = CALL_EXPR_ARG (exp, 0);
+ CALL_EXPR_ARG (exp, 0) = arg = builtin_save_expr (arg);
mode = TYPE_MODE (TREE_TYPE (arg));
op0 = expand_expr (arg, subtarget, VOIDmode, EXPAND_NORMAL);
return expand_abs (mode, op0, target, 0, safe_from_p (target, arg, 1));
case BUILT_IN_ARGS_INFO:
return expand_builtin_args_info (exp);
+ case BUILT_IN_VA_ARG_PACK:
+ /* All valid uses of __builtin_va_arg_pack () are removed during
+ inlining. */
+ error ("%Kinvalid use of %<__builtin_va_arg_pack ()%>", exp);
+ return const0_rtx;
+
+ case BUILT_IN_VA_ARG_PACK_LEN:
+ /* All valid uses of __builtin_va_arg_pack_len () are removed during
+ inlining. */
+ error ("%Kinvalid use of %<__builtin_va_arg_pack_len ()%>", exp);
+ return const0_rtx;
+
/* Return the address of the first anonymous stack arg. */
case BUILT_IN_NEXT_ARG:
if (fold_builtin_next_arg (exp, false))
return expand_builtin_extend_pointer (CALL_EXPR_ARG (exp, 0));
case BUILT_IN_VA_START:
- case BUILT_IN_STDARG_START:
return expand_builtin_va_start (exp);
case BUILT_IN_VA_END:
return expand_builtin_va_end (exp);
return NULL_TREE;
}
-/* Fold a call to __builtin_expect with argument ARG, if we expect that a
- comparison against the argument will fold to a constant. In practice,
- this means a true constant or the address of a non-weak symbol. */
+/* Create builtin_expect with PRED and EXPECTED as its arguments and
+ return it as a truthvalue. */
+
+static tree
+build_builtin_expect_predicate (tree pred, tree expected)
+{
+ tree fn, arg_types, pred_type, expected_type, call_expr, ret_type;
+
+ fn = built_in_decls[BUILT_IN_EXPECT];
+ arg_types = TYPE_ARG_TYPES (TREE_TYPE (fn));
+ ret_type = TREE_TYPE (TREE_TYPE (fn));
+ pred_type = TREE_VALUE (arg_types);
+ expected_type = TREE_VALUE (TREE_CHAIN (arg_types));
+
+ pred = fold_convert (pred_type, pred);
+ expected = fold_convert (expected_type, expected);
+ call_expr = build_call_expr (fn, 2, pred, expected);
+
+ return build2 (NE_EXPR, TREE_TYPE (pred), call_expr,
+ build_int_cst (ret_type, 0));
+}
+
+/* Fold a call to builtin_expect with arguments ARG0 and ARG1. Return
+ NULL_TREE if no simplification is possible. */
static tree
-fold_builtin_expect (tree arg)
+fold_builtin_expect (tree arg0, tree arg1)
{
- tree inner;
+ tree inner, fndecl;
+ enum tree_code code;
+
+ /* If this is a builtin_expect within a builtin_expect keep the
+ inner one. See through a comparison against a constant. It
+ might have been added to create a thruthvalue. */
+ inner = arg0;
+ if (COMPARISON_CLASS_P (inner)
+ && TREE_CODE (TREE_OPERAND (inner, 1)) == INTEGER_CST)
+ inner = TREE_OPERAND (inner, 0);
- /* If the argument isn't invariant, then there's nothing we can do. */
- if (!TREE_INVARIANT (arg))
+ if (TREE_CODE (inner) == CALL_EXPR
+ && (fndecl = get_callee_fndecl (inner))
+ && DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL
+ && DECL_FUNCTION_CODE (fndecl) == BUILT_IN_EXPECT)
+ return arg0;
+
+ /* Distribute the expected value over short-circuiting operators.
+ See through the cast from truthvalue_type_node to long. */
+ inner = arg0;
+ while (TREE_CODE (inner) == NOP_EXPR
+ && INTEGRAL_TYPE_P (TREE_TYPE (inner))
+ && INTEGRAL_TYPE_P (TREE_TYPE (TREE_OPERAND (inner, 0))))
+ inner = TREE_OPERAND (inner, 0);
+
+ code = TREE_CODE (inner);
+ if (code == TRUTH_ANDIF_EXPR || code == TRUTH_ORIF_EXPR)
+ {
+ tree op0 = TREE_OPERAND (inner, 0);
+ tree op1 = TREE_OPERAND (inner, 1);
+
+ op0 = build_builtin_expect_predicate (op0, arg1);
+ op1 = build_builtin_expect_predicate (op1, arg1);
+ inner = build2 (code, TREE_TYPE (inner), op0, op1);
+
+ return fold_convert (TREE_TYPE (arg0), inner);
+ }
+
+ /* If the argument isn't invariant then there's nothing else we can do. */
+ if (!TREE_INVARIANT (arg0))
return NULL_TREE;
- /* If we're looking at an address of a weak decl, then do not fold. */
- inner = arg;
+ /* If we expect that a comparison against the argument will fold to
+ a constant return the constant. In practice, this means a true
+ constant or the address of a non-weak symbol. */
+ inner = arg0;
STRIP_NOPS (inner);
if (TREE_CODE (inner) == ADDR_EXPR)
{
return NULL_TREE;
}
- /* Otherwise, ARG already has the proper type for the return value. */
- return arg;
+ /* Otherwise, ARG0 already has the proper type for the return value. */
+ return arg0;
}
/* Fold a call to __builtin_classify_type with argument ARG. */
&& operand_equal_p (real, imag, OEP_PURE_SAME))
{
const REAL_VALUE_TYPE sqrt2_trunc
- = real_value_truncate (TYPE_MODE (type), dconstsqrt2);
+ = real_value_truncate (TYPE_MODE (type),
+ *get_real_const (rv_sqrt2));
STRIP_NOPS (real);
return fold_build2 (MULT_EXPR, type,
fold_build1 (ABS_EXPR, type, real),
tree tree_root;
/* The inner root was either sqrt or cbrt. */
REAL_VALUE_TYPE dconstroot =
- BUILTIN_SQRT_P (fcode) ? dconsthalf : dconstthird;
+ BUILTIN_SQRT_P (fcode) ? dconsthalf : *get_real_const (rv_third);
/* Adjust for the outer root. */
SET_REAL_EXP (&dconstroot, REAL_EXP (&dconstroot) - 1);
{
tree expfn = TREE_OPERAND (CALL_EXPR_FN (arg), 0);
const REAL_VALUE_TYPE third_trunc =
- real_value_truncate (TYPE_MODE (type), dconstthird);
+ real_value_truncate (TYPE_MODE (type), *get_real_const (rv_third));
arg = fold_build2 (MULT_EXPR, type,
CALL_EXPR_ARG (arg, 0),
build_real (type, third_trunc));
{
tree arg0 = CALL_EXPR_ARG (arg, 0);
tree tree_root;
- REAL_VALUE_TYPE dconstroot = dconstthird;
+ REAL_VALUE_TYPE dconstroot = *get_real_const (rv_third);
SET_REAL_EXP (&dconstroot, REAL_EXP (&dconstroot) - 1);
dconstroot = real_value_truncate (TYPE_MODE (type), dconstroot);
tree tree_root;
REAL_VALUE_TYPE dconstroot;
- real_arithmetic (&dconstroot, MULT_EXPR, &dconstthird, &dconstthird);
+ real_arithmetic (&dconstroot, MULT_EXPR,
+ get_real_const (rv_third),
+ get_real_const (rv_third));
dconstroot = real_value_truncate (TYPE_MODE (type), dconstroot);
tree_root = build_real (type, dconstroot);
return build_call_expr (powfn, 2, arg0, tree_root);
{
tree powfn = TREE_OPERAND (CALL_EXPR_FN (arg), 0);
const REAL_VALUE_TYPE dconstroot
- = real_value_truncate (TYPE_MODE (type), dconstthird);
+ = real_value_truncate (TYPE_MODE (type),
+ *get_real_const (rv_third));
tree narg01 = fold_build2 (MULT_EXPR, type, arg01,
build_real (type, dconstroot));
return build_call_expr (powfn, 2, arg00, narg01);
icall = builtin_save_expr (icall);
rcall = build_call_expr (rfn, 1, realp);
rcall = builtin_save_expr (rcall);
- return build2 (COMPLEX_EXPR, type,
- build2 (MULT_EXPR, rtype,
- rcall,
- build1 (REALPART_EXPR, rtype, icall)),
- build2 (MULT_EXPR, rtype,
- rcall,
- build1 (IMAGPART_EXPR, rtype, icall)));
+ return fold_build2 (COMPLEX_EXPR, type,
+ fold_build2 (MULT_EXPR, rtype,
+ rcall,
+ fold_build1 (REALPART_EXPR, rtype, icall)),
+ fold_build2 (MULT_EXPR, rtype,
+ rcall,
+ fold_build1 (IMAGPART_EXPR, rtype, icall)));
}
return NULL_TREE;
if (flag_unsafe_math_optimizations && func == mpfr_log)
{
const REAL_VALUE_TYPE e_truncated =
- real_value_truncate (TYPE_MODE (type), dconste);
+ real_value_truncate (TYPE_MODE (type), *get_real_const (rv_e));
if (real_dconstp (arg, &e_truncated))
return build_real (type, dconst1);
}
CASE_FLT_FN (BUILT_IN_EXP):
/* Prepare to do logN(exp(exponent) -> exponent*logN(e). */
x = build_real (type,
- real_value_truncate (TYPE_MODE (type), dconste));
+ real_value_truncate (TYPE_MODE (type),
+ *get_real_const (rv_e)));
exponent = CALL_EXPR_ARG (arg, 0);
break;
CASE_FLT_FN (BUILT_IN_EXP2):
CASE_FLT_FN (BUILT_IN_EXP10):
CASE_FLT_FN (BUILT_IN_POW10):
/* Prepare to do logN(exp10(exponent) -> exponent*logN(10). */
- x = build_real (type, dconst10);
+ {
+ REAL_VALUE_TYPE dconst10;
+ real_from_integer (&dconst10, VOIDmode, 10, 0, 0);
+ x = build_real (type, dconst10);
+ }
exponent = CALL_EXPR_ARG (arg, 0);
break;
CASE_FLT_FN (BUILT_IN_SQRT):
/* Prepare to do logN(cbrt(x) -> (1/3)*logN(x). */
x = CALL_EXPR_ARG (arg, 0);
exponent = build_real (type, real_value_truncate (TYPE_MODE (type),
- dconstthird));
+ *get_real_const (rv_third)));
break;
CASE_FLT_FN (BUILT_IN_POW):
/* Prepare to do logN(pow(x,exponent) -> exponent*logN(x). */
&& operand_equal_p (arg0, arg1, OEP_PURE_SAME))
{
const REAL_VALUE_TYPE sqrt2_trunc
- = real_value_truncate (TYPE_MODE (type), dconstsqrt2);
+ = real_value_truncate (TYPE_MODE (type), *get_real_const (rv_sqrt2));
return fold_build2 (MULT_EXPR, type,
fold_build1 (ABS_EXPR, type, arg0),
build_real (type, sqrt2_trunc));
if (flag_unsafe_math_optimizations)
{
const REAL_VALUE_TYPE dconstroot
- = real_value_truncate (TYPE_MODE (type), dconstthird);
+ = real_value_truncate (TYPE_MODE (type),
+ *get_real_const (rv_third));
if (REAL_VALUES_EQUAL (c, dconstroot))
{
if (tree_expr_nonnegative_p (arg))
{
const REAL_VALUE_TYPE dconstroot
- = real_value_truncate (TYPE_MODE (type), dconstthird);
+ = real_value_truncate (TYPE_MODE (type),
+ *get_real_const (rv_third));
tree narg1 = fold_build2 (MULT_EXPR, type, arg1,
build_real (type, dconstroot));
return build_call_expr (fndecl, 2, arg, narg1);
case BUILT_IN_ISNAND128:
return fold_builtin_classify (fndecl, arg0, BUILT_IN_ISNAN);
+ case BUILT_IN_ISNORMAL:
+ if (!validate_arg (arg0, REAL_TYPE))
+ {
+ error ("non-floating-point argument to function %qs",
+ IDENTIFIER_POINTER (DECL_NAME (fndecl)));
+ return error_mark_node;
+ }
+ break;
+
case BUILT_IN_PRINTF:
case BUILT_IN_PRINTF_UNLOCKED:
case BUILT_IN_VPRINTF:
return fold_builtin_strpbrk (arg0, arg1, type);
case BUILT_IN_EXPECT:
- return fold_builtin_expect (arg0);
+ return fold_builtin_expect (arg0, arg1);
CASE_FLT_FN (BUILT_IN_POW):
return fold_builtin_pow (fndecl, arg0, arg1, type);
static tree
fold_builtin_n (tree fndecl, tree *args, int nargs, bool ignore)
{
+ enum built_in_function fcode = DECL_FUNCTION_CODE (fndecl);
tree ret = NULL_TREE;
+
+ /* Verify the number of arguments for type-generic and thus variadic
+ builtins. */
+ switch (fcode)
+ {
+ case BUILT_IN_ISFINITE:
+ case BUILT_IN_ISINF:
+ case BUILT_IN_ISNAN:
+ case BUILT_IN_ISNORMAL:
+ if (nargs < 1)
+ {
+ error ("too few arguments to function %qs",
+ IDENTIFIER_POINTER (DECL_NAME (fndecl)));
+ return error_mark_node;
+ }
+ else if (nargs > 1)
+ {
+ error ("too many arguments to function %qs",
+ IDENTIFIER_POINTER (DECL_NAME (fndecl)));
+ return error_mark_node;
+ }
+ break;
+
+ case BUILT_IN_ISGREATER:
+ case BUILT_IN_ISGREATEREQUAL:
+ case BUILT_IN_ISLESS:
+ case BUILT_IN_ISLESSEQUAL:
+ case BUILT_IN_ISLESSGREATER:
+ case BUILT_IN_ISUNORDERED:
+ if (nargs < 2)
+ {
+ error ("too few arguments to function %qs",
+ IDENTIFIER_POINTER (DECL_NAME (fndecl)));
+ return error_mark_node;
+ }
+ else if (nargs > 2)
+ {
+ error ("too many arguments to function %qs",
+ IDENTIFIER_POINTER (DECL_NAME (fndecl)));
+ return error_mark_node;
+ }
+ break;
+
+ default:
+ break;
+ }
+
switch (nargs)
{
case 0:
tree fndecl = get_callee_fndecl (exp);
if (fndecl
&& TREE_CODE (fndecl) == FUNCTION_DECL
- && DECL_BUILT_IN (fndecl))
- {
+ && DECL_BUILT_IN (fndecl)
+ /* If CALL_EXPR_VA_ARG_PACK is set, the arguments aren't finalized
+ yet. Defer folding until we see all the arguments
+ (after inlining). */
+ && !CALL_EXPR_VA_ARG_PACK (exp))
+ {
+ int nargs = call_expr_nargs (exp);
+
+ /* Before gimplification CALL_EXPR_VA_ARG_PACK is not set, but
+ instead last argument is __builtin_va_arg_pack (). Defer folding
+ even in that case, until arguments are finalized. */
+ if (nargs && TREE_CODE (CALL_EXPR_ARG (exp, nargs - 1)) == CALL_EXPR)
+ {
+ tree fndecl2 = get_callee_fndecl (CALL_EXPR_ARG (exp, nargs - 1));
+ if (fndecl2
+ && TREE_CODE (fndecl2) == FUNCTION_DECL
+ && DECL_BUILT_IN_CLASS (fndecl2) == BUILT_IN_NORMAL
+ && DECL_FUNCTION_CODE (fndecl2) == BUILT_IN_VA_ARG_PACK)
+ return NULL_TREE;
+ }
+
/* FIXME: Don't use a list in this interface. */
if (DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_MD)
return targetm.fold_builtin (fndecl, CALL_EXPR_ARGS (exp), ignore);
else
{
- int nargs = call_expr_nargs (exp);
if (nargs <= MAX_ARGS_TO_FOLD_BUILTIN)
{
tree *args = CALL_EXPR_ARGP (exp);
if (TREE_CODE (fndecl) == FUNCTION_DECL
&& DECL_BUILT_IN (fndecl))
{
+ /* If last argument is __builtin_va_arg_pack (), arguments to this
+ function are not finalized yet. Defer folding until they are. */
+ if (n && TREE_CODE (argarray[n - 1]) == CALL_EXPR)
+ {
+ tree fndecl2 = get_callee_fndecl (argarray[n - 1]);
+ if (fndecl2
+ && TREE_CODE (fndecl2) == FUNCTION_DECL
+ && DECL_BUILT_IN_CLASS (fndecl2) == BUILT_IN_NORMAL
+ && DECL_FUNCTION_CODE (fndecl2) == BUILT_IN_VA_ARG_PACK)
+ return build_call_array (type, fn, n, argarray);
+ }
if (DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_MD)
{
tree arglist = NULL_TREE;
return false;
else if (code == POINTER_TYPE)
return POINTER_TYPE_P (TREE_TYPE (arg));
+ else if (code == INTEGER_TYPE)
+ return INTEGRAL_TYPE_P (TREE_TYPE (arg));
return code == TREE_CODE (TREE_TYPE (arg));
}
tree ost;
int object_size_type;
tree fndecl = get_callee_fndecl (exp);
- location_t locus = EXPR_LOCATION (exp);
if (!validate_arglist (exp, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE))
{
- error ("%Hfirst argument of %D must be a pointer, second integer constant",
- &locus, fndecl);
+ error ("%Kfirst argument of %D must be a pointer, second integer constant",
+ exp, fndecl);
expand_builtin_trap ();
return const0_rtx;
}
|| tree_int_cst_sgn (ost) < 0
|| compare_tree_int (ost, 3) > 0)
{
- error ("%Hlast argument of %D is not integer constant between 0 and 3",
- &locus, fndecl);
+ error ("%Klast argument of %D is not integer constant between 0 and 3",
+ exp, fndecl);
expand_builtin_trap ();
return const0_rtx;
}
if (! integer_all_onesp (size) && tree_int_cst_lt (size, len))
{
- location_t locus = EXPR_LOCATION (exp);
- warning (0, "%Hcall to %D will always overflow destination buffer",
- &locus, get_callee_fndecl (exp));
+ warning (0, "%Kcall to %D will always overflow destination buffer",
+ exp, get_callee_fndecl (exp));
return NULL_RTX;
}
return NULL_RTX;
fn = build_call_expr (fn, 3, dest, src, len);
+ STRIP_TYPE_NOPS (fn);
+ while (TREE_CODE (fn) == COMPOUND_EXPR)
+ {
+ expand_expr (TREE_OPERAND (fn, 0), const0_rtx, VOIDmode,
+ EXPAND_NORMAL);
+ fn = TREE_OPERAND (fn, 1);
+ }
if (TREE_CODE (fn) == CALL_EXPR)
CALL_EXPR_TAILCALL (fn) = CALL_EXPR_TAILCALL (exp);
return expand_expr (fn, target, mode, EXPAND_NORMAL);
if (!fn)
return NULL_RTX;
fn = build_call_expr (fn, 4, dest, src, len, size);
+ STRIP_TYPE_NOPS (fn);
+ while (TREE_CODE (fn) == COMPOUND_EXPR)
+ {
+ expand_expr (TREE_OPERAND (fn, 0), const0_rtx, VOIDmode,
+ EXPAND_NORMAL);
+ fn = TREE_OPERAND (fn, 1);
+ }
if (TREE_CODE (fn) == CALL_EXPR)
CALL_EXPR_TAILCALL (fn) = CALL_EXPR_TAILCALL (exp);
return expand_expr (fn, target, mode, EXPAND_NORMAL);
{
int is_strlen = 0;
tree len, size;
- location_t locus;
switch (fcode)
{
src = c_strlen (src, 1);
if (! src || ! host_integerp (src, 1))
{
- locus = EXPR_LOCATION (exp);
- warning (0, "%Hcall to %D might overflow destination buffer",
- &locus, get_callee_fndecl (exp));
+ warning (0, "%Kcall to %D might overflow destination buffer",
+ exp, get_callee_fndecl (exp));
return;
}
else if (tree_int_cst_lt (src, size))
else if (! host_integerp (len, 1) || ! tree_int_cst_lt (size, len))
return;
- locus = EXPR_LOCATION (exp);
- warning (0, "%Hcall to %D will always overflow destination buffer",
- &locus, get_callee_fndecl (exp));
+ warning (0, "%Kcall to %D will always overflow destination buffer",
+ exp, get_callee_fndecl (exp));
}
/* Emit warning if a buffer overflow is detected at compile time
if (! tree_int_cst_lt (len, size))
{
- location_t locus = EXPR_LOCATION (exp);
- warning (0, "%Hcall to %D will always overflow destination buffer",
- &locus, get_callee_fndecl (exp));
+ warning (0, "%Kcall to %D will always overflow destination buffer",
+ exp, get_callee_fndecl (exp));
}
}