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;
+}

Reply via email to