https://gcc.gnu.org/g:d14a5db124777b12fcaeada4236878031d5ca505
commit r16-2383-gd14a5db124777b12fcaeada4236878031d5ca505 Author: Kyrylo Tkachov <ktkac...@nvidia.com> Date: Thu Jul 17 03:51:31 2025 -0700 aarch64: Avoid INS-(W|X)ZR instructions when optimising for speed 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 <ktkac...@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. Diff: --- gcc/config/aarch64/aarch64-simd.md | 5 ++++- gcc/testsuite/gcc.target/aarch64/inszero_split_1.c | 18 ++++++++++++++++++ gcc/testsuite/gcc.target/aarch64/simd/mf8_data_1.c | 10 ++++++++++ gcc/testsuite/gcc.target/aarch64/vec-set-zero.c | 2 +- 4 files changed, 33 insertions(+), 2 deletions(-) diff --git a/gcc/config/aarch64/aarch64-simd.md b/gcc/config/aarch64/aarch64-simd.md index 270cb2ff3a12..8b75c3d7f6d5 100644 --- a/gcc/config/aarch64/aarch64-simd.md +++ b/gcc/config/aarch64/aarch64-simd.md @@ -1190,13 +1190,16 @@ [(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 index 000000000000..5c739bd7bb1a --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/inszero_split_1.c @@ -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; +} diff --git a/gcc/testsuite/gcc.target/aarch64/simd/mf8_data_1.c b/gcc/testsuite/gcc.target/aarch64/simd/mf8_data_1.c index a3fd9b800e1e..79d1ccf6f7d5 100644 --- a/gcc/testsuite/gcc.target/aarch64/simd/mf8_data_1.c +++ b/gcc/testsuite/gcc.target/aarch64/simd/mf8_data_1.c @@ -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) diff --git a/gcc/testsuite/gcc.target/aarch64/vec-set-zero.c b/gcc/testsuite/gcc.target/aarch64/vec-set-zero.c index b34b902cf27b..ba4696e5840f 100644 --- a/gcc/testsuite/gcc.target/aarch64/vec-set-zero.c +++ b/gcc/testsuite/gcc.target/aarch64/vec-set-zero.c @@ -1,5 +1,5 @@ /* { dg-do compile } */ -/* { dg-options "-O2" } */ +/* { dg-options "-Os" } */ #include "arm_neon.h"