]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
aarch64/sve: combine AdvSIMD and SVE vec_duplicates
authorArtemiy Volkov <artemiy.volkov@arm.com>
Mon, 22 Dec 2025 12:46:21 +0000 (12:46 +0000)
committerArtemiy Volkov <artemiy.volkov@arm.com>
Thu, 28 May 2026 11:26:40 +0000 (11:26 +0000)
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
gcc/config/aarch64/iterators.md
gcc/testsuite/gcc.target/aarch64/sve/vec_init_5.c [new file with mode: 0644]

index e7d98c3754f157efc7711395364e0533775eebdc..ba4ff7267914f10f3674c93d7c0b7ea4a9d07260 100644 (file)
   [(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.
index 462f2d996f075c790eda59dad954c912d686df40..41410095ba39444a3af63f5cfe4647e481f1f857 100644 (file)
                         (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 (file)
index 0000000..99e04aa
--- /dev/null
@@ -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
+*/
+