{
switch (TREE_CODE (exp))
{
- case NOP_EXPR:
- case CONVERT_EXPR:
- case NON_LVALUE_EXPR:
+ CASE_CONVERT:
exp = TREE_OPERAND (exp, 0);
if (! POINTER_TYPE_P (TREE_TYPE (exp)))
return align;
runtime. */
if (offset < 0 || offset > max)
{
- warning (0, "offset outside bounds of constant string");
+ /* Suppress multiple warnings for propagated constant strings. */
+ if (! TREE_NO_WARNING (src))
+ {
+ warning (0, "offset outside bounds of constant string");
+ TREE_NO_WARNING (src) = 1;
+ }
return NULL_TREE;
}
tem = hard_frame_pointer_rtx;
/* Tell reload not to eliminate the frame pointer. */
- current_function_accesses_prior_frames = 1;
+ crtl->accesses_prior_frames = 1;
}
#endif
/* Tell optimize_save_area_alloca that extra work is going to
need to go on during alloca. */
- current_function_calls_setjmp = 1;
+ cfun->calls_setjmp = 1;
/* We have a nonlocal label. */
- current_function_has_nonlocal_label = 1;
+ cfun->has_nonlocal_label = 1;
}
/* Construct the trailing part of a __builtin_setjmp call. This is
/* 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
r_sp = gen_rtx_MEM (STACK_SAVEAREA_MODE (SAVE_NONLOCAL),
plus_constant (r_save_area, GET_MODE_SIZE (Pmode)));
- current_function_has_nonlocal_goto = 1;
+ crtl->has_nonlocal_goto = 1;
#ifdef HAVE_nonlocal_goto
/* ??? We no longer need to pass the static chain value, afaik. */
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);
}
/* Get an expression we can use to find the attributes to assign to MEM.
If it is an ADDR_EXPR, use the operand. Otherwise, dereference it if
we can. First remove any nops. */
- while ((TREE_CODE (exp) == NOP_EXPR || TREE_CODE (exp) == CONVERT_EXPR
- || TREE_CODE (exp) == NON_LVALUE_EXPR)
+ while (CONVERT_EXPR_P (exp)
&& POINTER_TYPE_P (TREE_TYPE (TREE_OPERAND (exp, 0))))
exp = TREE_OPERAND (exp, 0);
tree inner = exp;
while (TREE_CODE (inner) == ARRAY_REF
- || TREE_CODE (inner) == NOP_EXPR
- || TREE_CODE (inner) == CONVERT_EXPR
- || TREE_CODE (inner) == NON_LVALUE_EXPR
+ || CONVERT_EXPR_P (inner)
|| TREE_CODE (inner) == VIEW_CONVERT_EXPR
|| TREE_CODE (inner) == SAVE_EXPR)
inner = TREE_OPERAND (inner, 0);
as we might have pretended they were passed. Make sure it's a valid
operand, as emit_move_insn isn't expected to handle a PLUS. */
tem
- = force_operand (plus_constant (tem, current_function_pretend_args_size),
+ = force_operand (plus_constant (tem, crtl->args.pretend_args_size),
NULL_RTX);
#endif
emit_move_insn (adjust_address (registers, Pmode, 0), tem);
fcodel = BUILT_IN_MATHFN##L_R ; break;
/* Return mathematic function equivalent to FN but operating directly
- on TYPE, if available. If we can't do the conversion, return zero. */
-tree
-mathfn_built_in (tree type, enum built_in_function fn)
+ on TYPE, if available. If IMPLICIT is true find the function in
+ implicit_built_in_decls[], otherwise use built_in_decls[]. If we
+ can't do the conversion, return zero. */
+
+static tree
+mathfn_built_in_1 (tree type, enum built_in_function fn, bool implicit)
{
+ tree const *const fn_arr
+ = implicit ? implicit_built_in_decls : built_in_decls;
enum built_in_function fcode, fcodef, fcodel;
switch (fn)
CASE_MATHFN (BUILT_IN_SCALB)
CASE_MATHFN (BUILT_IN_SCALBLN)
CASE_MATHFN (BUILT_IN_SCALBN)
+ CASE_MATHFN (BUILT_IN_SIGNBIT)
CASE_MATHFN (BUILT_IN_SIGNIFICAND)
CASE_MATHFN (BUILT_IN_SIN)
CASE_MATHFN (BUILT_IN_SINCOS)
}
if (TYPE_MAIN_VARIANT (type) == double_type_node)
- return implicit_built_in_decls[fcode];
+ return fn_arr[fcode];
else if (TYPE_MAIN_VARIANT (type) == float_type_node)
- return implicit_built_in_decls[fcodef];
+ return fn_arr[fcodef];
else if (TYPE_MAIN_VARIANT (type) == long_double_type_node)
- return implicit_built_in_decls[fcodel];
+ return fn_arr[fcodel];
else
return NULL_TREE;
}
+/* Like mathfn_built_in_1(), but always use the implicit array. */
+
+tree
+mathfn_built_in (tree type, enum built_in_function fn)
+{
+ return mathfn_built_in_1 (type, fn, /*implicit=*/ 1);
+}
+
/* If errno must be maintained, expand the RTL to check if the result,
TARGET, of a built-in function call, EXP, is NaN, and if so set
errno to EDOM. */
}
#endif
+ /* Make sure the library call isn't expanded as a tail call. */
+ CALL_EXPR_TAILCALL (exp) = 0;
+
/* We can't set errno=EDOM directly; let the library call do it.
Pop the arguments right away in case the call gets deleted. */
NO_DEFER_POP;
&& (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);
op1 = convert_to_mode (mode2, op1, 0);
target = emit_library_call_value (optab_libfunc (powi_optab, mode),
- target, LCT_CONST_MAKE_BLOCK, mode, 2,
+ target, LCT_CONST, mode, 2,
op0, mode, op1, mode2);
return target;
if (insn)
emit_insn (insn);
else
- emit_library_call_value (memcmp_libfunc, result, LCT_PURE_MAKE_BLOCK,
+ emit_library_call_value (memcmp_libfunc, result, LCT_PURE,
TYPE_MODE (integer_type_node), 3,
XEXP (arg1_rtx, 0), Pmode,
XEXP (arg2_rtx, 0), Pmode,
expand_builtin_args_info (tree exp)
{
int nwords = sizeof (CUMULATIVE_ARGS) / sizeof (int);
- int *word_ptr = (int *) ¤t_function_args_info;
+ int *word_ptr = (int *) &crtl->args.info;
gcc_assert (sizeof (CUMULATIVE_ARGS) % sizeof (int) == 0);
/* Checking arguments is already done in fold_builtin_next_arg
that must be called before this function. */
return expand_binop (ptr_mode, add_optab,
- current_function_internal_arg_pointer,
- current_function_arg_offset_rtx,
+ crtl->args.internal_arg_pointer,
+ crtl->args.arg_offset_rtx,
NULL_RTX, 0, OPTAB_LIB_WIDEN);
}
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;
}
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));
t = build_string (len, str);
elem = build_type_variant (char_type_node, 1, 0);
- index = build_index_type (build_int_cst (NULL_TREE, len - 1));
+ index = build_index_type (size_int (len - 1));
type = build_array_type (elem, index);
TREE_TYPE (t) = type;
TREE_CONSTANT (t) = 1;
- TREE_INVARIANT (t) = 1;
TREE_READONLY (t) = 1;
TREE_STATIC (t) = 1;
- type = build_pointer_type (type);
- t = build1 (ADDR_EXPR, type, t);
-
type = build_pointer_type (elem);
- t = build1 (NOP_EXPR, type, t);
+ t = build1 (ADDR_EXPR, type,
+ build4 (ARRAY_REF, elem,
+ t, integer_zero_node, NULL_TREE, NULL_TREE));
return t;
}
none of its arguments are volatile, we can avoid expanding the
built-in call and just evaluate the arguments for side-effects. */
if (target == const0_rtx
- && (DECL_IS_PURE (fndecl) || TREE_READONLY (fndecl)))
+ && (DECL_PURE_P (fndecl) || TREE_READONLY (fndecl)))
{
bool volatilep = false;
tree arg;
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);
}
/* If the argument isn't invariant then there's nothing else we can do. */
- if (!TREE_INVARIANT (arg0))
+ if (!TREE_CONSTANT (arg0))
return NULL_TREE;
/* If we expect that a comparison against the argument will fold to
case ABS_EXPR:
case SAVE_EXPR:
- case NON_LVALUE_EXPR:
return integer_valued_real_p (TREE_OPERAND (t, 0));
case COMPOUND_EXPR:
&& 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);
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);
REAL_VALUE_TYPE r;
if (!validate_arg (arg, REAL_TYPE))
- {
- error ("non-floating-point argument to function %qs",
- IDENTIFIER_POINTER (DECL_NAME (fndecl)));
- return error_mark_node;
- }
+ return NULL_TREE;
switch (builtin_index)
{
return NULL_TREE;
+ case BUILT_IN_ISINF_SIGN:
+ {
+ /* isinf_sign(x) -> isinf(x) ? (signbit(x) ? -1 : 1) : 0 */
+ /* In a boolean context, GCC will fold the inner COND_EXPR to
+ 1. So e.g. "if (isinf_sign(x))" would be folded to just
+ "if (isinf(x) ? 1 : 0)" which becomes "if (isinf(x))". */
+ tree signbit_fn = mathfn_built_in_1 (TREE_TYPE (arg), BUILT_IN_SIGNBIT, 0);
+ tree isinf_fn = built_in_decls[BUILT_IN_ISINF];
+ tree tmp = NULL_TREE;
+
+ arg = builtin_save_expr (arg);
+
+ if (signbit_fn && isinf_fn)
+ {
+ tree signbit_call = build_call_expr (signbit_fn, 1, arg);
+ tree isinf_call = build_call_expr (isinf_fn, 1, arg);
+
+ signbit_call = fold_build2 (NE_EXPR, integer_type_node,
+ signbit_call, integer_zero_node);
+ isinf_call = fold_build2 (NE_EXPR, integer_type_node,
+ isinf_call, integer_zero_node);
+
+ tmp = fold_build3 (COND_EXPR, integer_type_node, signbit_call,
+ integer_minus_one_node, integer_one_node);
+ tmp = fold_build3 (COND_EXPR, integer_type_node, isinf_call, tmp,
+ integer_zero_node);
+ }
+
+ return tmp;
+ }
+
case BUILT_IN_ISFINITE:
if (!HONOR_NANS (TYPE_MODE (TREE_TYPE (arg)))
&& !HONOR_INFINITIES (TYPE_MODE (TREE_TYPE (arg))))
}
}
+/* Fold a call to __builtin_fpclassify(int, int, int, int, int, ...).
+ This builtin will generate code to return the appropriate floating
+ point classification depending on the value of the floating point
+ number passed in. The possible return values must be supplied as
+ int arguments to the call in the following order: FP_NAN, FP_INFINITE,
+ FP_NORMAL, FP_SUBNORMAL and FP_ZERO. The ellipses is for exactly
+ one floating point argument which is "type generic". */
+
+static tree
+fold_builtin_fpclassify (tree exp)
+{
+ tree fp_nan, fp_infinite, fp_normal, fp_subnormal, fp_zero,
+ arg, type, res, tmp;
+ enum machine_mode mode;
+ REAL_VALUE_TYPE r;
+ char buf[128];
+
+ /* Verify the required arguments in the original call. */
+ if (!validate_arglist (exp, INTEGER_TYPE, INTEGER_TYPE,
+ INTEGER_TYPE, INTEGER_TYPE,
+ INTEGER_TYPE, REAL_TYPE, VOID_TYPE))
+ return NULL_TREE;
+
+ fp_nan = CALL_EXPR_ARG (exp, 0);
+ fp_infinite = CALL_EXPR_ARG (exp, 1);
+ fp_normal = CALL_EXPR_ARG (exp, 2);
+ fp_subnormal = CALL_EXPR_ARG (exp, 3);
+ fp_zero = CALL_EXPR_ARG (exp, 4);
+ arg = CALL_EXPR_ARG (exp, 5);
+ type = TREE_TYPE (arg);
+ mode = TYPE_MODE (type);
+ arg = builtin_save_expr (fold_build1 (ABS_EXPR, type, arg));
+
+ /* fpclassify(x) ->
+ isnan(x) ? FP_NAN :
+ (fabs(x) == Inf ? FP_INFINITE :
+ (fabs(x) >= DBL_MIN ? FP_NORMAL :
+ (x == 0 ? FP_ZERO : FP_SUBNORMAL))). */
+
+ tmp = fold_build2 (EQ_EXPR, integer_type_node, arg,
+ build_real (type, dconst0));
+ res = fold_build3 (COND_EXPR, integer_type_node, tmp, fp_zero, fp_subnormal);
+
+ sprintf (buf, "0x1p%d", REAL_MODE_FORMAT (mode)->emin - 1);
+ real_from_string (&r, buf);
+ tmp = fold_build2 (GE_EXPR, integer_type_node, arg, build_real (type, r));
+ res = fold_build3 (COND_EXPR, integer_type_node, tmp, fp_normal, res);
+
+ if (HONOR_INFINITIES (mode))
+ {
+ real_inf (&r);
+ tmp = fold_build2 (EQ_EXPR, integer_type_node, arg,
+ build_real (type, r));
+ res = fold_build3 (COND_EXPR, integer_type_node, tmp, fp_infinite, res);
+ }
+
+ if (HONOR_NANS (mode))
+ {
+ tmp = fold_build2 (ORDERED_EXPR, integer_type_node, arg, arg);
+ res = fold_build3 (COND_EXPR, integer_type_node, tmp, res, fp_nan);
+ }
+
+ return res;
+}
+
/* Fold a call to an unordered comparison function such as
__builtin_isgreater(). FNDECL is the FUNCTION_DECL for the function
being called and ARG0 and ARG1 are the arguments for the call.
cmp_type = type0;
else if (code0 == INTEGER_TYPE && code1 == REAL_TYPE)
cmp_type = type1;
- else
- {
- error ("non-floating-point argument to function %qs",
- IDENTIFIER_POINTER (DECL_NAME (fndecl)));
- return error_mark_node;
- }
arg0 = fold_convert (cmp_type, arg0);
arg1 = fold_convert (cmp_type, arg1);
case BUILT_IN_ISINFD128:
return fold_builtin_classify (fndecl, arg0, BUILT_IN_ISINF);
+ case BUILT_IN_ISINF_SIGN:
+ return fold_builtin_classify (fndecl, arg0, BUILT_IN_ISINF_SIGN);
+
CASE_FLT_FN (BUILT_IN_ISNAN):
case BUILT_IN_ISNAND32:
case BUILT_IN_ISNAND64:
fold_builtin_n (tree fndecl, tree *args, int nargs, bool ignore)
{
tree ret = NULL_TREE;
+
switch (nargs)
{
case 0:
case BUILT_IN_SNPRINTF_CHK:
case BUILT_IN_VSNPRINTF_CHK:
ret = fold_builtin_snprintf_chk (exp, NULL_TREE, fcode);
+ break;
+
+ case BUILT_IN_FPCLASSIFY:
+ ret = fold_builtin_fpclassify (exp);
+ break;
default:
break;
if (CAN_HAVE_LOCATION_P (realret)
&& !EXPR_HAS_LOCATION (realret))
SET_EXPR_LOCATION (realret, EXPR_LOCATION (exp));
+ return realret;
}
return ret;
}
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));
}
is not quite the same as STRIP_NOPS. It does more.
We must also strip off INDIRECT_EXPR for C++ reference
parameters. */
- while (TREE_CODE (arg) == NOP_EXPR
- || TREE_CODE (arg) == CONVERT_EXPR
- || TREE_CODE (arg) == NON_LVALUE_EXPR
+ while (CONVERT_EXPR_P (arg)
|| TREE_CODE (arg) == INDIRECT_REF)
arg = TREE_OPERAND (arg, 0);
if (arg != last_parm)