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]>
---
gcc/match.pd | 10 +++++++--
gcc/testsuite/gcc.dg/torture/pr127406.c | 29 +++++++++++++++++++++++++
2 files changed, 37 insertions(+), 2 deletions(-)
create mode 100644 gcc/testsuite/gcc.dg/torture/pr127406.c
diff --git a/gcc/match.pd b/gcc/match.pd
index 4059ed787f0..08fe309c445 100644
--- a/gcc/match.pd
+++ b/gcc/match.pd
@@ -1177,7 +1177,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. */
@@ -1197,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)))))))
(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 00000000000..d81a548be46
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/torture/pr127406.c
@@ -0,0 +1,29 @@
+/* { dg-do run } */
+/* { dg-additional-options "-O2" } */
+
+__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;
+}
--
2.55.0