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
> 

Reply via email to