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