diff --git a/src/attacks.cpp b/src/attacks.cpp index 740acf2a3..809d8b7dd 100644 --- a/src/attacks.cpp +++ b/src/attacks.cpp @@ -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, 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 result{}; - Magic magics[64][2] = {}; - init_magics(ROOK, result.data(), magics, false); - return result; -}(); -constexpr auto BishopTable = []() { - std::array 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 RookTable; -std::array BishopTable; + #if !defined(USE_DUAL_HYPERBOLA_QUINT) && !defined(USE_HYPERBOLA_QUINT) +static std::array RookTable; +static std::array BishopTable; #endif } @@ -224,8 +166,8 @@ void init() { #elif defined(USE_DUAL_HYPERBOLA_QUINT) init_dual_magics(DualMagics); #else - init_magics(ROOK, const_cast(RookTable.data()), Magics, true); - init_magics(BISHOP, const_cast(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) diff --git a/src/attacks.h b/src/attacks.h index 0de24e0c7..de29914c9 100644 --- a/src/attacks.h +++ b/src/attacks.h @@ -31,7 +31,7 @@ #define USE_HYPERBOLA_QUINT #elif defined(__loongarch__) && __loongarch_grlen == 64 #define USE_HYPERBOLA_QUINT -#elif defined(USE_AVX2) && !defined(USE_PEXT) +#elif defined(USE_AVX2) #include #define USE_DUAL_HYPERBOLA_QUINT #endif @@ -75,7 +75,7 @@ const Magic& magic(Square s, PieceType pt); #elif defined(USE_DUAL_HYPERBOLA_QUINT) -struct DualMagic { +struct alignas(32) DualMagic { // file, diagonal, unused, antidiagonal Bitboard maskFile, maskDiag, maskNone, maskAntidiag; // Precomputed 2 * square_bb(sq), 2 * reverse(square_bb(sq)) @@ -128,37 +128,23 @@ const DualMagic& dual_magic(Square s); #else // Magic holds all magic bitboards relevant data for a single square struct Magic { - Bitboard mask; - #ifdef USE_PEXT - u16* attacks; - Bitboard pseudoAttacks; - #else + Bitboard mask; Bitboard* attacks; Bitboard magic; unsigned shift; - #endif // Compute the attack's index using the 'magic bitboards' approach unsigned index(Bitboard occupied) const { - - #ifdef USE_PEXT - return unsigned(pext(occupied, mask)); - #else if (Is64Bit) return unsigned(((occupied & mask) * magic) >> shift); unsigned lo = unsigned(occupied) & unsigned(mask); unsigned hi = unsigned(occupied >> 32) & unsigned(mask >> 32); return (lo * unsigned(magic) ^ hi * unsigned(magic >> 32)) >> shift; - #endif } Bitboard attacks_bb([[maybe_unused]] Square s, Bitboard occupied) const { - #ifdef USE_PEXT - return pdep(attacks[index(occupied)], pseudoAttacks); - #else return attacks[index(occupied)]; - #endif } }; diff --git a/src/movegen.cpp b/src/movegen.cpp index 7b8565a34..12d66f466 100644 --- a/src/movegen.cpp +++ b/src/movegen.cpp @@ -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, 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, 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 -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(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(KnightKingMoves[Pt == KING][from].data()); - _mm_storeu_si128(reinterpret_cast<__m128i*>(moveList), - _mm_maskz_compress_epi16(mask, moves)); - } - - return moveList + popcount(mask); -} - #else template @@ -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(moveList, from, pos.pieces(), target); - continue; - } -#endif - Bitboard b = Attacks::attacks_bb(from, pos.pieces()) & target; + Square from = pop_lsb(bb); + Bitboard b = Attacks::attacks_bb(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(pos, moveList, target); } - Bitboard b = Type == EVASIONS ? ~pos.pieces(Us) : target; + Bitboard b = Attacks::attacks_bb(ksq) & (Type == EVASIONS ? ~pos.pieces(Us) : target); -#ifdef USE_AVX512ICL - moveList = splat_precomputed_moves(moveList, ksq, 0ULL, b); -#else - moveList = splat_moves(moveList, ksq, Attacks::attacks_bb(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})