https://gcc.gnu.org/g:46ee9bbc9a7d92eb3435999b59c3d8b42254f88a

commit r17-4415-g46ee9bbc9a7d92eb3435999b59c3d8b42254f88a
Author: Kael Andrew Alonzo Franco <[email protected]>
Date:   Fri Sep 18 06:50:31 2026 -0400

    tree-optimization: Restrict (X {+,-} M*N) / N optimization. [PR127406]
    
    When X is INT_MIN and N is -1, then
    r14-3644 converts ((X {+,-} M*N) / N) to
    ((X / N) {+,-} M). But INT_MIN / -1 overflows where
    ((X {+,-} M*N) / N) does not.
    Add a check for ((X {+,-} M*N) / N) via X > INT_MIN
    and N != -1.
    
    Bootstrapped and regtested on x86_64-pc-linux-gnu.
    
            PR tree-optimization/127406
    
    gcc/ChangeLog:
    
            * match.pd: Restrict (X {+,-} M*N) / N optimization.
    
    gcc/testsuite/ChangeLog:
    
            * gcc.dg/torture/pr127406.c: New test.
    
    Signed-off-by: Kael Andrew Franco <[email protected]>

Diff:
---
 gcc/match.pd                            | 10 ++++++++--
 gcc/testsuite/gcc.dg/torture/pr127406.c | 28 ++++++++++++++++++++++++++++
 2 files changed, 36 insertions(+), 2 deletions(-)

diff --git a/gcc/match.pd b/gcc/match.pd
index 1c0393d11cde..e59c11d5d131 100644
--- a/gcc/match.pd
+++ b/gcc/match.pd
@@ -1200,7 +1200,10 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
        /* "X+N*M" is not with opposite sign as "X".  */
        && (TYPE_UNSIGNED (type)
           || (vr0.nonnegative_p () && vr4.nonnegative_p ())
-          || (vr0.nonpositive_p () && vr4.nonpositive_p ())))
+          || (vr0.nonpositive_p () && vr4.nonpositive_p ()
+              /* X = INT_MIN and N = -1 causes overflow.  */
+              && (!vr0.contains_p (wi::min_value (TYPE_PRECISION (type), 
SIGNED))
+                  || !vr2.contains_p (wi::minus_one (TYPE_PRECISION 
(type)))))))
   (plus (div @0 @2) @1))))
 
  /* Simplify (X - M*N) / N -> X / N - M.  */
@@ -1220,7 +1223,10 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
        /* "X-N*M" is not with opposite sign as "X".  */
        && (TYPE_UNSIGNED (type)
           || (vr0.nonnegative_p () && vr4.nonnegative_p ())
-          || (vr0.nonpositive_p () && vr4.nonpositive_p ())))
+          || (vr0.nonpositive_p () && vr4.nonpositive_p ()
+              /* X = INT_MIN and N = -1 causes overflow.  */
+              && (!vr0.contains_p (wi::min_value (TYPE_PRECISION (type), 
SIGNED))
+                  || !vr2.contains_p (wi::minus_one (TYPE_PRECISION 
(type)))))))
   (minus (div @0 @2) @1)))))
 
 /* Simplify
diff --git a/gcc/testsuite/gcc.dg/torture/pr127406.c 
b/gcc/testsuite/gcc.dg/torture/pr127406.c
new file mode 100644
index 000000000000..4cc48a320646
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/torture/pr127406.c
@@ -0,0 +1,28 @@
+/* { dg-do run } */
+
+__attribute__((noipa))
+int
+fplus (int x, int m, int n)
+{
+  if (x > -6 || m < -3 || m > -2 || n < -2 || n > -1)
+    return 0;
+  return (x + m * n) / n;
+}
+
+__attribute__((noipa))
+int
+fminus (int x, int m, int n)
+{
+  if (x > -6 || m < 2 || m > 3 || n < -2 || n > -1)
+    return 0;
+  return (x - m * n) / n;
+}
+
+int
+main (void)
+{
+  if (fplus (-2147483647 - 1, -2, -1) != 2147483646
+      || fminus (-2147483647 - 1, 2, -1) != 2147483646)
+    __builtin_abort ();
+  return 0;
+}

Reply via email to