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