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. Use vector-aware predicates
directly. Keep the integral type check before TYPE_OVERFLOW_WRAPS because
fixed-point vectors can reach the predicate, but TYPE_OVERFLOW_WRAPS does not
accept them. 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 | 27 ++++++++++--
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, 80 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..e41f4c19bf4 100644
--- a/gcc/match.pd
+++ b/gcc/match.pd
@@ -2428,11 +2428,32 @@ 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
+ {
+ bool negatable = (FLOAT_TYPE_P (type)
+ || (ANY_INTEGRAL_TYPE_P (type)
+ && TYPE_OVERFLOW_WRAPS (type)));
+ if (!negatable
+ && ANY_INTEGRAL_TYPE_P (type)
+ && !TYPE_OVERFLOW_SANITIZED (type)
+ && !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)