Recognize conditional addition and subtraction patterns equivalent to
Y + abs (X) and Y - abs (X).

For signed integral types, perform the addition or subtraction in the
corresponding unsigned type and convert the result back to the original
type.  This avoids introducing signed overflow and preserves wrapping
semantics including when X is TYPE_MIN_VALUE.

Do not perform the transformation when signed overflow traps or is
sanitized.

gcc/ChangeLog:
        PR tree-optimization/56223
        * match.pd (X >=/> 0 ? Y + X : Y - X): New simplification.
        (X <=/< 0 ? Y - X : Y + X): Likewise.

gcc/testsuite/ChangeLog:
        PR tree-optimization/56223
        * gcc.dg/tree-ssa/pr56223.c: New test.
        * gcc.dg/tree-ssa/pr56223-2.c: New test.
        * gcc.dg/tree-ssa/pr56223-3.c: New test.
        * gcc.dg/tree-ssa/pr56223-4.c: New test.

Signed-off-by: Naveen <[email protected]>
---
 gcc/match.pd                              | 45 ++++++++++++
 gcc/testsuite/gcc.dg/tree-ssa/pr56223-2.c | 63 +++++++++++++++++
 gcc/testsuite/gcc.dg/tree-ssa/pr56223-3.c | 25 +++++++
 gcc/testsuite/gcc.dg/tree-ssa/pr56223-4.c | 25 +++++++
 gcc/testsuite/gcc.dg/tree-ssa/pr56223.c   | 86 +++++++++++++++++++++++
 5 files changed, 244 insertions(+)
 create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/pr56223-2.c
 create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/pr56223-3.c
 create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/pr56223-4.c
 create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/pr56223.c

diff --git a/gcc/match.pd b/gcc/match.pd
index 723780b8c38..cc25d35ac0a 100644
--- a/gcc/match.pd
+++ b/gcc/match.pd
@@ -7261,6 +7261,51 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
  )
 )
 
