summaryrefslogtreecommitdiff
path: root/gcc/fold-const.c
diff options
context:
space:
mode:
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 c4be017c50c..6eed7b611c6 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.