]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
tree-optimization: Recognize add/sub absolute-value idiom [PR56223] master trunk
authorNaveen <naveen.siddegowda@oss.qualcomm.com>
Wed, 5 Aug 2026 07:52:53 +0000 (00:52 -0700)
committerNaveen <naveen.siddegowda@oss.qualcomm.com>
Wed, 5 Aug 2026 07:52:53 +0000 (00:52 -0700)
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 <naveen.siddegowda@oss.qualcomm.com>
gcc/match.pd
gcc/testsuite/gcc.dg/tree-ssa/pr56223-2.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/tree-ssa/pr56223-3.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/tree-ssa/pr56223-4.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/tree-ssa/pr56223.c [new file with mode: 0644]

index d5160d87e3048d7736d8bd9712fb8f32140e07fb..2545d62b4ab4ba6882c5846d30e90befc73a50ce 100644 (file)
@@ -7270,6 +7270,54 @@ 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.  */
+
+#if GIMPLE
+(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)))))))
+#endif
+
 /* -(type)!A -> (type)A - 1.  */
 (simplify
  (negate (convert?:s (logical_inverted_value:s @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 (file)
index 0000000..f031056
--- /dev/null
@@ -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 (file)
index 0000000..595a7df
--- /dev/null
@@ -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 (file)
index 0000000..f17f842
--- /dev/null
@@ -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 (file)
index 0000000..9a7c94b
--- /dev/null
@@ -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" } } */