The pattern X != C1 ? -X : C2 currently exits when C1 is
INT_MIN and the type doesn't wrap, because a signed negetion
of INT_MIN is undefined behavior. But the whole expression is
well-defined, it is equivalent to (signed)(-(unsigned)X).
Handle the wi::only_sign_bit_p case by emitting an unsigned
negate instead of giving up, copying what the abs pattern
already does for the same edge case.
PR tree-optimization/125050
gcc/ChangeLog:
* match.pd: (X != C1 ? -X : C2): Handle C1 being INT_MIN
by emitting (signed)(-(unsigned)X) instead of bailing out.
gcc/testsuite/ChangeLog:
* gcc.dg/pr125050.c: New test.
* gcc.dg/tree-ssa/phi-opt-50.c: New test.
* gcc.dg/tree-ssa/phi-opt-51.c: New test.
Signed-off-by: Avinal Kumar <[email protected]>
---
Build and ran full testsuite on AMD64 machine.
gcc/match.pd | 12 ++++++++----
gcc/testsuite/gcc.dg/pr125050.c | 13 +++++++++++++
gcc/testsuite/gcc.dg/tree-ssa/phi-opt-50.c | 21 +++++++++++++++++++++
gcc/testsuite/gcc.dg/tree-ssa/phi-opt-51.c | 21 +++++++++++++++++++++
4 files changed, 63 insertions(+), 4 deletions(-)
create mode 100644 gcc/testsuite/gcc.dg/pr125050.c
create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/phi-opt-50.c
create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/phi-opt-51.c
diff --git a/gcc/match.pd b/gcc/match.pd
index ff13a07ea94..9fca662a2e4 100644
--- a/gcc/match.pd
+++ b/gcc/match.pd
@@ -6755,14 +6755,18 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
)
#endif
-/* X != C1 ? -X : C2 simplifies to -X when -C1 == C2. */
+/* X != C1 ? -X : C2 simplifies to -X when -C1 == C2. Additionally,
+ when C1 is the minimum signed value (e.g) INT_MIN), -X would be
+ undefined for signed types, so emit (signed)(-(unsigned)X) instead. */
(simplify
(cond (ne @0 INTEGER_CST@1) (negate@3 @0) INTEGER_CST@2)
(if (!TYPE_SATURATING (type)
- && (TYPE_OVERFLOW_WRAPS (type)
- || !wi::only_sign_bit_p (wi::to_wide (@1)))
&& wi::eq_p (wi::neg (wi::to_wide (@1)), wi::to_wide (@2)))
- @3))
+ (if (TYPE_OVERFLOW_WRAPS (type)
+ || !wi::only_sign_bit_p (wi::to_wide (@1)))
+ @3
+ (with {tree utype = unsigned_type_for (TREE_TYPE (@0)); }
+ (convert (negate (convert:utype @0)))))))
/* X != C1 ? ~X : C2 simplifies to ~X when ~C1 == C2. */
(simplify
diff --git a/gcc/testsuite/gcc.dg/pr125050.c b/gcc/testsuite/gcc.dg/pr125050.c
new file mode 100644
index 00000000000..cf73d200cd5
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr125050.c
@@ -0,0 +1,13 @@
+/* PR tree-optimization/125050 */
+/* { dg-do compile } */
+/* {dg-options "O1 -fdump-tree-phiopt1" } */
+
+int f(int a)
+{
+ if (a == -__INT_MAX__ - 1)
+ return -__INT_MAX__ - 1;
+ return -a;
+}
+
+/* This should be converted to (int)(-(unsigned)a). */
+/* { dg-final {scan-tree-dump-not "if " "phiopt1" } } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/phi-opt-50.c
b/gcc/testsuite/gcc.dg/tree-ssa/phi-opt-50.c
new file mode 100644
index 00000000000..f386c25a61b
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/phi-opt-50.c
@@ -0,0 +1,21 @@
+/* { dg-do compile } */
+/* { dg-options "-O1 -fdump-tree-phiopt1" } */
+
+/* a == INT_MIN ? INT_MIN : -a simplifies to (int)(-(unsigned)a) */
+int f1(int a)
+{
+ if (a == -__INT_MAX__ - 1)
+ return -__INT_MAX__ - 1;
+ return -a;
+}
+
+/* a != INT_MIN ? -a : INT_MIN simplifies to (int)(-(unsigned)a) */
+int f2(int a)
+{
+ if (a != -__INT_MAX__ - 1)
+ return -a;
+ return -__INT_MAX__ - 1;
+}
+
+/* { dg-final { scan-tree-dump-times "negate_expr" 2 "phiopt1" } } */
+/* { dg-final { scan-tree-dump-not "if " "phiopt1" } } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/phi-opt-51.c
b/gcc/testsuite/gcc.dg/tree-ssa/phi-opt-51.c
new file mode 100644
index 00000000000..952774e9840
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/phi-opt-51.c
@@ -0,0 +1,21 @@
+/* { dg-do compile } */
+/* { dg-options "-O1 -fdump-tree-phiopt1" } */
+
+/* Try the same pattern with different integer types. */
+
+short f_short(short a)
+{
+ if (a == (short)(-__SHRT_MAX__ - 1))
+ return -__SHRT_MAX__ - 1;
+ return -a;
+}
+
+long long f_ll(long long a)
+{
+ if (a == -__LONG_LONG_MAX__ - 1)
+ return -__LONG_LONG_MAX__ - 1;
+ return -a;
+}
+
+/* { dg-final { scan-tree-dump-times "negate_expr" 2 "phiopt1" } } */
+/* { dg-final { scan-tree-dump-not "if " "phiopt1" } } */
--
2.54.0