diff options
author | Ian Lance Taylor <iant@google.com> | 2007-02-13 22:34:45 +0000 |
---|---|---|
committer | Ian Lance Taylor <ian@gcc.gnu.org> | 2007-02-13 22:34:45 +0000 |
commit | 6ac015100fa98539d577a6c04b69693aefce35dc (patch) | |
tree | 120377355d73c96495ca9008ae2e8dd5c40948af /gcc/fold-const.c | |
parent | 30d18db4847eb0995d65531e117c7fe75d1fc428 (diff) | |
download | gcc-6ac015100fa98539d577a6c04b69693aefce35dc.zip gcc-6ac015100fa98539d577a6c04b69693aefce35dc.tar.gz gcc-6ac015100fa98539d577a6c04b69693aefce35dc.tar.bz2 |
common.opt: Add Wstrict-overflow and Wstrict-overflow=.
./: * common.opt: Add Wstrict-overflow and Wstrict-overflow=.
* flags.h (warn_strict_overflow): Declare.
(enum warn_strict_overflow_code): Define.
(issue_strict_overflow_warning): New static inline function.
* opts.c (warn_strict_overflow): New variable.
(common_handle_option): Handle OPT_Wstrict_overflow and
OPT_Wstrict_overflow_.
* c-opts.c (c_common_handle_option): Set warn_strict_overflow for
OPT_Wall.
* fold-const.c: Include intl.h.
(fold_deferring_overflow_warnings): New static variable.
(fold_deferred_overflow_warning): New static variable.
(fold_deferred_overflow_code): New static variable.
(fold_defer_overflow_warnings): New function.
(fold_undefer_overflow_warnings): New function.
(fold_undefer_and_ignore_overflow_warnings): New function.
(fold_deferring_overflow_warnings_p): New function.
(fold_overflow_warning): New static function.
(make_range): Add strict_overflow_p parameter. Change all
callers.
(extract_muldiv, extract_muldiv_1): Likewise.
(fold_unary) [ABS_EXPR]: Check ABS_EXPR before calling
tree_expr_nonnegative_p.
(fold_negate_expr): Call fold_overflow_warning.
(fold_range_test): Likewise.
(fold_comparison): Likewise.
(fold_binary): Likewise. Call tree_expr_nonnegative_warnv_p
instead of tree_expr_nonnegative_p.
(tree_expr_nonnegative_warnv_p): Rename from
tree_expr_nonnegative_p, add strict_overflow_p parameter.
(tree_expr_nonnegative_p): New function.
(tree_expr_nonzero_warnv_p): Rename from tree_expr_nonzero_p, add
strict_overflow_p parameter.
(tree_expr_nonzero_p): New function.
* passes.c (verify_interpass_invariants): New static function.
(execute_one_pass): Call it.
* tree-ssa-loop-niter.c (expand_simple_operations): Ignore fold
warnings.
(number_of_iterations_exit, loop_niter_by_eval): Likewise.
(estimate_numbers_of_iterations): Likewise.
(scev_probably_wraps_p): Likewise.
* tree-ssa-ccp.c: Include "toplev.h".
(evaluate_stmt): Defer fold overflow warnings until we know we are
going to optimize.
(struct fold_stmt_r_data): Add stmt field.
(fold_stmt_r): Defer fold overflow warnings until we know we
optimized.
(fold_stmt): Initialize stmt field of fold_stmt_r_data.
(fold_stmt_inplace): Likewise.
* tree-cfgcleanup.c: Include "toplev.h" rather than "errors.h".
(cleanup_control_expr_graph): Defer fold overflow warnings until
we know we are going to optimize.
* tree-cfg.c (fold_cond_expr_cond): Likewise.
* tree-ssa-threadedge.c (simplify_control_stmt_condition):
Likewise.
* tree-vrp.c (vrp_expr_computes_nonnegative): Call
tree_expr_nonnegative_warnv_p instead of tree_expr_nonnegative_p.
* tree-ssa-loop-manip.c (create_iv): Likewise.
* c-typeck.c (build_conditional_expr): Likewise.
(build_binary_op): Likewise.
* tree-vrp.c (vrp_expr_computes_nonzero): Call
tree_expr_nonzero_warnv_p instead of tree_expr_nonzero_p.
(extract_range_from_unary_expr): Likewise.
* simplify-rtx.c (simplify_const_relational_operation): Warn when
assuming that signed overflow does not occur.
* c-common.c (pointer_int_sum): Ignore fold overflow warnings.
* tree.h (tree_expr_nonnegative_warnv_p): Declare.
(fold_defer_overflow_warnings): Declare.
(fold_undefer_overflow_warnings): Declare.
(fold_undefer_and_ignore_overflow_warnings): Declare.
(fold_deferring_overflow_warnings_p): Declare.
(tree_expr_nonzero_warnv_p): Declare.
* doc/invoke.texi (Option Summary): Add -Wstrict-overflow to list
of warning options.
(Warning Options): Document -Wstrict-overflow.
* Makefile.in (tree-ssa-threadedge.o): Depend on toplev.h.
(tree-ssa-ccp.o): Likewise.
(tree-cfgcleanup.o): Change errors.h dependency to toplev.h.
(fold-const.o): Depend on intl.h.
testsuite/:
* gcc.dg/Wstrict-overflow-1.c: New test.
* gcc.dg/Wstrict-overflow-2.c: New test.
* gcc.dg/Wstrict-overflow-3.c: New test.
* gcc.dg/Wstrict-overflow-4.c: New test.
* gcc.dg/Wstrict-overflow-5.c: New test.
* gcc.dg/Wstrict-overflow-6.c: New test.
* gcc.dg/Wstrict-overflow-7.c: New test.
* gcc.dg/Wstrict-overflow-8.c: New test.
* gcc.dg/Wstrict-overflow-9.c: New test.
* gcc.dg/Wstrict-overflow-10.c: New test.
From-SVN: r121895
Diffstat (limited to 'gcc/fold-const.c')
-rw-r--r-- | gcc/fold-const.c | 758 |
1 files changed, 621 insertions, 137 deletions
diff --git a/gcc/fold-const.c b/gcc/fold-const.c index d20d78f..7d66736 100644 --- a/gcc/fold-const.c +++ b/gcc/fold-const.c @@ -59,6 +59,7 @@ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA #include "expr.h" #include "tm_p.h" #include "toplev.h" +#include "intl.h" #include "ggc.h" #include "hashtab.h" #include "langhooks.h" @@ -119,7 +120,7 @@ static int simple_operand_p (tree); static tree range_binop (enum tree_code, tree, tree, int, tree, int); static tree range_predecessor (tree); static tree range_successor (tree); -static tree make_range (tree, int *, tree *, tree *); +static tree make_range (tree, int *, tree *, tree *, bool *); static tree build_range_check (tree, tree, int, tree, tree); static int merge_ranges (int *, tree *, tree *, int, tree, tree, int, tree, tree); @@ -128,8 +129,8 @@ static tree fold_cond_expr_with_comparison (tree, tree, tree, tree); static tree unextend (tree, int, int, tree); static tree fold_truthop (enum tree_code, tree, tree, tree); static tree optimize_minmax_comparison (enum tree_code, tree, tree, tree); -static tree extract_muldiv (tree, tree, enum tree_code, tree); -static tree extract_muldiv_1 (tree, tree, enum tree_code, tree); +static tree extract_muldiv (tree, tree, enum tree_code, tree, bool *); +static tree extract_muldiv_1 (tree, tree, enum tree_code, tree, bool *); static int multiple_of_p (tree, tree, tree); static tree fold_binary_op_with_conditional_arg (enum tree_code, tree, tree, tree, @@ -901,6 +902,122 @@ div_if_zero_remainder (enum tree_code code, tree arg1, tree arg2) return build_int_cst_wide (type, quol, quoh); } +/* This is non-zero if we should defer warnings about undefined + overflow. This facility exists because these warnings are a + special case. The code to estimate loop iterations does not want + to issue any warnings, since it works with expressions which do not + occur in user code. Various bits of cleanup code call fold(), but + only use the result if it has certain characteristics (e.g., is a + constant); that code only wants to issue a warning if the result is + used. */ + +static int fold_deferring_overflow_warnings; + +/* If a warning about undefined overflow is deferred, this is the + warning. Note that this may cause us to turn two warnings into + one, but that is fine since it is sufficient to only give one + warning per expression. */ + +static const char* fold_deferred_overflow_warning; + +/* If a warning about undefined overflow is deferred, this is the + level at which the warning should be emitted. */ + +static enum warn_strict_overflow_code fold_deferred_overflow_code; + +/* Start deferring overflow warnings. We could use a stack here to + permit nested calls, but at present it is not necessary. */ + +void +fold_defer_overflow_warnings (void) +{ + ++fold_deferring_overflow_warnings; +} + +/* Stop deferring overflow warnings. If there is a pending warning, + and ISSUE is true, then issue the warning if appropriate. STMT is + the statement with which the warning should be associated (used for + location information); STMT may be NULL. CODE is the level of the + warning--a warn_strict_overflow_code value. This function will use + the smaller of CODE and the deferred code when deciding whether to + issue the warning. CODE may be zero to mean to always use the + deferred code. */ + +void +fold_undefer_overflow_warnings (bool issue, tree stmt, int code) +{ + const char *warnmsg; + location_t locus; + + gcc_assert (fold_deferring_overflow_warnings > 0); + --fold_deferring_overflow_warnings; + if (fold_deferring_overflow_warnings > 0) + { + if (fold_deferred_overflow_warning != NULL + && code != 0 + && code < (int) fold_deferred_overflow_code) + fold_deferred_overflow_code = code; + return; + } + + warnmsg = fold_deferred_overflow_warning; + fold_deferred_overflow_warning = NULL; + + if (!issue || warnmsg == NULL) + return; + + /* Use the smallest code level when deciding to issue the + warning. */ + if (code == 0 || code > (int) fold_deferred_overflow_code) + code = fold_deferred_overflow_code; + + if (!issue_strict_overflow_warning (code)) + return; + + if (stmt == NULL_TREE || !expr_has_location (stmt)) + locus = input_location; + else + locus = expr_location (stmt); + warning (OPT_Wstrict_overflow, "%H%s", &locus, warnmsg); +} + +/* Stop deferring overflow warnings, ignoring any deferred + warnings. */ + +void +fold_undefer_and_ignore_overflow_warnings (void) +{ + fold_undefer_overflow_warnings (false, NULL_TREE, 0); +} + +/* Whether we are deferring overflow warnings. */ + +bool +fold_deferring_overflow_warnings_p (void) +{ + return fold_deferring_overflow_warnings > 0; +} + +/* This is called when we fold something based on the fact that signed + overflow is undefined. */ + +static void +fold_overflow_warning (const char* gmsgid, enum warn_strict_overflow_code wc) +{ + gcc_assert (!flag_wrapv && !flag_trapv); + if (fold_deferring_overflow_warnings > 0) + { + if (fold_deferred_overflow_warning == NULL + || wc < fold_deferred_overflow_code) + { + fold_deferred_overflow_warning = gmsgid; + fold_deferred_overflow_code = wc; + } + } + else if (issue_strict_overflow_warning (wc)) + warning (OPT_Wstrict_overflow, gmsgid); +} + /* Return true if the built-in mathematical function specified by CODE is odd, i.e. -f(x) == f(-x). */ @@ -1054,6 +1171,11 @@ negate_expr_p (tree t) case FLOOR_DIV_EXPR: case CEIL_DIV_EXPR: case EXACT_DIV_EXPR: + /* In general we can't negate A / B, because if A is INT_MIN and + B is 1, we may turn this into INT_MIN / -1 which is undefined + and actually traps on some architectures. But if overflow is + undefined, we can negate, because - (INT_MIN / 1) is an + overflow. */ if (INTEGRAL_TYPE_P (TREE_TYPE (t)) && !TYPE_OVERFLOW_UNDEFINED (TREE_TYPE (t))) break; @@ -1215,16 +1337,35 @@ fold_negate_expr (tree t) case FLOOR_DIV_EXPR: case CEIL_DIV_EXPR: case EXACT_DIV_EXPR: + /* In general we can't negate A / B, because if A is INT_MIN and + B is 1, we may turn this into INT_MIN / -1 which is undefined + and actually traps on some architectures. But if overflow is + undefined, we can negate, because - (INT_MIN / 1) is an + overflow. */ if (!INTEGRAL_TYPE_P (type) || TYPE_OVERFLOW_UNDEFINED (type)) { + const char * const warnmsg = G_("assuming signed overflow does not " + "occur when negating a division"); tem = TREE_OPERAND (t, 1); if (negate_expr_p (tem)) - return fold_build2 (TREE_CODE (t), type, - TREE_OPERAND (t, 0), negate_expr (tem)); + { + if (INTEGRAL_TYPE_P (type) + && (TREE_CODE (tem) != INTEGER_CST + || integer_onep (tem))) + fold_overflow_warning (warnmsg, WARN_STRICT_OVERFLOW_MISC); + return fold_build2 (TREE_CODE (t), type, + TREE_OPERAND (t, 0), negate_expr (tem)); + } tem = TREE_OPERAND (t, 0); if (negate_expr_p (tem)) - return fold_build2 (TREE_CODE (t), type, - negate_expr (tem), TREE_OPERAND (t, 1)); + { + if (INTEGRAL_TYPE_P (type) + && (TREE_CODE (tem) != INTEGER_CST + || tree_int_cst_equal (tem, TYPE_MIN_VALUE (type)))) + fold_overflow_warning (warnmsg, WARN_STRICT_OVERFLOW_MISC); + return fold_build2 (TREE_CODE (t), type, + negate_expr (tem), TREE_OPERAND (t, 1)); + } } break; @@ -3861,12 +4002,16 @@ range_binop (enum tree_code code, tree type, tree arg0, int upper0_p, /* Given EXP, a logical expression, set the range it is testing into variables denoted by PIN_P, PLOW, and PHIGH. Return the expression - actually being tested. *PLOW and *PHIGH will be made of the same type - as the returned expression. If EXP is not a comparison, we will most - likely not be returning a useful value and range. */ + actually being tested. *PLOW and *PHIGH will be made of the same + type as the returned expression. If EXP is not a comparison, we + will most likely not be returning a useful value and range. Set + *STRICT_OVERFLOW_P to true if the return value is only valid + because signed overflow is undefined; otherwise, do not change + *STRICT_OVERFLOW_P. */ static tree -make_range (tree exp, int *pin_p, tree *plow, tree *phigh) +make_range (tree exp, int *pin_p, tree *plow, tree *phigh, + bool *strict_overflow_p) { enum tree_code code; tree arg0 = NULL_TREE, arg1 = NULL_TREE; @@ -4015,6 +4160,9 @@ make_range (tree exp, int *pin_p, tree *plow, tree *phigh) || (n_high != 0 && TREE_OVERFLOW (n_high))) break; + if (TYPE_OVERFLOW_UNDEFINED (arg0_type)) + *strict_overflow_p = true; + /* Check for an unsigned range which has wrapped around the maximum value thus making n_high < n_low, and normalize it. */ if (n_low && n_high && tree_int_cst_lt (n_high, n_low)) @@ -4796,9 +4944,12 @@ fold_range_test (enum tree_code code, tree type, tree op0, tree op1) || code == TRUTH_OR_EXPR); int in0_p, in1_p, in_p; tree low0, low1, low, high0, high1, high; - tree lhs = make_range (op0, &in0_p, &low0, &high0); - tree rhs = make_range (op1, &in1_p, &low1, &high1); + bool strict_overflow_p = false; + tree lhs = make_range (op0, &in0_p, &low0, &high0, &strict_overflow_p); + tree rhs = make_range (op1, &in1_p, &low1, &high1, &strict_overflow_p); tree tem; + const char * const warnmsg = G_("assuming signed overflow does not occur " + "when simplifying range test"); /* If this is an OR operation, invert both sides; we will invert again at the end. */ @@ -4816,7 +4967,11 @@ fold_range_test (enum tree_code code, tree type, tree op0, tree op1) lhs != 0 ? lhs : rhs != 0 ? rhs : integer_zero_node, in_p, low, high)))) - return or_op ? invert_truthvalue (tem) : tem; + { + if (strict_overflow_p) + fold_overflow_warning (warnmsg, WARN_STRICT_OVERFLOW_COMPARISON); + return or_op ? invert_truthvalue (tem) : tem; + } /* On machines where the branch cost is expensive, if this is a short-circuited branch and the underlying object on both sides @@ -4846,9 +5001,14 @@ fold_range_test (enum tree_code code, tree type, tree op0, tree op1) && (0 != (rhs = build_range_check (type, common, or_op ? ! in1_p : in1_p, low1, high1)))) - return build2 (code == TRUTH_ANDIF_EXPR - ? TRUTH_AND_EXPR : TRUTH_OR_EXPR, - type, lhs, rhs); + { + if (strict_overflow_p) + fold_overflow_warning (warnmsg, + WARN_STRICT_OVERFLOW_COMPARISON); + return build2 (code == TRUTH_ANDIF_EXPR + ? TRUTH_AND_EXPR : TRUTH_OR_EXPR, + type, lhs, rhs); + } } } @@ -5447,10 +5607,15 @@ optimize_minmax_comparison (enum tree_code code, tree type, tree op0, tree op1) addressing calculation. If we return a non-null expression, it is an equivalent form of the - original computation, but need not be in the original type. */ + original computation, but need not be in the original type. + + We set *STRICT_OVERFLOW_P to true if the return values depends on + signed overflow being undefined. Otherwise we do not change + *STRICT_OVERFLOW_P. */ static tree -extract_muldiv (tree t, tree c, enum tree_code code, tree wide_type) +extract_muldiv (tree t, tree c, enum tree_code code, tree wide_type, + bool *strict_overflow_p) { /* To avoid exponential search depth, refuse to allow recursion past three levels. Beyond that (1) it's highly unlikely that we'll find @@ -5464,14 +5629,15 @@ extract_muldiv (tree t, tree c, enum tree_code code, tree wide_type) return NULL; depth++; - ret = extract_muldiv_1 (t, c, code, wide_type); + ret = extract_muldiv_1 (t, c, code, wide_type, strict_overflow_p); depth--; return ret; } static tree -extract_muldiv_1 (tree t, tree c, enum tree_code code, tree wide_type) +extract_muldiv_1 (tree t, tree c, enum tree_code code, tree wide_type, + bool *strict_overflow_p) { tree type = TREE_TYPE (t); enum tree_code tcode = TREE_CODE (t); @@ -5481,6 +5647,7 @@ extract_muldiv_1 (tree t, tree c, enum tree_code code, tree wide_type) tree t1, t2; int same_p = tcode == code; tree op0 = NULL_TREE, op1 = NULL_TREE; + bool sub_strict_overflow_p; /* Don't deal with constants of zero here; they confuse the code below. */ if (integer_zerop (c)) @@ -5537,7 +5704,8 @@ extract_muldiv_1 (tree t, tree c, enum tree_code code, tree wide_type) && !TREE_OVERFLOW (t2) && (0 != (t1 = extract_muldiv (op0, t2, code, code == MULT_EXPR - ? ctype : NULL_TREE)))) + ? ctype : NULL_TREE, + strict_overflow_p)))) return t1; break; @@ -5547,7 +5715,8 @@ extract_muldiv_1 (tree t, tree c, enum tree_code code, tree wide_type) if (TYPE_UNSIGNED (ctype) && !TYPE_UNSIGNED (type)) { tree cstype = (*lang_hooks.types.signed_type) (ctype); - if ((t1 = extract_muldiv (op0, c, code, cstype)) != 0) + if ((t1 = extract_muldiv (op0, c, code, cstype, strict_overflow_p)) + != 0) { t1 = fold_build1 (tcode, cstype, fold_convert (cstype, t1)); return fold_convert (ctype, t1); @@ -5556,7 +5725,8 @@ extract_muldiv_1 (tree t, tree c, enum tree_code code, tree wide_type) } /* FALLTHROUGH */ case NEGATE_EXPR: - if ((t1 = extract_muldiv (op0, c, code, wide_type)) != 0) + if ((t1 = extract_muldiv (op0, c, code, wide_type, strict_overflow_p)) + != 0) return fold_build1 (tcode, ctype, fold_convert (ctype, t1)); break; @@ -5567,12 +5737,16 @@ extract_muldiv_1 (tree t, tree c, enum tree_code code, tree wide_type) break; /* MIN (a, b) / 5 -> MIN (a / 5, b / 5) */ - if ((t1 = extract_muldiv (op0, c, code, wide_type)) != 0 - && (t2 = extract_muldiv (op1, c, code, wide_type)) != 0) + sub_strict_overflow_p = false; + if ((t1 = extract_muldiv (op0, c, code, wide_type, + &sub_strict_overflow_p)) != 0 + && (t2 = extract_muldiv (op1, c, code, wide_type, + &sub_strict_overflow_p)) != 0) { if (tree_int_cst_sgn (c) < 0) tcode = (tcode == MIN_EXPR ? MAX_EXPR : MIN_EXPR); - + if (sub_strict_overflow_p) + *strict_overflow_p = true; return fold_build2 (tcode, ctype, fold_convert (ctype, t1), fold_convert (ctype, t2)); } @@ -5599,7 +5773,7 @@ extract_muldiv_1 (tree t, tree c, enum tree_code code, tree wide_type) return extract_muldiv (build2 (tcode == LSHIFT_EXPR ? MULT_EXPR : FLOOR_DIV_EXPR, ctype, fold_convert (ctype, op0), t1), - c, code, wide_type); + c, code, wide_type, strict_overflow_p); break; case PLUS_EXPR: case MINUS_EXPR: @@ -5607,16 +5781,21 @@ extract_muldiv_1 (tree t, tree c, enum tree_code code, tree wide_type) can return a new PLUS or MINUS. If we can't, the only remaining cases where we can do anything are if the second operand is a constant. */ - t1 = extract_muldiv (op0, c, code, wide_type); - t2 = extract_muldiv (op1, c, code, wide_type); + sub_strict_overflow_p = false; + t1 = extract_muldiv (op0, c, code, wide_type, &sub_strict_overflow_p); + t2 = extract_muldiv (op1, c, code, wide_type, &sub_strict_overflow_p); if (t1 != 0 && t2 != 0 && (code == MULT_EXPR /* If not multiplication, we can only do this if both operands are divisible by c. */ || (multiple_of_p (ctype, op0, c) && multiple_of_p (ctype, op1, c)))) - return fold_build2 (tcode, ctype, fold_convert (ctype, t1), - fold_convert (ctype, t2)); + { + if (sub_strict_overflow_p) + *strict_overflow_p = true; + return fold_build2 (tcode, ctype, fold_convert (ctype, t1), + fold_convert (ctype, t2)); + } /* If this was a subtraction, negate OP1 and set it to be an addition. This simplifies the logic below. */ @@ -5697,11 +5876,13 @@ extract_muldiv_1 (tree t, tree c, enum tree_code code, tree wide_type) new operation. Likewise for the RHS from a MULT_EXPR. Otherwise, do something only if the second operand is a constant. */ if (same_p - && (t1 = extract_muldiv (op0, c, code, wide_type)) != 0) + && (t1 = extract_muldiv (op0, c, code, wide_type, + strict_overflow_p)) != 0) return fold_build2 (tcode, ctype, fold_convert (ctype, t1), fold_convert (ctype, op1)); else if (tcode == MULT_EXPR && code == MULT_EXPR - && (t1 = extract_muldiv (op1, c, code, wide_type)) != 0) + && (t1 = extract_muldiv (op1, c, code, wide_type, + strict_overflow_p)) != 0) return fold_build2 (tcode, ctype, fold_convert (ctype, op0), fold_convert (ctype, t1)); else if (TREE_CODE (op1) != INTEGER_CST) @@ -5731,15 +5912,23 @@ extract_muldiv_1 (tree t, tree c, enum tree_code code, tree wide_type) && code != FLOOR_MOD_EXPR && code != ROUND_MOD_EXPR))) { if (integer_zerop (const_binop (TRUNC_MOD_EXPR, op1, c, 0))) - return fold_build2 (tcode, ctype, fold_convert (ctype, op0), - fold_convert (ctype, - const_binop (TRUNC_DIV_EXPR, - op1, c, 0))); + { + if (TYPE_OVERFLOW_UNDEFINED (ctype)) + *strict_overflow_p = true; + return fold_build2 (tcode, ctype, fold_convert (ctype, op0), + fold_convert (ctype, + const_binop (TRUNC_DIV_EXPR, + op1, c, 0))); + } else if (integer_zerop (const_binop (TRUNC_MOD_EXPR, c, op1, 0))) - return fold_build2 (code, ctype, fold_convert (ctype, op0), - fold_convert (ctype, - const_binop (TRUNC_DIV_EXPR, - c, op1, 0))); + { + if (TYPE_OVERFLOW_UNDEFINED (ctype)) + *strict_overflow_p = true; + return fold_build2 (code, ctype, fold_convert (ctype, op0), + fold_convert (ctype, + const_binop (TRUNC_DIV_EXPR, + c, op1, 0))); + } } break; @@ -7667,7 +7856,9 @@ fold_unary (enum tree_code code, tree type, tree op0) targ0)); } /* ABS_EXPR<ABS_EXPR<x>> = ABS_EXPR<x> even if flag_wrapv is on. */ - else if (tree_expr_nonnegative_p (arg0) || TREE_CODE (arg0) == ABS_EXPR) + else if (TREE_CODE (arg0) == ABS_EXPR) + return arg0; + else if (tree_expr_nonnegative_p (arg0)) return arg0; /* Strip sign ops from argument. */ @@ -7884,11 +8075,14 @@ fold_minmax (enum tree_code code, tree type, tree op0, tree op1) by changing CODE to reduce the magnitude of constants involved in ARG0 of the comparison. Returns a canonicalized comparison tree if a simplification was - possible, otherwise returns NULL_TREE. */ + possible, otherwise returns NULL_TREE. + Set *STRICT_OVERFLOW_P to true if the canonicalization is only + valid if signed overflow is undefined. */ static tree maybe_canonicalize_comparison_1 (enum tree_code code, tree type, - tree arg0, tree arg1) + tree arg0, tree arg1, + bool *strict_overflow_p) { enum tree_code code0 = TREE_CODE (arg0); tree t, cst0 = NULL_TREE; @@ -7955,6 +8149,7 @@ maybe_canonicalize_comparison_1 (enum tree_code code, tree type, code = GT_EXPR; else return NULL_TREE; + *strict_overflow_p = true; } /* Now build the constant reduced in magnitude. */ @@ -7981,6 +8176,9 @@ maybe_canonicalize_comparison (enum tree_code code, tree type, tree arg0, tree arg1) { tree t; + bool strict_overflow_p; + const char * const warnmsg = G_("assuming signed overflow does not occur " + "when reducing constant in comparison"); /* In principle pointers also have undefined overflow behavior, but that causes problems elsewhere. */ @@ -7989,14 +8187,25 @@ maybe_canonicalize_comparison (enum tree_code code, tree type, return NULL_TREE; /* Try canonicalization by simplifying arg0. */ - t = maybe_canonicalize_comparison_1 (code, type, arg0, arg1); + strict_overflow_p = false; + t = maybe_canonicalize_comparison_1 (code, type, arg0, arg1, + &strict_overflow_p); if (t) - return t; + { + if (strict_overflow_p) + fold_overflow_warning (warnmsg, WARN_STRICT_OVERFLOW_MAGNITUDE); + return t; + } /* Try canonicalization by simplifying arg1 using the swapped comparison. */ code = swap_tree_comparison (code); - return maybe_canonicalize_comparison_1 (code, type, arg1, arg0); + strict_overflow_p = false; + t = maybe_canonicalize_comparison_1 (code, type, arg1, arg0, + &strict_overflow_p); + if (t && strict_overflow_p) + fold_overflow_warning (warnmsg, WARN_STRICT_OVERFLOW_MAGNITUDE); + return t; } /* Subroutine of fold_binary. This routine performs all of the @@ -8080,7 +8289,13 @@ fold_comparison (enum tree_code code, tree type, tree op0, tree op1) if (TREE_CODE (lhs) == TREE_CODE (arg1) && (TREE_CODE (lhs) != INTEGER_CST || !TREE_OVERFLOW (lhs))) - return fold_build2 (code, type, variable, lhs); + { + fold_overflow_warning (("assuming signed overflow does not occur " + "when changing X +- C1 cmp C2 to " + "X cmp C1 +- C2"), + WARN_STRICT_OVERFLOW_COMPARISON); + return fold_build2 (code, type, variable, lhs); + } } /* For comparisons of pointers we can decompose it to a compile time @@ -8245,6 +8460,9 @@ fold_comparison (enum tree_code code, tree type, tree op0, tree op1) tree variable1 = TREE_OPERAND (arg0, 0); tree variable2 = TREE_OPERAND (arg1, 0); tree cst; + const char * const warnmsg = G_("assuming signed overflow does not " + "occur when combining constants around " + "a comparison"); /* Put the constant on the side where it doesn't overflow and is of lower absolute value than before. */ @@ -8253,20 +8471,26 @@ fold_comparison (enum tree_code code, tree type, tree op0, tree op1) const2, const1, 0); if (!TREE_OVERFLOW (cst) && tree_int_cst_compare (const2, cst) == tree_int_cst_sgn (const2)) - return fold_build2 (code, type, - variable1, - fold_build2 (TREE_CODE (arg1), TREE_TYPE (arg1), - variable2, cst)); + { + fold_overflow_warning (warnmsg, WARN_STRICT_OVERFLOW_COMPARISON); + return fold_build2 (code, type, + variable1, + fold_build2 (TREE_CODE (arg1), TREE_TYPE (arg1), + variable2, cst)); + } cst = int_const_binop (TREE_CODE (arg0) == TREE_CODE (arg1) ? MINUS_EXPR : PLUS_EXPR, const1, const2, 0); if (!TREE_OVERFLOW (cst) && tree_int_cst_compare (const1, cst) == tree_int_cst_sgn (const1)) - return fold_build2 (code, type, - fold_build2 (TREE_CODE (arg0), TREE_TYPE (arg0), - variable1, cst), - variable2); + { + fold_overflow_warning (warnmsg, WARN_STRICT_OVERFLOW_COMPARISON); + return fold_build2 (code, type, + fold_build2 (TREE_CODE (arg0), TREE_TYPE (arg0), + variable1, cst), + variable2); + } } /* Transform comparisons of the form X * C1 CMP 0 to X CMP 0 in the @@ -8286,6 +8510,11 @@ fold_comparison (enum tree_code code, tree type, tree op0, tree op1) gcc_assert (!integer_zerop (const1)); + fold_overflow_warning (("assuming signed overflow does not occur when " + "eliminating multiplication in comparison " + "with zero"), + WARN_STRICT_OVERFLOW_COMPARISON); + /* If const1 is negative we swap the sense of the comparison. */ if (tree_int_cst_sgn (const1) < 0) cmp_code = swap_tree_comparison (cmp_code); @@ -8721,6 +8950,7 @@ fold_binary (enum tree_code code, tree type, tree op0, tree op1) enum tree_code_class kind = TREE_CODE_CLASS (code); tree arg0, arg1, tem; tree t1 = NULL_TREE; + bool strict_overflow_p; gcc_assert ((IS_EXPR_CODE_CLASS (kind) || IS_GIMPLE_STMT_CODE_CLASS (kind)) @@ -9468,11 +9698,20 @@ fold_binary (enum tree_code code, tree type, tree op0, tree op1) return fold_build2 (LSHIFT_EXPR, type, arg1, TREE_OPERAND (arg0, 1)); + strict_overflow_p = false; if (TREE_CODE (arg1) == INTEGER_CST && 0 != (tem = extract_muldiv (op0, fold_convert (type, arg1), - code, NULL_TREE))) - return fold_convert (type, tem); + code, NULL_TREE, + &strict_overflow_p))) + { + if (strict_overflow_p) + fold_overflow_warning (("assuming signed overflow does not " + "occur when simplifying " + "multiplication"), + WARN_STRICT_OVERFLOW_MISC); + return fold_convert (type, tem); + } /* Optimize z * conj(z) for integer complex numbers. */ if (TREE_CODE (arg0) == CONJ_EXPR @@ -10372,8 +10611,10 @@ fold_binary (enum tree_code code, tree type, tree op0, tree op1) case FLOOR_DIV_EXPR: /* Simplify A / (B << N) where A and B are positive and B is a power of 2, to A >> (N + log2(B)). */ + strict_overflow_p = false; if (TREE_CODE (arg1) == LSHIFT_EXPR - && (TYPE_UNSIGNED (type) || tree_expr_nonnegative_p (arg0))) + && (TYPE_UNSIGNED (type) + || tree_expr_nonnegative_warnv_p (arg0, &strict_overflow_p))) { tree sval = TREE_OPERAND (arg1, 0); if (integer_pow2p (sval) && tree_int_cst_sgn (sval) > 0) @@ -10381,6 +10622,11 @@ fold_binary (enum tree_code code, tree type, tree op0, tree op1) tree sh_cnt = TREE_OPERAND (arg1, 1); unsigned long pow2 = exact_log2 (TREE_INT_CST_LOW (sval)); + if (strict_overflow_p) + fold_overflow_warning (("assuming signed overflow does not " + "occur when simplifying A / (B << N)"), + WARN_STRICT_OVERFLOW_MISC); + sh_cnt = fold_build2 (PLUS_EXPR, TREE_TYPE (sh_cnt), sh_cnt, build_int_cst (NULL_TREE, pow2)); return fold_build2 (RSHIFT_EXPR, type, @@ -10408,13 +10654,27 @@ fold_binary (enum tree_code code, tree type, tree op0, tree op1) if ((!INTEGRAL_TYPE_P (type) || TYPE_OVERFLOW_UNDEFINED (type)) && TREE_CODE (arg0) == NEGATE_EXPR && negate_expr_p (arg1)) - return fold_build2 (code, type, TREE_OPERAND (arg0, 0), - negate_expr (arg1)); + { + if (INTEGRAL_TYPE_P (type)) + fold_overflow_warning (("assuming signed overflow does not occur " + "when distributing negation across " + "division"), + WARN_STRICT_OVERFLOW_MISC); + return fold_build2 (code, type, TREE_OPERAND (arg0, 0), + negate_expr (arg1)); + } if ((!INTEGRAL_TYPE_P (type) || TYPE_OVERFLOW_UNDEFINED (type)) && TREE_CODE (arg1) == NEGATE_EXPR && negate_expr_p (arg0)) - return fold_build2 (code, type, negate_expr (arg0), - TREE_OPERAND (arg1, 0)); + { + if (INTEGRAL_TYPE_P (type)) + fold_overflow_warning (("assuming signed overflow does not occur " + "when distributing negation across " + "division"), + WARN_STRICT_OVERFLOW_MISC); + return fold_build2 (code, type, negate_expr (arg0), + TREE_OPERAND (arg1, 0)); + } /* If arg0 is a multiple of arg1, then rewrite to the fastest div operation, EXACT_DIV_EXPR. @@ -10426,9 +10686,17 @@ fold_binary (enum tree_code code, tree type, tree op0, tree op1) && multiple_of_p (type, arg0, arg1)) return fold_build2 (EXACT_DIV_EXPR, type, arg0, arg1); + strict_overflow_p = false; if (TREE_CODE (arg1) == INTEGER_CST - && 0 != (tem = extract_muldiv (op0, arg1, code, NULL_TREE))) - return fold_convert (type, tem); + && 0 != (tem = extract_muldiv (op0, arg1, code, NULL_TREE, + &strict_overflow_p))) + { + if (strict_overflow_p) + fold_overflow_warning (("assuming signed overflow does not occur " + "when simplifying division"), + WARN_STRICT_OVERFLOW_MISC); + return fold_convert (type, tem); + } return NULL_TREE; @@ -10460,8 +10728,10 @@ fold_binary (enum tree_code code, tree type, tree op0, tree op1) /* Optimize TRUNC_MOD_EXPR by a power of two into a BIT_AND_EXPR, i.e. "X % C" into "X & (C - 1)", if X and C are positive. */ + strict_overflow_p = false; if ((code == TRUNC_MOD_EXPR || code == FLOOR_MOD_EXPR) - && (TYPE_UNSIGNED (type) || tree_expr_nonnegative_p (arg0))) + && (TYPE_UNSIGNED (type) + || tree_expr_nonnegative_warnv_p (arg0, &strict_overflow_p))) { tree c = arg1; /* Also optimize A % (C << N) where C is a power of 2, @@ -10473,6 +10743,11 @@ fold_binary (enum tree_code code, tree type, tree op0, tree op1) { tree mask = fold_build2 (MINUS_EXPR, TREE_TYPE (arg1), arg1, build_int_cst (TREE_TYPE (arg1), 1)); + if (strict_overflow_p) + fold_overflow_warning (("assuming signed overflow does not " + "occur when simplifying " + "X % (power of two)"), + WARN_STRICT_OVERFLOW_MISC); return fold_build2 (BIT_AND_EXPR, type, fold_convert (type, arg0), fold_convert (type, mask)); @@ -10500,8 +10775,15 @@ fold_binary (enum tree_code code, tree type, tree op0, tree op1) fold_convert (type, TREE_OPERAND (arg1, 0))); if (TREE_CODE (arg1) == INTEGER_CST - && 0 != (tem = extract_muldiv (op0, arg1, code, NULL_TREE))) - return fold_convert (type, tem); + && 0 != (tem = extract_muldiv (op0, arg1, code, NULL_TREE, + &strict_overflow_p))) + { + if (strict_overflow_p) + fold_overflow_warning (("assuming signed overflow does not occur " + "when simplifying modulos"), + WARN_STRICT_OVERFLOW_MISC); + return fold_convert (type, tem); + } return NULL_TREE; @@ -11330,27 +11612,59 @@ fold_binary (enum tree_code code, tree type, tree op0, tree op1) if (code == GT_EXPR && ((code0 == MINUS_EXPR && is_positive >= 0) || (code0 == PLUS_EXPR && is_positive <= 0))) - return constant_boolean_node (0, type); + { + if (TREE_CODE (arg01) == INTEGER_CST + && TYPE_OVERFLOW_UNDEFINED (TREE_TYPE (arg1))) + fold_overflow_warning (("assuming signed overflow does not " + "occur when assuming that (X - c) > X " + "is always false"), + WARN_STRICT_OVERFLOW_ALL); + return constant_boolean_node (0, type); + } /* Likewise (X + c) < X becomes false. */ if (code == LT_EXPR && ((code0 == PLUS_EXPR && is_positive >= 0) || (code0 == MINUS_EXPR && is_positive <= 0))) - return constant_boolean_node (0, type); + { + if (TREE_CODE (arg01) == INTEGER_CST + && TYPE_OVERFLOW_UNDEFINED (TREE_TYPE (arg1))) + fold_overflow_warning (("assuming signed overflow does not " + "occur when assuming that " + "(X + c) < X is always false"), + WARN_STRICT_OVERFLOW_ALL); + return constant_boolean_node (0, type); + } /* Convert (X - c) <= X to true. */ if (!HONOR_NANS (TYPE_MODE (TREE_TYPE (arg1))) && code == LE_EXPR && ((code0 == MINUS_EXPR && is_positive >= 0) || (code0 == PLUS_EXPR && is_positive <= 0))) - return constant_boolean_node (1, type); + { + if (TREE_CODE (arg01) == INTEGER_CST + && TYPE_OVERFLOW_UNDEFINED (TREE_TYPE (arg1))) + fold_overflow_warning (("assuming signed overflow does not " + "occur when assuming that " + "(X - c) <= X is always true"), + WARN_STRICT_OVERFLOW_ALL); + return constant_boolean_node (1, type); + } /* Convert (X + c) >= X to true. */ if (!HONOR_NANS (TYPE_MODE (TREE_TYPE (arg1))) && code == GE_EXPR && ((code0 == PLUS_EXPR && is_positive >= 0) || (code0 == MINUS_EXPR && is_positive <= 0))) - return constant_boolean_node (1, type); + { + if (TREE_CODE (arg01) == INTEGER_CST + && TYPE_OVERFLOW_UNDEFINED (TREE_TYPE (arg1))) + fold_overflow_warning (("assuming signed overflow does not " + "occur when assuming that " + "(X + c) >= X is always true"), + WARN_STRICT_OVERFLOW_ALL); + return constant_boolean_node (1, type); + } if (TREE_CODE (arg01) == INTEGER_CST) { @@ -11358,23 +11672,51 @@ fold_binary (enum tree_code code, tree type, tree op0, tree op1) if (code == GT_EXPR && ((code0 == PLUS_EXPR && is_positive > 0) || (code0 == MINUS_EXPR && is_positive < 0))) - return constant_boolean_node (1, type); + { + if (TYPE_OVERFLOW_UNDEFINED (TREE_TYPE (arg1))) + fold_overflow_warning (("assuming signed overflow does " + "not occur when assuming that " + "(X + c) > X is always true"), + WARN_STRICT_OVERFLOW_ALL); + return constant_boolean_node (1, type); + } if (code == LT_EXPR && ((code0 == MINUS_EXPR && is_positive > 0) || (code0 == PLUS_EXPR && is_positive < 0))) - return constant_boolean_node (1, type); + { + if (TYPE_OVERFLOW_UNDEFINED (TREE_TYPE (arg1))) + fold_overflow_warning (("assuming signed overflow does " + "not occur when assuming that " + "(X - c) < X is always true"), + WARN_STRICT_OVERFLOW_ALL); + return constant_boolean_node (1, type); + } /* Convert X + c <= X and X - c >= X to false for integers. */ if (code == LE_EXPR && ((code0 == PLUS_EXPR && is_positive > 0) || (code0 == MINUS_EXPR && is_positive < 0))) - return constant_boolean_node (0, type); + { + if (TYPE_OVERFLOW_UNDEFINED (TREE_TYPE (arg1))) + fold_overflow_warning (("assuming signed overflow does " + "not occur when assuming that " + "(X + c) <= X is always false"), + WARN_STRICT_OVERFLOW_ALL); + return constant_boolean_node (0, type); + } if (code == GE_EXPR && ((code0 == MINUS_EXPR && is_positive > 0) || (code0 == PLUS_EXPR && is_positive < 0))) - return constant_boolean_node (0, type); + { + if (TYPE_OVERFLOW_UNDEFINED (TREE_TYPE (arg1))) + fold_overflow_warning (("assuming signed overflow does " + "not occur when assuming that " + "(X - c) >= X is always true"), + WARN_STRICT_OVERFLOW_ALL); + return constant_boolean_node (0, type); + } } } @@ -11575,18 +11917,34 @@ fold_binary (enum tree_code code, tree type, tree op0, tree op1) TREE_OPERAND (arg0, 0), arg1)); /* Convert ABS_EXPR<x> >= 0 to true. */ + strict_overflow_p = false; if (code == GE_EXPR - && tree_expr_nonnegative_p (arg0) && (integer_zerop (arg1) || (! HONOR_NANS (TYPE_MODE (TREE_TYPE (arg0))) - && real_zerop (arg1)))) - return omit_one_operand (type, integer_one_node, arg0); + && real_zerop (arg1))) + && tree_expr_nonnegative_warnv_p (arg0, &strict_overflow_p)) + { + if (strict_overflow_p) + fold_overflow_warning (("assuming signed overflow does not occur " + "when simplifying comparison of " + "absolute value and zero"), + WARN_STRICT_OVERFLOW_CONDITIONAL); + return omit_one_operand (type, integer_one_node, arg0); + } /* Convert ABS_EXPR<x> < 0 to false. */ + strict_overflow_p = false; if (code == LT_EXPR - && tree_expr_nonnegative_p (arg0) - && (integer_zerop (arg1) || real_zerop (arg1))) - return omit_one_operand (type, integer_zero_node, arg0); + && (integer_zerop (arg1) || real_zerop (arg1)) + && tree_expr_nonnegative_warnv_p (arg0, &strict_overflow_p)) + { + if (strict_overflow_p) + fold_overflow_warning (("assuming signed overflow does not occur " + "when simplifying comparison of " + "absolute value and zero"), + WARN_STRICT_OVERFLOW_CONDITIONAL); + return omit_one_operand (type, integer_zero_node, arg0); + } /* If X is unsigned, convert X < (1 << Y) into X >> Y == 0 and similarly for >= into !=. */ @@ -12662,10 +13020,13 @@ multiple_of_p (tree type, tree top, tree bottom) } } -/* Return true if `t' is known to be non-negative. */ +/* Return true if `t' is known to be non-negative. If the return + value is based on the assumption that signed overflow is undefined, + set *STRICT_OVERFLOW_P to true; otherwise, don't change + *STRICT_OVERFLOW_P. */ bool -tree_expr_nonnegative_p (tree t) +tree_expr_nonnegative_warnv_p (tree t, bool *strict_overflow_p) { if (t == error_mark_node) return false; @@ -12686,7 +13047,10 @@ tree_expr_nonnegative_p (tree t) if (!INTEGRAL_TYPE_P (TREE_TYPE (t))) return true; if (TYPE_OVERFLOW_UNDEFINED (TREE_TYPE (t))) - return true; + { + *strict_overflow_p = true; + return true; + } break; case INTEGER_CST: @@ -12697,8 +13061,10 @@ tree_expr_nonnegative_p (tree t) case PLUS_EXPR: if (FLOAT_TYPE_P (TREE_TYPE (t))) - return tree_expr_nonnegative_p (TREE_OPERAND (t, 0)) - && tree_expr_nonnegative_p (TREE_OPERAND (t, 1)); + return (tree_expr_nonnegative_warnv_p (TREE_OPERAND (t, 0), + strict_overflow_p) + && tree_expr_nonnegative_warnv_p (TREE_OPERAND (t, 1), + strict_overflow_p)); /* zero_extend(x) + zero_extend(y) is non-negative if x and y are both unsigned and at least 2 bits shorter than the result. */ @@ -12724,8 +13090,10 @@ tree_expr_nonnegative_p (tree t) /* x * x for floating point x is always non-negative. */ if (operand_equal_p (TREE_OPERAND (t, 0), TREE_OPERAND (t, 1), 0)) return true; - return tree_expr_nonnegative_p (TREE_OPERAND (t, 0)) - && tree_expr_nonnegative_p (TREE_OPERAND (t, 1)); + return (tree_expr_nonnegative_warnv_p (TREE_OPERAND (t, 0), + strict_overflow_p) + && tree_expr_nonnegative_warnv_p (TREE_OPERAND (t, 1), + strict_overflow_p)); } /* zero_extend(x) * zero_extend(y) is non-negative if x and y are @@ -12745,8 +13113,10 @@ tree_expr_nonnegative_p (tree t) case BIT_AND_EXPR: case MAX_EXPR: - return tree_expr_nonnegative_p (TREE_OPERAND (t, 0)) - || tree_expr_nonnegative_p (TREE_OPERAND (t, 1)); + return (tree_expr_nonnegative_warnv_p (TREE_OPERAND (t, 0), + strict_overflow_p) + || tree_expr_nonnegative_warnv_p (TREE_OPERAND (t, 1), + strict_overflow_p)); case BIT_IOR_EXPR: case BIT_XOR_EXPR: @@ -12756,8 +13126,10 @@ tree_expr_nonnegative_p (tree t) case CEIL_DIV_EXPR: case FLOOR_DIV_EXPR: case ROUND_DIV_EXPR: - return tree_expr_nonnegative_p (TREE_OPERAND (t, 0)) - && tree_expr_nonnegative_p (TREE_OPERAND (t, 1)); + return (tree_expr_nonnegative_warnv_p (TREE_OPERAND (t, 0), + strict_overflow_p) + && tree_expr_nonnegative_warnv_p (TREE_OPERAND (t, 1), + strict_overflow_p)); case TRUNC_MOD_EXPR: case CEIL_MOD_EXPR: @@ -12766,19 +13138,24 @@ tree_expr_nonnegative_p (tree t) case SAVE_EXPR: case NON_LVALUE_EXPR: case FLOAT_EXPR: - return tree_expr_nonnegative_p (TREE_OPERAND (t, 0)); + return tree_expr_nonnegative_warnv_p (TREE_OPERAND (t, 0), + strict_overflow_p); case COMPOUND_EXPR: case MODIFY_EXPR: case GIMPLE_MODIFY_STMT: - return tree_expr_nonnegative_p (GENERIC_TREE_OPERAND (t, 1)); + return tree_expr_nonnegative_warnv_p (GENERIC_TREE_OPERAND (t, 1), + strict_overflow_p); case BIND_EXPR: - return tree_expr_nonnegative_p (expr_last (TREE_OPERAND (t, 1))); + return tree_expr_nonnegative_warnv_p (expr_last (TREE_OPERAND (t, 1)), + strict_overflow_p); case COND_EXPR: - return tree_expr_nonnegative_p (TREE_OPERAND (t, 1)) - && tree_expr_nonnegative_p (TREE_OPERAND (t, 2)); + return (tree_expr_nonnegative_warnv_p (TREE_OPERAND (t, 1), + strict_overflow_p) + && tree_expr_nonnegative_warnv_p (TREE_OPERAND (t, 2), + strict_overflow_p)); case NOP_EXPR: { @@ -12788,18 +13165,21 @@ tree_expr_nonnegative_p (tree t) if (TREE_CODE (outer_type) == REAL_TYPE) { if (TREE_CODE (inner_type) == REAL_TYPE) - return tree_expr_nonnegative_p (TREE_OPERAND (t, 0)); + return tree_expr_nonnegative_warnv_p (TREE_OPERAND (t, 0), + strict_overflow_p); if (TREE_CODE (inner_type) == INTEGER_TYPE) { if (TYPE_UNSIGNED (inner_type)) return true; - return tree_expr_nonnegative_p (TREE_OPERAND (t, 0)); + return tree_expr_nonnegative_warnv_p (TREE_OPERAND (t, 0), + strict_overflow_p); } } else if (TREE_CODE (outer_type) == INTEGER_TYPE) { if (TREE_CODE (inner_type) == REAL_TYPE) - return tree_expr_nonnegative_p (TREE_OPERAND (t,0)); + return tree_expr_nonnegative_warnv_p (TREE_OPERAND (t,0), + strict_overflow_p); if (TREE_CODE (inner_type) == INTEGER_TYPE) return TYPE_PRECISION (inner_type) < TYPE_PRECISION (outer_type) && TYPE_UNSIGNED (inner_type); @@ -12815,7 +13195,7 @@ tree_expr_nonnegative_p (tree t) /* If the initializer is non-void, then it's a normal expression that will be assigned to the slot. */ if (!VOID_TYPE_P (t)) - return tree_expr_nonnegative_p (t); + return tree_expr_nonnegative_warnv_p (t, strict_overflow_p); /* Otherwise, the initializer sets the slot in some way. One common way is an assignment statement at the end of the initializer. */ @@ -12834,7 +13214,8 @@ tree_expr_nonnegative_p (tree t) if ((TREE_CODE (t) == MODIFY_EXPR || TREE_CODE (t) == GIMPLE_MODIFY_STMT) && GENERIC_TREE_OPERAND (t, 0) == temp) - return tree_expr_nonnegative_p (GENERIC_TREE_OPERAND (t, 1)); + return tree_expr_nonnegative_warnv_p (GENERIC_TREE_OPERAND (t, 1), + strict_overflow_p); return false; } @@ -12870,7 +13251,8 @@ tree_expr_nonnegative_p (tree t) /* sqrt(-0.0) is -0.0. */ if (!HONOR_SIGNED_ZEROS (TYPE_MODE (TREE_TYPE (t)))) return true; - return tree_expr_nonnegative_p (TREE_VALUE (arglist)); + return tree_expr_nonnegative_warnv_p (TREE_VALUE (arglist), + strict_overflow_p); CASE_FLT_FN (BUILT_IN_ASINH): CASE_FLT_FN (BUILT_IN_ATAN): @@ -12900,21 +13282,30 @@ tree_expr_nonnegative_p (tree t) CASE_FLT_FN (BUILT_IN_TANH): CASE_FLT_FN (BUILT_IN_TRUNC): /* True if the 1st argument is nonnegative. */ - return tree_expr_nonnegative_p (TREE_VALUE (arglist)); + return tree_expr_nonnegative_warnv_p (TREE_VALUE (arglist), + strict_overflow_p); CASE_FLT_FN (BUILT_IN_FMAX): /* True if the 1st OR 2nd arguments are nonnegative. */ - return tree_expr_nonnegative_p (TREE_VALUE (arglist)) - || tree_expr_nonnegative_p (TREE_VALUE (TREE_CHAIN (arglist))); + return (tree_expr_nonnegative_warnv_p (TREE_VALUE (arglist), + strict_overflow_p) + || (tree_expr_nonnegative_warnv_p + (TREE_VALUE (TREE_CHAIN (arglist)), + strict_overflow_p))); CASE_FLT_FN (BUILT_IN_FMIN): /* True if the 1st AND 2nd arguments are nonnegative. */ - return tree_expr_nonnegative_p (TREE_VALUE (arglist)) - && tree_expr_nonnegative_p (TREE_VALUE (TREE_CHAIN (arglist))); + return (tree_expr_nonnegative_warnv_p (TREE_VALUE (arglist), + strict_overflow_p) + && (tree_expr_nonnegative_warnv_p + (TREE_VALUE (TREE_CHAIN (arglist)), + strict_overflow_p))); CASE_FLT_FN (BUILT_IN_COPYSIGN): /* True if the 2nd argument is nonnegative. */ - return tree_expr_nonnegative_p (TREE_VALUE (TREE_CHAIN (arglist))); + return (tree_expr_nonnegative_warnv_p + (TREE_VALUE (TREE_CHAIN (arglist)), + strict_overflow_p)); CASE_FLT_FN (BUILT_IN_POWI): /* True if the 1st argument is nonnegative or the second @@ -12925,7 +13316,8 @@ tree_expr_nonnegative_p (tree t) if ((TREE_INT_CST_LOW (arg1) & 1) == 0) return true; } - return tree_expr_nonnegative_p (TREE_VALUE (arglist)); + return tree_expr_nonnegative_warnv_p (TREE_VALUE (arglist), + strict_overflow_p); CASE_FLT_FN (BUILT_IN_POW): /* True if the 1st argument is nonnegative or the second @@ -12946,7 +13338,8 @@ tree_expr_nonnegative_p (tree t) return true; } } - return tree_expr_nonnegative_p (TREE_VALUE (arglist)); + return tree_expr_nonnegative_warnv_p (TREE_VALUE (arglist), + strict_overflow_p); default: break; @@ -12965,14 +13358,37 @@ tree_expr_nonnegative_p (tree t) return false; } +/* Return true if `t' is known to be non-negative. Handle warnings + about undefined signed overflow. */ + +bool +tree_expr_nonnegative_p (tree t) +{ + bool ret, strict_overflow_p; + + strict_overflow_p = false; + ret = tree_expr_nonnegative_warnv_p (t, &strict_overflow_p); + if (strict_overflow_p) + fold_overflow_warning (("assuming signed overflow does not occur when " + "determining that expression is always " + "non-negative"), + WARN_STRICT_OVERFLOW_MISC); + return ret; +} + /* Return true when T is an address and is known to be nonzero. For floating point we further ensure that T is not denormal. - Similar logic is present in nonzero_address in rtlanal.h. */ + Similar logic is present in nonzero_address in rtlanal.h. + + If the return value is based on the assumption that signed overflow + is undefined, set *STRICT_OVERFLOW_P to true; otherwise, don't + change *STRICT_OVERFLOW_P. */ bool -tree_expr_nonzero_p (tree t) +tree_expr_nonzero_warnv_p (tree t, bool *strict_overflow_p) { tree type = TREE_TYPE (t); + bool sub_strict_overflow_p; /* Doing something useful for floating point would need more work. */ if (!INTEGRAL_TYPE_P (type) && !POINTER_TYPE_P (type)) @@ -12986,7 +13402,8 @@ tree_expr_nonzero_p (tree t) return ssa_name_nonzero_p (t); case ABS_EXPR: - return tree_expr_nonzero_p (TREE_OPERAND (t, 0)); + return tree_expr_nonzero_warnv_p (TREE_OPERAND (t, 0), + strict_overflow_p); case INTEGER_CST: return !integer_zerop (t); @@ -12996,20 +13413,34 @@ tree_expr_nonzero_p (tree t) { /* With the presence of negative values it is hard to say something. */ - if (!tree_expr_nonnegative_p (TREE_OPERAND (t, 0)) - || !tree_expr_nonnegative_p (TREE_OPERAND (t, 1))) + sub_strict_overflow_p = false; + if (!tree_expr_nonnegative_warnv_p (TREE_OPERAND (t, 0), + &sub_strict_overflow_p) + || !tree_expr_nonnegative_warnv_p (TREE_OPERAND (t, 1), + &sub_strict_overflow_p)) return false; /* One of operands must be positive and the other non-negative. */ - return (tree_expr_nonzero_p (TREE_OPERAND (t, 0)) - || tree_expr_nonzero_p (TREE_OPERAND (t, 1))); + /* We don't set *STRICT_OVERFLOW_P here: even if this value + overflows, on a twos-complement machine the sum of two + nonnegative numbers can never be zero. */ + return (tree_expr_nonzero_warnv_p (TREE_OPERAND (t, 0), + strict_overflow_p) + || tree_expr_nonzero_warnv_p (TREE_OPERAND (t, 1), + strict_overflow_p)); } break; case MULT_EXPR: if (TYPE_OVERFLOW_UNDEFINED (type)) { - return (tree_expr_nonzero_p (TREE_OPERAND (t, 0)) - && tree_expr_nonzero_p (TREE_OPERAND (t, 1))); + if (tree_expr_nonzero_warnv_p (TREE_OPERAND (t, 0), + strict_overflow_p) + && tree_expr_nonzero_warnv_p (TREE_OPERAND (t, 1), + strict_overflow_p)) + { + *strict_overflow_p = true; + return true; + } } break; @@ -13019,7 +13450,8 @@ tree_expr_nonzero_p (tree t) tree outer_type = TREE_TYPE (t); return (TYPE_PRECISION (outer_type) >= TYPE_PRECISION (inner_type) - && tree_expr_nonzero_p (TREE_OPERAND (t, 0))); + && tree_expr_nonzero_warnv_p (TREE_OPERAND (t, 0), + strict_overflow_p)); } break; @@ -13042,42 +13474,76 @@ tree_expr_nonzero_p (tree t) } case COND_EXPR: - return (tree_expr_nonzero_p (TREE_OPERAND (t, 1)) - && tree_expr_nonzero_p (TREE_OPERAND (t, 2))); + sub_strict_overflow_p = false; + if (tree_expr_nonzero_warnv_p (TREE_OPERAND (t, 1), + &sub_strict_overflow_p) + && tree_expr_nonzero_warnv_p (TREE_OPERAND (t, 2), + &sub_strict_overflow_p)) + { + if (sub_strict_overflow_p) + *strict_overflow_p = true; + return true; + } + break; case MIN_EXPR: - return (tree_expr_nonzero_p (TREE_OPERAND (t, 0)) - && tree_expr_nonzero_p (TREE_OPERAND (t, 1))); + sub_strict_overflow_p = false; + if (tree_expr_nonzero_warnv_p (TREE_OPERAND (t, 0), + &sub_strict_overflow_p) + && tree_expr_nonzero_warnv_p (TREE_OPERAND (t, 1), + &sub_strict_overflow_p)) + { + if (sub_strict_overflow_p) + *strict_overflow_p = true; + } + break; case MAX_EXPR: - if (tree_expr_nonzero_p (TREE_OPERAND (t, 0))) + sub_strict_overflow_p = false; + if (tree_expr_nonzero_warnv_p (TREE_OPERAND (t, 0), + &sub_strict_overflow_p)) { + if (sub_strict_overflow_p) + *strict_overflow_p = true; + /* When both operands are nonzero, then MAX must be too. */ - if (tree_expr_nonzero_p (TREE_OPERAND (t, 1))) + if (tree_expr_nonzero_warnv_p (TREE_OPERAND (t, 1), + strict_overflow_p)) return true; /* MAX where operand 0 is positive is positive. */ - return tree_expr_nonnegative_p (TREE_OPERAND (t, 0)); + return tree_expr_nonnegative_warnv_p (TREE_OPERAND (t, 0), + strict_overflow_p); } /* MAX where operand 1 is positive is positive. */ - else if (tree_expr_nonzero_p (TREE_OPERAND (t, 1)) - && tree_expr_nonnegative_p (TREE_OPERAND (t, 1))) - return true; + else if (tree_expr_nonzero_warnv_p (TREE_OPERAND (t, 1), + &sub_strict_overflow_p) + && tree_expr_nonnegative_warnv_p (TREE_OPERAND (t, 1), + &sub_strict_overflow_p)) + { + if (sub_strict_overflow_p) + *strict_overflow_p = true; + return true; + } break; case COMPOUND_EXPR: case MODIFY_EXPR: case GIMPLE_MODIFY_STMT: case BIND_EXPR: - return tree_expr_nonzero_p (GENERIC_TREE_OPERAND (t, 1)); + return tree_expr_nonzero_warnv_p (GENERIC_TREE_OPERAND (t, 1), + strict_overflow_p); case SAVE_EXPR: case NON_LVALUE_EXPR: - return tree_expr_nonzero_p (TREE_OPERAND (t, 0)); + return tree_expr_nonzero_warnv_p (TREE_OPERAND (t, 0), + strict_overflow_p); case BIT_IOR_EXPR: - return tree_expr_nonzero_p (TREE_OPERAND (t, 1)) - || tree_expr_nonzero_p (TREE_OPERAND (t, 0)); + return (tree_expr_nonzero_warnv_p (TREE_OPERAND (t, 1), + strict_overflow_p) + || tree_expr_nonzero_warnv_p (TREE_OPERAND (t, 0), + strict_overflow_p)); case CALL_EXPR: return alloca_call_p (t); @@ -13088,6 +13554,24 @@ tree_expr_nonzero_p (tree t) return false; } +/* Return true when T is an address and is known to be nonzero. + Handle warnings about undefined signed overflow. */ + +bool +tree_expr_nonzero_p (tree t) +{ + bool ret, strict_overflow_p; + + strict_overflow_p = false; + ret = tree_expr_nonzero_warnv_p (t, &strict_overflow_p); + if (strict_overflow_p) + fold_overflow_warning (("assuming signed overflow does not occur when " + "determining that expression is always " + "non-zero"), + WARN_STRICT_OVERFLOW_MISC); + return ret; +} + /* 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. |