Fix MINUS_EXPR relations.
authorAndrew MacLeod <amacleod@redhat.com>
Tue, 29 Jun 2021 14:52:58 +0000 (10:52 -0400)
committerAndrew MacLeod <amacleod@redhat.com>
Tue, 29 Jun 2021 18:57:01 +0000 (14:57 -0400)
Flesh out and correct relations for both wrapping and non-wrapping values.

gcc/
PR tree-optimization/101254
* range-op.cc (operator_minus::op1_op2_relation_effect): Check for
wrapping/non-wrapping when setting the result range.

gcc/testsuite
* gcc.dg/pr101254.c: New.

gcc/range-op.cc
gcc/testsuite/gcc.dg/pr101254.c [new file with mode: 0644]

index 29ee9e0..97b9843 100644 (file)
@@ -1314,24 +1314,54 @@ operator_minus::op1_op2_relation_effect (irange &lhs_range, tree type,
   unsigned prec = TYPE_PRECISION (type);
   signop sgn = TYPE_SIGN (type);
 
-  switch (rel)
+  // == and != produce [0,0] and ~[0,0] regardless of wrapping.
+  if (rel == EQ_EXPR)
+    rel_range = int_range<2> (type, wi::zero (prec), wi::zero (prec));
+  else if (rel == NE_EXPR)
+    rel_range = int_range<2> (type, wi::zero (prec), wi::zero (prec),
+                             VR_ANTI_RANGE);
+  else if (TYPE_OVERFLOW_WRAPS (type))
     {
-      // op1 > op2,  op1 - op2 can be restricted to  [1, max]
-      case GT_EXPR:
-       rel_range = int_range<2> (type, wi::one (prec),
-                                 wi::max_value (prec, sgn));
-       break;
-      // op1 >= op2,  op1 - op2 can be restricted to  [0, max]
-      case GE_EXPR:
-       rel_range = int_range<2> (type, wi::zero (prec),
-                                 wi::max_value (prec, sgn));
-       break;
-      // op1 == op2,  op1 - op2 can be restricted to  [0, 0]
-      case EQ_EXPR:
-       rel_range = int_range<2> (type, wi::zero (prec), wi::zero (prec));
-       break;
-      default:
-       return false;
+      switch (rel)
+       {
+         // For wrapping signed values and unsigned, if op1 > op2 or
+         // op1 < op2, then op1 - op2 can be restricted to ~[0, 0].
+         case GT_EXPR:
+         case LT_EXPR:
+             rel_range = int_range<2> (type, wi::zero (prec), wi::zero (prec),
+                                       VR_ANTI_RANGE);
+           break;
+         default:
+           return false;
+       }
+    }
+  else
+    {
+      switch (rel)
+       {
+         // op1 > op2, op1 - op2 can be restricted to [1, +INF]
+         case GT_EXPR:
+           rel_range = int_range<2> (type, wi::one (prec),
+                                     wi::max_value (prec, sgn));
+           break;
+         // op1 >= op2, op1 - op2 can be restricted to [0, +INF]
+         case GE_EXPR:
+           rel_range = int_range<2> (type, wi::zero (prec),
+                                     wi::max_value (prec, sgn));
+           break;
+         // op1 < op2, op1 - op2 can be restricted to [-INF, -1]
+         case LT_EXPR:
+           rel_range = int_range<2> (type, wi::min_value (prec, sgn),
+                                     wi::minus_one (prec));
+           break;
+         // op1 <= op2, op1 - op2 can be restricted to [-INF, 0]
+         case LE_EXPR:
+           rel_range = int_range<2> (type, wi::min_value (prec, sgn),
+                                     wi::zero (prec));
+           break;
+         default:
+           return false;
+       }
     }
   lhs_range.intersect (rel_range);
   return true;
diff --git a/gcc/testsuite/gcc.dg/pr101254.c b/gcc/testsuite/gcc.dg/pr101254.c
new file mode 100644 (file)
index 0000000..b2460ed
--- /dev/null
@@ -0,0 +1,27 @@
+/* PR tree-optimization/101254 */
+/* { dg-do run } */
+/* { dg-options "-O2 -fwrapv" } */
+
+int
+foo (long long imin, long long imax)
+{
+  if (imin > imax)
+    return 0;
+  else if (imax - imin < 0 || (imax - imin) + 1 < 0)
+    return 0;
+  return 1;
+}
+
+int
+main ()
+{
+  long long imax = __LONG_LONG_MAX__;
+  long long imin = -imax - 1; 
+  if (!foo (-10, 10))
+    __builtin_abort ();
+  if (foo (-10, imax))
+    __builtin_abort ();
+  if (foo (imin, imax))
+    __builtin_abort ();
+  return 0;
+}