[PATCH] Avoid introducing undefined behavior in sccp (PR tree-optimization/59387)

Jakub Jelinek jakub@redhat.com
Mon Jan 13 19:15:00 GMT 2014


On Mon, Jan 13, 2014 at 11:42:11AM +0100, Richard Biener wrote:
> > +	  if (TREE_CODE (def) == INTEGER_CST && TREE_OVERFLOW (def))
> 
> TREE_OVERFLOW_P (), but it seems to me that the SCEV machinery
> should do this at a good place (like where it finally records
> the result into its cache before returning it, at set_and_end:
> of analyze_scalar_evolution_1).
> 
> > +	    def = drop_tree_overflow (def);

As discussed on IRC, dropped this part of the change altogether (for now).

> Hmm, stmt is still in the 'stmts' sequence here, I think you should
> gsi_remove it before inserting it elsewhere.

Fixed, bootstrapped/regtested on x86_64-linux and i686-linux, here is
what I've committed in the end:

2014-01-13  Jakub Jelinek  <jakub@redhat.com>

	PR tree-optimization/59387
	* tree-scalar-evolution.c: Include gimple-fold.h and gimplify-me.h.
	(scev_const_prop): If folded_casts and type has undefined overflow,
	use force_gimple_operand instead of force_gimple_operand_gsi and
	for each added stmt if it is assign with
	arith_code_with_undefined_signed_overflow, call
	rewrite_to_defined_overflow.
	* tree-ssa-loop-im.c: Don't include gimplify-me.h, include
	gimple-fold.h instead.
	(arith_code_with_undefined_signed_overflow,
	rewrite_to_defined_overflow): Moved to ...
	* gimple-fold.c (arith_code_with_undefined_signed_overflow,
	rewrite_to_defined_overflow): ... here.  No longer static.
	Include gimplify-me.h.
	* gimple-fold.h (arith_code_with_undefined_signed_overflow,
	rewrite_to_defined_overflow): New prototypes.

	* gcc.c-torture/execute/pr59387.c: New test.

--- gcc/tree-scalar-evolution.c.jj	2014-01-08 17:44:57.596582925 +0100
+++ gcc/tree-scalar-evolution.c	2014-01-10 15:46:55.355915072 +0100
@@ -286,6 +286,8 @@ along with GCC; see the file COPYING3.
 #include "dumpfile.h"
 #include "params.h"
 #include "tree-ssa-propagate.h"
