[PATCH v2] MATCH: Fold `A CMP B ? A - B : B - A` to abs of difference [PR50856]

Eikansh Gupta <[email protected]>
Newsgroups gmane.comp.gcc.patches
Message-ID <[email protected]>
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.

The transformation A </<= B ? A - B : B - A -> -abs (A - B) is only for
widened operation. For same precision operands it can introduce new
undefined behaviour for case a=0 and b=INT_MIN. (b-a) is defined for
given values. But -abs(a-b) overflows.

Transforming to abs(b-a) does not solve it either as for a=INT_MIN and
b=0, (b-a) overflows.

	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                               | 36 +++++++++++++++++++
 gcc/testsuite/g++.target/aarch64/pr50856.C | 26 ++++++++++++++
 gcc/testsuite/gcc.dg/tree-ssa/pr50856.c    | 41 ++++++++++++++++++++++
 3 files changed, 103 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..0e9e52a3387 100644
--- a/gcc/match.pd
+++ b/gcc/match.pd
@@ -7154,6 +7154,42 @@ 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)
+	    /* The below checks are for same width operands.  */
+	    || (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.
+    This pattern is only for widened operands as for same precision operands
+    there can be a new undefined behaviour for case a=0 and b=INT_MIN.  */
+ (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
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.