From: Samarth Tandale <[email protected]>
For MIN_EXPR, if x is TYPE_MAX_VALUE, then min (x, y) is y.
So:
x == TYPE_MAX_VALUE ? y : min (x, y)
can be simplified to:
min (x, y)
Similarly for MAX_EXPR, if x is TYPE_MIN_VALUE, then max (x, y)
is y.
So:
x == TYPE_MIN_VALUE ? y : max (x, y)
can be simplified to:
max (x, y)
This adds a combined match.pd pattern for MIN_EXPR and MAX_EXPR.
PR tree-optimization/125700
gcc/ChangeLog:
* match.pd: Fold type-bound guarded min/max expressions.
gcc/testsuite/ChangeLog:
* gcc.dg/tree-ssa/pr125700.c: New test.
* gcc.dg/tree-ssa/pr125700-int-width.c: New test.
* gcc.dg/tree-ssa/pr125700-negative.c: New test.
Signed-off-by: Samarth Tandale <[email protected]>
---
For MIN_EXPR, if x is TYPE_MAX_VALUE, then min (x, y) is y.
So:
x == TYPE_MAX_VALUE ? y : min (x, y)
can be simplified to:
min (x, y)
Similarly for MAX_EXPR, if x is TYPE_MIN_VALUE, then max (x, y)
is y.
So:
x == TYPE_MIN_VALUE ? y : max (x, y)
can be simplified to:
max (x, y)
This adds a combined match.pd pattern for MIN_EXPR and MAX_EXPR.
PR tree-optimization/125700
```
gcc/ChangeLog:
* match.pd: Fold type-bound guarded min/max expressions.
gcc/testsuite/ChangeLog:
* gcc.dg/tree-ssa/pr125700.c: New test.
* gcc.dg/tree-ssa/pr125700-int-width.c: New test.
* gcc.dg/tree-ssa/pr125700-negative.c: New test.
```
Signed-off-by: Samarth Tandale <[email protected]>
This is a forge pull request published on the gcc-patches mailing list mailing
list
as requested by Samarth Tandale via Sourceware Forge
<[email protected]>.
Forge discussion: https://forge.sourceware.org/gcc/gcc/pulls/214
Get it locally using:
```
git fetch forge-upstream "+refs/versioned_pull/214/*:refs/versioned_pull/214/*"
git switch -c "pr-214-v1" "refs/versioned_pull/214/1/head"
```
Or, download the patch at: https://forge.sourceware.org/gcc/gcc/pulls/214.diff
Created on: 2026-08-10 06:22:31+00:00
Latest update: 2026-08-10 06:35:25+00:00
Changes: 4 changed files, 223 additions, 0 deletions
Head revision: sam-100/gcc ref pr125700 commit
4d042112a60614fdea9eface9d3b6c00fab7a260
Base revision: gcc/gcc ref trunk commit
19a304d3680a1aeeb8ca412a6fe108a3f3b9d305 r17-3012-g19a304d3680a1a
Merge base: 19a304d3680a1aeeb8ca412a6fe108a3f3b9d305
Requested Reviewers: pinskia
Changed files:
- A: gcc/testsuite/gcc.dg/tree-ssa/pr125700-int-width.c
- A: gcc/testsuite/gcc.dg/tree-ssa/pr125700-negative.c
- A: gcc/testsuite/gcc.dg/tree-ssa/pr125700.c
- M: gcc/match.pd
gcc/match.pd | 16 +++
.../gcc.dg/tree-ssa/pr125700-int-width.c | 52 ++++++++
.../gcc.dg/tree-ssa/pr125700-negative.c | 41 +++++++
gcc/testsuite/gcc.dg/tree-ssa/pr125700.c | 114 ++++++++++++++++++
4 files changed, 223 insertions(+)
create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/pr125700-int-width.c
create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/pr125700-negative.c
create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/pr125700.c
diff --git a/gcc/match.pd b/gcc/match.pd
index e99a35046bc86..39c57a06cc733 100644
--- a/gcc/match.pd
+++ b/gcc/match.pd
@@ -12707,3 +12707,19 @@ and,
(if (INTEGRAL_TYPE_P (type))
(with { tree itype = TREE_TYPE (@2); }
(convert (minus @2 (convert:itype @1))))))
+
+/* Replace (x == TYPE_MAX) ? y : MIN (x, y) -> MIN (x, y)
+ because MIN (TYPE_MAX, y) is always y.
+ Similarly, (x == TYPE_MIN) ? y : MAX (x, y) -> MAX (x, y)
+ because MAX (TYPE_MIN, y) is always y. */
+(for minmax (min max)
+ (simplify
+ (cond (eq @0 INTEGER_CST@1) @2 (minmax:c@3 @0 @2))
+ (if (INTEGRAL_TYPE_P (type))
+ (with {
+ tree bound = (minmax == MIN_EXPR)
+ ? TYPE_MAX_VALUE (type)
+ : TYPE_MIN_VALUE (type);
+ }
+ (if (bound && tree_int_cst_equal (@1, bound))
+ @3)))))
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr125700-int-width.c
b/gcc/testsuite/gcc.dg/tree-ssa/pr125700-int-width.c
new file mode 100644
index 0000000000000..0ce990b6b4cf4
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/pr125700-int-width.c
@@ -0,0 +1,52 @@
+/* PR tree-optimization/125700 */
+/* Integer width variants to cover non-int widths and
+ both signed/unsigned. */
+
+/* { dg-do compile } */
+/* { dg-options "-O1 -fdump-tree-optimized" } */
+
+#include <limits.h>
+
+#define GEN_FUNCS(TAG, UTYPE, STYPE, UMAX, SMAX, SMIN) \
+UTYPE \
+fumin_##TAG (UTYPE x, UTYPE y) \
+{ \
+ if (x == (UMAX)) \
+ return y; \
+ return x < y ? x : y; \
+} \
+\
+STYPE \
+fsmin_##TAG (STYPE x, STYPE y) \
+{ \
+ if (x == (SMAX)) \
+ return y; \
+ return x < y ? x : y; \
+} \
+\
+UTYPE \
+fumax_##TAG (UTYPE x, UTYPE y) \
+{ \
+ if (x == 0) \
+ return y; \
+ return x > y ? x : y; \
+} \
+\
+STYPE \
+fsmax_##TAG (STYPE x, STYPE y) \
+{ \
+ if (x == (SMIN)) \
+ return y; \
+ return x > y ? x : y; \
+}
+
+GEN_FUNCS (char, unsigned char, signed char, UCHAR_MAX, SCHAR_MAX, SCHAR_MIN)
+GEN_FUNCS (short, unsigned short, short, USHRT_MAX, SHRT_MAX, SHRT_MIN)
+GEN_FUNCS (long, unsigned long, long, ULONG_MAX, LONG_MAX, LONG_MIN)
+GEN_FUNCS (long_long, unsigned long long, long long, ULLONG_MAX, LLONG_MAX,
+ LLONG_MIN)
+
+/* { dg-final { scan-tree-dump-not "if" "optimized" } } */
+/* { dg-final { scan-tree-dump-not " == " "optimized" } } */
+/* { dg-final { scan-tree-dump-times "MIN_EXPR" 8 "optimized" } } */
+/* { dg-final { scan-tree-dump-times "MAX_EXPR" 8 "optimized" } } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr125700-negative.c
b/gcc/testsuite/gcc.dg/tree-ssa/pr125700-negative.c
new file mode 100644
index 0000000000000..4bfd7f6ca5f05
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/pr125700-negative.c
@@ -0,0 +1,41 @@
+/* PR tree-optimization/125700 */
+/* Negative test cases, should not transform. */
+
+/* { dg-do compile } */
+/* { dg-options "-O1 -fdump-tree-optimized" } */
+
+unsigned
+fumin_negative (unsigned x, unsigned y)
+{
+ if (x == 0)
+ return y;
+ return x < y ? x : y;
+}
+
+unsigned
+fumax_negative (unsigned x, unsigned y)
+{
+ if (x == -1u)
+ return y;
+ return x > y ? x : y;
+}
+
+signed
+fsmin_negative (signed x, signed y)
+{
+ if (x == -__INT_MAX__ - 1)
+ return y;
+ return x < y ? x : y;
+}
+
+signed
+fsmax_negative (signed x, signed y)
+{
+ if (x == __INT_MAX__)
+ return y;
+ return x > y ? x : y;
+}
+
+/* None of the if and '==' comparisons should be eliminated. */
+/* { dg-final { scan-tree-dump-times "if" 4 "optimized" } } */
+/* { dg-final { scan-tree-dump-times " == " 4 "optimized" } } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr125700.c
b/gcc/testsuite/gcc.dg/tree-ssa/pr125700.c
new file mode 100644
index 0000000000000..569c61141ef75
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/pr125700.c
@@ -0,0 +1,114 @@
+/* PR tree-optimization/125700 */
+/* Test the original cases, alternative condition forms and reversed
+ minimum/maximum operand orders. */
+
+/* { dg-do compile } */
+/* { dg-options "-O1 -fdump-tree-optimized" } */
+
+unsigned
+fumin (unsigned x, unsigned y)
+{
+ if (x == -1u)
+ return y;
+ return x < y ? x : y;
+}
+
+signed
+fsmin (signed x, signed y)
+{
+ if (x == __INT_MAX__)
+ return y;
+ return x < y ? x : y;
+}
+
+unsigned
+fumax (unsigned x, unsigned y)
+{
+ if (x == 0)
+ return y;
+ return x > y ? x : y;
+}
+
+signed
+fsmax (signed x, signed y)
+{
+ if (x == -__INT_MAX__ - 1)
+ return y;
+ return x > y ? x : y;
+}
+
+unsigned
+fumin_ne (unsigned x, unsigned y)
+{
+ if (x != -1u)
+ return x < y ? x : y;
+ return y;
+}
+
+unsigned
+fumax_ne (unsigned x, unsigned y)
+{
+ if (x != 0)
+ return x > y ? x : y;
+ return y;
+}
+
+unsigned
+fumin_ge (unsigned x, unsigned y)
+{
+ if (x >= -1u)
+ return y;
+ return x < y ? x : y;
+}
+
+unsigned
+fumax_le (unsigned x, unsigned y)
+{
+ if (x <= 0)
+ return y;
+ return x > y ? x : y;
+}
+
+unsigned
+fumin_lt (unsigned x, unsigned y)
+{
+ if (!(x < -1u))
+ return y;
+ return x < y ? x : y;
+}
+
+unsigned
+fumax_gt (unsigned x, unsigned y)
+{
+ if (!(x > 0))
+ return y;
+ return x > y ? x : y;
+}
+
+unsigned
+fumin_flip (unsigned x, unsigned y)
+{
+ if (x == -1u)
+ return y;
+ return y > x ? x : y;
+}
+
+unsigned
+fumax_flip (unsigned x, unsigned y)
+{
+ if (x == 0)
+ return y;
+ return y < x ? x : y;
+}
+
+/* The if and all conditional operators should be removed
+ from the optimized dump output. */
+/* { dg-final { scan-tree-dump-not "if" "optimized" } } */
+/* { dg-final { scan-tree-dump-not " == " "optimized" } } */
+/* { dg-final { scan-tree-dump-not " != " "optimized" } } */
+/* { dg-final { scan-tree-dump-not " <= " "optimized" } } */
+/* { dg-final { scan-tree-dump-not " >= " "optimized" } } */
+/* { dg-final { scan-tree-dump-not " < " "optimized" } } */
+/* { dg-final { scan-tree-dump-not " > " "optimized" } } */
+/* { dg-final { scan-tree-dump-times "MIN_EXPR" 6 "optimized" } } */
+/* { dg-final { scan-tree-dump-times "MAX_EXPR" 6 "optimized" } } */
--
2.54.0