]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
aarch64: Avoid INS-(W|X)ZR instructions when optimising for speed
authorKyrylo Tkachov <ktkachov@nvidia.com>
Thu, 17 Jul 2025 10:51:31 +0000 (03:51 -0700)
committerKyrylo Tkachov <ktkachov@nvidia.com>
Mon, 21 Jul 2025 13:10:56 +0000 (15:10 +0200)
For inserting zero into a vector lane we usually use an instruction like:
ins     v0.h[2], wzr

This, however, has not-so-great performance on some CPUs.
On Grace, for example it has a latency of 5 and throughput 1.
The alternative sequence:
movi    v31.8b, #0
ins     v0.h[2], v31.h[0]
is prefereble bcause the MOVI-0 is often a zero-latency operation that is
eliminated by the CPU frontend and the lane-to-lane INS has a latency of 2 and
throughput of 4.
We can avoid the merging of the two instructions into the aarch64_simd_vec_set_zero<mode>
by disabling that pattern when optimizing for speed.

Thanks to wider benchmarking from Tamar, it makes sense to make this change for
all tunings, so no RTX costs or tuning flags are introduced to control this
in a more fine-grained manner.  They can be easily added in the future if needed
for a particular CPU.

Bootstrapped and tested on aarch64-none-linux-gnu.

Signed-off-by: Kyrylo Tkachov <ktkachov@nvidia.com>
gcc/

* config/aarch64/aarch64-simd.md (aarch64_simd_vec_set_zero<mode>):
Enable only when optimizing for size.

gcc/testsuite/

* gcc.target/aarch64/simd/mf8_data_1.c (test_set_lane4,
test_setq_lane4): Relax allowed assembly.
* gcc.target/aarch64/vec-set-zero.c: Use -Os in flags.
* gcc.target/aarch64/inszero_split_1.c: New test.

gcc/config/aarch64/aarch64-simd.md
gcc/testsuite/gcc.target/aarch64/inszero_split_1.c [new file with mode: 0644]
gcc/testsuite/gcc.target/aarch64/simd/mf8_data_1.c
gcc/testsuite/gcc.target/aarch64/vec-set-zero.c

index 270cb2ff3a120e228a21d1fafb4df82698864740..8b75c3d7f6d5ddc5c44f841da961423caaebe8b8 100644 (file)
   [(set_attr "type" "neon_ins<q>, neon_from_gp<q>, neon_load1_one_lane<q>")]
 )
 
+;; Inserting from the zero register into a vector lane is treated as an
+;; expensive GP->FP move on all CPUs.  Avoid it when optimizing for speed.
 (define_insn "aarch64_simd_vec_set_zero<mode>"
   [(set (match_operand:VALL_F16 0 "register_operand" "=w")
        (vec_merge:VALL_F16
            (match_operand:VALL_F16 1 "register_operand" "0")
            (match_operand:VALL_F16 3 "aarch64_simd_imm_zero" "")
            (match_operand:SI 2 "immediate_operand" "i")))]
-  "TARGET_SIMD && aarch64_exact_log2_inverse (<nunits>, operands[2]) >= 0"
+  "TARGET_SIMD && aarch64_exact_log2_inverse (<nunits>, operands[2]) >= 0
+   && optimize_function_for_size_p (cfun)"
   {
     int elt = ENDIAN_LANE_N (<nunits>,
                             aarch64_exact_log2_inverse (<nunits>,
diff --git a/gcc/testsuite/gcc.target/aarch64/inszero_split_1.c b/gcc/testsuite/gcc.target/aarch64/inszero_split_1.c
new file mode 100644 (file)
index 0000000..5c739bd
--- /dev/null
@@ -0,0 +1,18 @@
+/* { dg-do compile } */
+/* { dg-additional-options "-O2" } */
+/* { dg-final { check-function-bodies "**" "" "" } } */
+
+/* Avoid INS from WZR register when optimizing for speed.  */
+
+#include <arm_neon.h>
+
+/*
+** foo:
+**     movi?   [vdz]([0-9]+)\.?(?:[0-9]*[bhsd])?, #?0
+**     ins     v0.h\[2\], v(\1).h\[0\]
+**     ret
+*/
+uint16x8_t foo(uint16x8_t a) {
+  a[2] = 0;
+  return a;
+}
index a3fd9b800e1e2a2d33e3711f76b34afd4aa97829..79d1ccf6f7d5a7106f4add07df6fe0baf598a58c 100644 (file)
@@ -1016,7 +1016,12 @@ mfloat8x8_t test_set_lane3(mfloat8x8_t a, const mfloat8_t *ptr)
 
 /*
 ** test_set_lane4:
+**     (
 **     ins     v0.b\[6\], wzr
+**     |
+**     movi?   [vdz]([0-9]+)\.?(?:[0-9]*[bhsd])?, #?0
+**     ins     v0.b\[6\], v(\1).b\[0\]
+**     )
 **     ret
 */
 mfloat8x8_t test_set_lane4(mfloat8x8_t a)
@@ -1056,7 +1061,12 @@ mfloat8x16_t test_setq_lane3(mfloat8x16_t a, const mfloat8_t *ptr)
 
 /*
 ** test_setq_lane4:
+**     (
 **     ins     v0.b\[14\], wzr
+**     |
+**     movi?   [vdz]([0-9]+)\.?(?:[0-9]*[bhsd])?, #?0
+**     ins     v0.b\[14\], v(\1).b\[0\]
+**     )
 **     ret
 */
 mfloat8x16_t test_setq_lane4(mfloat8x16_t a)
index b34b902cf27bbfd9616c854b80181659706cf962..ba4696e5840f5756bf45680b1beb182855a98b6b 100644 (file)
@@ -1,5 +1,5 @@
 /* { dg-do compile } */
-/* { dg-options "-O2" } */
+/* { dg-options "-Os" } */
 
 #include "arm_neon.h"