This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
PATCH RFC: -Wstrict-overflow
- From: Ian Lance Taylor <iant at google dot com>
- 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<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. */
@@ -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<x> >= 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<x> < 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 ();