[PATCH 2/3] match.pd: canonicalize subtraction of an integral vector constant

<[email protected]>
Newsgroups gmane.comp.gcc.patches
Message-ID <[email protected]>
From: Kyrylo Tkachov <[email protected]>

The A - B -> A + (-B) rule uses negate_expr_p to decide whether B can be
negated cheaply.  The predicate rejects non-wrapping integral vector
constants, even when every encoded element can be negated without overflow.
This leaves vector subtraction in a noncanonical form and can hide an
encodable constant from target expansion.

  typedef int v4si __attribute__ ((vector_size (16)));

  v4si
  f (v4si x)
  {
    return x - (v4si) { -16711935, -16711935, -16711935, -16711935 };
  }

aarch64 -O2 before:

  f:
          adrp    x0, .LC0
          ldr     q31, [x0, #:lo12:.LC0]
          sub     v0.4s, v0.4s, v31.4s
          ret

The function also needs a 16-byte constant in .rodata.

After:

  f:
          movi    v31.8h, 0xff
          add     v0.4s, v0.4s, v31.4s
          ret

Accept a non-stepped integral vector constant when every encoded element can
be negated without overflow.  A stepped encoding can extrapolate an unencoded
signed minimum, so keep it in subtraction form.  Unsigned and -fwrapv vectors
already wrap and do not need an element scan.  Reject fixed-point vectors
before testing overflow wrapping.  Keep a signed minimum element and an
overflow-sanitized subtraction.

The canonical form remains visible before dead-code elimination in one
existing forwprop dump.  Adjust its addition count.

Bootstrapped and tested on aarch64-none-linux-gnu and x86_64-pc-linux-gnu.
Ok for trunk?
Thanks,
Kyrill

gcc/ChangeLog:

	* match.pd (negate_expr_p): Handle non-wrapping integral vector
	constants.

gcc/testsuite/ChangeLog:

	* gcc.dg/tree-ssa/forwprop-27.c: Adjust the expected addition count.
	* gcc.dg/tree-ssa/vector-sub-const-1.c: New test.
	* gcc.dg/tree-ssa/vector-sub-const-2.c: Likewise.

Signed-off-by: Kyrylo Tkachov <[email protected]>
---
 gcc/match.pd                                  | 28 ++++++++++--
 gcc/testsuite/gcc.dg/tree-ssa/forwprop-27.c   |  2 +-
 .../gcc.dg/tree-ssa/vector-sub-const-1.c      | 43 +++++++++++++++++++
 .../gcc.dg/tree-ssa/vector-sub-const-2.c      | 12 ++++++
 4 files changed, 81 insertions(+), 4 deletions(-)
 create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/vector-sub-const-1.c
 create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/vector-sub-const-2.c

diff --git a/gcc/match.pd b/gcc/match.pd
index eae8717bcfe..2c88e56b366 100644
--- a/gcc/match.pd
+++ b/gcc/match.pd
@@ -2428,11 +2428,33 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
 (match negate_expr_p
  REAL_CST
  (if (REAL_VALUE_NEGATIVE (TREE_REAL_CST (t)))))
-/* VECTOR_CST handling of non-wrapping types would recurse in unsupported
-   ways.  */
+/* A non-stepped, non-wrapping integral vector constant can be negated when
+   none of its encoded elements is the minimum value.  */
 (match negate_expr_p
  VECTOR_CST
- (if (FLOAT_TYPE_P (TREE_TYPE (type)) || TYPE_OVERFLOW_WRAPS (type))))
+ (with
+  {
+    tree etype = TREE_TYPE (type);
+    bool negatable = (FLOAT_TYPE_P (etype)
+		      || (INTEGRAL_TYPE_P (etype)
+			  && TYPE_OVERFLOW_WRAPS (type)));
+    if (!negatable
+	&& INTEGRAL_TYPE_P (etype)
+	&& !TYPE_OVERFLOW_SANITIZED (etype)
+	&& !VECTOR_CST_STEPPED_P (t))
+      {
+	negatable = true;
+	for (unsigned int i = 0; i < vector_cst_encoded_nelts (t); ++i)
+	  if (TREE_CODE (VECTOR_CST_ENCODED_ELT (t, i)) != INTEGER_CST
+	      || !may_negate_without_overflow_p
+		   (VECTOR_CST_ENCODED_ELT (t, i)))
+	    {
+	      negatable = false;
+	      break;
+	    }
+      }
+  }
+  (if (negatable))))
 (match negate_expr_p
  (minus @0 @1)
  (if ((ANY_INTEGRAL_TYPE_P (type) && TYPE_OVERFLOW_WRAPS (type))
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/forwprop-27.c b/gcc/testsuite/gcc.dg/tree-ssa/forwprop-27.c
index 6c71a4fc81c..29d39c67c79 100644
--- a/gcc/testsuite/gcc.dg/tree-ssa/forwprop-27.c
+++ b/gcc/testsuite/gcc.dg/tree-ssa/forwprop-27.c
@@ -33,7 +33,7 @@ void i (V *v1, V *v2){
   *v2 = (c1-*v2)+c2;
 }
 
-/* { dg-final { scan-tree-dump-times "\\\+" 1 "forwprop1"} } */
+/* { dg-final { scan-tree-dump-times "\\\+" 2 "forwprop1"} } */
 /* { dg-final { scan-tree-dump "{ 0, 4 }" "forwprop1"} } */
 /* { dg-final { scan-tree-dump "{ 37, -5 }" "forwprop1"} } */
 /* { dg-final { scan-tree-dump "{ 27, 23 }" "forwprop1"} } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/vector-sub-const-1.c b/gcc/testsuite/gcc.dg/tree-ssa/vector-sub-const-1.c
new file mode 100644
index 00000000000..56e1c146d70
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/vector-sub-const-1.c
@@ -0,0 +1,43 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -Wno-psabi -fdump-tree-forwprop1" } */
+
+typedef __INT32_TYPE__ v4si __attribute__ ((vector_size (16)));
+typedef __UINT32_TYPE__ v4ui __attribute__ ((vector_size (16)));
+
+v4si
+sub_splat (v4si x)
+{
+  return x - (v4si) { 1, 1, 1, 1 };
+}
+
+v4si
+sub_mixed (v4si x)
+{
+  return x - (v4si) { 1, -2, 3, -4 };
+}
+
+v4si
+sub_encodable (v4si x)
+{
+  return x - (v4si) { -16711935, -16711935, -16711935, -16711935 };
+}
+
+v4si
+keep_min (v4si x)
+{
+  return x - (v4si) { -__INT32_MAX__ - 1, 1, 1, 1 };
+}
+
+v4si
+keep_stepped_min (v4si x)
+{
+  return x - (v4si) ((v4ui) { 2147483644u, 2147483645u,
+			       2147483646u, 2147483647u }
+		      + (v4ui) { 1, 1, 1, 1 });
+}
+
+/* { dg-final { scan-tree-dump-times " \\+ \\{ -1, -1, -1, -1 \\}" 1 "forwprop1" } } */
+/* { dg-final { scan-tree-dump-times " \\+ \\{ -1, 2, -3, 4 \\}" 1 "forwprop1" } } */
+/* { dg-final { scan-tree-dump-times " \\+ \\{ 16711935, 16711935, 16711935, 16711935 \\}" 1 "forwprop1" } } */
+/* { dg-final { scan-tree-dump-times " - \\{ -2147483648, 1, 1, 1 \\}" 1 "forwprop1" } } */
+/* { dg-final { scan-tree-dump-times " - \\{ 2147483645, 2147483646, 2147483647, -2147483648 \\}" 1 "forwprop1" } } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/vector-sub-const-2.c b/gcc/testsuite/gcc.dg/tree-ssa/vector-sub-const-2.c
new file mode 100644
index 00000000000..27de9e77be2
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/vector-sub-const-2.c
@@ -0,0 +1,12 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -Wno-psabi -fsanitize=signed-integer-overflow -fdump-tree-forwprop1" } */
+
+typedef __INT32_TYPE__ v4si __attribute__ ((vector_size (16)));
+
+v4si
+f (v4si x)
+{
+  return x - (v4si) { 1, 1, 1, 1 };
+}
+
+/* { dg-final { scan-tree-dump-times "\\.UBSAN_CHECK_SUB" 1 "forwprop1" } } */
-- 
2.50.1 (Apple Git-155)
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.