Simplify out pext attacks

Passed STC non-regression on avx512icl (https://tests.stockfishchess.org/tests/view/6a421b46f97ff95f78795061)
LLR: 2.96 (-2.94,2.94) <-1.75,0.25>
Total: 81632 W: 21240 L: 21075 D: 39317
Ptnml(0-2): 184, 8907, 22464, 9082, 179

Passed STC non-regression on bmi2 (https://tests.stockfishchess.org/tests/view/6a41f6f9f97ff95f7879503e)
LLR: 2.93 (-2.94,2.94) <-1.75,0.25>
Total: 78112 W: 20411 L: 20245 D: 37456
Ptnml(0-2): 188, 8449, 21632, 8583, 204

After #6845 , pext attacks are slower or equal to parallel-hyperbola attacks which works on all architectures that pext supports. SVE2 supports pext/pdep in vector registers, but it's much slower than the `rbit`-based HQ that we have on ARM, so I don't foresee the code being useful there.

Ofc I don't think we should remove the `bmi2` build or anything, because it's nice for people to be able to freely use pext when testing ideas, and I'm sure we'll some day find another use for it!

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

No functional change

Co-authored-by: Dubslow <bunslow@gmail.com>
This commit is contained in:
anematode
2026-07-03 20:27:33 +02:00
committed by Joost VandeVondele
co-authored by Dubslow
parent 46428b9346
commit 99489f57dd
3 changed files with 18 additions and 171 deletions
+4 -85
View File
@@ -63,76 +63,6 @@ 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 = Attacks::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 = Attacks::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
u32 mask;
if constexpr (Pt == BISHOP || Pt == ROOK)
{
const Attacks::Magic& magic = Attacks::magic(from, Pt);
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, Attacks::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>
@@ -263,15 +193,8 @@ Move* generate_moves(const Position& pos, Move* moveList, Bitboard target) {
while (bb)
{
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::attacks_bb<Pt>(from, pos.pieces()) & target;
Square from = pop_lsb(bb);
Bitboard b = Attacks::attacks_bb<Pt>(from, pos.pieces()) & target;
moveList = splat_moves(moveList, from, b);
}
@@ -303,13 +226,9 @@ Move* generate_all(const Position& pos, Move* moveList) {
moveList = generate_moves<Us, QUEEN>(pos, moveList, target);
}
Bitboard b = Type == EVASIONS ? ~pos.pieces(Us) : target;
Bitboard b = Attacks::attacks_bb<KING>(ksq) & (Type == EVASIONS ? ~pos.pieces(Us) : target);
#ifdef USE_AVX512ICL
moveList = splat_precomputed_moves<KING>(moveList, ksq, 0ULL, b);
#else
moveList = splat_moves(moveList, ksq, Attacks::attacks_bb<KING>(ksq) & b);
#endif
moveList = splat_moves(moveList, ksq, b);
if ((Type == QUIETS || Type == NON_EVASIONS) && pos.can_castle(Us & ANY_CASTLING))
for (CastlingRights cr : {Us & KING_SIDE, Us & QUEEN_SIDE})