OSDN Git Service

PR tree-optimization/28632
authorjakub <jakub@138bc75d-0d04-0410-961f-82ee72b054a4>
Fri, 9 Jul 2010 19:40:03 +0000 (19:40 +0000)
committerjakub <jakub@138bc75d-0d04-0410-961f-82ee72b054a4>
Fri, 9 Jul 2010 19:40:03 +0000 (19:40 +0000)
* tree-vrp.c (zero_nonzero_bits_from_vr): New function.
(extract_range_from_binary_expr): Further optimize
BIT_AND_EXPR and BIT_IOR_EXPR.

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

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@162009 138bc75d-0d04-0410-961f-82ee72b054a4

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

index 9c04a7d..5ed0c14 100644 (file)
@@ -1,3 +1,12 @@
+2010-07-09  Jakub Jelinek  <jakub@redhat.com>
+           Denys Vlasenko  <dvlasenk@redhat.com>
+           Bernhard Reutner-Fischer  <aldot@gcc.gnu.org>
+
+       PR tree-optimization/28632
+       * tree-vrp.c (zero_nonzero_bits_from_vr): New function.
+       (extract_range_from_binary_expr): Further optimize
+       BIT_AND_EXPR and BIT_IOR_EXPR.
+
 2010-07-09  Sebastian Pop  <sebastian.pop@amd.com>
 
        * tree-if-conv.c (fold_or_predicates): New.
index 483e9ca..13363df 100644 (file)
@@ -1,3 +1,11 @@
+2010-07-09  Jakub Jelinek  <jakub@redhat.com>
+           Denys Vlasenko  <dvlasenk@redhat.com>
+           Bernhard Reutner-Fischer  <aldot@gcc.gnu.org>
+
+       PR tree-optimization/28632
+       * gcc.dg/tree-ssa/vrp51.c: New test.
+       * gcc.dg/tree-ssa/vrp52.c: New test.
+
 2010-07-09  Jason Merrill  <jason@redhat.com>
 
        * g++.dg/abi/covariant6.C: New.
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/vrp51.c b/gcc/testsuite/gcc.dg/tree-ssa/vrp51.c
new file mode 100644 (file)
index 0000000..66aa5ed
--- /dev/null
@@ -0,0 +1,58 @@
+/* PR tree-optimization/28632 */
+/* { dg-do compile } */
+/* { dg-options "-O2 -ftree-vrp" } */
+
+void
+v4 (unsigned a, unsigned b)
+{
+  if (a < 0x1000) return;
+  if (a > 0x1000) return;
+  if (b < 0x0110) return;
+  /* constant true.  */
+  if (!__builtin_constant_p ((a|b) >= 0x01000))
+    __asm__("bug.always.true");
+  /* VRP must not think that this is constant.  */
+  if (__builtin_constant_p ((a|b) >= 0x10000))
+    __asm__("bug.not.always.true");
+}
+
+void
+u4 (unsigned n)
+{
+  if (n > 0x10111) return;
+  if (n < 0x10101) return;
+  /* always true.  */
+  if (!__builtin_constant_p (n & 0x00100))
+    __asm__("bug.always.true");
+  /* VRP must not think that this is constant true.  */
+  if (__builtin_constant_p (n & 0x00001))
+    __asm__("bug.not.always.true");
+  /* Out of range, always evaluates to constant false.  */
+  if (!__builtin_constant_p (n & 0x01000))
+    __asm__("bug.always.false");
+}
+
+void
+u5 (unsigned n)
+{
+  struct s {unsigned exp:8;} x;
+  x.exp = n;
+  if (__builtin_constant_p(((n + 1) & 255) > 1))
+    __asm__("bug.not.always.true");
+}
+
+void
+v5 (int a, int b)
+{
+  if (a < 0x1000) return;
+  if (a > 0x1000) return;
+  if (b < 0x0110) return;
+  /* constant true.  */
+  if (!__builtin_constant_p ((a|b) >= 0x01000))
+    __asm__("bug.always.true");
+  /* VRP must not think that this is always true.  */
+  if (__builtin_constant_p ((a|b) >= 0x10000))
+    __asm__("bug.not.always.true");
+}
+
+/* { dg-final { scan-assembler-not "bug\." } } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/vrp52.c b/gcc/testsuite/gcc.dg/tree-ssa/vrp52.c
new file mode 100644 (file)
index 0000000..7d530e2
--- /dev/null
@@ -0,0 +1,16 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-vrp1" } */
+
+int
+foo (unsigned int i, unsigned int j)
+{
+  i &= 15;
+  j &= 15;
+  i += 1024;
+  j += 2048;
+  i |= j;
+  return i >= 1024 + 2048;
+}
+
+/* { dg-final { scan-tree-dump "Folding predicate i_\[^\n\r\]* to 1" "vrp1" } } */
+/* { dg-final { cleanup-tree-dump "vrp1" } } */
index 2aac9ac..c855511 100644 (file)
@@ -2064,6 +2064,60 @@ vrp_int_const_binop (enum tree_code code, tree val1, tree val2)
 }
 
 
