summaryrefslogtreecommitdiff
path: root/src/generate.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/generate.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/generate.c')
-rw-r--r--src/generate.c104
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);