From 6f97594eda9e50dd22e237abcb636d426727ef07 Mon Sep 17 00:00:00 2001 From: Dalton Hanaway Date: Thu, 25 Jun 2026 13:03:44 +0200 Subject: [PATCH] prefetch the TT entry as soon as the move is known Worker::do_move computes the successor hash key via the new Position::key_after(m) and prefetches the TT entry one full do_move earlier than the existing prefetch in Position::do_move. key_after does not model castling, en passant or promotion keys exactly; for rare moves the prefetch lands on an unused line. `key_after` has been around since 2014 (https://github.com/official-stockfish/Stockfish/commit/82d065b0) and was removed in (https://github.com/official-stockfish/Stockfish/pull/5770). Adding back `prefetch_key` helps in common, normal moves at the cost of extra compute. Speedup (PGO vs PGO, interleaved paired bench, n=48 pairs, Apple M2 Pro / apple-silicon): +0.69% [0.47, 0.91] Passed STC: https://tests.stockfishchess.org/tests/view/6a291f8d7c758d82accea17f LLR: 4.24 (-2.94,2.94) <0.00,2.00> Total: 473504 W: 121250 L: 120228 D: 232026 Ptnml(0-2): 1112, 51137, 131251, 52121, 1131 No functional change closes https://github.com/official-stockfish/Stockfish/pull/6911 No functional change --- AUTHORS | 1 + src/position.cpp | 15 +++++++++++++++ src/position.h | 7 +++++-- src/search.cpp | 4 ++++ 4 files changed, 25 insertions(+), 2 deletions(-) diff --git a/AUTHORS b/AUTHORS index a7afa9f50..11745df02 100644 --- a/AUTHORS +++ b/AUTHORS @@ -62,6 +62,7 @@ Clemens L. (rn5f107s2) Cody Ho (aesrentai) CSTENTOR Dale Weiler (graphitemaster) +Dalton Hanaway (dhanaway) Daniel Axtens (daxtens) Daniel Dugovic (ddugovic) Daniel Monroe (daniel-monroe) diff --git a/src/position.cpp b/src/position.cpp index d13f8472e..d14385b13 100644 --- a/src/position.cpp +++ b/src/position.cpp @@ -1315,6 +1315,21 @@ void Position::update_piece_threats(Piece pc, #endif } +Key Position::prefetch_key(Move m) const { + Square from = m.from_sq(); + Square to = m.to_sq(); + Piece pc = piece_on(from); + Piece captured = piece_on(to); + Key k = st->key ^ Zobrist::side; + + k ^= Zobrist::psq[captured][to] ^ Zobrist::psq[pc][to] ^ Zobrist::psq[pc][from]; + + if (captured || type_of(pc) == PAWN) + return k; + + return adjust_key50(k); +} + // Helper used to do/undo a castling move. This is a bit // tricky in Chess960 where from/to squares can overlap. template diff --git a/src/position.h b/src/position.h index 25b29e8b9..27becfed0 100644 --- a/src/position.h +++ b/src/position.h @@ -160,6 +160,7 @@ class Position { // Accessing hash keys Key key() const; + Key prefetch_key(Move m) const; Key material_key() const; Key pawn_key() const; Key minor_piece_key() const; @@ -211,7 +212,8 @@ class Position { Square& rto, DirtyThreats* const dts = nullptr, DirtyPiece* const dp = nullptr); - Key adjust_key50(Key k) const; + template + Key adjust_key50(Key k) const; // Data members std::array board; @@ -317,8 +319,9 @@ inline Bitboard Position::check_squares(PieceType pt) const { return st->checkSq inline Key Position::key() const { return adjust_key50(st->key); } +template inline Key Position::adjust_key50(Key k) const { - return st->rule50 < 14 ? k : k ^ make_key((st->rule50 - 14) / 8); + return st->rule50 < 14 - AfterMove ? k : k ^ make_key((st->rule50 - (14 - AfterMove)) / 8); } inline Key Position::pawn_key() const { return st->pawnKey; } diff --git a/src/search.cpp b/src/search.cpp index 8e8cbcbc4..9386bfb35 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -634,6 +634,10 @@ void Search::Worker::do_move(Position& pos, const Move move, StateInfo& st, Stac void Search::Worker::do_move( Position& pos, const Move move, StateInfo& st, const bool givesCheck, Stack* const ss) { + // prefetch_key does not model castling, en passant or promotion keys + // exactly; for rare moves the prefetch lands on an unused line. + prefetch(tt.first_entry(pos.prefetch_key(move))); + bool capture = pos.capture_stage(move); ++nodes;