]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
re PR tree-optimization/30318 (VRP does not create ANTI_RANGEs on overflow)
authorMarc Glisse <marc.glisse@inria.fr>
Fri, 3 Aug 2012 12:21:14 +0000 (14:21 +0200)
committerMarc Glisse <glisse@gcc.gnu.org>
Fri, 3 Aug 2012 12:21:14 +0000 (12:21 +0000)
gcc/
2012-08-03 Marc Glisse <marc.glisse@inria.fr>

PR tree-optimization/30318
* double-int.c (mul_double_wide_with_sign): New function.
(mul_double_with_sign): Call the new function.
* double-int.h (mul_double_wide_with_sign): Declare the new function.
* tree-vrp.c (extract_range_from_binary_expr_1) [MULT_EXPR]:
Handle integer types that wrap on overflow.
(quad_int_cmp): New helper function.
(quad_int_pair_sort): Likewise.

gcc/testsuite/
2012-08-03 Marc Glisse <marc.glisse@inria.fr>

PR tree-optimization/30318
* gcc.dg/tree-ssa/vrp77.c: New testcase.

From-SVN: r190125

gcc/ChangeLog
gcc/double-int.c
gcc/double-int.h
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.dg/tree-ssa/vrp77.c [new file with mode: 0644]
gcc/tree-vrp.c

index 12241aa58c7e348450dec2d696cc7eecc7c793dd..a8923b3885a685f7c8cf9ae8928df1f4766377a6 100644 (file)
@@ -1,3 +1,14 @@
+2012-08-03 Marc Glisse <marc.glisse@inria.fr>
+
+       PR tree-optimization/30318
+       * double-int.c (mul_double_wide_with_sign): New function.
+       (mul_double_with_sign): Call the new function.
+       * double-int.h (mul_double_wide_with_sign): Declare the new function.
+       * tree-vrp.c (extract_range_from_binary_expr_1) [MULT_EXPR]:
+       Handle integer types that wrap on overflow.
+       (quad_int_cmp): New helper function.
+       (quad_int_pair_sort): Likewise.
+
 2012-08-03  Richard Guenther  <rguenther@suse.de>
 
        * tree-vect-loop-manip.c (vect_can_advance_ivs_p): Query
index ae63ead903f59992b709fb338d53f14813709d21..1204dc77aadf226699f8e6301e581abaadc6a1b6 100644 (file)
@@ -134,14 +134,29 @@ mul_double_with_sign (unsigned HOST_WIDE_INT l1, HOST_WIDE_INT h1,
                      unsigned HOST_WIDE_INT l2, HOST_WIDE_INT h2,
                      unsigned HOST_WIDE_INT *lv, HOST_WIDE_INT *hv,
                      bool unsigned_p)
