Fix AVX2 detection.

Replaces calls to __get_cpuid by __cpuid_count on gcc and clang and
calls to __cpuid by __cpuidex on MSVC. Unlike __get_cpuid and __cpuid,
__cpuid_count and __cpuidex set the ecx register which is required for
AVX2 detection.
This commit is contained in:
Arttu Ylä-Outinen 2015-07-08 12:17:12 +03:00 committed by Ari Koivula
parent 9acf7795a2
commit 8550c6ccd8

View file

@ -182,20 +182,22 @@ typedef struct {
// CPUID adapters for different compilers. // CPUID adapters for different compilers.
# if defined(__GNUC__) # if defined(__GNUC__)
#include <cpuid.h> #include <cpuid.h>
static INLINE int get_cpuid(unsigned int level, cpuid_t *cpu_info) { static INLINE int get_cpuid(unsigned level, unsigned sublevel, cpuid_t *cpu_info) {
return __get_cpuid(level, &cpu_info->eax, &cpu_info->ebx, &cpu_info->ecx, &cpu_info->edx); if (__get_cpuid_max(level & 0x80000000, NULL) < level) return 0;
__cpuid_count(level, sublevel, cpu_info->eax, cpu_info->ebx, cpu_info->ecx, cpu_info->edx);
return 1;
} }
# elif defined(_MSC_VER) # elif defined(_MSC_VER)
#include <intrin.h> #include <intrin.h>
static INLINE int get_cpuid(unsigned int level, cpuid_t *cpu_info) { static INLINE int get_cpuid(unsigned level, unsigned sublevel, cpuid_t *cpu_info) {
int vendor_info[4] = { 0, 0, 0, 0 }; int vendor_info[4] = { 0, 0, 0, 0 };
__cpuid(vendor_info, 0); __cpuidex(vendor_info, 0, 0);
// Check highest supported function. // Check highest supported function.
if (level > vendor_info[0]) return 0; if (level > vendor_info[0]) return 0;
int ms_cpu_info[4] = { cpu_info->eax, cpu_info->ebx, cpu_info->ecx, cpu_info->edx }; int ms_cpu_info[4] = { cpu_info->eax, cpu_info->ebx, cpu_info->ecx, cpu_info->edx };
__cpuid(ms_cpu_info, level); __cpuidex(ms_cpu_info, level, sublevel);
cpu_info->eax = ms_cpu_info[0]; cpu_info->eax = ms_cpu_info[0];
cpu_info->ebx = ms_cpu_info[1]; cpu_info->ebx = ms_cpu_info[1];
cpu_info->ecx = ms_cpu_info[2]; cpu_info->ecx = ms_cpu_info[2];
@ -204,7 +206,7 @@ static INLINE int get_cpuid(unsigned int level, cpuid_t *cpu_info) {
return 1; return 1;
} }
# else # else
static INLINE int get_cpuid(unsigned int level, cpuid_t *cpu_info) static INLINE int get_cpuid(unsigned level, unsigned sublevel, cpuid_t *cpu_info)
{ {
return 0; return 0;
} }
@ -282,7 +284,7 @@ static void set_hardware_flags(int32_t cpuid) {
}; };
// Dig CPU features with cpuid // Dig CPU features with cpuid
get_cpuid(1, &cpuid1); get_cpuid(1, 0, &cpuid1);
// EDX // EDX
if (cpuid1.edx & CPUID1_EDX_MMX) g_hardware_flags.intel_flags.mmx = 1; if (cpuid1.edx & CPUID1_EDX_MMX) g_hardware_flags.intel_flags.mmx = 1;
@ -316,7 +318,7 @@ static void set_hardware_flags(int32_t cpuid) {
if (g_hardware_flags.intel_flags.avx) { if (g_hardware_flags.intel_flags.avx) {
cpuid_t cpuid7 = { 0, 0, 0, 0 }; cpuid_t cpuid7 = { 0, 0, 0, 0 };
get_cpuid(7, &cpuid7); get_cpuid(7, 0, &cpuid7);
if (cpuid7.ebx & CPUID7_EBX_AVX2) g_hardware_flags.intel_flags.avx2 = 1; if (cpuid7.ebx & CPUID7_EBX_AVX2) g_hardware_flags.intel_flags.avx2 = 1;
} }
} }