From: Steinar H. Gunderson Date: Sun, 9 Apr 2023 09:25:35 +0000 (+0200) Subject: Merge remote-tracking branch 'upstream/master' X-Git-Url: https://git.sesse.net/?p=stockfish;a=commitdiff_plain;h=b8499fa7a5bb7ecb71f004bff92eda04b2e21924;hp=-c Merge remote-tracking branch 'upstream/master' --- b8499fa7a5bb7ecb71f004bff92eda04b2e21924 diff --combined src/Makefile index 171f966c,abcf11b0..e55d52e0 --- a/src/Makefile +++ b/src/Makefile @@@ -1,5 -1,5 +1,5 @@@ # Stockfish, a UCI chess playing engine derived from Glaurung 2.1 - # Copyright (C) 2004-2022 The Stockfish developers (see AUTHORS file) + # Copyright (C) 2004-2023 The Stockfish developers (see AUTHORS file) # # Stockfish is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@@ -59,12 -59,9 +59,12 @@@ endi SRCS = benchmark.cpp bitbase.cpp bitboard.cpp endgame.cpp evaluate.cpp main.cpp \ material.cpp misc.cpp movegen.cpp movepick.cpp pawns.cpp position.cpp psqt.cpp \ search.cpp thread.cpp timeman.cpp tt.cpp uci.cpp ucioption.cpp tune.cpp syzygy/tbprobe.cpp \ - nnue/evaluate_nnue.cpp nnue/features/half_ka_v2_hm.cpp + nnue/evaluate_nnue.cpp nnue/features/half_ka_v2_hm.cpp \ + hashprobe.grpc.pb.cc hashprobe.pb.cc +CLISRCS = client.cpp hashprobe.grpc.pb.cc hashprobe.pb.cc uci.cpp OBJS = $(notdir $(SRCS:.cpp=.o)) +CLIOBJS = $(notdir $(CLISRCS:.cpp=.o)) VPATH = syzygy:nnue:nnue/features @@@ -72,32 -69,33 +72,33 @@@ ### Section 2. High-level Configuration ### ========================================================================== # - # flag --- Comp switch --- Description + # flag --- Comp switch --- Description # ---------------------------------------------------------------------------- # - # debug = yes/no --- -DNDEBUG --- Enable/Disable debug mode + # debug = yes/no --- -DNDEBUG --- Enable/Disable debug mode # sanitize = none/ ... (-fsanitize ) - # --- ( undefined ) --- enable undefined behavior checks - # --- ( thread ) --- enable threading error checks - # --- ( address ) --- enable memory access checks - # --- ...etc... --- see compiler documentation for supported sanitizers - # optimize = yes/no --- (-O3/-fast etc.) --- Enable/Disable optimizations - # arch = (name) --- (-arch) --- Target architecture - # bits = 64/32 --- -DIS_64BIT --- 64-/32-bit operating system - # prefetch = yes/no --- -DUSE_PREFETCH --- Use prefetch asm-instruction - # popcnt = yes/no --- -DUSE_POPCNT --- Use popcnt asm-instruction - # pext = yes/no --- -DUSE_PEXT --- Use pext x86_64 asm-instruction - # sse = yes/no --- -msse --- Use Intel Streaming SIMD Extensions - # mmx = yes/no --- -mmmx --- Use Intel MMX instructions - # sse2 = yes/no --- -msse2 --- Use Intel Streaming SIMD Extensions 2 - # ssse3 = yes/no --- -mssse3 --- Use Intel Supplemental Streaming SIMD Extensions 3 - # sse41 = yes/no --- -msse4.1 --- Use Intel Streaming SIMD Extensions 4.1 - # avx2 = yes/no --- -mavx2 --- Use Intel Advanced Vector Extensions 2 - # avxvnni = yes/no --- -mavxvnni --- Use Intel Vector Neural Network Instructions AVX - # avx512 = yes/no --- -mavx512bw --- Use Intel Advanced Vector Extensions 512 - # vnni256 = yes/no --- -mavx512vnni --- Use Intel Vector Neural Network Instructions 256 - # vnni512 = yes/no --- -mavx512vnni --- Use Intel Vector Neural Network Instructions 512 - # neon = yes/no --- -DUSE_NEON --- Use ARM SIMD architecture + # --- ( undefined ) --- enable undefined behavior checks + # --- ( thread ) --- enable threading error checks + # --- ( address ) --- enable memory access checks + # --- ...etc... --- see compiler documentation for supported sanitizers + # optimize = yes/no --- (-O3/-fast etc.) --- Enable/Disable optimizations + # arch = (name) --- (-arch) --- Target architecture + # bits = 64/32 --- -DIS_64BIT --- 64-/32-bit operating system + # prefetch = yes/no --- -DUSE_PREFETCH --- Use prefetch asm-instruction + # popcnt = yes/no --- -DUSE_POPCNT --- Use popcnt asm-instruction + # pext = yes/no --- -DUSE_PEXT --- Use pext x86_64 asm-instruction + # sse = yes/no --- -msse --- Use Intel Streaming SIMD Extensions + # mmx = yes/no --- -mmmx --- Use Intel MMX instructions + # sse2 = yes/no --- -msse2 --- Use Intel Streaming SIMD Extensions 2 + # ssse3 = yes/no --- -mssse3 --- Use Intel Supplemental Streaming SIMD Extensions 3 + # sse41 = yes/no --- -msse4.1 --- Use Intel Streaming SIMD Extensions 4.1 + # avx2 = yes/no --- -mavx2 --- Use Intel Advanced Vector Extensions 2 + # avxvnni = yes/no --- -mavxvnni --- Use Intel Vector Neural Network Instructions AVX + # avx512 = yes/no --- -mavx512bw --- Use Intel Advanced Vector Extensions 512 + # vnni256 = yes/no --- -mavx256vnni --- Use Intel Vector Neural Network Instructions 512 with 256bit operands + # vnni512 = yes/no --- -mavx512vnni --- Use Intel Vector Neural Network Instructions 512 + # neon = yes/no --- -DUSE_NEON --- Use ARM SIMD architecture + # dotprod = yes/no --- -DUSE_NEON_DOTPROD --- Use ARM advanced SIMD Int8 dot product instructions # # Note that Makefile is space sensitive, so when adding new architectures # or modifying existing flags, you have to make sure there are no extra spaces @@@ -119,7 -117,7 +120,7 @@@ ifeq ($(ARCH), $(filter $(ARCH), x86-64-vnni512 x86-64-vnni256 x86-64-avx512 x86-64-avxvnni x86-64-bmi2 \ x86-64-avx2 x86-64-sse41-popcnt x86-64-modern x86-64-ssse3 x86-64-sse3-popcnt \ x86-64 x86-32-sse41-popcnt x86-32-sse2 x86-32 ppc-64 ppc-32 e2k \ - armv7 armv7-neon armv8 apple-silicon general-64 general-32 riscv64)) + armv7 armv7-neon armv8 armv8-dotprod apple-silicon general-64 general-32 riscv64)) SUPPORTED_ARCH=true else SUPPORTED_ARCH=false @@@ -143,6 -141,7 +144,7 @@@ avx512 = n vnni256 = no vnni512 = no neon = no + dotprod = no arm_version = 0 STRIP = strip @@@ -311,11 -310,21 +313,21 @@@ ifeq ($(ARCH),armv8 arm_version = 8 endif + ifeq ($(ARCH),armv8-dotprod) + arch = armv8 + prefetch = yes + popcnt = yes + neon = yes + dotprod = yes + arm_version = 8 + endif + ifeq ($(ARCH),apple-silicon) arch = arm64 prefetch = yes popcnt = yes neon = yes + dotprod = yes arm_version = 8 endif @@@ -369,7 -378,7 +381,7 @@@ endi ifeq ($(COMP),gcc) comp=gcc CXX=g++ - CXXFLAGS += -pedantic -Wextra - CXXFLAGS += -pedantic -Wextra -Wshadow -Wmissing-declarations ++ CXXFLAGS += -pedantic -Wextra -Wmissing-declarations ifeq ($(arch),$(filter $(arch),armv7 armv8 riscv64)) ifeq ($(OS),Android) @@@ -413,13 -422,14 +425,14 @@@ ifeq ($(COMP),mingw CXX=i686-w64-mingw32-c++-posix endif endif - CXXFLAGS += -pedantic -Wextra -Wshadow + CXXFLAGS += -pedantic -Wextra -Wshadow -Wmissing-declarations endif - ifeq ($(COMP),icc) - comp=icc - CXX=icpc - CXXFLAGS += -diag-disable 1476,10120 -Wcheck -Wabi -Wdeprecated -strict-ansi + ifeq ($(COMP),icx) + comp=icx + CXX=icpx + CXXFLAGS += --intel -pedantic -Wextra -Wshadow -Wmissing-prototypes \ + -Wconditional-uninitialized -Wabi -Wdeprecated endif ifeq ($(COMP),clang) @@@ -429,7 -439,8 +442,8 @@@ CXX=x86_64-w64-mingw32-clang++ endif - CXXFLAGS += -pedantic -Wextra -Wshadow + CXXFLAGS += -pedantic -Wextra -Wshadow -Wmissing-prototypes \ + -Wconditional-uninitialized ifeq ($(filter $(KERNEL),Darwin OpenBSD FreeBSD),) ifeq ($(target_windows),) @@@ -489,9 -500,9 +503,9 @@@ ifeq ($(COMP),ndk LDFLAGS += -static-libstdc++ -pie -lm -latomic endif - ifeq ($(comp),icc) - profile_make = icc-profile-make - profile_use = icc-profile-use + ifeq ($(comp),icx) + profile_make = icx-profile-make + profile_use = icx-profile-use else ifeq ($(comp),clang) profile_make = clang-profile-make profile_use = clang-profile-use @@@ -553,7 -564,7 +567,7 @@@ endi ### 3.3 Optimization ifeq ($(optimize),yes) - CXXFLAGS += -O3 + CXXFLAGS += -O3 -g ifeq ($(comp),gcc) ifeq ($(OS), Android) @@@ -562,7 -573,7 +576,7 @@@ endif ifeq ($(KERNEL),Darwin) - ifeq ($(comp),$(filter $(comp),clang icc)) + ifeq ($(comp),$(filter $(comp),clang icx)) CXXFLAGS += -mdynamic-no-pic endif @@@ -574,7 -585,10 +588,10 @@@ endif ifeq ($(comp),clang) - CXXFLAGS += -fexperimental-new-pass-manager + clangmajorversion = $(shell $(CXX) -dumpversion 2>/dev/null | cut -f1 -d.) + ifeq ($(shell expr $(clangmajorversion) \< 16),1) + CXXFLAGS += -fexperimental-new-pass-manager + endif endif endif @@@ -595,8 -609,6 +612,6 @@@ endi ifeq ($(popcnt),yes) ifeq ($(arch),$(filter $(arch),ppc64 armv7 armv8 arm64)) CXXFLAGS += -DUSE_POPCNT - else ifeq ($(comp),icc) - CXXFLAGS += -msse3 -DUSE_POPCNT else CXXFLAGS += -msse3 -mpopcnt -DUSE_POPCNT endif @@@ -605,63 -617,63 +620,63 @@@ endi ### 3.6 SIMD architectures ifeq ($(avx2),yes) CXXFLAGS += -DUSE_AVX2 - ifeq ($(comp),$(filter $(comp),gcc clang mingw)) + ifeq ($(comp),$(filter $(comp),gcc clang mingw icx)) CXXFLAGS += -mavx2 -mbmi endif endif ifeq ($(avxvnni),yes) CXXFLAGS += -DUSE_VNNI -DUSE_AVXVNNI - ifeq ($(comp),$(filter $(comp),gcc clang mingw)) + ifeq ($(comp),$(filter $(comp),gcc clang mingw icx)) CXXFLAGS += -mavxvnni endif endif ifeq ($(avx512),yes) CXXFLAGS += -DUSE_AVX512 - ifeq ($(comp),$(filter $(comp),gcc clang mingw)) + ifeq ($(comp),$(filter $(comp),gcc clang mingw icx)) CXXFLAGS += -mavx512f -mavx512bw endif endif ifeq ($(vnni256),yes) CXXFLAGS += -DUSE_VNNI - ifeq ($(comp),$(filter $(comp),gcc clang mingw)) + ifeq ($(comp),$(filter $(comp),gcc clang mingw icx)) CXXFLAGS += -mavx512f -mavx512bw -mavx512vnni -mavx512dq -mavx512vl -mprefer-vector-width=256 endif endif ifeq ($(vnni512),yes) CXXFLAGS += -DUSE_VNNI - ifeq ($(comp),$(filter $(comp),gcc clang mingw)) - CXXFLAGS += -mavx512vnni -mavx512dq -mavx512vl + ifeq ($(comp),$(filter $(comp),gcc clang mingw icx)) + CXXFLAGS += -mavx512f -mavx512bw -mavx512vnni -mavx512dq -mavx512vl -mprefer-vector-width=512 endif endif ifeq ($(sse41),yes) CXXFLAGS += -DUSE_SSE41 - ifeq ($(comp),$(filter $(comp),gcc clang mingw)) + ifeq ($(comp),$(filter $(comp),gcc clang mingw icx)) CXXFLAGS += -msse4.1 endif endif ifeq ($(ssse3),yes) CXXFLAGS += -DUSE_SSSE3 - ifeq ($(comp),$(filter $(comp),gcc clang mingw)) + ifeq ($(comp),$(filter $(comp),gcc clang mingw icx)) CXXFLAGS += -mssse3 endif endif ifeq ($(sse2),yes) CXXFLAGS += -DUSE_SSE2 - ifeq ($(comp),$(filter $(comp),gcc clang mingw)) + ifeq ($(comp),$(filter $(comp),gcc clang mingw icx)) CXXFLAGS += -msse2 endif endif ifeq ($(mmx),yes) CXXFLAGS += -DUSE_MMX - ifeq ($(comp),$(filter $(comp),gcc clang mingw)) + ifeq ($(comp),$(filter $(comp),gcc clang mingw icx)) CXXFLAGS += -mmmx endif endif @@@ -677,10 -689,14 +692,14 @@@ ifeq ($(neon),yes endif endif + ifeq ($(dotprod),yes) + CXXFLAGS += -march=armv8.2-a+dotprod -DUSE_NEON_DOTPROD + endif + ### 3.7 pext ifeq ($(pext),yes) CXXFLAGS += -DUSE_PEXT - ifeq ($(comp),$(filter $(comp),gcc clang mingw)) + ifeq ($(comp),$(filter $(comp),gcc clang mingw icx)) CXXFLAGS += -mbmi2 endif endif @@@ -688,13 -704,13 +707,13 @@@ ### 3.7.1 Try to include git commit sha for versioning GIT_SHA = $(shell git rev-parse --short HEAD 2>/dev/null) ifneq ($(GIT_SHA), ) - CXXFLAGS += -DGIT_SHA=\"$(GIT_SHA)\" + CXXFLAGS += -DGIT_SHA=$(GIT_SHA) endif ### 3.7.2 Try to include git commit date for versioning GIT_DATE = $(shell git show -s --date=format:'%Y%m%d' --format=%cd HEAD 2>/dev/null) ifneq ($(GIT_DATE), ) - CXXFLAGS += -DGIT_DATE=\"$(GIT_DATE)\" + CXXFLAGS += -DGIT_DATE=$(GIT_DATE) endif ### 3.8 Link Time Optimization @@@ -702,8 -718,11 +721,11 @@@ ### needs access to the optimization flags. ifeq ($(optimize),yes) ifeq ($(debug), no) - ifeq ($(comp),clang) + ifeq ($(comp),$(filter $(comp),clang icx)) CXXFLAGS += -flto=full + ifeq ($(comp),icx) + CXXFLAGS += -fwhole-program-vtables + endif ifeq ($(target_windows),yes) CXXFLAGS += -fuse-ld=lld endif @@@ -759,10 -778,10 +781,10 @@@ help @echo "" @echo "Supported archs:" @echo "" - @echo "x86-64-vnni512 > x86 64-bit with vnni support 512bit wide" - @echo "x86-64-vnni256 > x86 64-bit with vnni support 256bit wide" + @echo "x86-64-vnni512 > x86 64-bit with vnni 512bit support" + @echo "x86-64-vnni256 > x86 64-bit with vnni 512bit support, limit operands to 256bit wide" @echo "x86-64-avx512 > x86 64-bit with avx512 support" - @echo "x86-64-avxvnni > x86 64-bit with avxvnni support" + @echo "x86-64-avxvnni > x86 64-bit with vnni 256bit support" @echo "x86-64-bmi2 > x86 64-bit with bmi2 support" @echo "x86-64-avx2 > x86 64-bit with avx2 support" @echo "x86-64-sse41-popcnt > x86 64-bit with sse41 and popcnt support" @@@ -778,6 -797,7 +800,7 @@@ @echo "armv7 > ARMv7 32-bit" @echo "armv7-neon > ARMv7 32-bit with popcnt and neon" @echo "armv8 > ARMv8 64-bit with popcnt and neon" + @echo "armv8-dotprod > ARMv8 64-bit with popcnt, neon and dot product support" @echo "e2k > Elbrus 2000" @echo "apple-silicon > Apple silicon ARM64" @echo "general-64 > unspecified 64-bit" @@@ -789,7 -809,7 +812,7 @@@ @echo "gcc > Gnu compiler (default)" @echo "mingw > Gnu compiler with MinGW under Windows" @echo "clang > LLVM Clang compiler" - @echo "icc > Intel compiler" + @echo "icx > Intel oneAPI DPC++/C++ Compiler" @echo "ndk > Google NDK to cross-compile for Android" @echo "" @echo "Simple examples. If you don't know what to do, you likely want to run one of: " @@@ -815,8 -835,10 +838,10 @@@ endi .PHONY: help build profile-build strip install clean net objclean profileclean \ - config-sanity icc-profile-use icc-profile-make gcc-profile-use gcc-profile-make \ - clang-profile-use clang-profile-make FORCE + config-sanity \ + icx-profile-use icx-profile-make \ + gcc-profile-use gcc-profile-make \ + clang-profile-use clang-profile-make FORCE build: net config-sanity $(MAKE) ARCH=$(ARCH) COMP=$(COMP) all @@@ -905,7 -927,7 +930,7 @@@ default ### Section 5. Private Targets ### ========================================================================== -all: $(EXE) .depend +all: $(EXE) client .depend config-sanity: net @echo "" @@@ -931,7 -953,9 +956,9 @@@ @echo "vnni256: '$(vnni256)'" @echo "vnni512: '$(vnni512)'" @echo "neon: '$(neon)'" + @echo "dotprod: '$(dotprod)'" @echo "arm_version: '$(arm_version)'" + @echo "target_windows: '$(target_windows)'" @echo "" @echo "Flags:" @echo "CXX: $(CXX)" @@@ -960,7 -984,7 +987,7 @@@ @test "$(vnni256)" = "yes" || test "$(vnni256)" = "no" @test "$(vnni512)" = "yes" || test "$(vnni512)" = "no" @test "$(neon)" = "yes" || test "$(neon)" = "no" - @test "$(comp)" = "gcc" || test "$(comp)" = "icc" || test "$(comp)" = "mingw" || test "$(comp)" = "clang" \ + @test "$(comp)" = "gcc" || test "$(comp)" = "icx" || test "$(comp)" = "mingw" || test "$(comp)" = "clang" \ || test "$(comp)" = "armv7a-linux-androideabi16-clang" || test "$(comp)" = "aarch64-linux-android21-clang" $(EXE): $(OBJS) @@@ -998,43 -1022,19 +1025,45 @@@ gcc-profile-use EXTRALDFLAGS='-lgcov' \ all - icc-profile-make: - @mkdir -p profdir + icx-profile-make: $(MAKE) ARCH=$(ARCH) COMP=$(COMP) \ - EXTRACXXFLAGS='-prof-gen=srcpos -prof_dir ./profdir' \ + EXTRACXXFLAGS='-fprofile-instr-generate ' \ + EXTRALDFLAGS=' -fprofile-instr-generate' \ all - icc-profile-use: + icx-profile-use: + $(XCRUN) llvm-profdata merge -output=stockfish.profdata *.profraw $(MAKE) ARCH=$(ARCH) COMP=$(COMP) \ - EXTRACXXFLAGS='-prof_use -prof_dir ./profdir' \ + EXTRACXXFLAGS='-fprofile-instr-use=stockfish.profdata' \ + EXTRALDFLAGS='-fprofile-use ' \ all +### GRPC + +PROTOS_PATH = . +PROTOC = protoc +GRPC_CPP_PLUGIN = grpc_cpp_plugin +GRPC_CPP_PLUGIN_PATH ?= `which $(GRPC_CPP_PLUGIN)` + +%.grpc.pb.h %.grpc.pb.cc: %.proto + $(PROTOC) -I $(PROTOS_PATH) --grpc_out=. --plugin=protoc-gen-grpc=$(GRPC_CPP_PLUGIN_PATH) $< + +# oh my +%.cpp: %.cc + cp $< $@ + +%.pb.h %.pb.cc: %.proto + $(PROTOC) -I $(PROTOS_PATH) --cpp_out=. $< + +#LDFLAGS += -Wl,-Bstatic -Wl,-\( -lprotobuf -lgrpc++_unsecure -lgrpc_unsecure -lgrpc -lz -Wl,-\) -Wl,-Bdynamic -ldl +LDFLAGS += /usr/lib/x86_64-linux-gnu/libprotobuf.a /usr/lib/x86_64-linux-gnu/libgrpc++_unsecure.a /usr/lib/x86_64-linux-gnu/libgrpc_unsecure.a /usr/lib/x86_64-linux-gnu/libgrpc.a /usr/lib/x86_64-linux-gnu/libcares.a /usr/lib/x86_64-linux-gnu/libgpr.a /usr/lib/x86_64-linux-gnu/libabsl_str_format_internal.a /usr/lib/x86_64-linux-gnu/libabsl_strings.a /usr/lib/x86_64-linux-gnu/libabsl_flags_marshalling.a /usr/lib/x86_64-linux-gnu/libabsl_throw_delegate.a /usr/lib/x86_64-linux-gnu/libabsl_raw_logging_internal.a /usr/lib/x86_64-linux-gnu/libabsl_base.a /usr/lib/x86_64-linux-gnu/libabsl_int128.a /usr/lib/x86_64-linux-gnu/libabsl_bad_optional_access.a -ldl -lz +#LDFLAGS += /usr/lib/x86_64-linux-gnu/libprotobuf.a /usr/lib/libgrpc++_unsecure.a /usr/lib/libgrpc_unsecure.a /usr/lib/libgrpc.a /usr/lib/x86_64-linux-gnu/libcares.a -ldl -lz + +client: $(CLIOBJS) + $(CXX) -o $@ $(CLIOBJS) $(LDFLAGS) + +# Other stuff + .depend: $(SRCS) -@$(CXX) $(DEPENDFLAGS) -MM $(SRCS) > $@ 2> /dev/null diff --combined src/main.cpp index 435e436c,c40e0fa3..557c8c27 --- a/src/main.cpp +++ b/src/main.cpp @@@ -1,6 -1,6 +1,6 @@@ /* Stockfish, a UCI chess playing engine derived from Glaurung 2.1 - Copyright (C) 2004-2022 The Stockfish developers (see AUTHORS file) + Copyright (C) 2004-2023 The Stockfish developers (see AUTHORS file) Stockfish is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@@ -16,10 -16,7 +16,10 @@@ along with this program. If not, see . */ +#include #include +#include +#include #include "bitboard.h" #include "endgame.h" @@@ -31,203 -28,8 +31,203 @@@ #include "tt.h" #include "uci.h" +#include +#include +#include +#include "hashprobe.h" +#include "hashprobe.grpc.pb.h" +#include "tt.h" + +using grpc::Server; +using grpc::ServerBuilder; +using grpc::ServerContext; +using grpc::Status; +using grpc::StatusCode; +using namespace hashprobe; using namespace Stockfish; +Status HashProbeImpl::Probe(ServerContext* context, + const HashProbeRequest* request, + HashProbeResponse *response) { + Position pos; + StateInfo st; + pos.set(request->fen(), /*isChess960=*/false, &st, Threads.main()); + if (!pos.pos_is_ok()) { + return Status(StatusCode::INVALID_ARGUMENT, "Invalid FEN"); + } + + bool invert = (pos.side_to_move() == BLACK); + StateListPtr setup_states = StateListPtr(new std::deque(1)); + + ProbeMove(&pos, setup_states.get(), invert, response->mutable_root()); + + MoveList moves(pos); + for (const ExtMove* em = moves.begin(); em != moves.end(); ++em) { + HashProbeLine *line = response->add_line(); + FillMove(&pos, em->move, line->mutable_move()); + setup_states->push_back(StateInfo()); + pos.do_move(em->move, setup_states->back()); + ProbeMove(&pos, setup_states.get(), !invert, line); + pos.undo_move(em->move); + } + + return Status::OK; +} + +void HashProbeImpl::FillMove(Position *pos, Move move, HashProbeMove* decoded) { + if (!is_ok(move)) return; + + Square from = from_sq(move); + Square to = to_sq(move); + + if (type_of(move) == CASTLING) { + to = make_square(to > from ? FILE_G : FILE_C, rank_of(from)); + } + + Piece moved_piece = pos->moved_piece(move); + std::string pretty; + if (type_of(move) == CASTLING) { + if (to > from) { + pretty = "O-O"; + } else { + pretty = "O-O-O"; + } + } else if (type_of(moved_piece) == PAWN) { + if (type_of(move) == EN_PASSANT || pos->piece_on(to) != NO_PIECE) { + // Capture. + pretty = char('a' + file_of(from)); + pretty += "x"; + } + pretty += UCI::square(to); + if (type_of(move) == PROMOTION) { + pretty += "="; + pretty += " PNBRQK"[promotion_type(move)]; + } + } else { + pretty = " PNBRQK"[type_of(moved_piece)]; + Bitboard attackers = pos->attackers_to(to) & pos->pieces(color_of(moved_piece), type_of(moved_piece)); + if (more_than_one(attackers)) { + // Remove all illegal moves to disambiguate. + Bitboard att_copy = attackers; + while (att_copy) { + Square s = pop_lsb(att_copy); + Move m = make_move(s, to); + if (!pos->pseudo_legal(m) || !pos->legal(m)) { - attackers &= ~SquareBB[s]; ++ attackers &= ~square_bb(s); + } + } + } + if (more_than_one(attackers)) { + // Disambiguate by file if possible. + Bitboard attackers_this_file = attackers & file_bb(file_of(from)); + if (attackers != attackers_this_file) { + pretty += char('a' + file_of(from)); + attackers = attackers_this_file; + } + if (more_than_one(attackers)) { + // Still ambiguous, so need to disambiguate by rank. + pretty += char('1' + rank_of(from)); + } + } + + if (type_of(move) == EN_PASSANT || pos->piece_on(to) != NO_PIECE) { + pretty += "x"; + } + + pretty += UCI::square(to); + } + + if (pos->gives_check(move)) { + // Check if mate. + StateInfo si; + pos->do_move(move, si, true); + if (MoveList(*pos).size() > 0) { + pretty += "+"; + } else { + pretty += "#"; + } + pos->undo_move(move); + } + + decoded->set_pretty(pretty); +} + +void HashProbeImpl::ProbeMove(Position* pos, std::deque* setup_states, bool invert, HashProbeLine* response) { + bool found; + TTEntry *entry = TT.probe(pos->key(), found); + response->set_found(found); + if (found) { + TTEntry entry_copy = *entry; + Value value = entry_copy.value(); + Value eval = entry_copy.eval(); + Bound bound = entry_copy.bound(); + + if (invert) { + value = -value; + eval = -eval; + if (bound == BOUND_UPPER) { + bound = BOUND_LOWER; + } else if (bound == BOUND_LOWER) { + bound = BOUND_UPPER; + } + } + + response->set_depth(entry_copy.depth()); + FillValue(eval, response->mutable_eval()); + if (entry_copy.depth() > DEPTH_NONE) { + FillValue(value, response->mutable_value()); + } + response->set_bound(HashProbeLine::ValueBound(bound)); + + // Follow the PV until we hit an illegal move. + std::stack pv; + std::set seen; + while (is_ok(entry_copy.move()) && + pos->pseudo_legal(entry_copy.move()) && + pos->legal(entry_copy.move())) { + FillMove(pos, entry_copy.move(), response->add_pv()); + if (seen.count(pos->key())) break; + pv.push(entry_copy.move()); + seen.insert(pos->key()); + setup_states->push_back(StateInfo()); + pos->do_move(entry_copy.move(), setup_states->back()); + entry = TT.probe(pos->key(), found); + if (!found) { + break; + } + entry_copy = *entry; + } + + // Unroll the PV back again, so the Position object remains unchanged. + while (!pv.empty()) { + pos->undo_move(pv.top()); + pv.pop(); + } + } +} + +void HashProbeImpl::FillValue(Value value, HashProbeScore* score) { + if (abs(value) < VALUE_MATE - MAX_PLY) { + score->set_score_type(HashProbeScore::SCORE_CP); + score->set_score_cp(value * 100 / PawnValueEg); + } else { + score->set_score_type(HashProbeScore::SCORE_MATE); + score->set_score_mate((value > 0 ? VALUE_MATE - value + 1 : -VALUE_MATE - value) / 2); + } +} + +HashProbeThread::HashProbeThread(const std::string &server_address) { + builder.AddListeningPort(server_address, grpc::InsecureServerCredentials()); + builder.RegisterService(&service); + server = std::move(builder.BuildAndStart()); + std::cout << "Server listening on " << server_address << std::endl; + std::thread([this]{ server->Wait(); }).detach(); +} + +void HashProbeThread::Shutdown() { + server->Shutdown(); +} + int main(int argc, char* argv[]) { std::cout << engine_info() << std::endl; diff --combined src/misc.cpp index 3c336c30,e36a04bc..581eb751 --- a/src/misc.cpp +++ b/src/misc.cpp @@@ -1,6 -1,6 +1,6 @@@ /* Stockfish, a UCI chess playing engine derived from Glaurung 2.1 - Copyright (C) 2004-2022 The Stockfish developers (see AUTHORS file) + Copyright (C) 2004-2023 The Stockfish developers (see AUTHORS file) Stockfish is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@@ -32,21 -32,26 +32,26 @@@ // the calls at compile time), try to load them at runtime. To do this we need // first to define the corresponding function pointers. extern "C" { - typedef bool(*fun1_t)(LOGICAL_PROCESSOR_RELATIONSHIP, - PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX, PDWORD); - typedef bool(*fun2_t)(USHORT, PGROUP_AFFINITY); - typedef bool(*fun3_t)(HANDLE, CONST GROUP_AFFINITY*, PGROUP_AFFINITY); - typedef bool(*fun4_t)(USHORT, PGROUP_AFFINITY, USHORT, PUSHORT); - typedef WORD(*fun5_t)(); + using fun1_t = bool(*)(LOGICAL_PROCESSOR_RELATIONSHIP, + PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX, PDWORD); + using fun2_t = bool(*)(USHORT, PGROUP_AFFINITY); + using fun3_t = bool(*)(HANDLE, CONST GROUP_AFFINITY*, PGROUP_AFFINITY); + using fun4_t = bool(*)(USHORT, PGROUP_AFFINITY, USHORT, PUSHORT); + using fun5_t = WORD(*)(); + using fun6_t = bool(*)(HANDLE, DWORD, PHANDLE); + using fun7_t = bool(*)(LPCSTR, LPCSTR, PLUID); + using fun8_t = bool(*)(HANDLE, BOOL, PTOKEN_PRIVILEGES, DWORD, PTOKEN_PRIVILEGES, PDWORD); } #endif + #include + #include #include #include #include #include + #include #include - #include #if defined(__linux__) && !defined(__ANDROID__) #include @@@ -68,7 -73,7 +73,7 @@@ namespace Stockfish namespace { /// Version number or dev. - const string version = "dev"; + constexpr string_view version = "dev"; /// Our fancy logging facility. The trick here is to replace cin.rdbuf() and /// cout.rdbuf() with two Tie objects that tie cin and cout to a file stream. We @@@ -151,13 -156,13 +156,13 @@@ string engine_info(bool to_uci) stringstream ss; ss << "Stockfish " << version << setfill('0'); - if (version == "dev") + if constexpr (version == "dev") { ss << "-"; #ifdef GIT_DATE - ss << GIT_DATE; + ss << stringify(GIT_DATE); #else - const string months("Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec"); + constexpr string_view months("Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec"); string month, day, year; stringstream date(__DATE__); // From compiler, format is "Sep 21 2008" @@@ -165,7 -170,13 +170,7 @@@ ss << year << setw(2) << setfill('0') << (1 + months.find(month) / 4) << setw(2) << setfill('0') << day; #endif - ss << "-"; - - #ifdef GIT_SHA - ss << stringify(GIT_SHA); - #else - ss << "nogit"; - #endif + ss << "-asn"; } ss << (to_uci ? "\nid author ": " by ") @@@ -179,8 -190,6 +184,6 @@@ std::string compiler_info() { - #define stringify2(x) #x - #define stringify(x) stringify2(x) #define make_version_string(major, minor, patch) stringify(major) "." stringify(minor) "." stringify(patch) /// Predefined macros hell: @@@ -292,21 -301,94 +295,94 @@@ /// Debug functions used mainly to collect run-time statistics - static std::atomic hits[2], means[2]; + constexpr int MaxDebugSlots = 32; + + namespace { + + template + struct DebugInfo { + std::atomic data[N] = { 0 }; - void dbg_hit_on(bool b) { ++hits[0]; if (b) ++hits[1]; } - void dbg_hit_on(bool c, bool b) { if (c) dbg_hit_on(b); } - void dbg_mean_of(int v) { ++means[0]; means[1] += v; } + constexpr inline std::atomic& operator[](int index) { return data[index]; } + }; + + DebugInfo<2> hit[MaxDebugSlots]; + DebugInfo<2> mean[MaxDebugSlots]; + DebugInfo<3> stdev[MaxDebugSlots]; + DebugInfo<6> correl[MaxDebugSlots]; + + } // namespace + + void dbg_hit_on(bool cond, int slot) { + + ++hit[slot][0]; + if (cond) + ++hit[slot][1]; + } + + void dbg_mean_of(int64_t value, int slot) { + + ++mean[slot][0]; + mean[slot][1] += value; + } + + void dbg_stdev_of(int64_t value, int slot) { + + ++stdev[slot][0]; + stdev[slot][1] += value; + stdev[slot][2] += value * value; + } + + void dbg_correl_of(int64_t value1, int64_t value2, int slot) { + + ++correl[slot][0]; + correl[slot][1] += value1; + correl[slot][2] += value1 * value1; + correl[slot][3] += value2; + correl[slot][4] += value2 * value2; + correl[slot][5] += value1 * value2; + } void dbg_print() { - if (hits[0]) - cerr << "Total " << hits[0] << " Hits " << hits[1] - << " hit rate (%) " << 100 * hits[1] / hits[0] << endl; + int64_t n; + auto E = [&n](int64_t x) { return double(x) / n; }; + auto sqr = [](double x) { return x * x; }; + + for (int i = 0; i < MaxDebugSlots; ++i) + if ((n = hit[i][0])) + std::cerr << "Hit #" << i + << ": Total " << n << " Hits " << hit[i][1] + << " Hit Rate (%) " << 100.0 * E(hit[i][1]) + << std::endl; + + for (int i = 0; i < MaxDebugSlots; ++i) + if ((n = mean[i][0])) + { + std::cerr << "Mean #" << i + << ": Total " << n << " Mean " << E(mean[i][1]) + << std::endl; + } - if (means[0]) - cerr << "Total " << means[0] << " Mean " - << (double)means[1] / means[0] << endl; + for (int i = 0; i < MaxDebugSlots; ++i) + if ((n = stdev[i][0])) + { + double r = sqrtl(E(stdev[i][2]) - sqr(E(stdev[i][1]))); + std::cerr << "Stdev #" << i + << ": Total " << n << " Stdev " << r + << std::endl; + } + + for (int i = 0; i < MaxDebugSlots; ++i) + if ((n = correl[i][0])) + { + double r = (E(correl[i][5]) - E(correl[i][1]) * E(correl[i][3])) + / ( sqrtl(E(correl[i][2]) - sqr(E(correl[i][1]))) + * sqrtl(E(correl[i][4]) - sqr(E(correl[i][3])))); + std::cerr << "Correl. #" << i + << ": Total " << n << " Coefficient " << r + << std::endl; + } } @@@ -367,8 -449,10 +443,10 @@@ void* std_aligned_alloc(size_t alignmen #if defined(POSIXALIGNEDALLOC) void *mem; return posix_memalign(&mem, alignment, size) ? nullptr : mem; - #elif defined(_WIN32) + #elif defined(_WIN32) && !defined(_M_ARM) && !defined(_M_ARM64) return _mm_malloc(size, alignment); + #elif defined(_WIN32) + return _aligned_malloc(size, alignment); #else return std::aligned_alloc(alignment, size); #endif @@@ -378,8 -462,10 +456,10 @@@ void std_aligned_free(void* ptr) #if defined(POSIXALIGNEDALLOC) free(ptr); - #elif defined(_WIN32) + #elif defined(_WIN32) && !defined(_M_ARM) && !defined(_M_ARM64) _mm_free(ptr); + #elif defined(_WIN32) + _aligned_free(ptr); #else free(ptr); #endif @@@ -403,11 -489,26 +483,26 @@@ static void* aligned_large_pages_alloc_ if (!largePageSize) return nullptr; + // Dynamically link OpenProcessToken, LookupPrivilegeValue and AdjustTokenPrivileges + HMODULE k32 = GetModuleHandle("Advapi32.dll"); + auto fun6 = (fun6_t)(void(*)())GetProcAddress(k32, "OpenProcessToken"); + if (!fun6) + return nullptr; + auto fun7 = (fun7_t)(void(*)())GetProcAddress(k32, "LookupPrivilegeValueA"); + if (!fun7) + return nullptr; + auto fun8 = (fun8_t)(void(*)())GetProcAddress(k32, "AdjustTokenPrivileges"); + if (!fun8) + return nullptr; + + // We need SeLockMemoryPrivilege, so try to enable it for the process - if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hProcessToken)) + // OpenProcessToken() + if (!fun6(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hProcessToken)) return nullptr; - if (LookupPrivilegeValue(NULL, SE_LOCK_MEMORY_NAME, &luid)) + // LookupPrivilegeValueA() + if (fun7(nullptr, SE_LOCK_MEMORY_NAME, &luid)) { TOKEN_PRIVILEGES tp { }; TOKEN_PRIVILEGES prevTp { }; @@@ -419,17 -520,19 +514,19 @@@ // Try to enable SeLockMemoryPrivilege. Note that even if AdjustTokenPrivileges() succeeds, // we still need to query GetLastError() to ensure that the privileges were actually obtained. - if (AdjustTokenPrivileges( + // AdjustTokenPrivileges() + if (fun8( hProcessToken, FALSE, &tp, sizeof(TOKEN_PRIVILEGES), &prevTp, &prevTpLen) && GetLastError() == ERROR_SUCCESS) { // Round up size to full pages and allocate allocSize = (allocSize + largePageSize - 1) & ~size_t(largePageSize - 1); mem = VirtualAlloc( - NULL, allocSize, MEM_RESERVE | MEM_COMMIT | MEM_LARGE_PAGES, PAGE_READWRITE); + nullptr, allocSize, MEM_RESERVE | MEM_COMMIT | MEM_LARGE_PAGES, PAGE_READWRITE); // Privilege no longer needed, restore previous state - AdjustTokenPrivileges(hProcessToken, FALSE, &prevTp, 0, NULL, NULL); + // AdjustTokenPrivileges () + fun8(hProcessToken, FALSE, &prevTp, 0, nullptr, nullptr); } } @@@ -447,7 -550,7 +544,7 @@@ void* aligned_large_pages_alloc(size_t // Fall back to regular, page aligned, allocation if necessary if (!mem) - mem = VirtualAlloc(NULL, allocSize, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE); + mem = VirtualAlloc(nullptr, allocSize, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE); return mem; } @@@ -511,7 -614,7 +608,7 @@@ void bindThisThread(size_t) { /// API and returns the best node id for the thread with index idx. Original /// code from Texel by Peter Österlund. - int best_node(size_t idx) { + static int best_node(size_t idx) { int threads = 0; int nodes = 0; @@@ -520,7 -623,7 +617,7 @@@ DWORD byteOffset = 0; // Early exit if the needed API is not available at runtime - HMODULE k32 = GetModuleHandle("Kernel32.dll"); + HMODULE k32 = GetModuleHandle(TEXT("Kernel32.dll")); auto fun1 = (fun1_t)(void(*)())GetProcAddress(k32, "GetLogicalProcessorInformationEx"); if (!fun1) return -1; @@@ -590,7 -693,7 +687,7 @@@ void bindThisThread(size_t idx) return; // Early exit if the needed API are not available at runtime - HMODULE k32 = GetModuleHandle("Kernel32.dll"); + HMODULE k32 = GetModuleHandle(TEXT("Kernel32.dll")); auto fun2 = (fun2_t)(void(*)())GetProcAddress(k32, "GetNumaNodeProcessorMaskEx"); auto fun3 = (fun3_t)(void(*)())GetProcAddress(k32, "SetThreadGroupAffinity"); auto fun4 = (fun4_t)(void(*)())GetProcAddress(k32, "GetNumaNodeProcessorMask2"); diff --combined src/position.cpp index e0d432e8,e6fdb511..3cfc23d3 --- a/src/position.cpp +++ b/src/position.cpp @@@ -1,6 -1,6 +1,6 @@@ /* Stockfish, a UCI chess playing engine derived from Glaurung 2.1 - Copyright (C) 2004-2022 The Stockfish developers (see AUTHORS file) + Copyright (C) 2004-2023 The Stockfish developers (see AUTHORS file) Stockfish is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@@ -22,6 -22,7 +22,7 @@@ #include // For std::memset, std::memcmp #include #include + #include #include "bitboard.h" #include "misc.h" @@@ -46,7 -47,7 +47,7 @@@ namespace Zobrist namespace { - const string PieceToChar(" PNBRQK pnbrqk"); + constexpr std::string_view PieceToChar(" PNBRQK pnbrqk"); constexpr Piece Pieces[] = { W_PAWN, W_KNIGHT, W_BISHOP, W_ROOK, W_QUEEN, W_KING, B_PAWN, B_KNIGHT, B_BISHOP, B_ROOK, B_QUEEN, B_KING }; @@@ -96,7 -97,7 +97,7 @@@ std::ostream& operator<<(std::ostream& // Marcel van Kervinck's cuckoo algorithm for fast detection of "upcoming repetition" // situations. Description of the algorithm in the following paper: - // https://marcelk.net/2013-04-06/paper/upcoming-rep-v2.pdf + // http://web.archive.org/web/20201107002606/https://marcelk.net/2013-04-06/paper/upcoming-rep-v2.pdf // First and second hash functions for indexing the cuckoo tables inline int H1(Key h) { return h & 0x1fff; } @@@ -281,8 -282,10 +282,8 @@@ Position& Position::set(const string& f chess960 = isChess960; thisThread = th; - set_state(st); + set_state(); - assert(pos_is_ok()); - return *this; } @@@ -310,19 -313,19 +311,19 @@@ void Position::set_castling_right(Colo /// Position::set_check_info() sets king attacks to detect if a move gives check - void Position::set_check_info(StateInfo* si) const { + void Position::set_check_info() const { - si->blockersForKing[WHITE] = slider_blockers(pieces(BLACK), square(WHITE), si->pinners[BLACK]); - si->blockersForKing[BLACK] = slider_blockers(pieces(WHITE), square(BLACK), si->pinners[WHITE]); + st->blockersForKing[WHITE] = slider_blockers(pieces(BLACK), square(WHITE), st->pinners[BLACK]); + st->blockersForKing[BLACK] = slider_blockers(pieces(WHITE), square(BLACK), st->pinners[WHITE]); Square ksq = square(~sideToMove); - si->checkSquares[PAWN] = pawn_attacks_bb(~sideToMove, ksq); - si->checkSquares[KNIGHT] = attacks_bb(ksq); - si->checkSquares[BISHOP] = attacks_bb(ksq, pieces()); - si->checkSquares[ROOK] = attacks_bb(ksq, pieces()); - si->checkSquares[QUEEN] = si->checkSquares[BISHOP] | si->checkSquares[ROOK]; - si->checkSquares[KING] = 0; + st->checkSquares[PAWN] = pawn_attacks_bb(~sideToMove, ksq); + st->checkSquares[KNIGHT] = attacks_bb(ksq); + st->checkSquares[BISHOP] = attacks_bb(ksq, pieces()); + st->checkSquares[ROOK] = attacks_bb(ksq, pieces()); + st->checkSquares[QUEEN] = st->checkSquares[BISHOP] | st->checkSquares[ROOK]; + st->checkSquares[KING] = 0; } @@@ -331,39 -334,39 +332,39 @@@ /// The function is only used when a new position is set up, and to verify /// the correctness of the StateInfo data when running in debug mode. - void Position::set_state(StateInfo* si) const { + void Position::set_state() const { - si->key = si->materialKey = 0; - si->pawnKey = Zobrist::noPawns; - si->nonPawnMaterial[WHITE] = si->nonPawnMaterial[BLACK] = VALUE_ZERO; - si->checkersBB = attackers_to(square(sideToMove)) & pieces(~sideToMove); + st->key = st->materialKey = 0; + st->pawnKey = Zobrist::noPawns; + st->nonPawnMaterial[WHITE] = st->nonPawnMaterial[BLACK] = VALUE_ZERO; + st->checkersBB = attackers_to(square(sideToMove)) & pieces(~sideToMove); - set_check_info(si); + set_check_info(); for (Bitboard b = pieces(); b; ) { Square s = pop_lsb(b); Piece pc = piece_on(s); - si->key ^= Zobrist::psq[pc][s]; + st->key ^= Zobrist::psq[pc][s]; if (type_of(pc) == PAWN) - si->pawnKey ^= Zobrist::psq[pc][s]; + st->pawnKey ^= Zobrist::psq[pc][s]; else if (type_of(pc) != KING) - si->nonPawnMaterial[color_of(pc)] += PieceValue[MG][pc]; + st->nonPawnMaterial[color_of(pc)] += PieceValue[MG][pc]; } - if (si->epSquare != SQ_NONE) - si->key ^= Zobrist::enpassant[file_of(si->epSquare)]; + if (st->epSquare != SQ_NONE) + st->key ^= Zobrist::enpassant[file_of(st->epSquare)]; if (sideToMove == BLACK) - si->key ^= Zobrist::side; + st->key ^= Zobrist::side; - si->key ^= Zobrist::castling[si->castlingRights]; + st->key ^= Zobrist::castling[st->castlingRights]; for (Piece pc : Pieces) for (int cnt = 0; cnt < pieceCount[pc]; ++cnt) - si->materialKey ^= Zobrist::psq[pc][cnt]; + st->materialKey ^= Zobrist::psq[pc][cnt]; } @@@ -566,8 -569,7 +567,7 @@@ bool Position::pseudo_legal(const Move : MoveList(*this).contains(m); // Is not a promotion, so promotion piece must be empty - if (promotion_type(m) - KNIGHT != NO_PIECE_TYPE) - return false; + assert(promotion_type(m) - KNIGHT == NO_PIECE_TYPE); // If the 'from' square is not occupied by a piece belonging to the side to // move, the move is obviously not legal. @@@ -763,9 -765,6 +763,6 @@@ void Position::do_move(Move m, StateInf // Update board and piece lists remove_piece(capsq); - if (type_of(m) == EN_PASSANT) - board[capsq] = NO_PIECE; - // Update material hash key and prefetch access to materialTable k ^= Zobrist::psq[captured][capsq]; st->materialKey ^= Zobrist::psq[captured][pieceCount[captured]]; @@@ -866,7 -865,7 +863,7 @@@ sideToMove = ~sideToMove; // Update king attacks used for fast check detection - set_check_info(st); + set_check_info(); // Calculate the repetition info. It is the ply distance from the previous // occurrence of the same position, negative in the 3-fold case, or zero @@@ -1018,7 -1017,7 +1015,7 @@@ void Position::do_null_move(StateInfo& sideToMove = ~sideToMove; - set_check_info(st); + set_check_info(); st->repetition = 0; @@@ -1063,7 -1062,7 +1060,7 @@@ Key Position::key_after(Move m) const /// SEE value of move is greater or equal to the given threshold. We'll use an /// algorithm similar to alpha-beta pruning with a null window. - bool Position::see_ge(Move m, Value threshold) const { + bool Position::see_ge(Move m, Bitboard& occupied, Value threshold) const { assert(is_ok(m)); @@@ -1082,7 -1081,7 +1079,7 @@@ return true; assert(color_of(piece_on(from)) == sideToMove); - Bitboard occupied = pieces() ^ from ^ to; + occupied = pieces() ^ from ^ to; // xoring to is important for pinned piece logic Color stm = sideToMove; Bitboard attackers = attackers_to(to, occupied); Bitboard stmAttackers, bb; @@@ -1113,45 -1112,44 +1110,44 @@@ // the bitboard 'attackers' any X-ray attackers behind it. if ((bb = stmAttackers & pieces(PAWN))) { + occupied ^= least_significant_square_bb(bb); if ((swap = PawnValueMg - swap) < res) break; - occupied ^= least_significant_square_bb(bb); attackers |= attacks_bb(to, occupied) & pieces(BISHOP, QUEEN); } else if ((bb = stmAttackers & pieces(KNIGHT))) { + occupied ^= least_significant_square_bb(bb); if ((swap = KnightValueMg - swap) < res) break; - - occupied ^= least_significant_square_bb(bb); } else if ((bb = stmAttackers & pieces(BISHOP))) { + occupied ^= least_significant_square_bb(bb); if ((swap = BishopValueMg - swap) < res) break; - occupied ^= least_significant_square_bb(bb); attackers |= attacks_bb(to, occupied) & pieces(BISHOP, QUEEN); } else if ((bb = stmAttackers & pieces(ROOK))) { + occupied ^= least_significant_square_bb(bb); if ((swap = RookValueMg - swap) < res) break; - occupied ^= least_significant_square_bb(bb); attackers |= attacks_bb(to, occupied) & pieces(ROOK, QUEEN); } else if ((bb = stmAttackers & pieces(QUEEN))) { + occupied ^= least_significant_square_bb(bb); if ((swap = QueenValueMg - swap) < res) break; - occupied ^= least_significant_square_bb(bb); attackers |= (attacks_bb(to, occupied) & pieces(BISHOP, QUEEN)) | (attacks_bb(to, occupied) & pieces(ROOK , QUEEN)); } @@@ -1165,6 -1163,11 +1161,11 @@@ return bool(res); } + bool Position::see_ge(Move m, Value threshold) const { + Bitboard occupied; + return see_ge(m, occupied, threshold); + } + /// Position::is_draw() tests whether the position is drawn by 50-move rule /// or by repetition. It does not detect stalemates. @@@ -1321,12 -1324,6 +1322,6 @@@ bool Position::pos_is_ok() const if (p1 != p2 && (pieces(p1) & pieces(p2))) assert(0 && "pos_is_ok: Bitboards"); - StateInfo si = *st; - ASSERT_ALIGNED(&si, Eval::NNUE::CacheLineSize); - - set_state(&si); - if (std::memcmp(&si, st, sizeof(StateInfo))) - assert(0 && "pos_is_ok: State"); for (Piece pc : Pieces) if ( pieceCount[pc] != popcount(pieces(color_of(pc), type_of(pc))) diff --combined src/ucioption.cpp index 8dd10a48,39933ea5..ee84e253 --- a/src/ucioption.cpp +++ b/src/ucioption.cpp @@@ -1,6 -1,6 +1,6 @@@ /* Stockfish, a UCI chess playing engine derived from Glaurung 2.1 - Copyright (C) 2004-2022 The Stockfish developers (see AUTHORS file) + Copyright (C) 2004-2023 The Stockfish developers (see AUTHORS file) Stockfish is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@@ -27,7 -27,6 +27,7 @@@ #include "thread.h" #include "tt.h" #include "uci.h" +#include "hashprobe.h" #include "syzygy/tbprobe.h" using std::string; @@@ -35,25 -34,17 +35,25 @@@ namespace Stockfish { UCI::OptionsMap Options; // Global object +std::unique_ptr hash_probe_thread; namespace UCI { /// 'On change' actions, triggered by an option's value change - void on_clear_hash(const Option&) { Search::clear(); } - void on_hash_size(const Option& o) { TT.resize(size_t(o)); } - void on_logger(const Option& o) { start_logger(o); } - void on_threads(const Option& o) { Threads.set(size_t(o)); } - void on_tb_path(const Option& o) { Tablebases::init(o); } - void on_use_NNUE(const Option& ) { Eval::NNUE::init(); } - void on_eval_file(const Option& ) { Eval::NNUE::init(); } - void on_rpc_server_address(const Option& o) { + static void on_clear_hash(const Option&) { Search::clear(); } + static void on_hash_size(const Option& o) { TT.resize(size_t(o)); } + static void on_logger(const Option& o) { start_logger(o); } + static void on_threads(const Option& o) { Threads.set(size_t(o)); } + static void on_tb_path(const Option& o) { Tablebases::init(o); } -static void on_use_NNUE(const Option&) { Eval::NNUE::init(); } -static void on_eval_file(const Option&) { Eval::NNUE::init(); } ++static void on_use_NNUE(const Option& ) { Eval::NNUE::init(); } ++static void on_eval_file(const Option& ) { Eval::NNUE::init(); } ++static void on_rpc_server_address(const Option& o) { + if (hash_probe_thread) { + hash_probe_thread->Shutdown(); + } + std::string addr = o; + hash_probe_thread.reset(new HashProbeThread(addr)); +} /// Our case insensitive less() function as required by UCI protocol bool CaseInsensitiveLess::operator() (const string& s1, const string& s2) const { @@@ -82,7 -73,7 +82,7 @@@ void init(OptionsMap& o) o["UCI_Chess960"] << Option(false); o["UCI_AnalyseMode"] << Option(false); o["UCI_LimitStrength"] << Option(false); - o["UCI_Elo"] << Option(1350, 1350, 2850); + o["UCI_Elo"] << Option(1320, 1320, 3190); o["UCI_ShowWDL"] << Option(false); o["SyzygyPath"] << Option("", on_tb_path); o["SyzygyProbeDepth"] << Option(1, 1, 100); @@@ -90,7 -81,6 +90,7 @@@ o["SyzygyProbeLimit"] << Option(7, 0, 7); o["Use NNUE"] << Option(true, on_use_NNUE); o["EvalFile"] << Option(EvalFileDefaultName, on_eval_file); + o["RPCServerAddress"] << Option("", on_rpc_server_address); }