mirror of
https://github.com/HChaZZY/Stockfish.git
synced 2025-12-06 10:53:50 +08:00
Compare commits
10 Commits
5337edfdb6
...
ce73441f20
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ce73441f20 | ||
|
|
e695b9537e | ||
|
|
ce7254b5ea | ||
|
|
ea85a54fef | ||
|
|
84e2f3851d | ||
|
|
3a0fff96cf | ||
|
|
318c948c4d | ||
|
|
a7a56c41f6 | ||
|
|
34b75f1575 | ||
|
|
15555e8f4a |
17
.github/workflows/tests.yml
vendored
17
.github/workflows/tests.yml
vendored
@@ -39,14 +39,15 @@ jobs:
|
|||||||
comp: ndk
|
comp: ndk
|
||||||
run_armv7_tests: true
|
run_armv7_tests: true
|
||||||
shell: bash
|
shell: bash
|
||||||
- name: Linux GCC riscv64
|
# Currently segfaults in the CI unrelated to a Stockfish change.
|
||||||
os: ubuntu-22.04
|
# - name: Linux GCC riscv64
|
||||||
compiler: g++
|
# os: ubuntu-22.04
|
||||||
comp: gcc
|
# compiler: g++
|
||||||
run_riscv64_tests: true
|
# comp: gcc
|
||||||
base_image: "riscv64/alpine:edge"
|
# run_riscv64_tests: true
|
||||||
platform: linux/riscv64
|
# base_image: "riscv64/alpine:edge"
|
||||||
shell: bash
|
# platform: linux/riscv64
|
||||||
|
# shell: bash
|
||||||
- name: Linux GCC ppc64
|
- name: Linux GCC ppc64
|
||||||
os: ubuntu-22.04
|
os: ubuntu-22.04
|
||||||
compiler: g++
|
compiler: g++
|
||||||
|
|||||||
@@ -701,7 +701,7 @@ endif
|
|||||||
ifeq ($(avx512),yes)
|
ifeq ($(avx512),yes)
|
||||||
CXXFLAGS += -DUSE_AVX512
|
CXXFLAGS += -DUSE_AVX512
|
||||||
ifeq ($(comp),$(filter $(comp),gcc clang mingw icx))
|
ifeq ($(comp),$(filter $(comp),gcc clang mingw icx))
|
||||||
CXXFLAGS += -mavx512f -mavx512bw
|
CXXFLAGS += -mavx512f -mavx512bw -mavx512dq -mavx512vl
|
||||||
endif
|
endif
|
||||||
endif
|
endif
|
||||||
|
|
||||||
@@ -996,10 +996,6 @@ net:
|
|||||||
format:
|
format:
|
||||||
$(CLANG-FORMAT) -i $(SRCS) $(HEADERS) -style=file
|
$(CLANG-FORMAT) -i $(SRCS) $(HEADERS) -style=file
|
||||||
|
|
||||||
# default target
|
|
||||||
default:
|
|
||||||
help
|
|
||||||
|
|
||||||
### ==========================================================================
|
### ==========================================================================
|
||||||
### Section 5. Private Targets
|
### Section 5. Private Targets
|
||||||
### ==========================================================================
|
### ==========================================================================
|
||||||
@@ -1125,6 +1121,6 @@ icx-profile-use:
|
|||||||
.depend: $(SRCS)
|
.depend: $(SRCS)
|
||||||
-@$(CXX) $(DEPENDFLAGS) -MM $(SRCS) > $@ 2> /dev/null
|
-@$(CXX) $(DEPENDFLAGS) -MM $(SRCS) > $@ 2> /dev/null
|
||||||
|
|
||||||
ifeq (, $(filter $(MAKECMDGOALS), help strip install clean net objclean profileclean config-sanity))
|
ifeq (, $(filter $(MAKECMDGOALS), help strip install clean net objclean profileclean format config-sanity))
|
||||||
-include .depend
|
-include .depend
|
||||||
endif
|
endif
|
||||||
|
|||||||
@@ -56,6 +56,7 @@ enum Stages {
|
|||||||
QCAPTURE
|
QCAPTURE
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
// Sort moves in descending order up to and including a given limit.
|
// Sort moves in descending order up to and including a given limit.
|
||||||
// The order of moves smaller than the limit is left unspecified.
|
// The order of moves smaller than the limit is left unspecified.
|
||||||
void partial_insertion_sort(ExtMove* begin, ExtMove* end, int limit) {
|
void partial_insertion_sort(ExtMove* begin, ExtMove* end, int limit) {
|
||||||
@@ -207,6 +208,7 @@ Move MovePicker::select(Pred filter) {
|
|||||||
// picking the move with the highest score from a list of generated moves.
|
// picking the move with the highest score from a list of generated moves.
|
||||||
Move MovePicker::next_move() {
|
Move MovePicker::next_move() {
|
||||||
|
|
||||||
|
constexpr int goodQuietThreshold = -14000;
|
||||||
top:
|
top:
|
||||||
switch (stage)
|
switch (stage)
|
||||||
{
|
{
|
||||||
@@ -222,7 +224,7 @@ top:
|
|||||||
case PROBCUT_INIT :
|
case PROBCUT_INIT :
|
||||||
case QCAPTURE_INIT :
|
case QCAPTURE_INIT :
|
||||||
cur = endBadCaptures = moves;
|
cur = endBadCaptures = moves;
|
||||||
endCur = generate<CAPTURES>(pos, cur);
|
endCur = endCaptures = generate<CAPTURES>(pos, cur);
|
||||||
|
|
||||||
score<CAPTURES>();
|
score<CAPTURES>();
|
||||||
partial_insertion_sort(cur, endCur, std::numeric_limits<int>::min());
|
partial_insertion_sort(cur, endCur, std::numeric_limits<int>::min());
|
||||||
@@ -244,8 +246,7 @@ top:
|
|||||||
case QUIET_INIT :
|
case QUIET_INIT :
|
||||||
if (!skipQuiets)
|
if (!skipQuiets)
|
||||||
{
|
{
|
||||||
cur = endBadQuiets = endBadCaptures;
|
endCur = endGenerated = generate<QUIETS>(pos, cur);
|
||||||
endCur = generate<QUIETS>(pos, cur);
|
|
||||||
|
|
||||||
score<QUIETS>();
|
score<QUIETS>();
|
||||||
partial_insertion_sort(cur, endCur, -3560 * depth);
|
partial_insertion_sort(cur, endCur, -3560 * depth);
|
||||||
@@ -255,12 +256,7 @@ top:
|
|||||||
[[fallthrough]];
|
[[fallthrough]];
|
||||||
|
|
||||||
case GOOD_QUIET :
|
case GOOD_QUIET :
|
||||||
if (!skipQuiets && select([&]() {
|
if (!skipQuiets && select([&]() { return cur->value > goodQuietThreshold; }))
|
||||||
if (cur->value > -14000)
|
|
||||||
return true;
|
|
||||||
*endBadQuiets++ = *cur;
|
|
||||||
return false;
|
|
||||||
}))
|
|
||||||
return *(cur - 1);
|
return *(cur - 1);
|
||||||
|
|
||||||
// Prepare the pointers to loop over the bad captures
|
// Prepare the pointers to loop over the bad captures
|
||||||
@@ -274,22 +270,22 @@ top:
|
|||||||
if (select([]() { return true; }))
|
if (select([]() { return true; }))
|
||||||
return *(cur - 1);
|
return *(cur - 1);
|
||||||
|
|
||||||
// Prepare the pointers to loop over the bad quiets
|
// Prepare the pointers to loop over quiets again
|
||||||
cur = endBadCaptures;
|
cur = endCaptures;
|
||||||
endCur = endBadQuiets;
|
endCur = endGenerated;
|
||||||
|
|
||||||
++stage;
|
++stage;
|
||||||
[[fallthrough]];
|
[[fallthrough]];
|
||||||
|
|
||||||
case BAD_QUIET :
|
case BAD_QUIET :
|
||||||
if (!skipQuiets)
|
if (!skipQuiets)
|
||||||
return select([]() { return true; });
|
return select([&]() { return cur->value <= goodQuietThreshold; });
|
||||||
|
|
||||||
return Move::none();
|
return Move::none();
|
||||||
|
|
||||||
case EVASION_INIT :
|
case EVASION_INIT :
|
||||||
cur = moves;
|
cur = moves;
|
||||||
endCur = generate<EVASIONS>(pos, cur);
|
endCur = endGenerated = generate<EVASIONS>(pos, cur);
|
||||||
|
|
||||||
score<EVASIONS>();
|
score<EVASIONS>();
|
||||||
partial_insertion_sort(cur, endCur, std::numeric_limits<int>::min());
|
partial_insertion_sort(cur, endCur, std::numeric_limits<int>::min());
|
||||||
@@ -315,7 +311,7 @@ bool MovePicker::can_move_king_or_pawn() const {
|
|||||||
// SEE negative captures shouldn't be returned in GOOD_CAPTURE stage
|
// SEE negative captures shouldn't be returned in GOOD_CAPTURE stage
|
||||||
assert(stage > GOOD_CAPTURE && stage != EVASION_INIT);
|
assert(stage > GOOD_CAPTURE && stage != EVASION_INIT);
|
||||||
|
|
||||||
for (const ExtMove* m = moves; m < endCur; ++m)
|
for (const ExtMove* m = moves; m < endGenerated; ++m)
|
||||||
{
|
{
|
||||||
PieceType movedPieceType = type_of(pos.moved_piece(*m));
|
PieceType movedPieceType = type_of(pos.moved_piece(*m));
|
||||||
if ((movedPieceType == PAWN || movedPieceType == KING) && pos.legal(*m))
|
if ((movedPieceType == PAWN || movedPieceType == KING) && pos.legal(*m))
|
||||||
|
|||||||
@@ -67,7 +67,7 @@ class MovePicker {
|
|||||||
const PieceToHistory** continuationHistory;
|
const PieceToHistory** continuationHistory;
|
||||||
const PawnHistory* pawnHistory;
|
const PawnHistory* pawnHistory;
|
||||||
Move ttMove;
|
Move ttMove;
|
||||||
ExtMove * cur, *endCur, *endBadCaptures, *endBadQuiets;
|
ExtMove * cur, *endCur, *endBadCaptures, *endCaptures, *endGenerated;
|
||||||
int stage;
|
int stage;
|
||||||
int threshold;
|
int threshold;
|
||||||
Depth depth;
|
Depth depth;
|
||||||
|
|||||||
@@ -68,9 +68,42 @@ alignas(CacheLineSize) static constexpr struct OffsetIndices {
|
|||||||
|
|
||||||
} Lookup;
|
} Lookup;
|
||||||
|
|
||||||
|
#if defined(__GNUC__) || defined(__clang__)
|
||||||
|
#define RESTRICT __restrict__
|
||||||
|
#elif defined(_MSC_VER)
|
||||||
|
#define RESTRICT __restrict
|
||||||
|
#else
|
||||||
|
#define RESTRICT
|
||||||
|
#endif
|
||||||
|
|
||||||
// Find indices of nonzero numbers in an int32_t array
|
// Find indices of nonzero numbers in an int32_t array
|
||||||
template<const IndexType InputDimensions>
|
template<const IndexType InputDimensions>
|
||||||
void find_nnz(const std::int32_t* input, std::uint16_t* out, IndexType& count_out) {
|
void find_nnz(const std::int32_t* RESTRICT input,
|
||||||
|
std::uint16_t* RESTRICT out,
|
||||||
|
IndexType& count_out) {
|
||||||
|
|
||||||
|
#ifdef USE_AVX512
|
||||||
|
constexpr IndexType SimdWidth = 16; // 512 bits / 32 bits
|
||||||
|
constexpr IndexType NumChunks = InputDimensions / SimdWidth;
|
||||||
|
const __m512i increment = _mm512_set1_epi32(SimdWidth);
|
||||||
|
__m512i base = _mm512_set_epi32(15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0);
|
||||||
|
|
||||||
|
IndexType count = 0;
|
||||||
|
for (IndexType i = 0; i < NumChunks; ++i)
|
||||||
|
{
|
||||||
|
const __m512i inputV = _mm512_load_si512(input + i * SimdWidth);
|
||||||
|
|
||||||
|
// Get a bitmask and gather non zero indices
|
||||||
|
const __mmask16 nnzMask = _mm512_test_epi32_mask(inputV, inputV);
|
||||||
|
const __m512i nnzV = _mm512_maskz_compress_epi32(nnzMask, base);
|
||||||
|
_mm512_mask_cvtepi32_storeu_epi16(out + count, 0xFFFF, nnzV);
|
||||||
|
count += popcount(nnzMask);
|
||||||
|
base = _mm512_add_epi32(base, increment);
|
||||||
|
}
|
||||||
|
count_out = count;
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
using namespace SIMD;
|
using namespace SIMD;
|
||||||
|
|
||||||
constexpr IndexType InputSimdWidth = sizeof(vec_uint_t) / sizeof(std::int32_t);
|
constexpr IndexType InputSimdWidth = sizeof(vec_uint_t) / sizeof(std::int32_t);
|
||||||
@@ -104,6 +137,7 @@ void find_nnz(const std::int32_t* input, std::uint16_t* out, IndexType& count_ou
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
count_out = count;
|
count_out = count;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -63,6 +63,9 @@ using namespace Search;
|
|||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
|
constexpr int SEARCHEDLIST_CAPACITY = 32;
|
||||||
|
using SearchedList = ValueList<Move, SEARCHEDLIST_CAPACITY>;
|
||||||
|
|
||||||
// (*Scalers):
|
// (*Scalers):
|
||||||
// The values with Scaler asterisks have proven non-linear scaling.
|
// The values with Scaler asterisks have proven non-linear scaling.
|
||||||
// They are optimized to time controls of 180 + 1.8 and longer,
|
// They are optimized to time controls of 180 + 1.8 and longer,
|
||||||
@@ -119,16 +122,16 @@ void update_pv(Move* pv, Move move, const Move* childPv);
|
|||||||
void update_continuation_histories(Stack* ss, Piece pc, Square to, int bonus);
|
void update_continuation_histories(Stack* ss, Piece pc, Square to, int bonus);
|
||||||
void update_quiet_histories(
|
void update_quiet_histories(
|
||||||
const Position& pos, Stack* ss, Search::Worker& workerThread, Move move, int bonus);
|
const Position& pos, Stack* ss, Search::Worker& workerThread, Move move, int bonus);
|
||||||
void update_all_stats(const Position& pos,
|
void update_all_stats(const Position& pos,
|
||||||
Stack* ss,
|
Stack* ss,
|
||||||
Search::Worker& workerThread,
|
Search::Worker& workerThread,
|
||||||
Move bestMove,
|
Move bestMove,
|
||||||
Square prevSq,
|
Square prevSq,
|
||||||
ValueList<Move, 32>& quietsSearched,
|
SearchedList& quietsSearched,
|
||||||
ValueList<Move, 32>& capturesSearched,
|
SearchedList& capturesSearched,
|
||||||
Depth depth,
|
Depth depth,
|
||||||
Move TTMove,
|
Move TTMove,
|
||||||
int moveCount);
|
int moveCount);
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
@@ -536,7 +539,6 @@ void Search::Worker::undo_null_move(Position& pos) { pos.undo_null_move(); }
|
|||||||
// Reset histories, usually before a new game
|
// Reset histories, usually before a new game
|
||||||
void Search::Worker::clear() {
|
void Search::Worker::clear() {
|
||||||
mainHistory.fill(67);
|
mainHistory.fill(67);
|
||||||
lowPlyHistory.fill(107);
|
|
||||||
captureHistory.fill(-688);
|
captureHistory.fill(-688);
|
||||||
pawnHistory.fill(-1287);
|
pawnHistory.fill(-1287);
|
||||||
pawnCorrectionHistory.fill(5);
|
pawnCorrectionHistory.fill(5);
|
||||||
@@ -606,8 +608,8 @@ Value Search::Worker::search(
|
|||||||
int priorReduction;
|
int priorReduction;
|
||||||
Piece movedPiece;
|
Piece movedPiece;
|
||||||
|
|
||||||
ValueList<Move, 32> capturesSearched;
|
SearchedList capturesSearched;
|
||||||
ValueList<Move, 32> quietsSearched;
|
SearchedList quietsSearched;
|
||||||
|
|
||||||
// Step 1. Initialize node
|
// Step 1. Initialize node
|
||||||
Worker* thisThread = this;
|
Worker* thisThread = this;
|
||||||
@@ -857,8 +859,8 @@ Value Search::Worker::search(
|
|||||||
{
|
{
|
||||||
assert(eval - beta >= 0);
|
assert(eval - beta >= 0);
|
||||||
|
|
||||||
// Null move dynamic reduction based on depth and eval
|
// Null move dynamic reduction based on depth
|
||||||
Depth R = std::min(int(eval - beta) / 213, 6) + depth / 3 + 5;
|
Depth R = 7 + depth / 3;
|
||||||
|
|
||||||
ss->currentMove = Move::null();
|
ss->currentMove = Move::null();
|
||||||
ss->continuationHistory = &thisThread->continuationHistory[0][0][NO_PIECE][0];
|
ss->continuationHistory = &thisThread->continuationHistory[0][0][NO_PIECE][0];
|
||||||
@@ -1083,7 +1085,7 @@ moves_loop: // When in check, search starts here
|
|||||||
|
|
||||||
lmrDepth += history / 3388;
|
lmrDepth += history / 3388;
|
||||||
|
|
||||||
Value baseFutility = (bestMove ? 46 : 138 + std::abs(history / 300));
|
Value baseFutility = (bestMove ? 46 : 230);
|
||||||
Value futilityValue =
|
Value futilityValue =
|
||||||
ss->staticEval + baseFutility + 117 * lmrDepth + 102 * (ss->staticEval > alpha);
|
ss->staticEval + baseFutility + 117 * lmrDepth + 102 * (ss->staticEval > alpha);
|
||||||
|
|
||||||
@@ -1207,8 +1209,7 @@ moves_loop: // When in check, search starts here
|
|||||||
if ((ss + 1)->cutoffCnt > 2)
|
if ((ss + 1)->cutoffCnt > 2)
|
||||||
r += 1036 + allNode * 848;
|
r += 1036 + allNode * 848;
|
||||||
|
|
||||||
if (!capture && !givesCheck && ss->quietMoveStreak >= 2)
|
r += (ss + 1)->quietMoveStreak * 50;
|
||||||
r += (ss->quietMoveStreak - 1) * 50;
|
|
||||||
|
|
||||||
// For first picked move (ttMove) reduce reduction
|
// For first picked move (ttMove) reduce reduction
|
||||||
if (move == ttData.move)
|
if (move == ttData.move)
|
||||||
@@ -1392,7 +1393,7 @@ moves_loop: // When in check, search starts here
|
|||||||
|
|
||||||
// If the move is worse than some previously searched move,
|
// If the move is worse than some previously searched move,
|
||||||
// remember it, to update its stats later.
|
// remember it, to update its stats later.
|
||||||
if (move != bestMove && moveCount <= 32)
|
if (move != bestMove && moveCount <= SEARCHEDLIST_CAPACITY)
|
||||||
{
|
{
|
||||||
if (capture)
|
if (capture)
|
||||||
capturesSearched.push_back(move);
|
capturesSearched.push_back(move);
|
||||||
@@ -1835,16 +1836,16 @@ void update_pv(Move* pv, Move move, const Move* childPv) {
|
|||||||
|
|
||||||
|
|
||||||
// Updates stats at the end of search() when a bestMove is found
|
// Updates stats at the end of search() when a bestMove is found
|
||||||
void update_all_stats(const Position& pos,
|
void update_all_stats(const Position& pos,
|
||||||
Stack* ss,
|
Stack* ss,
|
||||||
Search::Worker& workerThread,
|
Search::Worker& workerThread,
|
||||||
Move bestMove,
|
Move bestMove,
|
||||||
Square prevSq,
|
Square prevSq,
|
||||||
ValueList<Move, 32>& quietsSearched,
|
SearchedList& quietsSearched,
|
||||||
ValueList<Move, 32>& capturesSearched,
|
SearchedList& capturesSearched,
|
||||||
Depth depth,
|
Depth depth,
|
||||||
Move ttMove,
|
Move ttMove,
|
||||||
int moveCount) {
|
int moveCount) {
|
||||||
|
|
||||||
CapturePieceToHistory& captureHistory = workerThread.captureHistory;
|
CapturePieceToHistory& captureHistory = workerThread.captureHistory;
|
||||||
Piece movedPiece = pos.moved_piece(bestMove);
|
Piece movedPiece = pos.moved_piece(bestMove);
|
||||||
|
|||||||
@@ -85,16 +85,13 @@ void TimeManagement::init(Search::LimitsType& limits,
|
|||||||
// with constants are involved.
|
// with constants are involved.
|
||||||
const int64_t scaleFactor = useNodesTime ? npmsec : 1;
|
const int64_t scaleFactor = useNodesTime ? npmsec : 1;
|
||||||
const TimePoint scaledTime = limits.time[us] / scaleFactor;
|
const TimePoint scaledTime = limits.time[us] / scaleFactor;
|
||||||
const TimePoint scaledInc = limits.inc[us] / scaleFactor;
|
|
||||||
|
|
||||||
// Maximum move horizon
|
// Maximum move horizon
|
||||||
int centiMTG = limits.movestogo ? std::min(limits.movestogo * 100, 5000) : 5051;
|
int centiMTG = limits.movestogo ? std::min(limits.movestogo * 100, 5000) : 5051;
|
||||||
|
|
||||||
// If less than one second, gradually reduce mtg
|
// If less than one second, gradually reduce mtg
|
||||||
if (scaledTime < 1000 && double(centiMTG) / scaledInc > 5.051)
|
if (scaledTime < 1000)
|
||||||
{
|
|
||||||
centiMTG = scaledTime * 5.051;
|
centiMTG = scaledTime * 5.051;
|
||||||
}
|
|
||||||
|
|
||||||
// Make sure timeLeft is > 0 since we may use it as a divisor
|
// Make sure timeLeft is > 0 since we may use it as a divisor
|
||||||
TimePoint timeLeft =
|
TimePoint timeLeft =
|
||||||
|
|||||||
Reference in New Issue
Block a user