HikoGUI
A low latency retained GUI
Loading...
Searching...
No Matches
cpu_id_x86.hpp
1// Copyright Take Vos 2019, 2021.
2// Distributed under the Boost Software License, Version 1.0.
3// (See accompanying file LICENSE_1_0.txt or copy at https://www.boost.org/LICENSE_1_0.txt)
4
5#pragma once
6
7#include "macros.hpp"
8
9#if defined(_WIN32)
10#include <Windows.h>
11#endif
12
13#include <array>
14#include <utility>
15#include <cstdint>
16#include <format>
17#include <bit>
18#include <print>
19#include <iostream>
20
21#if HI_COMPILER == HI_CC_MSVC
22#include <intrin.h>
23#elif HI_COMPILER == HI_CC_GCC || HI_COMPILER == HI_CC_CLANG
24#include <cpuid.h>
25#else
26#error "Unsupported compiler for x64 cpu_id"
27#endif
28
60hi_export_module(hikocpu : cpu_id);
61
62namespace hi { inline namespace v1 {
63
76enum class cpu_feature : uint8_t {
77 // x86-64-v1
78 cmov,
79 cx8,
80 fpu,
81 fxsr,
82 mmx,
83 osfxsr,
84 sce,
85 sse,
86 sse2,
87 // x86-64-v2
88 cx16,
89 lahf,
90 popcnt,
91 sse3,
92 sse4_1,
93 sse4_2,
94 ssse3,
95 // x86-64-v3
96 avx,
97 avx2,
98 bmi1,
99 bmi2,
100 f16c,
101 fma,
102 lzcnt,
103 movbe,
104 osxsave,
105 // x86-64-v4
106 avx512f,
107 avx512bw,
108 avx512cd,
109 avx512dq,
110 avx512vl,
111 // others
112 avx512pf,
113 avx512er,
114 sha,
115 aes,
116 pclmul,
117 rdrnd,
118 rdseed,
119};
120
121constexpr auto cpu_feature_metadata_init() noexcept
122{
123 // At most 64 cpu_feature flags are allowed.
125
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";
163 return r;
164}
165
166constexpr auto cpu_feature_metadata = cpu_feature_metadata_init();
167
168}} // namespace hi::v1
169
170hi_export template<>
171struct std::formatter<::hi::cpu_feature, char> : std::formatter<std::string_view, char> {
172 auto format(::hi::cpu_feature const& t, auto& fc) const
173 {
174 return std::formatter<std::string_view, char>::format(::hi::cpu_feature_metadata[std::to_underlying(t)], fc);
175 }
176};
177
178hi_export namespace hi {
179inline namespace v1 {
180
181template<std::integral Lhs>
182[[nodiscard]] constexpr unsigned long long operator<<(Lhs const& lhs, cpu_feature const& rhs)
183{
184 if (not std::cmp_equal(lhs, 1)) {
185 throw std::logic_error("lhs of a cpu_feature shift must be 1.");
186 }
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");
189 }
190
191 return static_cast<unsigned long long>(lhs) << std::to_underlying(rhs);
192}
193
198enum class cpu_feature_mask : uint64_t {
199 none = 0,
200
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,
211
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,
220
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,
231
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,
238
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,
246};
247
248[[nodiscard]] constexpr cpu_feature_mask operator|(cpu_feature_mask const& lhs, cpu_feature_mask const& rhs) noexcept
249{
250 return static_cast<cpu_feature_mask>(std::to_underlying(lhs) | std::to_underlying(rhs));
251}
252
253[[nodiscard]] constexpr cpu_feature_mask operator&(cpu_feature_mask const& lhs, cpu_feature_mask const& rhs) noexcept
254{
255 return static_cast<cpu_feature_mask>(std::to_underlying(lhs) & std::to_underlying(rhs));
256}
257
258[[nodiscard]] constexpr cpu_feature_mask operator-(cpu_feature_mask const& lhs, cpu_feature_mask const& rhs) noexcept
259{
260 return static_cast<cpu_feature_mask>(std::to_underlying(lhs) & ~std::to_underlying(rhs));
261}
262
263[[nodiscard]] constexpr bool to_bool(cpu_feature_mask const& rhs) noexcept
264{
265 return std::to_underlying(rhs) != 0;
266}
267
268[[nodiscard]] constexpr cpu_feature_mask operator|(cpu_feature_mask const& lhs, cpu_feature const& rhs) noexcept
269{
270 auto const rhs_ = static_cast<cpu_feature_mask>(1 << rhs);
271 return lhs | rhs_;
272}
273
274[[nodiscard]] constexpr cpu_feature_mask operator&(cpu_feature_mask const& lhs, cpu_feature const& rhs) noexcept
275{
276 auto const rhs_ = static_cast<cpu_feature_mask>(1 << rhs);
277 return lhs & rhs_;
278}
279
280constexpr cpu_feature_mask& operator|=(cpu_feature_mask& lhs, cpu_feature const& rhs) noexcept
281{
282 return lhs = lhs | rhs;
283}
284
285} // namespace v1
286}
287
288hi_export template<>
289struct std::formatter<::hi::cpu_feature_mask, char> : std::formatter<std::string, char> {
290 auto format(::hi::cpu_feature_mask const& t, auto& fc) const
291 {
292 using mask_type = std::underlying_type_t<::hi::cpu_feature_mask>;
293
294 auto str = std::string{};
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));
298
299 if (str.empty()) {
300 str = std::format("{}", feature);
301 } else {
302 str = std::format("{}, {}", str, feature);
303 }
304 }
305 }
306
307 return std::formatter<std::string, char>::format(str, fc);
308 }
309};
310
311hi_export namespace hi {
312inline namespace v1 {
313
315 uint32_t eax;
316 uint32_t ebx;
317 uint32_t ecx;
318 uint32_t edx;
319
320 [[nodiscard]] bool eax_bit(int bit_nr) const noexcept
321 {
322 return (eax & (1U << bit_nr)) != 0;
323 }
324
325 [[nodiscard]] bool ebx_bit(int bit_nr) const noexcept
326 {
327 return (ebx & (1U << bit_nr)) != 0;
328 }
329
330 [[nodiscard]] bool ecx_bit(int bit_nr) const noexcept
331 {
332 return (ecx & (1U << bit_nr)) != 0;
333 }
334
335 [[nodiscard]] bool edx_bit(int bit_nr) const noexcept
336 {
337 return (edx & (1U << bit_nr)) != 0;
338 }
339};
340
347[[nodiscard]] inline cpu_id_result cpu_id(uint32_t leaf_id, uint32_t index = 0) noexcept
348{
349 auto r = cpu_id_result{};
350
351#if HI_COMPILER == HI_CC_MSVC
352 auto tmp = std::array<int, 4>{};
353 __cpuidex(tmp.data(), static_cast<int>(leaf_id), static_cast<int>(index));
354 std::memcpy(&r, tmp.data(), sizeof(cpu_id_result));
355
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);
358
359#else
360#error "cpu_id() not implemented"
361#endif
362
363 return r;
364}
365
366namespace detail {
367
370[[nodiscard]] constexpr cpu_feature_mask expected_cpu_features() noexcept
371{
372 auto r = cpu_feature_mask{};
373
374#if HI_HAS_CMOV
375 r |= cpu_feature::cmov;
376#endif
377#if HI_HAS_CX8
378 r |= cpu_feature::cx8;
379#endif
380#if HI_HAS_FPU
381 r |= cpu_feature::fpu;
382#endif
383#if HI_HAS_FXSR
384 r |= cpu_feature::fxsr;
385#endif
386#if HI_HAS_OSFXSR
387 r |= cpu_feature::osfxsr;
388#endif
389#if HI_HAS_SCE
390 r |= cpu_feature::sce;
391#endif
392#if HI_HAS_MMX
393 r |= cpu_feature::mmx;
394#endif
395#if HI_HAS_SSE
396 r |= cpu_feature::sse;
397#endif
398#if HI_HAS_SSE2
399 r |= cpu_feature::sse2;
400#endif
401#if HI_HAS_CX16
402 r |= cpu_feature::cx16;
403#endif
404#if HI_HAS_LAHF
405 r |= cpu_feature::lahf;
406#endif
407#if HI_HAS_POPCNT
408 r |= cpu_feature::popcnt;
409#endif
410#if HI_HAS_SSE3
411 r |= cpu_feature::sse3;
412#endif
413#if HI_HAS_SSE4_1
414 r |= cpu_feature::sse4_1;
415#endif
416#if HI_HAS_SSE4_2
417 r |= cpu_feature::sse4_2;
418#endif
419#if HI_HAS_SSSE3
420 r |= cpu_feature::ssse3;
421#endif
422#if HI_HAS_LZCNT
423 r |= cpu_feature::lzcnt;
424#endif
425#if HI_HAS_MOVBE
426 r |= cpu_feature::movbe;
427#endif
428#if HI_HAS_OSXSAVE
429 r |= cpu_feature::osxsave;
430#endif
431#if HI_HAS_F16C
432 r |= cpu_feature::f16c;
433#endif
434#if HI_HAS_FMA
435 r |= cpu_feature::fma;
436#endif
437#if HI_HAS_BMI1
438 r |= cpu_feature::bmi1;
439#endif
440#if HI_HAS_BMI2
441 r |= cpu_feature::bmi2;
442#endif
443#if HI_HAS_AVX
444 r |= cpu_feature::avx;
445#endif
446#if HI_HAS_AVX2
447 r |= cpu_feature::avx2;
448#endif
449#if HI_HAS_AVX512F
450 r |= cpu_feature::avx512f;
451#endif
452#if HI_HAS_AVX512BW
453 r |= cpu_feature::avx512bw;
454#endif
455#if HI_HAS_AVX512CD
456 r |= cpu_feature::avx512cd;
457#endif
458#if HI_HAS_AVX512DQ
459 r |= cpu_feature::avx512dq;
460#endif
461#if HI_HAS_AVX512VL
462 r |= cpu_feature::avx512vl;
463#endif
464#if HI_HAS_AVX512PF
465 r |= cpu_feature::avx512pf;
466#endif
467#if HI_HAS_AVX512ER
468 r |= cpu_feature::avx512er;
469#endif
470#if HI_HAS_SHA
471 r |= cpu_feature::sha;
472#endif
473#if HI_HAS_AES
474 r |= cpu_feature::aes;
475#endif
476#if HI_HAS_PCLMUL
477 r |= cpu_feature::pclmul;
478#endif
479#if HI_HAS_RDRND
480 r |= cpu_feature::rdrnd;
481#endif
482#if HI_HAS_RDSEED
483 r |= cpu_feature::rdseed;
484#endif
485
486 return r;
487}
488
489[[nodiscard]] inline cpu_feature_mask cpu_features_init() noexcept
490{
491 // clang-format off
492 auto r = cpu_feature_mask{};
493
494 auto const leaf0 = cpu_id(0);
495 auto const max_leaf = leaf0.eax;
496
497 if (max_leaf >= 1) {
498 auto const leaf1 = cpu_id(1);
499
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; }
514
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;
521 // Technically we need to read CR4, but this may be privileged.
522 // Moden operating system do support it though.
523 r |= cpu_feature::osfxsr;
524 }
525 if (leaf1.edx_bit(25)) { r |= cpu_feature::sse; }
526 if (leaf1.edx_bit(26)) { r |= cpu_feature::sse2; }
527 }
528
529 if (max_leaf >= 7) {
530 auto const leaf7 = cpu_id(7);
531
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; }
544 }
545
546 auto const leaf80 = cpu_id(0x8000'0000);
547 auto const max_leaf8 = leaf80.eax;
548
549 if (max_leaf8 >= 1) {
550 auto const leaf81 = cpu_id(0x8000'0001);
551
552 if (leaf81.ecx_bit( 0)) { r |= cpu_feature::lahf; }
553 if (leaf81.ecx_bit( 5)) { r |= cpu_feature::lzcnt; }
554
555 // edx[10] sce (only on AuthenticAMD Family 5 Model 7 CPUs)
556 if (leaf81.edx_bit(11)) { r |= cpu_feature::sce; }
557 }
558
559 if (auto const missing_features = expected_cpu_features() - r; to_bool(missing_features)) {
560 // On windows the console will not be attached to gui-executables,
561 // even if they where started from the console. start_console() will
562 // attach to the console if one exists, so that std::print() will work
563 // correctly.
564 //start_console();
565
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"
569 " {}",
570 missing_features);
571
572#if defined(_WIN32)
573 if (GetStdHandle(STD_ERROR_HANDLE) == NULL) {
574 // The application is not attached to the console, so probably a
575 // GUI application. Lets hope that ANSI code-page is set to UTF-8.
576 MessageBoxA(NULL, error_message.c_str(), NULL, MB_OK | MB_ICONERROR);
578 }
579#endif
580
581 std::println(std::cerr, "{}", error_message);
583 }
584
585 return r;
586}
587
590inline cpu_feature_mask const cpu_features = detail::cpu_features_init();
591
592}
593
596[[nodiscard]] inline cpu_feature_mask cpu_features() noexcept
597{
598 return detail::cpu_features;
599}
600
601// clang-format off
602
605#if HI_HAS_CMOV
606[[nodiscard]] constexpr bool has_cmov() noexcept { return true; }
607#else
608[[nodiscard]] inline bool has_cmov() noexcept { return to_bool(cpu_features() & cpu_feature::cmov); }
609#endif
610
613#if HI_HAS_CX8
614[[nodiscard]] constexpr bool has_cx8() noexcept { return true; }
615#else
616[[nodiscard]] inline bool has_cx8() noexcept { return to_bool(cpu_features() & cpu_feature::cx8); }
617#endif
618
621#if HI_HAS_FPU
622[[nodiscard]] constexpr bool has_fpu() noexcept { return true; }
623#else
624[[nodiscard]] inline bool has_fpu() noexcept { return to_bool(cpu_features() & cpu_feature::fpu); }
625#endif
626
629#if HI_HAS_FXSR
630[[nodiscard]] constexpr bool has_fxsr() noexcept { return true; }
631#else
632[[nodiscard]] inline bool has_fxsr() noexcept { return to_bool(cpu_features() & cpu_feature::fxsr); }
633#endif
634
637#if HI_HAS_OSFXSR
638[[nodiscard]] constexpr bool has_osfxsr() noexcept { return true; }
639#else
640[[nodiscard]] inline bool has_osfxsr() noexcept { return to_bool(cpu_features() & cpu_feature::osfxsr); }
641#endif
642
645#if HI_HAS_SCE
646[[nodiscard]] constexpr bool has_sce() noexcept { return true; }
647#else
648[[nodiscard]] inline bool has_sce() noexcept { return to_bool(cpu_features() & cpu_feature::sce); }
649#endif
650
653#if HI_HAS_MMX
654[[nodiscard]] constexpr bool has_mmx() noexcept { return true; }
655#else
656[[nodiscard]] inline bool has_mmx() noexcept { return to_bool(cpu_features() & cpu_feature::mmx); }
657#endif
658
661#if HI_HAS_SSE
662[[nodiscard]] constexpr bool has_sse() noexcept { return true; }
663#else
664[[nodiscard]] inline bool has_sse() noexcept { return to_bool(cpu_features() & cpu_feature::sse); }
665#endif
666
669#if HI_HAS_SSE2
670[[nodiscard]] constexpr bool has_sse2() noexcept { return true; }
671#else
672[[nodiscard]] inline bool has_sse2() noexcept { return to_bool(cpu_features() & cpu_feature::sse2); }
673#endif
674
677#if HI_HAS_X86_64_V1
678[[nodiscard]] constexpr bool has_x86_64_v1() noexcept { return true; }
679#else
680[[nodiscard]] inline bool has_x86_64_v1() noexcept { return (cpu_features() & cpu_feature_mask::x86_64_v1) == cpu_feature_mask::x86_64_v1; }
681#endif
682
685#if HI_HAS_CX16
686[[nodiscard]] constexpr bool has_cx16() noexcept { return true; }
687#else
688[[nodiscard]] inline bool has_cx16() noexcept { return to_bool(cpu_features() & cpu_feature::cx16); }
689#endif
690
693#if HI_HAS_LAHF
694[[nodiscard]] constexpr bool has_lahf() noexcept { return true; }
695#else
696[[nodiscard]] inline bool has_lahf() noexcept { return to_bool(cpu_features() & cpu_feature::lahf); }
697#endif
698
701#if HI_HAS_POPCNT
702[[nodiscard]] constexpr bool has_popcnt() noexcept { return true; }
703#else
704[[nodiscard]] inline bool has_popcnt() noexcept { return to_bool(cpu_features() & cpu_feature::popcnt); }
705#endif
706
709#if HI_HAS_SSE3
710[[nodiscard]] constexpr bool has_sse3() noexcept { return true; }
711#else
712[[nodiscard]] inline bool has_sse3() noexcept { return to_bool(cpu_features() & cpu_feature::sse3); }
713#endif
714
717#if HI_HAS_SSSE3
718[[nodiscard]] constexpr bool has_ssse3() noexcept { return true; }
719#else
720[[nodiscard]] inline bool has_ssse3() noexcept { return to_bool(cpu_features() & cpu_feature::ssse3); }
721#endif
722
725#if HI_HAS_SSE4_1
726[[nodiscard]] constexpr bool has_sse4_1() noexcept { return true; }
727#else
728[[nodiscard]] inline bool has_sse4_1() noexcept { return to_bool(cpu_features() & cpu_feature::sse4_1); }
729#endif
730
733#if HI_HAS_SSE4_2
734[[nodiscard]] constexpr bool has_sse4_2() noexcept { return true; }
735#else
736[[nodiscard]] inline bool has_sse4_2() noexcept { return to_bool(cpu_features() & cpu_feature::sse4_2); }
737#endif
738
741#if HI_HAS_X86_64_V2
742[[nodiscard]] constexpr bool has_x86_64_v2() noexcept { return true; }
743#else
744[[nodiscard]] inline bool has_x86_64_v2() noexcept { return (cpu_features() & cpu_feature_mask::x86_64_v2) == cpu_feature_mask::x86_64_v2; }
745#endif
746
749#if HI_HAS_F16C
750[[nodiscard]] constexpr bool has_f16c() noexcept { return true; }
751#else
752[[nodiscard]] inline bool has_f16c() noexcept { return to_bool(cpu_features() & cpu_feature::f16c); }
753#endif
754
757#if HI_HAS_FMA
758[[nodiscard]] constexpr bool has_fma() noexcept { return true; }
759#else
760[[nodiscard]] inline bool has_fma() noexcept { return to_bool(cpu_features() & cpu_feature::fma); }
761#endif
762
765#if HI_HAS_BMI1
766[[nodiscard]] constexpr bool has_bmi1() noexcept { return true; }
767#else
768[[nodiscard]] inline bool has_bmi1() noexcept { return to_bool(cpu_features() & cpu_feature::bmi1); }
769#endif
770
773#if HI_HAS_BMI2
774[[nodiscard]] constexpr bool has_bmi2() noexcept { return true; }
775#else
776[[nodiscard]] inline bool has_bmi2() noexcept { return to_bool(cpu_features() & cpu_feature::bmi2); }
777#endif
778
781#if HI_HAS_LZCNT
782[[nodiscard]] constexpr bool has_lzcnt() noexcept { return true; }
783#else
784[[nodiscard]] inline bool has_lzcnt() noexcept { return to_bool(cpu_features() & cpu_feature::lzcnt); }
785#endif
786
789#if HI_HAS_MOVBE
790[[nodiscard]] constexpr bool has_movbe() noexcept { return true; }
791#else
792[[nodiscard]] inline bool has_movbe() noexcept { return to_bool(cpu_features() & cpu_feature::movbe); }
793#endif
794
797#if HI_HAS_OSXSAVE
798[[nodiscard]] constexpr bool has_osxsave() noexcept { return true; }
799#else
800[[nodiscard]] inline bool has_osxsave() noexcept { return to_bool(cpu_features() & cpu_feature::osxsave); }
801#endif
802
805#if HI_HAS_AVX
806[[nodiscard]] constexpr bool has_avx() noexcept { return true; }
807#else
808[[nodiscard]] inline bool has_avx() noexcept { return to_bool(cpu_features() & cpu_feature::avx); }
809#endif
810
813#if HI_HAS_AVX2
814[[nodiscard]] constexpr bool has_avx2() noexcept { return true; }
815#else
816[[nodiscard]] inline bool has_avx2() noexcept { return to_bool(cpu_features() & cpu_feature::avx2); }
817#endif
818
821#if HI_HAS_X86_64_V3
822[[nodiscard]] constexpr bool has_x86_64_v3() noexcept { return true; }
823#else
824[[nodiscard]] inline bool has_x86_64_v3() noexcept { return (cpu_features() & cpu_feature_mask::x86_64_v3) == cpu_feature_mask::x86_64_v3; }
825#endif
826
829#if HI_HAS_AVX512F
830[[nodiscard]] constexpr bool has_avx512f() noexcept { return true; }
831#else
832[[nodiscard]] inline bool has_avx512f() noexcept { return to_bool(cpu_features() & cpu_feature::avx512f); }
833#endif
834
837#if HI_HAS_AVX512BW
838[[nodiscard]] constexpr bool has_avx512bw() noexcept { return true; }
839#else
840[[nodiscard]] inline bool has_avx512bw() noexcept { return to_bool(cpu_features() & cpu_feature::avx512bw); }
841#endif
842
845#if HI_HAS_AVX512CD
846[[nodiscard]] constexpr bool has_avx512cd() noexcept { return true; }
847#else
848[[nodiscard]] inline bool has_avx512cd() noexcept { return to_bool(cpu_features() & cpu_feature::avx512cd); }
849#endif
850
853#if HI_HAS_AVX512DQ
854[[nodiscard]] constexpr bool has_avx512dq() noexcept { return true; }
855#else
856[[nodiscard]] inline bool has_avx512dq() noexcept { return to_bool(cpu_features() & cpu_feature::avx512dq); }
857#endif
858
861#if HI_HAS_AVX512VL
862[[nodiscard]] constexpr bool has_avx512vl() noexcept { return true; }
863#else
864[[nodiscard]] inline bool has_avx512vl() noexcept { return to_bool(cpu_features() & cpu_feature::avx512vl); }
865#endif
866
869#if HI_HAS_X86_64_V4
870[[nodiscard]] constexpr bool has_x86_64_v4() noexcept { return true; }
871#else
872[[nodiscard]] inline bool has_x86_64_v4() noexcept { return (cpu_features() & cpu_feature_mask::x86_64_v4) == cpu_feature_mask::x86_64_v4; }
873#endif
874
877#if HI_HAS_AVX512PF
878[[nodiscard]] constexpr bool has_avx512pf() noexcept { return true; }
879#else
880[[nodiscard]] inline bool has_avx512pf() noexcept { return to_bool(cpu_features() & cpu_feature::avx512pf); }
881#endif
882
885#if HI_HAS_AVX512ER
886[[nodiscard]] constexpr bool has_avx512er() noexcept { return true; }
887#else
888[[nodiscard]] inline bool has_avx512er() noexcept { return to_bool(cpu_features() & cpu_feature::avx512er); }
889#endif
890
893#if HI_HAS_SHA
894[[nodiscard]] constexpr bool has_sha() noexcept { return true; }
895#else
896[[nodiscard]] inline bool has_sha() noexcept { return to_bool(cpu_features() & cpu_feature::sha); }
897#endif
898
901#if HI_HAS_AES
902[[nodiscard]] constexpr bool has_aes() noexcept { return true; }
903#else
904[[nodiscard]] inline bool has_aes() noexcept { return to_bool(cpu_features() & cpu_feature::aes); }
905#endif
906
909#if HI_HAS_AES
910[[nodiscard]] constexpr bool has_pclmul() noexcept { return true; }
911#else
912[[nodiscard]] inline bool has_pclmul() noexcept { return to_bool(cpu_features() & cpu_feature::pclmul); }
913#endif
914
917#if HI_HAS_RDRND
918[[nodiscard]] constexpr bool has_rdrnd() noexcept { return true; }
919#else
920[[nodiscard]] inline bool has_rdrnd() noexcept { return to_bool(cpu_features() & cpu_feature::rdrnd); }
921#endif
922
925#if HI_HAS_RDSEED
926[[nodiscard]] constexpr bool has_rdseed() noexcept { return true; }
927#else
928[[nodiscard]] inline bool has_rdseed() noexcept { return to_bool(cpu_features() & cpu_feature::rdseed); }
929#endif
930
931// clang-format on
932
933} // namespace v1
934}
STL namespace.
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
T memcpy(T... args)
T terminate(T... args)