On Mon, Sep 14, 2026 at 2:49 AM Richard Biener
<[email protected]> wrote:
>
> On Sat, Sep 12, 2026 at 9:25 AM Andrea Pinski
> <[email protected]> wrote:
> >
> > This adds a pattern to optimize `minmax (a, b) + c` into `minmax (a + c, b 
> > + c)` when
> > `a + c` and `b + c` are known not to overflow and either `a + c` or `b + c` 
> > simplifies.
>
> Why is this good if either simplifies?  Both would be obvious, but
> either?  Also your
> pattern picks the 2nd operand for simplifies and uses :c to test the
> other variant.
> That's of course more expensive than a way to tell genmatch to accept either
> operand simplifying ...

I changed this into just matching `minmax (a - c, b) + c` and
simplifying that into `minmax (a, b + c)`, the reason is what in some
cases, `b+c` can become `b+min(b, 1)` and then with some reorg of the
min/max and some further optimizations, we will get MAX(SAT_MUL(a, 2),
1) or MAX(SAT_MUL(a,8),4) with this.

The other reason why it is good to simplify in this case is because
`a` might be a constant, so it is obvious the MIN expression has a
limit and then you can optimize away a condition that happens
afterwards. Which in this case is enough to optimize away a condition
that was there with std::vector::push_back; VRP does not see the
relationship between the two arguments of the min because of a max in
the way so it does not produce a decent range.

Thanks,
Andrea


>
> > This shows up in std::vector::push_back :
> >
> > ```
> >   # RANGE [irange] const size_type [0, 2147483647] MASK 0x7fffffff VALUE 0x0
> >   __room_33 = 2147483647 - _32;
> > ...
> >   # RANGE [irange] long unsigned int [1, 2147483646] MASK 0x7fffffff VALUE 
> > 0x0
> >   _35 = MIN_EXPR <__room_33, _34>;
> >   # RANGE [irange] long unsigned int [1, 4294967292]
> >   _36 = _32 + _35;
> > ```
> > _32 has a range of `[0, 2147483647]`, _34 has a range of `[1, 2147483646]`.
> >
> > This is transformed into:
> > _t = _32 + _34;
> > _36 = MIN_EXPR<_t, 2147483647>
> >
> > This then allows to remove a condition that was never could be executed too.
> >
> > This is currently limited to unsigned types as overflow_free_p does not tell
> > me if we are going to introduce new undefined overflow; it will return true 
> > for
> > all TYPE_OVERFLOW_UNDEFINED types.  I filed PR 127356 to add a modified 
> > version
> > of overflow_free_p.  But since the types in push_back is unsigned this is 
> > enough
> > for now.
> >
> > Bootstrapped and tested on x86_64-linux-gnu.
> >
> >         PR tree-optimization/127103
> > gcc/ChangeLog:
> >
> >         * match.pd (`minmax (a, b) + c`): New pattern.
> >
> > gcc/testsuite/ChangeLog:
> >
> >         * gcc.dg/tree-ssa/minmax-plus-1.c: New test.
> >
> > Signed-off-by: Andrea Pinski <[email protected]>
> > ---
> >  gcc/match.pd                                  | 15 +++++++
> >  gcc/testsuite/gcc.dg/tree-ssa/minmax-plus-1.c | 39 +++++++++++++++++++
> >  2 files changed, 54 insertions(+)
> >  create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/minmax-plus-1.c
> >
> > diff --git a/gcc/match.pd b/gcc/match.pd
> > index d6ece84e186..81734b73a7d 100644
> > --- a/gcc/match.pd
> > +++ b/gcc/match.pd
> > @@ -532,6 +532,21 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
> >     (if (gimple_match_range_of_expr (vr0, @0, @2)
> >         && range_op_handler (PLUS_EXPR).overflow_free_p (vr0, vr0))
> >      (max (plus @0 @0) @1)))))
> > +
> > +/* minmax (a, b) + c -> minmax (a + c, b + c)
> > +   if a+c or b+c simplifies and a+c/b+c don't overlfow */
> > +(for minmax (min max)
> > + (simplify
> > +  (plus:c @0 (minmax:cs@3 @1 @2))
> > +  (with { int_range_max vr0, vr1, vr2; }
> > +   (if (TYPE_UNSIGNED (type)
> > +       && gimple_match_range_of_expr (vr0, @0)
> > +       && gimple_match_range_of_expr (vr1, @1, @3)
> > +       && gimple_match_range_of_expr (vr2, @2, @3)
> > +       && range_op_handler (PLUS_EXPR).overflow_free_p (vr0, vr1)
> > +       && range_op_handler (PLUS_EXPR).overflow_free_p (vr0, vr2))
> > +    (minmax (plus @0 @1) (plus! @0 @2))))))
> > +
> >  #endif
> >
> >  /* X * 1, X / 1 -> X.  */
> > diff --git a/gcc/testsuite/gcc.dg/tree-ssa/minmax-plus-1.c 
> > b/gcc/testsuite/gcc.dg/tree-ssa/minmax-plus-1.c
> > new file mode 100644
> > index 00000000000..75067fdb962
> > --- /dev/null
> > +++ b/gcc/testsuite/gcc.dg/tree-ssa/minmax-plus-1.c
> > @@ -0,0 +1,39 @@
> > +/* { dg-do compile } */
> > +/* { dg-options "-O2 -fdump-tree-optimized-raw" } */
> > +/* minmax (a, b) + c -> minmax (a + c, b + c) */
> > +/* PR tree-optimization/127103 */
> > +
> > +__attribute__((always_inline))
> > +static inline unsigned
> > +min(unsigned a, unsigned b)
> > +{
> > +  if (a > b)
> > +    return b;
> > +  return a;
> > +}
> > +__attribute__((always_inline))
> > +static inline unsigned
> > +max(unsigned a, unsigned b)
> > +{
> > +  if (a < b)
> > +    return b;
> > +  return a;
> > +}
> > +
> > +unsigned f(unsigned a, unsigned t1)
> > +{
> > +  if (a > __INT_MAX__)
> > +    return 0;
> > +  unsigned t = __INT_MAX__ - a;
> > +  return a + min(t, a);
> > +}
> > +
> > +unsigned f1(unsigned a, unsigned t1)
> > +{
> > +  if (a > __INT_MAX__)
> > +    return 0;
> > +  unsigned t = __INT_MAX__ - a;
> > +  return a + max(t, a);
> > +}
> > +
> > +/* { dg-final { scan-tree-dump-times "gimple_assign <mult_expr, _\[0-9\], 
> > a_\[0-9\].D., 2" 2 "optimized" } } */
> > --
> > 2.43.0
> >

Reply via email to