Recognize the absolute-difference idiom whose selector compares the
operands directly (a > b ? a - b : b - a), optionally widened, as
+/- abs (A - B).
The same-width case is not folded under -fsanitize=signed-integer-overflow
so the rewrite does not move the overflow the sanitizer reports.
PR tree-optimization/50856
gcc/ChangeLog:
* match.pd (A CMP B ? A - B : B - A -> +/- abs (A - B)): New
patterns.
gcc/testsuite/ChangeLog:
* gcc.dg/tree-ssa/pr50856.c: New test.
* g++.target/aarch64/pr50856.C: New test.
Signed-off-by: Eikansh Gupta <[email protected]>
---
gcc/match.pd | 33 +++++++++++++++++
gcc/testsuite/g++.target/aarch64/pr50856.C | 26 ++++++++++++++
gcc/testsuite/gcc.dg/tree-ssa/pr50856.c | 41 ++++++++++++++++++++++
3 files changed, 100 insertions(+)
create mode 100644 gcc/testsuite/g++.target/aarch64/pr50856.C
create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/pr50856.c
diff --git a/gcc/match.pd b/gcc/match.pd
index a7cec25dbad..7f480e43f7b 100644
--- a/gcc/match.pd
+++ b/gcc/match.pd
@@ -7154,6 +7154,39 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
(convert (negate (absu:utype @0))))
(negate (abs @0)))))
)
+ /* A >/>= B ? A - B : B - A -> abs (A - B)
+ with the operands optionally widened first. */
+ (for cmp (gt ge)
+ (simplify
+ (cnd (cmp @0 @1)
+ (minus@4 (convert1?@2 @0) (convert2?@3 @1))
+ (minus @3 @2))
+ (if (ANY_INTEGRAL_TYPE_P (type)
+ && !TYPE_UNSIGNED (type)
+ && types_match (TREE_TYPE (@0), TREE_TYPE (@1))
+ && (element_precision (@0) < element_precision (type)
+ || (types_match (TREE_TYPE (@0), type)
+ && TYPE_OVERFLOW_UNDEFINED (type)
+ /* Hoisting A - B out of the selector could move the
+ overflow the sanitizer reports. */
+ && !sanitize_flags_p (SANITIZE_SI_OVERFLOW)))
+ && (!VECTOR_TYPE_P (type)
+ || target_supports_op_p (type, ABS_EXPR, optab_vector)))
+ (abs @4))))
+ /* A </<= B ? A - B : B - A -> -abs (A - B). Widened operands only. */
+ (for cmp (lt le)
+ (simplify
+ (cnd (cmp @0 @1)
+ (minus@4 (convert1?@2 @0) (convert2?@3 @1))
+ (minus @3 @2))
+ (if (ANY_INTEGRAL_TYPE_P (type)
+ && !TYPE_UNSIGNED (type)
+ && types_match (TREE_TYPE (@0), TREE_TYPE (@1))
+ && element_precision (@0) < element_precision (type)
+ && (!VECTOR_TYPE_P (type)
+ || (target_supports_op_p (type, ABS_EXPR, optab_vector)
+ && target_supports_op_p (type, NEGATE_EXPR, optab_vector))))
+ (negate (abs @4)))))
)
/* -(type)!A -> (type)A - 1. */
diff --git a/gcc/testsuite/g++.target/aarch64/pr50856.C
b/gcc/testsuite/g++.target/aarch64/pr50856.C
new file mode 100644
index 00000000000..f10f16f3834
--- /dev/null
+++ b/gcc/testsuite/g++.target/aarch64/pr50856.C
@@ -0,0 +1,26 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-optimized" } */
+
+/* vector a CMP b ? a - b : b - a -> abs(a - b). Folds when the
+ target has a vector abs. */
+
+typedef short v8hi __attribute__ ((vector_size (16)));
+typedef int v4si __attribute__ ((vector_size (16)));
+
+v8hi abd_h (v8hi a, v8hi b)
+{
+ return a > b ? a - b : b - a;
+}
+
+v4si abd_s (v4si a, v4si b)
+{
+ return a >= b ? a - b : b - a;
+}
+
+/* Same-width -abs must not fold. */
+v8hi nabd_h (v8hi a, v8hi b)
+{
+ return a < b ? a - b : b - a;
+}
+
+/* { dg-final { scan-tree-dump-times "ABS_EXPR" 2 "optimized" } } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr50856.c
b/gcc/testsuite/gcc.dg/tree-ssa/pr50856.c
new file mode 100644
index 00000000000..3c0513efbbd
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/pr50856.c
@@ -0,0 +1,41 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-optimized" } */
+
+/* a CMP b ? a - b : b - a -> +/- abs (a - b). */
+
+int gt_w (unsigned char a, unsigned char b)
+{
+ int x = a, y = b;
+ return a > b ? x - y : y - x;
+}
+
+int ge_w (unsigned char a, unsigned char b)
+{
+ int x = a, y = b;
+ return a >= b ? x - y : y - x;
+}
+
+int lt_w (unsigned char a, unsigned char b)
+{
+ int x = a, y = b;
+ return a < b ? x - y : y - x;
+}
+
+int le_w (unsigned char a, unsigned char b)
+{
+ int x = a, y = b;
+ return a <= b ? x - y : y - x;
+}
+
+int gt_i (int a, int b)
+{
+ return a > b ? a - b : b - a;
+}
+
+/* Same-width -abs must not fold. */
+int lt_i (int a, int b)
+{
+ return a < b ? a - b : b - a;
+}
+
+/* { dg-final { scan-tree-dump-times "ABS_EXPR" 5 "optimized" } } */
--
2.34.1