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;
+}

Reply via email to