From e9296d694c72c2378b71ad29cfff2f2c7b45bb0c Mon Sep 17 00:00:00 2001 From: Marco Costalba Date: Sat, 31 Dec 2011 09:46:43 +0100 Subject: [PATCH] Unify BitCountType selection Now that HasPopCnt is a compile time constant we can centralize and unify the BitCountType selection. Also rename count_1s() in the more standard popcount() No functional change. Signed-off-by: Marco Costalba --- src/bitboard.cpp | 4 ++-- src/bitcount.h | 48 +++++++++++++++++++++++++++++++----------------- src/endgame.cpp | 2 +- src/evaluate.cpp | 33 +++++++++++++-------------------- src/pawns.cpp | 3 +-- src/position.cpp | 4 ++-- 6 files changed, 50 insertions(+), 44 deletions(-) diff --git a/src/bitboard.cpp b/src/bitboard.cpp index 04e5204b..e4e40958 100644 --- a/src/bitboard.cpp +++ b/src/bitboard.cpp @@ -154,7 +154,7 @@ Square pop_1st_bit(Bitboard* bb) { void bitboards_init() { for (Bitboard b = 0; b < 256; b++) - BitCount8Bit[b] = (uint8_t)count_1s(b); + BitCount8Bit[b] = (uint8_t)popcount(b); for (Square s = SQ_A1; s <= SQ_H8; s++) { @@ -321,7 +321,7 @@ namespace { // the number of 1s of the mask. Hence we deduce the size of the shift to // apply to the 64 or 32 bits word to get the index. masks[s] = sliding_attacks(pt, s, 0) & ~edges; - shifts[s] = (Is64Bit ? 64 : 32) - count_1s(masks[s]); + shifts[s] = (Is64Bit ? 64 : 32) - popcount(masks[s]); // Use Carry-Rippler trick to enumerate all subsets of masks[s] and // store the corresponding sliding attacks bitboard in reference[]. diff --git a/src/bitcount.h b/src/bitcount.h index 72ee37ca..9d25a5e5 100644 --- a/src/bitcount.h +++ b/src/bitcount.h @@ -21,25 +21,29 @@ #if !defined(BITCOUNT_H_INCLUDED) #define BITCOUNT_H_INCLUDED +#include #include "types.h" enum BitCountType { - CNT64, - CNT64_MAX15, - CNT32, - CNT32_MAX15, - CNT_POPCNT + CNT_64, + CNT_64_MAX15, + CNT_32, + CNT_32_MAX15, + CNT_HW_POPCNT }; -/// count_1s() counts the number of nonzero bits in a bitboard. -/// We have different optimized versions according if platform -/// is 32 or 64 bits, and to the maximum number of nonzero bits. -/// We also support hardware popcnt instruction. See Readme.txt -/// on how to pgo compile with popcnt support. -template inline int count_1s(Bitboard); +/// Determine at compile time the best popcount<> specialization according if +/// platform is 32 or 64 bits, to the maximum number of nonzero bits to count or +/// use hardware popcnt instruction when available. +const BitCountType Full = HasPopCnt ? CNT_HW_POPCNT : Is64Bit ? CNT_64 : CNT_32; +const BitCountType Max15 = HasPopCnt ? CNT_HW_POPCNT : Is64Bit ? CNT_64_MAX15 : CNT_32_MAX15; + + +/// popcount() counts the number of nonzero bits in a bitboard +template inline int popcount(Bitboard); template<> -inline int count_1s(Bitboard b) { +inline int popcount(Bitboard b) { b -= ((b>>1) & 0x5555555555555555ULL); b = ((b>>2) & 0x3333333333333333ULL) + (b & 0x3333333333333333ULL); b = ((b>>4) + b) & 0x0F0F0F0F0F0F0F0FULL; @@ -48,7 +52,7 @@ inline int count_1s(Bitboard b) { } template<> -inline int count_1s(Bitboard b) { +inline int popcount(Bitboard b) { b -= (b>>1) & 0x5555555555555555ULL; b = ((b>>2) & 0x3333333333333333ULL) + (b & 0x3333333333333333ULL); b *= 0x1111111111111111ULL; @@ -56,7 +60,7 @@ inline int count_1s(Bitboard b) { } template<> -inline int count_1s(Bitboard b) { +inline int popcount(Bitboard b) { unsigned w = unsigned(b >> 32), v = unsigned(b); v -= (v >> 1) & 0x55555555; // 0-2 in 2 bits w -= (w >> 1) & 0x55555555; @@ -69,7 +73,7 @@ inline int count_1s(Bitboard b) { } template<> -inline int count_1s(Bitboard b) { +inline int popcount(Bitboard b) { unsigned w = unsigned(b >> 32), v = unsigned(b); v -= (v >> 1) & 0x55555555; // 0-2 in 2 bits w -= (w >> 1) & 0x55555555; @@ -81,17 +85,27 @@ inline int count_1s(Bitboard b) { } template<> -inline int count_1s(Bitboard b) { +inline int popcount(Bitboard b) { + #if !defined(USE_POPCNT) + + assert(false); return int(b != 0); // Avoid 'b not used' warning + #elif defined(_MSC_VER) && defined(__INTEL_COMPILER) + return _mm_popcnt_u64(b); + #elif defined(_MSC_VER) + return (int)__popcnt64(b); -#elif defined(__GNUC__) + +#else + unsigned long ret; __asm__("popcnt %1, %0" : "=r" (ret) : "r" (b)); return ret; + #endif } diff --git a/src/endgame.cpp b/src/endgame.cpp index e44212b8..19c5b0b8 100644 --- a/src/endgame.cpp +++ b/src/endgame.cpp @@ -369,7 +369,7 @@ Value Endgame::operator()(const Position& pos) const { result += Value(square_distance(bksq, nsq) * 32); // Bonus for restricting the knight's mobility - result += Value((8 - count_1s(pos.attacks_from(nsq))) * 8); + result += Value((8 - popcount(pos.attacks_from(nsq))) * 8); return strongerSide == pos.side_to_move() ? result : -result; } diff --git a/src/evaluate.cpp b/src/evaluate.cpp index 2f51b1c3..a48dc13e 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -422,7 +422,6 @@ namespace { template void init_eval_info(const Position& pos, EvalInfo& ei) { - const BitCountType Max15 = HasPopCnt ? CNT_POPCNT : Is64Bit ? CNT64_MAX15 : CNT32_MAX15; const Color Them = (Us == WHITE ? BLACK : WHITE); Bitboard b = ei.attackedBy[Them][KING] = pos.attacks_from(pos.king_square(Them)); @@ -434,7 +433,7 @@ namespace { { ei.kingRing[Them] = (b | (Us == WHITE ? b >> 8 : b << 8)); b &= ei.attackedBy[Us][PAWN]; - ei.kingAttackersCount[Us] = b ? count_1s(b) / 2 : 0; + ei.kingAttackersCount[Us] = b ? popcount(b) / 2 : 0; ei.kingAdjacentZoneAttacksCount[Us] = ei.kingAttackersWeight[Us] = 0; } else ei.kingRing[Them] = ei.kingAttackersCount[Us] = 0; @@ -478,8 +477,6 @@ namespace { File f; Score score = SCORE_ZERO; - const BitCountType Full = HasPopCnt ? CNT_POPCNT : Is64Bit ? CNT64 : CNT32; - const BitCountType Max15 = HasPopCnt ? CNT_POPCNT : Is64Bit ? CNT64_MAX15 : CNT32_MAX15; const Color Them = (Us == WHITE ? BLACK : WHITE); const Square* pl = pos.piece_list(Us, Piece); @@ -507,12 +504,12 @@ namespace { ei.kingAttackersWeight[Us] += KingAttackWeights[Piece]; Bitboard bb = (b & ei.attackedBy[Them][KING]); if (bb) - ei.kingAdjacentZoneAttacksCount[Us] += count_1s(bb); + ei.kingAdjacentZoneAttacksCount[Us] += popcount(bb); } // Mobility - mob = (Piece != QUEEN ? count_1s(b & mobilityArea) - : count_1s(b & mobilityArea)); + mob = (Piece != QUEEN ? popcount(b & mobilityArea) + : popcount(b & mobilityArea)); mobility += MobilityBonus[Piece][mob]; @@ -667,7 +664,6 @@ namespace { template Score evaluate_king(const Position& pos, EvalInfo& ei, Value margins[]) { - const BitCountType Max15 = HasPopCnt ? CNT_POPCNT : Is64Bit ? CNT64_MAX15 : CNT32_MAX15; const Color Them = (Us == WHITE ? BLACK : WHITE); Bitboard undefended, b, b1, b2, safe; @@ -695,7 +691,7 @@ namespace { // attacked and undefended squares around our king, the square of the // king, and the quality of the pawn shelter. attackUnits = std::min(25, (ei.kingAttackersCount[Them] * ei.kingAttackersWeight[Them]) / 2) - + 3 * (ei.kingAdjacentZoneAttacksCount[Them] + count_1s(undefended)) + + 3 * (ei.kingAdjacentZoneAttacksCount[Them] + popcount(undefended)) + InitKingDanger[relative_square(Us, ksq)] - mg_value(ei.pi->king_shelter(pos, ksq)) / 32; @@ -709,7 +705,7 @@ namespace { | ei.attackedBy[Them][BISHOP] | ei.attackedBy[Them][ROOK]); if (b) attackUnits += QueenContactCheckBonus - * count_1s(b) + * popcount(b) * (Them == pos.side_to_move() ? 2 : 1); } @@ -727,7 +723,7 @@ namespace { | ei.attackedBy[Them][BISHOP] | ei.attackedBy[Them][QUEEN]); if (b) attackUnits += RookContactCheckBonus - * count_1s(b) + * popcount(b) * (Them == pos.side_to_move() ? 2 : 1); } @@ -740,22 +736,22 @@ namespace { // Enemy queen safe checks b = (b1 | b2) & ei.attackedBy[Them][QUEEN]; if (b) - attackUnits += QueenCheckBonus * count_1s(b); + attackUnits += QueenCheckBonus * popcount(b); // Enemy rooks safe checks b = b1 & ei.attackedBy[Them][ROOK]; if (b) - attackUnits += RookCheckBonus * count_1s(b); + attackUnits += RookCheckBonus * popcount(b); // Enemy bishops safe checks b = b2 & ei.attackedBy[Them][BISHOP]; if (b) - attackUnits += BishopCheckBonus * count_1s(b); + attackUnits += BishopCheckBonus * popcount(b); // Enemy knights safe checks b = pos.attacks_from(ksq) & ei.attackedBy[Them][KNIGHT] & safe; if (b) - attackUnits += KnightCheckBonus * count_1s(b); + attackUnits += KnightCheckBonus * popcount(b); // To index KingDangerTable[] attackUnits must be in [0, 99] range attackUnits = std::min(99, std::max(0, attackUnits)); @@ -879,8 +875,6 @@ namespace { Score evaluate_unstoppable_pawns(const Position& pos, EvalInfo& ei) { - const BitCountType Max15 = HasPopCnt ? CNT_POPCNT : Is64Bit ? CNT64_MAX15 : CNT32_MAX15; - Bitboard b, b2, blockers, supporters, queeningPath, candidates; Square s, blockSq, queeningSquare; Color c, winnerSide, loserSide; @@ -918,7 +912,7 @@ namespace { assert((queeningPath & pos.occupied_squares()) == (queeningPath & pos.pieces(c))); // Add moves needed to free the path from friendly pieces and retest condition - movesToGo += count_1s(queeningPath & pos.pieces(c)); + movesToGo += popcount(queeningPath & pos.pieces(c)); if (movesToGo >= oppMovesToGo && !pathDefended) continue; @@ -1046,7 +1040,6 @@ namespace { template int evaluate_space(const Position& pos, EvalInfo& ei) { - const BitCountType Max15 = HasPopCnt ? CNT_POPCNT : Is64Bit ? CNT64_MAX15 : CNT32_MAX15; const Color Them = (Us == WHITE ? BLACK : WHITE); // Find the safe squares for our pieces inside the area defined by @@ -1062,7 +1055,7 @@ namespace { behind |= (Us == WHITE ? behind >> 8 : behind << 8); behind |= (Us == WHITE ? behind >> 16 : behind << 16); - return count_1s(safe) + count_1s(behind & safe); + return popcount(safe) + popcount(behind & safe); } diff --git a/src/pawns.cpp b/src/pawns.cpp index f05be824..35bc45ae 100644 --- a/src/pawns.cpp +++ b/src/pawns.cpp @@ -116,7 +116,6 @@ template Score PawnInfoTable::evaluate_pawns(const Position& pos, Bitboard ourPawns, Bitboard theirPawns, PawnInfo* pi) { - const BitCountType Max15 = Is64Bit ? CNT64_MAX15 : CNT32_MAX15; const Color Them = (Us == WHITE ? BLACK : WHITE); Bitboard b; @@ -183,7 +182,7 @@ Score PawnInfoTable::evaluate_pawns(const Position& pos, Bitboard ourPawns, // enemy pawns in the forward direction on the neighboring files. candidate = !(opposed | passed | backward | isolated) && (b = attack_span_mask(Them, s + pawn_push(Us)) & ourPawns) != 0 - && count_1s(b) >= count_1s(attack_span_mask(Us, s) & theirPawns); + && popcount(b) >= popcount(attack_span_mask(Us, s) & theirPawns); // Passed pawns will be properly scored in evaluation because we need // full attack info to evaluate passed pawns. Only the frontmost passed diff --git a/src/position.cpp b/src/position.cpp index a4712559..7ee67e4c 100644 --- a/src/position.cpp +++ b/src/position.cpp @@ -1691,7 +1691,7 @@ bool Position::pos_is_ok(int* failedStep) const { // Is there more than 2 checkers? if (failedStep) (*failedStep)++; - if (debugCheckerCount && count_1s(st->checkersBB) > 2) + if (debugCheckerCount && popcount(st->checkersBB) > 2) return false; // Bitboards OK? @@ -1760,7 +1760,7 @@ bool Position::pos_is_ok(int* failedStep) const { if (debugPieceCounts) for (Color c = WHITE; c <= BLACK; c++) for (PieceType pt = PAWN; pt <= KING; pt++) - if (pieceCount[c][pt] != count_1s(pieces(pt, c))) + if (pieceCount[c][pt] != popcount(pieces(pt, c))) return false; if (failedStep) (*failedStep)++; -- 2.39.2