https://gcc.gnu.org/g:a76b2602808cd5a49eb88b5f993f0072f1184bf6
commit r16-248-ga76b2602808cd5a49eb88b5f993f0072f1184bf6 Author: Andrew MacLeod <amacl...@redhat.com> Date: Tue Apr 22 10:36:26 2025 -0400 Add lhs_op1 relation to pointer_plus When prange was split from irange, the functionality of lhs_op1_relation did not get ported. This patch adds that functionality back, and is also good example of how to add new dispatch patterns to range-ops as lhs_op1_relation had no prange/prange/irange combination. * range-op-ptr.cc (range_operator::lhs_op1_relation): Add prange/prange/irange (PPI) default. (pointer_plus_operator::lhs_op1_relation): New. * range-op.cc (range_op_handler::lhs_op1_relation): Add RO_PPI case. * range-op.h (range_op_handler::lhs_op1_relation): Add prototype. Diff: --- gcc/range-op-ptr.cc | 59 +++++++++++++++++++++++++++++++++++++++++++++++++++++ gcc/range-op.cc | 4 ++++ gcc/range-op.h | 4 ++++ 3 files changed, 67 insertions(+) diff --git a/gcc/range-op-ptr.cc b/gcc/range-op-ptr.cc index dd51c2e0c926..36e9dfc20baf 100644 --- a/gcc/range-op-ptr.cc +++ b/gcc/range-op-ptr.cc @@ -218,6 +218,15 @@ range_operator::lhs_op1_relation (const prange &lhs ATTRIBUTE_UNUSED, return VREL_VARYING; } +relation_kind +range_operator::lhs_op1_relation (const prange &lhs ATTRIBUTE_UNUSED, + const prange &op1 ATTRIBUTE_UNUSED, + const irange &op2 ATTRIBUTE_UNUSED, + relation_kind rel ATTRIBUTE_UNUSED) const +{ + return VREL_VARYING; +} + void range_operator::update_bitmask (irange &, const prange &, @@ -293,6 +302,7 @@ class pointer_plus_operator : public range_operator using range_operator::update_bitmask; using range_operator::fold_range; using range_operator::op2_range; + using range_operator::lhs_op1_relation; public: virtual bool fold_range (prange &r, tree type, const prange &op1, @@ -302,6 +312,10 @@ public: const prange &lhs, const prange &op1, relation_trio = TRIO_VARYING) const final override; + virtual relation_kind lhs_op1_relation (const prange &lhs, + const prange &op1, + const irange &op2, + relation_kind) const; void update_bitmask (prange &r, const prange &lh, const irange &rh) const { update_known_bitmask (r, POINTER_PLUS_EXPR, lh, rh); } } op_pointer_plus; @@ -379,6 +393,51 @@ pointer_plus_operator::op2_range (irange &r, tree type, return true; } +// Return the relation between the LHS and OP1 based on the value of the +// operand being added. Pointer_plus is define to have a size_type for +// operand 2 which can be interpreted as negative, so always used SIGNED. +// Any overflow is considered UB and thus ignored. + +relation_kind +pointer_plus_operator::lhs_op1_relation (const prange &lhs, + const prange &op1, + const irange &op2, + relation_kind) const +{ + if (lhs.undefined_p () || op1.undefined_p () || op2.undefined_p ()) + return VREL_VARYING; + + unsigned prec = TYPE_PRECISION (op2.type ()); + + // LHS = OP1 + 0 indicates LHS == OP1. + if (op2.zero_p ()) + return VREL_EQ; + + tree val; + // Only deal with singletons for now. + if (TYPE_OVERFLOW_UNDEFINED (lhs.type ()) && op2.singleton_p (&val)) + { + // Always interpret VALUE as a signed value. Positive will increase + // the pointer value, and negative will decrease the poiinter value. + // It cannot be zero or the earlier zero_p () condition will catch it. + wide_int value = wi::to_wide (val); + + // Positive op2 means lhs > op1. + if (wi::gt_p (value, wi::zero (prec), SIGNED)) + return VREL_GT; + + // Negative op2 means lhs < op1. + if (wi::lt_p (value, wi::zero (prec), SIGNED)) + return VREL_LT; + } + + // If op2 does not contain 0, then LHS and OP1 can never be equal. + if (!range_includes_zero_p (op2)) + return VREL_NE; + + return VREL_VARYING; +} + bool operator_bitwise_or::fold_range (prange &r, tree type, const prange &op1, diff --git a/gcc/range-op.cc b/gcc/range-op.cc index 5c0bcdc3b37d..35b3e18ebed2 100644 --- a/gcc/range-op.cc +++ b/gcc/range-op.cc @@ -390,6 +390,10 @@ range_op_handler::lhs_op1_relation (const vrange &lhs, return m_operator->lhs_op1_relation (as_a <prange> (lhs), as_a <irange> (op1), as_a <irange> (op2), rel); + case RO_PPI: + return m_operator->lhs_op1_relation (as_a <prange> (lhs), + as_a <prange> (op1), + as_a <irange> (op2), rel); case RO_IFF: return m_operator->lhs_op1_relation (as_a <irange> (lhs), as_a <frange> (op1), diff --git a/gcc/range-op.h b/gcc/range-op.h index 5dcb3fbae61c..594e6782dc38 100644 --- a/gcc/range-op.h +++ b/gcc/range-op.h @@ -189,6 +189,10 @@ public: const prange &op1, const prange &op2, relation_kind = VREL_VARYING) const; + virtual relation_kind lhs_op1_relation (const prange &lhs, + const prange &op1, + const irange &op2, + relation_kind = VREL_VARYING) const; virtual relation_kind lhs_op1_relation (const frange &lhs, const frange &op1, const frange &op2,