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" } } */
