X-Git-Url: http://git.sourceforge.jp/view?a=blobdiff_plain;f=gcc%2Fbuiltins.c;h=8541b829801f7de3647bbb48fb0c1f23f843030d;hb=4b4f621d9e7f639f8ffc140f37da4e5a3a5c3401;hp=75a7e10ea6daa535deac523213c496cd3431fa5a;hpb=b0e7c4d475e386f523616f07106a6a3e5b764989;p=pf3gnuchains%2Fgcc-fork.git diff --git a/gcc/builtins.c b/gcc/builtins.c index 75a7e10ea6d..8541b829801 100644 --- a/gcc/builtins.c +++ b/gcc/builtins.c @@ -1,6 +1,6 @@ /* 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. @@ -135,7 +135,7 @@ static rtx expand_builtin_expect (tree, rtx); 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, ...); @@ -323,7 +323,10 @@ get_object_alignment (tree exp, unsigned int align, unsigned int max_align) 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)) @@ -430,6 +433,7 @@ c_strlen (tree src, int only_value) HOST_WIDE_INT offset; int max; const char *ptr; + location_t loc; STRIP_NOPS (src); if (TREE_CODE (src) == COND_EXPR @@ -447,6 +451,11 @@ c_strlen (tree src, int only_value) && (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; @@ -472,7 +481,7 @@ c_strlen (tree src, int only_value) 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 @@ -491,7 +500,7 @@ c_strlen (tree src, int only_value) /* 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; @@ -551,7 +560,7 @@ c_readstr (const char *str, enum machine_mode mode) && 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]; @@ -1313,7 +1322,7 @@ apply_result_size (void) 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]; @@ -1872,7 +1881,9 @@ expand_errno_check (tree exp, rtx target) /* 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. */ @@ -2301,9 +2312,12 @@ expand_builtin_interclass_mathfn (tree exp, rtx target, rtx subtarget) 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 @@ -2321,8 +2335,10 @@ expand_builtin_interclass_mathfn (tree exp, rtx target, rtx subtarget) /* 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; @@ -2907,6 +2923,95 @@ expand_powi (rtx x, enum machine_mode mode, HOST_WIDE_INT n) 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 @@ -2969,7 +3074,16 @@ expand_builtin_pow (tree exp, rtx target, rtx subtarget) && ((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 @@ -2992,6 +3106,13 @@ expand_builtin_pow (tree exp, rtx target, rtx subtarget) } } + /* 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 @@ -5158,7 +5279,6 @@ expand_builtin_signbit (tree exp, rtx target) { 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; @@ -5183,9 +5303,11 @@ expand_builtin_signbit (tree exp, rtx target) 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 @@ -5232,21 +5354,12 @@ expand_builtin_signbit (tree exp, rtx target) 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 @@ -6614,7 +6727,7 @@ fold_builtin_classify_type (tree arg) /* 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; @@ -6623,12 +6736,7 @@ fold_builtin_strlen (location_t loc, tree arg) 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; } @@ -6934,6 +7042,77 @@ fold_builtin_cabs (location_t loc, tree arg, tree type, tree fndecl) 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. */ @@ -9638,7 +9817,6 @@ fold_builtin_1 (location_t loc, tree fndecl, tree arg0, bool ignore) enum built_in_function fcode = DECL_FUNCTION_CODE (fndecl); switch (fcode) { - case BUILT_IN_CONSTANT_P: { tree val = fold_builtin_constant_p (arg0); @@ -9656,7 +9834,7 @@ fold_builtin_1 (location_t loc, tree fndecl, tree arg0, bool ignore) 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); @@ -9691,6 +9869,9 @@ fold_builtin_1 (location_t loc, tree fndecl, tree arg0, bool ignore) 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) @@ -10017,6 +10198,11 @@ fold_builtin_1 (location_t loc, tree fndecl, tree arg0, bool ignore) 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; } @@ -10515,9 +10701,8 @@ fold_call_expr (location_t loc, tree exp, bool ignore) 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) @@ -13590,6 +13775,14 @@ set_builtin_user_assembler_name (tree decl, const char *asmspec) 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; }