On 9/10/26 5:48 AM, Aldy Hernandez wrote:
[Andrew, are you OK with this?  It seems simple enough, but I may be
missing something subtle, or perhaps there is another place in the
compiler we should be fixing this?  Either way, it seems something
good to implement for completeness sake.  OK for trunk?]


I'm OK with it... just check the performance... it'll probably trigger a bunch more edge range calculations...  At some point it might be worth adding some kind of indication to range-ops when a routine is "the default".  For instance, if op1_op2_relation is the default for handler, then we dont even need to check for that stmt.    Im not saying we do it now, but consider such a thing if performance starts to be impacted by some fo the checks we do. GORI might also benefit in places from it.  something to explore eventually.

Given that this seems OK, any reason why we would even check the type anymore?   could work with floating point or pointers too... I suspect its mostly an artifact from early days of relations...

Andrew


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.

Tested on ppc64le Linux.

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.
---
  gcc/gimple-range-fold.cc                      |  5 ++++-
  gcc/range-op-mixed.h                          |  3 +++
  gcc/range-op.cc                               | 19 +++++++++++++++++++
  .../gcc.dg/tree-ssa/vrp-minus-relation-1.c    | 17 +++++++++++++++++
  4 files changed, 43 insertions(+), 1 deletion(-)
  create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/vrp-minus-relation-1.c

diff --git a/gcc/gimple-range-fold.cc b/gcc/gimple-range-fold.cc
index abe3ade2960..a143c19647a 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 0e97fb11688..b084c3edeab 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 350548951f4..07318bca71e 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 00000000000..f071ffa5796
--- /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