Currently, with Advanced SIMD
vector char
f (vector char a)
{
return __builtin_shuffle (a, (vector char){ 15, 14, 13, 12, 11, 10, 9, 8,
7, 6, 5, 4, 3, 2, 1, 0 });
}
generates:
f:
adrp x0, .LANCHOR0
ldr q31, [x0, #:lo12:.LANCHOR0]
tbl v0.16b, {v0.16b}, v31.16b
ret
.set .LANCHOR0,. + 0
.LC0:
.byte 15
.byte 14
.byte 13
.byte 12
.byte 11
.byte 10
.byte 9
.byte 8
.byte 7
.byte 6
.byte 5
.byte 4
.byte 3
.byte 2
.byte 1
.byte 0
With this patch, it generates REV64 followed by EXT:
f:
rev64 v0.16b, v0.16b
ext v0.16b, v0.16b, v0.16b, #8
ret
Bootstrapped and tested on aarch64_linux_gnu.
Changes since v1:
* v2: Add loop check to avoid generating REV64+EXT if the shuffle is inside a
loop.
PR target/102055
gcc/ChangeLog:
* config/aarch64/aarch64.cc (is_bb_in_loop): New.
(aarch64_evpc_rev64_ext): New.
(aarch64_expand_vec_perm_const_1): Call aarch64_evpc_rev64_ext.
gcc/testsuite/ChangeLog:
* gcc.target/aarch64/pr102055-loop.c: New test.
* gcc.target/aarch64/pr102055.c: New test.
Signed-off-by: Pengxuan Zheng <[email protected]>
---
gcc/config/aarch64/aarch64.cc | 44 +++++++++++++++++++
.../gcc.target/aarch64/pr102055-loop.c | 16 +++++++
gcc/testsuite/gcc.target/aarch64/pr102055.c | 42 ++++++++++++++++++
3 files changed, 102 insertions(+)
create mode 100644 gcc/testsuite/gcc.target/aarch64/pr102055-loop.c
create mode 100644 gcc/testsuite/gcc.target/aarch64/pr102055.c
diff --git a/gcc/config/aarch64/aarch64.cc b/gcc/config/aarch64/aarch64.cc
index ec9fe25e9cc..081fc381713 100644
--- a/gcc/config/aarch64/aarch64.cc
+++ b/gcc/config/aarch64/aarch64.cc
@@ -28394,6 +28394,48 @@ aarch64_evpc_rev_global (struct expand_vec_perm_d *d)
return true;
}
+static bool
+is_bb_in_loop (basic_block bb)
+{
+ if (!bb || !cfun || !cfun->curr_properties)
+ return false;
+
+ return bb_loop_depth (bb) > 0;
+}
+
+/* Recognize patterns for the Advanced SIMD REV64 + EXT insns, which reverse
+ elements within a full vector. */
+
+static bool
+aarch64_evpc_rev64_ext (struct expand_vec_perm_d *d)
+{
+ poly_uint64 nelt = d->perm.length ();
+
+ if (!d->one_vector_p || d->vec_flags != VEC_ADVSIMD)
+ return false;
+
+ if (!d->perm.series_p (0, 1, nelt - 1, -1))
+ return false;
+
+ if (is_bb_in_loop (gimple_bb (currently_expanding_gimple_stmt)))
+ return false;
+
+ if (d->testing_p)
+ return true;
+
+ rtx tmp1 = gen_reg_rtx (d->vmode);
+ rtx tmp2 = gen_reg_rtx (V16QImode);
+ rtx unspec_rev64
+ = gen_rtx_UNSPEC (d->vmode, gen_rtvec (1, d->op0), UNSPEC_REV64);
+ emit_set_insn (tmp1, unspec_rev64);
+ rtvec vec = gen_rtvec (3, gen_lowpart (V16QImode, tmp1),
+ gen_lowpart (V16QImode, tmp1), GEN_INT (8));
+ rtx unspec_ext = gen_rtx_UNSPEC (V16QImode, vec, UNSPEC_EXT);
+ emit_set_insn (tmp2, unspec_ext);
+ emit_set_insn (d->target, gen_lowpart (d->vmode, tmp2));
+ return true;
+}
+
static bool
aarch64_evpc_dup (struct expand_vec_perm_d *d)
{
@@ -28858,6 +28900,8 @@ aarch64_expand_vec_perm_const_1 (struct
expand_vec_perm_d *d)
return true;
else if (aarch64_evpc_hvla (d))
return true;
+ else if (aarch64_evpc_rev64_ext (d))
+ return true;
else if (aarch64_evpc_reencode (d))
return true;
diff --git a/gcc/testsuite/gcc.target/aarch64/pr102055-loop.c
b/gcc/testsuite/gcc.target/aarch64/pr102055-loop.c
new file mode 100644
index 00000000000..26ec52e37d7
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/pr102055-loop.c
@@ -0,0 +1,16 @@
+/* { dg-do compile } */
+/* { dg-options "-O2" } */
+
+/* Check that the shuffle is NOT optimized to rev64+ext inside a loop. */
+/* { dg-final { scan-assembler-not "rev64" } } */
+
+#define vector __attribute__ ((vector_size (16)))
+
+void
+f (vector char *dst, vector char *src, int n)
+{
+ for (int i = 0; i < n; i++)
+ dst[i]
+ = __builtin_shuffle (src[i], (vector char) {15, 14, 13, 12, 11, 10, 9, 8,
+ 7, 6, 5, 4, 3, 2, 1, 0});
+}
diff --git a/gcc/testsuite/gcc.target/aarch64/pr102055.c
b/gcc/testsuite/gcc.target/aarch64/pr102055.c
new file mode 100644
index 00000000000..39b6355fc66
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/pr102055.c
@@ -0,0 +1,42 @@
+/* { dg-do compile } */
+/* { dg-options "-O2" } */
+/* { dg-final { check-function-bodies "**" "" "" } } */
+
+#define vector __attribute__ ((vector_size (16)))
+
+/*
+** f:
+** rev64 v([0-9]+).16b, v0.16b
+** ext v0.16b, v\1.16b, v\1.16b, #8
+** ret
+*/
+vector char
+f (vector char a)
+{
+ return __builtin_shuffle (a, (vector char){ 15, 14, 13, 12, 11, 10, 9, 8,
+ 7, 6, 5, 4, 3, 2, 1, 0 });
+}
+
+/*
+** f1:
+** rev64 v([0-9]+).8h, v0.8h
+** ext v0.16b, v\1.16b, v\1.16b, #8
+** ret
+*/
+vector short
+f1 (vector short a)
+{
+ return __builtin_shuffle (a, (vector short){ 7, 6, 5, 4, 3, 2, 1, 0 });
+}
+
+/*
+** f2:
+** rev64 v([0-9]+).4s, v0.4s
+** ext v0.16b, v\1.16b, v\1.16b, #8
+** ret
+*/
+vector int
+f2 (vector int a)
+{
+ return __builtin_shuffle (a, (vector int){ 3, 2, 1, 0 });
+}
--
2.34.1