https://gcc.gnu.org/g:bddea69ee406a0f68aed8f42ea7efba2d8b5883c

commit r17-4663-gbddea69ee406a0f68aed8f42ea7efba2d8b5883c
Author: Aldy Hernandez <[email protected]>
Date:   Sat Aug 29 20:16:11 2026 +0000

    range-ops: derive operand equality from a zero MINUS_EXPR
    
    A conditional such as:
    
      d_5 = a_3 - b_4;
      if (d_5 == 0)
    
    implies a_3 == b_4 on the true edge regardless of overflow behavior,
    but no relation was recorded because operator_minus lacks
    op1_op2_relation and register_outgoing_edges only derives relations
    from boolean exports.  Add the former and relax the latter.
    
    match.pd already folds this:
    
      /* Transform comparisons of the form X - Y CMP 0 to X CMP Y.  */
      (cmp (sub@2 @0 @1) integer_zerop)
       (if (single_use (@2)) (cmp @0 @1))
    
    but only for a single-use difference.
    
    Measured with perf over a corpus of .ii files from a stage1 bootstrap
    compile time is +0.13% overall.  VRP is +0.8%, DOM +1.7% and the
    threader +3.4%.  The cost is register_outgoing_edges itself which is
    +36%.
    
    Tested on ppc64le Linux.
    
            PR tree-optimization/127485
    
    gcc/ChangeLog:
    
            * range-op-mixed.h (class operator_minus): Add op1_op2_relation.
            * range-op.cc (operator_minus::op1_op2_relation): New.
            * gimple-range-fold.cc (fur_source::register_outgoing_edges):
            Derive relations from any integral export, not just booleans.
    
    gcc/testsuite/ChangeLog:
    
            * gcc.dg/tree-ssa/vrp-minus-relation-1.c: New test.

Diff:
---
 gcc/gimple-range-fold.cc                             |  5 ++++-
 gcc/range-op-mixed.h                                 |  3 +++
 gcc/range-op.cc                                      | 19 +++++++++++++++++++
 gcc/testsuite/gcc.dg/tree-ssa/vrp-minus-relation-1.c | 17 +++++++++++++++++
 4 files changed, 43 insertions(+), 1 deletion(-)

diff --git a/gcc/gimple-range-fold.cc b/gcc/gimple-range-fold.cc
index abe3ade2960d..a143c19647af 100644
--- a/gcc/gimple-range-fold.cc
+++ b/gcc/gimple-range-fold.cc
@@ -1751,9 +1751,12 @@ fur_source::register_outgoing_edges (gcond *s, irange 
&lhs_range,
   // leading to the condition such as:
   // c_2 = a_4 < b_7
   // if (c_2)
+  // as well as relations implied by a known result, such as:
+  // c_2 = a_4 - b_7
+  // if (c_2 == 0)
   FOR_EACH_GORI_EXPORT_NAME (gori_ssa (), bb, name)
     {
-      if (TREE_CODE (TREE_TYPE (name)) != BOOLEAN_TYPE)
+      if (!INTEGRAL_TYPE_P (TREE_TYPE (name)))
        continue;
       gimple *stmt = SSA_NAME_DEF_STMT (name);
       gimple_range_op_handler handler (stmt);
diff --git a/gcc/range-op-mixed.h b/gcc/range-op-mixed.h
index 0e97fb11688c..b084c3edeab5 100644
--- a/gcc/range-op-mixed.h
+++ b/gcc/range-op-mixed.h
@@ -648,6 +648,7 @@ public:
   using range_operator::op1_range;
   using range_operator::op2_range;
   using range_operator::lhs_op1_relation;
+  using range_operator::op1_op2_relation;
   using range_operator::op1_op2_relation_effect;
   using range_operator::update_bitmask;
   bool op1_range (irange &r, tree type,
@@ -668,6 +669,8 @@ public:
   relation_kind lhs_op1_relation (const irange &lhs,
                                  const irange &op1, const irange &op2,
                                  relation_kind rel) const final override;
+  relation_kind op1_op2_relation (const irange &lhs, const irange &,
+                                 const irange &) const final override;
   bool op1_op2_relation_effect (irange &lhs_range, tree type,
                                const irange &op1_range,
                                const irange &op2_range,
diff --git a/gcc/range-op.cc b/gcc/range-op.cc
index 350548951f45..07318bca71ee 100644
--- a/gcc/range-op.cc
+++ b/gcc/range-op.cc
@@ -2102,6 +2102,25 @@ minus_op1_op2_relation_effect (irange &lhs_range, tree 
type,
   return true;
 }
 
+// Check if the LHS range indicates a relation between OP1 and OP2.
+// OP1 - OP2 == 0 implies OP1 == OP2 even with wrapping arithmetic.
+
+relation_kind
+operator_minus::op1_op2_relation (const irange &lhs, const irange &,
+                                 const irange &) const
+{
+  if (lhs.undefined_p ())
+    return VREL_UNDEFINED;
+
+  if (lhs.zero_p ())
+    return VREL_EQ;
+
+  if (!lhs.contains_zero_p ())
+    return VREL_NE;
+
+  return VREL_VARYING;
+}
+
 bool
 operator_minus::op1_op2_relation_effect (irange &lhs_range, tree type,
                                         const irange &op1_range,
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/vrp-minus-relation-1.c 
b/gcc/testsuite/gcc.dg/tree-ssa/vrp-minus-relation-1.c
new file mode 100644
index 000000000000..f071ffa57962
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/vrp-minus-relation-1.c
@@ -0,0 +1,17 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-vrp1" } */
+
+void dead (void);
+
+void f (int a, int b)
+{
+  int d = a - b;
+  if (d < 0)
+    return;
+  if (d > 0)
+    return;
+  if (a != b)
+    dead ();
+}
+
+/* { dg-final { scan-tree-dump-not "dead" "vrp1" } } */

Reply via email to