Ian Lance Taylor - PATCH RFC: -Wstrict-overflow (original) (raw)
This is the mail archive of the gcc-patches@gcc.gnu.orgmailing list for the GCC project.
Index Nav: | [Date Index] [Subject Index] [Author Index] [Thread Index] | |
---|---|---|
Message Nav: | [Date Prev] [Date Next] | [Thread Prev] [Thread Next] |
Other format: | [Raw text] |
- From: Ian Lance Taylor
- To: gcc-patches at gcc dot gnu dot org
- Date: 31 Jan 2007 19:00:56 -0800
- Subject: PATCH RFC: -Wstrict-overflow
Following -fstrict-overflow, here is the first patch for -Wstrict-overflow. This adds a new warning for cases where gcc optimizes based on the fact that signed overflow is undefined. Note that this is not a warning for code that depends on undefined signed overflow: it is a warning for code which is optimized based on undefined signed overflow.
By way of example, I've attached the list of warnings generated by -Wstrict-overflow on a recent set of cc1 .i files. There is a total of 63 warnings.
This patch deliberately does not warn about cases where VRP relies on undefined signed overflow. I have reserved that for a separate follow-on patch.
I would like to hear comments about this patch. Thanks.
Bootstrapped and tested on i686-pc-linux-gnu.
Ian
../../trunk/gcc/bb-reorder.c: In function âfind_tracesâ: ../../trunk/gcc/bb-reorder.c:266: warning: assuming signed overflow is undefined when simplifying division ../../trunk/gcc/bb-reorder.c: In function âconnect_tracesâ: ../../trunk/gcc/bb-reorder.c:908: warning: assuming signed overflow is undefined when simplifying division ../../trunk/gcc/bb-reorder.c:910: warning: assuming signed overflow is undefined when simplifying division ../../trunk/gcc/calls.c: In function âstore_unaligned_arguments_into_pseudosâ: ../../trunk/gcc/calls.c:885: warning: assuming signed overflow is undefined when negating a division ../../trunk/gcc/cfgcleanup.c: In function âtry_crossjump_to_edgeâ: ../../trunk/gcc/cfgcleanup.c:1774: warning: assuming signed overflow is undefined when negating a division ../../trunk/gcc/cfgexpand.c: In function âexpand_gimple_tailcallâ: ../../trunk/gcc/cfgexpand.c:1384: warning: assuming signed overflow is undefined when negating a division ../../trunk/gcc/cfgexpand.c: In function âconstruct_exit_blockâ: ../../trunk/gcc/cfgexpand.c:1670: warning: assuming signed overflow is undefined when negating a division ../../trunk/gcc/cfghooks.c: In function âmake_forwarder_blockâ: ../../trunk/gcc/cfghooks.c:674: warning: assuming signed overflow is undefined when negating a division ../../trunk/gcc/cfghooks.c: In function âduplicate_blockâ: ../../trunk/gcc/cfghooks.c:858: warning: assuming signed overflow is undefined when negating a division ../../trunk/gcc/df-problems.c: In function âdf_create_unused_noteâ: ../../trunk/gcc/df-problems.c:3466: warning: assuming signed overflow is undefined when simplifying division ../../trunk/gcc/df-problems.c:3466: warning: assuming signed overflow is undefined when simplifying division ../../trunk/gcc/df-problems.c: In function âdf_ri_bb_computeâ: ../../trunk/gcc/df-problems.c:3634: warning: assuming signed overflow is undefined when simplifying division ../../trunk/gcc/df-problems.c:3634: warning: assuming signed overflow is undefined when simplifying division ../../trunk/gcc/emit-rtl.c: In function âset_mem_attributes_minus_bitposâ: ../../trunk/gcc/emit-rtl.c:1659: warning: assuming signed overflow is undefined when negating a division ../../trunk/gcc/expmed.c: In function âexpand_mult_highpart_optabâ: ../../trunk/gcc/expmed.c:3485: warning: assuming signed overflow is undefined when changing X +- C1 cmp C2 to X cmp C1 +- C2 ../../trunk/gcc/expmed.c:3511: warning: assuming signed overflow is undefined when changing X +- C1 cmp C2 to X cmp C1 +- C2 ../../trunk/gcc/expmed.c:3538: warning: assuming signed overflow is undefined when changing X +- C1 cmp C2 to X cmp C1 +- C2 ../../trunk/gcc/expmed.c: In function âexpand_divmodâ: ../../trunk/gcc/expmed.c:4106: warning: assuming signed overflow is undefined when changing X +- C1 cmp C2 to X cmp C1 +- C2 ../../trunk/gcc/expmed.c:4272: warning: assuming signed overflow is undefined when changing X +- C1 cmp C2 to X cmp C1 +- C2 ../../trunk/gcc/expmed.c:4307: warning: assuming signed overflow is undefined when changing X +- C1 cmp C2 to X cmp C1 +- C2 ../../trunk/gcc/expmed.c:4399: warning: assuming signed overflow is undefined when changing X +- C1 cmp C2 to X cmp C1 +- C2 ../../trunk/gcc/flow.c: In function âmark_set_1â: ../../trunk/gcc/flow.c:2924: warning: assuming signed overflow is undefined when simplifying division ../../trunk/gcc/flow.c:2924: warning: assuming signed overflow is undefined when simplifying division ../../trunk/gcc/flow.c: In function âmark_used_regâ: ../../trunk/gcc/flow.c:3811: warning: assuming signed overflow is undefined when simplifying division ../../trunk/gcc/flow.c:3811: warning: assuming signed overflow is undefined when simplifying division ../../trunk/gcc/function.c: In function âassign_stack_temp_for_typeâ: ../../trunk/gcc/function.c:708: warning: assuming signed overflow is undefined when negating a division ../../trunk/gcc/function.c: In function âpad_belowâ: ../../trunk/gcc/function.c:3498: warning: assuming signed overflow is undefined when simplifying division ../../trunk/gcc/genautomata.c: In function âreserv_sets_are_intersectedâ: ../../trunk/gcc/genautomata.c:3470: warning: assuming signed overflow is undefined when simplifying multiplication ../../trunk/gcc/genautomata.c:3475: warning: assuming signed overflow is undefined when simplifying multiplication ../../trunk/gcc/config/i386/i386.md:20245: warning: assuming signed overflow is undefined when changing X +- C1 cmp C2 to X cmp C1 +- C2 ../../trunk/gcc/config/i386/i386.md:20245: warning: assuming signed overflow is undefined when changing X +- C1 cmp C2 to X cmp C1 +- C2 ../../trunk/gcc/config/i386/i386.c: In function âexpand_set_or_movmem_via_loopâ: ../../trunk/gcc/config/i386/i386.c:12960: warning: assuming signed overflow is undefined when negating a division ../../trunk/gcc/config/i386/i386.c:12960: warning: assuming signed overflow is undefined when negating a division ../../trunk/gcc/ipa-inline.c: In function âlookup_recursive_callsâ: ../../trunk/gcc/ipa-inline.c:606: warning: assuming signed overflow is undefined when negating a division ../../trunk/gcc/ipa-inline.c:606: warning: assuming signed overflow is undefined when negating a division ../../trunk/gcc/local-alloc.c: In function âblock_allocâ: ../../trunk/gcc/local-alloc.c:1674: warning: assuming signed overflow is undefined when changing X +- C1 cmp C2 to X cmp C1 +- C2 ../../trunk/gcc/local-alloc.c:1675: warning: assuming signed overflow is undefined when combining constants around a comparison ../../trunk/gcc/profile.c: In function âcompute_branch_probabilitiesâ: ../../trunk/gcc/profile.c:549: warning: assuming signed overflow is undefined when simplifying division ../../trunk/gcc/real.c: In function âdo_compareâ: ../../trunk/gcc/real.c:949: warning: assuming signed overflow is undefined when combining constants around a comparison ../../trunk/gcc/real.c:951: warning: assuming signed overflow is undefined when combining constants around a comparison ../../trunk/gcc/real.c: In function âdo_fix_truncâ: ../../trunk/gcc/real.c:979: warning: assuming signed overflow is undefined when changing X +- C1 cmp C2 to X cmp C1 +- C2 ../../trunk/gcc/real.c:981: warning: assuming signed overflow is undefined when changing X +- C1 cmp C2 to X cmp C1 +- C2 ../../trunk/gcc/real.c: In function âreal_identicalâ: ../../trunk/gcc/real.c:1208: warning: assuming signed overflow is undefined when combining constants around a comparison ../../trunk/gcc/real.c: In function âreal_to_integerâ: ../../trunk/gcc/real.c:1293: warning: assuming signed overflow is undefined when changing X +- C1 cmp C2 to X cmp C1 +- C2 ../../trunk/gcc/real.c:1299: warning: assuming signed overflow is undefined when changing X +- C1 cmp C2 to X cmp C1 +- C2 ../../trunk/gcc/real.c: In function âreal_to_decimalâ: ../../trunk/gcc/real.c:1551: warning: assuming signed overflow is undefined when changing X +- C1 cmp C2 to X cmp C1 +- C2 ../../trunk/gcc/real.c:1589: warning: assuming signed overflow is undefined when changing X +- C1 cmp C2 to X cmp C1 +- C2 ../../trunk/gcc/real.c: In function âreal_sqrtâ: ../../trunk/gcc/real.c:4829: warning: assuming signed overflow is undefined when distributing negation across division ../../trunk/gcc/regclass.c: In function âregclassâ: ../../trunk/gcc/regclass.c:1259: warning: assuming signed overflow is undefined when simplifying division ../../trunk/gcc/regclass.c:1259: warning: assuming signed overflow is undefined when simplifying division ../../trunk/gcc/rtlanal.c: In function ânum_sign_bit_copies1â: ../../trunk/gcc/rtlanal.c:4217: warning: assuming signed overflow is undefined when changing X +- C1 cmp C2 to X cmp C1 +- C2 ../../trunk/gcc/sched-rgn.c: In function âcompute_dom_prob_psâ: ../../trunk/gcc/sched-rgn.c:1332: warning: assuming signed overflow is undefined when simplifying division ../../trunk/gcc/sched-rgn.c: In function âschedule_insnsâ: ../../trunk/gcc/sched-rgn.c:2927: warning: assuming signed overflow is undefined when simplifying division ../../trunk/gcc/stmt.c: In function âcheck_operand_nalternativesâ: ../../trunk/gcc/stmt.c:1144: warning: assuming signed overflow is undefined when changing X +- C1 cmp C2 to X cmp C1 +- C2 ../../trunk/gcc/stor-layout.c: In function âget_mode_alignmentâ: ../../trunk/gcc/stor-layout.c:263: warning: assuming signed overflow is undefined when eliminating multiplication in comparison with zero ../../trunk/gcc/stor-layout.c:263: warning: assuming signed overflow is undefined when eliminating multiplication in comparison with zero ../../trunk/gcc/stor-layout.c: In function âset_min_and_max_values_for_integral_typeâ: ../../trunk/gcc/stor-layout.c:2036: warning: assuming signed overflow is undefined when changing X +- C1 cmp C2 to X cmp C1 +- C2 ../../trunk/gcc/stor-layout.c:2039: warning: assuming signed overflow is undefined when changing X +- C1 cmp C2 to X cmp C1 +- C2 ../../trunk/gcc/stor-layout.c:2049: warning: assuming signed overflow is undefined when changing X +- C1 cmp C2 to X cmp C1 +- C2 ../../trunk/gcc/stor-layout.c:2053: warning: assuming signed overflow is undefined when changing X +- C1 cmp C2 to X cmp C1 +- C2 ../../trunk/gcc/stor-layout.c:2058: warning: assuming signed overflow is undefined when changing X +- C1 cmp C2 to X cmp C1 +- C2 ../../trunk/gcc/stor-layout.c:2061: warning: assuming signed overflow is undefined when changing X +- C1 cmp C2 to X cmp C1 +- C2 ../../trunk/gcc/varasm.c: In function âassemble_start_functionâ: ../../trunk/gcc/varasm.c:1450: warning: assuming signed overflow is undefined when changing X +- C1 cmp C2 to X cmp C1 +- C2
gcc/ChangeLog: 2007-01-31 Ian Lance Taylor iant@google.com
* common.opt: Add Wstrict-overflow.
* fold-const.c (fold_deferring_overflow_warnings): New static
variable.
(fold_deferred_overflow_warning): New static variable.
(fold_defer_overflow_warnings): New function.
(fold_undefer_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.
(fold_warnv): New function.
(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): Call
fold_warnv instead of fold.
(number_of_iterations_exit): Defer fold warnings.
(loop_niter_by_eval): Likewise.
(estimate_numbers_of_iterations): Likewise.
(scev_probably_wraps_p): Likewise.
* tree-cfgcleanup.c: Include "toplev.h" rather than "errors.h".
(cleanup_control_expr_graph): Call fold_warnv instead of fold, and
handle overflow warning.
* tree-cfg.c (fold_cond_expr_cond): 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.
* tree.h (tree_expr_nonnegative_warnv_p): Declare.
(fold_warnv): Declare.
(fold_defer_overflow_warnings): Declare.
(fold_undefer_overflow_warnings): Declare.
(fold_deferring_overflow_warnings_p): Declare.
(tree_expr_nonzero_warnv_p): Declare.
gcc/testsuite/ChangeLog: 2007-01-31 Ian Lance Taylor iant@google.com
* gcc.dg/Wstrict-overflow-1.c: New test.
* gcc.dg/Wstrict-overflow-2.c: New test.
* gcc.dg/Wstrict-overflow-3.c: New test.
Index: gcc/tree-vrp.c
--- gcc/tree-vrp.c (revision 121377) +++ gcc/tree-vrp.c (working copy) @@ -414,7 +414,10 @@ symbolic_range_p (value_range_t vr) static bool vrp_expr_computes_nonnegative (tree expr) { - return tree_expr_nonnegative_p (expr); + bool ovf; + + / FIXME: May need to record overflow information here. / + return tree_expr_nonnegative_warnv_p (expr, &ovf); } / Like tree_expr_nonzero_p, but this function uses value ranges @@ -423,7 +426,10 @@ vrp_expr_computes_nonnegative (tree expr static bool vrp_expr_computes_nonzero (tree expr) { - if (tree_expr_nonzero_p (expr)) + bool ovf; + + /* FIXME: May need to record overflow information here. / + if (tree_expr_nonzero_warnv_p (expr, &ovf)) return true; / If we have an expression of the form &X->a, then the expression @@ -1697,7 +1703,10 @@ extract_range_from_unary_expr (value_ran determining if it evaluates to NULL [0, 0] or non-NULL (~[0, 0]). / if (POINTER_TYPE_P (TREE_TYPE (expr)) || POINTER_TYPE_P (TREE_TYPE (op0))) { - if (range_is_nonnull (&vr0) || tree_expr_nonzero_p (expr)) + bool ovf; + + / FIXME: May need to record overflow information here. */ + if (range_is_nonnull (&vr0) || tree_expr_nonzero_warnv_p (expr, &ovf)) set_value_range_to_nonnull (vr, TREE_TYPE (expr)); else if (range_is_null (&vr0)) set_value_range_to_null (vr, TREE_TYPE (expr)); Index: gcc/tree-ssa-loop-niter.c
--- gcc/tree-ssa-loop-niter.c (revision 121377) +++ gcc/tree-ssa-loop-niter.c (working copy) @@ -681,6 +681,7 @@ expand_simple_operations (tree expr) unsigned i, n; tree ret = NULL_TREE, e, ee, stmt; enum tree_code code; + const char ignore; if (expr == NULL_TREE) return expr; @@ -705,7 +706,7 @@ expand_simple_operations (tree expr) TREE_OPERAND (ret, i) = ee; } - return (ret ? fold (ret) : expr); + return (ret ? fold_warnv (ret, &ignore) : expr); } if (TREE_CODE (expr) != SSA_NAME) @@ -1053,11 +1054,18 @@ number_of_iterations_exit (struct loop * if (!simple_iv (loop, stmt, op1, &iv1, false)) return false; + / We don't want to see undefined signed overflow warnings while + computing the nmber of iterations. */ + fold_defer_overflow_warnings (); + iv0.base = expand_simple_operations (iv0.base); iv1.base = expand_simple_operations (iv1.base); if (!number_of_iterations_cond (type, &iv0, code, &iv1, niter, loop_only_exit_p (loop, exit))) - return false; + { + fold_undefer_overflow_warnings (); + return false; + } if (optimize >= 3) { @@ -1078,6 +1086,8 @@ number_of_iterations_exit (struct loop * niter->may_be_zero, &niter->additional_info); + fold_undefer_overflow_warnings (); + if (integer_onep (niter->assumptions)) return true; @@ -1376,6 +1386,9 @@ loop_niter_by_eval (struct loop loop, e } } + / Don't issue signed overflow warnings. / + fold_defer_overflow_warnings (); + for (i = 0; i < MAX_ITERATIONS_TO_TRACK; i++) { for (j = 0; j < 2; j++) @@ -1384,6 +1397,7 @@ loop_niter_by_eval (struct loop *loop, e acnd = fold_binary (cmp, boolean_type_node, aval[0], aval[1]); if (acnd && integer_zerop (acnd)) { + fold_undefer_overflow_warnings (); if (dump_file && (dump_flags & TDF_DETAILS)) fprintf (dump_file, "Proved that loop %d iterates %d times using brute force.\n", @@ -1395,10 +1409,15 @@ loop_niter_by_eval (struct loop *loop, e { val[j] = get_val_for (next[j], val[j]); if (!is_gimple_min_invariant (val[j])) - return chrec_dont_know; + { + fold_undefer_overflow_warnings (); + return chrec_dont_know; + } } } + fold_undefer_overflow_warnings (); + return chrec_dont_know; } @@ -1994,10 +2013,16 @@ estimate_numbers_of_iterations (void) loop_iterator li; struct loop *loop; + /* We don't want to issue signed overflow warnings while getting + loop iteration estimates. */ + fold_defer_overflow_warnings (); + FOR_EACH_LOOP (li, loop, 0) { estimate_numbers_of_iterations_loop (loop); } + + fold_undefer_overflow_warnings (); } /* Returns true if statement S1 dominates statement S2. */ @@ -2153,6 +2178,9 @@ scev_probably_wraps_p (tree base, tree s if (use_overflow_semantics && nowrap_type_p (type)) return false; + /* Don't issue signed overflow warnings. */ + fold_defer_overflow_warnings (); + /* Otherwise, compute the number of iterations before we reach the bound of the type, and verify that the loop is exited before this occurs. */ @@ -2179,8 +2207,15 @@ scev_probably_wraps_p (tree base, tree s estimate_numbers_of_iterations_loop (loop); for (bound = loop->bounds; bound; bound = bound->next) - if (n_of_executions_at_most (at_stmt, bound, valid_niter)) - return false; + { + if (n_of_executions_at_most (at_stmt, bound, valid_niter)) + { + fold_undefer_overflow_warnings (); + return false; + } + } + + fold_undefer_overflow_warnings (); / At this point we still don't have a proof that the iv does not overflow: give up. */ Index: gcc/tree-ssa-loop-manip.c
--- gcc/tree-ssa-loop-manip.c (revision 121377) +++ gcc/tree-ssa-loop-manip.c (working copy) @@ -86,7 +86,9 @@ create_iv (tree base, tree step, tree va } else { - if (!tree_expr_nonnegative_p (step) + bool ovf; + + if (!tree_expr_nonnegative_warnv_p (step, &ovf) && may_negate_without_overflow_p (step)) { incr_op = MINUS_EXPR; Index: gcc/tree.h
--- gcc/tree.h (revision 121377) +++ gcc/tree.h (working copy) @@ -3716,6 +3716,7 @@ extern int tree_int_cst_msb (tree); extern int tree_int_cst_sgn (tree); extern int tree_int_cst_sign_bit (tree); extern bool tree_expr_nonnegative_p (tree); +extern bool tree_expr_nonnegative_warnv_p (tree, bool *); extern bool may_negate_without_overflow_p (tree); extern tree get_inner_array_type (tree); @@ -4297,6 +4298,7 @@ extern int folding_initializer; subexpressions are not changed. */ extern tree fold (tree); +extern tree fold_warnv (tree, const char **); extern tree fold_unary (enum tree_code, tree, tree); extern tree fold_binary (enum tree_code, tree, tree, tree); extern tree fold_ternary (enum tree_code, tree, tree, tree, tree); @@ -4314,6 +4316,9 @@ extern tree fold_single_bit_test (enum t extern tree fold_ignored_result (tree); extern tree fold_abs_const (tree, tree); extern tree fold_indirect_ref_1 (tree, tree); +extern void fold_defer_overflow_warnings (void); +extern const char* fold_undefer_overflow_warnings (void); +extern bool fold_deferring_overflow_warnings_p (void); extern tree force_fit_type_double (tree, unsigned HOST_WIDE_INT, HOST_WIDE_INT, int, bool); @@ -4386,6 +4391,7 @@ extern bool ptr_difference_const (tree, extern enum tree_code invert_tree_comparison (enum tree_code, bool); extern bool tree_expr_nonzero_p (tree); +extern bool tree_expr_nonzero_warnv_p (tree, bool ); / In builtins.c */ extern tree fold_builtin (tree, tree, bool); Index: gcc/fold-const.c
--- gcc/fold-const.c (revision 121377) +++ gcc/fold-const.c (working copy) @@ -119,7 +119,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 +128,8 @@ static tree fold_cond_expr_with_comparis 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 +901,73 @@ div_if_zero_remainder (enum tree_code co 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 such + warning per expression. / + +static const char fold_deferred_overflow_warning; + +/ 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 a warning was seen, and we + are no longer deferring warnings, it is returned. Otherwise this + function returns NULL. / + +const char +fold_undefer_overflow_warnings (void) +{ + const char ret = NULL; + + gcc_assert (fold_deferring_overflow_warnings > 0); + --fold_deferring_overflow_warnings; + if (fold_deferring_overflow_warnings == 0) + { + ret = fold_deferred_overflow_warning; + fold_deferred_overflow_warning = NULL; + } + return ret; +} + +/ 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 warnmsg) +{ + gcc_assert (!flag_wrapv && !flag_trapv); + if (fold_deferring_overflow_warnings > 0) + fold_deferred_overflow_warning = warnmsg; + else + warning (OPT_Wstrict_overflow, warnmsg); +} + / Return true if the built-in mathematical function specified by CODE is odd, i.e. -f(x) == f(-x). / @@ -1197,14 +1264,22 @@ fold_negate_expr (tree t) case EXACT_DIV_EXPR: if (!INTEGRAL_TYPE_P (type) || TYPE_OVERFLOW_UNDEFINED (type)) { + const char * const warnmsg = ("assuming signed overflow is " + "undefined 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)); + { + fold_overflow_warning (warnmsg); + 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)); + { + fold_overflow_warning (warnmsg); + return fold_build2 (TREE_CODE (t), type, + negate_expr (tem), TREE_OPERAND (t, 1)); + } } break; @@ -3841,12 +3916,16 @@ range_binop (enum tree_code code, tree t / 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; @@ -3995,6 +4074,9 @@ make_range (tree exp, int *pin_p, tree * || (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)) @@ -4776,9 +4858,12 @@ fold_range_test (enum tree_code code, tr || 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 = ("assuming signed overflow is undefined when " + "folding range test"); /* If this is an OR operation, invert both sides; we will invert again at the end. */ @@ -4796,7 +4881,11 @@ fold_range_test (enum tree_code code, tr 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); + 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 @@ -4826,9 +4915,13 @@ fold_range_test (enum tree_code code, tr && (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); + return build2 (code == TRUTH_ANDIF_EXPR + ? TRUTH_AND_EXPR : TRUTH_OR_EXPR, + type, lhs, rhs); + } } } @@ -5427,10 +5520,15 @@ optimize_minmax_comparison (enum tree_co 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 @@ -5444,14 +5542,15 @@ extract_muldiv (tree t, tree c, enum tre 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); @@ -5461,6 +5560,7 @@ extract_muldiv_1 (tree t, tree c, enum t 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)) @@ -5517,7 +5617,8 @@ extract_muldiv_1 (tree t, tree c, enum t && !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; @@ -5527,7 +5628,8 @@ extract_muldiv_1 (tree t, tree c, enum t 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); @@ -5536,7 +5638,8 @@ extract_muldiv_1 (tree t, tree c, enum t } /* 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; @@ -5547,12 +5650,16 @@ extract_muldiv_1 (tree t, tree c, enum t 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)); }
@@ -5579,7 +5686,7 @@ extract_muldiv_1 (tree t, tree c, enum t
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:
@@ -5587,16 +5694,21 @@ extract_muldiv_1 (tree t, tree c, enum t
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. */
@@ -5677,11 +5789,13 @@ extract_muldiv_1 (tree t, tree c, enum t
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)
@@ -5711,15 +5825,23 @@ extract_muldiv_1 (tree t, tree c, enum t
&& 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;
@@ -7618,7 +7740,9 @@ fold_unary (enum tree_code code, tree ty
targ0));
}
/ ABS_EXPR<ABS_EXPR> = ABS_EXPR 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. /
@@ -7931,6 +8055,15 @@ maybe_canonicalize_comparison (enum tree
|| POINTER_TYPE_P (TREE_TYPE (arg0)))
return NULL_TREE;
+ / We don't call fold_overflow_warning here. This is a judgement
+ call. This optimization will change INT_MAX + 1 > 0 into INT_MAX
+ >= 0. If signed overflow wraps, this will change the condition
+ from false to true. That is why we can't implement this if
+ flag_wrapv is true. By not warning, we are assuming that people
+ will not rely on wrapping semantics for this sort of code. If we
+ did issue a warning here, we would get a large number of false
+ positives. /
+
/ Try canonicalization by simplifying arg0. /
t = maybe_canonicalize_comparison_1 (code, type, arg0, arg1);
if (t)
@@ -7989,7 +8122,12 @@ fold_comparison (enum tree_code code, tr
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 is undefined "
+ "when changing X +- C1 cmp C2 to "
+ "X cmp C1 +- C2");
+ return fold_build2 (code, type, variable, lhs);
+ }
}
/ For comparisons of pointers we can decompose it to a compile time
@@ -8154,6 +8292,9 @@ fold_comparison (enum tree_code code, tr
tree variable1 = TREE_OPERAND (arg0, 0);
tree variable2 = TREE_OPERAND (arg1, 0);
tree cst;
+ const char * const warnmsg = ("assuming signed overflow is undefined "
+ "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. /
@@ -8162,20 +8303,26 @@ fold_comparison (enum tree_code code, tr
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);
+ 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);
+ 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
@@ -8195,6 +8342,10 @@ fold_comparison (enum tree_code code, tr
gcc_assert (!integer_zerop (const1));
+ fold_overflow_warning ("assuming signed overflow is undefined when "
+ "eliminating multiplication in comparison "
+ "with zero");
+
/ 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);
@@ -8630,6 +8781,7 @@ fold_binary (enum tree_code code, tree t
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))
@@ -9340,11 +9492,18 @@ fold_binary (enum tree_code code, tree t
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 is undefined "
+ "when simplifying multiplication");
+ return fold_convert (type, tem);
+ }
/* Optimize z * conj(z) for integer complex numbers. */
if (TREE_CODE (arg0) == CONJ_EXPR
@@ -10244,8 +10403,10 @@ fold_binary (enum tree_code code, tree t
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)
@@ -10253,6 +10414,10 @@ fold_binary (enum tree_code code, tree t
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 is defined "
+ "when simplifying A / (B << N)");
+
sh_cnt = fold_build2 (PLUS_EXPR, TREE_TYPE (sh_cnt),
sh_cnt, build_int_cst (NULL_TREE, pow2));
return fold_build2 (RSHIFT_EXPR, type,
@@ -10280,13 +10445,25 @@ fold_binary (enum tree_code code, tree t
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 is undefined "
+ "when distributing negation across "
+ "division");
+ 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 is undefined "
+ "when distributing negation across "
+ "division");
+ 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.
@@ -10298,9 +10475,16 @@ fold_binary (enum tree_code code, tree t
&& 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 is undefined "
+ "when simplifying division");
+ return fold_convert (type, tem);
+ }
return NULL_TREE;
@@ -10332,8 +10516,10 @@ fold_binary (enum tree_code code, tree t
/* 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,
@@ -10345,6 +10531,9 @@ fold_binary (enum tree_code code, tree t
{
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 is undefined "
+ "when simplifying X % (power of two)");
return fold_build2 (BIT_AND_EXPR, type,
fold_convert (type, arg0),
fold_convert (type, mask));
@@ -10372,8 +10561,14 @@ fold_binary (enum tree_code code, tree t
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 is undefined "
+ "when simplifying modulos");
+ return fold_convert (type, tem);
+ }
return NULL_TREE;
@@ -11202,27 +11397,55 @@ fold_binary (enum tree_code code, tree t
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 is undefined "
+ "when assuming that (X - c) > X "
+ "is always false");
+ 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 is undefined "
+ "when assuming that (X + c) < X "
+ "is always false");
+ 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 is undefined "
+ "when assuming that (X - c) <= X "
+ "is always true");
+ 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 is undefined "
+ "when assuming that (X + c) >= X "
+ "is always true");
+ return constant_boolean_node (1, type);
+ }
if (TREE_CODE (arg01) == INTEGER_CST)
{
@@ -11230,23 +11453,47 @@ fold_binary (enum tree_code code, tree t
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 is "
+ "undefined when assuming that "
+ "(X + c) > X is always true");
+ 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 is "
+ "undefined when assuming that "
+ "(X - c) < X is always true");
+ 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 is "
+ "undefined when assuming that "
+ "(X + c) <= X is always false");
+ 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 is "
+ "undefined when assuming that "
+ "(X - c) >= X is always true");
+ return constant_boolean_node (0, type);
+ }
}
}
@@ -11448,16 +11695,16 @@ fold_binary (enum tree_code code, tree t
/ Convert ABS_EXPR >= 0 to true. /
if (code == GE_EXPR
- && tree_expr_nonnegative_p (arg0)
&& (integer_zerop (arg1)
|| (! HONOR_NANS (TYPE_MODE (TREE_TYPE (arg0)))
- && real_zerop (arg1))))
+ && real_zerop (arg1)))
+ && tree_expr_nonnegative_p (arg0))
return omit_one_operand (type, integer_one_node, arg0);
/ Convert ABS_EXPR < 0 to false. */
if (code == LT_EXPR
- && tree_expr_nonnegative_p (arg0)
- && (integer_zerop (arg1) || real_zerop (arg1)))
+ && (integer_zerop (arg1) || real_zerop (arg1))
+ && tree_expr_nonnegative_p (arg0))
return omit_one_operand (type, integer_zero_node, arg0);
/* If X is unsigned, convert X < (1 << Y) into X >> Y == 0
@@ -12198,6 +12445,22 @@ recursive_label:
#endif
+/ Fold EXPR. Don't issue any warnings about the use of undefined
+ signed overflow. Instead, set *OVERFLOW_WARNING to NULL if there
+ were no warnings, or to the warning string if there was a
+ warning. */
+
+tree
+fold_warnv (tree expr, const char *overflow_warning)
+{
+ tree ret;
+
+ fold_defer_overflow_warnings ();
+ ret = fold (expr);
+ overflow_warning = fold_undefer_overflow_warnings ();
+ return ret;
+}
+
/ Fold a unary tree expression with code CODE of type TYPE with an
operand OP0. Return a folded expression if successful. Otherwise,
return a tree expression with code CODE of type TYPE with an
@@ -12534,10 +12797,13 @@ multiple_of_p (tree type, tree top, tree
}
}
-/ 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;
@@ -12558,7 +12824,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:
@@ -12569,8 +12838,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. /
@@ -12596,8 +12867,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
@@ -12617,8 +12890,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:
@@ -12628,8 +12903,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:
@@ -12638,19 +12915,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:
{
@@ -12660,18 +12942,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);
@@ -12687,7 +12972,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. */
@@ -12706,7 +12991,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;
}
@@ -12742,7 +13028,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):
@@ -12772,21 +13059,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
@@ -12797,7 +13093,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
@@ -12818,7 +13115,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;
@@ -12837,14 +13135,36 @@ 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 is undefined when "
+ "determining that expression is always "
+ "non-negative");
+ 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))
@@ -12858,7 +13178,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);
@@ -12868,20 +13189,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;
@@ -12891,7 +13226,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;
@@ -12914,42 +13250,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);
@@ -12960,6 +13330,23 @@ 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 is undefined when "
+ "determining that expression is always "
+ "non-zero");
+ 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.
Index: gcc/ChangeLog
--- gcc/ChangeLog (revision 121377) +++ gcc/ChangeLog (working copy) @@ -1,3 +1,11 @@ +2007-01-31 Ian Lance Taylor iant@google.com + + * tree-vrp.c (vrp_expr_computes_nonnegative): Call + tree_expr_nonnegative_warnv_p instead of tree_expr_nonnegative_p. + (vrp_expr_computes_nonzero): Call tree_expr_nonzero_warnv_p + instead of tree_expr_nonzero_p. + (extract_range_from_unary_expr): Likewise. + 2007-01-31 Kazu Hirata kazu@codesourcery.com * gcc/config/arm/unwind-arm.h (_sleb128_t, _uleb128_t): New. Index: gcc/testsuite/gcc.dg/Wstrict-overflow-2.c
--- gcc/testsuite/gcc.dg/Wstrict-overflow-2.c (revision 0) +++ gcc/testsuite/gcc.dg/Wstrict-overflow-2.c (revision 0) @@ -0,0 +1,13 @@ +/* { dg-do compile } / +/ { dg-options "-fstrict-overflow -O2 -Wstrict-overflow" } / + +/ Source: Ian Lance Taylor. Based on strict-overflow-2.c. / + +/ We can only simplify the division when using strict overflow + semantics. / + +int +foo (int i) +{ + return (i * 100) / 10; / { dg-warning "assuming signed overflow is undefined" "correct warning" } */ +} Index: gcc/testsuite/gcc.dg/Wstrict-overflow-1.c
--- gcc/testsuite/gcc.dg/Wstrict-overflow-1.c (revision 0) +++ gcc/testsuite/gcc.dg/Wstrict-overflow-1.c (revision 0) @@ -0,0 +1,13 @@ +/* { dg-do compile } / +/ { dg-options "-fstrict-overflow -O2 -Wstrict-overflow" } / + +/ Source: Ian Lance Taylor. Based on strict-overflow-1.c. / + +/ We can only simplify the conditional when using strict overflow + semantics. / + +int +foo (int i) +{ + return i - 5 < 10; / { dg-warning "assuming signed overflow is undefined" "correct warning" } */ +} Index: gcc/testsuite/gcc.dg/Wstrict-overflow-3.c
--- gcc/testsuite/gcc.dg/Wstrict-overflow-3.c (revision 0) +++ gcc/testsuite/gcc.dg/Wstrict-overflow-3.c (revision 0) @@ -0,0 +1,13 @@ +/* { dg-do compile } / +/ { dg-options "-fstrict-overflow -O2 -Wstrict-overflow" } / + +/ Source: Ian Lance Taylor. Based on strict-overflow-3.c. / + +/ We can only simplify the conditional when using strict overflow + semantics. / + +int +foo (int i, int j) +{ + return i + 100 < j + 1000; / { dg-warning "assuming signed overflow is undefined" "correct warning" } */ +} Index: gcc/c-typeck.c
--- gcc/c-typeck.c (revision 121377) +++ gcc/c-typeck.c (working copy) @@ -3270,6 +3270,8 @@ build_conditional_expr (tree ifexp, tree if (unsigned_op1 ^ unsigned_op2) { + bool ovf; + /* Do not warn if the result type is signed, since the signed type will only be chosen if it can represent all the values of the unsigned type. / @@ -3278,8 +3280,10 @@ build_conditional_expr (tree ifexp, tree / Do not warn if the signed quantity is an unsuffixed integer literal (or some static constant expression involving such literals) and it is non-negative. / - else if ((unsigned_op2 && tree_expr_nonnegative_p (op1)) - || (unsigned_op1 && tree_expr_nonnegative_p (op2))) + else if ((unsigned_op2 + && tree_expr_nonnegative_warnv_p (op1, &ovf)) + || (unsigned_op1 + && tree_expr_nonnegative_warnv_p (op2, &ovf))) / OK */; else warning (0, "signed and unsigned type in conditional expression"); @@ -8301,6 +8305,7 @@ build_binary_op (enum tree_code code, tr else { tree sop, uop; + bool ovf; if (op0_signed) sop = xop0, uop = xop1; @@ -8312,7 +8317,7 @@ build_binary_op (enum tree_code code, tr constant expression involving such literals or a conditional expression involving such literals) and it is non-negative. / - if (tree_expr_nonnegative_p (sop)) + if (tree_expr_nonnegative_warnv_p (sop, &ovf)) / OK /; / Do not warn if the comparison is an equality operation, the unsigned quantity is an integral constant, and it Index: gcc/tree-cfgcleanup.c
--- gcc/tree-cfgcleanup.c (revision 121377) +++ gcc/tree-cfgcleanup.c (working copy) @@ -28,7 +28,7 @@ Boston, MA 02110-1301, USA. / #include "hard-reg-set.h" #include "basic-block.h" #include "output.h" -#include "errors.h" +#include "toplev.h" #include "flags.h" #include "function.h" #include "expr.h" @@ -78,15 +78,16 @@ cleanup_control_expr_graph (basic_block { edge e; edge_iterator ei; + const char warnmsg; switch (TREE_CODE (expr)) { case COND_EXPR: - val = fold (COND_EXPR_COND (expr)); + val = fold_warnv (COND_EXPR_COND (expr), &warnmsg); break; case SWITCH_EXPR: - val = fold (SWITCH_COND (expr)); + val = fold_warnv (SWITCH_COND (expr), &warnmsg); if (TREE_CODE (val) != INTEGER_CST) return false; break; @@ -104,6 +105,20 @@ cleanup_control_expr_graph (basic_block { if (e != taken_edge) { + if (warnmsg != NULL) + { + location_t locus; + + if (!expr_has_location (expr)) + locus = input_location; + else + locus = expr_location (expr); + warning (OPT_Wstrict_overflow, "%H%s", &locus, warnmsg); + + /* Only warn once. */ + warnmsg = NULL; + } + taken_edge->probability += e->probability; taken_edge->count += e->count; remove_edge (e); Index: gcc/common.opt
--- gcc/common.opt (revision 121377) +++ gcc/common.opt (working copy) @@ -141,6 +141,10 @@ Wstrict-aliasing= Common Joined UInteger Warn about code which might break strict aliasing rules +Wstrict-overflow +Common Var(warn_strict_overflow) +Warn about optimizations that assume that signed overflow is undefined + Wstring-literal-comparison Common Var(warn_string_literal_comparison) Warn about comparisons to constant string literals Index: gcc/tree-cfg.c
--- gcc/tree-cfg.c (revision 121377) +++ gcc/tree-cfg.c (working copy) @@ -421,10 +421,27 @@ fold_cond_expr_cond (void) if (stmt && TREE_CODE (stmt) == COND_EXPR) { - tree cond = fold (COND_EXPR_COND (stmt)); - if (integer_zerop (cond)) + const char* warnmsg; + bool zerop, onep; + + tree cond = fold_warnv (COND_EXPR_COND (stmt), &warnmsg); + zerop = integer_zerop (cond); + onep = integer_onep (cond); + + if (warnmsg != NULL && (zerop || onep)) + { + location_t locus; + + if (!expr_has_location (stmt)) + locus = input_location; + else + locus = expr_location (stmt); + warning (OPT_Wstrict_overflow, "%H%s", &locus, warnmsg); + } + + if (zerop) COND_EXPR_COND (stmt) = boolean_false_node; - else if (integer_onep (cond)) + else if (onep) COND_EXPR_COND (stmt) = boolean_true_node; } } Index: gcc/passes.c
--- gcc/passes.c (revision 121377) +++ gcc/passes.c (working copy) @@ -926,6 +926,17 @@ execute_todo (unsigned int flags) } }
+/* Verify invariants that should hold between passes. This is a place
to put simple sanity checks. */
+static void +verify_interpass_invariants (void) +{ +#ifdef ENABLE_CHECKING
gcc_assert (!fold_deferring_overflow_warnings_p ()); +#endif +}
/* Clear the last verified flag. */
static void
@@ -1037,6 +1048,7 @@ execute_one_pass (struct tree_opt_pass *
/* Run post-pass cleanup and verification. */ execute_todo (todo_after | pass->todo_flags_finish);
verify_interpass_invariants ();
if (!current_function_decl) cgraph_process_new_functions ();
- Follow-Ups:
- Re: PATCH RFC: -Wstrict-overflow
* From: Richard Guenther - Re: PATCH RFC: -Wstrict-overflow
* From: Joseph S. Myers - Re: PATCH RFC: -Wstrict-overflow
* From: Eric Botcazou - Re: PATCH RFC: -Wstrict-overflow
* From: Paolo Bonzini
- Re: PATCH RFC: -Wstrict-overflow
Index Nav: | [Date Index] [Subject Index] [Author Index] [Thread Index] | |
---|---|---|
Message Nav: | [Date Prev] [Date Next] | [Thread Prev] [Thread Next] |