+{
+  unsigned HOST_WIDE_INT toplow;
+  HOST_WIDE_INT tophigh;
+
+  return mul_double_wide_with_sign (l1, h1, l2, h2,
+                                   lv, hv, &toplow, &tophigh,
+                                   unsigned_p);
+}
+
+int
+mul_double_wide_with_sign (unsigned HOST_WIDE_INT l1, HOST_WIDE_INT h1,
+                          unsigned HOST_WIDE_INT l2, HOST_WIDE_INT h2,
+                          unsigned HOST_WIDE_INT *lv, HOST_WIDE_INT *hv,
+                          unsigned HOST_WIDE_INT *lw, HOST_WIDE_INT *hw,
+                          bool unsigned_p)
 {
   HOST_WIDE_INT arg1[4];
   HOST_WIDE_INT arg2[4];
   HOST_WIDE_INT prod[4 * 2];
   unsigned HOST_WIDE_INT carry;
   int i, j, k;
-  unsigned HOST_WIDE_INT toplow, neglow;
-  HOST_WIDE_INT tophigh, neghigh;
+  unsigned HOST_WIDE_INT neglow;
+  HOST_WIDE_INT neghigh;
 
   encode (arg1, l1, h1);
   encode (arg2, l2, h2);
@@ -165,25 +180,25 @@ mul_double_with_sign (unsigned HOST_WIDE_INT l1, HOST_WIDE_INT h1,
     }
 
   decode (prod, lv, hv);
-  decode (prod + 4, &toplow, &tophigh);
+  decode (prod + 4, lw, hw);
 
   /* Unsigned overflow is immediate.  */
   if (unsigned_p)
-    return (toplow | tophigh) != 0;
+    return (*lw | *hw) != 0;
 
   /* Check for signed overflow by calculating the signed representation of the
      top half of the result; it should agree with the low half's sign bit.  */
   if (h1 < 0)
     {
       neg_double (l2, h2, &neglow, &neghigh);
-      add_double (neglow, neghigh, toplow, tophigh, &toplow, &tophigh);
+      add_double (neglow, neghigh, *lw, *hw, lw, hw);
     }
   if (h2 < 0)
     {
       neg_double (l1, h1, &neglow, &neghigh);
-      add_double (neglow, neghigh, toplow, tophigh, &toplow, &tophigh);
+      add_double (neglow, neghigh, *lw, *hw, lw, hw);
     }
-  return (*hv < 0 ? ~(toplow & tophigh) : toplow | tophigh) != 0;
+  return (*hv < 0 ? ~(*lw & *hw) : *lw | *hw) != 0;
 }
 
 /* Shift the doubleword integer in L1, H1 right by COUNT places
index eab9c3c14a642e7dbe8f7e7a36f6ad8b1862ba23..4c4c1b3ecbd770847b162da4f34cebc5c2ff5d19 100644 (file)
@@ -307,6 +307,11 @@ extern int mul_double_with_sign (unsigned HOST_WIDE_INT, HOST_WIDE_INT,
                                 unsigned HOST_WIDE_INT, HOST_WIDE_INT,
                                 unsigned HOST_WIDE_INT *, HOST_WIDE_INT *,
                                 bool);
+extern int mul_double_wide_with_sign (unsigned HOST_WIDE_INT, HOST_WIDE_INT,
+                                     unsigned HOST_WIDE_INT, HOST_WIDE_INT,
+                                     unsigned HOST_WIDE_INT *, HOST_WIDE_INT *,
+                                     unsigned HOST_WIDE_INT *, HOST_WIDE_INT *,
+                                     bool);
 #define mul_double(l1,h1,l2,h2,lv,hv) \
   mul_double_with_sign (l1, h1, l2, h2, lv, hv, false)
 extern void lshift_double (unsigned HOST_WIDE_INT, HOST_WIDE_INT,
index cde4e40bc6c67a1b3aae848f5b18067b7b4eab1d..b7486f97c2828c6123ee8c3b053ee27b1c78ed94 100644 (file)
@@ -1,3 +1,8 @@
+2012-08-03 Marc Glisse <marc.glisse@inria.fr>
+
+       PR tree-optimization/30318
+       * gcc.dg/tree-ssa/vrp77.c: New testcase.
+
 2012-08-03  Marc Glisse  <marc.glisse@inria.fr>
 
        * g++.dg/ext/vector17.C: New testcase.
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/vrp77.c b/gcc/testsuite/gcc.dg/tree-ssa/vrp77.c
new file mode 100644 (file)
index 0000000..c0a8a86
--- /dev/null
@@ -0,0 +1,47 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-optimized" } */
+
+#ifdef __SIZEOF_INT128__
+#define T __int128
+#else
+#define T long long
+#endif
+
+extern void impossible (void);
+
+void f(T x)
+{
+  unsigned T y;
+  unsigned T z;
+  if (x < -7)
+    return;
+  if (x > 2)
+    return;
+  y = x;
+  z = y * y;
+  if (z == 666)
+    impossible ();
+}
+
+void g(unsigned T x)
+{
+  unsigned T y;
+  unsigned T z;
+  unsigned T m = -1;
+  m = m / 2;
+  if (x < m-2)
+    return;
+  if (x > m-1)
+    return;
+  y = x;
+  z = y * y;
+  /* The product (ignoring it is a square) has only 3 possible values:
+     4, 9 and 2^127+6.  At least one of the values 7, 666 and -666 is
+     known to be impossible.  7 is the most logical in the current
+     implementation.  */
+  if (z == 7)
+    impossible ();
+}
+
+/* { dg-final { scan-tree-dump-not "impossible" "optimized" } } */
+/* { dg-final { cleanup-tree-dump "optimized" } } */
index 9a18b222db2ac95a3a68f12d732cd53a45e4893e..0d41493a6b01c6196ad73f27f84d29e568c138c6 100644 (file)
@@ -2188,6 +2188,28 @@ extract_range_from_multiplicative_op_1 (value_range_t *vr,
     set_value_range (vr, type, min, max, NULL);
 }
 
+/* Some quadruple precision helpers.  */
+static int
+quad_int_cmp (double_int l0, double_int h0,
+             double_int l1, double_int h1, bool uns)
+{
+  int c = double_int_cmp (h0, h1, uns);
+  if (c != 0) return c;
+  return double_int_ucmp (l0, l1);
+}
+
+static void
+quad_int_pair_sort (double_int *l0, double_int *h0,
+                   double_int *l1, double_int *h1, bool uns)
+{
+  if (quad_int_cmp (*l0, *h0, *l1, *h1, uns) > 0)
+    {
+      double_int tmp;
+      tmp = *l0; *l0 = *l1; *l1 = tmp;
+      tmp = *h0; *h0 = *h1; *h1 = tmp;
+    }
+}
+
 /* Extract range information from a binary operation CODE based on
    the ranges of each of its operands, *VR0 and *VR1 with resulting
    type EXPR_TYPE.  The resulting range is stored in *VR.  */
