diff options
author | Richard Sandiford <richard.sandiford@arm.com> | 2015-10-23 10:01:47 +0000 |
---|---|---|
committer | Richard Sandiford <rsandifo@gcc.gnu.org> | 2015-10-23 10:01:47 +0000 |
commit | 67dbe5829e2f9cac9deb756762cdaf5a8829cb31 (patch) | |
tree | 2104e5a46faba7156714cceac0b8be8dce7c9b63 /gcc/builtins.c | |
parent | 735a559c68e208b9dd5b5a4bb7e109289743fbeb (diff) | |
download | gcc-67dbe5829e2f9cac9deb756762cdaf5a8829cb31.zip gcc-67dbe5829e2f9cac9deb756762cdaf5a8829cb31.tar.gz gcc-67dbe5829e2f9cac9deb756762cdaf5a8829cb31.tar.bz2 |
Move fold_trunc_transparent_mathfn to match.pd
This moves the fold rules for trunc, floor, ceil, round, nearbyint and
rint in one go, since they're tested as a group. Most of the code is
supporting the f(x)->x fold when x is known to be integer-valued.
Like with the non-negative test, this is probably more elegantly handled
by tracking range information for reals, but until that happens, I think
we should handle it analogously to tree_expr_nonnegative_p.
I've incorporated the fix for PR68031 in the new version of
integer_valued_real_p. However, it seemed confusing to test for an
SSA name at the head of the function rather than the case statement,
and not fall through to tree_simple_nonnegative_warnv_p (which
conceptually shouldn't care whether an update is in progress).
But tree_simple_nonnegative_warnv_p is a no-op for SSA names,
so I simply changed it to:
return (!name_registered_for_update_p (t)
&& depth < PARAM_VALUE (PARAM_MAX_SSA_NAME_QUERY_DEPTH)
&& gimple_stmt_nonnegative_warnv_p (SSA_NAME_DEF_STMT (t),
strict_overflow_p, depth));
and used that in the new code too.
Doing these folds later meant that IPA would start to use information
about the aborting sinf and floor in 20030125-1.c before the folds
kicked in. I changed them from noinline to weak to stop that.
Tested on x86_64-linux-gnu, aarch64-linux-gnu and arm-linux-gnueabi.
gcc/
* builtins.c (integer_valued_real_p): Move to fold-const.c.
(fold_trunc_transparent_mathfn, fold_builtin_trunc, fold_builtin_floor)
(fold_builtin_ceil, fold_builtin_round): Delete.
(fold_builtin_1): Handle constant trunc, floor, ceil and round
arguments here.
* convert.c (convert_to_real): Remove narrowing of rounding
functions.
* fold-const.h (integer_valued_real_unary_p)
(integer_valued_real_binary_p, integer_valued_real_call_p)
(integer_valued_real_single_p, integer_valued_real_p): Declare.
* fold-const.c (tree_single_nonnegative_warnv_p): Move
name_registered_for_update_p check to SSA_NAME case statement.
Don't call tree_simple_nonnegative_warnv_p for SSA names.
(integer_valued_real_unary_p, integer_valued_real_binary_p)
(integer_valued_real_call_p, integer_valued_real_single_p)
(integer_valued_real_invalid_p): New functions.
(integer_valued_real_p): Move from fold-const.c and rework
to call the functions above. Handle SSA names.
* gimple-fold.h (gimple_stmt_integer_valued_real_p): Declare.
* gimple-fold.c (gimple_assign_integer_valued_real_p)
(gimple_call_integer_valued_real_p, gimple_phi_integer_valued_real_p)
(gimple_stmt_integer_valued_real_p): New functions.
* match.pd: Fold f(f(x))->f(x) for fp->fp rounding functions f.
Fold f(x)->x for the same f if x is known to be integer-valued.
Fold f(extend(x))->extend(f'(x)) if doing so doesn't affect
the result. Canonicalize floor(x) as trunc(x) if x is
nonnegative.
gcc/testsuite/
* gcc.c-torture/execute/20030125-1.c (floor, floorf, sin, sinf):
Make weak rather than noinline.
* gcc.dg/builtins-57.c: Compile with -O.
* gcc.dg/torture/builtin-integral-1.c: Skip for -O0.
From-SVN: r229221
Diffstat (limited to 'gcc/builtins.c')
-rw-r--r-- | gcc/builtins.c | 284 |
1 files changed, 44 insertions, 240 deletions
diff --git a/gcc/builtins.c b/gcc/builtins.c index 02bf9f6..8b5e3f3 100644 --- a/gcc/builtins.c +++ b/gcc/builtins.c @@ -154,16 +154,10 @@ 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, ...); static bool validate_arg (const_tree, enum tree_code code); -static bool integer_valued_real_p (tree); -static tree fold_trunc_transparent_mathfn (location_t, tree, tree); static rtx expand_builtin_fabs (tree, rtx, rtx); static rtx expand_builtin_signbit (tree, rtx); static tree fold_builtin_pow (location_t, tree, tree, tree, tree); static tree fold_builtin_powi (location_t, tree, tree, tree, tree); -static tree fold_builtin_trunc (location_t, tree, tree); -static tree fold_builtin_floor (location_t, tree, tree); -static tree fold_builtin_ceil (location_t, tree, tree); -static tree fold_builtin_round (location_t, tree, tree); static tree fold_builtin_int_roundingfn (location_t, tree, tree); static tree fold_builtin_bitop (tree, tree); static tree fold_builtin_strchr (location_t, tree, tree, tree); @@ -7320,117 +7314,6 @@ fold_builtin_nan (tree arg, tree type, int quiet) return build_real (type, real); } -/* Return true if the floating point expression T has an integer value. - We also allow +Inf, -Inf and NaN to be considered integer values. */ - -static bool -integer_valued_real_p (tree t) -{ - switch (TREE_CODE (t)) - { - case FLOAT_EXPR: - return true; - - case ABS_EXPR: - case SAVE_EXPR: - return integer_valued_real_p (TREE_OPERAND (t, 0)); - - case COMPOUND_EXPR: - case MODIFY_EXPR: - case BIND_EXPR: - return integer_valued_real_p (TREE_OPERAND (t, 1)); - - case PLUS_EXPR: - case MINUS_EXPR: - case MULT_EXPR: - case MIN_EXPR: - case MAX_EXPR: - return integer_valued_real_p (TREE_OPERAND (t, 0)) - && integer_valued_real_p (TREE_OPERAND (t, 1)); - - case COND_EXPR: - return integer_valued_real_p (TREE_OPERAND (t, 1)) - && integer_valued_real_p (TREE_OPERAND (t, 2)); - - case REAL_CST: - return real_isinteger (TREE_REAL_CST_PTR (t), TYPE_MODE (TREE_TYPE (t))); - - CASE_CONVERT: - { - tree type = TREE_TYPE (TREE_OPERAND (t, 0)); - if (TREE_CODE (type) == INTEGER_TYPE) - return true; - if (TREE_CODE (type) == REAL_TYPE) - return integer_valued_real_p (TREE_OPERAND (t, 0)); - break; - } - - case CALL_EXPR: - switch (builtin_mathfn_code (t)) - { - CASE_FLT_FN (BUILT_IN_CEIL): - CASE_FLT_FN (BUILT_IN_FLOOR): - CASE_FLT_FN (BUILT_IN_NEARBYINT): - CASE_FLT_FN (BUILT_IN_RINT): - CASE_FLT_FN (BUILT_IN_ROUND): - CASE_FLT_FN (BUILT_IN_TRUNC): - return true; - - CASE_FLT_FN (BUILT_IN_FMIN): - CASE_FLT_FN (BUILT_IN_FMAX): - return integer_valued_real_p (CALL_EXPR_ARG (t, 0)) - && integer_valued_real_p (CALL_EXPR_ARG (t, 1)); - - default: - break; - } - break; - - default: - break; - } - return false; -} - -/* FNDECL is assumed to be a builtin where truncation can be propagated - across (for instance floor((double)f) == (double)floorf (f). - Do the transformation for a call with argument ARG. */ - -static tree -fold_trunc_transparent_mathfn (location_t loc, tree fndecl, tree arg) -{ - enum built_in_function fcode = DECL_FUNCTION_CODE (fndecl); - - if (!validate_arg (arg, REAL_TYPE)) - return NULL_TREE; - - /* Integer rounding functions are idempotent. */ - if (fcode == builtin_mathfn_code (arg)) - return arg; - - /* If argument is already integer valued, and we don't need to worry - about setting errno, there's no need to perform rounding. */ - if (! flag_errno_math && integer_valued_real_p (arg)) - return arg; - - if (optimize) - { - tree arg0 = strip_float_extensions (arg); - tree ftype = TREE_TYPE (TREE_TYPE (fndecl)); - tree newtype = TREE_TYPE (arg0); - tree decl; - - if (TYPE_PRECISION (newtype) < TYPE_PRECISION (ftype) - && (decl = mathfn_built_in (newtype, fcode))) - return fold_convert_loc (loc, ftype, - build_call_expr_loc (loc, decl, 1, - fold_convert_loc (loc, - newtype, - arg0))); - } - return NULL_TREE; -} - /* FNDECL is assumed to be builtin which can narrow the FP type of the argument, for instance lround((double)f) -> lroundf (f). Do the transformation for a call with argument ARG. */ @@ -7645,121 +7528,6 @@ fold_builtin_cexp (location_t loc, tree arg0, tree type) return NULL_TREE; } -/* Fold function call to builtin trunc, truncf or truncl with argument ARG. - Return NULL_TREE if no simplification can be made. */ - -static tree -fold_builtin_trunc (location_t loc, tree fndecl, tree arg) -{ - if (!validate_arg (arg, REAL_TYPE)) - return NULL_TREE; - - /* Optimize trunc of constant value. */ - if (TREE_CODE (arg) == REAL_CST && !TREE_OVERFLOW (arg)) - { - REAL_VALUE_TYPE r, x; - tree type = TREE_TYPE (TREE_TYPE (fndecl)); - - x = TREE_REAL_CST (arg); - real_trunc (&r, TYPE_MODE (type), &x); - return build_real (type, r); - } - - return fold_trunc_transparent_mathfn (loc, fndecl, arg); -} - -/* Fold function call to builtin floor, floorf or floorl with argument ARG. - Return NULL_TREE if no simplification can be made. */ - -static tree -fold_builtin_floor (location_t loc, tree fndecl, tree arg) -{ - if (!validate_arg (arg, REAL_TYPE)) - return NULL_TREE; - - /* Optimize floor of constant value. */ - if (TREE_CODE (arg) == REAL_CST && !TREE_OVERFLOW (arg)) - { - REAL_VALUE_TYPE x; - - x = TREE_REAL_CST (arg); - if (! REAL_VALUE_ISNAN (x) || ! flag_errno_math) - { - tree type = TREE_TYPE (TREE_TYPE (fndecl)); - REAL_VALUE_TYPE r; - - real_floor (&r, TYPE_MODE (type), &x); - return build_real (type, r); - } - } - - /* Fold floor (x) where x is nonnegative to trunc (x). */ - if (tree_expr_nonnegative_p (arg)) - { - tree truncfn = mathfn_built_in (TREE_TYPE (arg), BUILT_IN_TRUNC); - if (truncfn) - return build_call_expr_loc (loc, truncfn, 1, arg); - } - - return fold_trunc_transparent_mathfn (loc, fndecl, arg); -} - -/* Fold function call to builtin ceil, ceilf or ceill with argument ARG. - Return NULL_TREE if no simplification can be made. */ - -static tree -fold_builtin_ceil (location_t loc, tree fndecl, tree arg) -{ - if (!validate_arg (arg, REAL_TYPE)) - return NULL_TREE; - - /* Optimize ceil of constant value. */ - if (TREE_CODE (arg) == REAL_CST && !TREE_OVERFLOW (arg)) - { - REAL_VALUE_TYPE x; - - x = TREE_REAL_CST (arg); - if (! REAL_VALUE_ISNAN (x) || ! flag_errno_math) - { - tree type = TREE_TYPE (TREE_TYPE (fndecl)); - REAL_VALUE_TYPE r; - - real_ceil (&r, TYPE_MODE (type), &x); - return build_real (type, r); - } - } - - return fold_trunc_transparent_mathfn (loc, fndecl, arg); -} - -/* Fold function call to builtin round, roundf or roundl with argument ARG. - Return NULL_TREE if no simplification can be made. */ - -static tree -fold_builtin_round (location_t loc, tree fndecl, tree arg) -{ - if (!validate_arg (arg, REAL_TYPE)) - return NULL_TREE; - - /* Optimize round of constant value. */ - if (TREE_CODE (arg) == REAL_CST && !TREE_OVERFLOW (arg)) - { - REAL_VALUE_TYPE x; - - x = TREE_REAL_CST (arg); - if (! REAL_VALUE_ISNAN (x) || ! flag_errno_math) - { - tree type = TREE_TYPE (TREE_TYPE (fndecl)); - REAL_VALUE_TYPE r; - - real_round (&r, TYPE_MODE (type), &x); - return build_real (type, r); - } - } - - return fold_trunc_transparent_mathfn (loc, fndecl, arg); -} - /* Fold function call to builtin lround, lroundf or lroundl (or the corresponding long long versions) and other rounding functions. ARG is the argument to the call. Return NULL_TREE if no simplification @@ -9696,20 +9464,56 @@ fold_builtin_1 (location_t loc, tree fndecl, tree arg0) return fold_builtin_nan (arg0, type, false); CASE_FLT_FN (BUILT_IN_FLOOR): - return fold_builtin_floor (loc, fndecl, arg0); + if (TREE_CODE (arg0) == REAL_CST && !TREE_OVERFLOW (arg0)) + { + REAL_VALUE_TYPE x = TREE_REAL_CST (arg0); + if (!REAL_VALUE_ISNAN (x) || !flag_errno_math) + { + tree type = TREE_TYPE (TREE_TYPE (fndecl)); + REAL_VALUE_TYPE r; + real_floor (&r, TYPE_MODE (type), &x); + return build_real (type, r); + } + } + break; CASE_FLT_FN (BUILT_IN_CEIL): - return fold_builtin_ceil (loc, fndecl, arg0); + if (TREE_CODE (arg0) == REAL_CST && !TREE_OVERFLOW (arg0)) + { + REAL_VALUE_TYPE x = TREE_REAL_CST (arg0); + if (!REAL_VALUE_ISNAN (x) || !flag_errno_math) + { + tree type = TREE_TYPE (TREE_TYPE (fndecl)); + REAL_VALUE_TYPE r; + real_ceil (&r, TYPE_MODE (type), &x); + return build_real (type, r); + } + } + break; CASE_FLT_FN (BUILT_IN_TRUNC): - return fold_builtin_trunc (loc, fndecl, arg0); + if (TREE_CODE (arg0) == REAL_CST && !TREE_OVERFLOW (arg0)) + { + REAL_VALUE_TYPE x = TREE_REAL_CST (arg0); + REAL_VALUE_TYPE r; + real_trunc (&r, TYPE_MODE (type), &x); + return build_real (type, r); + } + break; CASE_FLT_FN (BUILT_IN_ROUND): - return fold_builtin_round (loc, fndecl, arg0); - - CASE_FLT_FN (BUILT_IN_NEARBYINT): - CASE_FLT_FN (BUILT_IN_RINT): - return fold_trunc_transparent_mathfn (loc, fndecl, arg0); + if (TREE_CODE (arg0) == REAL_CST && !TREE_OVERFLOW (arg0)) + { + REAL_VALUE_TYPE x = TREE_REAL_CST (arg0); + if (!REAL_VALUE_ISNAN (x) || !flag_errno_math) + { + tree type = TREE_TYPE (TREE_TYPE (fndecl)); + REAL_VALUE_TYPE r; + real_round (&r, TYPE_MODE (type), &x); + return build_real (type, r); + } + } + break; CASE_FLT_FN (BUILT_IN_ICEIL): CASE_FLT_FN (BUILT_IN_LCEIL): |