読者です 読者をやめる 読者になる 読者になる

cpuidでAVX2に対応しているか調べる

intelの以下のページに方法とコードが書いてあります.

software.intel.com

AVX2等は以下のCPUIDで調べることができます.

CPUID.(EAX=01H, ECX=0H):ECX.FMA[bit 12]==1
CPUID.(EAX=07H, ECX=0H):EBX.AVX2[bit 5]==1
CPUID.(EAX=07H, ECX=0H):EBX.BMI1[bit 3]==1
CPUID.(EAX=07H, ECX=0H):EBX.BMI2[bit 8]==1
CPUID.(EAX=80000001H):ECX.LZCNT[bit 5]==1
CPUID.(EAX=01H, ECX=0H):ECX.MOVBE[bit 22]==1

以下,検証用コード (とりあえず自分の環境で動けば良かったのでかなり適当です)

#include <stdio.h>
#include <string.h>


struct abcd{
    unsigned int a,b,c,d;
};

void cpuid(struct abcd* r, unsigned int eax, unsigned int ecx){
    __asm__ volatile ("cpuid"
                      :"=a"(r->a), "=b"(r->b), "=c"(r->c), "=d"(r->d)
                      : "a"(eax), "c"(ecx));
}

int main(){
    struct abcd r;
    char buf[48];

    // GenuinIntel
    cpuid(&r, 0x0, 0x0);
    printf("0x%x\n", r.a);
    memcpy(buf, &r.b, 4);
    memcpy(buf+4, &r.d, 4);
    memcpy(buf+8, &r.c, 4);
    buf[12] = '\0';
    printf("%s\n", buf);

    // Processor Name, Freq
    cpuid(&r, 0x80000002, 0x0);
    memcpy(buf, &r, 16);
    cpuid(&r, 0x80000003, 0x0);
    memcpy(buf+16, &r, 16);
    cpuid(&r, 0x80000004, 0x0);
    memcpy(buf+32, &r, 16);
    printf("%s\n", buf);

    // SIMD
    // https://software.intel.com/en-us/articles/how-to-detect-new-instruction-support-in-the-4th-generation-intel-core-processor-family
    cpuid(&r, 0x1, 0x0);
    printf("MMX:    %s\n", r.d & 1 << 23 ? "OK" : "NG");
    printf("SSE:    %s\n", r.d & 1 << 25 ? "OK" : "NG");
    printf("AVX:    %s\n", r.c & 1 << 28 ? "OK" : "NG");
    printf("FMA:    %s\n", r.c & 1 << 12 ? "OK" : "NG");
    cpuid(&r, 0x7, 0x0);
    printf("AVX2:   %s\n", r.b & 1 <<  5 ? "OK" : "NG");

    return 0;
}

実行結果

% gcc-6 cpuid.c
% ./a.out
0x16
GenuineIntel
Intel(R) Core(TM) i7-6567U CPU @ 3.30GHz
MMX:    OK
SSE:    OK
AVX:    OK
FMA:    OK
AVX2:   OK