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

Reply via email to