mirror of
https://github.com/official-stockfish/Stockfish.git
synced 2026-07-22 12:47:08 +00:00
Improve update_piece_threats
passed on avx512ICL: LLR: 2.95 (-2.94,2.94) <0.00,2.00> Total: 30240 W: 8026 L: 7726 D: 14488 Ptnml(0-2): 95, 3235, 8171, 3513, 106 https://tests.stockfishchess.org/tests/view/69281d9ab23dfeae38cfeeb8 passed on generic architectures: LLR: 2.94 (-2.94,2.94) <0.00,2.00> Total: 73184 W: 19183 L: 18821 D: 35180 Ptnml(0-2): 258, 7988, 19744, 8338, 264 https://tests.stockfishchess.org/tests/view/6928ba11b23dfeae38cff276 subsequent cleanups tested as: LLR: 2.94 (-2.94,2.94) <-1.75,0.25> Total: 72480 W: 18678 L: 18502 D: 35300 Ptnml(0-2): 242, 7925, 19718, 8125, 230 https://tests.stockfishchess.org/tests/view/692a26adb23dfeae38cff566 We add an argument noRaysContaining, which skips all discoveries which contain all bits in the argument; if the argument is from | to, then this will eliminate the discovery. Separately, on AVX512ICL we can speed up the computation of DirtyThreats by moving from a pop_lsb loop to a vector extraction with vpcompressb. See PR for details. closes https://github.com/official-stockfish/Stockfish/pull/6453 No functional change
This commit is contained in:
committed by
Joost VandeVondele
parent
9e2ee13e77
commit
abd835dcbc
@@ -142,6 +142,13 @@ class ValueList {
|
|||||||
const T* end() const { return values_ + size_; }
|
const T* end() const { return values_ + size_; }
|
||||||
const T& operator[](int index) const { return values_[index]; }
|
const T& operator[](int index) const { return values_[index]; }
|
||||||
|
|
||||||
|
T* make_space(size_t count) {
|
||||||
|
T* result = &values_[size_];
|
||||||
|
size_ += count;
|
||||||
|
assert(size_ <= MaxSize);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
T values_[MaxSize];
|
T values_[MaxSize];
|
||||||
std::size_t size_ = 0;
|
std::size_t size_ = 0;
|
||||||
|
|||||||
+80
-14
@@ -1052,8 +1052,51 @@ inline void add_dirty_threat(
|
|||||||
dts->list.push_back({pc, threatened, s, threatenedSq, PutPiece});
|
dts->list.push_back({pc, threatened, s, threatenedSq, PutPiece});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef USE_AVX512ICL
|
||||||
|
// Given a DirtyThreat template and bit offsets to insert the piece type and square, write the threats
|
||||||
|
// present at the given bitboard.
|
||||||
|
template<int SqShift, int PcShift>
|
||||||
|
void write_multiple_dirties(const Position& p,
|
||||||
|
Bitboard mask,
|
||||||
|
DirtyThreat dt_template,
|
||||||
|
DirtyThreats* dts) {
|
||||||
|
static_assert(sizeof(DirtyThreat) == 4);
|
||||||
|
|
||||||
|
const __m512i board = _mm512_loadu_si512(p.piece_array().data());
|
||||||
|
const __m512i AllSquares = _mm512_set_epi8(
|
||||||
|
63, 62, 61, 60, 59, 58, 57, 56, 55, 54, 53, 52, 51, 50, 49, 48, 47, 46, 45, 44, 43, 42, 41,
|
||||||
|
40, 39, 38, 37, 36, 35, 34, 33, 32, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18,
|
||||||
|
17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0);
|
||||||
|
|
||||||
|
const int dt_count = popcount(mask);
|
||||||
|
assert(dt_count <= 16);
|
||||||
|
|
||||||
|
const __m512i template_v = _mm512_set1_epi32(dt_template.raw());
|
||||||
|
auto* write = dts->list.make_space(dt_count);
|
||||||
|
|
||||||
|
// Extract the list of squares and upconvert to 32 bits. There are never more than 16
|
||||||
|
// incoming threats so this is sufficient.
|
||||||
|
__m512i threat_squares = _mm512_maskz_compress_epi8(mask, AllSquares);
|
||||||
|
threat_squares = _mm512_cvtepi8_epi32(_mm512_castsi512_si128(threat_squares));
|
||||||
|
|
||||||
|
__m512i threat_pieces =
|
||||||
|
_mm512_maskz_permutexvar_epi8(0x1111111111111111ULL, threat_squares, board);
|
||||||
|
|
||||||
|
// Shift the piece and square into place
|
||||||
|
threat_squares = _mm512_slli_epi32(threat_squares, SqShift);
|
||||||
|
threat_pieces = _mm512_slli_epi32(threat_pieces, PcShift);
|
||||||
|
|
||||||
|
const __m512i dirties =
|
||||||
|
_mm512_ternarylogic_epi32(template_v, threat_squares, threat_pieces, 254 /* A | B | C */);
|
||||||
|
_mm512_storeu_si512(reinterpret_cast<__m512i*>(write), dirties);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
template<bool PutPiece, bool ComputeRay>
|
template<bool PutPiece, bool ComputeRay>
|
||||||
void Position::update_piece_threats(Piece pc, Square s, DirtyThreats* const dts) {
|
void Position::update_piece_threats(Piece pc,
|
||||||
|
Square s,
|
||||||
|
DirtyThreats* const dts,
|
||||||
|
Bitboard noRaysContaining) {
|
||||||
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);
|
||||||
@@ -1093,7 +1136,36 @@ void Position::update_piece_threats(Piece pc, Square s, DirtyThreats* const dts)
|
|||||||
}
|
}
|
||||||
|
|
||||||
threatened &= occupied;
|
threatened &= occupied;
|
||||||
|
Bitboard sliders = (rookQueens & rAttacks) | (bishopQueens & bAttacks);
|
||||||
|
Bitboard incoming_threats =
|
||||||
|
(PseudoAttacks[KNIGHT][s] & knights) | (attacks_bb<PAWN>(s, WHITE) & blackPawns)
|
||||||
|
| (attacks_bb<PAWN>(s, BLACK) & whitePawns) | (PseudoAttacks[KING][s] & kings);
|
||||||
|
|
||||||
|
#ifdef USE_AVX512ICL
|
||||||
|
if (threatened)
|
||||||
|
{
|
||||||
|
if constexpr (PutPiece)
|
||||||
|
{
|
||||||
|
dts->threatenedSqs |= threatened;
|
||||||
|
dts->threateningSqs |= square_bb(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
DirtyThreat dt_template{pc, NO_PIECE, s, Square(0), PutPiece};
|
||||||
|
write_multiple_dirties<DirtyThreat::ThreatenedSqOffset, DirtyThreat::ThreatenedPcOffset>(
|
||||||
|
*this, threatened, dt_template, dts);
|
||||||
|
}
|
||||||
|
|
||||||
|
Bitboard all_attackers = sliders | incoming_threats;
|
||||||
|
if (!all_attackers)
|
||||||
|
return; // Square s is threatened iff there's at least one attacker
|
||||||
|
|
||||||
|
dts->threatenedSqs |= square_bb(s);
|
||||||
|
dts->threateningSqs |= all_attackers;
|
||||||
|
|
||||||
|
DirtyThreat dt_template{NO_PIECE, pc, Square(0), s, PutPiece};
|
||||||
|
write_multiple_dirties<DirtyThreat::PcSqOffset, DirtyThreat::PcOffset>(*this, all_attackers,
|
||||||
|
dt_template, dts);
|
||||||
|
#else
|
||||||
while (threatened)
|
while (threatened)
|
||||||
{
|
{
|
||||||
Square threatenedSq = pop_lsb(threatened);
|
Square threatenedSq = pop_lsb(threatened);
|
||||||
@@ -1104,8 +1176,7 @@ void Position::update_piece_threats(Piece pc, Square s, DirtyThreats* const dts)
|
|||||||
|
|
||||||
add_dirty_threat<PutPiece>(dts, pc, threatenedPc, s, threatenedSq);
|
add_dirty_threat<PutPiece>(dts, pc, threatenedPc, s, threatenedSq);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
Bitboard sliders = (rookQueens & rAttacks) | (bishopQueens & bAttacks);
|
|
||||||
|
|
||||||
if constexpr (ComputeRay)
|
if constexpr (ComputeRay)
|
||||||
{
|
{
|
||||||
@@ -1118,30 +1189,24 @@ void Position::update_piece_threats(Piece pc, Square s, DirtyThreats* const dts)
|
|||||||
const Bitboard discovered = ray & qAttacks & occupied;
|
const Bitboard discovered = ray & qAttacks & occupied;
|
||||||
|
|
||||||
assert(!more_than_one(discovered));
|
assert(!more_than_one(discovered));
|
||||||
if (discovered)
|
if (discovered && (RayPassBB[sliderSq][s] & noRaysContaining) != noRaysContaining)
|
||||||
{
|
{
|
||||||
const Square threatenedSq = lsb(discovered);
|
const Square threatenedSq = lsb(discovered);
|
||||||
const Piece threatenedPc = piece_on(threatenedSq);
|
const Piece threatenedPc = piece_on(threatenedSq);
|
||||||
add_dirty_threat<!PutPiece>(dts, slider, threatenedPc, sliderSq, threatenedSq);
|
add_dirty_threat<!PutPiece>(dts, slider, threatenedPc, sliderSq, threatenedSq);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifndef USE_AVX512ICL // for ICL, direct threats were processed earlier (all_attackers)
|
||||||
add_dirty_threat<PutPiece>(dts, slider, pc, sliderSq, s);
|
add_dirty_threat<PutPiece>(dts, slider, pc, sliderSq, s);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
while (sliders)
|
incoming_threats |= sliders;
|
||||||
{
|
|
||||||
Square sliderSq = pop_lsb(sliders);
|
|
||||||
Piece slider = piece_on(sliderSq);
|
|
||||||
add_dirty_threat<PutPiece>(dts, slider, pc, sliderSq, s);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Bitboard incoming_threats =
|
#ifndef USE_AVX512ICL
|
||||||
(PseudoAttacks[KNIGHT][s] & knights) | (attacks_bb<PAWN>(s, WHITE) & blackPawns)
|
|
||||||
| (attacks_bb<PAWN>(s, BLACK) & whitePawns) | (PseudoAttacks[KING][s] & kings);
|
|
||||||
|
|
||||||
while (incoming_threats)
|
while (incoming_threats)
|
||||||
{
|
{
|
||||||
Square srcSq = pop_lsb(incoming_threats);
|
Square srcSq = pop_lsb(incoming_threats);
|
||||||
@@ -1152,6 +1217,7 @@ void Position::update_piece_threats(Piece pc, Square s, DirtyThreats* const dts)
|
|||||||
|
|
||||||
add_dirty_threat<PutPiece>(dts, srcPc, pc, srcSq, s);
|
add_dirty_threat<PutPiece>(dts, srcPc, pc, srcSq, s);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
// Helper used to do/undo a castling move. This is a bit
|
// Helper used to do/undo a castling move. This is a bit
|
||||||
|
|||||||
+6
-3
@@ -187,7 +187,10 @@ class Position {
|
|||||||
|
|
||||||
// Other helpers
|
// Other helpers
|
||||||
template<bool PutPiece, bool ComputeRay = true>
|
template<bool PutPiece, bool ComputeRay = true>
|
||||||
void update_piece_threats(Piece pc, Square s, DirtyThreats* const dts);
|
void update_piece_threats(Piece pc,
|
||||||
|
Square s,
|
||||||
|
DirtyThreats* const dts,
|
||||||
|
Bitboard noRaysContaining = -1ULL);
|
||||||
void move_piece(Square from, Square to, DirtyThreats* const dts = nullptr);
|
void move_piece(Square from, Square to, DirtyThreats* const dts = nullptr);
|
||||||
template<bool Do>
|
template<bool Do>
|
||||||
void do_castling(Color us,
|
void do_castling(Color us,
|
||||||
@@ -372,7 +375,7 @@ inline void Position::move_piece(Square from, Square to, DirtyThreats* const dts
|
|||||||
Bitboard fromTo = from | to;
|
Bitboard fromTo = from | to;
|
||||||
|
|
||||||
if (dts)
|
if (dts)
|
||||||
update_piece_threats<false>(pc, from, dts);
|
update_piece_threats<false>(pc, from, dts, fromTo);
|
||||||
|
|
||||||
byTypeBB[ALL_PIECES] ^= fromTo;
|
byTypeBB[ALL_PIECES] ^= fromTo;
|
||||||
byTypeBB[type_of(pc)] ^= fromTo;
|
byTypeBB[type_of(pc)] ^= fromTo;
|
||||||
@@ -381,7 +384,7 @@ inline void Position::move_piece(Square from, Square to, DirtyThreats* const dts
|
|||||||
board[to] = pc;
|
board[to] = pc;
|
||||||
|
|
||||||
if (dts)
|
if (dts)
|
||||||
update_piece_threats<true>(pc, to, dts);
|
update_piece_threats<true>(pc, to, dts, fromTo);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void Position::swap_piece(Square s, Piece pc, DirtyThreats* const dts) {
|
inline void Position::swap_piece(Square s, Piece pc, DirtyThreats* const dts) {
|
||||||
|
|||||||
+11
-2
@@ -293,9 +293,17 @@ struct DirtyPiece {
|
|||||||
|
|
||||||
// Keep track of what threats change on the board (used by NNUE)
|
// Keep track of what threats change on the board (used by NNUE)
|
||||||
struct DirtyThreat {
|
struct DirtyThreat {
|
||||||
|
static constexpr int PcSqOffset = 0;
|
||||||
|
static constexpr int ThreatenedSqOffset = 8;
|
||||||
|
static constexpr int ThreatenedPcOffset = 16;
|
||||||
|
static constexpr int PcOffset = 20;
|
||||||
|
|
||||||
DirtyThreat() { /* don't initialize data */ }
|
DirtyThreat() { /* don't initialize data */ }
|
||||||
|
DirtyThreat(uint32_t raw) :
|
||||||
|
data(raw) {}
|
||||||
DirtyThreat(Piece pc, Piece threatened_pc, Square pc_sq, Square threatened_sq, bool add) {
|
DirtyThreat(Piece pc, Piece threatened_pc, Square pc_sq, Square threatened_sq, bool add) {
|
||||||
data = (add << 31) | (pc << 20) | (threatened_pc << 16) | (threatened_sq << 8) | (pc_sq);
|
data = (uint32_t(add) << 31) | (pc << PcOffset) | (threatened_pc << ThreatenedPcOffset)
|
||||||
|
| (threatened_sq << ThreatenedSqOffset) | (pc_sq << PcSqOffset);
|
||||||
}
|
}
|
||||||
|
|
||||||
Piece pc() const { return static_cast<Piece>(data >> 20 & 0xf); }
|
Piece pc() const { return static_cast<Piece>(data >> 20 & 0xf); }
|
||||||
@@ -303,12 +311,13 @@ struct DirtyThreat {
|
|||||||
Square threatened_sq() const { return static_cast<Square>(data >> 8 & 0xff); }
|
Square threatened_sq() const { return static_cast<Square>(data >> 8 & 0xff); }
|
||||||
Square pc_sq() const { return static_cast<Square>(data & 0xff); }
|
Square pc_sq() const { return static_cast<Square>(data & 0xff); }
|
||||||
bool add() const { return data >> 31; }
|
bool add() const { return data >> 31; }
|
||||||
|
uint32_t raw() const { return data; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
uint32_t data;
|
uint32_t data;
|
||||||
};
|
};
|
||||||
|
|
||||||
using DirtyThreatList = ValueList<DirtyThreat, 80>;
|
using DirtyThreatList = ValueList<DirtyThreat, 96>;
|
||||||
|
|
||||||
// A piece can be involved in at most 8 outgoing attacks and 16 incoming attacks.
|
// A piece can be involved in at most 8 outgoing attacks and 16 incoming attacks.
|
||||||
// Moving a piece also can reveal at most 8 discovered attacks.
|
// Moving a piece also can reveal at most 8 discovered attacks.
|
||||||
|
|||||||
Reference in New Issue
Block a user