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/generate.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/generate.c')
| -rw-r--r-- | src/generate.c | 104 |
1 files changed, 57 insertions, 47 deletions
diff --git a/src/generate.c b/src/generate.c index e3db067..7e8f43e 100644 --- a/src/generate.c +++ b/src/generate.c @@ -40,6 +40,16 @@ Revision History: #include "chess.h" #include "psqt.h" +// See eval.c's identical comment: CoorFromBitBoardRank8ToRank1 +// (bitboard.c) is a real out-of-line extern call; this routes the +// bitboard-scan loops added during the cNonPawns/cPawns retirement +// (dead mailbox-fallback paths under this build's *_BITBOARD toggles, +// but still worth keeping fast for other toggle combinations) to the +// inlined FastCoorFromBitBoardRank8ToRank1 (chess.h) instead. +#ifndef CROUTINES +#define CoorFromBitBoardRank8ToRank1 FastCoorFromBitBoardRank8ToRank1 +#endif + // // Note: this order is important because of how EvalQueen works // @@ -83,7 +93,7 @@ Return value: **/ { register ULONG u; - COOR cKing = pos->cNonPawns[FLIP(pos->uToMove)][0]; + COOR cKing = KingPosition(pos, FLIP(pos->uToMove)); COOR c; ULONG uPly = pStack->uPly; #ifdef DEBUG @@ -182,7 +192,7 @@ Return value: COOR cTo = mv.cTo; COOR cFrom = mv.cFrom; PIECE pPiece = mv.pMoved; - COOR xKing = pos->cNonPawns[FLIP(GET_COLOR(pPiece))][0]; + COOR xKing = KingPosition(pos, FLIP(GET_COLOR(pPiece))); KEY_POINTER *kp = &(pStack->sUnblocked[ctx->uPly][0]); ULONG uUnblocked = pStack->uUnblockedKeyValue[ctx->uPly]; COOR cEpSquare; @@ -771,8 +781,8 @@ Return value: pos->bbPieces[BLACK][KNIGHT] | pos->bbPieces[BLACK][BISHOP] | pos->bbPieces[BLACK][ROOK] | pos->bbPieces[BLACK][QUEEN] | pos->bbPawns[WHITE] | pos->bbPawns[BLACK] | - COOR_TO_BB(pos->cNonPawns[WHITE][0]) | - COOR_TO_BB(pos->cNonPawns[BLACK][0])); + COOR_TO_BB(KingPosition(pos, WHITE)) | + COOR_TO_BB(KingPosition(pos, BLACK))); } // board_representation/MOVEGEN_MIGRATION.md section 6a Phase 2: raw @@ -3365,7 +3375,6 @@ Return value: GenerateWhiteKing // 13 (WHITE_KING) #endif }; - ULONG u; #ifdef DEBUG PIECE p; #endif @@ -3386,19 +3395,20 @@ Return value: pStack->bbOccupied = pos->bbOccupied; #endif - for(u = pos->uNonPawnCount[pos->uToMove][0] - 1; - u != (ULONG)-1; - u--) { - c = pos->cNonPawns[pos->uToMove][u]; + BITBOARD bbNonPawns = NON_KING_PIECES_BB(pos, pos->uToMove) | + COOR_TO_BB(KingPosition(pos, pos->uToMove)); + while (IS_ON_BOARD(c = CoorFromBitBoardRank8ToRank1(&bbNonPawns))) + { #ifdef DEBUG - ASSERT(IS_ON_BOARD(c)); - p = pos->rgSquare[c].pPiece; - ASSERT(!IS_EMPTY(p)); - ASSERT(!IS_PAWN(p)); - ASSERT(GET_COLOR(p) == pos->uToMove); + ASSERT(IS_ON_BOARD(c)); + p = pos->rgSquare[c].pPiece; + ASSERT(!IS_EMPTY(p)); + ASSERT(!IS_PAWN(p)); + ASSERT(GET_COLOR(p) == pos->uToMove); #endif - (JumpTable[pos->rgSquare[c].pPiece])(pStack, pos, c); + (JumpTable[pos->rgSquare[c].pPiece])(pStack, pos, c); + } } #if defined(GENERATE_PAWN_BITBOARD) @@ -3406,11 +3416,11 @@ Return value: #else if (pos->uToMove == BLACK) { - for(u = 0; u < pos->uPawnCount[BLACK]; u++) + BITBOARD bbPawnsToWalk = pos->bbPawns[BLACK]; + + while (IS_ON_BOARD(c = CoorFromBitBoardRank8ToRank1(&bbPawnsToWalk))) { - c = pos->cPawns[BLACK][u]; #ifdef DEBUG - ASSERT(IS_ON_BOARD(c)); p = pos->rgSquare[c].pPiece; ASSERT(!IS_EMPTY(p)); ASSERT(IS_PAWN(p)); @@ -3419,12 +3429,12 @@ Return value: GenerateBlackPawn(pStack, pos, c); } } else { + BITBOARD bbPawnsToWalk = pos->bbPawns[WHITE]; + ASSERT(pos->uToMove == WHITE); - for(u = 0; u < pos->uPawnCount[WHITE]; u++) + while (IS_ON_BOARD(c = CoorFromBitBoardRank8ToRank1(&bbPawnsToWalk))) { - c = pos->cPawns[WHITE][u]; #ifdef DEBUG - ASSERT(IS_ON_BOARD(c)); p = pos->rgSquare[c].pPiece; ASSERT(!IS_EMPTY(p)); ASSERT(IS_PAWN(p)); @@ -3504,9 +3514,6 @@ Return value: BITBOARD bb; ULONG uBitIndex; COOR c; -#if !defined(GENERATE_PAWN_BITBOARD) - ULONG u; -#endif #if defined(DEBUG) && !defined(GENERATE_PAWN_BITBOARD) PIECE p; #endif @@ -3558,7 +3565,7 @@ Return value: // side][0] -- see POSITION's bbPieces field comment in chess.h for // why a bitboard would add nothing here); still a direct, // statically-known call, same as the four loops above. - c = pos->cNonPawns[uSide][0]; + c = KingPosition(pos, uSide); ASSERT(IS_KING(pos->rgSquare[c].pPiece)); _GenerateKingBB(pStack, pos, c); @@ -3572,11 +3579,11 @@ Return value: #else if (uSide == BLACK) { - for(u = 0; u < pos->uPawnCount[BLACK]; u++) + BITBOARD bbPawnsToWalk = pos->bbPawns[BLACK]; + + while (IS_ON_BOARD(c = CoorFromBitBoardRank8ToRank1(&bbPawnsToWalk))) { - c = pos->cPawns[BLACK][u]; #ifdef DEBUG - ASSERT(IS_ON_BOARD(c)); p = pos->rgSquare[c].pPiece; ASSERT(!IS_EMPTY(p)); ASSERT(IS_PAWN(p)); @@ -3587,12 +3594,12 @@ Return value: } else { + BITBOARD bbPawnsToWalk = pos->bbPawns[WHITE]; + ASSERT(uSide == WHITE); - for(u = 0; u < pos->uPawnCount[WHITE]; u++) + while (IS_ON_BOARD(c = CoorFromBitBoardRank8ToRank1(&bbPawnsToWalk))) { - c = pos->cPawns[WHITE][u]; #ifdef DEBUG - ASSERT(IS_ON_BOARD(c)); p = pos->rgSquare[c].pPiece; ASSERT(!IS_EMPTY(p)); ASSERT(IS_PAWN(p)); @@ -3656,7 +3663,7 @@ Return value: #endif PIECE p; PIECE pKing; - COOR cKing = pos->cNonPawns[pos->uToMove][0]; + COOR cKing = KingPosition(pos, pos->uToMove); #if !defined(GENERATE_ESCAPES_KING_BITBOARD) int iIndex; #endif @@ -3920,27 +3927,29 @@ Return value: bbTargetMask); } #else - for (u = 1; // don't consider the king - u < pos->uNonPawnCount[pos->uToMove][0]; - u++) { - cDefender = pos->cNonPawns[pos->uToMove][u]; - ASSERT(IS_ON_BOARD(cDefender)); - p = pos->rgSquare[cDefender].pPiece; - ASSERT(p && !IS_PAWN(p)); - ASSERT(GET_COLOR(p) == pos->uToMove); + BITBOARD bbNonKingPieces = NON_KING_PIECES_BB(pos, pos->uToMove); - (JumpTable[p])(pStack, pos, cDefender, cKing, c); + while (IS_ON_BOARD(cDefender = + CoorFromBitBoardRank8ToRank1(&bbNonKingPieces))) + { + p = pos->rgSquare[cDefender].pPiece; + ASSERT(p && !IS_PAWN(p)); + ASSERT(GET_COLOR(p) == pos->uToMove); + + (JumpTable[p])(pStack, pos, cDefender, cKing, c); + } } // Consider all pawns too if (pos->uToMove == BLACK) { - for (u = 0; u < pos->uPawnCount[BLACK]; u++) + BITBOARD bbPawnsToWalk = pos->bbPawns[BLACK]; + + while (IS_ON_BOARD(cDefender = + CoorFromBitBoardRank8ToRank1(&bbPawnsToWalk))) { - cDefender = pos->cPawns[BLACK][u]; #ifdef DEBUG - ASSERT(IS_ON_BOARD(cDefender)); p = pos->rgSquare[cDefender].pPiece; ASSERT(p && IS_PAWN(p)); ASSERT(GET_COLOR(p) == pos->uToMove); @@ -3948,12 +3957,13 @@ Return value: SaveMeBlackPawn(pStack, pos, cDefender, cKing, c); } } else { + BITBOARD bbPawnsToWalk = pos->bbPawns[WHITE]; + ASSERT(pos->uToMove == WHITE); - for (u = 0; u < pos->uPawnCount[WHITE]; u++) + while (IS_ON_BOARD(cDefender = + CoorFromBitBoardRank8ToRank1(&bbPawnsToWalk))) { - cDefender = pos->cPawns[WHITE][u]; #ifdef DEBUG - ASSERT(IS_ON_BOARD(cDefender)); p = pos->rgSquare[cDefender].pPiece; ASSERT(p && IS_PAWN(p)); ASSERT(GET_COLOR(p) == pos->uToMove); |
