On Wed, Jun 3, 2026 at 4:56 AM Artemiy Volkov <[email protected]> wrote:
>
> 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 am not so sure there on no obvious benefit.
Take:
```
#define vect4 __attribute__((vector_size(4)))
void f(vect4 signed char *a, signed char b)
{
*a = (vect4 signed char){b,b,b,b};
}
void f1(signed char *a, signed char b)
{
a[0] = b;
a[1] = b;
a[2] = b;
a[3] = b;
}
```
These could use a benifit of having a vec_dup of V4QI.
And it would be a good step forward of having V4QI/V2HI as not just a
container for initializations.
Thanks,
Andrea
>
> 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
>