mirror of
https://github.com/official-stockfish/Stockfish.git
synced 2026-07-22 12:47:08 +00:00
Simplify out double_inc_update
Passed STC https://tests.stockfishchess.org/tests/view/69e82e200e9667dd5a765631 LLR: 2.93 (-2.94,2.94) <-1.75,0.25> Total: 115424 W: 29950 L: 29822 D: 55652 Ptnml(0-2): 318, 12712, 31544, 12800, 338 Passed AVX2-only STC https://tests.stockfishchess.org/tests/view/69e953080e9667dd5a7657c0 LLR: 2.93 (-2.94,2.94) <-1.75,0.25> Total: 134720 W: 34773 L: 34665 D: 65282 Ptnml(0-2): 344, 14958, 36694, 14974, 390 Now that our L1 size is much smaller, the overhead of tracking diffs for `double_inc_update` is a larger share of the cost. Interestingly ces42 measured a -0.9% slowdown locally (avxvnni build). Meanwhile Torom and I find this branch to be 2% faster. I'm not sure exactly what's going on but more tests may be in order closes https://github.com/official-stockfish/Stockfish/pull/6776 No functional change
This commit is contained in:
committed by
Joost VandeVondele
parent
0e78190b72
commit
1a882efc7f
@@ -27,7 +27,6 @@
|
|||||||
#include "../misc.h"
|
#include "../misc.h"
|
||||||
#include "../position.h"
|
#include "../position.h"
|
||||||
#include "../types.h"
|
#include "../types.h"
|
||||||
#include "features/half_ka_v2_hm.h"
|
|
||||||
#include "nnue_architecture.h"
|
#include "nnue_architecture.h"
|
||||||
#include "nnue_common.h"
|
#include "nnue_common.h"
|
||||||
#include "nnue_feature_transformer.h" // IWYU pragma: keep
|
#include "nnue_feature_transformer.h" // IWYU pragma: keep
|
||||||
@@ -39,23 +38,6 @@ using namespace SIMD;
|
|||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
template<IndexType TransformedFeatureDimensions>
|
|
||||||
void double_inc_update(Color perspective,
|
|
||||||
const FeatureTransformer<TransformedFeatureDimensions>& featureTransformer,
|
|
||||||
const Square ksq,
|
|
||||||
const AccumulatorState<PSQFeatureSet>& middle_state,
|
|
||||||
AccumulatorState<PSQFeatureSet>& target_state,
|
|
||||||
const AccumulatorState<PSQFeatureSet>& computed);
|
|
||||||
|
|
||||||
template<IndexType TransformedFeatureDimensions>
|
|
||||||
void double_inc_update(Color perspective,
|
|
||||||
const FeatureTransformer<TransformedFeatureDimensions>& featureTransformer,
|
|
||||||
const Square ksq,
|
|
||||||
const AccumulatorState<ThreatFeatureSet>& middle_state,
|
|
||||||
AccumulatorState<ThreatFeatureSet>& target_state,
|
|
||||||
const AccumulatorState<ThreatFeatureSet>& computed,
|
|
||||||
const DirtyPiece& dp2);
|
|
||||||
|
|
||||||
template<bool Forward, typename FeatureSet, IndexType TransformedFeatureDimensions>
|
template<bool Forward, typename FeatureSet, IndexType TransformedFeatureDimensions>
|
||||||
void update_accumulator_incremental(
|
void update_accumulator_incremental(
|
||||||
Color perspective,
|
Color perspective,
|
||||||
@@ -213,40 +195,6 @@ void AccumulatorStack::forward_update_incremental(
|
|||||||
|
|
||||||
for (std::size_t next = begin + 1; next < size; next++)
|
for (std::size_t next = begin + 1; next < size; next++)
|
||||||
{
|
{
|
||||||
if (next + 1 < size)
|
|
||||||
{
|
|
||||||
DirtyPiece& dp1 = mut_accumulators<PSQFeatureSet>()[next].diff;
|
|
||||||
DirtyPiece& dp2 = mut_accumulators<PSQFeatureSet>()[next + 1].diff;
|
|
||||||
|
|
||||||
auto& accumulators = mut_accumulators<FeatureSet>();
|
|
||||||
|
|
||||||
if constexpr (std::is_same_v<FeatureSet, ThreatFeatureSet>)
|
|
||||||
{
|
|
||||||
if (dp2.remove_sq != SQ_NONE
|
|
||||||
&& (accumulators[next].diff.threateningSqs & square_bb(dp2.remove_sq)))
|
|
||||||
{
|
|
||||||
double_inc_update(perspective, featureTransformer, ksq, accumulators[next],
|
|
||||||
accumulators[next + 1], accumulators[next - 1], dp2);
|
|
||||||
next++;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if constexpr (std::is_same_v<FeatureSet, PSQFeatureSet>)
|
|
||||||
{
|
|
||||||
if (dp1.to != SQ_NONE && dp1.to == dp2.remove_sq)
|
|
||||||
{
|
|
||||||
const Square captureSq = dp1.to;
|
|
||||||
dp1.to = dp2.remove_sq = SQ_NONE;
|
|
||||||
double_inc_update(perspective, featureTransformer, ksq, accumulators[next],
|
|
||||||
accumulators[next + 1], accumulators[next - 1]);
|
|
||||||
dp1.to = dp2.remove_sq = captureSq;
|
|
||||||
next++;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
update_accumulator_incremental<true>(perspective, featureTransformer, ksq,
|
update_accumulator_incremental<true>(perspective, featureTransformer, ksq,
|
||||||
mut_accumulators<FeatureSet>()[next],
|
mut_accumulators<FeatureSet>()[next],
|
||||||
accumulators<FeatureSet>()[next - 1]);
|
accumulators<FeatureSet>()[next - 1]);
|
||||||
@@ -487,87 +435,6 @@ auto make_accumulator_update_context(Color persp
|
|||||||
accumulatorFrom, accumulatorTo};
|
accumulatorFrom, accumulatorTo};
|
||||||
}
|
}
|
||||||
|
|
||||||
template<IndexType TransformedFeatureDimensions>
|
|
||||||
void double_inc_update(Color perspective,
|
|
||||||
const FeatureTransformer<TransformedFeatureDimensions>& featureTransformer,
|
|
||||||
const Square ksq,
|
|
||||||
const AccumulatorState<PSQFeatureSet>& middle_state,
|
|
||||||
AccumulatorState<PSQFeatureSet>& target_state,
|
|
||||||
const AccumulatorState<PSQFeatureSet>& computed) {
|
|
||||||
|
|
||||||
assert(computed.acc<TransformedFeatureDimensions>().computed[perspective]);
|
|
||||||
assert(!middle_state.acc<TransformedFeatureDimensions>().computed[perspective]);
|
|
||||||
assert(!target_state.acc<TransformedFeatureDimensions>().computed[perspective]);
|
|
||||||
|
|
||||||
PSQFeatureSet::IndexList removed, added;
|
|
||||||
PSQFeatureSet::append_changed_indices(perspective, ksq, middle_state.diff, removed, added);
|
|
||||||
// you can't capture a piece that was just involved in castling since the rook ends up
|
|
||||||
// in a square that the king passed
|
|
||||||
assert(added.size() < 2);
|
|
||||||
PSQFeatureSet::append_changed_indices(perspective, ksq, target_state.diff, removed, added);
|
|
||||||
|
|
||||||
[[maybe_unused]] const int addedSize = added.ssize();
|
|
||||||
[[maybe_unused]] const int removedSize = removed.ssize();
|
|
||||||
|
|
||||||
assert(addedSize == 1);
|
|
||||||
assert(removedSize == 2 || removedSize == 3);
|
|
||||||
|
|
||||||
// Workaround compiler warning for uninitialized variables, replicated on
|
|
||||||
// profile builds on windows with gcc 14.2.0.
|
|
||||||
// Also helps with optimizations on some compilers.
|
|
||||||
|
|
||||||
sf_assume(addedSize == 1);
|
|
||||||
sf_assume(removedSize == 2 || removedSize == 3);
|
|
||||||
|
|
||||||
auto updateContext =
|
|
||||||
make_accumulator_update_context(perspective, featureTransformer, computed, target_state);
|
|
||||||
|
|
||||||
if (removedSize == 2)
|
|
||||||
{
|
|
||||||
updateContext.template apply<Add, Sub, Sub>(added[0], removed[0], removed[1]);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
updateContext.template apply<Add, Sub, Sub, Sub>(added[0], removed[0], removed[1],
|
|
||||||
removed[2]);
|
|
||||||
}
|
|
||||||
|
|
||||||
target_state.acc<TransformedFeatureDimensions>().computed[perspective] = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<IndexType TransformedFeatureDimensions>
|
|
||||||
void double_inc_update(Color perspective,
|
|
||||||
const FeatureTransformer<TransformedFeatureDimensions>& featureTransformer,
|
|
||||||
const Square ksq,
|
|
||||||
const AccumulatorState<ThreatFeatureSet>& middle_state,
|
|
||||||
AccumulatorState<ThreatFeatureSet>& target_state,
|
|
||||||
const AccumulatorState<ThreatFeatureSet>& computed,
|
|
||||||
const DirtyPiece& dp2) {
|
|
||||||
|
|
||||||
assert(computed.acc<TransformedFeatureDimensions>().computed[perspective]);
|
|
||||||
assert(!middle_state.acc<TransformedFeatureDimensions>().computed[perspective]);
|
|
||||||
assert(!target_state.acc<TransformedFeatureDimensions>().computed[perspective]);
|
|
||||||
|
|
||||||
ThreatFeatureSet::FusedUpdateData fusedData;
|
|
||||||
|
|
||||||
fusedData.dp2removed = dp2.remove_sq;
|
|
||||||
|
|
||||||
ThreatFeatureSet::IndexList removed, added;
|
|
||||||
const auto* pfBase = &featureTransformer.threatWeights[0];
|
|
||||||
auto pfStride = static_cast<IndexType>(TransformedFeatureDimensions);
|
|
||||||
ThreatFeatureSet::append_changed_indices(perspective, ksq, middle_state.diff, removed, added,
|
|
||||||
&fusedData, true, pfBase, pfStride);
|
|
||||||
ThreatFeatureSet::append_changed_indices(perspective, ksq, target_state.diff, removed, added,
|
|
||||||
&fusedData, false, pfBase, pfStride);
|
|
||||||
|
|
||||||
auto updateContext =
|
|
||||||
make_accumulator_update_context(perspective, featureTransformer, computed, target_state);
|
|
||||||
|
|
||||||
updateContext.apply(added, removed);
|
|
||||||
|
|
||||||
target_state.acc<TransformedFeatureDimensions>().computed[perspective] = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<bool Forward, typename FeatureSet, IndexType TransformedFeatureDimensions>
|
template<bool Forward, typename FeatureSet, IndexType TransformedFeatureDimensions>
|
||||||
void update_accumulator_incremental(
|
void update_accumulator_incremental(
|
||||||
Color perspective,
|
Color perspective,
|
||||||
|
|||||||
+21
-38
@@ -860,13 +860,12 @@ void Position::do_move(Move m,
|
|||||||
Piece pc = piece_on(from);
|
Piece pc = piece_on(from);
|
||||||
Piece captured = m.type_of() == EN_PASSANT ? make_piece(them, PAWN) : piece_on(to);
|
Piece captured = m.type_of() == EN_PASSANT ? make_piece(them, PAWN) : piece_on(to);
|
||||||
|
|
||||||
dp.pc = pc;
|
dp.pc = pc;
|
||||||
dp.from = from;
|
dp.from = from;
|
||||||
dp.to = to;
|
dp.to = to;
|
||||||
dp.add_sq = SQ_NONE;
|
dp.add_sq = SQ_NONE;
|
||||||
dts.us = us;
|
dts.us = us;
|
||||||
dts.prevKsq = square<KING>(us);
|
dts.prevKsq = square<KING>(us);
|
||||||
dts.threatenedSqs = dts.threateningSqs = 0;
|
|
||||||
|
|
||||||
assert(color_of(pc) == us);
|
assert(color_of(pc) == us);
|
||||||
assert(captured == NO_PIECE || color_of(captured) == (m.type_of() != CASTLING ? them : us));
|
assert(captured == NO_PIECE || color_of(captured) == (m.type_of() != CASTLING ? them : us));
|
||||||
@@ -1151,16 +1150,13 @@ void Position::undo_move(Move m) {
|
|||||||
assert(pos_is_ok());
|
assert(pos_is_ok());
|
||||||
}
|
}
|
||||||
|
|
||||||
template<bool PutPiece>
|
inline void add_dirty_threat(DirtyThreats* const dts,
|
||||||
inline void add_dirty_threat(
|
bool putPiece,
|
||||||
DirtyThreats* const dts, Piece pc, Piece threatened, Square s, Square threatenedSq) {
|
Piece pc,
|
||||||
if (PutPiece)
|
Piece threatened,
|
||||||
{
|
Square s,
|
||||||
dts->threatenedSqs |= threatenedSq;
|
Square threatenedSq) {
|
||||||
dts->threateningSqs |= s;
|
dts->list.push_back({pc, threatened, s, threatenedSq, putPiece});
|
||||||
}
|
|
||||||
|
|
||||||
dts->list.push_back({pc, threatened, s, threatenedSq, PutPiece});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef USE_AVX512ICL
|
#ifdef USE_AVX512ICL
|
||||||
@@ -1198,8 +1194,9 @@ void write_multiple_dirties(const Position& p,
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
template<bool PutPiece, bool ComputeRay>
|
template<bool ComputeRay>
|
||||||
void Position::update_piece_threats(Piece pc,
|
void Position::update_piece_threats(Piece pc,
|
||||||
|
bool putPiece,
|
||||||
Square s,
|
Square s,
|
||||||
DirtyThreats* const dts,
|
DirtyThreats* const dts,
|
||||||
[[maybe_unused]] Bitboard noRaysContaining) const {
|
[[maybe_unused]] Bitboard noRaysContaining) const {
|
||||||
@@ -1226,11 +1223,11 @@ void Position::update_piece_threats(Piece pc,
|
|||||||
{
|
{
|
||||||
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(dts, !putPiece, slider, threatenedPc, sliderSq, threatenedSq);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (addDirectAttacks)
|
if (addDirectAttacks)
|
||||||
add_dirty_threat<PutPiece>(dts, slider, pc, sliderSq, s);
|
add_dirty_threat(dts, putPiece, slider, pc, sliderSq, s);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -1270,27 +1267,13 @@ void Position::update_piece_threats(Piece pc,
|
|||||||
}
|
}
|
||||||
|
|
||||||
#ifdef USE_AVX512ICL
|
#ifdef USE_AVX512ICL
|
||||||
if constexpr (PutPiece)
|
DirtyThreat dt_template{pc, NO_PIECE, s, Square(0), putPiece};
|
||||||
{
|
|
||||||
dts->threatenedSqs |= threatened;
|
|
||||||
// A bit may only be set if that square actually produces a threat, so we
|
|
||||||
// must guard setting the square accordingly
|
|
||||||
dts->threateningSqs |= Bitboard(bool(threatened)) << s;
|
|
||||||
}
|
|
||||||
|
|
||||||
DirtyThreat dt_template{pc, NO_PIECE, s, Square(0), PutPiece};
|
|
||||||
write_multiple_dirties<DirtyThreat::ThreatenedSqOffset, DirtyThreat::ThreatenedPcOffset>(
|
write_multiple_dirties<DirtyThreat::ThreatenedSqOffset, DirtyThreat::ThreatenedPcOffset>(
|
||||||
*this, threatened, dt_template, dts);
|
*this, threatened, dt_template, dts);
|
||||||
|
|
||||||
Bitboard all_attackers = sliders | incoming_threats;
|
Bitboard all_attackers = sliders | incoming_threats;
|
||||||
|
|
||||||
if constexpr (PutPiece)
|
dt_template = {NO_PIECE, pc, Square(0), s, putPiece};
|
||||||
{
|
|
||||||
dts->threatenedSqs |= Bitboard(bool(all_attackers)) << s; // same as above
|
|
||||||
dts->threateningSqs |= all_attackers;
|
|
||||||
}
|
|
||||||
|
|
||||||
dt_template = {NO_PIECE, pc, Square(0), s, PutPiece};
|
|
||||||
write_multiple_dirties<DirtyThreat::PcSqOffset, DirtyThreat::PcOffset>(*this, all_attackers,
|
write_multiple_dirties<DirtyThreat::PcSqOffset, DirtyThreat::PcOffset>(*this, all_attackers,
|
||||||
dt_template, dts);
|
dt_template, dts);
|
||||||
#else
|
#else
|
||||||
@@ -1302,7 +1285,7 @@ void Position::update_piece_threats(Piece pc,
|
|||||||
assert(threatenedSq != s);
|
assert(threatenedSq != s);
|
||||||
assert(threatenedPc);
|
assert(threatenedPc);
|
||||||
|
|
||||||
add_dirty_threat<PutPiece>(dts, pc, threatenedPc, s, threatenedSq);
|
add_dirty_threat(dts, putPiece, pc, threatenedPc, s, threatenedSq);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -1328,7 +1311,7 @@ void Position::update_piece_threats(Piece pc,
|
|||||||
assert(srcSq != s);
|
assert(srcSq != s);
|
||||||
assert(srcPc != NO_PIECE);
|
assert(srcPc != NO_PIECE);
|
||||||
|
|
||||||
add_dirty_threat<PutPiece>(dts, srcPc, pc, srcSq, s);
|
add_dirty_threat(dts, putPiece, srcPc, pc, srcSq, s);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|||||||
+8
-7
@@ -195,8 +195,9 @@ class Position {
|
|||||||
void set_check_info() const;
|
void set_check_info() const;
|
||||||
|
|
||||||
// Other helpers
|
// Other helpers
|
||||||
template<bool PutPiece, bool ComputeRay = true>
|
template<bool ComputeRay = true>
|
||||||
void update_piece_threats(Piece pc,
|
void update_piece_threats(Piece pc,
|
||||||
|
bool putPiece,
|
||||||
Square s,
|
Square s,
|
||||||
DirtyThreats* const dts,
|
DirtyThreats* const dts,
|
||||||
Bitboard noRaysContaining = -1ULL) const;
|
Bitboard noRaysContaining = -1ULL) const;
|
||||||
@@ -362,14 +363,14 @@ inline void Position::put_piece(Piece pc, Square s, DirtyThreats* const dts) {
|
|||||||
pieceCount[make_piece(color_of(pc), ALL_PIECES)]++;
|
pieceCount[make_piece(color_of(pc), ALL_PIECES)]++;
|
||||||
|
|
||||||
if (dts)
|
if (dts)
|
||||||
update_piece_threats<true>(pc, s, dts);
|
update_piece_threats(pc, true, s, dts);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void Position::remove_piece(Square s, DirtyThreats* const dts) {
|
inline void Position::remove_piece(Square s, DirtyThreats* const dts) {
|
||||||
Piece pc = board[s];
|
Piece pc = board[s];
|
||||||
|
|
||||||
if (dts)
|
if (dts)
|
||||||
update_piece_threats<false>(pc, s, dts);
|
update_piece_threats(pc, false, s, dts);
|
||||||
|
|
||||||
byTypeBB[ALL_PIECES] ^= s;
|
byTypeBB[ALL_PIECES] ^= s;
|
||||||
byTypeBB[type_of(pc)] ^= s;
|
byTypeBB[type_of(pc)] ^= s;
|
||||||
@@ -384,7 +385,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, fromTo);
|
update_piece_threats(pc, false, from, dts, fromTo);
|
||||||
|
|
||||||
byTypeBB[ALL_PIECES] ^= fromTo;
|
byTypeBB[ALL_PIECES] ^= fromTo;
|
||||||
byTypeBB[type_of(pc)] ^= fromTo;
|
byTypeBB[type_of(pc)] ^= fromTo;
|
||||||
@@ -393,7 +394,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, fromTo);
|
update_piece_threats(pc, true, 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) {
|
||||||
@@ -402,12 +403,12 @@ inline void Position::swap_piece(Square s, Piece pc, DirtyThreats* const dts) {
|
|||||||
remove_piece(s);
|
remove_piece(s);
|
||||||
|
|
||||||
if (dts)
|
if (dts)
|
||||||
update_piece_threats<false, false>(old, s, dts);
|
update_piece_threats<false>(old, false, s, dts);
|
||||||
|
|
||||||
put_piece(pc, s);
|
put_piece(pc, s);
|
||||||
|
|
||||||
if (dts)
|
if (dts)
|
||||||
update_piece_threats<true, false>(pc, s, dts);
|
update_piece_threats<false>(pc, true, s, dts);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void Position::do_move(Move m, StateInfo& newSt, const TranspositionTable* tt = nullptr) {
|
inline void Position::do_move(Move m, StateInfo& newSt, const TranspositionTable* tt = nullptr) {
|
||||||
|
|||||||
@@ -329,8 +329,6 @@ struct DirtyThreats {
|
|||||||
DirtyThreatList list;
|
DirtyThreatList list;
|
||||||
Color us;
|
Color us;
|
||||||
Square prevKsq, ksq;
|
Square prevKsq, ksq;
|
||||||
|
|
||||||
Bitboard threatenedSqs, threateningSqs;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#define ENABLE_INCR_OPERATORS_ON(T) \
|
#define ENABLE_INCR_OPERATORS_ON(T) \
|
||||||
|
|||||||
Reference in New Issue
Block a user