+/* For range VR compute two double_int bitmasks.  In *MAY_BE_NONZERO
+   bitmask if some bit is unset, it means for all numbers in the range
+   the bit is 0, otherwise it might be 0 or 1.  In *MUST_BE_NONZERO
+   bitmask if some bit is set, it means for all numbers in the range
+   the bit is 1, otherwise it might be 0 or 1.  */
+
+static bool
+zero_nonzero_bits_from_vr (value_range_t *vr, double_int *may_be_nonzero,
+                          double_int *must_be_nonzero)
+{
+  if (range_int_cst_p (vr))
+    {
+      if (range_int_cst_singleton_p (vr))
+       {
+         *may_be_nonzero = tree_to_double_int (vr->min);
+         *must_be_nonzero = *may_be_nonzero;
+         return true;
+       }
+      if (tree_int_cst_sgn (vr->min) >= 0)
+       {
+         double_int dmin = tree_to_double_int (vr->min);
+         double_int dmax = tree_to_double_int (vr->max);
+         double_int xor_mask = double_int_xor (dmin, dmax);
+         *may_be_nonzero = double_int_ior (dmin, dmax);
+         *must_be_nonzero = double_int_and (dmin, dmax);
+         if (xor_mask.high != 0)
+           {
+             unsigned HOST_WIDE_INT mask
+               = ((unsigned HOST_WIDE_INT) 1
+                  << floor_log2 (xor_mask.high)) - 1;
+             may_be_nonzero->low = ALL_ONES;
+             may_be_nonzero->high |= mask;
+             must_be_nonzero->low = 0;
+             must_be_nonzero->high &= ~mask;
+           }
+         else if (xor_mask.low != 0)
+           {
+             unsigned HOST_WIDE_INT mask
+               = ((unsigned HOST_WIDE_INT) 1
+                  << floor_log2 (xor_mask.low)) - 1;
+             may_be_nonzero->low |= mask;
+             must_be_nonzero->low &= ~mask;
+           }
+         return true;
+       }
+    }
+  may_be_nonzero->low = ALL_ONES;
+  may_be_nonzero->high = ALL_ONES;
+  must_be_nonzero->low = 0;
+  must_be_nonzero->high = 0;
+  return false;
+}
+
+
 /* Extract range information from a binary expression EXPR based on
    the ranges of each of its operands and the expression code.  */
 
@@ -2569,120 +2623,79 @@ extract_range_from_binary_expr (value_range_t *vr,
       min = vrp_int_const_binop (code, vr0.min, vr1.max);
       max = vrp_int_const_binop (code, vr0.max, vr1.min);
     }
