Re: [PATCH] match: fold the sum of a min/max pair
Andrea Pinski <[email protected]> Tue, 4 Aug 2026 13:30:50 -0700
| Newsgroups | gmane.comp.gcc.patches |
|---|---|
| Message-ID | <CALvbMcAfin103MScu-cxjHGjjyW4NT=sCyYvNr9sWZLz_8oBoA@mail.gmail.com> |
On Tue, Aug 4, 2026 at 3:15=E2=80=AFAM <[email protected]> wrote: > > From: Kyrylo Tkachov <[email protected]> > > The minimum and the maximum of two values add up to the sum of those > values, so subtracting one of them from the sum yields the other one. > That identity holds in modular arithmetic, so it needs only the guards > the neighbouring (x + y) - (x | y) rule uses. It holds even in non-modular (infinite) arithmetic too. That is it will either be min =3D=3D y: `x+y - y` (x) or min=3D=3Dx: `x+y-x` (y). So w= hat was min will turn into max. > > int f (int a, int b) { int mn =3D a < b ? a : b; return (a + b) - mn; } > > aarch64 -O2: > > before after > cmp w1, w0 cmp w1, w0 > add w2, w1, w0 csel w0, w1, w0, ge > csel w0, w1, w0, le > sub w0, w2, w0 > > Bootstrapped and tested on aarch64-none-linux-gnu. > Ok for trunk? > Thanks, > Kyrill > > gcc/ChangeLog: > > * match.pd ((x + y) - minmax (x, y)): New simplification. > > gcc/testsuite/ChangeLog: > > * gcc.dg/tree-ssa/minmax-sum-1.c: New test. > > Signed-off-by: Kyrylo Tkachov <[email protected]> > --- > gcc/match.pd | 11 +++++++++++ > gcc/testsuite/gcc.dg/tree-ssa/minmax-sum-1.c | 18 ++++++++++++++++++ > 2 files changed, 29 insertions(+) > create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/minmax-sum-1.c > > diff --git a/gcc/match.pd b/gcc/match.pd > index 72169a7a666..3c789e41493 100644 > --- a/gcc/match.pd > +++ b/gcc/match.pd > @@ -2048,6 +2048,17 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT) > && !TYPE_SATURATING (type)) > (res @0 @1)))) > > +/* (x + y) - min (x, y) -> max (x, y) > + (x + y) - max (x, y) -> min (x, y) > + The sum of the minimum and the maximum is the sum of the operands. *= / > +(for minmax (min max) > + maxmin (max min) > + (simplify > + (minus (plus @0 @1) (minmax:c @0 @1)) :c is not needed here since the order should be the same for both plus and min/max. > + (if (ANY_INTEGRAL_TYPE_P (type) > + && !TYPE_OVERFLOW_SANITIZED (type) && !TYPE_OVERFLOW_TRAPS (type)= ) Since you use ANY_INTEGRAL_TYPE_P, can you add a few vector testcases? Also should this work for fp with -ffast-math too? > + (maxmin @0 @1)))) > + > /* (x | y) - y -> (x & ~y) */ > (simplify > (minus (bit_ior:cs @0 @1) @1) > diff --git a/gcc/testsuite/gcc.dg/tree-ssa/minmax-sum-1.c b/gcc/testsuite= /gcc.dg/tree-ssa/minmax-sum-1.c > new file mode 100644 > index 00000000000..47a78abd0fa > --- /dev/null > +++ b/gcc/testsuite/gcc.dg/tree-ssa/minmax-sum-1.c > @@ -0,0 +1,18 @@ > +/* { dg-do compile } */ > +/* { dg-options "-O2 -fdump-tree-optimized" } */ > + > +/* The sum of the minimum and the maximum is the sum of the operands. *= / > + > +int f1 (int a, int b) { int mn =3D a < b ? a : b; return (a + b) - mn; } > +int f2 (int a, int b) { int mx =3D a < b ? b : a; return (a + b) - mx; } > +unsigned int f3 (unsigned int a, unsigned int b) > +{ > + unsigned int mn =3D a < b ? a : b; > + return (a + b) - mn; > +} > +long f4 (long a, long b) { long mx =3D a < b ? b : a; return (b + a) - m= x; } > + > +/* { dg-final { scan-tree-dump-times "MAX_EXPR" 2 "optimized" } } */ > +/* { dg-final { scan-tree-dump-times "MIN_EXPR" 2 "optimized" } } */ > +/* { dg-final { scan-tree-dump-not " \\+ " "optimized" } } */ > +/* { dg-final { scan-tree-dump-not " - " "optimized" } } */ > -- > 2.50.1 (Apple Git-155) >