Files
stockfish/src/universal/entry_x86.cpp
T
DisservinandJoost VandeVondele 583e0c1c75 cleanup feature detection code
makes the main dispatch logic more easy to follow and possibly update

closes https://github.com/official-stockfish/Stockfish/pull/6753

No functional change
2026-04-20 17:42:47 +02:00

115 lines
4.3 KiB
C++

#include <cpuid.h>
#include <stdint.h>
#define DEFINE_BUILD(x) \
namespace Stockfish_##x { \
extern int main(int argc, char* argv[]); \
} \
extern "C" void (*__start_##x##_init[])(void); \
extern "C" void (*__stop_##x##_init[])(void); \
int entry_##x(int argc, char* argv[]) { \
unsigned count = __stop_##x##_init - __start_##x##_init; \
for (unsigned i = 0; i < count; i++) \
__start_##x##_init[i](); \
return Stockfish_##x::main(argc, argv); \
}
DEFINE_BUILD(x86_64)
DEFINE_BUILD(x86_64_sse41_popcnt)
DEFINE_BUILD(x86_64_avx2)
DEFINE_BUILD(x86_64_bmi2)
DEFINE_BUILD(x86_64_avxvnni)
DEFINE_BUILD(x86_64_avx512)
DEFINE_BUILD(x86_64_vnni512)
DEFINE_BUILD(x86_64_avx512icl)
// AMD Zen/Zen+/Zen2 (family 17h) implement pdep/pext via microcode.
static bool has_slow_bmi2() {
return __builtin_cpu_is("amd") && (__builtin_cpu_is("znver1") || __builtin_cpu_is("znver2"));
}
struct CpuFeatures {
bool sse41; // SSE4.1
bool popcnt; // POPCNT
bool avx2; // AVX2
bool bmi2; // BMI2 (may be slow on AMD Zen/Zen+/Zen2)
bool avx512f; // AVX-512 Foundation
bool avx512vl; // AVX-512 Vector Length extensions
bool avx512bw; // AVX-512 Byte and Word instructions
bool avx512vnni; // AVX-512 Vector Neural Network Instructions
bool avx512ifma; // AVX-512 Integer Fused Multiply-Add
bool avx512vbmi; // AVX-512 Vector Bit Manipulation Instructions
bool avx512vbmi2; // AVX-512 VBMI2
bool avx512vpopcntdq; // AVX-512 VPOPCNTDQ
bool avx512bitalg; // AVX-512 BITALG
bool vpclmulqdq; // Carry-less multiplication (AVX512 variant)
bool gfni; // Galois Field instructions
bool vaes; // AES instructions (AVX512 variant)
bool avxvnni; // AVX-VNNI (non-512 dot product instructions)
};
static CpuFeatures query_cpu_features() {
return {
.sse41 = (bool) __builtin_cpu_supports("sse4.1"),
.popcnt = (bool) __builtin_cpu_supports("popcnt"),
.avx2 = (bool) __builtin_cpu_supports("avx2"),
.bmi2 = (bool) __builtin_cpu_supports("bmi2"),
.avx512f = (bool) __builtin_cpu_supports("avx512f"),
.avx512vl = (bool) __builtin_cpu_supports("avx512vl"),
.avx512bw = (bool) __builtin_cpu_supports("avx512bw"),
.avx512vnni = (bool) __builtin_cpu_supports("avx512vnni"),
.avx512ifma = (bool) __builtin_cpu_supports("avx512ifma"),
.avx512vbmi = (bool) __builtin_cpu_supports("avx512vbmi"),
.avx512vbmi2 = (bool) __builtin_cpu_supports("avx512vbmi2"),
.avx512vpopcntdq = (bool) __builtin_cpu_supports("avx512vpopcntdq"),
.avx512bitalg = (bool) __builtin_cpu_supports("avx512bitalg"),
.vpclmulqdq = (bool) __builtin_cpu_supports("vpclmulqdq"),
.gfni = (bool) __builtin_cpu_supports("gfni"),
.vaes = (bool) __builtin_cpu_supports("vaes"),
.avxvnni = (bool) __builtin_cpu_supports("avxvnni"),
};
}
// Selects the most capable ISA variant supported by this CPU and OS
static int dispatch(const CpuFeatures& f, int argc, char* argv[]) {
if (!f.sse41 || !f.popcnt)
return entry_x86_64(argc, argv);
if (!f.avx2)
return entry_x86_64_sse41_popcnt(argc, argv);
if (!f.bmi2 || has_slow_bmi2())
return entry_x86_64_avx2(argc, argv);
if (!f.avx512f || !f.avx512vl || !f.avx512bw)
{
if (f.avxvnni)
return entry_x86_64_avxvnni(argc, argv);
return entry_x86_64_bmi2(argc, argv);
}
if (!f.avx512vnni)
return entry_x86_64_avx512(argc, argv);
// AVX512ICL requires the full Icelake-client feature suite
if (!f.avx512ifma //
|| !f.avx512vbmi //
|| !f.avx512vbmi2 //
|| !f.avx512vpopcntdq //
|| !f.avx512bitalg //
|| !f.vpclmulqdq //
|| !f.gfni //
|| !f.vaes //
)
return entry_x86_64_vnni512(argc, argv);
return entry_x86_64_avx512icl(argc, argv);
}
int main(int argc, char* argv[]) {
__builtin_cpu_init();
CpuFeatures features = query_cpu_features();
return dispatch(features, argc, argv);
}