From 3376c68f4bb83dc9fd874eb9d710dab09609ae54 Mon Sep 17 00:00:00 2001 From: Marco Costalba Date: Thu, 21 May 2009 15:29:28 +0200 Subject: [PATCH 01/11] Introduce bitcount.h It will be used for POPCNT intrinsics. For now no bianry and functional change. Signed-off-by: Marco Costalba --- src/bitboard.cpp | 3 +- src/bitboard.h | 65 ------------------- src/bitcount.h | 162 +++++++++++++++++++++++++++++++++++++++++++++++ src/endgame.cpp | 3 +- src/evaluate.cpp | 37 +++++------ src/main.cpp | 2 +- src/pawns.cpp | 5 +- src/position.cpp | 5 +- 8 files changed, 192 insertions(+), 90 deletions(-) create mode 100644 src/bitcount.h diff --git a/src/bitboard.cpp b/src/bitboard.cpp index 474e321c..f7a6ba27 100644 --- a/src/bitboard.cpp +++ b/src/bitboard.cpp @@ -35,6 +35,7 @@ #include #include "bitboard.h" +#include "bitcount.h" #include "direction.h" @@ -460,7 +461,7 @@ namespace { Bitboard index_to_bitboard(int index, Bitboard mask) { - int i, j, bits = count_1s(mask); + int i, j, bits = count_1s(mask); Bitboard result = 0ULL; for(i = 0; i < bits; i++) { j = pop_1st_bit(&mask); diff --git a/src/bitboard.h b/src/bitboard.h index d3a4ae53..54ed5053 100644 --- a/src/bitboard.h +++ b/src/bitboard.h @@ -22,7 +22,6 @@ #if !defined(BITBOARD_H_INCLUDED) #define BITBOARD_H_INCLUDED - //// //// Defines //// @@ -47,15 +46,10 @@ //#define USE_32BIT_ATTACKS #define USE_FOLDED_BITSCAN -#define BITCOUNT_SWAR_64 -//#define BITCOUNT_SWAR_32 -//#define BITCOUNT_LOOP - #else #define USE_32BIT_ATTACKS #define USE_FOLDED_BITSCAN -#define BITCOUNT_SWAR_32 #endif @@ -429,65 +423,6 @@ inline Bitboard isolated_pawn_mask(Square s) { } -/// count_1s() counts the number of nonzero bits in a bitboard. - -#if defined(BITCOUNT_LOOP) - -inline int count_1s(Bitboard b) { - int r; - for(r = 0; b; r++, b &= b - 1); - return r; -} - -inline int count_1s_max_15(Bitboard b) { - return count_1s(b); -} - -#elif defined(BITCOUNT_SWAR_32) - -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; - v = ((v >> 2) & 0x33333333) + (v & 0x33333333); // 0-4 in 4 bits - w = ((w >> 2) & 0x33333333) + (w & 0x33333333); - v = ((v >> 4) + v) & 0x0F0F0F0F; // 0-8 in 8 bits - v += (((w >> 4) + w) & 0x0F0F0F0F); // 0-16 in 8 bits - v *= 0x01010101; // mul is fast on amd procs - return int(v >> 24); -} - -inline int count_1s_max_15(Bitboard b) { - unsigned w = unsigned(b >> 32), v = unsigned(b); - v -= (v >> 1) & 0x55555555; // 0-2 in 2 bits - w -= (w >> 1) & 0x55555555; - v = ((v >> 2) & 0x33333333) + (v & 0x33333333); // 0-4 in 4 bits - w = ((w >> 2) & 0x33333333) + (w & 0x33333333); - v += w; // 0-8 in 4 bits - v *= 0x11111111; - return int(v >> 28); -} - -#elif defined(BITCOUNT_SWAR_64) - -inline int count_1s(Bitboard b) { - b -= ((b>>1) & 0x5555555555555555ULL); - b = ((b>>2) & 0x3333333333333333ULL) + (b & 0x3333333333333333ULL); - b = ((b>>4) + b) & 0x0F0F0F0F0F0F0F0FULL; - b *= 0x0101010101010101ULL; - return int(b >> 56); -} - -inline int count_1s_max_15(Bitboard b) { - b -= (b>>1) & 0x5555555555555555ULL; - b = ((b>>2) & 0x3333333333333333ULL) + (b & 0x3333333333333333ULL); - b *= 0x1111111111111111ULL; - return int(b >> 60); -} - -#endif // BITCOUNT - - //// //// Prototypes //// diff --git a/src/bitcount.h b/src/bitcount.h new file mode 100644 index 00000000..12826a9f --- /dev/null +++ b/src/bitcount.h @@ -0,0 +1,162 @@ +/* + Stockfish, a UCI chess playing engine derived from Glaurung 2.1 + Copyright (C) 2004-2008 Tord Romstad (Glaurung author) + Copyright (C) 2008-2009 Marco Costalba + + Stockfish is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + + Stockfish is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + + +#if !defined(BITCOUNT_H_INCLUDED) +#define BITCOUNT_H_INCLUDED + +#include "bitboard.h" + + +// Select type of software bit count function to use + +#if !defined(AUTO_CONFIGURATION) || defined(IS_64BIT) + +//#define USE_COMPACT_ROOK_ATTACKS +//#define USE_32BIT_ATTACKS +#define USE_FOLDED_BITSCAN + +#define BITCOUNT_SWAR_64 +//#define BITCOUNT_SWAR_32 +//#define BITCOUNT_LOOP + +#else + +#define USE_32BIT_ATTACKS +#define USE_FOLDED_BITSCAN +#define BITCOUNT_SWAR_32 + +#endif + + +// Select type of intrinsic bit count instruction to use + +#if defined(_MSC_VER) // Microsoft compiler + +#include + +inline bool cpu_has_popcnt() { + + int CPUInfo[4] = {-1}; + __cpuid(CPUInfo, 0x00000001); + return (CPUInfo[2] >> 23) & 1; +} + +#define POPCNT_INTRINSIC(x) __popcnt64(x) + +#elif defined(__INTEL_COMPILER) && (defined(__x86_64) || defined(_M_X64)) // Intel compiler + +#include + +inline bool cpu_has_popcnt() { + + int CPUInfo[4] = {-1}; + __cpuid(CPUInfo, 0x00000001); + return (CPUInfo[2] >> 23) & 1; +} + +#define POPCNT_INTRINSIC(x) _mm_popcnt_u64(x) + +#else // Safe fallback for unsupported compilers + +inline bool cpu_has_popcnt() { return false; } + +#define POPCNT_INTRINSIC(x) sw_count_1s(x) + +#endif + + +/// Software implementation of bit count functions + +#if defined(BITCOUNT_LOOP) + +inline int sw_count_1s(Bitboard b) { + int r; + for(r = 0; b; r++, b &= b - 1); + return r; +} + +inline int sw_count_1s_max_15(Bitboard b) { + return count_1s(b); +} + +#elif defined(BITCOUNT_SWAR_32) + +inline int sw_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; + v = ((v >> 2) & 0x33333333) + (v & 0x33333333); // 0-4 in 4 bits + w = ((w >> 2) & 0x33333333) + (w & 0x33333333); + v = ((v >> 4) + v) & 0x0F0F0F0F; // 0-8 in 8 bits + v += (((w >> 4) + w) & 0x0F0F0F0F); // 0-16 in 8 bits + v *= 0x01010101; // mul is fast on amd procs + return int(v >> 24); +} + +inline int sw_count_1s_max_15(Bitboard b) { + unsigned w = unsigned(b >> 32), v = unsigned(b); + v -= (v >> 1) & 0x55555555; // 0-2 in 2 bits + w -= (w >> 1) & 0x55555555; + v = ((v >> 2) & 0x33333333) + (v & 0x33333333); // 0-4 in 4 bits + w = ((w >> 2) & 0x33333333) + (w & 0x33333333); + v += w; // 0-8 in 4 bits + v *= 0x11111111; + return int(v >> 28); +} + +#elif defined(BITCOUNT_SWAR_64) + +inline int sw_count_1s(Bitboard b) { + b -= ((b>>1) & 0x5555555555555555ULL); + b = ((b>>2) & 0x3333333333333333ULL) + (b & 0x3333333333333333ULL); + b = ((b>>4) + b) & 0x0F0F0F0F0F0F0F0FULL; + b *= 0x0101010101010101ULL; + return int(b >> 56); +} + +inline int sw_count_1s_max_15(Bitboard b) { + b -= (b>>1) & 0x5555555555555555ULL; + b = ((b>>2) & 0x3333333333333333ULL) + (b & 0x3333333333333333ULL); + b *= 0x1111111111111111ULL; + return int(b >> 60); +} + +#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) : sw_count_1s(b); +} + +template +inline int count_1s_max_15(Bitboard b) { + + return UseIntrinsic ? POPCNT_INTRINSIC(b) : sw_count_1s_max_15(b); +} + + +#endif // !defined(BITCOUNT_H_INCLUDED) diff --git a/src/endgame.cpp b/src/endgame.cpp index 3f3bdcce..90898e83 100644 --- a/src/endgame.cpp +++ b/src/endgame.cpp @@ -25,6 +25,7 @@ #include #include "bitbase.h" +#include "bitcount.h" #include "endgame.h" @@ -377,7 +378,7 @@ Value EvaluationFunction::apply(const Position& pos) { result += Value(square_distance(bksq, nsq) * 32); // Bonus for restricting the knight's mobility - result += Value((8 - count_1s_max_15(pos.piece_attacks(nsq))) * 8); + result += Value((8 - count_1s_max_15(pos.piece_attacks(nsq))) * 8); return (strongerSide == pos.side_to_move() ? result : -result); } diff --git a/src/evaluate.cpp b/src/evaluate.cpp index c0b4866b..35922281 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -25,6 +25,7 @@ #include #include +#include "bitcount.h" #include "evaluate.h" #include "material.h" #include "pawns.h" @@ -339,8 +340,8 @@ Value evaluate(const Position &pos, EvalInfo &ei, int threadID) { // Initialize pawn attack bitboards for both sides ei.attackedBy[WHITE][PAWN] = ((pos.pawns(WHITE) << 9) & ~FileABB) | ((pos.pawns(WHITE) << 7) & ~FileHBB); ei.attackedBy[BLACK][PAWN] = ((pos.pawns(BLACK) >> 7) & ~FileABB) | ((pos.pawns(BLACK) >> 9) & ~FileHBB); - ei.kingAttackersCount[WHITE] = count_1s_max_15(ei.attackedBy[WHITE][PAWN] & ei.attackedBy[BLACK][KING])/2; - ei.kingAttackersCount[BLACK] = count_1s_max_15(ei.attackedBy[BLACK][PAWN] & ei.attackedBy[WHITE][KING])/2; + ei.kingAttackersCount[WHITE] = count_1s_max_15(ei.attackedBy[WHITE][PAWN] & ei.attackedBy[BLACK][KING])/2; + ei.kingAttackersCount[BLACK] = count_1s_max_15(ei.attackedBy[BLACK][PAWN] & ei.attackedBy[WHITE][KING])/2; // Evaluate pieces for (Color c = WHITE; c <= BLACK; c++) @@ -481,8 +482,8 @@ void init_eval(int threads) { for (Bitboard b = 0ULL; b < 256ULL; b++) { - assert(count_1s(b) == int(uint8_t(count_1s(b)))); - BitCount8Bit[b] = (uint8_t)count_1s(b); + assert(count_1s(b) == int(uint8_t(count_1s(b)))); + BitCount8Bit[b] = (uint8_t)count_1s(b); } } @@ -547,15 +548,15 @@ namespace { ei.kingAttackersWeight[us] += AttackWeight[Piece]; Bitboard bb = (b & ei.attackedBy[them][KING]); if (bb) - ei.kingAdjacentZoneAttacksCount[us] += count_1s_max_15(bb); + ei.kingAdjacentZoneAttacksCount[us] += count_1s_max_15(bb); } // Remove squares protected by enemy pawns Bitboard bb = (b & ~ei.attackedBy[them][PAWN]); // Mobility - int mob = (Piece != QUEEN ? count_1s_max_15(bb & ~p.pieces_of_color(us)) - : count_1s(bb & ~p.pieces_of_color(us))); + int mob = (Piece != QUEEN ? count_1s_max_15(bb & ~p.pieces_of_color(us)) + : count_1s(bb & ~p.pieces_of_color(us))); ei.mgMobility += Sign[us] * MgBonus[Piece][mob]; ei.egMobility += Sign[us] * EgBonus[Piece][mob]; @@ -744,7 +745,7 @@ namespace { // quality of the pawn shelter. int attackUnits = Min((ei.kingAttackersCount[them] * ei.kingAttackersWeight[them]) / 2, 25) - + (ei.kingAdjacentZoneAttacksCount[them] + count_1s_max_15(undefended)) * 3 + + (ei.kingAdjacentZoneAttacksCount[them] + count_1s_max_15(undefended)) * 3 + InitKingDanger[relative_square(us, s)] - (shelter >> 5); // Analyse safe queen contact checks @@ -760,7 +761,7 @@ namespace { { // The bitboard b now contains the squares available for safe queen // contact checks. - int count = count_1s_max_15(b); + int count = count_1s_max_15(b); attackUnits += QueenContactCheckBonus * count * (sente ? 2 : 1); // Is there a mate threat? @@ -800,12 +801,12 @@ namespace { // Queen checks b2 = b & ei.attacked_by(them, QUEEN); if( b2) - attackUnits += QueenCheckBonus * count_1s_max_15(b2); + attackUnits += QueenCheckBonus * count_1s_max_15(b2); // Rook checks b2 = b & ei.attacked_by(them, ROOK); if (b2) - attackUnits += RookCheckBonus * count_1s_max_15(b2); + attackUnits += RookCheckBonus * count_1s_max_15(b2); } if (QueenCheckBonus > 0 || BishopCheckBonus > 0) { @@ -814,12 +815,12 @@ namespace { // Queen checks b2 = b & ei.attacked_by(them, QUEEN); if (b2) - attackUnits += QueenCheckBonus * count_1s_max_15(b2); + attackUnits += QueenCheckBonus * count_1s_max_15(b2); // Bishop checks b2 = b & ei.attacked_by(them, BISHOP); if (b2) - attackUnits += BishopCheckBonus * count_1s_max_15(b2); + attackUnits += BishopCheckBonus * count_1s_max_15(b2); } if (KnightCheckBonus > 0) { @@ -828,7 +829,7 @@ namespace { // Knight checks b2 = b & ei.attacked_by(them, KNIGHT); if (b2) - attackUnits += KnightCheckBonus * count_1s_max_15(b2); + attackUnits += KnightCheckBonus * count_1s_max_15(b2); } // Analyse discovered checks (only for non-pawns right now, consider @@ -837,7 +838,7 @@ namespace { { b = p.discovered_check_candidates(them) & ~p.pawns(); if (b) - attackUnits += DiscoveredCheckBonus * count_1s_max_15(b) * (sente? 2 : 1); + attackUnits += DiscoveredCheckBonus * count_1s_max_15(b) * (sente? 2 : 1); } // Has a mate threat been found? We don't do anything here if the @@ -972,7 +973,7 @@ namespace { if (d < 0) { int mtg = RANK_8 - relative_rank(us, s); - int blockerCount = count_1s_max_15(squares_in_front_of(us,s) & pos.occupied_squares()); + int blockerCount = count_1s_max_15(squares_in_front_of(us,s) & pos.occupied_squares()); mtg += blockerCount; d += blockerCount; if (d < 0) @@ -1133,8 +1134,8 @@ namespace { behindFriendlyPawns |= (behindFriendlyPawns << 16); } - int space = count_1s_max_15(safeSquares) - + count_1s_max_15(behindFriendlyPawns & safeSquares); + int space = count_1s_max_15(safeSquares) + + count_1s_max_15(behindFriendlyPawns & safeSquares); ei.mgValue += Sign[us] * apply_weight(Value(space * ei.mi->space_weight()), WeightSpace); } diff --git a/src/main.cpp b/src/main.cpp index e009fd96..91986206 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -18,7 +18,7 @@ */ // To profile with callgrind uncomment following line -//#define USE_CALLGRIND +#define USE_CALLGRIND //// diff --git a/src/pawns.cpp b/src/pawns.cpp index 3cfe3750..08b0e7ba 100644 --- a/src/pawns.cpp +++ b/src/pawns.cpp @@ -25,6 +25,7 @@ #include #include +#include "bitcount.h" #include "pawns.h" #include "position.h" @@ -329,8 +330,8 @@ PawnInfo *PawnInfoTable::get_pawn_info(const Position &pos) { // Test for candidate passed pawn candidate = !passed && pos.file_is_half_open(them, f) - && ( count_1s_max_15(neighboring_files_bb(f) & (behind_bb(us, r) | rank_bb(r)) & ourPawns) - - count_1s_max_15(neighboring_files_bb(f) & in_front_bb(us, r) & theirPawns) + && ( count_1s_max_15(neighboring_files_bb(f) & (behind_bb(us, r) | rank_bb(r)) & ourPawns) + - count_1s_max_15(neighboring_files_bb(f) & in_front_bb(us, r) & theirPawns) >= 0); // In order to prevent doubled passed pawns from receiving a too big diff --git a/src/position.cpp b/src/position.cpp index f4752c5e..6e6bf38b 100644 --- a/src/position.cpp +++ b/src/position.cpp @@ -27,6 +27,7 @@ #include #include +#include "bitcount.h" #include "mersenne.h" #include "movegen.h" #include "movepick.h" @@ -2090,7 +2091,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? @@ -2165,7 +2166,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_of_color_and_type(c, pt))) + if (pieceCount[c][pt] != count_1s(pieces_of_color_and_type(c, pt))) return false; if (failedStep) (*failedStep)++; From e7d3a006cda7822517159cad0ef222eb7e46db00 Mon Sep 17 00:00:00 2001 From: Marco Costalba Date: Thu, 21 May 2009 16:41:31 +0200 Subject: [PATCH 02/11] Enable POPCNT at runtime Runtime detect POPCNT instruction support and use it. Also if POPCNT is not supported we don't add _any_ overhead so that we don't lose any speed in standard case. No functional change. Signed-off-by: Marco Costalba --- src/bitcount.h | 5 +++++ src/evaluate.cpp | 44 ++++++++++++++++++++++++++++---------------- 2 files changed, 33 insertions(+), 16 deletions(-) diff --git a/src/bitcount.h b/src/bitcount.h index 12826a9f..40160633 100644 --- a/src/bitcount.h +++ b/src/bitcount.h @@ -159,4 +159,9 @@ inline int count_1s_max_15(Bitboard b) { } +// Global variable initialized at startup that is set to true if +// CPU on which application runs support POPCNT intrinsic. + +const bool CpuHasPOPCNT = cpu_has_popcnt(); + #endif // !defined(BITCOUNT_H_INCLUDED) diff --git a/src/evaluate.cpp b/src/evaluate.cpp index 35922281..78cefc45 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -268,11 +268,14 @@ namespace { uint8_t BitCount8Bit[256]; // Function prototypes - template + template + Value do_evaluate(const Position& pos, EvalInfo& ei, int threadID); + + template void evaluate_pieces(const Position& p, Color us, EvalInfo& ei); template<> - void evaluate_pieces(const Position& p, Color us, EvalInfo &ei); + void evaluate_pieces(const Position& p, Color us, EvalInfo &ei); void evaluate_passed_pawns(const Position &pos, EvalInfo &ei); void evaluate_trapped_bishop_a7h7(const Position &pos, Square s, Color us, @@ -295,11 +298,19 @@ namespace { //// Functions //// -/// evaluate() is the main evaluation function. It always computes two +/// evaluate() is the main evaluation function. It always computes two /// values, an endgame score and a middle game score, and interpolates /// between them based on the remaining material. +Value evaluate(const Position& pos, EvalInfo& ei, int threadID) { -Value evaluate(const Position &pos, EvalInfo &ei, int threadID) { + return CpuHasPOPCNT ? do_evaluate(pos, ei, threadID) + : do_evaluate(pos, ei, threadID); +} + +namespace { + +template +Value do_evaluate(const Position& pos, EvalInfo& ei, int threadID) { assert(pos.is_ok()); assert(threadID >= 0 && threadID < THREAD_MAX); @@ -346,10 +357,10 @@ Value evaluate(const Position &pos, EvalInfo &ei, int threadID) { // Evaluate pieces for (Color c = WHITE; c <= BLACK; c++) { - evaluate_pieces(pos, c, ei); - evaluate_pieces(pos, c, ei); - evaluate_pieces(pos, c, ei); - evaluate_pieces(pos, c, ei); + evaluate_pieces(pos, c, ei); + evaluate_pieces(pos, c, ei); + evaluate_pieces(pos, c, ei); + evaluate_pieces(pos, c, ei); // Sum up all attacked squares ei.attackedBy[c][0] = ei.attackedBy[c][PAWN] | ei.attackedBy[c][KNIGHT] @@ -361,7 +372,7 @@ Value evaluate(const Position &pos, EvalInfo &ei, int threadID) { // because we need complete attack information for all pieces when computing // the king safety evaluation. for (Color c = WHITE; c <= BLACK; c++) - evaluate_pieces(pos, c, ei); + evaluate_pieces(pos, c, ei); // Evaluate passed pawns. We evaluate passed pawns for both sides at once, // because we need to know which side promotes first in positions where @@ -437,6 +448,7 @@ Value evaluate(const Position &pos, EvalInfo &ei, int threadID) { return (ei.mateThreat[stm] == MOVE_NONE ? v : 8 * QueenValueMidgame - v); } +} // namespace /// quick_evaluate() does a very approximate evaluation of the current position. /// It currently considers only material and piece square table scores. Perhaps @@ -528,7 +540,7 @@ namespace { // evaluate_common() computes terms common to all pieces attack - template + template int evaluate_common(const Position& p, const Bitboard& b, Color us, EvalInfo& ei, Square s = SQ_NONE) { static const int AttackWeight[] = { 0, 0, KnightAttackWeight, BishopAttackWeight, RookAttackWeight, QueenAttackWeight }; @@ -548,15 +560,15 @@ namespace { ei.kingAttackersWeight[us] += AttackWeight[Piece]; Bitboard bb = (b & ei.attackedBy[them][KING]); if (bb) - ei.kingAdjacentZoneAttacksCount[us] += count_1s_max_15(bb); + ei.kingAdjacentZoneAttacksCount[us] += count_1s_max_15(bb); } // Remove squares protected by enemy pawns Bitboard bb = (b & ~ei.attackedBy[them][PAWN]); // Mobility - int mob = (Piece != QUEEN ? count_1s_max_15(bb & ~p.pieces_of_color(us)) - : count_1s(bb & ~p.pieces_of_color(us))); + int mob = (Piece != QUEEN ? count_1s_max_15(bb & ~p.pieces_of_color(us)) + : count_1s(bb & ~p.pieces_of_color(us))); ei.mgMobility += Sign[us] * MgBonus[Piece][mob]; ei.egMobility += Sign[us] * EgBonus[Piece][mob]; @@ -588,7 +600,7 @@ namespace { // evaluate_pieces<>() assigns bonuses and penalties to the pieces of a given // color. - template + template void evaluate_pieces(const Position& pos, Color us, EvalInfo& ei) { Bitboard b; @@ -609,7 +621,7 @@ namespace { b = rook_attacks_bb(s, pos.occupied_squares() & ~pos.rooks_and_queens(us)); // Attacks, mobility and outposts - mob = evaluate_common(pos, b, us, ei, s); + mob = evaluate_common(pos, b, us, ei, s); // Special patterns: trapped bishops on a7/h7/a2/h2 // and trapped bishops on a1/h1/a8/h8 in Chess960. @@ -692,7 +704,7 @@ namespace { // color. template<> - void evaluate_pieces(const Position& p, Color us, EvalInfo& ei) { + void evaluate_pieces(const Position& p, Color us, EvalInfo& ei) { int shelter = 0, sign = Sign[us]; Square s = p.king_square(us); From 0228ff9ca04fad817de5f1e7a7890908a3b0013e Mon Sep 17 00:00:00 2001 From: Marco Costalba Date: Thu, 21 May 2009 16:42:07 +0200 Subject: [PATCH 03/11] Add temporary debug info on POPCNT support To be removed before to release. Signed-off-by: Marco Costalba --- src/main.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/main.cpp b/src/main.cpp index 91986206..210b8363 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -29,6 +29,7 @@ #include #include "benchmark.h" +#include "bitcount.h" #include "misc.h" #include "uci.h" @@ -77,6 +78,9 @@ int main(int argc, char *argv[]) { cout << engine_name() << ". Copyright (C) " << "2004-2009 Tord Romstad, Marco Costalba. " << endl; + // FIXME ONLY FOR DEBUG, REMOVE BEFORE RELEASE + cout << "Support for POPCNT is " << CpuHasPOPCNT << endl; + // Enter UCI mode uci_main_loop(); return 0; From c729e4e1aba0d0d1cded8bf1dc1eb6c7e56938dd Mon Sep 17 00:00:00 2001 From: Marco Costalba Date: Thu, 21 May 2009 16:50:19 +0200 Subject: [PATCH 04/11] Forgot two conversion to new POPCNT interface No functional change. Signed-off-by: Marco Costalba --- src/evaluate.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/evaluate.cpp b/src/evaluate.cpp index 78cefc45..1d4be67b 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -351,8 +351,8 @@ Value do_evaluate(const Position& pos, EvalInfo& ei, int threadID) { // Initialize pawn attack bitboards for both sides ei.attackedBy[WHITE][PAWN] = ((pos.pawns(WHITE) << 9) & ~FileABB) | ((pos.pawns(WHITE) << 7) & ~FileHBB); ei.attackedBy[BLACK][PAWN] = ((pos.pawns(BLACK) >> 7) & ~FileABB) | ((pos.pawns(BLACK) >> 9) & ~FileHBB); - ei.kingAttackersCount[WHITE] = count_1s_max_15(ei.attackedBy[WHITE][PAWN] & ei.attackedBy[BLACK][KING])/2; - ei.kingAttackersCount[BLACK] = count_1s_max_15(ei.attackedBy[BLACK][PAWN] & ei.attackedBy[WHITE][KING])/2; + ei.kingAttackersCount[WHITE] = count_1s_max_15(ei.attackedBy[WHITE][PAWN] & ei.attackedBy[BLACK][KING])/2; + ei.kingAttackersCount[BLACK] = count_1s_max_15(ei.attackedBy[BLACK][PAWN] & ei.attackedBy[WHITE][KING])/2; // Evaluate pieces for (Color c = WHITE; c <= BLACK; c++) From 628f844c116e3afe99d0f72ca5f6cd2119e918d9 Mon Sep 17 00:00:00 2001 From: Marco Costalba Date: Thu, 21 May 2009 17:08:34 +0100 Subject: [PATCH 05/11] Fix compile errors under MSVC Fallback from previous patches. Signed-off-by: Marco Costalba --- src/bitcount.h | 2 +- src/main.cpp | 2 +- src/movegen.cpp | 3 ++- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/bitcount.h b/src/bitcount.h index 40160633..a4133fb2 100644 --- a/src/bitcount.h +++ b/src/bitcount.h @@ -48,7 +48,7 @@ // Select type of intrinsic bit count instruction to use -#if defined(_MSC_VER) // Microsoft compiler +#if defined(_MSC_VER) && defined(_WIN64) // Microsoft compiler #include diff --git a/src/main.cpp b/src/main.cpp index 210b8363..9c860114 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -18,7 +18,7 @@ */ // To profile with callgrind uncomment following line -#define USE_CALLGRIND +//#define USE_CALLGRIND //// diff --git a/src/movegen.cpp b/src/movegen.cpp index a783a625..4f1d14de 100644 --- a/src/movegen.cpp +++ b/src/movegen.cpp @@ -24,6 +24,7 @@ #include +#include "bitcount.h" #include "movegen.h" // Simple macro to wrap a very common while loop, no facny, no flexibility, @@ -333,7 +334,7 @@ int generate_evasions(const Position& pos, MoveStack* mlist, Bitboard pinned) { // The checking pawn cannot be a discovered (bishop) check candidate // otherwise we were in check also before last double push move. assert(!bit_is_set(pos.discovered_check_candidates(them), checksq)); - assert(count_1s(b1) == 1 || count_1s(b1) == 2); + assert(count_1s(b1) == 1 || count_1s(b1) == 2); b1 &= ~pinned; while (b1) From ce5d9eb19da890c77d8ef00e078c60edc3e8e4aa Mon Sep 17 00:00:00 2001 From: Marco Costalba Date: Sat, 23 May 2009 11:42:43 +0100 Subject: [PATCH 06/11] Print info about use of 64bit functions and hardware POPCNT With this patch at the applications startup a line is printed with info about use of optimized 64 bit routines and hardware POPCNT. Also allow the possibility to disable POPCNT support during PGO compiles to exercise the fallback software only path. Signed-off-by: Marco Costalba --- src/bitcount.h | 23 +++++++++++++++++++++-- src/main.cpp | 6 +++--- src/misc.cpp | 7 +++++-- 3 files changed, 29 insertions(+), 7 deletions(-) diff --git a/src/bitcount.h b/src/bitcount.h index a4133fb2..c6e969a8 100644 --- a/src/bitcount.h +++ b/src/bitcount.h @@ -22,6 +22,12 @@ #if !defined(BITCOUNT_H_INCLUDED) #define BITCOUNT_H_INCLUDED +// To disable POPCNT support uncomment following line. You should do it only +// in PGO compiling to exercise the default fallback path. Don't forget to +// re-comment the line for the final optimized compile though ;-) +//#define DISABLE_POPCNT_SUPPORT + + #include "bitboard.h" @@ -160,8 +166,21 @@ inline int count_1s_max_15(Bitboard b) { // Global variable initialized at startup that is set to true if -// CPU on which application runs support POPCNT intrinsic. - +// CPU on which application runs supports POPCNT intrinsic. Unless +// DISABLE_POPCNT_SUPPORT is defined. +#if defined(DISABLE_POPCNT_SUPPORT) +const bool CpuHasPOPCNT = false; +#else const bool CpuHasPOPCNT = cpu_has_popcnt(); +#endif + + +// Global variable used to print info about the use of 64 optimized +// functions to verify that a 64bit compile has been correctly built. +#if defined(BITCOUNT_SWAR_64) +const bool CpuHas64BitPath = true; +#else +const bool CpuHas64BitPath = false; +#endif #endif // !defined(BITCOUNT_H_INCLUDED) diff --git a/src/main.cpp b/src/main.cpp index 9c860114..fc970a0e 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -75,11 +75,11 @@ int main(int argc, char *argv[]) { } // Print copyright notice - cout << engine_name() << ". Copyright (C) " + cout << engine_name() << ". Copyright (C) " << "2004-2009 Tord Romstad, Marco Costalba. " << endl; - // FIXME ONLY FOR DEBUG, REMOVE BEFORE RELEASE - cout << "Support for POPCNT is " << CpuHasPOPCNT << endl; + if (CpuHasPOPCNT) + cout << "Good! CPU has hardware POPCNT. We will use it." << endl; // Enter UCI mode uci_main_loop(); diff --git a/src/misc.cpp b/src/misc.cpp index ba4da568..149cfb45 100644 --- a/src/misc.cpp +++ b/src/misc.cpp @@ -65,6 +65,7 @@ static int gettimeofday(struct timeval* tp, struct timezone*) #include #include +#include "bitcount.h" #include "misc.h" using namespace std; @@ -162,8 +163,10 @@ void dbg_print_mean(ofstream& logFile) { const string engine_name() { + const string cpu64(CpuHas64BitPath ? " 64bit" : ""); + if (!EngineVersion.empty()) - return "Stockfish " + EngineVersion; + return AppName+ " " + EngineVersion + cpu64; string date(__DATE__); // From compiler, format is "Sep 21 2008" string months("Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec"); @@ -176,7 +179,7 @@ const string engine_name() { string name = AppName + " " + AppTag + " "; s << name << date.substr(date.length() - 2) << setfill('0') - << setw(2) << mon << setw(2) << day; + << setw(2) << mon << setw(2) << day << cpu64; return s.str(); } From f90f810ac4de5ea2f5582ca05a9354c33971a953 Mon Sep 17 00:00:00 2001 From: Marco Costalba Date: Sun, 24 May 2009 09:46:43 +0100 Subject: [PATCH 07/11] Enable _BitScanForward64 at runtime Only add infrastructure, still disabled. No functional change. Signed-off-by: Marco Costalba --- src/bitboard.cpp | 2 +- src/bitcount.h | 24 ++++++++++++++++++++++++ src/movegen.cpp | 2 +- 3 files changed, 26 insertions(+), 2 deletions(-) diff --git a/src/bitboard.cpp b/src/bitboard.cpp index f7a6ba27..3dfa040b 100644 --- a/src/bitboard.cpp +++ b/src/bitboard.cpp @@ -340,7 +340,7 @@ Square pop_1st_bit(Bitboard *b) { #endif -#else +#else // defined(USE_FOLDED_BITSCAN) static const int BitTable[64] = { 0, 1, 2, 7, 3, 13, 8, 19, 4, 25, 14, 28, 9, 34, 20, 40, 5, 17, 26, 38, 15, diff --git a/src/bitcount.h b/src/bitcount.h index c6e969a8..41a1446e 100644 --- a/src/bitcount.h +++ b/src/bitcount.h @@ -66,6 +66,7 @@ inline bool cpu_has_popcnt() { } #define POPCNT_INTRINSIC(x) __popcnt64(x) +#define BITSCAN_INTRINSIC(idx, x) _BitScanForward64(idx, x) #elif defined(__INTEL_COMPILER) && (defined(__x86_64) || defined(_M_X64)) // Intel compiler @@ -79,12 +80,14 @@ inline bool cpu_has_popcnt() { } #define POPCNT_INTRINSIC(x) _mm_popcnt_u64(x) +#define BITSCAN_INTRINSIC(idx, x) _BitScanForward64(idx, x) #else // Safe fallback for unsupported compilers inline bool cpu_has_popcnt() { return false; } #define POPCNT_INTRINSIC(x) sw_count_1s(x) +#define BITSCAN_INTRINSIC(idx, x) sw_count_1s(x) // dummy #endif @@ -183,4 +186,25 @@ const bool CpuHas64BitPath = true; const bool CpuHas64BitPath = false; #endif + +/// pop_1st_bit() finds and clears the least significant nonzero bit in a +/// nonzero bitboard. If template parameter is true an intrinsic is called, +/// otherwise we fallback on a software implementation. + +template +inline Square pop_1st_bit(Bitboard *b) { + + return pop_1st_bit(b); +} + +template<> +inline Square pop_1st_bit(Bitboard *b) { + + unsigned long idx; + Bitboard bb = *b; + BITSCAN_INTRINSIC(&idx, bb); + *b &= (bb - 1); + return Square(idx); +} + #endif // !defined(BITCOUNT_H_INCLUDED) diff --git a/src/movegen.cpp b/src/movegen.cpp index 4f1d14de..c51bc37f 100644 --- a/src/movegen.cpp +++ b/src/movegen.cpp @@ -29,7 +29,7 @@ // Simple macro to wrap a very common while loop, no facny, no flexibility, // hardcoded list name 'mlist' and from square 'from'. -#define SERIALIZE_MOVES(b) while (b) (*mlist++).move = make_move(from, pop_1st_bit(&b)) +#define SERIALIZE_MOVES(b) while (b) (*mlist++).move = make_move(from, pop_1st_bit(&b)) //// //// Local definitions From 6c9a64124a37afe82825e2a8ff91fe8418d8f388 Mon Sep 17 00:00:00 2001 From: Marco Costalba Date: Sun, 24 May 2009 10:07:03 +0100 Subject: [PATCH 08/11] Enable _BitScanForward64 in move generation No functional change. Signed-off-by: Marco Costalba --- src/movegen.cpp | 108 +++++++++++++++++++++++++++++------------------- 1 file changed, 66 insertions(+), 42 deletions(-) diff --git a/src/movegen.cpp b/src/movegen.cpp index c51bc37f..dbdb0875 100644 --- a/src/movegen.cpp +++ b/src/movegen.cpp @@ -29,7 +29,7 @@ // Simple macro to wrap a very common while loop, no facny, no flexibility, // hardcoded list name 'mlist' and from square 'from'. -#define SERIALIZE_MOVES(b) while (b) (*mlist++).move = make_move(from, pop_1st_bit(&b)) +#define SERIALIZE_MOVES(b, bsf) while (b) (*mlist++).move = make_move(from, pop_1st_bit(&b)) //// //// Local definitions @@ -83,22 +83,22 @@ namespace { } // Template generate_piece_checks() with specializations - template + template MoveStack* generate_piece_checks(const Position&, MoveStack*, Color, Bitboard, Square); template<> - inline MoveStack* generate_piece_checks(const Position& p, MoveStack* m, Color us, Bitboard dc, Square ksq) { + inline MoveStack* generate_piece_checks(const Position& p, MoveStack* m, Color us, Bitboard dc, Square ksq) { return (us == WHITE ? generate_pawn_checks(p, dc, ksq, m) : generate_pawn_checks(p, dc, ksq, m)); } // Template generate_piece_moves() with specializations and overloads - template + template MoveStack* generate_piece_moves(const Position&, MoveStack*, Color us, Bitboard); template<> - MoveStack* generate_piece_moves(const Position&, MoveStack*, Color, Bitboard); + MoveStack* generate_piece_moves(const Position&, MoveStack*, Color, Bitboard); template inline MoveStack* generate_piece_moves(const Position& p, MoveStack* m, Color us) { @@ -113,12 +113,12 @@ namespace { : generate_pawn_noncaptures(p, m)); } - template + template MoveStack* generate_piece_moves(const Position&, MoveStack*, Color us, Bitboard, Bitboard); template<> - inline MoveStack* generate_piece_moves(const Position& p, MoveStack* m, - Color us, Bitboard t, Bitboard pnd) { + inline MoveStack* generate_piece_moves(const Position& p, MoveStack* m, + Color us, Bitboard t, Bitboard pnd) { return (us == WHITE ? generate_pawn_blocking_evasions(p, pnd, t, m) : generate_pawn_blocking_evasions(p, pnd, t, m)); @@ -133,7 +133,7 @@ namespace { /// generate_captures generates() all pseudo-legal captures and queen /// promotions. The return value is the number of moves generated. - +template int generate_captures(const Position& pos, MoveStack* mlist) { assert(pos.is_ok()); @@ -143,19 +143,25 @@ int generate_captures(const Position& pos, MoveStack* mlist) { Bitboard target = pos.pieces_of_color(opposite_color(us)); MoveStack* mlist_start = mlist; - mlist = generate_piece_moves(pos, mlist, us, target); - mlist = generate_piece_moves(pos, mlist, us, target); - mlist = generate_piece_moves(pos, mlist, us, target); - mlist = generate_piece_moves(pos, mlist, us, target); + mlist = generate_piece_moves(pos, mlist, us, target); + mlist = generate_piece_moves(pos, mlist, us, target); + mlist = generate_piece_moves(pos, mlist, us, target); + mlist = generate_piece_moves(pos, mlist, us, target); mlist = generate_piece_moves(pos, mlist, us); - mlist = generate_piece_moves(pos, mlist, us, target); + mlist = generate_piece_moves(pos, mlist, us, target); return int(mlist - mlist_start); } +int generate_captures(const Position& pos, MoveStack* mlist) { + + return CpuHasPOPCNT ? generate_captures(pos, mlist) + : generate_captures(pos, mlist); +} + /// generate_noncaptures() generates all pseudo-legal non-captures and /// underpromotions. The return value is the number of moves generated. - +template int generate_noncaptures(const Position& pos, MoveStack* mlist) { assert(pos.is_ok()); @@ -166,20 +172,26 @@ int generate_noncaptures(const Position& pos, MoveStack* mlist) { MoveStack* mlist_start = mlist; mlist = generate_piece_moves(pos, mlist, us); - mlist = generate_piece_moves(pos, mlist, us, target); - mlist = generate_piece_moves(pos, mlist, us, target); - mlist = generate_piece_moves(pos, mlist, us, target); - mlist = generate_piece_moves(pos, mlist, us, target); - mlist = generate_piece_moves(pos, mlist, us, target); + mlist = generate_piece_moves(pos, mlist, us, target); + mlist = generate_piece_moves(pos, mlist, us, target); + mlist = generate_piece_moves(pos, mlist, us, target); + mlist = generate_piece_moves(pos, mlist, us, target); + mlist = generate_piece_moves(pos, mlist, us, target); mlist = generate_castle_moves(pos, mlist); mlist = generate_castle_moves(pos, mlist); return int(mlist - mlist_start); } +int generate_noncaptures(const Position& pos, MoveStack* mlist) { + + return CpuHasPOPCNT ? generate_noncaptures(pos, mlist) + : generate_noncaptures(pos, mlist); +} + /// generate_non_capture_checks() generates all pseudo-legal non-capturing, /// non-promoting checks. It returns the number of generated moves. - +template int generate_non_capture_checks(const Position& pos, MoveStack* mlist, Bitboard dc) { assert(pos.is_ok()); @@ -192,12 +204,12 @@ int generate_non_capture_checks(const Position& pos, MoveStack* mlist, Bitboard assert(pos.piece_on(ksq) == piece_of_color_and_type(opposite_color(us), KING)); // Pieces moves - mlist = generate_piece_checks(pos, mlist, us, dc, ksq); - mlist = generate_piece_checks(pos, mlist, us, dc, ksq); - mlist = generate_piece_checks(pos, mlist, us, dc, ksq); - mlist = generate_piece_checks(pos, mlist, us, dc, ksq); - mlist = generate_piece_checks(pos, mlist, us, dc, ksq); - mlist = generate_piece_checks(pos, mlist, us, dc, ksq); + mlist = generate_piece_checks(pos, mlist, us, dc, ksq); + mlist = generate_piece_checks(pos, mlist, us, dc, ksq); + mlist = generate_piece_checks(pos, mlist, us, dc, ksq); + mlist = generate_piece_checks(pos, mlist, us, dc, ksq); + mlist = generate_piece_checks(pos, mlist, us, dc, ksq); + mlist = generate_piece_checks(pos, mlist, us, dc, ksq); // Castling moves that give check. Very rare but nice to have! if ( pos.can_castle_queenside(us) @@ -213,11 +225,17 @@ int generate_non_capture_checks(const Position& pos, MoveStack* mlist, Bitboard return int(mlist - mlist_start); } +int generate_non_capture_checks(const Position& pos, MoveStack* mlist, Bitboard dc) { + + return CpuHasPOPCNT ? generate_non_capture_checks(pos, mlist, dc) + : generate_non_capture_checks(pos, mlist, dc); +} + /// generate_evasions() generates all check evasions when the side to move is /// in check. Unlike the other move generation functions, this one generates /// only legal moves. It returns the number of generated moves. - +template int generate_evasions(const Position& pos, MoveStack* mlist, Bitboard pinned) { assert(pos.is_ok()); @@ -313,11 +331,11 @@ int generate_evasions(const Position& pos, MoveStack* mlist, Bitboard pinned) { if (blockSquares != EmptyBoardBB) { - mlist = generate_piece_moves(pos, mlist, us, blockSquares, pinned); - mlist = generate_piece_moves(pos, mlist, us, blockSquares, pinned); - mlist = generate_piece_moves(pos, mlist, us, blockSquares, pinned); - mlist = generate_piece_moves(pos, mlist, us, blockSquares, pinned); - mlist = generate_piece_moves(pos, mlist, us, blockSquares, pinned); + mlist = generate_piece_moves(pos, mlist, us, blockSquares, pinned); + mlist = generate_piece_moves(pos, mlist, us, blockSquares, pinned); + mlist = generate_piece_moves(pos, mlist, us, blockSquares, pinned); + mlist = generate_piece_moves(pos, mlist, us, blockSquares, pinned); + mlist = generate_piece_moves(pos, mlist, us, blockSquares, pinned); } } @@ -350,6 +368,12 @@ int generate_evasions(const Position& pos, MoveStack* mlist, Bitboard pinned) { return int(mlist - mlist_start); } +int generate_evasions(const Position& pos, MoveStack* mlist, Bitboard pinned) { + + return CpuHasPOPCNT ? generate_evasions(pos, mlist, pinned) + : generate_evasions(pos, mlist, pinned); +} + /// generate_legal_moves() computes a complete list of legal moves in the /// current position. This function is not very fast, and should be used @@ -566,7 +590,7 @@ bool move_is_legal(const Position& pos, const Move m, Bitboard pinned) { namespace { - template + template MoveStack* generate_piece_moves(const Position& pos, MoveStack* mlist, Color us, Bitboard target) { Square from; @@ -576,12 +600,12 @@ namespace { { from = pos.piece_list(us, Piece, i); b = pos.piece_attacks(from) & target; - SERIALIZE_MOVES(b); + SERIALIZE_MOVES(b, HasBSF); } return mlist; } - template + template MoveStack* generate_piece_moves(const Position& pos, MoveStack* mlist, Color us, Bitboard target, Bitboard pinned) { Square from; @@ -594,19 +618,19 @@ namespace { continue; b = pos.piece_attacks(from) & target; - SERIALIZE_MOVES(b); + SERIALIZE_MOVES(b, HasBSF); } return mlist; } template<> - MoveStack* generate_piece_moves(const Position& pos, MoveStack* mlist, Color us, Bitboard target) { + MoveStack* generate_piece_moves(const Position& pos, MoveStack* mlist, Color us, Bitboard target) { Bitboard b; Square from = pos.king_square(us); b = pos.piece_attacks(from) & target; - SERIALIZE_MOVES(b); + SERIALIZE_MOVES(b, false); return mlist; } @@ -816,7 +840,7 @@ namespace { return mlist; } - template + template MoveStack* generate_piece_checks(const Position& pos, MoveStack* mlist, Color us, Bitboard dc, Square ksq) { @@ -831,7 +855,7 @@ namespace { if (Piece == KING) bb &= ~QueenPseudoAttacks[ksq]; - SERIALIZE_MOVES(bb); + SERIALIZE_MOVES(bb, HasBSF); } // Direct checks @@ -851,7 +875,7 @@ namespace { continue; Bitboard bb = pos.piece_attacks(from) & checkSqs; - SERIALIZE_MOVES(bb); + SERIALIZE_MOVES(bb, HasBSF); } } return mlist; From 76024ac40ea45e44a8389cb4206d40b884e259a5 Mon Sep 17 00:00:00 2001 From: Marco Costalba Date: Sun, 24 May 2009 10:15:23 +0100 Subject: [PATCH 09/11] Use compiler name lookup to simplify code We don't need different names between a function and a template. Compiler will know when use one or the other. This let use restore original count_1s_xx() names instead of sw_count_1s_xxx so to simplify a bit the code. No functional change. Signed-off-by: Marco Costalba --- src/bitboard.cpp | 2 +- src/bitcount.h | 58 ++++++++++++++++++++++++------------------------ src/endgame.cpp | 2 +- src/evaluate.cpp | 26 +++++++++++----------- src/movegen.cpp | 2 +- src/pawns.cpp | 4 ++-- src/position.cpp | 4 ++-- 7 files changed, 49 insertions(+), 49 deletions(-) diff --git a/src/bitboard.cpp b/src/bitboard.cpp index 3dfa040b..a73c5a2d 100644 --- a/src/bitboard.cpp +++ b/src/bitboard.cpp @@ -461,7 +461,7 @@ namespace { Bitboard index_to_bitboard(int index, Bitboard mask) { - int i, j, bits = count_1s(mask); + int i, j, bits = count_1s(mask); Bitboard result = 0ULL; for(i = 0; i < bits; i++) { j = pop_1st_bit(&mask); diff --git a/src/bitcount.h b/src/bitcount.h index 41a1446e..871247ab 100644 --- a/src/bitcount.h +++ b/src/bitcount.h @@ -86,8 +86,8 @@ inline bool cpu_has_popcnt() { inline bool cpu_has_popcnt() { return false; } -#define POPCNT_INTRINSIC(x) sw_count_1s(x) -#define BITSCAN_INTRINSIC(idx, x) sw_count_1s(x) // dummy +#define POPCNT_INTRINSIC(x) count_1s(x) +#define BITSCAN_INTRINSIC(idx, x) count_1s(x) // dummy #endif @@ -96,19 +96,19 @@ inline bool cpu_has_popcnt() { return false; } #if defined(BITCOUNT_LOOP) -inline int sw_count_1s(Bitboard b) { +inline int count_1s(Bitboard b) { int r; for(r = 0; b; r++, b &= b - 1); return r; } -inline int sw_count_1s_max_15(Bitboard b) { +inline int count_1s_max_15(Bitboard b) { return count_1s(b); } #elif defined(BITCOUNT_SWAR_32) -inline int sw_count_1s(Bitboard b) { +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; @@ -120,7 +120,7 @@ inline int sw_count_1s(Bitboard b) { return int(v >> 24); } -inline int sw_count_1s_max_15(Bitboard b) { +inline int count_1s_max_15(Bitboard b) { unsigned w = unsigned(b >> 32), v = unsigned(b); v -= (v >> 1) & 0x55555555; // 0-2 in 2 bits w -= (w >> 1) & 0x55555555; @@ -133,7 +133,7 @@ inline int sw_count_1s_max_15(Bitboard b) { #elif defined(BITCOUNT_SWAR_64) -inline int sw_count_1s(Bitboard b) { +inline int count_1s(Bitboard b) { b -= ((b>>1) & 0x5555555555555555ULL); b = ((b>>2) & 0x3333333333333333ULL) + (b & 0x3333333333333333ULL); b = ((b>>4) + b) & 0x0F0F0F0F0F0F0F0FULL; @@ -141,7 +141,7 @@ inline int sw_count_1s(Bitboard b) { return int(b >> 56); } -inline int sw_count_1s_max_15(Bitboard b) { +inline int count_1s_max_15(Bitboard b) { b -= (b>>1) & 0x5555555555555555ULL; b = ((b>>2) & 0x3333333333333333ULL) + (b & 0x3333333333333333ULL); b *= 0x1111111111111111ULL; @@ -158,35 +158,16 @@ inline int sw_count_1s_max_15(Bitboard b) { template inline int count_1s(Bitboard b) { - return UseIntrinsic ? POPCNT_INTRINSIC(b) : sw_count_1s(b); + return UseIntrinsic ? POPCNT_INTRINSIC(b) : count_1s(b); } template inline int count_1s_max_15(Bitboard b) { - return UseIntrinsic ? POPCNT_INTRINSIC(b) : sw_count_1s_max_15(b); + return UseIntrinsic ? POPCNT_INTRINSIC(b) : count_1s_max_15(b); } -// Global variable initialized at startup that is set to true if -// CPU on which application runs supports POPCNT intrinsic. Unless -// DISABLE_POPCNT_SUPPORT is defined. -#if defined(DISABLE_POPCNT_SUPPORT) -const bool CpuHasPOPCNT = false; -#else -const bool CpuHasPOPCNT = cpu_has_popcnt(); -#endif - - -// Global variable used to print info about the use of 64 optimized -// functions to verify that a 64bit compile has been correctly built. -#if defined(BITCOUNT_SWAR_64) -const bool CpuHas64BitPath = true; -#else -const bool CpuHas64BitPath = false; -#endif - - /// pop_1st_bit() finds and clears the least significant nonzero bit in a /// nonzero bitboard. If template parameter is true an intrinsic is called, /// otherwise we fallback on a software implementation. @@ -207,4 +188,23 @@ inline Square pop_1st_bit(Bitboard *b) { return Square(idx); } + +// Global variable initialized at startup that is set to true if +// CPU on which application runs supports POPCNT intrinsic. Unless +// DISABLE_POPCNT_SUPPORT is defined. +#if defined(DISABLE_POPCNT_SUPPORT) +const bool CpuHasPOPCNT = false; +#else +const bool CpuHasPOPCNT = cpu_has_popcnt(); +#endif + + +// Global variable used to print info about the use of 64 optimized +// functions to verify that a 64bit compile has been correctly built. +#if defined(BITCOUNT_SWAR_64) +const bool CpuHas64BitPath = true; +#else +const bool CpuHas64BitPath = false; +#endif + #endif // !defined(BITCOUNT_H_INCLUDED) diff --git a/src/endgame.cpp b/src/endgame.cpp index 90898e83..3258c6fc 100644 --- a/src/endgame.cpp +++ b/src/endgame.cpp @@ -378,7 +378,7 @@ Value EvaluationFunction::apply(const Position& pos) { result += Value(square_distance(bksq, nsq) * 32); // Bonus for restricting the knight's mobility - result += Value((8 - count_1s_max_15(pos.piece_attacks(nsq))) * 8); + result += Value((8 - count_1s_max_15(pos.piece_attacks(nsq))) * 8); return (strongerSide == pos.side_to_move() ? result : -result); } diff --git a/src/evaluate.cpp b/src/evaluate.cpp index 1d4be67b..9fd4040e 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -494,8 +494,8 @@ void init_eval(int threads) { for (Bitboard b = 0ULL; b < 256ULL; b++) { - assert(count_1s(b) == int(uint8_t(count_1s(b)))); - BitCount8Bit[b] = (uint8_t)count_1s(b); + assert(count_1s(b) == int(uint8_t(count_1s(b)))); + BitCount8Bit[b] = (uint8_t)count_1s(b); } } @@ -757,7 +757,7 @@ namespace { // quality of the pawn shelter. int attackUnits = Min((ei.kingAttackersCount[them] * ei.kingAttackersWeight[them]) / 2, 25) - + (ei.kingAdjacentZoneAttacksCount[them] + count_1s_max_15(undefended)) * 3 + + (ei.kingAdjacentZoneAttacksCount[them] + count_1s_max_15(undefended)) * 3 + InitKingDanger[relative_square(us, s)] - (shelter >> 5); // Analyse safe queen contact checks @@ -773,7 +773,7 @@ namespace { { // The bitboard b now contains the squares available for safe queen // contact checks. - int count = count_1s_max_15(b); + int count = count_1s_max_15(b); attackUnits += QueenContactCheckBonus * count * (sente ? 2 : 1); // Is there a mate threat? @@ -813,12 +813,12 @@ namespace { // Queen checks b2 = b & ei.attacked_by(them, QUEEN); if( b2) - attackUnits += QueenCheckBonus * count_1s_max_15(b2); + attackUnits += QueenCheckBonus * count_1s_max_15(b2); // Rook checks b2 = b & ei.attacked_by(them, ROOK); if (b2) - attackUnits += RookCheckBonus * count_1s_max_15(b2); + attackUnits += RookCheckBonus * count_1s_max_15(b2); } if (QueenCheckBonus > 0 || BishopCheckBonus > 0) { @@ -827,12 +827,12 @@ namespace { // Queen checks b2 = b & ei.attacked_by(them, QUEEN); if (b2) - attackUnits += QueenCheckBonus * count_1s_max_15(b2); + attackUnits += QueenCheckBonus * count_1s_max_15(b2); // Bishop checks b2 = b & ei.attacked_by(them, BISHOP); if (b2) - attackUnits += BishopCheckBonus * count_1s_max_15(b2); + attackUnits += BishopCheckBonus * count_1s_max_15(b2); } if (KnightCheckBonus > 0) { @@ -841,7 +841,7 @@ namespace { // Knight checks b2 = b & ei.attacked_by(them, KNIGHT); if (b2) - attackUnits += KnightCheckBonus * count_1s_max_15(b2); + attackUnits += KnightCheckBonus * count_1s_max_15(b2); } // Analyse discovered checks (only for non-pawns right now, consider @@ -850,7 +850,7 @@ namespace { { b = p.discovered_check_candidates(them) & ~p.pawns(); if (b) - attackUnits += DiscoveredCheckBonus * count_1s_max_15(b) * (sente? 2 : 1); + attackUnits += DiscoveredCheckBonus * count_1s_max_15(b) * (sente? 2 : 1); } // Has a mate threat been found? We don't do anything here if the @@ -985,7 +985,7 @@ namespace { if (d < 0) { int mtg = RANK_8 - relative_rank(us, s); - int blockerCount = count_1s_max_15(squares_in_front_of(us,s) & pos.occupied_squares()); + int blockerCount = count_1s_max_15(squares_in_front_of(us,s) & pos.occupied_squares()); mtg += blockerCount; d += blockerCount; if (d < 0) @@ -1146,8 +1146,8 @@ namespace { behindFriendlyPawns |= (behindFriendlyPawns << 16); } - int space = count_1s_max_15(safeSquares) - + count_1s_max_15(behindFriendlyPawns & safeSquares); + int space = count_1s_max_15(safeSquares) + + count_1s_max_15(behindFriendlyPawns & safeSquares); ei.mgValue += Sign[us] * apply_weight(Value(space * ei.mi->space_weight()), WeightSpace); } diff --git a/src/movegen.cpp b/src/movegen.cpp index dbdb0875..a76d9f7c 100644 --- a/src/movegen.cpp +++ b/src/movegen.cpp @@ -352,7 +352,7 @@ int generate_evasions(const Position& pos, MoveStack* mlist, Bitboard pinned) { // The checking pawn cannot be a discovered (bishop) check candidate // otherwise we were in check also before last double push move. assert(!bit_is_set(pos.discovered_check_candidates(them), checksq)); - assert(count_1s(b1) == 1 || count_1s(b1) == 2); + assert(count_1s(b1) == 1 || count_1s(b1) == 2); b1 &= ~pinned; while (b1) diff --git a/src/pawns.cpp b/src/pawns.cpp index 08b0e7ba..19bf6c51 100644 --- a/src/pawns.cpp +++ b/src/pawns.cpp @@ -330,8 +330,8 @@ PawnInfo *PawnInfoTable::get_pawn_info(const Position &pos) { // Test for candidate passed pawn candidate = !passed && pos.file_is_half_open(them, f) - && ( count_1s_max_15(neighboring_files_bb(f) & (behind_bb(us, r) | rank_bb(r)) & ourPawns) - - count_1s_max_15(neighboring_files_bb(f) & in_front_bb(us, r) & theirPawns) + && ( count_1s_max_15(neighboring_files_bb(f) & (behind_bb(us, r) | rank_bb(r)) & ourPawns) + - count_1s_max_15(neighboring_files_bb(f) & in_front_bb(us, r) & theirPawns) >= 0); // In order to prevent doubled passed pawns from receiving a too big diff --git a/src/position.cpp b/src/position.cpp index 6e6bf38b..dd6ec05b 100644 --- a/src/position.cpp +++ b/src/position.cpp @@ -2091,7 +2091,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? @@ -2166,7 +2166,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_of_color_and_type(c, pt))) + if (pieceCount[c][pt] != count_1s(pieces_of_color_and_type(c, pt))) return false; if (failedStep) (*failedStep)++; From d63ff85a43667f8e0de7b7e163cba02193a70815 Mon Sep 17 00:00:00 2001 From: Marco Costalba Date: Sun, 24 May 2009 10:25:59 +0100 Subject: [PATCH 10/11] Add a bit more pop_1st_bit conversions No functional change. Signed-off-by: Marco Costalba --- src/movegen.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/movegen.cpp b/src/movegen.cpp index a76d9f7c..8a03acd6 100644 --- a/src/movegen.cpp +++ b/src/movegen.cpp @@ -262,14 +262,14 @@ int generate_evasions(const Position& pos, MoveStack* mlist, Bitboard pinned) { Bitboard b = checkers & (pos.queens() | pos.bishops()); while (b) { - from = pop_1st_bit(&b); + from = pop_1st_bit(&b); checkersAttacks |= bishop_attacks_bb(from, b_noKing); } b = checkers & (pos.queens() | pos.rooks()); while (b) { - from = pop_1st_bit(&b); + from = pop_1st_bit(&b); checkersAttacks |= rook_attacks_bb(from, b_noKing); } @@ -277,7 +277,7 @@ int generate_evasions(const Position& pos, MoveStack* mlist, Bitboard pinned) { Bitboard b1 = pos.piece_attacks(ksq) & ~pos.pieces_of_color(us) & ~checkersAttacks; while (b1) { - to = pop_1st_bit(&b1); + to = pop_1st_bit(&b1); // Note that we can use square_is_attacked() only because we // have already removed slider checkers. if (!pos.square_is_attacked(to, them)) @@ -299,7 +299,7 @@ int generate_evasions(const Position& pos, MoveStack* mlist, Bitboard pinned) { b1 = pos.pawn_attacks(them, checksq) & pos.pawns(us) & ~pinned; while (b1) { - from = pop_1st_bit(&b1); + from = pop_1st_bit(&b1); if (relative_rank(us, checksq) == RANK_8) { (*mlist++).move = make_promotion_move(from, checksq, QUEEN); @@ -317,7 +317,7 @@ int generate_evasions(const Position& pos, MoveStack* mlist, Bitboard pinned) { while (b1) { - from = pop_1st_bit(&b1); + from = pop_1st_bit(&b1); (*mlist++).move = make_move(from, checksq); } @@ -357,7 +357,7 @@ int generate_evasions(const Position& pos, MoveStack* mlist, Bitboard pinned) { b1 &= ~pinned; while (b1) { - from = pop_1st_bit(&b1); + from = pop_1st_bit(&b1); // Move is always legal because checking pawn is not a discovered // check candidate and our capturing pawn has been already tested // against pinned pieces. @@ -850,7 +850,7 @@ namespace { Bitboard b = target & dc; while (b) { - Square from = pop_1st_bit(&b); + Square from = pop_1st_bit(&b); Bitboard bb = pos.piece_attacks(from) & pos.empty_squares(); if (Piece == KING) bb &= ~QueenPseudoAttacks[ksq]; @@ -868,7 +868,7 @@ namespace { while (b) { - Square from = pop_1st_bit(&b); + Square from = pop_1st_bit(&b); if ( (Piece == QUEEN && !(QueenPseudoAttacks[from] & checkSqs)) || (Piece == ROOK && !(RookPseudoAttacks[from] & checkSqs)) || (Piece == BISHOP && !(BishopPseudoAttacks[from] & checkSqs))) From f1591447cf791b6c0ed4710df7eb688c65c4c20e Mon Sep 17 00:00:00 2001 From: Marco Costalba Date: Mon, 25 May 2009 07:28:55 +0100 Subject: [PATCH 11/11] Revert _BitScanForward64 support It shows almost no improvment and adds a good bunch of complexity. So remove for now. No functional change. Signed-off-by: Marco Costalba --- src/bitcount.h | 24 ---------- src/movegen.cpp | 124 +++++++++++++++++++----------------------------- 2 files changed, 50 insertions(+), 98 deletions(-) diff --git a/src/bitcount.h b/src/bitcount.h index 871247ab..d57b3f40 100644 --- a/src/bitcount.h +++ b/src/bitcount.h @@ -66,7 +66,6 @@ inline bool cpu_has_popcnt() { } #define POPCNT_INTRINSIC(x) __popcnt64(x) -#define BITSCAN_INTRINSIC(idx, x) _BitScanForward64(idx, x) #elif defined(__INTEL_COMPILER) && (defined(__x86_64) || defined(_M_X64)) // Intel compiler @@ -80,14 +79,12 @@ inline bool cpu_has_popcnt() { } #define POPCNT_INTRINSIC(x) _mm_popcnt_u64(x) -#define BITSCAN_INTRINSIC(idx, x) _BitScanForward64(idx, x) #else // Safe fallback for unsupported compilers inline bool cpu_has_popcnt() { return false; } #define POPCNT_INTRINSIC(x) count_1s(x) -#define BITSCAN_INTRINSIC(idx, x) count_1s(x) // dummy #endif @@ -168,27 +165,6 @@ inline int count_1s_max_15(Bitboard b) { } -/// pop_1st_bit() finds and clears the least significant nonzero bit in a -/// nonzero bitboard. If template parameter is true an intrinsic is called, -/// otherwise we fallback on a software implementation. - -template -inline Square pop_1st_bit(Bitboard *b) { - - return pop_1st_bit(b); -} - -template<> -inline Square pop_1st_bit(Bitboard *b) { - - unsigned long idx; - Bitboard bb = *b; - BITSCAN_INTRINSIC(&idx, bb); - *b &= (bb - 1); - return Square(idx); -} - - // Global variable initialized at startup that is set to true if // CPU on which application runs supports POPCNT intrinsic. Unless // DISABLE_POPCNT_SUPPORT is defined. diff --git a/src/movegen.cpp b/src/movegen.cpp index 8a03acd6..1135c219 100644 --- a/src/movegen.cpp +++ b/src/movegen.cpp @@ -29,7 +29,7 @@ // Simple macro to wrap a very common while loop, no facny, no flexibility, // hardcoded list name 'mlist' and from square 'from'. -#define SERIALIZE_MOVES(b, bsf) while (b) (*mlist++).move = make_move(from, pop_1st_bit(&b)) +#define SERIALIZE_MOVES(b) while (b) (*mlist++).move = make_move(from, pop_1st_bit(&b)) //// //// Local definitions @@ -83,22 +83,22 @@ namespace { } // Template generate_piece_checks() with specializations - template + template MoveStack* generate_piece_checks(const Position&, MoveStack*, Color, Bitboard, Square); template<> - inline MoveStack* generate_piece_checks(const Position& p, MoveStack* m, Color us, Bitboard dc, Square ksq) { + inline MoveStack* generate_piece_checks(const Position& p, MoveStack* m, Color us, Bitboard dc, Square ksq) { return (us == WHITE ? generate_pawn_checks(p, dc, ksq, m) : generate_pawn_checks(p, dc, ksq, m)); } // Template generate_piece_moves() with specializations and overloads - template + template MoveStack* generate_piece_moves(const Position&, MoveStack*, Color us, Bitboard); template<> - MoveStack* generate_piece_moves(const Position&, MoveStack*, Color, Bitboard); + MoveStack* generate_piece_moves(const Position&, MoveStack*, Color, Bitboard); template inline MoveStack* generate_piece_moves(const Position& p, MoveStack* m, Color us) { @@ -113,12 +113,12 @@ namespace { : generate_pawn_noncaptures(p, m)); } - template + template MoveStack* generate_piece_moves(const Position&, MoveStack*, Color us, Bitboard, Bitboard); template<> - inline MoveStack* generate_piece_moves(const Position& p, MoveStack* m, - Color us, Bitboard t, Bitboard pnd) { + inline MoveStack* generate_piece_moves(const Position& p, MoveStack* m, + Color us, Bitboard t, Bitboard pnd) { return (us == WHITE ? generate_pawn_blocking_evasions(p, pnd, t, m) : generate_pawn_blocking_evasions(p, pnd, t, m)); @@ -133,7 +133,7 @@ namespace { /// generate_captures generates() all pseudo-legal captures and queen /// promotions. The return value is the number of moves generated. -template + int generate_captures(const Position& pos, MoveStack* mlist) { assert(pos.is_ok()); @@ -143,25 +143,19 @@ int generate_captures(const Position& pos, MoveStack* mlist) { Bitboard target = pos.pieces_of_color(opposite_color(us)); MoveStack* mlist_start = mlist; - mlist = generate_piece_moves(pos, mlist, us, target); - mlist = generate_piece_moves(pos, mlist, us, target); - mlist = generate_piece_moves(pos, mlist, us, target); - mlist = generate_piece_moves(pos, mlist, us, target); + mlist = generate_piece_moves(pos, mlist, us, target); + mlist = generate_piece_moves(pos, mlist, us, target); + mlist = generate_piece_moves(pos, mlist, us, target); + mlist = generate_piece_moves(pos, mlist, us, target); mlist = generate_piece_moves(pos, mlist, us); - mlist = generate_piece_moves(pos, mlist, us, target); + mlist = generate_piece_moves(pos, mlist, us, target); return int(mlist - mlist_start); } -int generate_captures(const Position& pos, MoveStack* mlist) { - - return CpuHasPOPCNT ? generate_captures(pos, mlist) - : generate_captures(pos, mlist); -} - /// generate_noncaptures() generates all pseudo-legal non-captures and /// underpromotions. The return value is the number of moves generated. -template + int generate_noncaptures(const Position& pos, MoveStack* mlist) { assert(pos.is_ok()); @@ -172,26 +166,20 @@ int generate_noncaptures(const Position& pos, MoveStack* mlist) { MoveStack* mlist_start = mlist; mlist = generate_piece_moves(pos, mlist, us); - mlist = generate_piece_moves(pos, mlist, us, target); - mlist = generate_piece_moves(pos, mlist, us, target); - mlist = generate_piece_moves(pos, mlist, us, target); - mlist = generate_piece_moves(pos, mlist, us, target); - mlist = generate_piece_moves(pos, mlist, us, target); + mlist = generate_piece_moves(pos, mlist, us, target); + mlist = generate_piece_moves(pos, mlist, us, target); + mlist = generate_piece_moves(pos, mlist, us, target); + mlist = generate_piece_moves(pos, mlist, us, target); + mlist = generate_piece_moves(pos, mlist, us, target); mlist = generate_castle_moves(pos, mlist); mlist = generate_castle_moves(pos, mlist); return int(mlist - mlist_start); } -int generate_noncaptures(const Position& pos, MoveStack* mlist) { - - return CpuHasPOPCNT ? generate_noncaptures(pos, mlist) - : generate_noncaptures(pos, mlist); -} - /// generate_non_capture_checks() generates all pseudo-legal non-capturing, /// non-promoting checks. It returns the number of generated moves. -template + int generate_non_capture_checks(const Position& pos, MoveStack* mlist, Bitboard dc) { assert(pos.is_ok()); @@ -204,12 +192,12 @@ int generate_non_capture_checks(const Position& pos, MoveStack* mlist, Bitboard assert(pos.piece_on(ksq) == piece_of_color_and_type(opposite_color(us), KING)); // Pieces moves - mlist = generate_piece_checks(pos, mlist, us, dc, ksq); - mlist = generate_piece_checks(pos, mlist, us, dc, ksq); - mlist = generate_piece_checks(pos, mlist, us, dc, ksq); - mlist = generate_piece_checks(pos, mlist, us, dc, ksq); - mlist = generate_piece_checks(pos, mlist, us, dc, ksq); - mlist = generate_piece_checks(pos, mlist, us, dc, ksq); + mlist = generate_piece_checks(pos, mlist, us, dc, ksq); + mlist = generate_piece_checks(pos, mlist, us, dc, ksq); + mlist = generate_piece_checks(pos, mlist, us, dc, ksq); + mlist = generate_piece_checks(pos, mlist, us, dc, ksq); + mlist = generate_piece_checks(pos, mlist, us, dc, ksq); + mlist = generate_piece_checks(pos, mlist, us, dc, ksq); // Castling moves that give check. Very rare but nice to have! if ( pos.can_castle_queenside(us) @@ -225,17 +213,11 @@ int generate_non_capture_checks(const Position& pos, MoveStack* mlist, Bitboard return int(mlist - mlist_start); } -int generate_non_capture_checks(const Position& pos, MoveStack* mlist, Bitboard dc) { - - return CpuHasPOPCNT ? generate_non_capture_checks(pos, mlist, dc) - : generate_non_capture_checks(pos, mlist, dc); -} - /// generate_evasions() generates all check evasions when the side to move is /// in check. Unlike the other move generation functions, this one generates /// only legal moves. It returns the number of generated moves. -template + int generate_evasions(const Position& pos, MoveStack* mlist, Bitboard pinned) { assert(pos.is_ok()); @@ -262,14 +244,14 @@ int generate_evasions(const Position& pos, MoveStack* mlist, Bitboard pinned) { Bitboard b = checkers & (pos.queens() | pos.bishops()); while (b) { - from = pop_1st_bit(&b); + from = pop_1st_bit(&b); checkersAttacks |= bishop_attacks_bb(from, b_noKing); } b = checkers & (pos.queens() | pos.rooks()); while (b) { - from = pop_1st_bit(&b); + from = pop_1st_bit(&b); checkersAttacks |= rook_attacks_bb(from, b_noKing); } @@ -277,7 +259,7 @@ int generate_evasions(const Position& pos, MoveStack* mlist, Bitboard pinned) { Bitboard b1 = pos.piece_attacks(ksq) & ~pos.pieces_of_color(us) & ~checkersAttacks; while (b1) { - to = pop_1st_bit(&b1); + to = pop_1st_bit(&b1); // Note that we can use square_is_attacked() only because we // have already removed slider checkers. if (!pos.square_is_attacked(to, them)) @@ -299,7 +281,7 @@ int generate_evasions(const Position& pos, MoveStack* mlist, Bitboard pinned) { b1 = pos.pawn_attacks(them, checksq) & pos.pawns(us) & ~pinned; while (b1) { - from = pop_1st_bit(&b1); + from = pop_1st_bit(&b1); if (relative_rank(us, checksq) == RANK_8) { (*mlist++).move = make_promotion_move(from, checksq, QUEEN); @@ -317,7 +299,7 @@ int generate_evasions(const Position& pos, MoveStack* mlist, Bitboard pinned) { while (b1) { - from = pop_1st_bit(&b1); + from = pop_1st_bit(&b1); (*mlist++).move = make_move(from, checksq); } @@ -331,11 +313,11 @@ int generate_evasions(const Position& pos, MoveStack* mlist, Bitboard pinned) { if (blockSquares != EmptyBoardBB) { - mlist = generate_piece_moves(pos, mlist, us, blockSquares, pinned); - mlist = generate_piece_moves(pos, mlist, us, blockSquares, pinned); - mlist = generate_piece_moves(pos, mlist, us, blockSquares, pinned); - mlist = generate_piece_moves(pos, mlist, us, blockSquares, pinned); - mlist = generate_piece_moves(pos, mlist, us, blockSquares, pinned); + mlist = generate_piece_moves(pos, mlist, us, blockSquares, pinned); + mlist = generate_piece_moves(pos, mlist, us, blockSquares, pinned); + mlist = generate_piece_moves(pos, mlist, us, blockSquares, pinned); + mlist = generate_piece_moves(pos, mlist, us, blockSquares, pinned); + mlist = generate_piece_moves(pos, mlist, us, blockSquares, pinned); } } @@ -357,7 +339,7 @@ int generate_evasions(const Position& pos, MoveStack* mlist, Bitboard pinned) { b1 &= ~pinned; while (b1) { - from = pop_1st_bit(&b1); + from = pop_1st_bit(&b1); // Move is always legal because checking pawn is not a discovered // check candidate and our capturing pawn has been already tested // against pinned pieces. @@ -368,12 +350,6 @@ int generate_evasions(const Position& pos, MoveStack* mlist, Bitboard pinned) { return int(mlist - mlist_start); } -int generate_evasions(const Position& pos, MoveStack* mlist, Bitboard pinned) { - - return CpuHasPOPCNT ? generate_evasions(pos, mlist, pinned) - : generate_evasions(pos, mlist, pinned); -} - /// generate_legal_moves() computes a complete list of legal moves in the /// current position. This function is not very fast, and should be used @@ -590,7 +566,7 @@ bool move_is_legal(const Position& pos, const Move m, Bitboard pinned) { namespace { - template + template MoveStack* generate_piece_moves(const Position& pos, MoveStack* mlist, Color us, Bitboard target) { Square from; @@ -600,12 +576,12 @@ namespace { { from = pos.piece_list(us, Piece, i); b = pos.piece_attacks(from) & target; - SERIALIZE_MOVES(b, HasBSF); + SERIALIZE_MOVES(b); } return mlist; } - template + template MoveStack* generate_piece_moves(const Position& pos, MoveStack* mlist, Color us, Bitboard target, Bitboard pinned) { Square from; @@ -618,19 +594,19 @@ namespace { continue; b = pos.piece_attacks(from) & target; - SERIALIZE_MOVES(b, HasBSF); + SERIALIZE_MOVES(b); } return mlist; } template<> - MoveStack* generate_piece_moves(const Position& pos, MoveStack* mlist, Color us, Bitboard target) { + MoveStack* generate_piece_moves(const Position& pos, MoveStack* mlist, Color us, Bitboard target) { Bitboard b; Square from = pos.king_square(us); b = pos.piece_attacks(from) & target; - SERIALIZE_MOVES(b, false); + SERIALIZE_MOVES(b); return mlist; } @@ -840,7 +816,7 @@ namespace { return mlist; } - template + template MoveStack* generate_piece_checks(const Position& pos, MoveStack* mlist, Color us, Bitboard dc, Square ksq) { @@ -850,12 +826,12 @@ namespace { Bitboard b = target & dc; while (b) { - Square from = pop_1st_bit(&b); + Square from = pop_1st_bit(&b); Bitboard bb = pos.piece_attacks(from) & pos.empty_squares(); if (Piece == KING) bb &= ~QueenPseudoAttacks[ksq]; - SERIALIZE_MOVES(bb, HasBSF); + SERIALIZE_MOVES(bb); } // Direct checks @@ -868,14 +844,14 @@ namespace { while (b) { - Square from = pop_1st_bit(&b); + Square from = pop_1st_bit(&b); if ( (Piece == QUEEN && !(QueenPseudoAttacks[from] & checkSqs)) || (Piece == ROOK && !(RookPseudoAttacks[from] & checkSqs)) || (Piece == BISHOP && !(BishopPseudoAttacks[from] & checkSqs))) continue; Bitboard bb = pos.piece_attacks(from) & checkSqs; - SERIALIZE_MOVES(bb, HasBSF); + SERIALIZE_MOVES(bb); } } return mlist;