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