Ping. https://gcc.gnu.org/pipermail/gcc-patches/2026-October/733713.html
Thanks, Kyrill > On 7 Oct 2026, at 15:21, Kyrylo Tkachov <[email protected]> wrote: > > From: Kyrylo Tkachov <[email protected]> > > The patterns that insert a scalar into element 0 of a zero SVE vector > accept the scalar only in an FP register. A scalar in a general > register needs an extra move: > > fmov s0, w0 > fmov s0, s0 > > and, for 8-bit elements: > > dup v31.8b, w0 > fmov h0, h31 > and z0.h, z0.h, #0xff > > Add alternatives that take the scalar from a general register. FMOV > from a general register also clears the rest of the vector. > > Bootstrapped and tested on aarch64-none-linux-gnu. > Ok for trunk? > Thanks, > Kyrill > > Cc: Tamar Christina <[email protected]> > Cc: Wilco Dijkstra <[email protected]> > > gcc/ChangeLog: > > * config/aarch64/aarch64-sve.md > (*aarch64_vec_shl_insert_into_zero_<mode>): Add an alternative for > general registers. Give the instruction type per alternative. > (*aarch64_vec_shl_insert_into_zero_vnx16qi): Likewise. > > gcc/testsuite/ChangeLog: > > * gcc.target/aarch64/sve/copsi.c (func_init3): Update expected > assembly. > * gcc.target/aarch64/sve/insr-zero-gpr.c: New test. > * gcc.target/aarch64/sve/insr-zero-gpr_run.c: New test. > > Signed-off-by: Kyrylo Tkachov <[email protected]> > --- > Changes since v1: > - Also handle 8-bit elements (*aarch64_vec_shl_insert_into_zero_vnx16qi). > - Use the attrs column for the instruction type. > - Test the floating-point element types too. Rename the run test to > insr-zero-gpr_run.c. > > gcc/config/aarch64/aarch64-sve.md | 12 +- > gcc/testsuite/gcc.target/aarch64/sve/copsi.c | 1 - > .../gcc.target/aarch64/sve/insr-zero-gpr.c | 165 ++++++++++++++++++ > .../aarch64/sve/insr-zero-gpr_run.c | 72 ++++++++ > 4 files changed, 243 insertions(+), 7 deletions(-) > create mode 100644 gcc/testsuite/gcc.target/aarch64/sve/insr-zero-gpr.c > create mode 100644 gcc/testsuite/gcc.target/aarch64/sve/insr-zero-gpr_run.c > > diff --git a/gcc/config/aarch64/aarch64-sve.md > b/gcc/config/aarch64/aarch64-sve.md > index dc92cef4d..735983e4d 100644 > --- a/gcc/config/aarch64/aarch64-sve.md > +++ b/gcc/config/aarch64/aarch64-sve.md > @@ -3029,10 +3029,10 @@ > (match_operand:<VEL> 2 "register_operand")] > UNSPEC_INSR))] > "TARGET_SVE" > - {@ [ cons: =0 , 1 , 2 ] > - [ w , Dz , w ] fmov\t%<Vetype>0, %<Vetype>2 > + {@ [ cons: =0 , 1 , 2 ; attrs: type ] > + [ w , Dz , w ; neon_move ] fmov\t%<Vetype>0, %<Vetype>2 > + [ w , Dz , r ; f_mcr ] fmov\t%<Vetype>0, %<vccore>2 > } > - [(set_attr "type" "neon_move")] > ) > > ;; Shift an SVE vector left and insert a scalar into element 0 of a zero > @@ -3044,10 +3044,10 @@ > (match_operand:QI 2 "register_operand")] > UNSPEC_INSR))] > "TARGET_SVE" > - {@ [ cons: =0 , 1 , 2 ; attrs: length ] > - [ w , Dz , w ; 8 ] fmov\t%h0, %h2\;and\t%0.h, %0.h, > #0xff > + {@ [ cons: =0 , 1 , 2 ; attrs: length , type ] > + [ w , Dz , w ; 8 , neon_move ] fmov\t%h0, > %h2\;and\t%0.h, %0.h, #0xff > + [ w , Dz , r ; 8 , f_mcr ] fmov\t%h0, > %w2\;and\t%0.h, %0.h, #0xff > } > - [(set_attr "type" "neon_move")] > ) > > ;; Shift an SVE vector left and insert a scalar into element 0 from a memory > diff --git a/gcc/testsuite/gcc.target/aarch64/sve/copsi.c > b/gcc/testsuite/gcc.target/aarch64/sve/copsi.c > index d85403640..6bcbffe64 100644 > --- a/gcc/testsuite/gcc.target/aarch64/sve/copsi.c > +++ b/gcc/testsuite/gcc.target/aarch64/sve/copsi.c > @@ -20,7 +20,6 @@ func_init4 (int64_t a, int64_t b) > /* > ** func_init3: > ** fmov s0, w2 > -** fmov s0, s0 > ** insr z0\.s, w1 > ** insr z0\.s, w0 > ** ret > diff --git a/gcc/testsuite/gcc.target/aarch64/sve/insr-zero-gpr.c > b/gcc/testsuite/gcc.target/aarch64/sve/insr-zero-gpr.c > new file mode 100644 > index 000000000..4aaf9bfd4 > --- /dev/null > +++ b/gcc/testsuite/gcc.target/aarch64/sve/insr-zero-gpr.c > @@ -0,0 +1,165 @@ > +/* { dg-do compile } */ > +/* { dg-options "-O2" } */ > +/* { dg-final { check-function-bodies "**" "" } } */ > + > +#include <arm_sve.h> > +#include <string.h> > + > +/* Insert a scalar from a general register into an otherwise zero vector. > + The scalar move also clears the rest of the SVE register. */ > + > +/* > +** zero_8: > +** fmov h0, w0 > +** and z0\.h, z0\.h, #0xff > +** ret > +*/ > +__attribute__ ((noipa)) > +svuint8_t > +zero_8 (uint8_t value) > +{ > + return svinsr_n_u8 (svdup_n_u8 (0), value); > +} > + > +/* > +** nonzero_8: > +** insr z0\.b, w0 > +** ret > +*/ > +__attribute__ ((noipa)) > +svuint8_t > +nonzero_8 (svuint8_t vector, uint8_t value) > +{ > + return svinsr_n_u8 (vector, value); > +} > + > +/* > +** zero_16: > +** fmov h0, w0 > +** ret > +*/ > +__attribute__ ((noipa)) > +svuint16_t > +zero_16 (uint16_t value) > +{ > + return svinsr_n_u16 (svdup_n_u16 (0), value); > +} > + > +/* > +** nonzero_16: > +** insr z0\.h, w0 > +** ret > +*/ > +__attribute__ ((noipa)) > +svuint16_t > +nonzero_16 (svuint16_t vector, uint16_t value) > +{ > + return svinsr_n_u16 (vector, value); > +} > + > +/* > +** zero_32: > +** fmov s0, w0 > +** ret > +*/ > +__attribute__ ((noipa)) > +svuint32_t > +zero_32 (uint32_t value) > +{ > + return svinsr_n_u32 (svdup_n_u32 (0), value); > +} > + > +/* > +** nonzero_32: > +** insr z0\.s, w0 > +** ret > +*/ > +__attribute__ ((noipa)) > +svuint32_t > +nonzero_32 (svuint32_t vector, uint32_t value) > +{ > + return svinsr_n_u32 (vector, value); > +} > + > +/* > +** zero_64: > +** fmov d0, x0 > +** ret > +*/ > +__attribute__ ((noipa)) > +svuint64_t > +zero_64 (uint64_t value) > +{ > + return svinsr_n_u64 (svdup_n_u64 (0), value); > +} > + > +/* > +** nonzero_64: > +** insr z0\.d, x0 > +** ret > +*/ > +__attribute__ ((noipa)) > +svuint64_t > +nonzero_64 (svuint64_t vector, uint64_t value) > +{ > + return svinsr_n_u64 (vector, value); > +} > + > +/* The same applies to floating-point elements whose bits are in a general > + register. */ > + > +/* > +** zero_f16: > +** fmov h0, w0 > +** ret > +*/ > +__attribute__ ((noipa)) > +svfloat16_t > +zero_f16 (uint16_t bits) > +{ > + float16_t value; > + memcpy (&value, &bits, sizeof (value)); > + return svinsr_n_f16 (svdup_n_f16 (0), value); > +} > + > +/* > +** zero_bf16: > +** fmov h0, w0 > +** ret > +*/ > +__attribute__ ((noipa)) > +svbfloat16_t > +zero_bf16 (uint16_t bits) > +{ > + bfloat16_t value; > + memcpy (&value, &bits, sizeof (value)); > + return svinsr_n_bf16 (svreinterpret_bf16 (svdup_n_u16 (0)), value); > +} > + > +/* > +** zero_f32: > +** fmov s0, w0 > +** ret > +*/ > +__attribute__ ((noipa)) > +svfloat32_t > +zero_f32 (uint32_t bits) > +{ > + float32_t value; > + memcpy (&value, &bits, sizeof (value)); > + return svinsr_n_f32 (svdup_n_f32 (0), value); > +} > + > +/* > +** zero_f64: > +** fmov d0, x0 > +** ret > +*/ > +__attribute__ ((noipa)) > +svfloat64_t > +zero_f64 (uint64_t bits) > +{ > + float64_t value; > + memcpy (&value, &bits, sizeof (value)); > + return svinsr_n_f64 (svdup_n_f64 (0), value); > +} > diff --git a/gcc/testsuite/gcc.target/aarch64/sve/insr-zero-gpr_run.c > b/gcc/testsuite/gcc.target/aarch64/sve/insr-zero-gpr_run.c > new file mode 100644 > index 000000000..37d56a2a7 > --- /dev/null > +++ b/gcc/testsuite/gcc.target/aarch64/sve/insr-zero-gpr_run.c > @@ -0,0 +1,72 @@ > +/* { dg-do run { target aarch64_sve_hw } } */ > +/* { dg-options "-O2" } */ > + > +#include "insr-zero-gpr.c" > + > +#define CHECK(BITS, COUNT) \ > +static __attribute__ ((noinline, noclone)) void \ > +check_##BITS (uint##BITS##_t value) \ > +{ \ > + unsigned long count = COUNT; \ > + uint##BITS##_t input[count], output[count]; \ > + for (unsigned long i = 0; i < count; ++i) \ > + input[i] = (uint##BITS##_t) (i * 13 + 7); \ > + svst1_u##BITS (svptrue_b##BITS (), output, zero_##BITS (value)); \ > + if (output[0] != value) \ > + __builtin_abort (); \ > + for (unsigned long i = 1; i < count; ++i) \ > + if (output[i] != 0) \ > + __builtin_abort (); \ > + svuint##BITS##_t v = svld1_u##BITS (svptrue_b##BITS (), input); \ > + svst1_u##BITS (svptrue_b##BITS (), output, nonzero_##BITS (v, value)); \ > + if (output[0] != value) \ > + __builtin_abort (); \ > + for (unsigned long i = 1; i < count; ++i) \ > + if (output[i] != input[i - 1]) \ > + __builtin_abort (); \ > +} > + > +CHECK (8, svcntb ()) > +CHECK (16, svcnth ()) > +CHECK (32, svcntw ()) > +CHECK (64, svcntd ()) > + > +#define CHECK_FLOAT(NAME, BITS, COUNT) \ > +static __attribute__ ((noinline, noclone)) void \ > +check_##NAME (uint##BITS##_t value) \ > +{ \ > + unsigned long count = COUNT; \ > + uint##BITS##_t output[count]; \ > + svst1_u##BITS (svptrue_b##BITS (), output, \ > + svreinterpret_u##BITS (zero_##NAME (value))); \ > + if (output[0] != value) \ > + __builtin_abort (); \ > + for (unsigned long i = 1; i < count; ++i) \ > + if (output[i] != 0) \ > + __builtin_abort (); \ > +} > + > +CHECK_FLOAT (f16, 16, svcnth ()) > +CHECK_FLOAT (bf16, 16, svcnth ()) > +CHECK_FLOAT (f32, 32, svcntw ()) > +CHECK_FLOAT (f64, 64, svcntd ()) > + > +int > +main (void) > +{ > + const uint64_t values[] = { 0, 1, 0x80, 0x8000, 0x80000000ULL, > + 0x8000000000000000ULL, UINT64_MAX, > + 0x123456789abcdef0ULL }; > + for (unsigned int i = 0; i < sizeof (values) / sizeof (values[0]); ++i) > + { > + check_8 (values[i]); > + check_16 (values[i]); > + check_32 (values[i]); > + check_64 (values[i]); > + check_f16 (values[i]); > + check_bf16 (values[i]); > + check_f32 (values[i]); > + check_f64 (values[i]); > + } > + return 0; > +} > -- > 2.43.0 >
