re PR tree-optimization/80558 (VRP not handling x & -2 well)
authorJakub Jelinek <jakub@redhat.com>
Fri, 5 May 2017 15:43:22 +0000 (17:43 +0200)
committerJakub Jelinek <jakub@gcc.gnu.org>
Fri, 5 May 2017 15:43:22 +0000 (17:43 +0200)
PR tree-optimization/80558
* tree-vrp.c (extract_range_from_binary_expr_1): Optimize
[x, y] op z into [x op, y op z] for op & or | if conditions
are met.

* gcc.dg/tree-ssa/vrp115.c: New test.

From-SVN: r247641

gcc/ChangeLog
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.dg/tree-ssa/vrp115.c [new file with mode: 0644]
gcc/tree-vrp.c

index ff1d499..51471bf 100644 (file)
@@ -1,3 +1,10 @@
+2017-05-05  Jakub Jelinek  <jakub@redhat.com>
+
+       PR tree-optimization/80558
+       * tree-vrp.c (extract_range_from_binary_expr_1): Optimize
+       [x, y] op z into [x op, y op z] for op & or | if conditions
+       are met.
+
 2017-05-05  Andre Vieira  <andre.simoesdiasvieira@arm.com>
            Prakhar Bahuguna  <prakhar.bahuguna@arm.com>
 
index 8606518..7a1b002 100644 (file)
@@ -1,3 +1,8 @@
+2017-05-05  Jakub Jelinek  <jakub@redhat.com>
+
+       PR tree-optimization/80558
+       * gcc.dg/tree-ssa/vrp115.c: New test.
+
 2017-05-05  Andre Vieira  <andre.simoesdiasvieira@arm.com>
            Thomas Preud'homme  <thomas.preudhomme@arm.com>
            Prakhar Bahuguna  <prakhar.bahuguna@arm.com>
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/vrp115.c b/gcc/testsuite/gcc.dg/tree-ssa/vrp115.c
new file mode 100644 (file)
index 0000000..6d1c9c5
--- /dev/null
@@ -0,0 +1,50 @@
+/* PR tree-optimization/80558 */
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-evrp" } */
+/* { dg-final { scan-tree-dump-not "link_error" "evrp" } } */
+
+void link_error (void);
+
+void
+f1 (int x)
+{
+  if (x >= 5 && x <= 19)
+    {
+      x &= -2;
+      if (x < 4 || x > 18)
+       link_error ();
+    }
+}
+
+void
+f2 (int x)
+{
+  if (x >= 5 && x <= 19)
+    {
+      x |= 7;
+      if (x < 7 || x > 23)
+       link_error ();
+    }
+}
+
+void
+f3 (int x)
+{
+  if (x >= -18 && x <= 19)
+    {
+      x |= 7;
+      if (x < -17 || x > 23)
+       link_error ();
+    }
+}
+
+void
+f4 (int x)
+{
+  if (x >= 1603 && x <= 2015)
+    {
+      x &= 496;
+      if (x < 64 || x > 464)
+       link_error ();
+    }
+}
index cb1a3e5..cf50e90 100644 (file)
@@ -2865,8 +2865,59 @@ extract_range_from_binary_expr_1 (value_range *vr,
                                                  &may_be_nonzero1,
                                                  &must_be_nonzero1);
 
+      if (code == BIT_AND_EXPR || code == BIT_IOR_EXPR)
+       {
+         value_range *vr0p = NULL, *vr1p = NULL;
+         if (range_int_cst_singleton_p (&vr1))
+           {
+             vr0p = &vr0;
+             vr1p = &vr1;
+           }
+         else if (range_int_cst_singleton_p (&vr0))
+           {
+             vr0p = &vr1;
+             vr1p = &vr0;
+           }
+         /* For op & or | attempt to optimize:
+            [x, y] op z into [x op z, y op z]
+            if z is a constant which (for op | its bitwise not) has n
+            consecutive least significant bits cleared followed by m 1
+            consecutive bits set immediately above it and either
+            m + n == precision, or (x >> (m + n)) == (y >> (m + n)).
+            The least significant n bits of all the values in the range are
+            cleared or set, the m bits above it are preserved and any bits
+            above these are required to be the same for all values in the
+            range.  */
+         if (vr0p && range_int_cst_p (vr0p))
+           {
+             wide_int w = vr1p->min;
+             int m = 0, n = 0;
+             if (code == BIT_IOR_EXPR)
+               w = ~w;
+             if (wi::eq_p (w, 0))
+               n = TYPE_PRECISION (expr_type);
+             else
+               {
+                 n = wi::ctz (w);
+                 w = ~(w | wi::mask (n, false, w.get_precision ()));
+                 if (wi::eq_p (w, 0))
+                   m = TYPE_PRECISION (expr_type) - n;
+                 else
+                   m = wi::ctz (w) - n;
+               }
+             wide_int mask = wi::mask (m + n, true, w.get_precision ());
+             if (wi::eq_p (mask & vr0p->min, mask & vr0p->max))
+               {
+                 min = int_const_binop (code, vr0p->min, vr1p->min);
+                 max = int_const_binop (code, vr0p->max, vr1p->min);
+               }
+           }
+       }
+
       type = VR_RANGE;
-      if (code == BIT_AND_EXPR)
+      if (min && max)
+       /* Optimized above already.  */;
+      else if (code == BIT_AND_EXPR)
        {
          min = wide_int_to_tree (expr_type,
                                  must_be_nonzero0 & must_be_nonzero1);