Precompute moves and use magics index as compress mask on AVX512ICL

Passed STC
https://tests.stockfishchess.org/tests/view/69f6df65b64b50e29dbed427
LLR: 2.94 (-2.94,2.94) <0.00,2.00>
Total: 112224 W: 29195 L: 28782 D: 54247
Ptnml(0-2): 312, 12345, 30381, 12766, 308

Local speedup:
```
Result of 100 runs
base (...kfish.master) =    2050387  +/- 5497
test (./stockfish    ) =    2069598  +/- 4426
diff                   =     +19211  +/- 7468
speedup         = +0.0094
P(speedup > 0) =  1.0000
```

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

No functional change
This commit is contained in:
Timothy Herchen
2026-05-04 08:33:01 +02:00
committed by Joost VandeVondele
parent ab8f901d25
commit 1554a2ca0b
3 changed files with 96 additions and 17 deletions
+85 -4
View File
@@ -62,6 +62,76 @@ inline Move* splat_moves(Move* moveList, Square from, Bitboard to_bb) {
return moveList + popcount(to_bb);
}
// Rook/bishop, indexed by (Pt - BISHOP) and from sq
// Moves are provided in ascending order of the piece's attacks on an empty board
alignas(64) constexpr auto SliderMoves = []() {
std::array<std::array<std::array<Move, 16>, SQUARE_NB>, 2> arr{};
for (PieceType pt : {BISHOP, ROOK})
{
for (Square s = SQ_A1; s <= SQ_H8; ++s)
{
Bitboard bb = PseudoAttacks[pt][s];
int i = 0;
while (bb)
{
arr[pt - BISHOP][s][i++] = Move(s, Square(constexpr_lsb(bb)));
bb &= bb - 1;
}
}
}
return arr;
}();
// Knight/king analog of the above
alignas(64) constexpr auto KnightKingMoves = []() {
std::array<std::array<std::array<Move, 8>, SQUARE_NB>, 2> arr{};
for (PieceType pt : {KNIGHT, KING})
{
for (Square s = SQ_A1; s <= SQ_H8; ++s)
{
Bitboard bb = PseudoAttacks[pt][s];
int i = 0;
while (bb)
{
arr[pt == KING][s][i++] = Move(s, Square(constexpr_lsb(bb)));
bb &= bb - 1;
}
}
}
return arr;
}();
template<PieceType Pt>
inline Move*
splat_precomputed_moves(Move* moveList, Square from, Bitboard occupied, Bitboard target) {
static_assert(Pt != QUEEN && Pt != PAWN, "Unsupported piece type");
// The nth bit in the mask corresponds to the nth square in the piece's pseudo-attacks
uint32_t mask;
if constexpr (Pt == BISHOP || Pt == ROOK)
{
const Magic& magic = Magics[from][Pt - BISHOP];
mask = magic.attacks[magic.index(occupied)];
mask &= pext(target, magic.pseudoAttacks);
const __m256i moves =
*reinterpret_cast<const __m256i*>(SliderMoves[Pt - BISHOP][from].data());
_mm256_storeu_si256(reinterpret_cast<__m256i*>(moveList),
_mm256_maskz_compress_epi16(mask, moves));
}
else
{
mask = pext(target, PseudoAttacks[Pt][from]);
__m128i moves = *reinterpret_cast<const __m128i*>(KnightKingMoves[Pt == KING][from].data());
_mm_storeu_si128(reinterpret_cast<__m128i*>(moveList),
_mm_maskz_compress_epi16(mask, moves));
}
return moveList + popcount(mask);
}
#else
template<Direction offset>
@@ -192,8 +262,15 @@ Move* generate_moves(const Position& pos, Move* moveList, Bitboard target) {
while (bb)
{
Square from = pop_lsb(bb);
Bitboard b = attacks_bb<Pt>(from, pos.pieces()) & target;
Square from = pop_lsb(bb);
#ifdef USE_AVX512ICL
if constexpr (Pt != QUEEN)
{
moveList = splat_precomputed_moves<Pt>(moveList, from, pos.pieces(), target);
continue;
}
#endif
Bitboard b = attacks_bb<Pt>(from, pos.pieces()) & target;
moveList = splat_moves(moveList, from, b);
}
@@ -225,9 +302,13 @@ Move* generate_all(const Position& pos, Move* moveList) {
moveList = generate_moves<Us, QUEEN>(pos, moveList, target);
}
Bitboard b = attacks_bb<KING>(ksq) & (Type == EVASIONS ? ~pos.pieces(Us) : target);
Bitboard b = Type == EVASIONS ? ~pos.pieces(Us) : target;
moveList = splat_moves(moveList, ksq, b);
#ifdef USE_AVX512ICL
moveList = splat_precomputed_moves<KING>(moveList, ksq, 0ULL, b);
#else
moveList = splat_moves(moveList, ksq, attacks_bb<KING>(ksq) & b);
#endif
if ((Type == QUIETS || Type == NON_EVASIONS) && pos.can_castle(Us & ANY_CASTLING))
for (CastlingRights cr : {Us & KING_SIDE, Us & QUEEN_SIDE})