41# include <immintrin.h>
42#elif defined(__GNUC__) || defined(__clang__)
44# include <immintrin.h>
74inline void cpuid(std::uint32_t leaf, std::uint32_t subleaf,
75 std::uint32_t out[4])
noexcept {
79 __cpuidex(regs,
static_cast<int>(leaf),
static_cast<int>(subleaf));
80 for (
int i = 0; i < 4; ++i)
81 out[i] =
static_cast<std::uint32_t
>(regs[i]);
82#elif defined(__GNUC__) || defined(__clang__)
83 __cpuid_count(leaf, subleaf, out[0], out[1], out[2], out[3]);
86 out[0] = out[1] = out[2] = out[3] = 0u;
91inline std::uint64_t
xgetbv(std::uint32_t xcr)
noexcept {
94#elif (defined(__GNUC__) || defined(__clang__)) && defined(__XSAVE__)
96 __asm__
volatile(
"xgetbv" :
"=a"(lo),
"=d"(hi) :
"c"(xcr));
97 return (
static_cast<std::uint64_t
>(hi) << 32u) | lo;
106 std::uint32_t regs[4] = {};
107 cpuid(0x1u, 0u, regs);
109 const bool osxsave = (regs[2] >> 27u) & 1u;
110 if (!osxsave)
return false;
112 const std::uint64_t xcr0 =
xgetbv(0u);
113 return (xcr0 & 0x6u) == 0x6u;
120 const std::uint64_t xcr0 =
xgetbv(0u);
121 return (xcr0 & 0xE0u) == 0xE0u;
157 std::uint32_t max_leaf[4] = {};
159 const std::uint32_t max_func = max_leaf[0];
163 std::uint32_t leaf1[4] = {};
166 const bool sse42 = (leaf1[2] >> 20u) & 1u;
170 std::uint32_t leaf7[4] = {};
173 const bool avx2 = (leaf7[1] >> 5u) & 1u;
174 const bool avx512f = (leaf7[1] >> 16u) & 1u;
210 default:
return "UNKNOWN";
bool os_saves_zmm() noexcept
Probe OS support for ZMM (AVX-512) register save/restore.
void cpuid(std::uint32_t leaf, std::uint32_t subleaf, std::uint32_t out[4]) noexcept
std::uint64_t xgetbv(std::uint32_t xcr) noexcept
Read XCR0 (used to verify OS XSAVE support for YMM/ZMM state).
bool os_saves_ymm() noexcept
Probe OS support for YMM (AVX) register save/restore.
bool has_avx2() noexcept
Returns true when AVX2 is available on this CPU/OS.
const char * simd_level_name(SimdLevel level) noexcept
Human-readable name for a SimdLevel value.
bool has_avx512f() noexcept
Returns true when AVX-512F is available on this CPU/OS.
SimdLevel
Ordered enumeration of SIMD capability tiers.
@ SCALAR
No SIMD; pure scalar C++ path.
@ AVX512F
AVX-512F — 512-bit; 8 doubles per ZMM register.
@ SSE42
SSE 4.2 — 128-bit; 2 doubles per YMM half.
@ AVX2
AVX2 — 256-bit; 4 doubles per YMM register.
bool has_sse42() noexcept
Returns true when SSE 4.2 is available on this CPU/OS.
SimdLevel detect_simd_level() noexcept