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
+11 -69
View File
@@ -38,12 +38,6 @@ alignas(64) Magic Magics[SQUARE_NB][2];
}
#ifdef USE_PEXT
using MagicMask = u16;
#else
using MagicMask = Bitboard;
#endif
[[maybe_unused]] static Bitboard line_mask(Square sq, Direction d1, Direction d2) {
Bitboard mask = 0, dest;
for (Direction d : {d1, d2})
@@ -76,7 +70,7 @@ static void init_magics(Magic magics[][2]) {
// Sliding attacks within a rank, indexed by the slider's file and the
// 8-bit rank occupancy, yielding the 8-bit attack set on that rank
constexpr auto RankAttacks = []() {
[[maybe_unused]] constexpr auto RankAttacks = []() {
std::array<std::array<u8, 256>, FILE_NB> table{};
for (int file = 0; file < 8; ++file)
for (int occ = 0; occ < 256; ++occ)
@@ -102,38 +96,15 @@ static void init_dual_magics(DualMagic magics[]) {
#else
namespace {
[[maybe_unused]] constexpr Bitboard constexpr_pext(Bitboard b, Bitboard m) {
Bitboard result = 0, bit = 0;
while (m)
{
Bitboard last = m & -m;
result |= bool(b & last) << bit++;
m ^= last;
}
return result;
}
void init_magics(PieceType pt, Bitboard table[], Magic magics[][2]) {
#ifdef USE_COMPTIME_ATTACKS
constexpr
#endif
void
init_magics(PieceType pt,
MagicMask table[],
Magic magics[][2],
[[maybe_unused]] bool tableAlreadyInit) {
#if !defined(USE_COMPTIME_ATTACKS)
tableAlreadyInit = false;
#endif
#ifndef USE_PEXT
int seeds[][RANK_NB] = {{8977, 44560, 54343, 38998, 5731, 95205, 104912, 17020},
{728, 10316, 55013, 32803, 12281, 15100, 16645, 255}};
Bitboard occupancy[4096];
int epoch[4096] = {}, cnt = 0;
Bitboard reference[4096] = {};
#endif
int size = 0;
int size = 0;
for (Square s = SQ_A1; s <= SQ_H8; ++s)
{
@@ -142,36 +113,21 @@ constexpr
Magic& m = magics[s][pt - BISHOP];
Bitboard attacks = sliding_attack(pt, s, 0);
m.mask = attacks & ~edges;
#ifdef USE_PEXT
m.pseudoAttacks = attacks;
#else
m.shift = (Is64Bit ? 64 : 32) - popcount(m.mask);
#endif
m.attacks = s == SQ_A1 ? table : magics[s - 1][pt - BISHOP].attacks + size;
size = 0;
m.shift = (Is64Bit ? 64 : 32) - popcount(m.mask);
m.attacks = s == SQ_A1 ? table : magics[s - 1][pt - BISHOP].attacks + size;
size = 0;
Bitboard b = 0;
[[maybe_unused]] Bitboard prevSliding = -1;
do
{
#ifdef USE_PEXT
if (!tableAlreadyInit)
{
Bitboard sliding = sliding_attack(pt, s, b);
m.attacks[size] =
sliding != prevSliding ? constexpr_pext(sliding, attacks) : m.attacks[size - 1];
prevSliding = sliding;
}
#else
occupancy[size] = b;
reference[size] = sliding_attack(pt, s, b);
#endif
size++;
b = (b - m.mask) & m.mask;
} while (b);
#ifndef USE_PEXT
PRNG rng(seeds[Is64Bit][rank_of(s)]);
for (int i = 0; i < size;)
@@ -192,26 +148,12 @@ constexpr
break;
}
}
#endif
}
}
#if defined(USE_COMPTIME_ATTACKS) && defined(USE_PEXT)
constexpr auto RookTable = []() {
std::array<u16, 0x19000> result{};
Magic magics[64][2] = {};
init_magics(ROOK, result.data(), magics, false);
return result;
}();
constexpr auto BishopTable = []() {
std::array<u16, 0x1480> result{};
Magic magics[64][2] = {};
init_magics(BISHOP, result.data(), magics, false);
return result;
}();
#elif !defined(USE_DUAL_HYPERBOLA_QUINT) && !defined(USE_HYPERBOLA_QUINT)
std::array<MagicMask, 0x19000> RookTable;
std::array<MagicMask, 0x1480> BishopTable;
#if !defined(USE_DUAL_HYPERBOLA_QUINT) && !defined(USE_HYPERBOLA_QUINT)
static std::array<Bitboard, 0x19000> RookTable;
static std::array<Bitboard, 0x1480> BishopTable;
#endif
}
@@ -224,8 +166,8 @@ void init() {
#elif defined(USE_DUAL_HYPERBOLA_QUINT)
init_dual_magics(DualMagics);
#else
init_magics(ROOK, const_cast<MagicMask*>(RookTable.data()), Magics, true);
init_magics(BISHOP, const_cast<MagicMask*>(BishopTable.data()), Magics, true);
init_magics(ROOK, RookTable.data(), Magics);
init_magics(BISHOP, BishopTable.data(), Magics);
#endif
for (Square s1 = SQ_A1; s1 <= SQ_H8; ++s1)