https://gcc.gnu.org/g:b3a040d9d0900192f41ef46922fb19f46a540401
commit r17-5184-gb3a040d9d0900192f41ef46922fb19f46a540401 Author: Kyrylo Tkachov <[email protected]> Date: Wed Oct 7 05:18:12 2026 -0700 aarch64: insert general registers into zero SVE vectors directly 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. 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]> Diff: --- 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 +++++++++++++++++++++ .../gcc.target/aarch64/sve/insr-zero-gpr_run.c | 72 +++++++++ 4 files changed, 243 insertions(+), 7 deletions(-) diff --git a/gcc/config/aarch64/aarch64-sve.md b/gcc/config/aarch64/aarch64-sve.md index 88544a4fde9a..015ec68641b1 100644 --- a/gcc/config/aarch64/aarch64-sve.md +++ b/gcc/config/aarch64/aarch64-sve.md @@ -3030,10 +3030,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 @@ -3045,10 +3045,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 d85403640b9a..6bcbffe64464 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 000000000000..4aaf9bfd42cb --- /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 000000000000..37d56a2a73df --- /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; +}
