Patchwork Fix VRP single-bit signed precision handling (PR tree-optimization/54676)

login
register
mail settings
Submitter Jakub Jelinek
Date Sept. 25, 2012, 11:23 a.m.
Message ID <20120925112353.GK1787@tucnak.redhat.com>
Download mbox | patch
Permalink /patch/186778/
State New
Headers show

Comments

Jakub Jelinek - Sept. 25, 2012, 11:23 a.m.
Hi!

This patch fixes two spots where signed 1-bit precision isn't handled
properly in VRP.  With that type, build_int_cst (TREE_TYPE (min), 1)
will overflow and thus adding it to something or subtracting leads to
ICEs or bad code.  In the first spot min is different from max, which
for 1-bit precision implies either all values, or none (but we don't have
empty ranges and fallback to varying for those anyway).
In the second case we can optimize if the anti range is singleton, then
the corresponding range is singleton too (the other value).

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

2012-09-25  Jakub Jelinek  <jakub@redhat.com>

	PR tree-optimization/54676
	* tree-vrp.c (set_and_canonicalize_value_range): Handle
	one bit precision properly.

	* gcc.dg/pr54676.c: New test.


	Jakub
Richard Guenther - Sept. 25, 2012, 11:35 a.m.
On Tue, Sep 25, 2012 at 1:23 PM, Jakub Jelinek <jakub@redhat.com> wrote:
> Hi!
>
> This patch fixes two spots where signed 1-bit precision isn't handled
> properly in VRP.  With that type, build_int_cst (TREE_TYPE (min), 1)
> will overflow and thus adding it to something or subtracting leads to
> ICEs or bad code.  In the first spot min is different from max, which
> for 1-bit precision implies either all values, or none (but we don't have
> empty ranges and fallback to varying for those anyway).

emty ranges are turned into VR_UNDEFINED in intersect_range for example
(but not consistently so I see, not in set_and_canonicalize_value_range
at least).

> In the second case we can optimize if the anti range is singleton, then
> the corresponding range is singleton too (the other value).
>
> Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?

Ok.

Thanks,
Richard.

