> -----Original Message-----
> From: Andrew Pinski <[email protected]>
> Sent: 03 June 2026 20:58
> To: Artemiy Volkov <[email protected]>
> Cc: [email protected]; Tamar Christina <[email protected]>;
> Wilco Dijkstra <[email protected]>; Richard Earnshaw
> <[email protected]>; [email protected]; Alice Carlotti
> <[email protected]>; Alex Coplan <[email protected]>
> Subject: Re: [PATCH] aarch64: suppress duplication into sub-64-bit AdvSIMD
> vectors [PR125538]
>
> 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.
I was busy writing an elaborate response to this but Pinski beat me to it.
I would also indeed rather have you just add the RTL patterns for vec_duplate
of the partial modes. I don't think they really require that much churn.
Whether you take a subreg or just use a 128-bit/64-bit vector dup the semantic
remains the same, as long as we access the register in their intended modes
the result is sound.
So I think you should really just define the vec_duplicates and you only really
need
2 new RTL patterns.
Additionally I'd not want to lose that gen_vec_duplicate just works. Requiring
a target
specific function is always annoying. It works better if we can just support
the generic
abstractions.
Thanks,
Tamar
>
> 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
> >