PHI-OPT fails to simplify conditional accumulation of an absolute value:
if (x >= 0)
y += x;
else
y -= x;
For signed integral types, perform the addition 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 apply 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.
Signed-off-by: Naveen <[email protected]>
---
gcc/match.pd | 35 +++++++++++++++++
gcc/testsuite/gcc.dg/tree-ssa/pr56223-2.c | 39 +++++++++++++++++++
gcc/testsuite/gcc.dg/tree-ssa/pr56223.c | 46 +++++++++++++++++++++++
3 files changed, 120 insertions(+)
create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/pr56223-2.c
create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/pr56223.c
diff --git a/gcc/match.pd b/gcc/match.pd
index d1a12c35ed3..70005a6fda2 100644
--- a/gcc/match.pd
+++ b/gcc/match.pd
@@ -7243,6 +7243,41 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
)
)
+
+ /* X >=/> 0 ? Y + X : Y - X same as Y + abs (X).
+ Build the addition 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 (INTEGRAL_TYPE_P (type)
+ && types_match (type, @0)
+ && types_match (type, @1)
+ && !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)))))))
+
+ /* X <=/< 0 ? Y - X : Y + X same as Y + abs (X).
+ Build the addition in an unsigned type for integral types so the
+ replacement does not introduce signed overflow. */
+ (for cmp (le lt)
+ (simplify
+ (cond (cmp @0 integer_zerop) (minus @1 @0) (plus:c @0 @1))
+ (if (INTEGRAL_TYPE_P (type)
+ && types_match (type, @0)
+ && types_match (type, @1)
+ && !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)))))))
+
/* -(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..76ce731ad76
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/pr56223-2.c
@@ -0,0 +1,39 @@
+/* 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
+f (int s, int x)
+{
+ if (x >= 0)
+ s += x;
+ else
+ s -= x;
+ return s;
+}
+
+int
+main (void)
+{
+ if (f (10, 4) != 14)
+ __builtin_abort ();
+
+ if (f (10, -4) != 14)
+ __builtin_abort ();
+
+ if (f (INT_MIN, INT_MIN) != 0)
+ __builtin_abort ();
+
+ if (f (INT_MAX, 1) != INT_MIN)
+ __builtin_abort ();
+
+ if (f (0, INT_MIN) != INT_MIN)
+ __builtin_abort ();
+
+ return 0;
+}
+
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..36e3c50f2d4
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/pr56223.c
@@ -0,0 +1,46 @@
+/* PR tree-optimization/56223 */
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-phiopt2" } */
+
+int
+f_ge (int s, int x)
+{
+ if (x >= 0)
+ s += x;
+ else
+ s -= x;
+ return s;
+}
+
+int
+f_gt (int s, int x)
+{
+ if (x > 0)
+ s += x;
+ else
+ s -= x;
+ return s;
+}
+
+int
+f_le (int s, int x)
+{
+ if (x <= 0)
+ s -= x;
+ else
+ s += x;
+ return s;
+}
+
+int
+f_lt (int s, int x)
+{
+ if (x < 0)
+ s -= x;
+ else
+ s += x;
+ return s;
+}
+
+/* { dg-final { scan-tree-dump-times "ABSU_EXPR" 4 "phiopt2" } } */
+/* { dg-final { scan-tree-dump-not "if " "phiopt2" } } */
--
2.34.1