1
0
Fork 0
mirror of https://github.com/sockspls/badfish synced 2025-04-30 08:43:09 +00:00

Simplify popcnt

Also a speedup(about 1%) on 64-bit w/o hardware popcnt

Retire Max15 and Full template parameters
(Contributed by Marco Costalba)

Now that we have just SW and HW versions, use
template default parameter to get rid of explicit
template parameters.

Retire bitcount.h and move the only defined
function to bitboard.h

No functional change

Resolves #620
This commit is contained in:
mstembera 2016-04-08 18:52:15 +01:00 committed by Joona Kiiski
parent 900279a06f
commit 8fb45caade
8 changed files with 60 additions and 129 deletions

View file

@ -21,9 +21,9 @@
#include <algorithm>
#include "bitboard.h"
#include "bitcount.h"
#include "misc.h"
uint8_t PopCnt16[1 << 16];
int SquareDistance[SQUARE_NB][SQUARE_NB];
Bitboard RookMasks [SQUARE_NB];
@ -74,6 +74,16 @@ namespace {
return Is64Bit ? (b * DeBruijn64) >> 58
: ((unsigned(b) ^ unsigned(b >> 32)) * DeBruijn32) >> 26;
}
// popcount16() counts the non-zero bits using SWAR-Popcount algorithm
uint8_t popcount16(uint16_t u) {
u -= (u >> 1) & 0x5555U;
u = ((u >> 2) & 0x3333U) + (u & 0x3333U);
u = ((u >> 4) + u) & 0x0F0FU;
return (u * 0x0101U) >> 8;
}
}
#ifdef NO_BSF
@ -141,6 +151,9 @@ const std::string Bitboards::pretty(Bitboard b) {
void Bitboards::init() {
for (unsigned i = 0; i < (1 << 16); ++i)
PopCnt16[i] = popcount16(i);
for (Square s = SQ_A1; s <= SQ_H8; ++s)
{
SquareBB[s] = 1ULL << s;
@ -265,7 +278,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_attack(deltas, s, 0) & ~edges;
shifts[s] = (Is64Bit ? 64 : 32) - popcount<Max15>(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 attack bitboard in reference[].
@ -296,7 +309,7 @@ namespace {
do {
do
magics[s] = rng.sparse_rand<Bitboard>();
while (popcount<Max15>((magics[s] * masks[s]) >> 56) < 6);
while (popcount((magics[s] * masks[s]) >> 56) < 6);
// A good magic must map every possible occupancy to an index that
// looks up the correct sliding attack in the attacks[s] database.

View file

@ -257,6 +257,32 @@ inline Bitboard attacks_bb(Piece pc, Square s, Bitboard occupied) {
}
/// popcount() counts the number of non-zero bits in a bitboard
inline int popcount(Bitboard b) {
#ifndef USE_POPCNT
extern uint8_t PopCnt16[1 << 16];
union { Bitboard bb; uint16_t u[4]; } v = { b };
return PopCnt16[v.u[0]] + PopCnt16[v.u[1]] + PopCnt16[v.u[2]] + PopCnt16[v.u[3]];
#elif defined(_MSC_VER) && defined(__INTEL_COMPILER)
return _mm_popcnt_u64(b);
#elif defined(_MSC_VER)
return (int)__popcnt64(b);
#else // Assumed gcc or compatible compiler
return __builtin_popcountll(b);
#endif
}
/// lsb() and msb() return the least/most significant bit in a non-zero bitboard
#if defined(__GNUC__)

View file

@ -1,105 +0,0 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2008 Tord Romstad (Glaurung author)
Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad
Copyright (C) 2015-2016 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad
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 <http://www.gnu.org/licenses/>.
*/
#ifndef BITCOUNT_H_INCLUDED
#define BITCOUNT_H_INCLUDED
#include <cassert>
#include "types.h"
enum BitCountType {
CNT_64,
CNT_64_MAX15,
CNT_32,
CNT_32_MAX15,
CNT_HW_POPCNT
};
/// Determine at compile time the best popcount<> specialization according to
/// whether the platform is 32 or 64 bit, the maximum number of non-zero
/// bits to count and if the hardware popcnt instruction is 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 non-zero bits in a bitboard
template<BitCountType> inline int popcount(Bitboard);
template<>
inline int popcount<CNT_64>(Bitboard b) {
b -= (b >> 1) & 0x5555555555555555ULL;
b = ((b >> 2) & 0x3333333333333333ULL) + (b & 0x3333333333333333ULL);
b = ((b >> 4) + b) & 0x0F0F0F0F0F0F0F0FULL;
return (b * 0x0101010101010101ULL) >> 56;
}
template<>
inline int popcount<CNT_64_MAX15>(Bitboard b) {
b -= (b >> 1) & 0x5555555555555555ULL;
b = ((b >> 2) & 0x3333333333333333ULL) + (b & 0x3333333333333333ULL);
return (b * 0x1111111111111111ULL) >> 60;
}
template<>
inline int popcount<CNT_32>(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 + (w >> 4) + w) & 0x0F0F0F0F;
return (v * 0x01010101) >> 24;
}
template<>
inline int popcount<CNT_32_MAX15>(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);
return ((v + w) * 0x11111111) >> 28;
}
template<>
inline int popcount<CNT_HW_POPCNT>(Bitboard b) {
#ifndef USE_POPCNT
assert(false);
return 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);
#else // Assumed gcc or compatible compiler
return __builtin_popcountll(b);
#endif
}
#endif // #ifndef BITCOUNT_H_INCLUDED

View file

@ -22,7 +22,6 @@
#include <cassert>
#include "bitboard.h"
#include "bitcount.h"
#include "endgame.h"
#include "movegen.h"

View file

@ -24,7 +24,7 @@
#include <iomanip>
#include <sstream>
#include "bitcount.h"
#include "bitboard.h"
#include "evaluate.h"
#include "material.h"
#include "pawns.h"
@ -234,7 +234,7 @@ namespace {
{
ei.kingRing[Them] = b | shift_bb<Down>(b);
b &= ei.attackedBy[Us][PAWN];
ei.kingAttackersCount[Us] = b ? popcount<Max15>(b) : 0;
ei.kingAttackersCount[Us] = b ? popcount(b) : 0;
ei.kingAdjacentZoneAttacksCount[Us] = ei.kingAttackersWeight[Us] = 0;
}
else
@ -278,7 +278,7 @@ namespace {
ei.kingAttackersWeight[Us] += KingAttackWeights[Pt];
bb = b & ei.attackedBy[Them][KING];
if (bb)
ei.kingAdjacentZoneAttacksCount[Us] += popcount<Max15>(bb);
ei.kingAdjacentZoneAttacksCount[Us] += popcount(bb);
}
if (Pt == QUEEN)
@ -286,7 +286,7 @@ namespace {
| ei.attackedBy[Them][BISHOP]
| ei.attackedBy[Them][ROOK]);
int mob = popcount<Pt == QUEEN ? Full : Max15>(b & mobilityArea[Us]);
int mob = popcount(b & mobilityArea[Us]);
mobility[Us] += MobilityBonus[Pt][mob];
@ -334,7 +334,7 @@ namespace {
{
Bitboard alignedPawns = pos.pieces(Them, PAWN) & PseudoAttacks[ROOK][s];
if (alignedPawns)
score += RookOnPawn * popcount<Max15>(alignedPawns);
score += RookOnPawn * popcount(alignedPawns);
}
// Bonus when on an open or semi-open file
@ -399,7 +399,7 @@ namespace {
// the pawn shelter (current 'score' value).
attackUnits = std::min(72, ei.kingAttackersCount[Them] * ei.kingAttackersWeight[Them])
+ 9 * ei.kingAdjacentZoneAttacksCount[Them]
+ 27 * popcount<Max15>(undefended)
+ 27 * popcount(undefended)
+ 11 * !!ei.pinnedPieces[Us]
- 64 * !pos.count<QUEEN>(Them)
- mg_value(score) / 8;
@ -415,7 +415,7 @@ namespace {
| ei.attackedBy[Them][KING];
if (b)
attackUnits += QueenContactCheck * popcount<Max15>(b);
attackUnits += QueenContactCheck * popcount(b);
}
// Analyse the enemy's safe distance checks for sliders and knights
@ -513,7 +513,7 @@ namespace {
b = weak & ~ei.attackedBy[Them][ALL_PIECES];
if (b)
score += Hanging * popcount<Max15>(b);
score += Hanging * popcount(b);
b = weak & ei.attackedBy[Us][KING];
if (b)
@ -533,7 +533,7 @@ namespace {
& ~ei.attackedBy[Us][PAWN];
if (b)
score += ThreatByPawnPush * popcount<Max15>(b);
score += ThreatByPawnPush * popcount(b);
if (DoTrace)
Trace::add(THREAT, Us, score);
@ -656,7 +656,7 @@ namespace {
assert(unsigned(safe >> (Us == WHITE ? 32 : 0)) == 0);
// ...count safe + (behind & safe) with a single popcount
int bonus = popcount<Full>((Us == WHITE ? safe << 32 : safe >> 32) | (behind & safe));
int bonus = popcount((Us == WHITE ? safe << 32 : safe >> 32) | (behind & safe));
int weight = pos.count<KNIGHT>(Us) + pos.count<BISHOP>(Us)
+ pos.count<KNIGHT>(Them) + pos.count<BISHOP>(Them);

View file

@ -22,7 +22,6 @@
#include <cassert>
#include "bitboard.h"
#include "bitcount.h"
#include "pawns.h"
#include "position.h"
#include "thread.h"
@ -114,7 +113,7 @@ namespace {
e->kingSquares[Us] = SQ_NONE;
e->semiopenFiles[Us] = 0xFF;
e->pawnAttacks[Us] = shift_bb<Right>(ourPawns) | shift_bb<Left>(ourPawns);
e->pawnsOnSquares[Us][BLACK] = popcount<Max15>(ourPawns & DarkSquares);
e->pawnsOnSquares[Us][BLACK] = popcount(ourPawns & DarkSquares);
e->pawnsOnSquares[Us][WHITE] = pos.count<PAWN>(Us) - e->pawnsOnSquares[Us][BLACK];
// Loop through all pawns of the current color and score each pawn
@ -233,7 +232,7 @@ Entry* probe(const Position& pos) {
e->key = key;
e->score = evaluate<WHITE>(pos, e) - evaluate<BLACK>(pos, e);
e->asymmetry = popcount<Max15>(e->semiopenFiles[WHITE] ^ e->semiopenFiles[BLACK]);
e->asymmetry = popcount(e->semiopenFiles[WHITE] ^ e->semiopenFiles[BLACK]);
return e;
}

View file

@ -24,7 +24,7 @@
#include <iomanip>
#include <sstream>
#include "bitcount.h"
#include "bitboard.h"
#include "misc.h"
#include "movegen.h"
#include "position.h"
@ -1170,7 +1170,7 @@ bool Position::pos_is_ok(int* failedStep) const {
for (Color c = WHITE; c <= BLACK; ++c)
for (PieceType pt = PAWN; pt <= KING; ++pt)
{
if (pieceCount[c][pt] != popcount<Full>(pieces(c, pt)))
if (pieceCount[c][pt] != popcount(pieces(c, pt)))
return false;
for (int i = 0; i < pieceCount[c][pt]; ++i)

View file

@ -15,7 +15,6 @@
#include "../movegen.h"
#include "../bitboard.h"
#include "../search.h"
#include "../bitcount.h"
#include "tbprobe.h"
#include "tbcore.h"
@ -39,12 +38,12 @@ static void prt_str(Position& pos, char *str, int mirror)
color = !mirror ? WHITE : BLACK;
for (pt = KING; pt >= PAWN; --pt)
for (i = popcount<Max15>(pos.pieces(color, pt)); i > 0; i--)
for (i = popcount(pos.pieces(color, pt)); i > 0; i--)
*str++ = pchr[6 - pt];
*str++ = 'v';
color = ~color;
for (pt = KING; pt >= PAWN; --pt)
for (i = popcount<Max15>(pos.pieces(color, pt)); i > 0; i--)
for (i = popcount(pos.pieces(color, pt)); i > 0; i--)
*str++ = pchr[6 - pt];
*str++ = 0;
}
@ -60,11 +59,11 @@ static uint64 calc_key(Position& pos, int mirror)
color = !mirror ? WHITE : BLACK;
for (pt = PAWN; pt <= KING; ++pt)
for (i = popcount<Max15>(pos.pieces(color, pt)); i > 0; i--)
for (i = popcount(pos.pieces(color, pt)); i > 0; i--)
key ^= Zobrist::psq[WHITE][pt][i - 1];
color = ~color;
for (pt = PAWN; pt <= KING; ++pt)
for (i = popcount<Max15>(pos.pieces(color, pt)); i > 0; i--)
for (i = popcount(pos.pieces(color, pt)); i > 0; i--)
key ^= Zobrist::psq[BLACK][pt][i - 1];
return key;