/* Expand builtin functions.
Copyright (C) 1988, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
- 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009
+ 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
Free Software Foundation, Inc.
This file is part of GCC.
static tree fold_builtin_constant_p (tree);
static tree fold_builtin_expect (location_t, tree, tree);
static tree fold_builtin_classify_type (tree);
-static tree fold_builtin_strlen (location_t, tree);
+static tree fold_builtin_strlen (location_t, tree, tree);
static tree fold_builtin_inf (location_t, tree, int);
static tree fold_builtin_nan (tree, tree, int);
static tree rewrite_call_expr (location_t, tree, int, tree, int, ...);
offset = next_offset;
}
}
- if (DECL_P (exp))
+ if (TREE_CODE (exp) == CONST_DECL)
+ exp = DECL_INITIAL (exp);
+ if (DECL_P (exp)
+ && TREE_CODE (exp) != LABEL_DECL)
align = MIN (inner, DECL_ALIGN (exp));
#ifdef CONSTANT_ALIGNMENT
else if (CONSTANT_CLASS_P (exp))
HOST_WIDE_INT offset;
int max;
const char *ptr;
+ location_t loc;
STRIP_NOPS (src);
if (TREE_CODE (src) == COND_EXPR
&& (only_value || !TREE_SIDE_EFFECTS (TREE_OPERAND (src, 0))))
return c_strlen (TREE_OPERAND (src, 1), only_value);
+ if (EXPR_HAS_LOCATION (src))
+ loc = EXPR_LOCATION (src);
+ else
+ loc = input_location;
+
src = string_constant (src, &offset_node);
if (src == 0)
return NULL_TREE;
and return that. This would perhaps not be valid if we were dealing
with named arrays in addition to literal string constants. */
- return size_diffop_loc (input_location, size_int (max), offset_node);
+ return size_diffop_loc (loc, size_int (max), offset_node);
}
/* We have a known offset into the string. Start searching there for
/* Suppress multiple warnings for propagated constant strings. */
if (! TREE_NO_WARNING (src))
{
- warning (0, "offset outside bounds of constant string");
+ warning_at (loc, 0, "offset outside bounds of constant string");
TREE_NO_WARNING (src) = 1;
}
return NULL_TREE;
&& GET_MODE_SIZE (mode) > UNITS_PER_WORD)
j = j + UNITS_PER_WORD - 2 * (j % UNITS_PER_WORD) - 1;
j *= BITS_PER_UNIT;
- gcc_assert (j <= 2 * HOST_BITS_PER_WIDE_INT);
+ gcc_assert (j < 2 * HOST_BITS_PER_WIDE_INT);
if (ch)
ch = (unsigned char) str[i];
size = 0;
for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
- if (FUNCTION_VALUE_REGNO_P (regno))
+ if (targetm.calls.function_value_regno_p (regno))
{
mode = reg_raw_mode[regno];
/* Test the result; if it is NaN, set errno=EDOM because
the argument was not in the domain. */
do_compare_rtx_and_jump (target, target, EQ, 0, GET_MODE (target),
- NULL_RTX, NULL_RTX, lab);
+ NULL_RTX, NULL_RTX, lab,
+ /* The jump is very likely. */
+ REG_BR_PROB_BASE - (REG_BR_PROB_BASE / 2000 - 1));
#ifdef TARGET_EDOM
/* If this built-in doesn't throw an exception, set errno directly. */
if (icode != CODE_FOR_nothing)
{
+ rtx last = get_last_insn ();
+ tree orig_arg = arg;
/* Make a suitable register to place result in. */
if (!target
- || GET_MODE (target) != TYPE_MODE (TREE_TYPE (exp)))
+ || GET_MODE (target) != TYPE_MODE (TREE_TYPE (exp))
+ || !insn_data[icode].operand[0].predicate (target, GET_MODE (target)))
target = gen_reg_rtx (TYPE_MODE (TREE_TYPE (exp)));
gcc_assert (insn_data[icode].operand[0].predicate
/* Compute into TARGET.
Set TARGET to wherever the result comes back. */
- emit_unop_insn (icode, target, op0, UNKNOWN);
- return target;
+ if (maybe_emit_unop_insn (icode, target, op0, UNKNOWN))
+ return target;
+ delete_insns_since (last);
+ CALL_EXPR_ARG (exp, 0) = orig_arg;
}
return NULL_RTX;
return result;
}
+/* Fold a builtin function call to pow, powf, or powl into a series of sqrts or
+ cbrts. Return NULL_RTX if no simplification can be made or expand the tree
+ if we can simplify it. */
+static rtx
+expand_builtin_pow_root (location_t loc, tree arg0, tree arg1, tree type,
+ rtx subtarget)
+{
+ if (TREE_CODE (arg1) == REAL_CST
+ && !TREE_OVERFLOW (arg1)
+ && flag_unsafe_math_optimizations)
+ {
+ enum machine_mode mode = TYPE_MODE (type);
+ tree sqrtfn = mathfn_built_in (type, BUILT_IN_SQRT);
+ tree cbrtfn = mathfn_built_in (type, BUILT_IN_CBRT);
+ REAL_VALUE_TYPE c = TREE_REAL_CST (arg1);
+ tree op = NULL_TREE;
+
+ if (sqrtfn)
+ {
+ /* Optimize pow (x, 0.5) into sqrt. */
+ if (REAL_VALUES_EQUAL (c, dconsthalf))
+ op = build_call_nofold_loc (loc, sqrtfn, 1, arg0);
+
+ else
+ {
+ REAL_VALUE_TYPE dconst1_4 = dconst1;
+ REAL_VALUE_TYPE dconst3_4;
+ SET_REAL_EXP (&dconst1_4, REAL_EXP (&dconst1_4) - 2);
+
+ real_from_integer (&dconst3_4, VOIDmode, 3, 0, 0);
+ SET_REAL_EXP (&dconst3_4, REAL_EXP (&dconst3_4) - 2);
+
+ /* Optimize pow (x, 0.25) into sqrt (sqrt (x)). Assume on most
+ machines that a builtin sqrt instruction is smaller than a
+ call to pow with 0.25, so do this optimization even if
+ -Os. */
+ if (REAL_VALUES_EQUAL (c, dconst1_4))
+ {
+ op = build_call_nofold_loc (loc, sqrtfn, 1, arg0);
+ op = build_call_nofold_loc (loc, sqrtfn, 1, op);
+ }
+
+ /* Optimize pow (x, 0.75) = sqrt (x) * sqrt (sqrt (x)) unless we
+ are optimizing for space. */
+ else if (optimize_insn_for_speed_p ()
+ && !TREE_SIDE_EFFECTS (arg0)
+ && REAL_VALUES_EQUAL (c, dconst3_4))
+ {
+ tree sqrt1 = build_call_expr_loc (loc, sqrtfn, 1, arg0);
+ tree sqrt2 = builtin_save_expr (sqrt1);
+ tree sqrt3 = build_call_expr_loc (loc, sqrtfn, 1, sqrt1);
+ op = fold_build2_loc (loc, MULT_EXPR, type, sqrt2, sqrt3);
+ }
+ }
+ }
+
+ /* Check whether we can do cbrt insstead of pow (x, 1./3.) and
+ cbrt/sqrts instead of pow (x, 1./6.). */
+ if (cbrtfn && ! op
+ && (tree_expr_nonnegative_p (arg0) || !HONOR_NANS (mode)))
+ {
+ /* First try 1/3. */
+ REAL_VALUE_TYPE dconst1_3
+ = real_value_truncate (mode, dconst_third ());
+
+ if (REAL_VALUES_EQUAL (c, dconst1_3))
+ op = build_call_nofold_loc (loc, cbrtfn, 1, arg0);
+
+ /* Now try 1/6. */
+ else if (optimize_insn_for_speed_p ())
+ {
+ REAL_VALUE_TYPE dconst1_6 = dconst1_3;
+ SET_REAL_EXP (&dconst1_6, REAL_EXP (&dconst1_6) - 1);
+
+ if (REAL_VALUES_EQUAL (c, dconst1_6))
+ {
+ op = build_call_nofold_loc (loc, sqrtfn, 1, arg0);
+ op = build_call_nofold_loc (loc, cbrtfn, 1, op);
+ }
+ }
+ }
+
+ if (op)
+ return expand_expr (op, subtarget, mode, EXPAND_NORMAL);
+ }
+
+ return NULL_RTX;
+}
+
/* Expand a call to the pow built-in mathematical function. Return NULL_RTX if
a normal call should be emitted rather than expanding the function
in-line. EXP is the expression that is a call to the builtin
&& ((flag_unsafe_math_optimizations
&& optimize_insn_for_speed_p ()
&& powi_cost (n/2) <= POWI_MAX_MULTS)
- || n == 1))
+ /* Even the c == 0.5 case cannot be done unconditionally
+ when we need to preserve signed zeros, as
+ pow (-0, 0.5) is +0, while sqrt(-0) is -0. */
+ || (!HONOR_SIGNED_ZEROS (mode) && n == 1)
+ /* For c == 1.5 we can assume that x * sqrt (x) is always
+ smaller than pow (x, 1.5) if sqrt will not be expanded
+ as a call. */
+ || (n == 3
+ && (optab_handler (sqrt_optab, mode)->insn_code
+ != CODE_FOR_nothing))))
{
tree call_expr = build_call_nofold (fn, 1, narg0);
/* Use expand_expr in case the newly built call expression
}
}
+ /* Check whether we can do a series of sqrt or cbrt's instead of the pow
+ call. */
+ op = expand_builtin_pow_root (EXPR_LOCATION (exp), arg0, arg1, type,
+ subtarget);
+ if (op)
+ return op;
+
/* Try if the exponent is a third of an integer. In this case
we can expand to x**(n/3) * cbrt(x)**(n%3). As cbrt (x) is
different from pow (x, 1./3.) due to rounding and behavior
{
const struct real_format *fmt;
enum machine_mode fmode, imode, rmode;
- HOST_WIDE_INT hi, lo;
tree arg;
int word, bitpos;
enum insn_code icode;
icode = signbit_optab->handlers [(int) fmode].insn_code;
if (icode != CODE_FOR_nothing)
{
+ rtx last = get_last_insn ();
target = gen_reg_rtx (TYPE_MODE (TREE_TYPE (exp)));
- emit_unop_insn (icode, target, temp, UNKNOWN);
- return target;
+ if (maybe_emit_unop_insn (icode, target, temp, UNKNOWN))
+ return target;
+ delete_insns_since (last);
}
/* For floating point formats without a sign bit, implement signbit
if (bitpos < GET_MODE_BITSIZE (rmode))
{
- if (bitpos < HOST_BITS_PER_WIDE_INT)
- {
- hi = 0;
- lo = (HOST_WIDE_INT) 1 << bitpos;
- }
- else
- {
- hi = (HOST_WIDE_INT) 1 << (bitpos - HOST_BITS_PER_WIDE_INT);
- lo = 0;
- }
+ double_int mask = double_int_setbit (double_int_zero, bitpos);
if (GET_MODE_SIZE (imode) > GET_MODE_SIZE (rmode))
temp = gen_lowpart (rmode, temp);
temp = expand_binop (rmode, and_optab, temp,
- immed_double_const (lo, hi, rmode),
+ immed_double_int_const (mask, rmode),
NULL_RTX, 1, OPTAB_LIB_WIDEN);
}
else
/* Fold a call to __builtin_strlen with argument ARG. */
static tree
-fold_builtin_strlen (location_t loc, tree arg)
+fold_builtin_strlen (location_t loc, tree type, tree arg)
{
if (!validate_arg (arg, POINTER_TYPE))
return NULL_TREE;
tree len = c_strlen (arg, 0);
if (len)
- {
- /* Convert from the internal "sizetype" type to "size_t". */
- if (size_type_node)
- len = fold_convert_loc (loc, size_type_node, len);
- return len;
- }
+ return fold_convert_loc (loc, type, len);
return NULL_TREE;
}
return NULL_TREE;
}
+/* Build a complex (inf +- 0i) for the result of cproj. TYPE is the
+ complex tree type of the result. If NEG is true, the imaginary
+ zero is negative. */
+
+static tree
+build_complex_cproj (tree type, bool neg)
+{
+ REAL_VALUE_TYPE rinf, rzero = dconst0;
+
+ real_inf (&rinf);
+ rzero.sign = neg;
+ return build_complex (type, build_real (TREE_TYPE (type), rinf),
+ build_real (TREE_TYPE (type), rzero));
+}
+
+/* Fold call to builtin cproj, cprojf or cprojl with argument ARG. TYPE is the
+ return type. Return NULL_TREE if no simplification can be made. */
+
+static tree
+fold_builtin_cproj (location_t loc, tree arg, tree type)
+{
+ if (!validate_arg (arg, COMPLEX_TYPE)
+ || TREE_CODE (TREE_TYPE (TREE_TYPE (arg))) != REAL_TYPE)
+ return NULL_TREE;
+
+ /* If there are no infinities, return arg. */
+ if (! HONOR_INFINITIES (TYPE_MODE (TREE_TYPE (type))))
+ return non_lvalue_loc (loc, arg);
+
+ /* Calculate the result when the argument is a constant. */
+ if (TREE_CODE (arg) == COMPLEX_CST)
+ {
+ const REAL_VALUE_TYPE *real = TREE_REAL_CST_PTR (TREE_REALPART (arg));
+ const REAL_VALUE_TYPE *imag = TREE_REAL_CST_PTR (TREE_IMAGPART (arg));
+
+ if (real_isinf (real) || real_isinf (imag))
+ return build_complex_cproj (type, imag->sign);
+ else
+ return arg;
+ }
+ else if (TREE_CODE (arg) == COMPLEX_EXPR)
+ {
+ tree real = TREE_OPERAND (arg, 0);
+ tree imag = TREE_OPERAND (arg, 1);
+
+ STRIP_NOPS (real);
+ STRIP_NOPS (imag);
+
+ /* If the real part is inf and the imag part is known to be
+ nonnegative, return (inf + 0i). Remember side-effects are
+ possible in the imag part. */
+ if (TREE_CODE (real) == REAL_CST
+ && real_isinf (TREE_REAL_CST_PTR (real))
+ && tree_expr_nonnegative_p (imag))
+ return omit_one_operand_loc (loc, type,
+ build_complex_cproj (type, false),
+ arg);
+
+ /* If the imag part is inf, return (inf+I*copysign(0,imag)).
+ Remember side-effects are possible in the real part. */
+ if (TREE_CODE (imag) == REAL_CST
+ && real_isinf (TREE_REAL_CST_PTR (imag)))
+ return
+ omit_one_operand_loc (loc, type,
+ build_complex_cproj (type, TREE_REAL_CST_PTR
+ (imag)->sign), arg);
+ }
+
+ return NULL_TREE;
+}
+
/* Fold a builtin function call to sqrt, sqrtf, or sqrtl with argument ARG.
Return NULL_TREE if no simplification can be made. */
enum built_in_function fcode = DECL_FUNCTION_CODE (fndecl);
switch (fcode)
{
-
case BUILT_IN_CONSTANT_P:
{
tree val = fold_builtin_constant_p (arg0);
return fold_builtin_classify_type (arg0);
case BUILT_IN_STRLEN:
- return fold_builtin_strlen (loc, arg0);
+ return fold_builtin_strlen (loc, type, arg0);
CASE_FLT_FN (BUILT_IN_FABS):
return fold_builtin_fabs (loc, arg0, type);
CASE_FLT_FN (BUILT_IN_CCOSH):
return fold_builtin_ccos(loc, arg0, type, fndecl, /*hyper=*/ true);
+ CASE_FLT_FN (BUILT_IN_CPROJ):
+ return fold_builtin_cproj(loc, arg0, type);
+
CASE_FLT_FN (BUILT_IN_CSIN):
if (validate_arg (arg0, COMPLEX_TYPE)
&& TREE_CODE (TREE_TYPE (TREE_TYPE (arg0))) == REAL_TYPE)
case BUILT_IN_VPRINTF:
return fold_builtin_printf (loc, fndecl, arg0, NULL_TREE, ignore, fcode);
+ case BUILT_IN_FREE:
+ if (integer_zerop (arg0))
+ return build_empty_stmt (loc);
+ break;
+
default:
break;
}
if (avoid_folding_inline_builtin (fndecl))
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);
+ return targetm.fold_builtin (fndecl, exp, ignore);
else
{
if (nargs <= MAX_ARGS_TO_FOLD_BUILTIN)
case BUILT_IN_ABORT:
abort_libfunc = set_user_assembler_libfunc ("abort", asmspec);
break;
+ case BUILT_IN_FFS:
+ if (INT_TYPE_SIZE < BITS_PER_WORD)
+ {
+ set_user_assembler_libfunc ("ffs", asmspec);
+ set_optab_libfunc (ffs_optab, mode_for_size (INT_TYPE_SIZE,
+ MODE_INT, 0), "ffs");
+ }
+ break;
default:
break;
}