Improve Threats Speed

Passed STC:
LLR: 2.95 (-2.94,2.94) <0.00,2.00>
Total: 23168 W: 6132 L: 5845 D: 11191
Ptnml(0-2): 77, 2405, 6325, 2708, 69
https://tests.stockfishchess.org/tests/view/69148c3c7ca8781852331831

```
Result of  50 runs
==================
base (./stockfish.master       ) =     985641  +/- 4249
test (./stockfish.patch        ) =    1038567  +/- 5679
diff                             =     +52926  +/- 4473

speedup        = +0.0537
P(speedup > 0) =  1.0000

CPU: 16 x AMD Ryzen 9 3950X 16-Core Processor
Hyperthreading: on
```

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

No functional change
This commit is contained in:
Viren6
2025-11-13 22:13:47 +01:00
committed by Joost VandeVondele
parent 7ac8e62219
commit 3ae7684714
3 changed files with 107 additions and 63 deletions
+46 -35
View File
@@ -58,6 +58,35 @@ constexpr std::array<Piece, 12> AllPieces = {
PiecePairData index_lut1[PIECE_NB][PIECE_NB]; // [attacker][attacked]
uint8_t index_lut2[PIECE_NB][SQUARE_NB][SQUARE_NB]; // [attacker][from][to]
namespace {
template<Color Perspective>
IndexType make_index_with_orientation(
Piece attacker, Square from, Square to, Piece attacked, int orientation) {
from = Square(int(from) ^ orientation);
to = Square(int(to) ^ orientation);
if constexpr (Perspective == BLACK)
{
attacker = ~attacker;
attacked = ~attacked;
}
const auto piecePairData = index_lut1[attacker][attacked];
const bool less_than = static_cast<unsigned>(from) < static_cast<unsigned>(to);
if ((piecePairData.excluded_pair_info() + less_than) & 2)
return FullThreats::Dimensions;
const IndexType index =
piecePairData.feature_index_base() + offsets[attacker][from] + index_lut2[attacker][from][to];
sf_assume(index != FullThreats::Dimensions);
return index;
}
} // namespace
static void init_index_luts() {
for (Piece attacker : AllPieces)
{
@@ -129,32 +158,8 @@ void init_threat_offsets() {
template<Color Perspective>
IndexType
FullThreats::make_index(Piece attacker, Square from, Square to, Piece attacked, Square ksq) {
from = (Square) (int(from) ^ OrientTBL[Perspective][ksq]);
to = (Square) (int(to) ^ OrientTBL[Perspective][ksq]);
if (Perspective == BLACK)
{
attacker = ~attacker;
attacked = ~attacked;
}
auto piecePairData = index_lut1[attacker][attacked];
// Some threats imply the existence of the corresponding ones in the opposite
// direction. We filter them here to ensure only one such threat is active.
// In the below addition, the 2nd lsb gets set iff either the pair is always excluded,
// or the pair is semi-excluded and from < to. By using an unsigned compare, the following
// sequence can use an add-with-carry instruction.
bool less_than = static_cast<uint8_t>(from) < static_cast<uint8_t>(to);
if ((piecePairData.excluded_pair_info() + less_than) & 2)
return Dimensions;
IndexType index =
piecePairData.feature_index_base() + offsets[attacker][from] + index_lut2[attacker][from][to];
sf_assume(index != Dimensions);
return index;
return make_index_with_orientation<Perspective>(attacker, from, to, attacked,
OrientTBL[Perspective][ksq]);
}
// Get a list of indices for active features in ascending order
@@ -162,8 +167,9 @@ template<Color Perspective>
void FullThreats::append_active_indices(const Position& pos, IndexList& active) {
static constexpr Color order[2][2] = {{WHITE, BLACK}, {BLACK, WHITE}};
Square ksq = pos.square<KING>(Perspective);
Bitboard occupied = pos.pieces();
Square ksq = pos.square<KING>(Perspective);
const int orientation = OrientTBL[Perspective][ksq];
Bitboard occupied = pos.pieces();
for (Color color : {WHITE, BLACK})
{
@@ -187,7 +193,8 @@ void FullThreats::append_active_indices(const Position& pos, IndexList& active)
Square to = pop_lsb(attacks_left);
Square from = to - right;
Piece attacked = pos.piece_on(to);
IndexType index = make_index<Perspective>(attacker, from, to, attacked, ksq);
IndexType index = make_index_with_orientation<Perspective>(
attacker, from, to, attacked, orientation);
if (index < Dimensions)
active.push_back(index);
@@ -198,7 +205,8 @@ void FullThreats::append_active_indices(const Position& pos, IndexList& active)
Square to = pop_lsb(attacks_right);
Square from = to - left;
Piece attacked = pos.piece_on(to);
IndexType index = make_index<Perspective>(attacker, from, to, attacked, ksq);
IndexType index = make_index_with_orientation<Perspective>(
attacker, from, to, attacked, orientation);
if (index < Dimensions)
active.push_back(index);
@@ -215,8 +223,8 @@ void FullThreats::append_active_indices(const Position& pos, IndexList& active)
{
Square to = pop_lsb(attacks);
Piece attacked = pos.piece_on(to);
IndexType index =
make_index<Perspective>(attacker, from, to, attacked, ksq);
IndexType index = make_index_with_orientation<Perspective>(
attacker, from, to, attacked, orientation);
if (index < Dimensions)
active.push_back(index);
@@ -243,7 +251,9 @@ void FullThreats::append_changed_indices(Square ksq,
IndexList& added,
FusedUpdateData* fusedData,
bool first) {
for (const auto dirty : diff.list)
const int orientation = OrientTBL[Perspective][ksq];
for (const auto& dirty : diff.list)
{
auto attacker = dirty.pc();
auto attacked = dirty.threatened_pc();
@@ -282,9 +292,10 @@ void FullThreats::append_changed_indices(Square ksq,
}
}
IndexType index = make_index<Perspective>(attacker, from, to, attacked, ksq);
const IndexType index =
make_index_with_orientation<Perspective>(attacker, from, to, attacked, orientation);
if (index != Dimensions)
if (index < Dimensions)
(add ? added : removed).push_back(index);
}
}
+17 -1
View File
@@ -336,7 +336,8 @@ struct AccumulatorUpdateContext {
to_psqt_weight_vector(indices)...);
}
void apply(typename FeatureSet::IndexList added, typename FeatureSet::IndexList removed) {
void apply(const typename FeatureSet::IndexList& added,
const typename FeatureSet::IndexList& removed) {
const auto fromAcc = from.template acc<Dimensions>().accumulation[Perspective];
const auto toAcc = to.template acc<Dimensions>().accumulation[Perspective];
@@ -573,6 +574,21 @@ void update_accumulator_incremental(
FeatureSet::template append_changed_indices<Perspective>(ksq, computed.diff, added,
removed);
if (!added.size() && !removed.size())
{
auto& targetAcc = target_state.template acc<TransformedFeatureDimensions>();
const auto& sourceAcc = computed.template acc<TransformedFeatureDimensions>();
std::memcpy(targetAcc.accumulation[Perspective], sourceAcc.accumulation[Perspective],
sizeof(targetAcc.accumulation[Perspective]));
std::memcpy(targetAcc.psqtAccumulation[Perspective],
sourceAcc.psqtAccumulation[Perspective],
sizeof(targetAcc.psqtAccumulation[Perspective]));
targetAcc.computed[Perspective] = true;
return;
}
auto updateContext =
make_accumulator_update_context<Perspective>(featureTransformer, computed, target_state);
+44 -27
View File
@@ -1051,12 +1051,22 @@ inline void add_dirty_threat(
template<bool PutPiece, bool ComputeRay>
void Position::update_piece_threats(Piece pc, Square s, DirtyThreats* const dts) {
// Add newly threatened pieces
Bitboard occupied = pieces();
const Bitboard occupied = pieces();
const Bitboard rookQueens = pieces(ROOK, QUEEN);
const Bitboard bishopQueens = pieces(BISHOP, QUEEN);
const Bitboard knights = pieces(KNIGHT);
const Bitboard kings = pieces(KING);
const Bitboard whitePawns = pieces(WHITE, PAWN);
const Bitboard blackPawns = pieces(BLACK, PAWN);
Bitboard rAttacks = attacks_bb<ROOK>(s, occupied);
Bitboard bAttacks = attacks_bb<BISHOP>(s, occupied);
Bitboard qAttacks = rAttacks | bAttacks;
const Bitboard rAttacks = attacks_bb<ROOK>(s, occupied);
const Bitboard bAttacks = attacks_bb<BISHOP>(s, occupied);
Bitboard qAttacks = Bitboard(0);
if constexpr (ComputeRay)
qAttacks = rAttacks | bAttacks;
else if (type_of(pc) == QUEEN)
qAttacks = rAttacks | bAttacks;
Bitboard threatened;
@@ -1092,35 +1102,42 @@ void Position::update_piece_threats(Piece pc, Square s, DirtyThreats* const dts)
add_dirty_threat<PutPiece>(dts, pc, threatened_pc, s, threatened_sq);
}
Bitboard sliders = (pieces(ROOK, QUEEN) & rAttacks) | (pieces(BISHOP, QUEEN) & bAttacks);
Bitboard sliders = (rookQueens & rAttacks) | (bishopQueens & bAttacks);
Bitboard incoming_threats = (attacks_bb<KNIGHT>(s, occupied) & pieces(KNIGHT))
| (attacks_bb<PAWN>(s, WHITE) & pieces(BLACK, PAWN))
| (attacks_bb<PAWN>(s, BLACK) & pieces(WHITE, PAWN))
| (attacks_bb<KING>(s, occupied) & pieces(KING));
while (sliders)
if constexpr (ComputeRay)
{
Square slider_sq = pop_lsb(sliders);
Piece slider = piece_on(slider_sq);
Bitboard ray = RayPassBB[slider_sq][s] & ~BetweenBB[slider_sq][s];
threatened = ray & qAttacks & occupied;
assert(!more_than_one(threatened));
if (ComputeRay && threatened)
while (sliders)
{
Square threatened_sq = lsb(threatened);
Square slider_sq = pop_lsb(sliders);
Piece slider = piece_on(slider_sq);
Piece threatened_pc = piece_on(threatened_sq);
add_dirty_threat<!PutPiece>(dts, slider, threatened_pc, slider_sq, threatened_sq);
const Bitboard ray = RayPassBB[slider_sq][s] & ~BetweenBB[slider_sq][s];
const Bitboard discovered = ray & qAttacks & occupied;
assert(!more_than_one(discovered));
if (discovered)
{
const Square threatened_sq = lsb(discovered);
const Piece threatened_pc = piece_on(threatened_sq);
add_dirty_threat<!PutPiece>(dts, slider, threatened_pc, slider_sq, threatened_sq);
}
add_dirty_threat<PutPiece>(dts, slider, pc, slider_sq, s);
}
}
else
{
while (sliders)
{
Square slider_sq = pop_lsb(sliders);
Piece slider = piece_on(slider_sq);
add_dirty_threat<PutPiece>(dts, slider, pc, slider_sq, s);
}
add_dirty_threat<PutPiece>(dts, slider, pc, slider_sq, s);
}
// Add threats of sliders that were already threatening s,
// sliders are already handled in the loop above
Bitboard incoming_threats =
(PseudoAttacks[KNIGHT][s] & knights) | (attacks_bb<PAWN>(s, WHITE) & blackPawns)
| (attacks_bb<PAWN>(s, BLACK) & whitePawns) | (PseudoAttacks[KING][s] & kings);
while (incoming_threats)
{