From 5c8d794782d3be6368dbba613ef129b11d878d97 Mon Sep 17 00:00:00 2001 From: Scott Gasch Date: Fri, 4 Sep 2026 01:03:00 -0700 Subject: Fix passed-pawn bitboard bit-clear bug, LMR gate coupling, inline hot bitboard helpers - bitboard.c: CoorFromBitBoardRank1ToRank8 cleared the lowest set bit unconditionally instead of the reported (highest) one, silently mis-walking doubled-pawn files in eval.c's passed-pawn detection. - search.c/searchsup.c: move GetLMRReduction's precondition checks from inside the function to the caller in search.c (pre-existing work), finishing the split with a matching gate in split.c's HelpSearch -- the parallel-search call site had no gate at all, letting it call GetLMRReduction unconditionally (including for checking moves), reachable only under real multithreading (--cpus > 1) and the intermittent root cause of assertion crashes seen under --cpus 4. - eval.c: redirect CountBits/CoorFromBitBoardRank8ToRank1/ CoorFromBitBoardRank1ToRank8 to inline compiler-builtin versions (gated !CROUTINES) instead of the real out-of-line asm calls, on eval.c's ~20 existing production call sites. CountBits' asm body isn't O(1) popcnt, it's a Kernighan bit-clearing loop plus call overhead, paid on every Eval() call. Co-Authored-By: Claude Sonnet 5 Claude-Session: https://claude.ai/code/session_01Jntky4yGUTyQVaGCXms4F2 --- src/bitboard.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) (limited to 'src/bitboard.c') diff --git a/src/bitboard.c b/src/bitboard.c index 0478fc1..9e9df48 100755 --- a/src/bitboard.c +++ b/src/bitboard.c @@ -389,10 +389,21 @@ Return value: { ASSERT(*pbb); uLastBit--; - *pbb &= (*pbb - 1); c = BIT_NUMBER_TO_COOR(uLastBit); ASSERT(c == SLOW_BIT_NUMBER_TO_COOR(uLastBit)); ASSERT(IS_ON_BOARD(c)); + // BUG (fixed): this used to be `*pbb &= (*pbb - 1)`, which + // clears the LOWEST set bit -- correct for + // CoorFromBitBoardRank8ToRank1's first-bit semantics, wrong + // here, where uLastBit is the HIGHEST set bit. With more than + // one bit set (e.g. doubled pawns on a file), that cleared the + // wrong bit: the reported (highest) bit was never actually + // removed, so a caller looping on this function would see it + // again next call (a duplicate) while the true lowest bit was + // silently skipped forever. Single-bit inputs never exposed + // this (lowest-bit-clear and highest-bit-clear coincide when + // there's only one bit). + *pbb &= ~COOR_TO_BB(c); } return(c); } -- cgit v1.3