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

Reply via email to