This is the mail archive of the gcc-patches@gcc.gnu.org mailing 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]

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 ();


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]