+/* X >=/> 0 ? Y + X : Y - X
+   X <=/< 0 ? Y - X : Y + X
+     same as Y + abs (X).
+
+   X >=/> 0 ? Y - X : Y + X
+   X <=/< 0 ? Y + X : Y - X
+     same as Y - abs (X).
+
+   Build the addition or subtraction in an unsigned type for integral
+   types so the replacement does not introduce signed overflow.  */
+(for cmp (ge gt)
+ (simplify
+  (cond (cmp @0 integer_zerop) (plus:c @0 @1) (minus @1 @0))
+  (if (!TYPE_UNSIGNED (type)
+       && !TYPE_OVERFLOW_TRAPS (type)
+       && !TYPE_OVERFLOW_SANITIZED (type))
+   (with { tree utype = unsigned_type_for (type); }
+    (convert (plus:utype (convert:utype @1)
+                        (absu:utype @0))))))
+ (simplify
+  (cond (cmp @0 integer_zerop) (minus @1 @0) (plus:c @0 @1))
+  (if (!TYPE_UNSIGNED (type)
+       && !TYPE_OVERFLOW_TRAPS (type)
+       && !TYPE_OVERFLOW_SANITIZED (type))
+   (with { tree utype = unsigned_type_for (type); }
+    (convert (minus:utype (convert:utype @1)
+                         (absu:utype @0)))))))
+(for cmp (le lt)
+ (simplify
+  (cond (cmp @0 integer_zerop) (minus @1 @0) (plus:c @0 @1))
+  (if (!TYPE_UNSIGNED (type)
+       && !TYPE_OVERFLOW_TRAPS (type)
+       && !TYPE_OVERFLOW_SANITIZED (type))
+   (with { tree utype = unsigned_type_for (type); }
+    (convert (plus:utype (convert:utype @1)
+                        (absu:utype @0))))))
+ (simplify
+  (cond (cmp @0 integer_zerop) (plus:c @0 @1) (minus @1 @0))
+  (if (!TYPE_UNSIGNED (type)
+       && !TYPE_OVERFLOW_TRAPS (type)
+       && !TYPE_OVERFLOW_SANITIZED (type))
+   (with { tree utype = unsigned_type_for (type); }
+    (convert (minus:utype (convert:utype @1)
+                         (absu:utype @0)))))))
+
 /* -(type)!A -> (type)A - 1.  */
 (simplify
  (negate (convert?:s (logical_inverted_value:s @0)))
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr56223-2.c 
b/gcc/testsuite/gcc.dg/tree-ssa/pr56223-2.c
new file mode 100644
index 00000000000..f03105683c4
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/pr56223-2.c
@@ -0,0 +1,63 @@
+/* PR tree-optimization/56223 */
+/* Verify wrapping and INT_MIN behavior of the ABSU-based replacement.  */
+/* { dg-do run } */
+/* { dg-options "-O2 -fwrapv" } */
+
+#define INT_MAX __INT_MAX__
+#define INT_MIN (-INT_MAX - 1)
+
+__attribute__ ((noipa)) int
+add_abs (int s, int x)
+{
+  if (x >= 0)
+    s += x;
+  else
+    s -= x;
+  return s;
+}
+
+__attribute__ ((noipa)) int
+sub_abs (int s, int x)
+{
+  if (x >= 0)
+    s -= x;
+  else
+    s += x;
+  return s;
+}
+
+int
+main (void)
+{
+  if (add_abs (10, 4) != 14)
+    __builtin_abort ();
+
+  if (add_abs (10, -4) != 14)
+    __builtin_abort ();
+
+  if (add_abs (INT_MIN, INT_MIN) != 0)
+    __builtin_abort ();
+
+  if (add_abs (INT_MAX, 1) != INT_MIN)
+    __builtin_abort ();
+
+  if (add_abs (0, INT_MIN) != INT_MIN)
+    __builtin_abort ();
+
+  if (sub_abs (10, 4) != 6)
+    __builtin_abort ();
+
+  if (sub_abs (10, -4) != 6)
+    __builtin_abort ();
+
+  if (sub_abs (INT_MIN, INT_MIN) != 0)
+    __builtin_abort ();
+
+  if (sub_abs (INT_MIN, 1) != INT_MAX)
+    __builtin_abort ();
+
+  if (sub_abs (0, INT_MIN) != INT_MIN)
+    __builtin_abort ();
+
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr56223-3.c 
b/gcc/testsuite/gcc.dg/tree-ssa/pr56223-3.c
new file mode 100644
index 00000000000..595a7df1b2f
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/pr56223-3.c
@@ -0,0 +1,25 @@
+/* PR tree-optimization/56223 */
+/* { dg-do compile } */
+/* { dg-options "-O2 -ftrapv -fdump-tree-phiopt2" } */
+
+int
+add_abs (int s, int x)
+{
+  if (x >= 0)
+    s += x;
+  else
+    s -= x;
+  return s;
+}
+
+int
+sub_abs (int s, int x)
+{
+  if (x >= 0)
+    s -= x;
+  else
+    s += x;
+  return s;
+}
+
+/* { dg-final { scan-tree-dump-not "ABSU_EXPR" "phiopt2" } } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr56223-4.c 
b/gcc/testsuite/gcc.dg/tree-ssa/pr56223-4.c
new file mode 100644
index 00000000000..f17f84219d9
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/pr56223-4.c
@@ -0,0 +1,25 @@
+/* PR tree-optimization/56223 */
+/* { dg-do compile } */
+/* { dg-options "-O2 -fsanitize=signed-integer-overflow -fdump-tree-phiopt2" } 
*/
+
+int
+add_abs (int s, int x)
+{
+  if (x >= 0)
+    s += x;
+  else
+    s -= x;
+  return s;
+}
+
+int
+sub_abs (int s, int x)
+{
+  if (x >= 0)
+    s -= x;
+  else
+    s += x;
+  return s;
+}
+
+/* { dg-final { scan-tree-dump-not "ABSU_EXPR" "phiopt2" } } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr56223.c 
b/gcc/testsuite/gcc.dg/tree-ssa/pr56223.c
new file mode 100644
index 00000000000..9a7c94bfb75
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/pr56223.c
@@ -0,0 +1,86 @@
+/* PR tree-optimization/56223 */
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-phiopt2" } */
+
+int
+add_ge (int s, int x)
+{
+  if (x >= 0)
+    s += x;
+  else
+    s -= x;
+  return s;
+}
+
+int
+add_gt (int s, int x)
+{
+  if (x > 0)
+    s += x;
+  else
+    s -= x;
+  return s;
+}
+
+int
+add_le (int s, int x)
+{
+  if (x <= 0)
+    s -= x;
+  else
+    s += x;
+  return s;
+}
+
+int
+add_lt (int s, int x)
+{
+  if (x < 0)
+    s -= x;
+  else
+    s += x;
+  return s;
+}
+
+int
+sub_ge (int s, int x)
+{
+  if (x >= 0)
+    s -= x;
+  else
+    s += x;
+  return s;
+}
+
+int
+sub_gt (int s, int x)
+{
+  if (x > 0)
+    s -= x;
+  else
+    s += x;
+  return s;
+}
+
+int
+sub_le (int s, int x)
+{
+  if (x <= 0)
+    s += x;
+  else
+    s -= x;
+  return s;
+}
+
+int
+sub_lt (int s, int x)
+{
+  if (x < 0)
+    s += x;
+  else
+    s -= x;
+  return s;
+}
+
+/* { dg-final { scan-tree-dump-times "ABSU_EXPR" 8 "phiopt2" } } */
+/* { dg-final { scan-tree-dump-not "if " "phiopt2" } } */
-- 
2.34.1

Reply via email to