+#include "gimple-fold.h"
+#include "gimplify-me.h"
 
 static tree analyze_scalar_evolution_1 (struct loop *, tree, tree);
 static tree analyze_scalar_evolution_for_address_of (struct loop *loop,
@@ -3409,7 +3411,7 @@ scev_const_prop (void)
     {
       edge exit;
       tree def, rslt, niter;
-      gimple_stmt_iterator bsi;
+      gimple_stmt_iterator gsi;
 
       /* If we do not know exact number of iterations of the loop, we cannot
 	 replace the final value.  */
@@ -3424,7 +3426,7 @@ scev_const_prop (void)
       /* Ensure that it is possible to insert new statements somewhere.  */
       if (!single_pred_p (exit->dest))
 	split_loop_exit_edge (exit);
-      bsi = gsi_after_labels (exit->dest);
+      gsi = gsi_after_labels (exit->dest);
 
       ex_loop = superloop_at_depth (loop,
 				    loop_depth (exit->dest->loop_father) + 1);
@@ -3447,7 +3449,9 @@ scev_const_prop (void)
 	      continue;
 	    }
 
-	  def = analyze_scalar_evolution_in_loop (ex_loop, loop, def, NULL);
+	  bool folded_casts;
+	  def = analyze_scalar_evolution_in_loop (ex_loop, loop, def,
+						  &folded_casts);
 	  def = compute_overall_effect_of_inner_loop (ex_loop, def);
 	  if (!tree_does_not_contain_chrecs (def)
 	      || chrec_contains_symbols_defined_in_loop (def, ex_loop->num)
@@ -3485,10 +3489,37 @@ scev_const_prop (void)
 	  def = unshare_expr (def);
 	  remove_phi_node (&psi, false);
 
-	  def = force_gimple_operand_gsi (&bsi, def, false, NULL_TREE,
-      					  true, GSI_SAME_STMT);
+	  /* If def's type has undefined overflow and there were folded
+	     casts, rewrite all stmts added for def into arithmetics
+	     with defined overflow behavior.  */
+	  if (folded_casts && TYPE_OVERFLOW_UNDEFINED (TREE_TYPE (def)))
+	    {
+	      gimple_seq stmts;
+	      gimple_stmt_iterator gsi2;
+	      def = force_gimple_operand (def, &stmts, true, NULL_TREE);
+	      gsi2 = gsi_start (stmts);
+	      while (!gsi_end_p (gsi2))
+		{
+		  gimple stmt = gsi_stmt (gsi2);
+		  gimple_stmt_iterator gsi3 = gsi2;
+		  gsi_next (&gsi2);
+		  gsi_remove (&gsi3, false);
+		  if (is_gimple_assign (stmt)
+		      && arith_code_with_undefined_signed_overflow
+					(gimple_assign_rhs_code (stmt)))
+		    gsi_insert_seq_before (&gsi,
+					   rewrite_to_defined_overflow (stmt),
+					   GSI_SAME_STMT);
+		  else
+		    gsi_insert_before (&gsi, stmt, GSI_SAME_STMT);
+		}
+	    }
+	  else
+	    def = force_gimple_operand_gsi (&gsi, def, false, NULL_TREE,
+					    true, GSI_SAME_STMT);
+
 	  ass = gimple_build_assign (rslt, def);
-	  gsi_insert_before (&bsi, ass, GSI_SAME_STMT);
+	  gsi_insert_before (&gsi, ass, GSI_SAME_STMT);
 	  if (dump_file)
 	    {
 	      print_gimple_stmt (dump_file, ass, 0, 0);
--- gcc/tree-ssa-loop-im.c.jj	2014-01-03 11:40:29.000000000 +0100
+++ gcc/tree-ssa-loop-im.c	2014-01-10 15:34:32.512734315 +0100
@@ -35,7 +35,6 @@ along with GCC; see the file COPYING3.
 #include "gimple.h"
 #include "gimplify.h"
 #include "gimple-iterator.h"
-#include "gimplify-me.h"
 #include "gimple-ssa.h"
 #include "tree-cfg.h"
 #include "tree-phinodes.h"
@@ -53,6 +52,7 @@ along with GCC; see the file COPYING3.
 #include "tree-affine.h"
 #include "tree-ssa-propagate.h"
 #include "trans-mem.h"
+#include "gimple-fold.h"
 
 /* TODO:  Support for predicated code motion.  I.e.
 
@@ -1135,67 +1135,6 @@ public:
   unsigned int todo_;
 };
 
-/* Return true if CODE is an operation that when operating on signed
-   integer types involves undefined behavior on overflow and the
-   operation can be expressed with unsigned arithmetic.  */
-
-static bool
-arith_code_with_undefined_signed_overflow (tree_code code)
-{
-  switch (code)
-    {
-    case PLUS_EXPR:
-    case MINUS_EXPR:
-    case MULT_EXPR:
-    case NEGATE_EXPR:
-    case POINTER_PLUS_EXPR:
-      return true;
-    default:
-      return false;
-    }
-}
-
-/* Rewrite STMT, an assignment with a signed integer or pointer arithmetic
-   operation that can be transformed to unsigned arithmetic by converting
-   its operand, carrying out the operation in the corresponding unsigned
-   type and converting the result back to the original type.
-
-   Returns a sequence of statements that replace STMT and also contain
-   a modified form of STMT itself.  */
-
-static gimple_seq
-rewrite_to_defined_overflow (gimple stmt)
-{
-  if (dump_file && (dump_flags & TDF_DETAILS))
-    {
-      fprintf (dump_file, "rewriting stmt with undefined signed "
-	       "overflow ");
-      print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
-    }
-
-  tree lhs = gimple_assign_lhs (stmt);
-  tree type = unsigned_type_for (TREE_TYPE (lhs));
-  gimple_seq stmts = NULL;
-  for (unsigned i = 1; i < gimple_num_ops (stmt); ++i)
-    {
-      gimple_seq stmts2 = NULL;
-      gimple_set_op (stmt, i,
-		     force_gimple_operand (fold_convert (type,
-							 gimple_op (stmt, i)),
-					   &stmts2, true, NULL_TREE));
-      gimple_seq_add_seq (&stmts, stmts2);
-    }
-  gimple_assign_set_lhs (stmt, make_ssa_name (type, stmt));
-  if (gimple_assign_rhs_code (stmt) == POINTER_PLUS_EXPR)
-    gimple_assign_set_rhs_code (stmt, PLUS_EXPR);
-  gimple_seq_add_stmt (&stmts, stmt);
-  gimple cvt = gimple_build_assign_with_ops
-      (NOP_EXPR, lhs, gimple_assign_lhs (stmt), NULL_TREE);
-  gimple_seq_add_stmt (&stmts, cvt);
-
-  return stmts;
-}
-
 /* Hoist the statements in basic block BB out of the loops prescribed by
    data stored in LIM_DATA structures associated with each statement.  Callback
    for walk_dominator_tree.  */
--- gcc/gimple-fold.c.jj	2014-01-09 21:08:41.000000000 +0100
+++ gcc/gimple-fold.c	2014-01-10 15:34:02.274882625 +0100
@@ -51,6 +51,7 @@ along with GCC; see the file COPYING3.
 #include "gimple-pretty-print.h"
 #include "tree-ssa-address.h"
 #include "langhooks.h"
+#include "gimplify-me.h"
 
 /* Return true when DECL can be referenced from current unit.
    FROM_DECL (if non-null) specify constructor of variable DECL was taken from.
@@ -3548,3 +3549,64 @@ gimple_fold_indirect_ref (tree t)
 
   return NULL_TREE;
 }
+
+/* Return true if CODE is an operation that when operating on signed
+   integer types involves undefined behavior on overflow and the
+   operation can be expressed with unsigned arithmetic.  */
+
+bool
+arith_code_with_undefined_signed_overflow (tree_code code)
+{
+  switch (code)
+    {
+    case PLUS_EXPR:
+    case MINUS_EXPR:
+    case MULT_EXPR:
+    case NEGATE_EXPR:
+    case POINTER_PLUS_EXPR:
+      return true;
+    default:
+      return false;
+    }
+}
+
+/* Rewrite STMT, an assignment with a signed integer or pointer arithmetic
+   operation that can be transformed to unsigned arithmetic by converting
+   its operand, carrying out the operation in the corresponding unsigned
+   type and converting the result back to the original type.
+
+   Returns a sequence of statements that replace STMT and also contain
+   a modified form of STMT itself.  */
+
+gimple_seq
+rewrite_to_defined_overflow (gimple stmt)
+{
+  if (dump_file && (dump_flags & TDF_DETAILS))
+    {
+      fprintf (dump_file, "rewriting stmt with undefined signed "
+	       "overflow ");
+      print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
+    }
+
+  tree lhs = gimple_assign_lhs (stmt);
+  tree type = unsigned_type_for (TREE_TYPE (lhs));
+  gimple_seq stmts = NULL;
+  for (unsigned i = 1; i < gimple_num_ops (stmt); ++i)
+    {
+      gimple_seq stmts2 = NULL;
+      gimple_set_op (stmt, i,
+		     force_gimple_operand (fold_convert (type,
+							 gimple_op (stmt, i)),
+					   &stmts2, true, NULL_TREE));
+      gimple_seq_add_seq (&stmts, stmts2);
+    }
+  gimple_assign_set_lhs (stmt, make_ssa_name (type, stmt));
+  if (gimple_assign_rhs_code (stmt) == POINTER_PLUS_EXPR)
+    gimple_assign_set_rhs_code (stmt, PLUS_EXPR);
+  gimple_seq_add_stmt (&stmts, stmt);
+  gimple cvt = gimple_build_assign_with_ops
+      (NOP_EXPR, lhs, gimple_assign_lhs (stmt), NULL_TREE);
+  gimple_seq_add_stmt (&stmts, cvt);
+
+  return stmts;
+}
--- gcc/gimple-fold.h.jj	2014-01-03 11:40:57.000000000 +0100
+++ gcc/gimple-fold.h	2014-01-10 15:25:32.705493146 +0100
@@ -40,5 +40,7 @@ extern tree fold_const_aggregate_ref (tr
 extern tree gimple_get_virt_method_for_binfo (HOST_WIDE_INT, tree);
 extern bool gimple_val_nonnegative_real_p (tree);
 extern tree gimple_fold_indirect_ref (tree);
+extern bool arith_code_with_undefined_signed_overflow (tree_code);
+extern gimple_seq rewrite_to_defined_overflow (gimple);
 
 #endif  /* GCC_GIMPLE_FOLD_H */
--- gcc/testsuite/gcc.c-torture/execute/pr59387.c.jj	2014-01-10 14:36:03.476754070 +0100
+++ gcc/testsuite/gcc.c-torture/execute/pr59387.c	2014-01-10 14:36:03.476754070 +0100
@@ -0,0 +1,19 @@
+/* PR tree-optimization/59387 */
+
+int a, *d, **e = &d, f;
+char c;
+struct S { int f1; } b;
+
+int
+main ()
+{
+  for (a = -19; a; a++)
+    {
+      for (b.f1 = 0; b.f1 < 24; b.f1++)
+	c--;
+      *e = &f;
+      if (!d)
+	return 0;
+    }
+  return 0;
+}


	Jakub



More information about the Gcc-patches mailing list