Patchwork Fix discover_iteration_bound_by_body_walk bounds computation overflows (PR fortran/55633)

login
register
mail settings
Submitter Jakub Jelinek
Date Dec. 11, 2012, 6:32 p.m.
Message ID <20121211183205.GT2315@tucnak.redhat.com>
Download mbox | patch
Permalink /patch/205287/
State New
Headers show

Comments

Jakub Jelinek - Dec. 11, 2012, 6:32 p.m.
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  <jakub@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.


	Jakub
Richard Guenther - Dec. 12, 2012, 9:20 a.m.
On Tue, 11 Dec 2012, Jakub Jelinek wrote:

> 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?

Ok.

Thanks,
Richard.

> 2012-12-11  Jakub Jelinek  <jakub@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
> 
>

Patch

--- 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;
+}