Skip to content

Instantly share code, notes, and snippets.

@christianparpart
Created July 14, 2021 12:33
Show Gist options
  • Save christianparpart/0a7f577f5c9c0c8764da20467abe6bc0 to your computer and use it in GitHub Desktop.
Save christianparpart/0a7f577f5c9c0c8764da20467abe6bc0 to your computer and use it in GitHub Desktop.
#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, &regs[0], &regs[1], &regs[2], &regs[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