So this is a fairly old regression, but with all the ranger work that's been done, it's become easy to resolve.

The basic idea here is to use known relationships between two operands of a SUB_OVERFLOW IFN to statically compute the overflow state and ultimately allow turning the IFN into simple arithmetic (or for the tests in this BZ elide the arithmetic entirely).

The regression example is when the two inputs are known equal. In that case the subtraction will never overflow. But there's a few other cases we can handle as well.

a == b -> never overflows
a > b  -> never overflows when A and B are unsigned
a >= b -> never overflows when A and B are unsigned
a < b  -> always overflows when A and B are unsigned

Bootstrapped and regression tested on x86, and regression tested on the usual cross platforms.

OK for the trunk?

Jeff
        PR tree-optimization/98028
gcc/
        * vr-values.cc (check_for_binary_op_overflow): Try to use a known
        relationship betwen op0/op1 to statically determine overflow state.

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

diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr98028.c 
b/gcc/testsuite/gcc.dg/tree-ssa/pr98028.c
new file mode 100644
index 00000000000..4e371b69235
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/pr98028.c
@@ -0,0 +1,26 @@
+/* { dg-options "-O2 -fdump-tree-optimized" } */
+
+unsigned f1(unsigned i, unsigned j) {
+  if (j != i) __builtin_unreachable();
+  return __builtin_sub_overflow_p(i, j, (unsigned)0);
+}
+
+unsigned f2(unsigned i, unsigned j) {
+  if (j > i) __builtin_unreachable();
+  return __builtin_sub_overflow_p(i, j, (unsigned)0);
+}
+
+unsigned f3(unsigned i, unsigned j) {
+  if (j >= i) __builtin_unreachable();
+  return __builtin_sub_overflow_p(i, j, (unsigned)0);
+}
+
+unsigned f4(unsigned i, unsigned j) {
+  if (j <= i) __builtin_unreachable();
+  return __builtin_sub_overflow_p(i, j, (unsigned)0);
+}
+
+/* { dg-final { scan-tree-dump-times "return 0" 3 optimized } } */
+/* { dg-final { scan-tree-dump-times "return 1" 1 optimized } } */
+/* { dg-final { scan-tree-dump-not "SUB_OVERFLOW" optimized } } */
+/* { dg-final { scan-tree-dump-not "IMAGPART_EXPR" optimized } } */
diff --git a/gcc/vr-values.cc b/gcc/vr-values.cc
index ed590138fe8..29568e27c38 100644
--- a/gcc/vr-values.cc
+++ b/gcc/vr-values.cc
@@ -85,6 +85,33 @@ check_for_binary_op_overflow (range_query *query,
                              enum tree_code subcode, tree type,
                              tree op0, tree op1, bool *ovf, gimple *s = NULL)
 {
+  /* For MINUS_EXPR, we may know based the relationship
+     (if any) between op0 and op1.  */
+  if (subcode == MINUS_EXPR)
+    {
+      relation_kind rel = query->relation().query (s, op0, op1);
+
+      /* If the operands are equal, then the result will be zero
+        and there is never an overflow.  */
+      if (rel == VREL_EQ)
+       return true;
+
+      /* If op0 and op1 are unsigned types, we still have a chance.  */
+      if (TYPE_UNSIGNED (TREE_TYPE (op0)) && TYPE_UNSIGNED (TREE_TYPE (op1)))
+       {
+         /* op0 > op1 or op0 >= op1 never overflows.  */
+         if (rel == VREL_GT || rel == VREL_GE)
+           return true;
+
+         /* And op0 < op1 always overflows.  */
+         if (rel == VREL_LT)
+           {
+             *ovf = true;
+             return true;
+           }
+       }
+    }
+       
   int_range_max vr0, vr1;
   if (!query->range_of_expr (vr0, op0, s) || vr0.undefined_p ())
     vr0.set_varying (TREE_TYPE (op0));

Reply via email to