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

Submitted by Jakub Jelinek on Sept. 25, 2012, 11:23 a.m.

Details

Message ID 20120925112353.GK1787@tucnak.redhat.com
State New
Headers show

Commit Message

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

Comments

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 hide | download patch | download mbox

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