re PR tree-optimization/58143 (wrong code at -O3)
authorRichard Biener <rguenther@suse.de>
Thu, 17 Oct 2013 09:59:47 +0000 (09:59 +0000)
committerRichard Biener <rguenth@gcc.gnu.org>
Thu, 17 Oct 2013 09:59:47 +0000 (09:59 +0000)
2013-10-17  Richard Biener  <rguenther@suse.de>

PR tree-optimization/58143
* tree-ssa-loop-im.c (arith_code_with_undefined_signed_overflow):
New function.
(rewrite_to_defined_overflow): Likewise.
(move_computations_dom_walker::before_dom): Rewrite stmts
with undefined signed overflow that are not always executed
into unsigned arithmetic.

* gcc.dg/torture/pr58143-1.c: New testcase.
* gcc.dg/torture/pr58143-2.c: Likewise.
* gcc.dg/torture/pr58143-3.c: Likewise.

From-SVN: r203745

gcc/ChangeLog
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.dg/torture/pr58143-1.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/torture/pr58143-2.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/torture/pr58143-3.c [new file with mode: 0644]
gcc/tree-ssa-loop-im.c

index de8bf88..5a8fb7f 100644 (file)
@@ -1,3 +1,13 @@
+2013-10-17  Richard Biener  <rguenther@suse.de>
+
+       PR tree-optimization/58143
+       * tree-ssa-loop-im.c (arith_code_with_undefined_signed_overflow):
+       New function.
+       (rewrite_to_defined_overflow): Likewise.
+       (move_computations_dom_walker::before_dom): Rewrite stmts
+       with undefined signed overflow that are not always executed
+       into unsigned arithmetic.
+
 2013-10-16  Michael Meissner  <meissner@linux.vnet.ibm.com>
 
        PR target/57756
index 8be6025..dce8a58 100644 (file)
@@ -1,3 +1,10 @@
+2013-10-17  Richard Biener  <rguenther@suse.de>
+
+       PR tree-optimization/58143
+       * gcc.dg/torture/pr58143-1.c: New testcase.
+       * gcc.dg/torture/pr58143-2.c: Likewise.
+       * gcc.dg/torture/pr58143-3.c: Likewise.
+
 2013-10-17  Marek Polacek  <polacek@redhat.com>
 
        PR c/58267
diff --git a/gcc/testsuite/gcc.dg/torture/pr58143-1.c b/gcc/testsuite/gcc.dg/torture/pr58143-1.c
new file mode 100644 (file)
index 0000000..855515e
--- /dev/null
@@ -0,0 +1,51 @@
+/* { dg-do run } */
+/* { dg-additional-options "-fstrict-overflow" } */
+
+extern void abort (void);
+
+int a, b, c, d, e, f, g, h = 1, i;
+
+int foo (int p)
+{
+  return p < 0 && a < - __INT_MAX__ - 1 - p ? 0 : 1;
+}
+
+int *bar ()
+{
+  int j; 
+  i = h ? 0 : 1 % h;
+  for (j = 0; j < 1; j++)
+    for (d = 0; d; d++)
+      for (e = 1; e;)
+       return 0;
+  return 0;
+}
+
+int baz ()
+{
+  for (; b >= 0; b--)
+    for (c = 1; c >= 0; c--)
+      {
+       int *k = &c;
+       for (;;)
+         {
+           for (f = 0; f < 1; f++)
+             {
+               g = foo (*k);
+               bar ();
+             }
+           if (*k)
+             break;
+           return 0;
+         }
+      }
+  return 0;
+}
+
+int main ()
+{
+  baz ();
+  if (b != 0)
+    abort ();
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.dg/torture/pr58143-2.c b/gcc/testsuite/gcc.dg/torture/pr58143-2.c
new file mode 100644 (file)
index 0000000..dd0dae1
--- /dev/null
@@ -0,0 +1,34 @@
+/* { dg-do run } */
+/* { dg-additional-options "-fstrict-overflow" } */
+
+int a, b, d, e, f, *g, h, i;
+volatile int c;
+
+char foo (unsigned char p)
+{
+  return p + 1;
+}
+
+int bar () 
+{
+  for (h = 0; h < 3; h = foo (h))
+    {
+      c;
+      for (f = 0; f < 1; f++)
+       {
+         i = a && 0 < -__INT_MAX__ - h ? 0 : 1;
+         if (e)
+           for (; d;)
+             b = 0;
+         else
+           g = 0;
+       }
+    }
+  return 0;
+}
+
+int main ()
+{
+  bar ();
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.dg/torture/pr58143-3.c b/gcc/testsuite/gcc.dg/torture/pr58143-3.c
new file mode 100644 (file)
index 0000000..23ae9cd
--- /dev/null
@@ -0,0 +1,18 @@
+/* { dg-do run } */
+/* { dg-additional-options "-fstrict-overflow" } */
+
+int a, b, c, d, e;
+
+int
+main ()
+{
+  for (b = 4; b > -30; b--)
+    for (; c;)
+      for (;;)
+       {
+         e = a > __INT_MAX__ - b;
+         if (d)
+           break;
+       }
+  return 0;
+}
index 84f50cd..15af428 100644 (file)
@@ -1117,6 +1117,67 @@ 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.  */
@@ -1247,7 +1308,21 @@ move_computations_dom_walker::before_dom_children (basic_block bb)
            }
        }
       gsi_remove (&bsi, false);
-      gsi_insert_on_edge (e, stmt);
+      /* In case this is a stmt that is not unconditionally executed
+         when the target loop header is executed and the stmt may
+        invoke undefined integer or pointer overflow rewrite it to
+        unsigned arithmetic.  */
+      if (is_gimple_assign (stmt)
+         && INTEGRAL_TYPE_P (TREE_TYPE (gimple_assign_lhs (stmt)))
+         && TYPE_OVERFLOW_UNDEFINED (TREE_TYPE (gimple_assign_lhs (stmt)))
+         && arith_code_with_undefined_signed_overflow
+              (gimple_assign_rhs_code (stmt))
+         && (!ALWAYS_EXECUTED_IN (bb)
+             || !(ALWAYS_EXECUTED_IN (bb) == level
+                  || flow_loop_nested_p (ALWAYS_EXECUTED_IN (bb), level))))
+       gsi_insert_seq_on_edge (e, rewrite_to_defined_overflow (stmt));
+      else
+       gsi_insert_on_edge (e, stmt);
     }
 }