[PATCH v1] match: Simplify type-bound guarded min/max expressions [PR125700]

Samarth Tandale via Sourceware Forge <[email protected]>
Newsgroups gmane.comp.gcc.patches
Message-ID <bmm.hl7ez99rr8.gcc.gcc.sam-100.214.1.0@forge-stage.sourceware.org>
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
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.