From 2d239de4604f4b7ff3679d4c31ccc8249fde3d00 Mon Sep 17 00:00:00 2001 From: Linmiao Xu Date: Fri, 10 Jul 2026 20:16:42 +0200 Subject: [PATCH] Split NEON dense affine accumulation two ways Speedup measured locally with apple-silicon M3 Pro: ``` Result of 50 runs ================== base (./sf-master ) = 1570076 +/- 27215 test (...-neon-2chain) = 1578923 +/- 29000 diff = +8847 +/- 5700 speedup = +0.0056 P(speedup > 0) = 0.9988 CPU: 11 x arm Hyperthreading: off ``` Passed STC: https://tests.stockfishchess.org/tests/view/6a49678cf97ff95f78795b38 LLR: 4.43 (-2.94,2.94) <0.00,2.00> Total: 137696 W: 36041 L: 35477 D: 66178 Ptnml(0-2): 289, 14663, 38396, 15195, 305 closes https://github.com/official-stockfish/Stockfish/pull/6956 No functional change --- src/nnue/layers/affine_transform.h | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/nnue/layers/affine_transform.h b/src/nnue/layers/affine_transform.h index bdf6ff281..055e7ca5f 100644 --- a/src/nnue/layers/affine_transform.h +++ b/src/nnue/layers/affine_transform.h @@ -255,7 +255,7 @@ class AffineTransform { constexpr IndexType NumChunks = ceil_to_multiple(InputDimensions, 8) / 4; constexpr IndexType NumAccums = OutputDimensions / OutputSimdWidth; - #if defined(USE_VNNI) + #if defined(USE_VNNI) || defined(USE_NEON_DOTPROD) constexpr IndexType NumRegs = 2 * NumAccums; #else constexpr IndexType NumRegs = NumAccums; @@ -269,7 +269,7 @@ class AffineTransform { acc[k] = vec_set_32(0); IndexType i = 0; - #if defined(USE_VNNI) + #if defined(USE_VNNI) || defined(USE_NEON_DOTPROD) for (; i < NumChunks; i += 2) { const vec_t in0 = vec_set_32(load_as(input + i * sizeof(i32))); @@ -287,7 +287,11 @@ class AffineTransform { } for (IndexType k = 0; k < NumAccums; ++k) + #if defined(USE_NEON_DOTPROD) + acc[k] = vaddq_s32(acc[k], acc[k + NumAccums]); + #else acc[k] = vec_add_32(acc[k], acc[k + NumAccums]); + #endif #endif for (; i < NumChunks; ++i) { @@ -295,12 +299,12 @@ class AffineTransform { const auto col0 = reinterpret_cast(&weights[i * OutputDimensions * 4]); - for (IndexType k = 0; k < NumRegs; ++k) + for (IndexType k = 0; k < NumAccums; ++k) vec_add_dpbusd_32(acc[k], in0, col0[k]); } vec_t* outptr = reinterpret_cast(output); - for (IndexType k = 0; k < NumRegs; ++k) + for (IndexType k = 0; k < NumAccums; ++k) outptr[k] = acc[k]; #undef vec_set_32