This is an alternate fix (see 
http://gcc.gnu.org/ml/gcc-patches/2013-09/msg00234.html for the other
one) for the various PRs that show that LIM exposes undefined
signed overflow on paths where it wasn't executed before LIM
ultimately leading to a miscompilation.

For this fix we rewrite invariant stmts to use unsigned arithmetic
when it is one of the operations that SCEV and niter analysis
handles (thus not division or absolute).  The other fix instead
disables invariant motion for those expressions.

Bootstrapped and tested on x86_64-unknown-linux-gnu.

The issue is also present on the 4.8 branch, so either patch
should be backported in the end.  I will try to benchmark
both tomorrow (unless somebody beats me on that).

Any preference or other suggestions?

Thanks,
Richard.

2013-10-15  Richard Biener  <rguent...@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.

Index: gcc/tree-ssa-loop-im.c
===================================================================
*** gcc/tree-ssa-loop-im.c      (revision 203600)
--- gcc/tree-ssa-loop-im.c      (working copy)
*************** public:
*** 1117,1122 ****
--- 1117,1183 ----
    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.  */
*************** move_computations_dom_walker::before_dom
*** 1247,1253 ****
            }
        }
        gsi_remove (&bsi, false);
!       gsi_insert_on_edge (e, stmt);
      }
  }
  
--- 1308,1328 ----
            }
        }
        gsi_remove (&bsi, false);
!       /* 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);
      }
  }
  
Index: gcc/testsuite/gcc.dg/torture/pr58143-1.c
===================================================================
*** gcc/testsuite/gcc.dg/torture/pr58143-1.c    (revision 0)
--- gcc/testsuite/gcc.dg/torture/pr58143-1.c    (working copy)
***************
*** 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;
+ }
Index: gcc/testsuite/gcc.dg/torture/pr58143-2.c
===================================================================
*** gcc/testsuite/gcc.dg/torture/pr58143-2.c    (revision 0)
--- gcc/testsuite/gcc.dg/torture/pr58143-2.c    (working copy)
***************
*** 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;
+ }
Index: gcc/testsuite/gcc.dg/torture/pr58143-3.c
===================================================================
*** gcc/testsuite/gcc.dg/torture/pr58143-3.c    (revision 0)
--- gcc/testsuite/gcc.dg/torture/pr58143-3.c    (working copy)
***************
*** 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;
+ }

Reply via email to