aboutsummaryrefslogtreecommitdiff
path: root/gcc/fold-const.c
diff options
context:
space:
mode:
authorRichard Sandiford <richard.sandiford@arm.com>2015-10-23 10:01:47 +0000
committerRichard Sandiford <rsandifo@gcc.gnu.org>2015-10-23 10:01:47 +0000
commit67dbe5829e2f9cac9deb756762cdaf5a8829cb31 (patch)
tree2104e5a46faba7156714cceac0b8be8dce7c9b63 /gcc/fold-const.c
parent735a559c68e208b9dd5b5a4bb7e109289743fbeb (diff)
downloadgcc-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.c222
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.