Created
July 14, 2021 12:33
-
-
Save christianparpart/0a7f577f5c9c0c8764da20467abe6bc0 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <array> | |
#include <cassert> | |
#include <iomanip> | |
#include <iostream> | |
#include <limits> | |
#include <string_view> | |
#include <tuple> | |
#include <utility> | |
#include <immintrin.h> | |
#include <cpuid.h> | |
namespace cpu | |
{ | |
enum class feature | |
{ | |
SSE = 0, | |
SSE2, | |
SSE3, | |
SSE4_1, | |
SSE4_2, | |
FMA, | |
BMI, | |
BMI2, | |
AVX, | |
AVX2, | |
AVX512F, | |
AVX512BW, | |
AVX512DQ, | |
AVX512VBMI, | |
}; | |
std::string_view to_string(feature _f) | |
{ | |
using namespace std::string_view_literals; | |
auto constexpr names = std::array{ | |
"SSE"sv, | |
"SSE2"sv, | |
"SSE3"sv, | |
"SSE4.1"sv, | |
"SSE4.2"sv, | |
"FMA"sv, | |
"BMI"sv, | |
"BMI2"sv, | |
"AVX"sv, | |
"AVX2"sv, | |
"AVX512F"sv, | |
"AVX512BW"sv, | |
"AVX512DQ"sv, | |
"AVX512VBMI"sv, | |
}; | |
return names.at(static_cast<size_t>(_f)); | |
} | |
} | |
namespace std | |
{ | |
template <> | |
struct numeric_limits<cpu::feature> { | |
static size_t min() { return 0; } | |
static size_t max() { return 13; } | |
}; | |
} | |
namespace cpu | |
{ | |
inline bool is_available(feature _feature) noexcept | |
{ | |
using namespace std; | |
enum class reg : uint8_t { eax, ebx, ecx, edx }; | |
constexpr auto mappings = array{ | |
tuple{feature::SSE, reg::edx, bit_SSE}, | |
tuple{feature::SSE2, reg::edx, bit_SSE2}, | |
tuple{feature::SSE3, reg::ecx, bit_SSE3}, | |
tuple{feature::SSE4_1, reg::ecx, bit_SSE4_1}, | |
tuple{feature::SSE4_2, reg::ecx, bit_SSE4_2}, | |
tuple{feature::FMA, reg::ecx, bit_FMA}, | |
tuple{feature::BMI, reg::ebx, bit_BMI}, | |
tuple{feature::BMI2, reg::ebx, bit_BMI2}, | |
tuple{feature::AVX, reg::ecx, bit_AVX}, | |
tuple{feature::AVX2, reg::ebx, bit_AVX2}, | |
tuple{feature::AVX512F, reg::ebx, bit_AVX512F}, | |
tuple{feature::AVX512BW, reg::ebx, bit_AVX512BW}, | |
tuple{feature::AVX512DQ, reg::ebx, bit_AVX512DQ}, | |
tuple{feature::AVX512VBMI, reg::ecx, bit_AVX512VBMI}, | |
tuple{feature::AVX512VBMI, reg::ecx, bit_AVX512VBMI2}, | |
}; | |
auto regs = array<unsigned, 4>{0, 0, 0, 0}; | |
__get_cpuid(1, ®s[0], ®s[1], ®s[2], ®s[3]); | |
assert( get<0>(mappings[static_cast<uint8_t>(_feature)]) == _feature); | |
auto const reg = get<1>(mappings[static_cast<uint8_t>(_feature)]); | |
auto const bit = get<2>(mappings[static_cast<uint8_t>(_feature)]); | |
return (regs[static_cast<uint8_t>(reg)] & bit) ? true : false; | |
} | |
} | |
int main() | |
{ | |
using namespace std; | |
for (auto i = numeric_limits<cpu::feature>::min(); | |
i <= numeric_limits<cpu::feature>::max(); | |
++i) | |
{ | |
auto const feature = static_cast<cpu::feature>(i); | |
cout << setw(20) << cpu::to_string(feature) << ": " | |
<< (cpu::is_available(feature) ? "supported" : "not supported") | |
<< endl; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment