[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?]
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;