[PATCH] match: fold the sum of a min/max pair

<[email protected]> Tue, 4 Aug 2026 12:14:24 +0200
Newsgroups gmane.comp.gcc.patches
Message-ID <[email protected]>
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.

  int f (int a, int b) { int mn = 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))
+  (if (ANY_INTEGRAL_TYPE_P (type)
+       && !TYPE_OVERFLOW_SANITIZED (type) && !TYPE_OVERFLOW_TRAPS (type))
+   (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 = a < b ? a : b; return (a + b) - mn; }
+int f2 (int a, int b) { int mx = a < b ? b : a; return (a + b) - mx; }
+unsigned int f3 (unsigned int a, unsigned int b)
+{
+  unsigned int mn = a < b ? a : b;
+  return (a + b) - mn;
+}
+long f4 (long a, long b) { long mx = a < b ? b : a; return (b + a) - mx; }
+
+/* { 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)