diff options
| author | Scott Gasch <[email protected]> | 2026-09-16 08:02:21 -0700 |
|---|---|---|
| committer | Scott Gasch <[email protected]> | 2026-09-16 08:02:21 -0700 |
| commit | 966a0ef4da9cf3911eb3da0533179199808717b4 (patch) | |
| tree | e09363b574215ef0d8996155a5ab24314db2dd69 /src/fen.c | |
| parent | b91c8453f3fe21c8ccd3568923d8e39141c9c945 (diff) | |
Retire cPawns/cNonPawns piece-location lists in favor of bbPawns/bbPieces/cKingSq, and hoist two redundant TotalNonPawnCount POPCNT calls out of per-node hot loops.
POSITION no longer stores cPawns[2][8], cNonPawns[2][16], uPawnCount[2],
uNonPawnCount[2][8], or uWhiteSqBishopCount[2] -- every reader now goes
through PawnMaterial/TotalNonPawnCount/WhiteSqBishopCount/KingPosition
(chess.h), computed from the already-incrementally-maintained bbPawns/
bbPieces/cKingSq bitboards via a single -mpopcnt POPCNT instead of a
stored counter. move.c's make/unmake loses the list-swap-on-removal
bookkeeping entirely. GNUmakefile now passes -mpopcnt so the popcount
builtins actually compile to one instruction instead of clang's ~15-op
SWAR fallback.
Measured a small but real nps regression from the naive swap (search.c's
QSearch move-filter and eval.c's _EvalKing were each recomputing the same
TotalNonPawnCount sum on every candidate move / twice per node); hoisted
both to a single call per node instead. Net result across a same-code
self-play match: ~1541.5 knps candidate vs ~1505.7 knps head_reference.
A third hoist (FindEnprisePiece out of SelectBestWithHistory) was tried
and reverted -- its cache isn't actually loop-invariant within a node
(populated from inside Eval(), which doesn't run before every selection
call), caught by a DEBUG-build ASSERT before it landed.
Co-Authored-By: Claude Sonnet 5 <[email protected]>
Diffstat (limited to 'src/fen.c')
| -rw-r--r-- | src/fen.c | 72 |
1 files changed, 10 insertions, 62 deletions
@@ -224,8 +224,6 @@ Return value: { char *pPieceIndex; ULONG uPieceIndex; - ULONG uPieceCounters[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; - ULONG uNumNonPawns[2] = { 0, 0 }; ULONG uColor; ULONG uFile = 0; ULONG uIndex; @@ -295,43 +293,28 @@ Return value: if (IS_PAWN(p)) { - // - // The pawn list is not ordered at all, add the new pawn's - // location to the list and point from the pawn to the list. - // - pos->cPawns[uColor][uPieceCounters[uPieceIndex]] = cSquare; pos->bbPawns[uColor] |= COOR_TO_BB(cSquare); pos->bbOccupied |= COOR_TO_BB(cSquare); pos->bbOccupiedSide[uColor] |= COOR_TO_BB(cSquare); - pos->rgSquare[cSquare].uIndex = uPieceCounters[uPieceIndex]; + pos->rgSquare[cSquare].uIndex = INVALID_PIECE_INDEX; pos->rgSquare[cSquare].pPiece = p; - pos->uPawnMaterial[uColor] += VALUE_PAWN; } else { if (IS_KING(p)) { - if (pos->cNonPawns[uColor][0] != ILLEGAL_COOR) + if (pos->cKingSq[uColor] != ILLEGAL_COOR) { Trace("_FenToPosition: I can't handle positions with " "more than one king, sorry.\n"); return(FALSE); } - pos->cNonPawns[uColor][0] = cSquare; - uIndex = 0; + pos->cKingSq[uColor] = cSquare; + uIndex = INVALID_PIECE_INDEX; } else { - if (IS_BISHOP(p)) - { - if (IS_WHITE_SQUARE_COOR(cSquare)) - { - pos->uWhiteSqBishopCount[uColor]++; - } - } - uIndex = uNumNonPawns[uColor] + 1; - pos->cNonPawns[uColor][uIndex] = cSquare; - uNumNonPawns[uColor]++; + uIndex = INVALID_PIECE_INDEX; pos->bbPieces[uColor][PIECE_TYPE(p)] |= COOR_TO_BB(cSquare); } pos->bbOccupied |= COOR_TO_BB(cSquare); @@ -340,39 +323,13 @@ Return value: pos->rgSquare[cSquare].uIndex = uIndex; pos->uNonPawnMaterial[uColor] += PIECE_VALUE(p); } - uPieceCounters[uPieceIndex]++; cSquare++; } pPieces++; } - // - // Set the piece counts based on uPieceCounter contents - // - if (IS_ON_BOARD(pos->cNonPawns[WHITE][0])) - { - uNumNonPawns[WHITE]++; - } - pos->uNonPawnCount[WHITE][0] = uNumNonPawns[WHITE]; - if (IS_ON_BOARD(pos->cNonPawns[BLACK][0])) - { - uNumNonPawns[BLACK]++; - } - pos->uNonPawnCount[BLACK][0] = uNumNonPawns[BLACK]; - FOREACH_COLOR(uColor) - { - pos->uPawnCount[uColor] = uPieceCounters[(PAWN << 1) | uColor]; - for (p = KNIGHT; p <= KING; p++) - { - pos->uNonPawnCount[uColor][p] = - uPieceCounters[(p << 1) | uColor]; - } - } - ASSERT((pos->uPawnCount[WHITE] * VALUE_PAWN) == pos->uPawnMaterial[WHITE]); - ASSERT((pos->uPawnCount[BLACK] * VALUE_PAWN) == pos->uPawnMaterial[BLACK]); - - if ((ILLEGAL_COOR == pos->cNonPawns[BLACK][0]) || - (ILLEGAL_COOR == pos->cNonPawns[WHITE][0])) + if ((ILLEGAL_COOR == pos->cKingSq[BLACK]) || + (ILLEGAL_COOR == pos->cKingSq[WHITE])) { Trace("FenToPosition: Warning, missing king location.\n"); } @@ -705,7 +662,6 @@ Return value: { char *szCapturedFen = SystemAllocateMemory((ULONG)strlen(szFen) + 2); char *szPieces, *szToMove, *szCastle, *szEnPassant, *szFifty; - ULONG u; // // Initialize the captured fen buffer with a trailing whitespace char @@ -734,15 +690,7 @@ Return value: // Clear the position struct // memset(p, 0, sizeof(POSITION)); - for (u = 0; u < ARRAY_SIZE(p->cPawns[WHITE]); u++) - { - p->cPawns[WHITE][u] = p->cPawns[BLACK][u] = ILLEGAL_COOR; - } - - for (u = 0; u < ARRAY_SIZE(p->cNonPawns[WHITE]); u++) - { - p->cNonPawns[WHITE][u] = p->cNonPawns[BLACK][u] = ILLEGAL_COOR; - } + p->cKingSq[WHITE] = p->cKingSq[BLACK] = ILLEGAL_COOR; // // Do the pieces / board @@ -771,8 +719,8 @@ Return value: p->u64NonPawnSig = ComputeSig(p); p->u64PawnSig = ComputePawnSig(p); p->iMaterialBalance[WHITE] = - ((SCORE)(p->uNonPawnMaterial[WHITE] + p->uPawnMaterial[WHITE]) - - (SCORE)(p->uNonPawnMaterial[BLACK] + p->uPawnMaterial[BLACK])); + ((SCORE)(p->uNonPawnMaterial[WHITE] + PawnMaterial(p, WHITE)) - + (SCORE)(p->uNonPawnMaterial[BLACK] + PawnMaterial(p, BLACK))); p->iMaterialBalance[BLACK] = p->iMaterialBalance[WHITE] * -1; #ifdef DEBUG |
