https://gcc.gnu.org/g:c8aaf14bf6882705d2515a5eb9c15de7f4034c5b
commit r17-4800-gc8aaf14bf6882705d2515a5eb9c15de7f4034c5b Author: Dominic P <[email protected]> Date: Tue Sep 29 09:20:27 2026 +0100 match.pd: Check that a - c does not wrap in minmax (a - c, b) + c [PR127103] r17-4378 folds minmax (a - c, b) + c to minmax (a, b + c) when b + c cannot overflow. The fold also needs a - c not to wrap: for unsigned a = 0, b = 0, c = 1, MIN (a - c, b) + c is 1 but MIN (a, b + c) is 0, and the MAX form gives 0 against 1. Require that with range_op_handler (MINUS_EXPR).overflow_free_p on the ranges of a and c. The std::vector::push_back case from the PR, where a is 2147483647, still folds. Bootstrapped and regression tested on x86_64-pc-linux-gnu, and dg.exp, tree-ssa.exp and execute.exp on aarch64-linux-gnu under qemu. Assisted-by: Claude Opus 5 (Anthropic) PR tree-optimization/127103 gcc/ChangeLog: * match.pd (minmax (a - c, b) + c): Also require that a - c does not overflow. gcc/testsuite/ChangeLog: * gcc.dg/torture/pr127103.c: New test. Signed-off-by: Dominic P <[email protected]> Diff: --- gcc/match.pd | 6 ++++-- gcc/testsuite/gcc.dg/torture/pr127103.c | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 37 insertions(+), 2 deletions(-) diff --git a/gcc/match.pd b/gcc/match.pd index c70a8e6d6d27..2d1161b860b2 100644 --- a/gcc/match.pd +++ b/gcc/match.pd @@ -531,13 +531,15 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT) (if (gimple_match_range_of_expr (vr0, @0, @2) && range_op_handler (PLUS_EXPR).overflow_free_p (vr0, vr0)) (max (plus @0 @0) @1))))) -/* minmax (a - c, b) + c -> minmax (a, b + c) if b+c don't overflow. */ +/* minmax (a - c, b) + c -> minmax (a, b + c) if a-c and b+c don't overflow. */ (for minmax (min max) (simplify (plus:c @0 (minmax:cs@3 (minus @1 @0) @2)) - (with { int_range_max vr0, vr2; } + (with { int_range_max vr0, vr1, vr2; } (if (TYPE_UNSIGNED (type) && gimple_match_range_of_expr (vr0, @0) + && gimple_match_range_of_expr (vr1, @1, @3) + && range_op_handler (MINUS_EXPR).overflow_free_p (vr1, vr0) && gimple_match_range_of_expr (vr2, @2, @3) && range_op_handler (PLUS_EXPR).overflow_free_p (vr0, vr2)) (minmax @1 (plus @2 @0)))))) diff --git a/gcc/testsuite/gcc.dg/torture/pr127103.c b/gcc/testsuite/gcc.dg/torture/pr127103.c new file mode 100644 index 000000000000..3b622d3388f7 --- /dev/null +++ b/gcc/testsuite/gcc.dg/torture/pr127103.c @@ -0,0 +1,33 @@ +/* { dg-do run } */ +/* minmax (a - c, b) + c must not become minmax (a, b + c) when a - c + can wrap. */ + +__attribute__((noipa)) unsigned +f_min (unsigned a, unsigned b, unsigned c) +{ + c &= 1; + b &= 1; + unsigned t = a - c; + t = t < b ? t : b; + return t + c; +} + +__attribute__((noipa)) unsigned +f_max (unsigned a, unsigned b, unsigned c) +{ + c &= 1; + b &= 1; + unsigned t = a - c; + t = t > b ? t : b; + return t + c; +} + +int +main (void) +{ + if (f_min (0, 0, 1) != 1) + __builtin_abort (); + if (f_max (0, 0, 1) != 0) + __builtin_abort (); + return 0; +}
