Optimize attacks

STC:  https://tests.stockfishchess.org/tests/view/6a57f12c5529b8472df80e2a
LLR: 2.95 (-2.94,2.94) <0.00,2.00>
Total: 85856 W: 22400 L: 22037 D: 41419
Ptnml(0-2): 153, 8999, 24290, 9304, 182

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

No functional change
This commit is contained in:
mstembera
2026-07-20 10:59:45 +02:00
committed by Joost VandeVondele
parent b4ea9205a6
commit d70dec7d6f
4 changed files with 56 additions and 41 deletions
+1 -1
View File
@@ -903,7 +903,7 @@ endif
ifeq ($(pext),yes) ifeq ($(pext),yes)
CXXFLAGS += -DUSE_PEXT CXXFLAGS += -DUSE_PEXT
ifeq ($(comp),$(filter $(comp),gcc clang mingw icx)) ifeq ($(comp),$(filter $(comp),gcc clang mingw icx))
CXXFLAGS += -mbmi2 -DUSE_COMPTIME_ATTACKS CXXFLAGS += -mbmi2
endif endif
endif endif
+7 -22
View File
@@ -24,15 +24,17 @@
namespace Stockfish::Attacks { namespace Stockfish::Attacks {
namespace { #ifdef USE_DUAL_HYPERBOLA_QUINT
alignas(64) DualMagic DualMagics[SQUARE_NB];
#endif
Bitboard LineBB[SQUARE_NB][SQUARE_NB]; Bitboard LineBB[SQUARE_NB][SQUARE_NB];
Bitboard BetweenBB[SQUARE_NB][SQUARE_NB]; Bitboard BetweenBB[SQUARE_NB][SQUARE_NB];
Bitboard RayPassBB[SQUARE_NB][SQUARE_NB]; Bitboard RayPassBB[SQUARE_NB][SQUARE_NB];
#ifdef USE_DUAL_HYPERBOLA_QUINT namespace {
alignas(64) DualMagic DualMagics[SQUARE_NB];
#else #ifndef USE_DUAL_HYPERBOLA_QUINT
alignas(64) Magic Magics[SQUARE_NB][2]; alignas(64) Magic Magics[SQUARE_NB][2];
#endif #endif
@@ -187,28 +189,11 @@ void init() {
} }
} }
#ifdef USE_DUAL_HYPERBOLA_QUINT #ifndef USE_DUAL_HYPERBOLA_QUINT
const DualMagic& dual_magic(Square s) { return DualMagics[s]; }
#else
const Magic& magic(Square s, PieceType pt) { const Magic& magic(Square s, PieceType pt) {
assert((pt == BISHOP || pt == ROOK) && is_ok(s)); assert((pt == BISHOP || pt == ROOK) && is_ok(s));
return Magics[s][pt - BISHOP]; return Magics[s][pt - BISHOP];
} }
#endif #endif
Bitboard line_bb(Square s1, Square s2) {
assert(is_ok(s1) && is_ok(s2));
return LineBB[s1][s2];
}
Bitboard between_bb(Square s1, Square s2) {
assert(is_ok(s1) && is_ok(s2));
return BetweenBB[s1][s2];
}
Bitboard ray_pass_bb(Square s1, Square s2) {
assert(is_ok(s1) && is_ok(s2));
return RayPassBB[s1][s2];
}
} // namespace Stockfish::Attacks } // namespace Stockfish::Attacks
+30 -4
View File
@@ -22,6 +22,7 @@
#include <cassert> #include <cassert>
#include <array> #include <array>
#include <initializer_list> #include <initializer_list>
#include <utility>
#include "types.h" #include "types.h"
#include "bitboard.h" #include "bitboard.h"
@@ -135,7 +136,9 @@ struct alignas(32) DualMagic {
} }
}; };
const DualMagic& dual_magic(Square s); extern DualMagic DualMagics[SQUARE_NB];
inline const DualMagic& dual_magic(Square s) { return DualMagics[s]; }
#else #else
// Magic holds all magic bitboards relevant data for a single square // Magic holds all magic bitboards relevant data for a single square
@@ -164,9 +167,24 @@ const Magic& magic(Square s, PieceType pt);
#endif #endif
Bitboard line_bb(Square s1, Square s2); extern Bitboard LineBB[SQUARE_NB][SQUARE_NB];
Bitboard between_bb(Square s1, Square s2); extern Bitboard BetweenBB[SQUARE_NB][SQUARE_NB];
Bitboard ray_pass_bb(Square s1, Square s2); extern Bitboard RayPassBB[SQUARE_NB][SQUARE_NB];
inline Bitboard line_bb(Square s1, Square s2) {
assert(is_ok(s1) && is_ok(s2));
return LineBB[s1][s2];
}
inline Bitboard between_bb(Square s1, Square s2) {
assert(is_ok(s1) && is_ok(s2));
return BetweenBB[s1][s2];
}
inline Bitboard ray_pass_bb(Square s1, Square s2) {
assert(is_ok(s1) && is_ok(s2));
return RayPassBB[s1][s2];
}
// Returns the bitboard of target square for the given step // Returns the bitboard of target square for the given step
// from the given square. If the step is off the board, returns empty bitboard. // from the given square. If the step is off the board, returns empty bitboard.
@@ -304,6 +322,14 @@ inline Bitboard attacks_bb(Square s, Bitboard occupied) {
#endif #endif
} }
inline std::pair<Bitboard, Bitboard> both_attacks_bb(Square s, Bitboard occupied) {
#ifdef USE_DUAL_HYPERBOLA_QUINT
return dual_magic(s).both_attacks_bb(occupied);
#else
return {attacks_bb<BISHOP>(s, occupied), attacks_bb<ROOK>(s, occupied)};
#endif
}
// Returns the attacks by the given piece // Returns the attacks by the given piece
// assuming the board is occupied according to the passed Bitboard. // assuming the board is occupied according to the passed Bitboard.
// Sliding piece attacks do not continue past an occupied square. // Sliding piece attacks do not continue past an occupied square.
+18 -14
View File
@@ -469,12 +469,13 @@ void Position::set_check_info() const {
update_slider_blockers(WHITE); update_slider_blockers(WHITE);
update_slider_blockers(BLACK); update_slider_blockers(BLACK);
Square ksq = square<KING>(~sideToMove); Square ksq = square<KING>(~sideToMove);
const auto [bishopAttacks, rookAttacks] = both_attacks_bb(ksq, pieces());
st->checkSquares[PAWN] = attacks_bb<PAWN>(ksq, ~sideToMove); st->checkSquares[PAWN] = attacks_bb<PAWN>(ksq, ~sideToMove);
st->checkSquares[KNIGHT] = attacks_bb<KNIGHT>(ksq); st->checkSquares[KNIGHT] = attacks_bb<KNIGHT>(ksq);
st->checkSquares[BISHOP] = attacks_bb<BISHOP>(ksq, pieces()); st->checkSquares[BISHOP] = bishopAttacks;
st->checkSquares[ROOK] = attacks_bb<ROOK>(ksq, pieces()); st->checkSquares[ROOK] = rookAttacks;
st->checkSquares[QUEEN] = st->checkSquares[BISHOP] | st->checkSquares[ROOK]; st->checkSquares[QUEEN] = st->checkSquares[BISHOP] | st->checkSquares[ROOK];
st->checkSquares[KING] = 0; st->checkSquares[KING] = 0;
} }
@@ -641,8 +642,9 @@ void Position::update_slider_blockers(Color c) const {
// Slider attacks use the occupied bitboard to indicate occupancy. // Slider attacks use the occupied bitboard to indicate occupancy.
Bitboard Position::attackers_to(Square s, Bitboard occupied) const { Bitboard Position::attackers_to(Square s, Bitboard occupied) const {
return (attacks_bb<ROOK>(s, occupied) & pieces(ROOK, QUEEN)) const auto [bishopAttacks, rookAttacks] = both_attacks_bb(s, occupied);
| (attacks_bb<BISHOP>(s, occupied) & pieces(BISHOP, QUEEN))
return (rookAttacks & pieces(ROOK, QUEEN)) | (bishopAttacks & pieces(BISHOP, QUEEN))
| (attacks_bb<PAWN>(s, BLACK) & pieces(WHITE, PAWN)) | (attacks_bb<PAWN>(s, BLACK) & pieces(WHITE, PAWN))
| (attacks_bb<PAWN>(s, WHITE) & pieces(BLACK, PAWN)) | (attacks_bb<PAWN>(s, WHITE) & pieces(BLACK, PAWN))
| (attacks_bb<KNIGHT>(s) & pieces(KNIGHT)) | (attacks_bb<KING>(s) & pieces(KING)); | (attacks_bb<KNIGHT>(s) & pieces(KNIGHT)) | (attacks_bb<KING>(s) & pieces(KING));
@@ -789,12 +791,12 @@ bool Position::gives_check(Move m) const {
// checks and ordinary discovered check, so the only case we need to handle // checks and ordinary discovered check, so the only case we need to handle
// is the unusual case of a discovered check through the captured pawn. // is the unusual case of a discovered check through the captured pawn.
case EN_PASSANT : { case EN_PASSANT : {
Square capsq = make_square(file_of(to), rank_of(from)); Square capsq = make_square(file_of(to), rank_of(from));
Bitboard b = (pieces() ^ from ^ capsq) | to; Bitboard b = (pieces() ^ from ^ capsq) | to;
const auto [bishopAttacks, rookAttacks] = both_attacks_bb(square<KING>(~sideToMove), b);
return (attacks_bb<ROOK>(square<KING>(~sideToMove), b) & pieces(sideToMove, QUEEN, ROOK)) return (rookAttacks & pieces(sideToMove, QUEEN, ROOK))
| (attacks_bb<BISHOP>(square<KING>(~sideToMove), b) | (bishopAttacks & pieces(sideToMove, QUEEN, BISHOP));
& pieces(sideToMove, QUEEN, BISHOP));
} }
default : //CASTLING default : //CASTLING
{ {
@@ -1189,8 +1191,9 @@ void Position::update_piece_threats(Piece pc,
const Bitboard occupied = pieces(); const Bitboard occupied = pieces();
const Bitboard rookQueens = pieces(ROOK, QUEEN); const Bitboard rookQueens = pieces(ROOK, QUEEN);
const Bitboard bishopQueens = pieces(BISHOP, QUEEN); const Bitboard bishopQueens = pieces(BISHOP, QUEEN);
const Bitboard rAttacks = attacks_bb<ROOK>(s, occupied); const auto attacks = both_attacks_bb(s, occupied);
const Bitboard bAttacks = attacks_bb<BISHOP>(s, occupied); const Bitboard bAttacks = attacks.first;
const Bitboard rAttacks = attacks.second;
const Bitboard occupiedNoK = occupied ^ pieces(KING); const Bitboard occupiedNoK = occupied ^ pieces(KING);
Bitboard sliders = (rookQueens & rAttacks) | (bishopQueens & bAttacks); Bitboard sliders = (rookQueens & rAttacks) | (bishopQueens & bAttacks);
@@ -1508,8 +1511,9 @@ bool Position::see_ge(Move m, int threshold) const {
assert(swap >= res); assert(swap >= res);
occupied ^= least_significant_square_bb(bb); occupied ^= least_significant_square_bb(bb);
attackers |= (attacks_bb<BISHOP>(to, occupied) & pieces(BISHOP, QUEEN)) const auto [bishopAttacks, rookAttacks] = both_attacks_bb(to, occupied);
| (attacks_bb<ROOK>(to, occupied) & pieces(ROOK, QUEEN)); attackers |=
(bishopAttacks & pieces(BISHOP, QUEEN)) | (rookAttacks & pieces(ROOK, QUEEN));
} }
else // KING else // KING