Shave some instructions off a hot loop in affine transform

On x86, GCC generates highly suboptimal code for this loop in its old form,
about 2x as many instructions as necessary. This decreases throughput
especially in an SMT setting. Clang does a better job but this change still has
some improvement. Note that the std::ptrdiff_t type is not optional; using an
unsigned type brings back the bad assembly. (Not sure why, but it seems
reliable on all the GCC versions I tested.)

passed STC:
LLR: 2.93 (-2.94,2.94) <0.00,2.00>
Total: 44672 W: 11841 L: 11527 D: 21304
Ptnml(0-2): 165, 4625, 12415, 4993, 138
https://tests.stockfishchess.org/tests/view/68d8111efa806e2e8393b10e

closes https://github.com/official-stockfish/Stockfish/pull/6331

No functional change
This commit is contained in:
Timothy Herchen
2025-09-28 21:04:29 +02:00
committed by Joost VandeVondele
parent 4f4f78f86e
commit 9b164d9520
2 changed files with 13 additions and 5 deletions
+1
View File
@@ -243,6 +243,7 @@ Thanar2
thaspel thaspel
theo77186 theo77186
TierynnB TierynnB
Timothy Herchen (anematode)
Ting-Hsuan Huang (fffelix-huang) Ting-Hsuan Huang (fffelix-huang)
Tobias Steinmann Tobias Steinmann
Tomasz Sobczyk (Sopel97) Tomasz Sobczyk (Sopel97)
@@ -22,6 +22,7 @@
#define NNUE_LAYERS_AFFINE_TRANSFORM_SPARSE_INPUT_H_INCLUDED #define NNUE_LAYERS_AFFINE_TRANSFORM_SPARSE_INPUT_H_INCLUDED
#include <algorithm> #include <algorithm>
#include <cstddef>
#include <cstdint> #include <cstdint>
#include <iostream> #include <iostream>
@@ -287,12 +288,18 @@ class AffineTransformSparseInput {
for (IndexType k = 0; k < NumRegs; ++k) for (IndexType k = 0; k < NumRegs; ++k)
acc[k] = biasvec[k]; acc[k] = biasvec[k];
for (IndexType j = 0; j < count; ++j) auto* start = nnz;
auto* end = nnz + count;
// convince GCC to not do weird pointer arithmetic in the following loop
const std::int8_t* weights_cp = weights;
while (start < end)
{ {
const auto i = nnz[j]; const std::ptrdiff_t i = *start;
start++;
const invec_t in = vec_set_32(input32[i]); const invec_t in = vec_set_32(input32[i]);
const auto col = const auto col = (const invec_t*) (&weights_cp[i * OutputDimensions * ChunkSize]);
reinterpret_cast<const invec_t*>(&weights[i * OutputDimensions * ChunkSize]);
for (IndexType k = 0; k < NumRegs; ++k) for (IndexType k = 0; k < NumRegs; ++k)
vec_add_dpbusd_32(acc[k], in, col[k]); vec_add_dpbusd_32(acc[k], in, col[k]);
} }