As we don't have RTL support for duplicating values into partial AdvSIMD
vector modes, any expression like (vec_duplicate:V4QI (reg:QI)) is going
to be malformed. The ICE reported in PR125538 occurred because in
r17-897-g4ddae2a94a032d we started generating such expressions when doing
a splat of the most common element at aarch64.cc:25876.
To address the problem, this patch introduces the
aarch64_gen_vec_duplicate () wrapper, which handles the case of a
sub-64-bit destination mode by duplicating the source value into 64 bits
and wrapping that into a SUBREG expression. The alternative here would be
to add some more vec_duplicate RTL patterns, but that would lead to some
code churn in aarch64-simd.md and break a long-standing invariant for no
obvious benefit.
I've added the reduced testcase from the PR, as well as appended some
similar tests to vec_init_5.c and vec-init-23.c.
Regtested and bootstrapped on aarch64-linux-gnu.
PR target/125538
gcc/ChangeLog:
* config/aarch64/aarch64-protos.h (aarch64_gen_vec_duplicate):
Declare new function.
* config/aarch64/aarch64.cc (aarch64_gen_vec_duplicate): Define
it.
(aarch64_expand_vector_init_fallback): Use
aarch64_gen_vec_duplicate () instead of gen_vec_duplicate ().
gcc/testsuite/ChangeLog:
* gcc.target/aarch64/sve/vec_init_5.c: Add new 8/16-bit testcases.
* gcc.target/aarch64/vec-init-23.c: Likewise.
* gcc.target/aarch64/pr125538.c: New test.
---
gcc/config/aarch64/aarch64-protos.h | 1 +
gcc/config/aarch64/aarch64.cc | 36 ++++++++--
gcc/testsuite/gcc.target/aarch64/pr125538.c | 20 ++++++
.../gcc.target/aarch64/sve/vec_init_5.c | 69 ++++++++++++++++++
.../gcc.target/aarch64/vec-init-23.c | 71 ++++++++++++++++++-
5 files changed, 191 insertions(+), 6 deletions(-)
create mode 100644 gcc/testsuite/gcc.target/aarch64/pr125538.c
diff --git a/gcc/config/aarch64/aarch64-protos.h
b/gcc/config/aarch64/aarch64-protos.h
index 513b556398f..3e679f6d36a 100644
--- a/gcc/config/aarch64/aarch64-protos.h
+++ b/gcc/config/aarch64/aarch64-protos.h
@@ -1014,6 +1014,7 @@ rtx aarch64_mask_from_zextract_ops (rtx, rtx);
rtx aarch64_return_addr_rtx (void);
rtx aarch64_return_addr (int, rtx);
rtx aarch64_simd_gen_const_vector_dup (machine_mode, HOST_WIDE_INT);
+rtx aarch64_gen_vec_duplicate (machine_mode, rtx);
rtx aarch64_gen_shareable_zero (machine_mode);
bool aarch64_split_simd_shift_p (rtx_insn *);
bool aarch64_simd_mem_operand_p (rtx);
diff --git a/gcc/config/aarch64/aarch64.cc b/gcc/config/aarch64/aarch64.cc
index 5a859e12b1a..4c7173c162a 100644
--- a/gcc/config/aarch64/aarch64.cc
+++ b/gcc/config/aarch64/aarch64.cc
@@ -25039,6 +25039,30 @@ aarch64_gen_shareable_zero (machine_mode mode)
return lowpart_subreg (mode, reg, GET_MODE (reg));
}
+/* Duplicate value X into a vector of type MODE. In case MODE is a
+ sub-64-bit mode and the result isn't a const_vector, duplicate into a
+ full register and take a SUBREG of that. */
+
+rtx
+aarch64_gen_vec_duplicate (machine_mode mode, rtx x)
+{
+ gcc_assert (VECTOR_MODE_P (mode));
+
+ if (!aarch64_advsimd_sub_dword_mode_p (mode))
+ return gen_vec_duplicate (mode, x);
+
+ if (valid_for_const_vector_p (mode, x))
+ return gen_const_vec_duplicate (mode, x);
+
+ machine_mode dup_mode = mode_for_vector (GET_MODE_INNER (mode),
+ 64 / GET_MODE_BITSIZE (GET_MODE_INNER (mode)))
+ .require ();
+
+ rtx reg = gen_reg_rtx (dup_mode);
+ aarch64_emit_move (reg, gen_rtx_VEC_DUPLICATE (dup_mode, x));
+ return lowpart_subreg (mode, reg, dup_mode);
+}
+
/* INSN is some form of extension or shift that can be split into a
permutation involving a shared zero. Return true if we should
perform such a split.
@@ -25699,7 +25723,7 @@ aarch64_expand_vector_init_fallback (rtx target, rtx
vals)
2 * GET_MODE_SIZE (narrow_mode)));
if (rtx_equal_p (v0, v1))
aarch64_emit_move (target,
- gen_vec_duplicate (mode,
+ aarch64_gen_vec_duplicate (mode,
force_reg (narrow_mode, v0)));
else
emit_insn (gen_aarch64_vec_concat (narrow_mode, target,
@@ -25733,7 +25757,7 @@ aarch64_expand_vector_init_fallback (rtx target, rtx
vals)
if (all_same)
{
rtx x = force_reg (inner_mode, v0);
- aarch64_emit_move (target, gen_vec_duplicate (mode, x));
+ aarch64_emit_move (target, aarch64_gen_vec_duplicate (mode, x));
return;
}
@@ -25769,7 +25793,8 @@ aarch64_expand_vector_init_fallback (rtx target, rtx
vals)
RTVEC_ELT (new_vals, i) = XVECEXP (vals, 0, i);
aarch64_expand_vector_init (new_target,
gen_rtx_PARALLEL (subv_mode, new_vals));
- aarch64_emit_move (target, gen_vec_duplicate (mode, new_target));
+ aarch64_emit_move (target,
+ aarch64_gen_vec_duplicate (mode, new_target));
return;
}
}
@@ -25862,7 +25887,8 @@ aarch64_expand_vector_init_fallback (rtx target, rtx
vals)
if (const_elem)
{
maxelement = const_elem_pos;
- aarch64_emit_move (target, gen_vec_duplicate (mode, const_elem));
+ aarch64_emit_move (target,
+ aarch64_gen_vec_duplicate (mode, const_elem));
}
else
{
@@ -25873,7 +25899,7 @@ aarch64_expand_vector_init_fallback (rtx target, rtx
vals)
else
{
rtx x = force_reg (inner_mode, XVECEXP (vals, 0, maxelement));
- aarch64_emit_move (target, gen_vec_duplicate (mode, x));
+ aarch64_emit_move (target, aarch64_gen_vec_duplicate (mode, x));
}
/* Insert the rest. */
diff --git a/gcc/testsuite/gcc.target/aarch64/pr125538.c
b/gcc/testsuite/gcc.target/aarch64/pr125538.c
new file mode 100644
index 00000000000..f0cdcd58dfb
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/pr125538.c
@@ -0,0 +1,20 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -march=armv9.5-a" } */
+/* { dg-final { check-function-bodies "**" "" "" } } */
+
+#define vect16 __attribute__((vector_size(16)))
+
+vect16 char fff(char _292, char _145, char _231)
+{
+ return (vect16 char) {_292, _145, _145, _231, _292, _145, _145, _231,
_292, _145, _145, _231, _292, _145, _145, _231};
+}
+
+/*
+** fff:
+** bfi w0, w1, 8, 8
+** bfi w1, w2, 8, 8
+** dup v31\.4h, w0
+** dup v0\.4h, w1
+** zip1 v0\.16b, v31\.16b, v0\.16b
+** ret
+*/
diff --git a/gcc/testsuite/gcc.target/aarch64/sve/vec_init_5.c
b/gcc/testsuite/gcc.target/aarch64/sve/vec_init_5.c
index 99e04aac265..112a0eafc7a 100644
--- a/gcc/testsuite/gcc.target/aarch64/sve/vec_init_5.c
+++ b/gcc/testsuite/gcc.target/aarch64/sve/vec_init_5.c
@@ -152,6 +152,27 @@
** ret
*/
+/*
+** test_int8_14:
+** bfi w0, w1, 8, 8
+** bfi w1, w2, 8, 8
+** dup v31\.4h, w0
+** dup v30\.4h, w1
+** zip1 v31\.16b, v31\.16b, v30\.16b
+** dup z0\.q, z31.q\[0\]
+** ret
+*/
+
+/*
+** test_int8_15:
+** bfi w0, w2, 8, 8
+** dup v30\.8b, w1
+** dup v31\.4h, w0
+** zip1 v31\.16b, v31\.16b, v30\.16b
+** dup z0\.q, z31\.q\[0\]
+** ret
+*/
+
/*
** test_float16_1:
** fcvt h0, s0
@@ -236,6 +257,33 @@
** ret
*/
+/*
+** test_float16_9:
+** fcvt h1, s1
+** fcvt h2, s2
+** fcvt h0, s0
+** uzp1 v0\.4h, v0\.4h, v1\.4h
+** uzp1 v1\.4h, v1\.4h, v2\.4h
+** dup v0\.2s, v0\.s\[0\]
+** dup v1\.2s, v1\.s\[0\]
+** zip1 v0\.8h, v0\.8h, v1\.8h
+** dup z0\.q, z0.q\[0\]
+** ret
+*/
+
+/*
+** test_float16_10:
+** fcvt h2, s2
+** fcvt h0, s0
+** fcvt h1, s1
+** uzp1 v0\.4h, v0\.4h, v2\.4h
+** dup v1\.4h, v1\.h\[0\]
+** dup v0\.2s, v0\.s\[0\]
+** zip1 v0\.8h, v0\.8h, v1\.8h
+** dup z0\.q, z0.q\[0\]
+** ret
+*/
+
/*
** test_int16_1:
** mov z0\.h, w0
@@ -310,6 +358,27 @@
** ret
*/
+/*
+** test_int16_9:
+** bfi w0, w1, 16, 16
+** bfi w1, w2, 16, 16
+** dup v31\.2s, w0
+** dup v30\.2s, w1
+** zip1 v31\.8h, v31\.8h, v30\.8h
+** dup z0\.q, z31\.q\[0\]
+** ret
+*/
+
+/*
+** test_int16_10:
+** bfi w0, w2, 16, 16
+** dup v30\.4h, w1
+** dup v31\.2s, w0
+** zip1 v31\.8h, v31\.8h, v30\.8h
+** dup z0\.q, z31\.q\[0\]
+** ret
+*/
+
/*
** test_float32_1:
** mov z0\.s, s0
diff --git a/gcc/testsuite/gcc.target/aarch64/vec-init-23.c
b/gcc/testsuite/gcc.target/aarch64/vec-init-23.c
index 8c154f3680d..4721b068366 100644
--- a/gcc/testsuite/gcc.target/aarch64/vec-init-23.c
+++ b/gcc/testsuite/gcc.target/aarch64/vec-init-23.c
@@ -41,7 +41,11 @@
TESTCASE (TYPE, ETYPE, T, 8, 12, x16, x0, x1, 0, 1, x2, x3, 2, 3,\
x0, x1, 0, 1, x2, x3, 2, 3)\
TESTCASE (TYPE, ETYPE, T, 8, 13, x16, 0, 1, x0, x1, 2, 3, x2, x3,\
- 0, 1, x0, x1, 2, 3, x2, x3)
+ 0, 1, x0, x1, 2, 3, x2, x3) \
+ TESTCASE (TYPE, ETYPE, T, 8, 14, x16, x0, x1, x1, x2, x0, x1, x1, x2,\
+ x0, x1, x1, x2, x0, x1, x1, x2) \
+ TESTCASE (TYPE, ETYPE, T, 8, 15, x16, x0, x1, x2, x1, x0, x1, x2, x1,\
+ x0, x1, x2, x1, x0, x1, x2, x1)
#define TEST_16(TYPE, ETYPE, T)\
TESTCASE (TYPE, ETYPE, T, 16, 1, x8, x0, x0, x0, x0, x0, x0, x0, x0)\
@@ -52,6 +56,8 @@
TESTCASE (TYPE, ETYPE, T, 16, 6, x8, x0, x1, 0, 1, x0, x1, 0, 1)\
TESTCASE (TYPE, ETYPE, T, 16, 7, x8, 0, 1, x0, x1, 0, 1, x0, x1)\
TESTCASE (TYPE, ETYPE, T, 16, 8, x8, 0, x0, 1, x1, 0, x0, 1, x1)\
+ TESTCASE (TYPE, ETYPE, T, 16, 9, x8, x0, x1, x1, x2, x0, x1, x1, x2)\
+ TESTCASE (TYPE, ETYPE, T, 16, 10, x8, x0, x1, x2, x1, x0, x1, x2, x1)
#define TEST_32(TYPE, ETYPE, T)\
TESTCASE (TYPE, ETYPE, T, 32, 1, x4, x0, x0, x0, x0)\
@@ -205,6 +211,25 @@ TEST_64(int, int64_t, s)
** ret
*/
+/*
+** test_int8_14:
+** bfi w0, w1, 8, 8
+** bfi w1, w2, 8, 8
+** dup v31\.4h, w0
+** dup v0\.4h, w1
+** zip1 v0\.16b, v31\.16b, v0\.16b
+** ret
+*/
+
+/*
+** test_int8_15:
+** bfi w0, w2, 8, 8
+** dup v0.8b, w1
+** dup v31.4h, w0
+** zip1 v0.16b, v31.16b, v0.16b
+** ret
+*/
+
/*
** test_float16_1:
** fcvt h0, s0
@@ -286,6 +311,31 @@ TEST_64(int, int64_t, s)
** ret
*/
+/*
+** test_float16_9:
+** fcvt h1, s1
+** fcvt h2, s2
+** fcvt h0, s0
+** uzp1 v0\.4h, v0\.4h, v1\.4h
+** uzp1 v1\.4h, v1\.4h, v2\.4h
+** dup v0\.2s, v0\.s\[0\]
+** dup v1\.2s, v1\.s\[0\]
+** zip1 v0\.8h, v0\.8h, v1\.8h
+** ret
+*/
+
+/*
+** test_float16_10:
+** fcvt h2, s2
+** fcvt h0, s0
+** fcvt h1, s1
+** uzp1 v0\.4h, v0\.4h, v2\.4h
+** dup v1\.4h, v1\.h\[0\]
+** dup v0\.2s, v0\.s\[0\]
+** zip1 v0\.8h, v0\.8h, v1\.8h
+** ret
+*/
+
/*
** test_int16_1:
** dup v0\.8h, w0
@@ -356,6 +406,25 @@ TEST_64(int, int64_t, s)
** ret
*/
+/*
+** test_int16_9:
+** bfi w0, w1, 16, 16
+** bfi w1, w2, 16, 16
+** dup v31\.2s, w0
+** dup v0\.2s, w1
+** zip1 v0\.8h, v31\.8h, v0\.8h
+** ret
+*/
+
+/*
+** test_int16_10:
+** bfi w0, w2, 16, 16
+** dup v0\.4h, w1
+** dup v31\.2s, w0
+** zip1 v0\.8h, v31\.8h, v0\.8h
+** ret
+*/
+
/*
** test_float32_1:
** dup v0\.4s, v0\.s\[0\]
--
2.43.0