From: Marco Costalba Date: Mon, 4 Oct 2010 09:45:04 +0000 (+0200) Subject: Rewrite bit counting functions X-Git-Url: https://git.sesse.net/?p=stockfish;a=commitdiff_plain;h=d4876dc96395f5592bfbc25b2eca2360db0655e6 Rewrite bit counting functions Get rid of macros and use templates instead, this is safer and allows us fix the warning: ISO C++ forbids braced-groups within expressions That broke compilation with -pedantic flag under gcc and POPCNT enabled. No functional and no performance change. Signed-off-by: Marco Costalba --- diff --git a/src/Makefile b/src/Makefile index bb587440..3feaf11b 100644 --- a/src/Makefile +++ b/src/Makefile @@ -222,7 +222,7 @@ endif CXXFLAGS = -g -Wall -Wcast-qual -ansi -fno-exceptions -fno-rtti $(EXTRACXXFLAGS) ifeq ($(comp),gcc) - CXXFLAGS += -Wno-long-long -Wextra + CXXFLAGS += -pedantic -Wno-long-long -Wextra endif ifeq ($(comp),icc) diff --git a/src/bitboard.cpp b/src/bitboard.cpp index 0c38e182..2b42ce01 100644 --- a/src/bitboard.cpp +++ b/src/bitboard.cpp @@ -404,7 +404,7 @@ namespace { } for (Bitboard b = 0ULL; b < 256ULL; b++) - BitCount8Bit[b] = (uint8_t)count_1s(b); + BitCount8Bit[b] = (uint8_t)count_1s(b); } int remove_bit_8(int i) { return ((i & ~15) >> 1) | (i & 7); } @@ -494,7 +494,7 @@ namespace { Bitboard index_to_bitboard(int index, Bitboard mask) { Bitboard result = 0ULL; - int bits = count_1s(mask); + int bits = count_1s(mask); for (int i = 0; i < bits; i++) { diff --git a/src/bitcount.h b/src/bitcount.h index 63d7704b..0992c006 100644 --- a/src/bitcount.h +++ b/src/bitcount.h @@ -24,27 +24,23 @@ #include "types.h" -// Select type of intrinsic bit count instruction to use, see -// README.txt on how to pgo compile with POPCNT support. -#if !defined(USE_POPCNT) -#define POPCNT_INTRINSIC(x) 0 -#elif defined(_MSC_VER) -#define POPCNT_INTRINSIC(x) (int)__popcnt64(x) -#elif defined(__GNUC__) - -#define POPCNT_INTRINSIC(x) ({ \ - unsigned long __ret; \ - __asm__("popcnt %1, %0" : "=r" (__ret) : "r" (x)); \ - __ret; }) - -#endif +enum BitCountType { + CNT64, + CNT64_MAX15, + CNT32, + CNT32_MAX15, + CNT_POPCNT +}; - -/// Software implementation of bit count functions - -#if defined(IS_64BIT) - -inline int count_1s(Bitboard b) { +/// 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); + +template<> +inline int count_1s(Bitboard b) { b -= ((b>>1) & 0x5555555555555555ULL); b = ((b>>2) & 0x3333333333333333ULL) + (b & 0x3333333333333333ULL); b = ((b>>4) + b) & 0x0F0F0F0F0F0F0F0FULL; @@ -52,16 +48,16 @@ inline int count_1s(Bitboard b) { return int(b >> 56); } -inline int count_1s_max_15(Bitboard b) { +template<> +inline int count_1s(Bitboard b) { b -= (b>>1) & 0x5555555555555555ULL; b = ((b>>2) & 0x3333333333333333ULL) + (b & 0x3333333333333333ULL); b *= 0x1111111111111111ULL; return int(b >> 60); } -#else // if !defined(IS_64BIT) - -inline int count_1s(Bitboard b) { +template<> +inline int count_1s(Bitboard b) { unsigned w = unsigned(b >> 32), v = unsigned(b); v -= (v >> 1) & 0x55555555; // 0-2 in 2 bits w -= (w >> 1) & 0x55555555; @@ -73,7 +69,8 @@ inline int count_1s(Bitboard b) { return int(v >> 24); } -inline int count_1s_max_15(Bitboard b) { +template<> +inline int count_1s(Bitboard b) { unsigned w = unsigned(b >> 32), v = unsigned(b); v -= (v >> 1) & 0x55555555; // 0-2 in 2 bits w -= (w >> 1) & 0x55555555; @@ -84,27 +81,21 @@ inline int count_1s_max_15(Bitboard b) { return int(v >> 28); } -#endif // BITCOUNT - - -/// count_1s() counts the number of nonzero bits in a bitboard. -/// If template parameter is true an intrinsic is called, otherwise -/// we fallback on a software implementation. - -template -inline int count_1s(Bitboard b) { - - return UseIntrinsic ? POPCNT_INTRINSIC(b) : count_1s(b); -} - -template -inline int count_1s_max_15(Bitboard b) { - - return UseIntrinsic ? POPCNT_INTRINSIC(b) : count_1s_max_15(b); +template<> +inline int count_1s(Bitboard b) { +#if !defined(USE_POPCNT) + return int(b != 0); // Avoid 'b not used' warning +#elif defined(_MSC_VER) + return __popcnt64(b); +#elif defined(__GNUC__) + unsigned long ret; + __asm__("popcnt %1, %0" : "=r" (ret) : "r" (b)); + return ret; +#endif } -// Detect hardware POPCNT support +/// cpu_has_popcnt() detects support for popcnt instruction at runtime inline bool cpu_has_popcnt() { int CPUInfo[4] = {-1}; @@ -113,9 +104,9 @@ inline bool cpu_has_popcnt() { } -// Global constant initialized at startup that is set to true if -// CPU on which application runs supports POPCNT intrinsic. Unless -// USE_POPCNT is not defined. +/// CpuHasPOPCNT is a global constant initialized at startup that +/// is set to true if CPU on which application runs supports popcnt +/// hardware instruction. Unless USE_POPCNT is not defined. #if defined(USE_POPCNT) const bool CpuHasPOPCNT = cpu_has_popcnt(); #else @@ -123,12 +114,12 @@ const bool CpuHasPOPCNT = false; #endif -// Global constant used to print info about the use of 64 optimized -// functions to verify that a 64 bit compile has been correctly built. +/// CpuIs64Bit is a global constant initialized at compile time that +/// is set to true if CPU on which application runs is a 64 bits. #if defined(IS_64BIT) -const bool CpuHas64BitPath = true; +const bool CpuIs64Bit = true; #else -const bool CpuHas64BitPath = false; +const bool CpuIs64Bit = false; #endif #endif // !defined(BITCOUNT_H_INCLUDED) diff --git a/src/endgame.cpp b/src/endgame.cpp index 913be63f..abf27d52 100644 --- a/src/endgame.cpp +++ b/src/endgame.cpp @@ -357,7 +357,7 @@ Value EvaluationFunction::apply(const Position& pos) const { result += Value(square_distance(bksq, nsq) * 32); // Bonus for restricting the knight's mobility - result += Value((8 - count_1s_max_15(pos.attacks_from(nsq))) * 8); + result += Value((8 - count_1s(pos.attacks_from(nsq))) * 8); return strongerSide == pos.side_to_move() ? result : -result; } diff --git a/src/evaluate.cpp b/src/evaluate.cpp index 842d4777..86cebecb 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -439,6 +439,7 @@ namespace { template void init_eval_info(const Position& pos, EvalInfo& ei) { + const BitCountType Max15 = HasPopCnt ? CNT_POPCNT : CpuIs64Bit ? CNT64_MAX15 : CNT32_MAX15; const Color Them = (Us == WHITE ? BLACK : WHITE); Bitboard b = ei.attackedBy[Them][KING] = pos.attacks_from(pos.king_square(Them)); @@ -448,7 +449,7 @@ namespace { if (ei.updateKingTables[Us]) { b &= ei.attackedBy[Us][PAWN]; - ei.kingAttackersCount[Us] = b ? count_1s_max_15(b) / 2 : EmptyBoardBB; + ei.kingAttackersCount[Us] = b ? count_1s(b) / 2 : EmptyBoardBB; ei.kingAdjacentZoneAttacksCount[Us] = ei.kingAttackersWeight[Us] = EmptyBoardBB; } } @@ -491,6 +492,8 @@ namespace { File f; Score bonus = SCORE_ZERO; + const BitCountType Full = HasPopCnt ? CNT_POPCNT : CpuIs64Bit ? CNT64 : CNT32; + const BitCountType Max15 = HasPopCnt ? CNT_POPCNT : CpuIs64Bit ? CNT64_MAX15 : CNT32_MAX15; const Color Them = (Us == WHITE ? BLACK : WHITE); const Square* ptr = pos.piece_list_begin(Us, Piece); @@ -518,12 +521,12 @@ namespace { ei.kingAttackersWeight[Us] += KingAttackWeights[Piece]; Bitboard bb = (b & ei.attackedBy[Them][KING]); if (bb) - ei.kingAdjacentZoneAttacksCount[Us] += count_1s_max_15(bb); + ei.kingAdjacentZoneAttacksCount[Us] += count_1s(bb); } // Mobility - mob = (Piece != QUEEN ? count_1s_max_15(b & mobilityArea) - : count_1s(b & mobilityArea)); + mob = (Piece != QUEEN ? count_1s(b & mobilityArea) + : count_1s(b & mobilityArea)); mobility += MobilityBonus[Piece][mob]; @@ -652,6 +655,7 @@ namespace { template Score evaluate_king(const Position& pos, EvalInfo& ei, Value& margin) { + const BitCountType Max15 = HasPopCnt ? CNT_POPCNT : CpuIs64Bit ? CNT64_MAX15 : CNT32_MAX15; const Color Them = (Us == WHITE ? BLACK : WHITE); Bitboard undefended, b, b1, b2, safe; @@ -680,7 +684,7 @@ namespace { // attacked and undefended squares around our king, the square of the // king, and the quality of the pawn shelter. attackUnits = Min(25, (ei.kingAttackersCount[Them] * ei.kingAttackersWeight[Them]) / 2) - + 3 * (ei.kingAdjacentZoneAttacksCount[Them] + count_1s_max_15(undefended)) + + 3 * (ei.kingAdjacentZoneAttacksCount[Them] + count_1s(undefended)) + InitKingDanger[relative_square(Us, ksq)] - mg_value(ei.pi->king_shelter(pos, ksq)) / 32; @@ -694,7 +698,7 @@ namespace { | ei.attackedBy[Them][BISHOP] | ei.attackedBy[Them][ROOK]); if (b) attackUnits += QueenContactCheckBonus - * count_1s_max_15(b) + * count_1s(b) * (Them == pos.side_to_move() ? 2 : 1); } @@ -712,7 +716,7 @@ namespace { | ei.attackedBy[Them][BISHOP] | ei.attackedBy[Them][QUEEN]); if (b) attackUnits += RookContactCheckBonus - * count_1s_max_15(b) + * count_1s(b) * (Them == pos.side_to_move() ? 2 : 1); } @@ -725,22 +729,22 @@ namespace { // Enemy queen safe checks b = (b1 | b2) & ei.attackedBy[Them][QUEEN]; if (b) - attackUnits += QueenCheckBonus * count_1s_max_15(b); + attackUnits += QueenCheckBonus * count_1s(b); // Enemy rooks safe checks b = b1 & ei.attackedBy[Them][ROOK]; if (b) - attackUnits += RookCheckBonus * count_1s_max_15(b); + attackUnits += RookCheckBonus * count_1s(b); // Enemy bishops safe checks b = b2 & ei.attackedBy[Them][BISHOP]; if (b) - attackUnits += BishopCheckBonus * count_1s_max_15(b); + attackUnits += BishopCheckBonus * count_1s(b); // Enemy knights safe checks b = pos.attacks_from(ksq) & ei.attackedBy[Them][KNIGHT] & safe; if (b) - attackUnits += KnightCheckBonus * count_1s_max_15(b); + attackUnits += KnightCheckBonus * count_1s(b); // To index KingDangerTable[] attackUnits must be in [0, 99] range attackUnits = Min(99, Max(0, attackUnits)); @@ -865,6 +869,7 @@ namespace { template int evaluate_space(const Position& pos, EvalInfo& ei) { + const BitCountType Max15 = HasPopCnt ? CNT_POPCNT : CpuIs64Bit ? CNT64_MAX15 : CNT32_MAX15; const Color Them = (Us == WHITE ? BLACK : WHITE); // Find the safe squares for our pieces inside the area defined by @@ -880,7 +885,7 @@ namespace { behind |= (Us == WHITE ? behind >> 8 : behind << 8); behind |= (Us == WHITE ? behind >> 16 : behind << 16); - return count_1s_max_15(safe) + count_1s_max_15(behind & safe); + return count_1s(safe) + count_1s(behind & safe); } diff --git a/src/misc.cpp b/src/misc.cpp index 49b41b2f..9a9d0dda 100644 --- a/src/misc.cpp +++ b/src/misc.cpp @@ -146,7 +146,7 @@ void dbg_print_mean(ofstream& logFile) { const string engine_name() { - const string cpu64(CpuHas64BitPath ? " 64bit" : ""); + const string cpu64(CpuIs64Bit ? " 64bit" : ""); if (!EngineVersion.empty()) return AppName + " " + EngineVersion + cpu64; diff --git a/src/pawns.cpp b/src/pawns.cpp index 37a54dd9..07decab1 100644 --- a/src/pawns.cpp +++ b/src/pawns.cpp @@ -147,6 +147,7 @@ Score PawnInfoTable::evaluate_pawns(const Position& pos, Bitboard ourPawns, Rank r; bool passed, isolated, doubled, opposed, chain, backward, candidate; Score value = SCORE_ZERO; + const BitCountType Max15 = CpuIs64Bit ? CNT64_MAX15 : CNT32_MAX15; const Square* ptr = pos.piece_list_begin(Us, PAWN); // Initialize halfOpenFiles[] @@ -206,7 +207,7 @@ Score PawnInfoTable::evaluate_pawns(const Position& pos, Bitboard ourPawns, // Test for candidate passed pawn candidate = !(opposed | passed) && (b = attack_span_mask(opposite_color(Us), s + pawn_push(Us)) & ourPawns) != EmptyBoardBB - && count_1s_max_15(b) >= count_1s_max_15(attack_span_mask(Us, s) & theirPawns); + && count_1s(b) >= count_1s(attack_span_mask(Us, s) & theirPawns); // In order to prevent doubled passed pawns from receiving a too big // bonus, only the frontmost passed pawn on each file is considered as diff --git a/src/position.cpp b/src/position.cpp index cb63cf95..3b7916bf 100644 --- a/src/position.cpp +++ b/src/position.cpp @@ -1917,7 +1917,7 @@ bool Position::is_ok(int* failedStep) const { // Is there more than 2 checkers? if (failedStep) (*failedStep)++; - if (debugCheckerCount && count_1s(st->checkersBB) > 2) + if (debugCheckerCount && count_1s(st->checkersBB) > 2) return false; // Bitboards OK? @@ -1986,7 +1986,7 @@ bool Position::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] != count_1s(pieces(pt, c))) return false; if (failedStep) (*failedStep)++;