summaryrefslogtreecommitdiff
path: root/src/testbitboard.c
diff options
context:
space:
mode:
authorScott Gasch <[email protected]>2026-09-04 01:27:59 -0700
committerScott Gasch <[email protected]>2026-09-04 01:27:59 -0700
commit6c045be8a37a8eae1ea6aed250944e22af2335a1 (patch)
tree7cc90d47795e25d5ad0848cbc904136525596057 /src/testbitboard.c
parent5c8d794782d3be6368dbba613ef129b11d878d97 (diff)
Add bbPieces incremental piece-location bitboards (migration plan section 1)
Board-representation migration, section 1: add POSITION.bbPieces[2][8] (per-color, per-piece-type location bitboards, indexed like the existing uNonPawnCount) as incrementally-maintained state, not a per-Eval()-call rebuild -- the structural fix for why the earlier attack-presence-bitboard work measured slower, not faster. - chess.h: bbPieces[2][8] field; extern decls for data.c's g_RookRayToEdge/g_BishopRayToEdge/g_KnightAttacksBB ray tables and their Initialize* functions (needed by the planned bitboard-backed GetAttacks/CountKingSafetyDefects primitive, section 3). - fen.c: populate bbPieces during piece placement; zeroing is free via the existing memset(p, 0, sizeof(POSITION)). - move.c: maintain bbPieces at all 6 non-pawn piece-movement functions (SlidePiece/LiftPiece/PlacePiece and their WithoutSigs siblings used by UnmakeMove) -- covers every move type: normal moves, captures, both-side castling, promotion with/without capture, en passant, and every undo. - board.c: extend VerifyPositionConsistency's existing non-pawn piece-list walk with a parallel bbPieces reconstruction-and-compare, rather than a separate bespoke check. - data.c/main.c: pulled ray-to-edge/knight-attack tables from stash (needed by section 3, not section 1 itself, but zero-risk to land now). Also, while verifying: COOR_TO_BB was a table lookup (BBSQUARE[idx]) measured ~5-7% slower than the pure-ALU shift already sitting unused in SLOWCOOR_TO_BB (whose "SLOW" name reflects a stale assumption about variable shifts never actually tested on this hardware). Switched COOR_TO_BB to the shift; fixed testbitboard.c's existing but broken (dead-code-eliminated, silently reporting "0 cycles/op") comparison benchmark for both while at it. Verified via gmake TEST=1 (including TestMakeUnmakeMove's explicit en-passant/promotion-with-capture/both-castling coverage) and debug_smoke_test.sh, both clean; release build clean and runs normally. Nothing reads bbPieces yet -- pure addition, zero behavioral risk. See board_representation/MIGRATION.md for the full plan. Co-Authored-By: Claude Sonnet 5 <[email protected]> Claude-Session: https://claude.ai/code/session_01Jntky4yGUTyQVaGCXms4F2
Diffstat (limited to 'src/testbitboard.c')
-rw-r--r--src/testbitboard.c31
1 files changed, 27 insertions, 4 deletions
diff --git a/src/testbitboard.c b/src/testbitboard.c
index 7d2bfeb..c91f87c 100644
--- a/src/testbitboard.c
+++ b/src/testbitboard.c
@@ -42,6 +42,22 @@ Return value:
COOR c;
ULONG b;
BITBOARD bb;
+ // volatile, separate from bb (which is reused below for unrelated
+ // correctness checks and gets passed by address -- making it
+ // volatile there breaks those calls): without a volatile sink, the
+ // SLOWCOOR_TO_BB/COOR_TO_BB benchmark loops just below compute a
+ // value and never use it again, so the optimizer proves they have
+ // no effect and deletes them entirely -- this used to silently
+ // report "0 cycles/op" for both, an obviously impossible number
+ // that was never actually measuring anything (same class of bug
+ // documented in eval.c's RunEvalRookAB comment: "the first time
+ // this was written it produced 0.000s / inf calls/sec"). Other
+ // loops below (CountBits/LastBit/FirstBit etc.) happened to
+ // survive because those are real out-of-line/opaque calls the
+ // optimizer can't prove are side-effect-free; the COOR_TO_BB
+ // macros expand to plain visible expressions with nothing
+ // stopping them from being optimized away.
+ volatile BITBOARD bbSink;
BITBOARD bbSpeed[1000];
ULONG u, v, w, z;
UINT64 u64;
@@ -74,20 +90,27 @@ Return value:
for (u = 0; u < 1000000; u++)
{
b = u % 64;
- bb = SLOWCOOR_TO_BB(b);
+ bbSink = SLOWCOOR_TO_BB(b);
}
- printf(" SLOWCOOR_TO_BB: %" COMPILER_LONGLONG_UNSIGNED_FORMAT
+ printf(" SLOWCOOR_TO_BB: %" COMPILER_LONGLONG_UNSIGNED_FORMAT
" cycles/op\n",
(SystemReadTimeStampCounter() - u64) / 1000000);
u64 = SystemReadTimeStampCounter();
for (u = 0; u < 1000000; u++)
{
b = u % 64;
- bb = COOR_TO_BB(b);
+ bbSink = COOR_TO_BB(b);
}
- printf(" COOR_TO_BB: %" COMPILER_LONGLONG_UNSIGNED_FORMAT
+ printf(" COOR_TO_BB: %" COMPILER_LONGLONG_UNSIGNED_FORMAT
" cycles/op\n",
(SystemReadTimeStampCounter() - u64) / 1000000);
+ // bbSink's individual writes are never dead-code-eliminated
+ // (that's what volatile guarantees) regardless of whether anything
+ // reads it afterward, but nothing did until this line -- report it
+ // so the compiler doesn't flag it as unused, same pattern the
+ // evalcycles command uses for its own timing-loop sink.
+ printf(" (bbSink final value, just to use it: %#llx)\n",
+ (unsigned long long)bbSink);
u64 = SystemReadTimeStampCounter();
for (v = 1; v < 1000; v++)