-  else if (code == BIT_AND_EXPR)
+  else if (code == BIT_AND_EXPR || code == BIT_IOR_EXPR)
     {
       bool vr0_int_cst_singleton_p, vr1_int_cst_singleton_p;
+      bool int_cst_range0, int_cst_range1;
+      double_int may_be_nonzero0, may_be_nonzero1;
+      double_int must_be_nonzero0, must_be_nonzero1;
 
       vr0_int_cst_singleton_p = range_int_cst_singleton_p (&vr0);
       vr1_int_cst_singleton_p = range_int_cst_singleton_p (&vr1);
+      int_cst_range0 = zero_nonzero_bits_from_vr (&vr0, &may_be_nonzero0,
+                                                 &must_be_nonzero0);
+      int_cst_range1 = zero_nonzero_bits_from_vr (&vr1, &may_be_nonzero1,
+                                                 &must_be_nonzero1);
 
+      type = VR_RANGE;
       if (vr0_int_cst_singleton_p && vr1_int_cst_singleton_p)
        min = max = int_const_binop (code, vr0.max, vr1.max, 0);
-      else if (range_int_cst_p (&vr0)
-              && range_int_cst_p (&vr1)
-              && tree_int_cst_sgn (vr0.min) >= 0
-              && tree_int_cst_sgn (vr1.min) >= 0)
-       {
-         double_int vr0_mask = tree_to_double_int (vr0.min);
-         double_int vr1_mask = tree_to_double_int (vr1.min);
-         double_int maxd, diff;
-         tree mask;
-
-         min = build_int_cst (expr_type, 0);
-         /* Compute non-zero bits mask from both ranges.  */
-         if (!vr0_int_cst_singleton_p)
-           {
-             maxd = tree_to_double_int (vr0.max);
-             diff = double_int_sub (maxd, vr0_mask);
-             if (diff.high)
-               {
-                 diff.low = ~(unsigned HOST_WIDE_INT)0;
-                 diff.high = ((HOST_WIDE_INT) 2
-                              << floor_log2 (diff.high)) - 1;
-               }
-             else
-               diff.low = ((HOST_WIDE_INT) 2 << floor_log2 (diff.low)) - 1;
-             vr0_mask = double_int_ior (vr0_mask,
-                                        double_int_ior (maxd, diff));
-           }
-         if (!vr1_int_cst_singleton_p)
-           {
-             maxd = tree_to_double_int (vr1.max);
-             diff = double_int_sub (maxd, vr1_mask);
-             if (diff.high)
-               {
-                 diff.low = ~(unsigned HOST_WIDE_INT)0;
-                 diff.high = ((HOST_WIDE_INT) 2
-                              << floor_log2 (diff.high)) - 1;
-               }
-             else
-               diff.low = ((HOST_WIDE_INT) 2 << floor_log2 (diff.low)) - 1;
-             vr1_mask = double_int_ior (vr1_mask,
-                                        double_int_ior (maxd, diff));
-           }
-         mask = double_int_to_tree (expr_type,
-                                    double_int_and (vr0_mask, vr1_mask));
-         max = vr0.max;
-         if (tree_int_cst_lt (vr1.max, max))
-           max = vr1.max;
-         if (!TREE_OVERFLOW (mask)
-             && tree_int_cst_lt (mask, max)
-             && tree_int_cst_sgn (mask) >= 0)
-           max = mask;
-       }
-      else if (vr0_int_cst_singleton_p
-              && tree_int_cst_sgn (vr0.max) >= 0)
-       {
-         min = build_int_cst (expr_type, 0);
-         max = vr0.max;
-       }
-      else if (vr1_int_cst_singleton_p
-              && tree_int_cst_sgn (vr1.max) >= 0)
-       {
-         type = VR_RANGE;
-         min = build_int_cst (expr_type, 0);
-         max = vr1.max;
-       }
-      else
+      else if (!int_cst_range0 && !int_cst_range1)
        {
          set_value_range_to_varying (vr);
          return;
        }
-    }
-  else if (code == BIT_IOR_EXPR)
-    {
-      if (range_int_cst_p (&vr0)
-         && range_int_cst_p (&vr1)
-         && tree_int_cst_sgn (vr0.min) >= 0
-         && tree_int_cst_sgn (vr1.min) >= 0)
+      else if (code == BIT_AND_EXPR)
        {
-         double_int vr0_max = tree_to_double_int (vr0.max);
-         double_int vr1_max = tree_to_double_int (vr1.max);
-         double_int ior_max;
-
-         /* Set all bits to the right of the most significant one to 1.
-            For example, [0, 4] | [4, 4] = [4, 7]. */
-         ior_max.low = vr0_max.low | vr1_max.low;
-         ior_max.high = vr0_max.high | vr1_max.high;
-         if (ior_max.high != 0)
+         min = double_int_to_tree (expr_type,
+                                   double_int_and (must_be_nonzero0,
+                                                   must_be_nonzero1));
+         max = double_int_to_tree (expr_type,
+                                   double_int_and (may_be_nonzero0,
+                                                   may_be_nonzero1));
+         if (TREE_OVERFLOW (min) || tree_int_cst_sgn (min) < 0)
+           min = NULL_TREE;
+         if (TREE_OVERFLOW (max) || tree_int_cst_sgn (max) < 0)
+           max = NULL_TREE;
+         if (int_cst_range0 && tree_int_cst_sgn (vr0.min) >= 0)
+           {
+             if (min == NULL_TREE)
+               min = build_int_cst (expr_type, 0);
+             if (max == NULL_TREE || tree_int_cst_lt (vr0.max, max))
+               max = vr0.max;
+           }
+         if (int_cst_range1 && tree_int_cst_sgn (vr1.min) >= 0)
            {
-             ior_max.low = ~(unsigned HOST_WIDE_INT)0u;
-             ior_max.high |= ((HOST_WIDE_INT) 1
-                              << floor_log2 (ior_max.high)) - 1;
+             if (min == NULL_TREE)
+               min = build_int_cst (expr_type, 0);
+             if (max == NULL_TREE || tree_int_cst_lt (vr1.max, max))
+               max = vr1.max;
            }
-         else if (ior_max.low != 0)
-           ior_max.low |= ((unsigned HOST_WIDE_INT) 1u
-                           << floor_log2 (ior_max.low)) - 1;
-
-         /* Both of these endpoints are conservative.  */
-          min = vrp_int_const_binop (MAX_EXPR, vr0.min, vr1.min);
-          max = double_int_to_tree (expr_type, ior_max);
        }
-      else
+      else if (!int_cst_range0
+              || !int_cst_range1
+              || tree_int_cst_sgn (vr0.min) < 0
+              || tree_int_cst_sgn (vr1.min) < 0)
        {
          set_value_range_to_varying (vr);
          return;
        }
+      else
+       {
+         min = double_int_to_tree (expr_type,
+                                   double_int_ior (must_be_nonzero0,
+                                                   must_be_nonzero1));
+         max = double_int_to_tree (expr_type,
+                                   double_int_ior (may_be_nonzero0,
+                                                   may_be_nonzero1));
+         if (TREE_OVERFLOW (min) || tree_int_cst_sgn (min) < 0)
+           min = vr0.min;
+         else
+           min = vrp_int_const_binop (MAX_EXPR, min, vr0.min);
+         if (TREE_OVERFLOW (max) || tree_int_cst_sgn (max) < 0)
+           max = NULL_TREE;
+         min = vrp_int_const_binop (MAX_EXPR, min, vr1.min);
+       }
     }
   else
     gcc_unreachable ();