Currently, to duplicate a 64-bit or narrower value into a SVE register, we
choose to go via an intermediate 128-bit AdvSIMD register, viz.:
svfloat32_t foo(float x) {
return svdupq_n_f32(x, x, x, x);
}
which will produce the following code:
dup v0.4s, v0.s[0]
dup z0.q, z0.q[0]
ret
when compiled with -O2 -march=armv9-a+sve.
This can be simplified into a single dup instruction going to an SVE
register directly from a scalar (or a smaller vector) value:
mov z0.s, s0
ret
To facilitate this, this patch adds a pattern that combine can use to
merge two vec_duplicate instructions (scalar -> AdvSIMD and AdvSIMD ->
SVE) into a single one (scalar -> SVE).
To demonstrate the effect of this patch, the vec-init-23.c test from
AdvSIMD was reused as a new SVE test (vec_init_5.c).
gcc/ChangeLog:
* config/aarch64/aarch64-sve.md
(*aarch64_vec_duplicate_subvector<vconsv><vconq><mode>):
New pattern.
* config/aarch64/iterators.md (VCONSV): New mode attribute.
(vconsv): Likewise.
gcc/testsuite/ChangeLog:
* gcc.target/aarch64/sve/vec_init_5.c: New test.
---
gcc/config/aarch64/aarch64-sve.md | 14 +
gcc/config/aarch64/iterators.md | 24 ++
.../gcc.target/aarch64/sve/vec_init_5.c | 382 ++++++++++++++++++
3 files changed, 420 insertions(+)
create mode 100644 gcc/testsuite/gcc.target/aarch64/sve/vec_init_5.c
diff --git a/gcc/config/aarch64/aarch64-sve.md
b/gcc/config/aarch64/aarch64-sve.md
index 019630eb8d2..ba46e2871e0 100644
--- a/gcc/config/aarch64/aarch64-sve.md
+++ b/gcc/config/aarch64/aarch64-sve.md
@@ -2890,6 +2890,20 @@
[(set_attr "sve_type" "sve_int_general")]
)
+;; Initialize an SVE vector by duplicating a 128-bit AdvSIMD register that
+;; itself contains a duplicated scalar or subvector value.
+(define_insn "*aarch64_vec_duplicate_subvector<vconsv><vconq><mode>"
+ [(set (match_operand:<VCONSV> 0 "register_operand")
+ (vec_duplicate:<VCONSV>
+ (vec_duplicate:<VCONQ>
+ (match_operand:VQDUP 1 "register_operand"))))]
+ "TARGET_SVE"
+ {@ [ cons: =0 , 1 ]
+ [ w , r ] mov\t%0.<single_type>, %<single_wx>1
+ [ w , w ] mov\t%0.<single_type>, %<single_type>1
+ }
+)
+
;; This is used for vec_duplicate<mode>s from memory, but can also
;; be used by combine to optimize selects of a vec_duplicate<mode>
;; with zero.
diff --git a/gcc/config/aarch64/iterators.md b/gcc/config/aarch64/iterators.md
index 462f2d996f0..41410095ba3 100644
--- a/gcc/config/aarch64/iterators.md
+++ b/gcc/config/aarch64/iterators.md
@@ -1995,6 +1995,30 @@
(HI "v8hi") (QI "v16qi")
(SF "v4sf") (DF "v2df")])
+;; SVE container modes for duplication into a full SVE register.
+(define_mode_attr VCONSV [(V8QI "VNx16QI") (V4QI "VNx16QI")
+ (V2QI "VNx16QI") (QI "VNx16QI")
+ (V4HI "VNx8HI") (V2HI "VNx8HI")
+ (HI "VNx8HI") (V2SI "VNx4SI")
+ (SI "VNx4SI") (DI "VNx2DI")
+ (V4BF "VNx8BF") (V2BF "VNx8BF")
+ (BF "VNx8BF") (V4HF "VNx8HF")
+ (V2HF "VNx8HF") (HF "VNx8HF")
+ (V2SF "VNx4SF") (SF "VNx4SF")
+ (DF "VNx2DF")])
+
+;; Same as above, but in lowercase.
+(define_mode_attr vconsv [(V8QI "vnx16qi") (V4QI "vnx16qi")
+ (V2QI "vnx16qi") (QI "vnx16qi")
+ (V4HI "vnx8hi") (V2HI "vnx8hi")
+ (HI "vnx8hi") (V2SI "vnx4si")
+ (SI "vnx4si") (DI "vnx2di")
+ (V4BF "vnx8bf") (V2BF "vnx8bf")
+ (BF "vnx8bf") (V4HF "vnx8hf")
+ (V2HF "vnx8hf") (HF "vnx8hf")
+ (V2SF "vnx4sf") (SF "vnx4sf")
+ (DF "vnx2df")])
+
;; Half modes of all vector modes.
(define_mode_attr VHALF [(V8QI "V4QI") (V16QI "V8QI")
(V4HI "V2HI") (V8HI "V4HI")
diff --git a/gcc/testsuite/gcc.target/aarch64/sve/vec_init_5.c
b/gcc/testsuite/gcc.target/aarch64/sve/vec_init_5.c
new file mode 100644
index 00000000000..99e04aac265
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/sve/vec_init_5.c
@@ -0,0 +1,382 @@
+/* { dg-do compile } */
+/* { dg-options "-O2" } */
+/* { dg-final { check-function-bodies "**" "" "" } } */
+
+#include <arm_sve.h>
+
+#define TESTCASE(TYPE, ETYPE, T, SZ, NUM, MULT, ...)\
+ sv##TYPE##SZ##_t test_##TYPE##SZ##_##NUM (ETYPE x0, ETYPE x1, ETYPE x2,
ETYPE x3,\
+ ETYPE x4, ETYPE x5, ETYPE x6, ETYPE
x7)\
+ {\
+ return svdupq_n_##T##SZ (__VA_ARGS__);\
+ }
+
+#include "../vec-init-23.c"
+
+/*
+** test_int8_1:
+** mov z0\.b, w0
+** ret
+*/
+
+/*
+** test_int8_2:
+** bfi w0, w1, 8, 8
+** mov z0\.h, w0
+** ret
+*/
+
+/*
+** test_int8_3:
+** bfi w0, w1, 8, 8
+** bfi w0, w2, 16, 8
+** bfi w0, w3, 24, 8
+** mov z0\.s, w0
+** ret
+*/
+
+/*
+** test_int8_4:
+** bfi w0, w2, 8, 8
+** bfi w1, w3, 8, 8
+** bfi w0, w4, 16, 8
+** bfi w1, w5, 16, 8
+** bfi w0, w6, 24, 8
+** bfi w1, w7, 24, 8
+** dup v31\.2s, w0
+** dup v30\.2s, w1
+** zip1 v31\.16b, v31\.16b, v30\.16b
+** dup z0\.q, z31\.q\[0\]
+** ret
+*/
+
+/*
+** test_int8_5:
+** uxtb w0, w0
+** mov z0\.h, w0
+** ret
+*/
+
+/*
+** test_int8_6:
+** mov w1, 0
+** bfi w1, w0, 8, 8
+** mov z0\.h, w1
+** ret
+*/
+
+/*
+** test_int8_7:
+** mov w2, 16777472
+** bfi w2, w0, 0, 8
+** bfi w2, w1, 8, 8
+** mov z0\.s, w2
+** ret
+*/
+
+/*
+** test_int8_8:
+** mov w2, 16777472
+** bfi w2, w0, 16, 8
+** bfi w2, w1, 24, 8
+** mov z0\.s, w2
+** ret
+*/
+
+/*
+** test_int8_9:
+** mov w2, 16777216
+** bfi w2, w0, 0, 8
+** bfi w2, w1, 16, 8
+** mov z0.s, w2
+** ret
+*/
+
+/*
+** test_int8_10:
+** bfi w0, w1, 8, 8
+** bfi w0, w2, 16, 8
+** bfi w0, w3, 24, 8
+** dup v31\.2s, w0
+** adrp x0, .LANCHOR[0-9]+
+** ldr d30, \[x0, #:lo12:.LANCHOR[0-9]+\]
+** zip1 v31\.16b, v31\.16b, v30\.16b
+** dup z0\.q, z31\.q\[0\]
+** ret
+*/
+
+/*
+** test_int8_11:
+** bfi w0, w1, 8, 8
+** adrp x4, .LANCHOR[0-9]+
+** bfi w0, w2, 16, 8
+** ldr d31, \[x4, #:lo12:\.LANCHOR[0-9]+\]
+** bfi w0, w3, 24, 8
+** dup v30\.2s, w0
+** zip1 v31\.16b, v31\.16b, v30\.16b
+** dup z0\.q, z31\.q\[0\]
+** ret
+*/
+
+/*
+** test_int8_12:
+** mov w4, 255
+** movk w4, 0x201, lsl 16
+** bfi w4, w0, 0, 8
+** mov w0, 256
+** movk w0, 0x302, lsl 16
+** bfi w0, w1, 0, 8
+** bfi w4, w2, 16, 8
+** bfi w0, w3, 16, 8
+** dup v31\.2s, w4
+** dup v30\.2s, w0
+** zip1 v31\.16b, v31\.16b, v30\.16b
+** dup z0\.q, z31\.q\[0\]
+** ret
+*/
+
+/*
+** test_int8_13:
+** mov w4, 256
+** movk w4, 0x302, lsl 16
+** bfi w4, w0, 8, 8
+** mov w0, 513
+** movk w0, 0x403, lsl 16
+** bfi w0, w1, 8, 8
+** bfi w4, w2, 24, 8
+** bfi w0, w3, 24, 8
+** dup v31\.2s, w4
+** dup v30\.2s, w0
+** zip1 v31\.16b, v31\.16b, v30\.16b
+** dup z0\.q, z31\.q\[0\]
+** ret
+*/
+
+/*
+** test_float16_1:
+** fcvt h0, s0
+** mov z0\.h, h0
+** ret
+*/
+
+/*
+** test_float16_2:
+** fcvt h1, s1
+** fcvt h0, s0
+** uzp1 v0\.4h, v0\.4h, v1\.4h
+** mov z0\.s, s0
+** ret
+*/
+
+/*
+** test_float16_3:
+** uzp1 v2\.2s, v0\.2s, v2\.2s
+** uzp1 v3\.2s, v1\.2s, v3\.2s
+** zip1 v3\.4s, v2\.4s, v3\.4s
+** fcvtn v3\.4h, v3\.4s
+** mov z0\.d, d3
+** ret
+*/
+
+/*
+** test_float16_4:
+** fcvt h0, s0
+** fmov h0, h0
+** mov z0\.s, s0
+** ret
+*/
+
+/*
+** test_float16_5:
+** movi v31\.4h, #0
+** fcvt h0, s0
+** uzp1 v0\.4h, v31\.4h, v0\.4h
+** mov z0\.s, s0
+** ret
+*/
+
+/*
+** test_float16_6:
+** fcvt h2, s0
+** fcvt h1, s1
+** fmov h31, 1.0e\+0
+** fmov h2, h2
+** uzp1 v1\.4h, v1\.4h, v31\.4h
+** dup v0\.2s, v2\.s\[0\]
+** dup v1\.2s, v1\.s\[0\]
+** zip1 v0\.8h, v0\.8h, v1\.8h
+** dup z0\.q, z0\.q\[0\]
+** ret
+*/
+
+/*
+** test_float16_7:
+** fcvt h3, s0
+** fcvt h2, s1
+** movi v0\.4h, #0
+** fmov h1, 1.0e\+0
+** uzp1 v1\.4h, v1\.4h, v2\.4h
+** uzp1 v0\.4h, v0\.4h, v3\.4h
+** dup v1\.2s, v1\.s\[0\]
+** dup v0\.2s, v0\.s\[0\]
+** zip1 v0\.8h, v0\.8h, v1\.8h
+** dup z0\.q, z0\.q\[0\]
+** ret
+*/
+
+/*
+** test_float16_8:
+** fcvt h1, s1
+** fcvt h0, s0
+** movi v31\.2s, 0x3c, lsl 24
+** uzp1 v0\.4h, v0\.4h, v1.4h
+** dup v0\.2s, v0\.s\[0\]
+** zip1 v0\.8h, v31\.8h, v0\.8h
+** dup z0\.q, z0\.q\[0\]
+** ret
+*/
+
+/*
+** test_int16_1:
+** mov z0\.h, w0
+** ret
+*/
+
+/*
+** test_int16_2:
+** bfi w0, w1, 16, 16
+** mov z0\.s, w0
+** ret
+*/
+
+/*
+** test_int16_3:
+** bfi w0, w2, 16, 16
+** bfi w1, w3, 16, 16
+** dup v31\.2s, w0
+** dup v30\.2s, w1
+** zip1 v31\.8h, v31\.8h, v30\.8h
+** dup z0\.q, z31\.q\[0\]
+** ret
+*/
+
+/*
+** test_int16_4:
+** uxth w0, w0
+** mov z0\.s, w0
+** ret
+*/
+
+/*
+** test_int16_5:
+** mov w1, 0
+** bfi w1, w0, 16, 16
+** mov z0\.s, w1
+** ret
+*/
+
+/*
+** test_int16_6:
+** uxth w0, w0
+** dup v31\.2s, w0
+** mov w0, 1
+** bfi w1, w0, 16, 16
+** dup v30\.2s, w1
+** zip1 v31\.8h, v31\.8h, v30\.8h
+** dup z0\.q, z31\.q\[0\]
+** ret
+*/
+
+/*
+** test_int16_7:
+** mov w2, 0
+** bfi w2, w0, 16, 16
+** mov w0, 65537
+** bfi w0, w1, 16, 16
+** dup v31\.2s, w2
+** dup v30\.2s, w0
+** zip1 v31\.8h, v31\.8h, v30\.8h
+** dup z0\.q, z31\.q\[0\]
+** ret
+*/
+
+/*
+** test_int16_8:
+** bfi w0, w1, 16, 16
+** movi v31\.2s, 0x1, lsl 16
+** dup v30\.2s, w0
+** zip1 v31\.8h, v31\.8h, v30\.8h
+** dup z0\.q, z31\.q\[0\]
+** ret
+*/
+
+/*
+** test_float32_1:
+** mov z0\.s, s0
+** ret
+*/
+
+/*
+** test_float32_2:
+** uzp1 v0\.2s, v0\.2s, v1\.2s
+** mov z0\.d, d0
+** ret
+*/
+
+/*
+** test_float32_3:
+** fmov s0, s0
+** mov z0\.d, d0
+** ret
+*/
+
+/*
+** test_float32_4:
+** movi v31\.2s, #0
+** uzp1 v0\.2s, v31\.2s, v0\.2s
+** mov z0\.d, d0
+** ret
+*/
+
+/*
+** test_int32_1:
+** mov z0\.s, w0
+** ret
+*/
+
+/*
+** test_int32_2:
+** fmov s0, w0
+** ins v0\.s\[1\], w1
+** mov z0\.d, d0
+** ret
+*/
+
+/*
+** test_int32_3:
+** fmov s0, w0
+** mov z0\.d, d0
+** ret
+*/
+
+/*
+** test_int32_4:
+** dup v30\.2s, w0
+** movi v31\.2s, 0
+** zip1 v31\.4s, v31\.4s, v30\.4s
+** dup z0\.q, z31\.q\[0\]
+** ret
+*/
+
+/*
+** test_int64_1:
+** mov z0\.d, x0
+** ret
+*/
+
+/*
+** test_float64_1:
+** mov z0\.d, d0
+** ret
+*/
+
--
2.43.0