On Wed, Oct 7, 2026 at 5:38 PM Andrea Pinski
<[email protected]> wrote:
>
> On Sat, Oct 3, 2026 at 11:01 PM Aldy Hernandez <[email protected]> wrote:
> >
> > When x == y, x & y is x, similarly for x | y.
> >
> > When x <= y, MIN(x,y) is x.
> >
> > When x >= y, MAX(x,y) is x.
> >
> > When we implement this, we can fold the following:
> >
> > if (x == y)
> > {
> > int t = x & y;
> > if (t != x) // folds to false since t == x
> > link_error ();
> > }
> >
> > Found while auditing DOM. It's doing some simplifications that are
> > best done in range-ops. In a follow-up patch I will rip out the
> > relevant code from DOM.
>
> I think this fixes https://gcc.gnu.org/bugzilla/show_bug.cgi?id=126750
> . I would have to look to double check.
Just to confirm yes r17-4863-g7b3563c38b7b1e did fix that PR.
Thanks,
Andrea
>
> >
> > Tested on ppc64le Linux.
> >
> > Pushed.
> >
> > gcc/ChangeLog:
> >
> > * range-op-mixed.h (operator_bitwise_or::lhs_op1_relation): New.
> > (operator_min::lhs_op1_relation): New.
> > (operator_min::lhs_op2_relation): New.
> > (operator_max::lhs_op1_relation): New.
> > (operator_max::lhs_op2_relation): New.
> > * range-op.cc (operator_bitwise_and::lhs_op1_relation): Return
> > VREL_EQ when the operands are equal.
> > (operator_bitwise_or::lhs_op1_relation): New.
> > (operator_min::lhs_op1_relation): New.
> > (operator_min::lhs_op2_relation): New.
> > (operator_max::lhs_op1_relation): New.
> > (operator_max::lhs_op2_relation): New.
> >
> > gcc/testsuite/ChangeLog:
> >
> > * gcc.dg/tree-ssa/vrp-and-or-relation-1.c: New test.
> > ---
> > gcc/range-op-mixed.h | 20 +++++
> > gcc/range-op.cc | 80 ++++++++++++++++++-
> > .../gcc.dg/tree-ssa/vrp-and-or-relation-1.c | 61 ++++++++++++++
> > 3 files changed, 160 insertions(+), 1 deletion(-)
> > create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/vrp-and-or-relation-1.c
> >
> > diff --git a/gcc/range-op-mixed.h b/gcc/range-op-mixed.h
> > index b084c3edeab..a294958ce8f 100644
> > --- a/gcc/range-op-mixed.h
> > +++ b/gcc/range-op-mixed.h
> > @@ -852,8 +852,12 @@ public:
> > using range_operator::fold_range;
> > using range_operator::op1_range;
> > using range_operator::op2_range;
> > + using range_operator::lhs_op1_relation;
> > using range_operator::op1_op2_relation_effect;
> > using range_operator::update_bitmask;
> > + relation_kind lhs_op1_relation (const irange &lhs,
> > + const irange &op1, const irange &op2,
> > + relation_kind) const final override;
> >
> > bool fold_range (prange &r, tree type,
> > const prange &op1,
> > @@ -922,7 +926,15 @@ class operator_min : public range_operator
> > {
> > public:
> > using range_operator::fold_range;
> > + using range_operator::lhs_op1_relation;
> > + using range_operator::lhs_op2_relation;
> > using range_operator::update_bitmask;
> > + relation_kind lhs_op1_relation (const irange &lhs,
> > + const irange &op1, const irange &op2,
> > + relation_kind) const final override;
> > + relation_kind lhs_op2_relation (const irange &lhs,
> > + const irange &op1, const irange &op2,
> > + relation_kind) const final override;
> > bool fold_range (prange &r, tree type,
> > const prange &op1,
> > const prange &op2,
> > @@ -942,7 +954,15 @@ class operator_max : public range_operator
> > {
> > public:
> > using range_operator::fold_range;
> > + using range_operator::lhs_op1_relation;
> > + using range_operator::lhs_op2_relation;
> > using range_operator::update_bitmask;
> > + relation_kind lhs_op1_relation (const irange &lhs,
> > + const irange &op1, const irange &op2,
> > + relation_kind) const final override;
> > + relation_kind lhs_op2_relation (const irange &lhs,
> > + const irange &op1, const irange &op2,
> > + relation_kind) const final override;
> > bool fold_range (prange &r, tree type,
> > const prange &op1,
> > const prange &op2,
> > diff --git a/gcc/range-op.cc b/gcc/range-op.cc
> > index 07318bca71e..3f302bdc1d1 100644
> > --- a/gcc/range-op.cc
> > +++ b/gcc/range-op.cc
> > @@ -2180,6 +2180,36 @@ operator_min::wi_fold (irange &r, tree type,
> > value_range_with_overflow (r, type, new_lb, new_ub);
> > }
> >
> > +// When op1 <= op2, MIN (op1, op2) is op1.
> > +
> > +relation_kind
> > +operator_min::lhs_op1_relation (const irange &lhs, const irange &op1,
> > + const irange &op2, relation_kind rel) const
> > +{
> > + if (lhs.undefined_p () || op1.undefined_p () || op2.undefined_p ())
> > + return VREL_VARYING;
> > + if (rel == VREL_LE || rel == VREL_LT || rel == VREL_EQ
> > + || wi::le_p (op1.upper_bound (), op2.lower_bound (),
> > + TYPE_SIGN (op1.type ())))
> > + return VREL_EQ;
> > + return VREL_VARYING;
> > +}
> > +
> > +// Same as above, but for op2.
> > +
> > +relation_kind
> > +operator_min::lhs_op2_relation (const irange &lhs, const irange &op1,
> > + const irange &op2, relation_kind rel) const
> > +{
> > + if (lhs.undefined_p () || op1.undefined_p () || op2.undefined_p ())
> > + return VREL_VARYING;
> > + if (rel == VREL_GE || rel == VREL_GT || rel == VREL_EQ
> > + || wi::le_p (op2.upper_bound (), op1.lower_bound (),
> > + TYPE_SIGN (op1.type ())))
> > + return VREL_EQ;
> > + return VREL_VARYING;
> > +}
> > +
> >
> > void
> > operator_max::update_bitmask (irange &r, const irange &lh,
> > @@ -2199,6 +2229,36 @@ operator_max::wi_fold (irange &r, tree type,
> > value_range_with_overflow (r, type, new_lb, new_ub);
> > }
> >
> > +// When op1 >= op2, MAX (op1, op2) is op1.
> > +
> > +relation_kind
> > +operator_max::lhs_op1_relation (const irange &lhs, const irange &op1,
> > + const irange &op2, relation_kind rel) const
> > +{
> > + if (lhs.undefined_p () || op1.undefined_p () || op2.undefined_p ())
> > + return VREL_VARYING;
> > + if (rel == VREL_GE || rel == VREL_GT || rel == VREL_EQ
> > + || wi::ge_p (op1.lower_bound (), op2.upper_bound (),
> > + TYPE_SIGN (op1.type ())))
> > + return VREL_EQ;
> > + return VREL_VARYING;
> > +}
> > +
> > +// Same as above, but for op2.
> > +
> > +relation_kind
> > +operator_max::lhs_op2_relation (const irange &lhs, const irange &op1,
> > + const irange &op2, relation_kind rel) const
> > +{
> > + if (lhs.undefined_p () || op1.undefined_p () || op2.undefined_p ())
> > + return VREL_VARYING;
> > + if (rel == VREL_LE || rel == VREL_LT || rel == VREL_EQ
> > + || wi::ge_p (op2.lower_bound (), op1.upper_bound (),
> > + TYPE_SIGN (op1.type ())))
> > + return VREL_EQ;
> > + return VREL_VARYING;
> > +}
> > +
> >
> > // Calculate the cross product of two sets of ranges and return it.
> > //
> > @@ -3568,10 +3628,13 @@ relation_kind
> > operator_bitwise_and::lhs_op1_relation (const irange &lhs,
> > const irange &op1,
> > const irange &op2,
> > - relation_kind) const
> > + relation_kind rel) const
> > {
> > if (lhs.undefined_p () || op1.undefined_p () || op2.undefined_p ())
> > return VREL_VARYING;
> > + // When x == y, x & y is x.
> > + if (rel == VREL_EQ)
> > + return VREL_EQ;
> > if (!op2.singleton_p ())
> > return VREL_VARYING;
> > // if val == 0xff or 0xFFFF OR 0Xffffffff OR 0Xffffffffffffffff, return
> > TRUE
> > @@ -4134,6 +4197,21 @@ operator_bitwise_or::wi_fold (irange &r, tree type,
> > value_range_with_overflow (r, type, new_lb, new_ub);
> > }
> >
> > +// When x == y, x | y is x.
> > +
> > +relation_kind
> > +operator_bitwise_or::lhs_op1_relation (const irange &lhs,
> > + const irange &op1,
> > + const irange &op2,
> > + relation_kind rel) const
> > +{
> > + if (lhs.undefined_p () || op1.undefined_p () || op2.undefined_p ())
> > + return VREL_VARYING;
> > + if (rel == VREL_EQ)
> > + return VREL_EQ;
> > + return VREL_VARYING;
> > +}
> > +
> > bool
> > operator_bitwise_or::op1_op2_relation_effect (irange &lhs_range,
> > tree type,
> > diff --git a/gcc/testsuite/gcc.dg/tree-ssa/vrp-and-or-relation-1.c
> > b/gcc/testsuite/gcc.dg/tree-ssa/vrp-and-or-relation-1.c
> > new file mode 100644
> > index 00000000000..cb17e56be4f
> > --- /dev/null
> > +++ b/gcc/testsuite/gcc.dg/tree-ssa/vrp-and-or-relation-1.c
> > @@ -0,0 +1,61 @@
> > +/* { dg-do compile } */
> > +/* { dg-options "-O2 -fgimple -fdump-tree-evrp" } */
> > +
> > +/* x & y and x | y are x when x == y: range-op records that relation
> > + when the statement is folded, and the test against x folds. */
> > +
> > +void link_error (void);
> > +
> > +void __GIMPLE (ssa,startwith("evrp"))
> > +and_it (int x, int y)
> > +{
> > + int t;
> > +
> > + __BB(2):
> > + if (x_1(D) == y_2(D))
> > + goto __BB3;
> > + else
> > + goto __BB5;
> > +
> > + __BB(3):
> > + t_3 = x_1(D) & y_2(D);
> > + if (t_3 != x_1(D))
> > + goto __BB4;
> > + else
> > + goto __BB5;
> > +
> > + __BB(4):
> > + link_error ();
> > + goto __BB5;
> > +
> > + __BB(5):
> > + return;
> > +}
> > +
> > +void __GIMPLE (ssa,startwith("evrp"))
> > +or_it (int x, int y)
> > +{
> > + int t;
> > +
> > + __BB(2):
> > + if (x_1(D) == y_2(D))
> > + goto __BB3;
> > + else
> > + goto __BB5;
> > +
> > + __BB(3):
> > + t_3 = x_1(D) | y_2(D);
> > + if (t_3 != x_1(D))
> > + goto __BB4;
> > + else
> > + goto __BB5;
> > +
> > + __BB(4):
> > + link_error ();
> > + goto __BB5;
> > +
> > + __BB(5):
> > + return;
> > +}
> > +
> > +/* { dg-final { scan-tree-dump-not "link_error" "evrp" } } */
> > --
> > 2.53.0
> >