Bonita Montero
2024-04-28 15:31:29 UTC
This is just overengineered ?
#include <iostream>
#include <intrin.h>
using namespace std;
int main()
{
struct feature_t
{
uint8_t id, leaf;
uint8_t reg, bit;
string_view descr;
};
enum { EAX, EBX, ECX, EDX };
static feature_t const features[] =
{
{ 7, 0, EBX, 16, "AVX512F" },
{ 7, 0, EBX, 17, "AVX512DQ" },
{ 7, 0, EBX, 21, "AVX512IFMA" },
{ 7, 0, EBX, 26, "AVX512PF" },
{ 7, 0, EBX, 27, "AVX512ER" },
{ 7, 0, EBX, 28, "AVX512CD" },
{ 7, 0, EBX, 30, "AVX512BW" },
{ 7, 0, EBX, 31, "AVX512VL" },
{ 7, 0, ECX, 0, "AVX512_VBMI" },
{ 7, 0, ECX, 6, "AVX512_VBMI2" },
{ 7, 0, ECX, 11, "AVX512_VNNI" },
{ 7, 0, ECX, 12, "AVX512_BITALG" },
{ 7, 0, ECX, 14, "AVX512_VPOPCNTDQ" },
{ 7, 0, EDX, 2, "AVX512_4VNNIW" },
{ 7, 0, EDX, 3, "AVX512_4FMAPS" },
{ 7, 0, EDX, 8, "AVX512_VP2INTERSECT" },
{ 7, 0, EDX, 23, "AVX512_FP16" },
{ 7, 1, EAX, 5, "AVX512_BF16" }
};
auto enumerate = [&]<typename Fn>( Fn fn )
requires requires( Fn fn, feature_t const &ft ) { { fn( ft ) }; }
{
int regs[4];
for( feature_t const *ftLast = nullptr; feature_t const &ft : features )
{
if( !ftLast || ft.id != ftLast->id || ft.leaf != ftLast->leaf )
__cpuidex( regs, ft.id, ft.leaf );
if( regs[ft.reg] >> ft.bit & 1 )
fn( ft );
ftLast = &ft;
}
};
size_t n = 0;
enumerate( [&]( feature_t const &ft ) { n += (size_t)(bool)n * 2 +
ft.descr.length(); } );
string strFt;
strFt.reserve( n );
enumerate( [&]( feature_t const &ft )
{
if( strFt.size() )
strFt += ", ";
strFt += ft.descr;
} );
cout << strFt << endl;
}
I could have used /proc/cpuinfo also.
#include <iostream>
#include <intrin.h>
using namespace std;
int main()
{
struct feature_t
{
uint8_t id, leaf;
uint8_t reg, bit;
string_view descr;
};
enum { EAX, EBX, ECX, EDX };
static feature_t const features[] =
{
{ 7, 0, EBX, 16, "AVX512F" },
{ 7, 0, EBX, 17, "AVX512DQ" },
{ 7, 0, EBX, 21, "AVX512IFMA" },
{ 7, 0, EBX, 26, "AVX512PF" },
{ 7, 0, EBX, 27, "AVX512ER" },
{ 7, 0, EBX, 28, "AVX512CD" },
{ 7, 0, EBX, 30, "AVX512BW" },
{ 7, 0, EBX, 31, "AVX512VL" },
{ 7, 0, ECX, 0, "AVX512_VBMI" },
{ 7, 0, ECX, 6, "AVX512_VBMI2" },
{ 7, 0, ECX, 11, "AVX512_VNNI" },
{ 7, 0, ECX, 12, "AVX512_BITALG" },
{ 7, 0, ECX, 14, "AVX512_VPOPCNTDQ" },
{ 7, 0, EDX, 2, "AVX512_4VNNIW" },
{ 7, 0, EDX, 3, "AVX512_4FMAPS" },
{ 7, 0, EDX, 8, "AVX512_VP2INTERSECT" },
{ 7, 0, EDX, 23, "AVX512_FP16" },
{ 7, 1, EAX, 5, "AVX512_BF16" }
};
auto enumerate = [&]<typename Fn>( Fn fn )
requires requires( Fn fn, feature_t const &ft ) { { fn( ft ) }; }
{
int regs[4];
for( feature_t const *ftLast = nullptr; feature_t const &ft : features )
{
if( !ftLast || ft.id != ftLast->id || ft.leaf != ftLast->leaf )
__cpuidex( regs, ft.id, ft.leaf );
if( regs[ft.reg] >> ft.bit & 1 )
fn( ft );
ftLast = &ft;
}
};
size_t n = 0;
enumerate( [&]( feature_t const &ft ) { n += (size_t)(bool)n * 2 +
ft.descr.length(); } );
string strFt;
strFt.reserve( n );
enumerate( [&]( feature_t const &ft )
{
if( strFt.size() )
strFt += ", ";
strFt += ft.descr;
} );
cout << strFt << endl;
}
I could have used /proc/cpuinfo also.