diff options
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 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. |