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. > > 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 >
