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