> 2012-09-25  Jakub Jelinek  <jakub@redhat.com>
>
>         PR tree-optimization/54676
>         * tree-vrp.c (set_and_canonicalize_value_range): Handle
>         one bit precision properly.
>
>         * gcc.dg/pr54676.c: New test.
>
> --- gcc/tree-vrp.c.jj   2012-09-17 11:13:12.000000000 +0200
> +++ gcc/tree-vrp.c      2012-09-24 10:06:10.814376659 +0200
> @@ -501,8 +501,19 @@ set_and_canonicalize_value_range (value_
>       to adjust them.  */
>    if (tree_int_cst_lt (max, min))
>      {
> -      tree one = build_int_cst (TREE_TYPE (min), 1);
> -      tree tmp = int_const_binop (PLUS_EXPR, max, one);
> +      tree one, tmp;
> +
> +      /* For one bit precision if max < min, then the swapped
> +        range covers all values, so for VR_RANGE it is varying and
> +        for VR_ANTI_RANGE empty range, so drop to varying as well.  */
> +      if (TYPE_PRECISION (TREE_TYPE (min)) == 1)
> +       {
> +         set_value_range_to_varying (vr);
> +         return;
> +       }
> +
> +      one = build_int_cst (TREE_TYPE (min), 1);
> +      tmp = int_const_binop (PLUS_EXPR, max, one);
>        max = int_const_binop (MINUS_EXPR, min, one);
>        min = tmp;
>
> @@ -531,6 +542,24 @@ set_and_canonicalize_value_range (value_
>           set_value_range_to_varying (vr);
>           return;
>         }
> +      else if (TYPE_PRECISION (TREE_TYPE (min)) == 1
> +              && !TYPE_UNSIGNED (TREE_TYPE (min))
> +              && (is_min || is_max))
> +       {
> +         /* For signed 1-bit precision, one is not in-range and
> +            thus adding/subtracting it would result in overflows.  */
> +         if (operand_equal_p (min, max, 0))
> +           {
> +             min = max = is_min ? vrp_val_max (TREE_TYPE (min))
> +                                : vrp_val_min (TREE_TYPE (min));
> +             t = VR_RANGE;
> +           }
> +         else
> +           {
> +             set_value_range_to_varying (vr);
> +             return;
> +           }
> +       }
>        else if (is_min
>                /* As a special exception preserve non-null ranges.  */
>                && !(TYPE_UNSIGNED (TREE_TYPE (min))
> --- gcc/testsuite/gcc.dg/pr54676.c.jj   2012-09-24 10:52:48.911691835 +0200
> +++ gcc/testsuite/gcc.dg/pr54676.c      2012-09-24 10:52:30.000000000 +0200
> @@ -0,0 +1,23 @@
> +/* PR tree-optimization/54676 */
> +/* { dg-do compile } */
> +/* { dg-options "-O -fno-tree-ccp -fno-tree-copy-prop -fno-tree-fre -ftree-vrp" } */
> +
> +struct S
> +{
> +  int s:1;
> +};
> +
> +struct S bar (void);
> +
> +int a;
> +
> +void
> +foo (int x)
> +{
> +  struct S s = bar ();
> +  while (!a)
> +    {
> +      int l = 94967295;
> +      a = x || (s.s &= l);
> +    }
> +}
>
>         Jakub

Patch

--- gcc/tree-vrp.c.jj	2012-09-17 11:13:12.000000000 +0200
+++ gcc/tree-vrp.c	2012-09-24 10:06:10.814376659 +0200
@@ -501,8 +501,19 @@  set_and_canonicalize_value_range (value_
      to adjust them.  */
   if (tree_int_cst_lt (max, min))
     {
-      tree one = build_int_cst (TREE_TYPE (min), 1);
-      tree tmp = int_const_binop (PLUS_EXPR, max, one);
+      tree one, tmp;
+
+      /* For one bit precision if max < min, then the swapped
+	 range covers all values, so for VR_RANGE it is varying and
+	 for VR_ANTI_RANGE empty range, so drop to varying as well.  */
+      if (TYPE_PRECISION (TREE_TYPE (min)) == 1)
+	{
+	  set_value_range_to_varying (vr);
+	  return;
+	}
+
+      one = build_int_cst (TREE_TYPE (min), 1);
+      tmp = int_const_binop (PLUS_EXPR, max, one);
       max = int_const_binop (MINUS_EXPR, min, one);
       min = tmp;
 
@@ -531,6 +542,24 @@  set_and_canonicalize_value_range (value_
 	  set_value_range_to_varying (vr);
 	  return;
 	}
+      else if (TYPE_PRECISION (TREE_TYPE (min)) == 1
+	       && !TYPE_UNSIGNED (TREE_TYPE (min))
+	       && (is_min || is_max))
+	{
+	  /* For signed 1-bit precision, one is not in-range and
+	     thus adding/subtracting it would result in overflows.  */
+	  if (operand_equal_p (min, max, 0))
+	    {
+	      min = max = is_min ? vrp_val_max (TREE_TYPE (min))
+				 : vrp_val_min (TREE_TYPE (min));
+	      t = VR_RANGE;
+	    }
+	  else
+	    {
+	      set_value_range_to_varying (vr);
+	      return;
+	    }
+	}
       else if (is_min
 	       /* As a special exception preserve non-null ranges.  */
 	       && !(TYPE_UNSIGNED (TREE_TYPE (min))
--- gcc/testsuite/gcc.dg/pr54676.c.jj	2012-09-24 10:52:48.911691835 +0200
+++ gcc/testsuite/gcc.dg/pr54676.c	2012-09-24 10:52:30.000000000 +0200
@@ -0,0 +1,23 @@ 
+/* PR tree-optimization/54676 */
+/* { dg-do compile } */
+/* { dg-options "-O -fno-tree-ccp -fno-tree-copy-prop -fno-tree-fre -ftree-vrp" } */
+
+struct S
+{
+  int s:1;
+};
+
+struct S bar (void);
+
+int a;
+
+void
+foo (int x)
+{
+  struct S s = bar ();
+  while (!a)
+    {
+      int l = 94967295;
+      a = x || (s.s &= l);
+    }
+}