[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