만약
MinGW-W64 (또는 일반 MinGW) 에서 -mavx 또는 -march=corei7-avx 와 같은 빌드를 지시해서 만든 바이너리를 배포 하는데, 만약 이를 구동하는 PC 가 AVX 관련 명령어를 지원 하지 않는 환경에서 해당 바이너리를 구동하면?
이럴 경우 해당 바이너리는 그냥은 구동이 되나, AVX 관련 명령어가 실행 되는 위치에서 exception 을 뱉고, 해당 callstack 은 이전 pc 로 돌아가나, 여기서 문제가 발생 해서 함수 자체가 멍청이가 됩니다. 그래서 배포한 바이너리가 내가 빌드한 환경과 자동으로 구동 될 PC 에서의 환경과 맞는지를 간단히 테스트 할 수 있는 방법을 gcc 는 물론 MinGW 역시 지원 합니다.
이를 확인 하기 위해서는 먼저 #include 에 <cpuid.h> 를 넣어 주고 나서 다음과 같은 함수를 main() 초기에 호출해 주면 됩니다.
#include <cpuid.h>
bool testing_cpu()
{
unsigned int eax = 0;
unsigned int ebx = 0;
unsigned int ecx = 0;
unsigned int edx = 0;
unsigned int max_level = 0;
unsigned int ext_level = 0;
unsigned int vendor = 0;
unsigned int model = 0;
unsigned int family = 0;
⁄⁄ related in Core2Duo or DualCore.
unsigned int has_sse3 = 0;
unsigned int has_ssse3 = 0;
unsigned int has_cmpxchg8b = 0;
unsigned int has_cmov = 0;
unsigned int has_mmx = 0;
unsigned int has_sse = 0;
unsigned int has_sse2 = 0;
⁄⁄ related in Core I series and AVX.
unsigned int has_movbe = 0;
unsigned int has_sse4_1 = 0;
unsigned int has_sse4_2 = 0;
unsigned int has_avx = 0;
max_level = __get_cpuid_max (0, &vendor);
if (max_level < 1)
return false;
__cpuid (1, eax, ebx, ecx, edx);
model = (eax >> 4) & 0x0f;
family = (eax >> 8) & 0x0f;
if ( vendor == signature_INTEL_ebx || vendor == signature_AMD_ebx )
{
unsigned int extended_model, extended_family;
extended_model = (eax >> 12) & 0xf0;
extended_family = (eax >> 20) & 0xff;
if (family == 0x0f)
{
family += extended_family;
model += extended_model;
}
else
if (family == 0x06)
{
model += extended_model;
}
has_cmpxchg8b = edx & bit_CMPXCHG8B;
has_cmov = edx & bit_CMOV;
has_mmx = edx & bit_MMX;
has_sse = edx & bit_SSE;
has_sse2 = edx & bit_SSE2;
has_sse3 = ecx & bit_SSE3;
has_ssse3 = ecx & bit_SSSE3;
has_sse4_1 = ecx & bit_SSE4_1;
has_sse4_2 = ecx & bit_SSE4_2;
has_avx = ecx & bit_AVX;
#ifdef __SSE3__
if ( has_sse3 == 0 )
return false;
#endif ⁄⁄⁄ of __SSE3__
#ifdef __SSE4_1__
if ( has_sse4_1 == 0 )
return false;
#endif ⁄⁄⁄ of __SSE4_1__
#ifdef __SSE4_2__
if ( has_sse4_2 == 0 )
return false;
#endif ⁄⁄⁄ of __SSE4_2__
#ifdef __AVX__
if ( has_avx == 0 )
return false;
#endif ⁄⁄⁄ of __AVX__
return true;
}
return false;
}
이는 자동으로 현재 빌드에 사용된 명렁어와 구동시 CPU 검사를 통해 맞지 않을 경우 자동으로 false 를 return 하도록 한 것인데, gcc 내에 구현된 cpuid 가 틀리지 않았다면 매우 정확히 구동 됩니다.
예로 test.exe 를 -march=corei7-avx 로 빌드 한 것을 일반 DualCore 또는 Core2Duo Intel CPU 에서 구동을 하게 되면 이 함수에서 무조건 return false 를 받게 되므로 main() 에서 구동시 이를 확인하여 구동을 종료 시킬 수 있습니다.