https://gcc.gnu.org/g:42a22b801d4ad654e420495fafc4d29d113f00eb

commit r15-7571-g42a22b801d4ad654e420495fafc4d29d113f00eb
Author: Jakub Jelinek <ja...@redhat.com>
Date:   Sat Feb 15 16:45:21 2025 -0700

    [PR tree-optimization/98028] Use relationship between operands to simplify 
SUB_OVERFLOW
    
    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.
    
    This is Jakub's version of the vr-values.cc fix rather than Jeff's.
    
            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:
---
 gcc/testsuite/gcc.dg/tree-ssa/pr98028.c | 26 ++++++++++++++++++++++++++
 gcc/vr-values.cc                        | 33 +++++++++++++++++++++++++++++++++
 2 files changed, 59 insertions(+)

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 000000000000..4e371b692354
--- /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 ed590138fe8f..6603d90c392c 100644
--- a/gcc/vr-values.cc
+++ b/gcc/vr-values.cc
@@ -85,6 +85,20 @@ check_for_binary_op_overflow (range_query *query,
                              enum tree_code subcode, tree type,
                              tree op0, tree op1, bool *ovf, gimple *s = NULL)
 {
+  relation_kind rel = VREL_VARYING;
+  /* For subtraction see if relations could simplify it.  */
+  if (s
+      && subcode == MINUS_EXPR
+      && types_compatible_p (TREE_TYPE (op0), TREE_TYPE (op1)))
+    {
+      rel = query->relation().query (s, op0, op1);
+      /* The result of the infinite precision subtraction of
+        the same values will be always 0.  That will fit into any result
+        type.  */
+      if (rel == VREL_EQ)
+        return true;
+    }
+
   int_range_max vr0, vr1;
   if (!query->range_of_expr (vr0, op0, s) || vr0.undefined_p ())
     vr0.set_varying (TREE_TYPE (op0));
@@ -96,6 +110,25 @@ check_for_binary_op_overflow (range_query *query,
   tree vr1min = wide_int_to_tree (TREE_TYPE (op1), vr1.lower_bound ());
   tree vr1max = wide_int_to_tree (TREE_TYPE (op1), vr1.upper_bound ());
 
+  /* If op1 is not negative, op0 - op1 in infinite precision for op0 >= op1
+     will be always in [0, op0] and so if vr0max - vr1min fits into type,
+     there won't be any overflow.  */
+  if ((rel == VREL_GT || rel == VREL_GE)
+      && tree_int_cst_sgn (vr1min) >= 0
+      && !arith_overflowed_p (MINUS_EXPR, type, vr0max, vr1min))
+    return true;
+
+  /* If op1 is not negative, op0 - op1 in infinite precision for op0 < op1
+     will be always in [-inf, -1] and so will always overflow if type is
+     unsigned.  */
+  if (rel == VREL_LT
+      && tree_int_cst_sgn (vr1min) >= 0
+      && TYPE_UNSIGNED (type))
+    {
+      *ovf = true;
+      return true;
+    }
+
   *ovf = arith_overflowed_p (subcode, type, vr0min,
                             subcode == MINUS_EXPR ? vr1max : vr1min);
   if (arith_overflowed_p (subcode, type, vr0max,

Reply via email to