21#if HI_COMPILER == HI_CC_MSVC
23#elif HI_COMPILER == HI_CC_GCC || HI_COMPILER == HI_CC_CLANG
26#error "Unsupported compiler for x64 cpu_id"
60hi_export_module(hikocpu :
cpu_id);
62namespace hi {
inline namespace v1 {
121constexpr auto cpu_feature_metadata_init() noexcept
126 r[std::to_underlying(cpu_feature::cmov)] =
"CMOV";
127 r[std::to_underlying(cpu_feature::cx8)] =
"CX8";
128 r[std::to_underlying(cpu_feature::fpu)] =
"FPU";
129 r[std::to_underlying(cpu_feature::fxsr)] =
"FXSR";
130 r[std::to_underlying(cpu_feature::mmx)] =
"MMX";
131 r[std::to_underlying(cpu_feature::osfxsr)] =
"OSDXSR";
132 r[std::to_underlying(cpu_feature::sce)] =
"SCE";
133 r[std::to_underlying(cpu_feature::sse)] =
"SSE";
134 r[std::to_underlying(cpu_feature::sse2)] =
"SSE2";
135 r[std::to_underlying(cpu_feature::cx16)] =
"CX16";
136 r[std::to_underlying(cpu_feature::lahf)] =
"LAHF";
137 r[std::to_underlying(cpu_feature::popcnt)] =
"POPCNT";
138 r[std::to_underlying(cpu_feature::sse3)] =
"SSE3";
139 r[std::to_underlying(cpu_feature::sse4_1)] =
"SSE4.1";
140 r[std::to_underlying(cpu_feature::sse4_2)] =
"SSE4.2";
141 r[std::to_underlying(cpu_feature::ssse3)] =
"SSSE3";
142 r[std::to_underlying(cpu_feature::avx)] =
"AVX";
143 r[std::to_underlying(cpu_feature::avx2)] =
"AVX2";
144 r[std::to_underlying(cpu_feature::bmi1)] =
"BMI1";
145 r[std::to_underlying(cpu_feature::bmi2)] =
"BMI2";
146 r[std::to_underlying(cpu_feature::f16c)] =
"F16C";
147 r[std::to_underlying(cpu_feature::fma)] =
"FMA";
148 r[std::to_underlying(cpu_feature::lzcnt)] =
"LZCNT";
149 r[std::to_underlying(cpu_feature::movbe)] =
"MOVBE";
150 r[std::to_underlying(cpu_feature::osxsave)] =
"OSXSAVE";
151 r[std::to_underlying(cpu_feature::avx512f)] =
"AVX512F";
152 r[std::to_underlying(cpu_feature::avx512bw)] =
"AVX512BW";
153 r[std::to_underlying(cpu_feature::avx512cd)] =
"AVX512CD";
154 r[std::to_underlying(cpu_feature::avx512dq)] =
"AVX512DQ";
155 r[std::to_underlying(cpu_feature::avx512vl)] =
"AVX512VL";
156 r[std::to_underlying(cpu_feature::avx512pf)] =
"AVX512PF";
157 r[std::to_underlying(cpu_feature::avx512er)] =
"AVX512ER";
158 r[std::to_underlying(cpu_feature::sha)] =
"SHA";
159 r[std::to_underlying(cpu_feature::aes)] =
"AES";
160 r[std::to_underlying(cpu_feature::pclmul)] =
"PCLMUL";
161 r[std::to_underlying(cpu_feature::rdrnd)] =
"RDRND";
162 r[std::to_underlying(cpu_feature::rdseed)] =
"RDSEED";
166constexpr auto cpu_feature_metadata = cpu_feature_metadata_init();
171struct std::formatter<::
hi::cpu_feature, char> : std::formatter<std::string_view, char> {
174 return std::formatter<std::string_view, char>::format(::hi::cpu_feature_metadata[std::to_underlying(t)], fc);
178hi_export
namespace hi {
181template<std::
integral Lhs>
182[[nodiscard]]
constexpr unsigned long long operator<<(Lhs
const& lhs,
cpu_feature const& rhs)
184 if (not std::cmp_equal(lhs, 1)) {
187 if (not std::cmp_less(std::to_underlying(rhs), 64)) {
188 throw std::logic_error(
"cpu_feature is not allowed the have a value beyond 63");
191 return static_cast<unsigned long long>(lhs) << std::to_underlying(rhs);
201 cmov = 1 << cpu_feature::cmov,
202 cx8 = 1 << cpu_feature::cx8,
203 fpu = 1 << cpu_feature::fpu,
204 fxsr = 1 << cpu_feature::fxsr,
205 mmx = 1 << cpu_feature::mmx,
206 osfxsr = 1 << cpu_feature::osfxsr,
207 sce = 1 << cpu_feature::sce,
208 sse = 1 << cpu_feature::sse,
209 sse2 = 1 << cpu_feature::sse2,
210 x86_64_v1 = cmov | cx8 | fpu | fxsr | mmx | osfxsr | sce | sse | sse2,
212 cx16 = 1 << cpu_feature::cx16,
213 lahf = 1 << cpu_feature::lahf,
214 popcnt = 1 << cpu_feature::popcnt,
215 sse3 = 1 << cpu_feature::sse3,
216 sse4_1 = 1 << cpu_feature::sse4_1,
217 sse4_2 = 1 << cpu_feature::sse4_2,
218 ssse3 = 1 << cpu_feature::ssse3,
219 x86_64_v2 = x86_64_v1 | cx16 | lahf | popcnt | sse3 | sse4_1 | sse4_2 | ssse3,
221 avx = 1 << cpu_feature::avx,
222 avx2 = 1 << cpu_feature::avx2,
223 bmi1 = 1 << cpu_feature::bmi1,
224 bmi2 = 1 << cpu_feature::bmi2,
225 f16c = 1 << cpu_feature::f16c,
226 fma = 1 << cpu_feature::fma,
227 lzcnt = 1 << cpu_feature::lzcnt,
228 movbe = 1 << cpu_feature::movbe,
229 osxsave = 1 << cpu_feature::osxsave,
230 x86_64_v3 = x86_64_v2 | avx | avx2 | bmi1 | bmi2 | f16c | fma | lzcnt | movbe | osxsave,
232 avx512f = 1 << cpu_feature::avx512f,
233 avx512bw = 1 << cpu_feature::avx512bw,
234 avx512cd = 1 << cpu_feature::avx512cd,
235 avx512dq = 1 << cpu_feature::avx512dq,
236 avx512vl = 1 << cpu_feature::avx512vl,
237 x86_64_v4 = x86_64_v3 | avx512f | avx512bw | avx512cd | avx512dq | avx512vl,
239 avx512pf = 1 << cpu_feature::avx512pf,
240 avx512er = 1 << cpu_feature::avx512er,
241 sha = 1 << cpu_feature::sha,
242 aes = 1 << cpu_feature::aes,
243 pclmul = 1 << cpu_feature::pclmul,
244 rdrnd = 1 << cpu_feature::rdrnd,
245 rdseed = 1 << cpu_feature::rdseed,
250 return static_cast<cpu_feature_mask>(std::to_underlying(lhs) | std::to_underlying(rhs));
255 return static_cast<cpu_feature_mask>(std::to_underlying(lhs) & std::to_underlying(rhs));
265 return std::to_underlying(rhs) != 0;
282 return lhs = lhs | rhs;
292 using mask_type = std::underlying_type_t<::hi::cpu_feature_mask>;
295 for (mask_type mask = 1; mask != 0; mask <<= 1) {
296 if ((std::to_underlying(t) & mask) != 0) {
297 auto const feature =
static_cast<::
hi::cpu_feature>(std::countr_zero(mask));
300 str = std::format(
"{}", feature);
302 str = std::format(
"{}, {}", str, feature);
307 return std::formatter<std::string, char>::format(str, fc);
311hi_export
namespace hi {
320 [[nodiscard]]
bool eax_bit(
int bit_nr)
const noexcept
322 return (eax & (1U << bit_nr)) != 0;
325 [[nodiscard]]
bool ebx_bit(
int bit_nr)
const noexcept
327 return (ebx & (1U << bit_nr)) != 0;
330 [[nodiscard]]
bool ecx_bit(
int bit_nr)
const noexcept
332 return (ecx & (1U << bit_nr)) != 0;
335 [[nodiscard]]
bool edx_bit(
int bit_nr)
const noexcept
337 return (edx & (1U << bit_nr)) != 0;
351#if HI_COMPILER == HI_CC_MSVC
353 __cpuidex(tmp.data(),
static_cast<int>(leaf_id),
static_cast<int>(index));
356#elif HI_COMPILER == HI_CC_GCC || HI_COMPILER == HI_CC_CLANG
357 __cpuid_count(leaf_id, index, r.eax, r.ebx, r.ecx, r.edx);
360#error "cpu_id() not implemented"
375 r |= cpu_feature::cmov;
378 r |= cpu_feature::cx8;
381 r |= cpu_feature::fpu;
384 r |= cpu_feature::fxsr;
387 r |= cpu_feature::osfxsr;
390 r |= cpu_feature::sce;
393 r |= cpu_feature::mmx;
396 r |= cpu_feature::sse;
399 r |= cpu_feature::sse2;
402 r |= cpu_feature::cx16;
405 r |= cpu_feature::lahf;
408 r |= cpu_feature::popcnt;
411 r |= cpu_feature::sse3;
414 r |= cpu_feature::sse4_1;
417 r |= cpu_feature::sse4_2;
420 r |= cpu_feature::ssse3;
423 r |= cpu_feature::lzcnt;
426 r |= cpu_feature::movbe;
429 r |= cpu_feature::osxsave;
432 r |= cpu_feature::f16c;
435 r |= cpu_feature::fma;
438 r |= cpu_feature::bmi1;
441 r |= cpu_feature::bmi2;
444 r |= cpu_feature::avx;
447 r |= cpu_feature::avx2;
450 r |= cpu_feature::avx512f;
453 r |= cpu_feature::avx512bw;
456 r |= cpu_feature::avx512cd;
459 r |= cpu_feature::avx512dq;
462 r |= cpu_feature::avx512vl;
465 r |= cpu_feature::avx512pf;
468 r |= cpu_feature::avx512er;
471 r |= cpu_feature::sha;
474 r |= cpu_feature::aes;
477 r |= cpu_feature::pclmul;
480 r |= cpu_feature::rdrnd;
483 r |= cpu_feature::rdseed;
494 auto const leaf0 =
cpu_id(0);
495 auto const max_leaf = leaf0.eax;
498 auto const leaf1 =
cpu_id(1);
500 if (leaf1.ecx_bit( 0)) { r |= cpu_feature::sse3; }
501 if (leaf1.ecx_bit( 1)) { r |= cpu_feature::pclmul; }
502 if (leaf1.ecx_bit( 9)) { r |= cpu_feature::ssse3; }
503 if (leaf1.ecx_bit(12)) { r |= cpu_feature::fma; }
504 if (leaf1.ecx_bit(13)) { r |= cpu_feature::cx16; }
505 if (leaf1.ecx_bit(19)) { r |= cpu_feature::sse4_1; }
506 if (leaf1.ecx_bit(20)) { r |= cpu_feature::sse4_2; }
507 if (leaf1.ecx_bit(22)) { r |= cpu_feature::movbe; }
508 if (leaf1.ecx_bit(23)) { r |= cpu_feature::popcnt; }
509 if (leaf1.ecx_bit(25)) { r |= cpu_feature::aes; }
510 if (leaf1.ecx_bit(27)) { r |= cpu_feature::osxsave; }
511 if (leaf1.ecx_bit(28)) { r |= cpu_feature::avx; }
512 if (leaf1.ecx_bit(29)) { r |= cpu_feature::f16c; }
513 if (leaf1.ecx_bit(30)) { r |= cpu_feature::rdrnd; }
515 if (leaf1.edx_bit( 0)) { r |= cpu_feature::fpu; }
516 if (leaf1.edx_bit( 8)) { r |= cpu_feature::cx8; }
517 if (leaf1.edx_bit(15)) { r |= cpu_feature::cmov; }
518 if (leaf1.edx_bit(23)) { r |= cpu_feature::mmx; }
519 if (leaf1.edx_bit(24)) {
520 r |= cpu_feature::fxsr;
523 r |= cpu_feature::osfxsr;
525 if (leaf1.edx_bit(25)) { r |= cpu_feature::sse; }
526 if (leaf1.edx_bit(26)) { r |= cpu_feature::sse2; }
530 auto const leaf7 =
cpu_id(7);
532 if (leaf7.ebx_bit( 3)) { r |= cpu_feature::bmi1; }
533 if (leaf7.ebx_bit( 5)) { r |= cpu_feature::avx2; }
534 if (leaf7.ebx_bit( 8)) { r |= cpu_feature::bmi2; }
535 if (leaf7.ebx_bit(16)) { r |= cpu_feature::avx512f; }
536 if (leaf7.ebx_bit(17)) { r |= cpu_feature::avx512dq; }
537 if (leaf7.ebx_bit(18)) { r |= cpu_feature::rdseed; }
538 if (leaf7.ebx_bit(26)) { r |= cpu_feature::avx512pf; }
539 if (leaf7.ebx_bit(27)) { r |= cpu_feature::avx512er; }
540 if (leaf7.ebx_bit(28)) { r |= cpu_feature::avx512cd; }
541 if (leaf7.ebx_bit(29)) { r |= cpu_feature::sha; }
542 if (leaf7.ebx_bit(30)) { r |= cpu_feature::avx512bw; }
543 if (leaf7.ebx_bit(31)) { r |= cpu_feature::avx512vl; }
546 auto const leaf80 =
cpu_id(0x8000'0000);
547 auto const max_leaf8 = leaf80.eax;
549 if (max_leaf8 >= 1) {
550 auto const leaf81 =
cpu_id(0x8000'0001);
552 if (leaf81.ecx_bit( 0)) { r |= cpu_feature::lahf; }
553 if (leaf81.ecx_bit( 5)) { r |= cpu_feature::lzcnt; }
556 if (leaf81.edx_bit(11)) { r |= cpu_feature::sce; }
559 if (
auto const missing_features = expected_cpu_features() - r; to_bool(missing_features)) {
566 auto const error_message = std::format(
567 "This executable is incompatible with the CPU in this computer.\n"
568 "The CPU is missing the following features:\n"
573 if (GetStdHandle(STD_ERROR_HANDLE) == NULL) {
576 MessageBoxA(NULL, error_message.c_str(), NULL, MB_OK | MB_ICONERROR);
581 std::println(
std::cerr,
"{}", error_message);
598 return detail::cpu_features;
606[[nodiscard]]
constexpr bool has_cmov() noexcept {
return true; }
614[[nodiscard]]
constexpr bool has_cx8() noexcept {
return true; }
622[[nodiscard]]
constexpr bool has_fpu() noexcept {
return true; }
630[[nodiscard]]
constexpr bool has_fxsr() noexcept {
return true; }
638[[nodiscard]]
constexpr bool has_osfxsr() noexcept {
return true; }
646[[nodiscard]]
constexpr bool has_sce() noexcept {
return true; }
654[[nodiscard]]
constexpr bool has_mmx() noexcept {
return true; }
662[[nodiscard]]
constexpr bool has_sse() noexcept {
return true; }
670[[nodiscard]]
constexpr bool has_sse2() noexcept {
return true; }
678[[nodiscard]]
constexpr bool has_x86_64_v1() noexcept {
return true; }
680[[nodiscard]]
inline bool has_x86_64_v1() noexcept {
return (
cpu_features() & cpu_feature_mask::x86_64_v1) == cpu_feature_mask::x86_64_v1; }
686[[nodiscard]]
constexpr bool has_cx16() noexcept {
return true; }
694[[nodiscard]]
constexpr bool has_lahf() noexcept {
return true; }
702[[nodiscard]]
constexpr bool has_popcnt() noexcept {
return true; }
710[[nodiscard]]
constexpr bool has_sse3() noexcept {
return true; }
718[[nodiscard]]
constexpr bool has_ssse3() noexcept {
return true; }
726[[nodiscard]]
constexpr bool has_sse4_1() noexcept {
return true; }
734[[nodiscard]]
constexpr bool has_sse4_2() noexcept {
return true; }
742[[nodiscard]]
constexpr bool has_x86_64_v2() noexcept {
return true; }
744[[nodiscard]]
inline bool has_x86_64_v2() noexcept {
return (
cpu_features() & cpu_feature_mask::x86_64_v2) == cpu_feature_mask::x86_64_v2; }
750[[nodiscard]]
constexpr bool has_f16c() noexcept {
return true; }
758[[nodiscard]]
constexpr bool has_fma() noexcept {
return true; }
766[[nodiscard]]
constexpr bool has_bmi1() noexcept {
return true; }
774[[nodiscard]]
constexpr bool has_bmi2() noexcept {
return true; }
782[[nodiscard]]
constexpr bool has_lzcnt() noexcept {
return true; }
790[[nodiscard]]
constexpr bool has_movbe() noexcept {
return true; }
798[[nodiscard]]
constexpr bool has_osxsave() noexcept {
return true; }
806[[nodiscard]]
constexpr bool has_avx() noexcept {
return true; }
814[[nodiscard]]
constexpr bool has_avx2() noexcept {
return true; }
822[[nodiscard]]
constexpr bool has_x86_64_v3() noexcept {
return true; }
824[[nodiscard]]
inline bool has_x86_64_v3() noexcept {
return (
cpu_features() & cpu_feature_mask::x86_64_v3) == cpu_feature_mask::x86_64_v3; }
830[[nodiscard]]
constexpr bool has_avx512f() noexcept {
return true; }
838[[nodiscard]]
constexpr bool has_avx512bw() noexcept {
return true; }
846[[nodiscard]]
constexpr bool has_avx512cd() noexcept {
return true; }
854[[nodiscard]]
constexpr bool has_avx512dq() noexcept {
return true; }
862[[nodiscard]]
constexpr bool has_avx512vl() noexcept {
return true; }
870[[nodiscard]]
constexpr bool has_x86_64_v4() noexcept {
return true; }
872[[nodiscard]]
inline bool has_x86_64_v4() noexcept {
return (
cpu_features() & cpu_feature_mask::x86_64_v4) == cpu_feature_mask::x86_64_v4; }
878[[nodiscard]]
constexpr bool has_avx512pf() noexcept {
return true; }
886[[nodiscard]]
constexpr bool has_avx512er() noexcept {
return true; }
894[[nodiscard]]
constexpr bool has_sha() noexcept {
return true; }
902[[nodiscard]]
constexpr bool has_aes() noexcept {
return true; }
910[[nodiscard]]
constexpr bool has_pclmul() noexcept {
return true; }
918[[nodiscard]]
constexpr bool has_rdrnd() noexcept {
return true; }
926[[nodiscard]]
constexpr bool has_rdseed() noexcept {
return true; }
The HikoGUI namespace.
Definition array_generic.hpp:20
bool has_mmx() noexcept
This CPU has the MMX instruction set.
Definition cpu_id_x86.hpp:656
bool has_fxsr() noexcept
This CPU has the fxsave instruction.
Definition cpu_id_x86.hpp:632
bool has_sse4_1() noexcept
This CPU has the SSE4.1 instruction set.
Definition cpu_id_x86.hpp:728
bool has_bmi2() noexcept
This CPU has the BMI2 instruction set.
Definition cpu_id_x86.hpp:776
bool has_fpu() noexcept
This CPU has a floating-point co-processor.
Definition cpu_id_x86.hpp:624
cpu_feature_mask cpu_features() noexcept
Get a list of features of the current CPU.
Definition cpu_id_x86.hpp:596
bool has_sse4_2() noexcept
This CPU has the SSE4.2 instruction set.
Definition cpu_id_x86.hpp:736
bool has_x86_64_v4() noexcept
This CPU has all the features for x86-64-v4 microarchitecture level.
Definition cpu_id_x86.hpp:872
bool has_cx16() noexcept
This CPU has the CMPXCG16 (Compare and exchange 16 bytes) instruction.
Definition cpu_id_x86.hpp:688
bool has_avx() noexcept
This CPU has the AVX instruction set.
Definition cpu_id_x86.hpp:808
bool has_rdseed() noexcept
This CPU has the RDSEED access to the conditioned on-chip entropy.
Definition cpu_id_x86.hpp:928
bool has_rdrnd() noexcept
This CPU has the RDRAND on-chip random number generator instruction.
Definition cpu_id_x86.hpp:920
bool has_sse() noexcept
This CPU has the SSE instruction set.
Definition cpu_id_x86.hpp:664
bool has_cx8() noexcept
This CPU has the CMPXCG8 (Compare and exchange 8 bytes) instruction.
Definition cpu_id_x86.hpp:616
bool has_avx512vl() noexcept
This CPU has the AVX512VL instruction set.
Definition cpu_id_x86.hpp:864
bool has_x86_64_v1() noexcept
This CPU has all the features for x86-64-v1 microarchitecture level.
Definition cpu_id_x86.hpp:680
bool has_cmov() noexcept
This CPU has the CMOV (Conditional Move) instruction.
Definition cpu_id_x86.hpp:608
bool has_lahf() noexcept
This CPU has the LAHF and SAHF instructions.
Definition cpu_id_x86.hpp:696
bool has_avx512pf() noexcept
This CPU has the AVX512PF instruction set.
Definition cpu_id_x86.hpp:880
bool has_sha() noexcept
This CPU has the SHA cryptographical secure hash instruction set.
Definition cpu_id_x86.hpp:896
bool has_sce() noexcept
This operating system uses the SYSCALL instruction.
Definition cpu_id_x86.hpp:648
bool has_pclmul() noexcept
This CPU has the PCLMUL carry-less multiply instruction.
Definition cpu_id_x86.hpp:912
bool has_avx512bw() noexcept
This CPU has the AVX512BW instruction set.
Definition cpu_id_x86.hpp:840
bool has_avx512dq() noexcept
This CPU has the AVX512DQ instruction set.
Definition cpu_id_x86.hpp:856
bool has_sse3() noexcept
This CPU has the SSE3 instruction set.
Definition cpu_id_x86.hpp:712
bool has_osxsave() noexcept
This operating system uses the SXSAVE instruction.
Definition cpu_id_x86.hpp:800
bool has_popcnt() noexcept
This CPU has the POPCNT instructions.
Definition cpu_id_x86.hpp:704
cpu_feature_mask
A mask of features.
Definition cpu_id_x86.hpp:198
bool has_sse2() noexcept
This CPU has the SSE2 instruction set.
Definition cpu_id_x86.hpp:672
bool has_x86_64_v2() noexcept
This CPU has all the features for x86-64-v2 microarchitecture level.
Definition cpu_id_x86.hpp:744
cpu_feature
Possible features of x86 CPUs.
Definition cpu_id_x86.hpp:76
cpu_id_result cpu_id(uint32_t leaf_id, uint32_t index=0) noexcept
A generic x86 cpu-id instruction.
Definition cpu_id_x86.hpp:347
bool has_fma() noexcept
This CPU has fused-multiply-accumulate instructions.
Definition cpu_id_x86.hpp:760
bool has_f16c() noexcept
This CPU has float-16 conversion instructions.
Definition cpu_id_x86.hpp:752
bool has_lzcnt() noexcept
This CPU has the LZCNT instruction.
Definition cpu_id_x86.hpp:784
bool has_ssse3() noexcept
This CPU has the SSSE3 instruction set.
Definition cpu_id_x86.hpp:720
bool has_avx512cd() noexcept
This CPU has the AVX512CD instruction set.
Definition cpu_id_x86.hpp:848
bool has_avx512er() noexcept
This CPU has the AVX512ER instruction set.
Definition cpu_id_x86.hpp:888
bool has_osfxsr() noexcept
This operating system uses the FXSAVE instruction.
Definition cpu_id_x86.hpp:640
bool has_avx512f() noexcept
This CPU has the AVX512F instruction set.
Definition cpu_id_x86.hpp:832
bool has_avx2() noexcept
This CPU has the AVX2 instruction set.
Definition cpu_id_x86.hpp:816
bool has_aes() noexcept
This CPU has the AES-NI block cypher instruction set.
Definition cpu_id_x86.hpp:904
bool has_movbe() noexcept
This CPU has the MOVBE (Move Big Endian) instruction.
Definition cpu_id_x86.hpp:792
bool has_bmi1() noexcept
This CPU has the BMI1 instruction set.
Definition cpu_id_x86.hpp:768
bool has_x86_64_v3() noexcept
This CPU has all the features for x86-64-v3 microarchitecture level.
Definition cpu_id_x86.hpp:824
DOXYGEN BUG.
Definition algorithm_misc.hpp:20
Definition cpu_id_x86.hpp:314