mirror of
https://github.com/official-stockfish/Stockfish.git
synced 2026-07-22 12:47:08 +00:00
Hyperbola quintessence for ARM
Passed STC https://tests.stockfishchess.org/tests/view/69f44c1e1e5788938e86aa2a LLR: 2.93 (-2.94,2.94) <0.00,2.00> Total: 27680 W: 7340 L: 7053 D: 13287 Ptnml(0-2): 72, 2862, 7683, 3153, 70 x86 is unaffected Data from Joost's machine (Neoverse V2): ``` ==== master ==== ==== Bench: 2723949 ==== 1 Nodes/second : 276819933 2 Nodes/second : 273971948 3 Nodes/second : 275567995 Average (over 3): 275453292 ==== 5b54755db23a3de29407b805b85e7bbdef28df49 ==== ==== Bench: 2723949 ==== 1 Nodes/second : 282861542 2 Nodes/second : 279085277 3 Nodes/second : 279612223 Average (over 3): 280519680 (+1.8%) ``` Data from my M1 macbook ``` Result of 100 runs ================== base (./stockfish ) = 1474702 +/- 6169 test (...fish.rbit-pr) = 1500236 +/- 6690 diff = +25533 +/- 4011 speedup = +0.0173 P(speedup > 0) = 1.0000 ``` Hyperbola quintessence works nicely on ARM because it has an efficient bit reversal instruction `rbit`. This lets us avoid the large magic bitboards lookup table. Codegen looks nice (this is for rook attacks I think): ``` 0000000100001ecc <__ZN9Stockfish10attacks_bbILNS_9PieceTypeE3EEEyNS_6SquareEy>: 100001ecc: 2a0003e8 mov w8, w0 100001ed0: f002cb09 adrp x9, 0x105964000 <dyld_stub_binder+0x105964000> 100001ed4: 91200129 add x9, x9, #0x800 100001ed8: 8b081928 add x8, x9, x8, lsl #6 100001edc: a9402909 ldp x9, x10, [x8] 100001ee0: 8a01012b and x11, x9, x1 100001ee4: dac0016c rbit x12, x11 100001ee8: a941210d ldp x13, x8, [x8, #0x10] 100001eec: cb08018c sub x12, x12, x8 100001ef0: dac0018c rbit x12, x12 100001ef4: cb0d016b sub x11, x11, x13 100001ef8: ca0b018b eor x11, x12, x11 100001efc: 8a090169 and x9, x11, x9 100001f00: 8a01014b and x11, x10, x1 100001f04: dac0016c rbit x12, x11 100001f08: cb080188 sub x8, x12, x8 100001f0c: dac00108 rbit x8, x8 100001f10: cb0d016b sub x11, x11, x13 100001f14: ca0b0108 eor x8, x8, x11 100001f18: 8a0a0108 and x8, x8, x10 100001f1c: 8b090100 add x0, x8, x9 100001f20: d65f03c0 ret ``` closes https://github.com/official-stockfish/Stockfish/pull/6795 No functional change
This commit is contained in:
committed by
Joost VandeVondele
parent
fe1d2b456c
commit
dc1686345c
@@ -62,6 +62,39 @@ std::string Bitboards::pretty(Bitboard b) {
|
|||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef USE_HYPERBOLA_QUINT
|
||||||
|
static Bitboard line_mask(Square sq, Direction d1, Direction d2) {
|
||||||
|
Bitboard mask = 0, dest;
|
||||||
|
for (Direction d : {d1, d2})
|
||||||
|
{
|
||||||
|
Square s = sq;
|
||||||
|
while ((dest = Bitboards::safe_destination(s, d)))
|
||||||
|
{
|
||||||
|
mask |= dest;
|
||||||
|
s += d;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return mask;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void init_magics(Magic magics[][2]) {
|
||||||
|
for (Square s = SQ_A1; s <= SQ_H8; ++s)
|
||||||
|
{
|
||||||
|
Magic& rook = magics[s][ROOK - BISHOP];
|
||||||
|
rook.mask1 = line_mask(s, NORTH, SOUTH);
|
||||||
|
rook.mask2 = line_mask(s, EAST, WEST);
|
||||||
|
|
||||||
|
Magic& bishop = magics[s][BISHOP - BISHOP];
|
||||||
|
bishop.mask1 = line_mask(s, NORTH_EAST, SOUTH_WEST);
|
||||||
|
bishop.mask2 = line_mask(s, NORTH_WEST, SOUTH_EAST);
|
||||||
|
|
||||||
|
rook.r = bishop.r = square_bb(s) * 2;
|
||||||
|
rook.rr = bishop.rr = square_bb(Square(63 - int(s))) * 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
[[maybe_unused]] constexpr Bitboard constexpr_pext(Bitboard b, Bitboard m) {
|
[[maybe_unused]] constexpr Bitboard constexpr_pext(Bitboard b, Bitboard m) {
|
||||||
Bitboard result = 0, bit = 0;
|
Bitboard result = 0, bit = 0;
|
||||||
@@ -199,6 +232,7 @@ std::array<MagicMask, 0x1480> BishopTable;
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
// Initializes various bitboard tables. It is called at
|
// Initializes various bitboard tables. It is called at
|
||||||
// startup and relies on global objects to be already zero-initialized.
|
// startup and relies on global objects to be already zero-initialized.
|
||||||
@@ -211,8 +245,12 @@ void Bitboards::init() {
|
|||||||
for (Square s2 = SQ_A1; s2 <= SQ_H8; ++s2)
|
for (Square s2 = SQ_A1; s2 <= SQ_H8; ++s2)
|
||||||
SquareDistance[s1][s2] = std::max(distance<File>(s1, s2), distance<Rank>(s1, s2));
|
SquareDistance[s1][s2] = std::max(distance<File>(s1, s2), distance<Rank>(s1, s2));
|
||||||
|
|
||||||
|
#ifdef USE_HYPERBOLA_QUINT
|
||||||
|
init_magics(Magics);
|
||||||
|
#else
|
||||||
init_magics(ROOK, const_cast<MagicMask*>(RookTable.data()), Magics, true);
|
init_magics(ROOK, const_cast<MagicMask*>(RookTable.data()), Magics, true);
|
||||||
init_magics(BISHOP, const_cast<MagicMask*>(BishopTable.data()), Magics, true);
|
init_magics(BISHOP, const_cast<MagicMask*>(BishopTable.data()), Magics, true);
|
||||||
|
#endif
|
||||||
|
|
||||||
for (Square s1 = SQ_A1; s1 <= SQ_H8; ++s1)
|
for (Square s1 = SQ_A1; s1 <= SQ_H8; ++s1)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -31,6 +31,11 @@
|
|||||||
|
|
||||||
#include "types.h"
|
#include "types.h"
|
||||||
|
|
||||||
|
#ifdef __aarch64__
|
||||||
|
#include <arm_acle.h>
|
||||||
|
#define USE_HYPERBOLA_QUINT
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace Stockfish {
|
namespace Stockfish {
|
||||||
|
|
||||||
namespace Bitboards {
|
namespace Bitboards {
|
||||||
@@ -74,6 +79,28 @@ extern Bitboard BetweenBB[SQUARE_NB][SQUARE_NB];
|
|||||||
extern Bitboard LineBB[SQUARE_NB][SQUARE_NB];
|
extern Bitboard LineBB[SQUARE_NB][SQUARE_NB];
|
||||||
extern Bitboard RayPassBB[SQUARE_NB][SQUARE_NB];
|
extern Bitboard RayPassBB[SQUARE_NB][SQUARE_NB];
|
||||||
|
|
||||||
|
#ifdef USE_HYPERBOLA_QUINT
|
||||||
|
// Hyperbola quintessence implementation for ARM, thanks to the availability of an
|
||||||
|
// efficient bit reversal instruction.
|
||||||
|
// See https://www.chessprogramming.org/Hyperbola_Quintessence
|
||||||
|
struct Magic {
|
||||||
|
// For rooks: file attacks, rank attacks. For bishops: diagonal/antidiagonal
|
||||||
|
Bitboard mask1, mask2;
|
||||||
|
// Precomputed 2 * square_bb(sq), 2 * reverse(square_bb(sq))
|
||||||
|
Bitboard r, rr;
|
||||||
|
|
||||||
|
Bitboard hyperbola(Bitboard occupied, Bitboard mask) const {
|
||||||
|
Bitboard o = occupied & mask;
|
||||||
|
Bitboard fwd = o - r;
|
||||||
|
Bitboard rev = __rbitll(o) - rr;
|
||||||
|
return (fwd ^ __rbitll(rev)) & mask;
|
||||||
|
}
|
||||||
|
|
||||||
|
Bitboard attacks_bb(Bitboard occupied) const {
|
||||||
|
return hyperbola(occupied, mask1) | hyperbola(occupied, mask2);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
#else
|
||||||
// Magic holds all magic bitboards relevant data for a single square
|
// Magic holds all magic bitboards relevant data for a single square
|
||||||
struct Magic {
|
struct Magic {
|
||||||
Bitboard mask;
|
Bitboard mask;
|
||||||
@@ -109,6 +136,7 @@ struct Magic {
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
extern Magic Magics[SQUARE_NB][2];
|
extern Magic Magics[SQUARE_NB][2];
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user