summaryrefslogtreecommitdiff
path: root/src/fen.c
diff options
context:
space:
mode:
authorScott Gasch <[email protected]>2026-09-16 08:02:21 -0700
committerScott Gasch <[email protected]>2026-09-16 08:02:21 -0700
commit966a0ef4da9cf3911eb3da0533179199808717b4 (patch)
treee09363b574215ef0d8996155a5ab24314db2dd69 /src/fen.c
parentb91c8453f3fe21c8ccd3568923d8e39141c9c945 (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.c72
1 files changed, 10 insertions, 62 deletions
diff --git a/src/fen.c b/src/fen.c
index 60ff4dc..13c2563 100644
--- a/src/fen.c
+++ b/src/fen.c
@@ -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