@@ -2569,6 +2591,123 @@ extract_range_from_binary_expr_1 (value_range_t *vr,
     }
   else if (code == MULT_EXPR)
     {
+      /* Fancy code so that with unsigned, [-3,-1]*[-3,-1] does not
+        drop to varying.  */
+      if (range_int_cst_p (&vr0)
+         && range_int_cst_p (&vr1)
+         && TYPE_OVERFLOW_WRAPS (expr_type))
+       {
+         double_int min0, max0, min1, max1, sizem1, size;
+         double_int prod0l, prod0h, prod1l, prod1h,
+                    prod2l, prod2h, prod3l, prod3h;
+         bool uns0, uns1, uns;
+
+         sizem1 = double_int_max_value (TYPE_PRECISION (expr_type), true);
+         size = double_int_add (sizem1, double_int_one);
+
+         min0 = tree_to_double_int (vr0.min);
+         max0 = tree_to_double_int (vr0.max);
+         min1 = tree_to_double_int (vr1.min);
+         max1 = tree_to_double_int (vr1.max);
+
+         uns0 = TYPE_UNSIGNED (expr_type);
+         uns1 = uns0;
+
+         /* Canonicalize the intervals.  */
+         if (TYPE_UNSIGNED (expr_type))
+           {
+             double_int min2 = double_int_sub (size, min0);
+             if (double_int_cmp (min2, max0, true) < 0)
+               {
+                 min0 = double_int_neg (min2);
+                 max0 = double_int_sub (max0, size);
+                 uns0 = false;
+               }
+
+             min2 = double_int_sub (size, min1);
+             if (double_int_cmp (min2, max1, true) < 0)
+               {
+                 min1 = double_int_neg (min2);
+                 max1 = double_int_sub (max1, size);
+                 uns1 = false;
+               }
+           }
+         uns = uns0 & uns1;
+
+         mul_double_wide_with_sign (min0.low, min0.high,
+                                    min1.low, min1.high,
+                                    &prod0l.low, &prod0l.high,
+                                    &prod0h.low, &prod0h.high, true);
+         if (!uns0 && double_int_negative_p (min0))
+           prod0h = double_int_sub (prod0h, min1);
+         if (!uns1 && double_int_negative_p (min1))
+           prod0h = double_int_sub (prod0h, min0);
+
+         mul_double_wide_with_sign (min0.low, min0.high,
+                                    max1.low, max1.high,
+                                    &prod1l.low, &prod1l.high,
+                                    &prod1h.low, &prod1h.high, true);
+         if (!uns0 && double_int_negative_p (min0))
+           prod1h = double_int_sub (prod1h, max1);
+         if (!uns1 && double_int_negative_p (max1))
+           prod1h = double_int_sub (prod1h, min0);
+
+         mul_double_wide_with_sign (max0.low, max0.high,
+                                    min1.low, min1.high,
+                                    &prod2l.low, &prod2l.high,
+                                    &prod2h.low, &prod2h.high, true);
+         if (!uns0 && double_int_negative_p (max0))
+           prod2h = double_int_sub (prod2h, min1);
+         if (!uns1 && double_int_negative_p (min1))
+           prod2h = double_int_sub (prod2h, max0);
+
+         mul_double_wide_with_sign (max0.low, max0.high,
+                                    max1.low, max1.high,
+                                    &prod3l.low, &prod3l.high,
+                                    &prod3h.low, &prod3h.high, true);
+         if (!uns0 && double_int_negative_p (max0))
+           prod3h = double_int_sub (prod3h, max1);
+         if (!uns1 && double_int_negative_p (max1))
+           prod3h = double_int_sub (prod3h, max0);
+
+         /* Sort the 4 products.  */
+         quad_int_pair_sort (&prod0l, &prod0h, &prod3l, &prod3h, uns);
+         quad_int_pair_sort (&prod1l, &prod1h, &prod2l, &prod2h, uns);
+         quad_int_pair_sort (&prod0l, &prod0h, &prod1l, &prod1h, uns);
+         quad_int_pair_sort (&prod2l, &prod2h, &prod3l, &prod3h, uns);
+
+         /* Max - min.  */
+         if (double_int_zero_p (prod0l))
+           {
+             prod1l = double_int_zero;
+             prod1h = double_int_neg (prod0h);
+           }
+         else
+           {
+             prod1l = double_int_neg (prod0l);
+             prod1h = double_int_not (prod0h);
+           }
+         prod2l = double_int_add (prod3l, prod1l);
+         prod2h = double_int_add (prod3h, prod1h);
+         if (double_int_ucmp (prod2l, prod3l) < 0)
+           prod2h = double_int_add (prod2h, double_int_one); /* carry */
+
+         if (!double_int_zero_p (prod2h)
+             || double_int_cmp (prod2l, sizem1, true) >= 0)
+           {
+             /* the range covers all values.  */
+             set_value_range_to_varying (vr);
+             return;
+           }
+
+         /* The following should handle the wrapping and selecting
+            VR_ANTI_RANGE for us.  */
+         min = double_int_to_tree (expr_type, prod0l);
+         max = double_int_to_tree (expr_type, prod3l);
+         set_and_canonicalize_value_range (vr, VR_RANGE, min, max, NULL);
+         return;
+       }
+
       /* If we have an unsigned MULT_EXPR with two VR_ANTI_RANGEs,
         drop to VR_VARYING.  It would take more effort to compute a
         precise range for such a case.  For example, if we have