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/fold-const.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/fold-const.c')
-rw-r--r-- | gcc/fold-const.c | 222 |
1 files changed, 214 insertions, 8 deletions
diff --git a/gcc/fold-const.c b/gcc/fold-const.c index c4be017..6eed7b6 100644 --- a/gcc/fold-const.c +++ b/gcc/fold-const.c @@ -12896,10 +12896,6 @@ tree_binary_nonnegative_warnv_p (enum tree_code code, tree type, tree op0, bool tree_single_nonnegative_warnv_p (tree t, bool *strict_overflow_p, int depth) { - if (TREE_CODE (t) == SSA_NAME - && name_registered_for_update_p (t)) - return false; - if (TYPE_UNSIGNED (TREE_TYPE (t))) return true; @@ -12923,11 +12919,11 @@ tree_single_nonnegative_warnv_p (tree t, bool *strict_overflow_p, int depth) If this code misses important cases that unbounded recursion would not, passes that need this information could be revised to provide it through dataflow propagation. */ - if (depth < PARAM_VALUE (PARAM_MAX_SSA_NAME_QUERY_DEPTH)) - return gimple_stmt_nonnegative_warnv_p (SSA_NAME_DEF_STMT (t), - strict_overflow_p, depth); + 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)); - /* Fallthru. */ default: return tree_simple_nonnegative_warnv_p (TREE_CODE (t), TREE_TYPE (t)); } @@ -13440,6 +13436,216 @@ tree_single_nonzero_warnv_p (tree t, bool *strict_overflow_p) return false; } +#define integer_valued_real_p(X) \ + _Pragma ("GCC error \"Use RECURSE for recursive calls\"") 0 + +#define RECURSE(X) \ + ((integer_valued_real_p) (X, depth + 1)) + +/* Return true if the floating point result of (CODE OP0) has an + integer value. We also allow +Inf, -Inf and NaN to be considered + integer values. + + DEPTH is the current nesting depth of the query. */ + +bool +integer_valued_real_unary_p (tree_code code, tree op0, int depth) +{ + switch (code) + { + case FLOAT_EXPR: + return true; + + case ABS_EXPR: + return RECURSE (op0); + + CASE_CONVERT: + { + tree type = TREE_TYPE (op0); + if (TREE_CODE (type) == INTEGER_TYPE) + return true; + if (TREE_CODE (type) == REAL_TYPE) + return RECURSE (op0); + break; + } + + default: + break; + } + return false; +} + +/* Return true if the floating point result of (CODE OP0 OP1) has an + integer value. We also allow +Inf, -Inf and NaN to be considered + integer values. + + DEPTH is the current nesting depth of the query. */ + +bool +integer_valued_real_binary_p (tree_code code, tree op0, tree op1, int depth) +{ + switch (code) + { + case PLUS_EXPR: + case MINUS_EXPR: + case MULT_EXPR: + case MIN_EXPR: + case MAX_EXPR: + return RECURSE (op0) && RECURSE (op1); + + default: + break; + } + return false; +} + +/* Return true if the floating point result of calling FNDECL with arguments + ARG0 and ARG1 has an integer value. We also allow +Inf, -Inf and NaN to be + considered integer values. If FNDECL takes fewer than 2 arguments, + the remaining ARGn are null. + + DEPTH is the current nesting depth of the query. */ + +bool +integer_valued_real_call_p (tree fndecl, tree arg0, tree arg1, int depth) +{ + if (fndecl && DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL) + switch (DECL_FUNCTION_CODE (fndecl)) + { + 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 RECURSE (arg0) && RECURSE (arg1); + + default: + break; + } + return false; +} + +/* Return true if the floating point expression T (a GIMPLE_SINGLE_RHS) + has an integer value. We also allow +Inf, -Inf and NaN to be + considered integer values. + + DEPTH is the current nesting depth of the query. */ + +bool +integer_valued_real_single_p (tree t, int depth) +{ + switch (TREE_CODE (t)) + { + case REAL_CST: + return real_isinteger (TREE_REAL_CST_PTR (t), TYPE_MODE (TREE_TYPE (t))); + + case COND_EXPR: + return RECURSE (TREE_OPERAND (t, 1)) && RECURSE (TREE_OPERAND (t, 2)); + + case SSA_NAME: + /* Limit the depth of recursion to avoid quadratic behavior. + This is expected to catch almost all occurrences in practice. + If this code misses important cases that unbounded recursion + would not, passes that need this information could be revised + to provide it through dataflow propagation. */ + return (!name_registered_for_update_p (t) + && depth < PARAM_VALUE (PARAM_MAX_SSA_NAME_QUERY_DEPTH) + && gimple_stmt_integer_valued_real_p (SSA_NAME_DEF_STMT (t), + depth)); + + default: + break; + } + return false; +} + +/* Return true if the floating point expression T (a GIMPLE_INVALID_RHS) + has an integer value. We also allow +Inf, -Inf and NaN to be + considered integer values. + + DEPTH is the current nesting depth of the query. */ + +static bool +integer_valued_real_invalid_p (tree t, int depth) +{ + switch (TREE_CODE (t)) + { + case COMPOUND_EXPR: + case MODIFY_EXPR: + case BIND_EXPR: + return RECURSE (TREE_OPERAND (t, 1)); + + case SAVE_EXPR: + return RECURSE (TREE_OPERAND (t, 0)); + + default: + break; + } + return false; +} + +#undef RECURSE +#undef integer_valued_real_p + +/* Return true if the floating point expression T has an integer value. + We also allow +Inf, -Inf and NaN to be considered integer values. + + DEPTH is the current nesting depth of the query. */ + +bool +integer_valued_real_p (tree t, int depth) +{ + if (t == error_mark_node) + return false; + + tree_code code = TREE_CODE (t); + switch (TREE_CODE_CLASS (code)) + { + case tcc_binary: + case tcc_comparison: + return integer_valued_real_binary_p (code, TREE_OPERAND (t, 0), + TREE_OPERAND (t, 1), depth); + + case tcc_unary: + return integer_valued_real_unary_p (code, TREE_OPERAND (t, 0), depth); + + case tcc_constant: + case tcc_declaration: + case tcc_reference: + return integer_valued_real_single_p (t, depth); + + default: + break; + } + + switch (code) + { + case COND_EXPR: + case SSA_NAME: + return integer_valued_real_single_p (t, depth); + + case CALL_EXPR: + { + tree arg0 = (call_expr_nargs (t) > 0 + ? CALL_EXPR_ARG (t, 0) + : NULL_TREE); + tree arg1 = (call_expr_nargs (t) > 1 + ? CALL_EXPR_ARG (t, 1) + : NULL_TREE); + return integer_valued_real_call_p (get_callee_fndecl (t), + arg0, arg1, depth); + } + + default: + return integer_valued_real_invalid_p (t, depth); + } +} + /* Given the components of a binary expression CODE, TYPE, OP0 and OP1, attempt to fold the expression to a constant without modifying TYPE, OP0 or OP1. |