Hi!

The following testcase on x86_64 (or the f90-intrinsic-bitsize.f on 32-bit
HWI) with -Os shows a bug in discover_iteration_bound_by_body_walk.  If some
bound is a -1, -1 HWI, then adding double_int_one to it overflows into 0, 0
HWI and we can return that as maximum number of iterations.  We need to
ignore such bounds instead.

Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?

2012-12-11  Jakub Jelinek  <ja...@redhat.com>

        PR fortran/55633
        * tree-ssa-loop-niter.c (discover_iteration_bound_by_body_walk):
        Ignore bounds on which bound += double_int_one overflowed.

        * gcc.dg/torture/pr55633.c: New test.

--- gcc/tree-ssa-loop-niter.c.jj        2012-11-21 16:00:09.000000000 +0100
+++ gcc/tree-ssa-loop-niter.c   2012-12-11 10:56:49.890396498 +0100
@@ -3011,7 +3011,12 @@ discover_iteration_bound_by_body_walk (s
       /* Exit terminates loop at given iteration, while non-exits produce 
undefined
         effect on the next iteration.  */
       if (!elt->is_exit)
-       bound += double_int_one;
+       {
+         bound += double_int_one;
+         /* If an overflow occurred, ignore the result.  */
+         if (bound.is_zero ())
+           continue;
+       }
 
       if (!loop->any_upper_bound
          || bound.ult (loop->nb_iterations_upper_bound))
@@ -3037,7 +3042,12 @@ discover_iteration_bound_by_body_walk (s
     {
       double_int bound = elt->bound;
       if (!elt->is_exit)
-       bound += double_int_one;
+       {
+         bound += double_int_one;
+         /* If an overflow occurred, ignore the result.  */
+         if (bound.is_zero ())
+           continue;
+       }
 
       if (!loop->any_upper_bound
          || bound.ult (loop->nb_iterations_upper_bound))
--- gcc/testsuite/gcc.dg/torture/pr55633.c.jj   2012-12-11 11:12:19.567069030 
+0100
+++ gcc/testsuite/gcc.dg/torture/pr55633.c      2012-12-11 11:12:04.000000000 
+0100
@@ -0,0 +1,39 @@
+/* PR fortran/55633 */
+/* { dg-do run { target int128 } } */
+
+extern void abort (void);
+
+__attribute__((noinline, noclone)) void
+bar (__int128_t *x)
+{
+  int c = sizeof (__int128_t) * __CHAR_BIT__;
+  if (c > 127)
+    c = 127;
+  if (*x != c)
+    abort ();
+}
+
+__attribute__((noinline)) void
+foo (void)
+{
+  __int128_t m, ma;
+  ma = 0;
+  m = 0;
+  m = ~m;
+  do
+    {
+      if (m == 0 || ma > 126)
+       break;
+      ma = ma + 1;
+      m = ((__uint128_t) m) >> 1;
+    }
+  while (1);
+  bar (&ma);
+}
+
+int
+main ()
+{
+  foo ();
+  return 0;
+}

        Jakub

Reply via email to