]> git.sesse.net Git - stockfish/commitdiff
Merge remote-tracking branch 'upstream/master'
authorSteinar H. Gunderson <sgunderson@bigfoot.com>
Sun, 9 Apr 2023 09:25:35 +0000 (11:25 +0200)
committerSteinar H. Gunderson <sgunderson@bigfoot.com>
Sun, 9 Apr 2023 09:28:36 +0000 (11:28 +0200)
1  2 
src/Makefile
src/main.cpp
src/misc.cpp
src/position.cpp
src/ucioption.cpp

diff --combined src/Makefile
index 171f966cc2473b53a7c7ac531b3ba42778edb618,abcf11b0a1158ae73d26ff36af64ce7c5c63272c..e55d52e00f9688f4ac0b545e2215600dc4df93d1
@@@ -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
  
  ### 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/<sanitizer> ... (-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)
                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)
        endif
  
        ifeq ($(KERNEL),Darwin)
-               ifeq ($(comp),$(filter $(comp),clang icc))
+               ifeq ($(comp),$(filter $(comp),clang icx))
                        CXXFLAGS += -mdynamic-no-pic
                endif
  
        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
  ### 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
  ### 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"
        @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"
        @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 ""
        @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)"
        @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 435e436c3fe7a39e7ebd51b411b5676d6245dcfe,c40e0fa34928d9a3943a130d892eab1170998c71..557c8c2789b77fb8b830801ae030ffe0582f2bf1
@@@ -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
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
  
 +#include <deque>
  #include <iostream>
 +#include <stack>
 +#include <thread>
  
  #include "bitboard.h"
  #include "endgame.h"
  #include "tt.h"
  #include "uci.h"
  
 +#include <grpc/grpc.h>
 +#include <grpc++/server.h>
 +#include <grpc++/server_builder.h>
 +#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;
  
-                                       attackers &= ~SquareBB[s];
 +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<StateInfo>(1));
 +
 +      ProbeMove(&pos, setup_states.get(), invert, response->mutable_root());
 +
 +      MoveList<LEGAL> 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 &= ~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<LEGAL>(*pos).size() > 0) {
 +                      pretty += "+";
 +              } else {
 +                      pretty += "#";
 +              }
 +              pos->undo_move(move);
 +      }
 +
 +      decoded->set_pretty(pretty);
 +}
 +
 +void HashProbeImpl::ProbeMove(Position* pos, std::deque<StateInfo>* 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<Move> pv;
 +              std::set<Key> 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 3c336c3014c7b5a4524df40c7b03c04dd560f866,e36a04bccfbef712f07229e78417b252a68625ea..581eb7519b50ca2155612ee563fb631cb1cc432c
@@@ -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
  // 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 <cmath>
+ #include <cstdlib>
  #include <fstream>
  #include <iomanip>
  #include <iostream>
  #include <sstream>
+ #include <string_view>
  #include <vector>
- #include <cstdlib>
  
  #if defined(__linux__) && !defined(__ANDROID__)
  #include <stdlib.h>
@@@ -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"
  
        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 ")
  
  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:
  
  
  /// Debug functions used mainly to collect run-time statistics
- static std::atomic<int64_t> hits[2], means[2];
+ constexpr int MaxDebugSlots = 32;
+ namespace {
+ template<size_t N>
+ struct DebugInfo {
+     std::atomic<int64_t> 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<int64_t>& 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 { };
  
        // 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;
    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 e0d432e8a7fe5d8aa2b484258c67eceb341c6214,e6fdb511fcc10a03f11ab3eb72fd79917f52d96e..3cfc23d33c4a015302b1866fba7a929b4ea0afc3
@@@ -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 <cstring> // For std::memset, std::memcmp
  #include <iomanip>
  #include <sstream>
+ #include <string_view>
  
  #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<KING>(WHITE), si->pinners[BLACK]);
-   si->blockersForKing[BLACK] = slider_blockers(pieces(WHITE), square<KING>(BLACK), si->pinners[WHITE]);
+   st->blockersForKing[WHITE] = slider_blockers(pieces(BLACK), square<KING>(WHITE), st->pinners[BLACK]);
+   st->blockersForKing[BLACK] = slider_blockers(pieces(WHITE), square<KING>(BLACK), st->pinners[WHITE]);
  
    Square ksq = square<KING>(~sideToMove);
  
-   si->checkSquares[PAWN]   = pawn_attacks_bb(~sideToMove, ksq);
-   si->checkSquares[KNIGHT] = attacks_bb<KNIGHT>(ksq);
-   si->checkSquares[BISHOP] = attacks_bb<BISHOP>(ksq, pieces());
-   si->checkSquares[ROOK]   = attacks_bb<ROOK>(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<KNIGHT>(ksq);
+   st->checkSquares[BISHOP] = attacks_bb<BISHOP>(ksq, pieces());
+   st->checkSquares[ROOK]   = attacks_bb<ROOK>(ksq, pieces());
+   st->checkSquares[QUEEN]  = st->checkSquares[BISHOP] | st->checkSquares[ROOK];
+   st->checkSquares[KING]   = 0;
  }
  
  
  /// 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<KING>(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<KING>(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<NON_EVASIONS>(*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]];
    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));
  
        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;
        // 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<BISHOP>(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<BISHOP>(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<ROOK>(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<BISHOP>(to, occupied) & pieces(BISHOP, QUEEN))
                        | (attacks_bb<ROOK  >(to, occupied) & pieces(ROOK  , QUEEN));
        }
    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 8dd10a48a26525b6f0c2c59e61989922cfb60a15,39933ea5e8d0150b6a7472bfad0223829b9e35c0..ee84e25323753d7e67710c86dcefc0bd1aa0600e
@@@ -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;
  namespace Stockfish {
  
  UCI::OptionsMap Options; // Global object
 +std::unique_ptr<HashProbeThread> 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("<empty>", 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("<empty>", on_rpc_server_address);
  }