From 377202b9f6154ae56c5b2f0a45e235ceaeb6da9c Mon Sep 17 00:00:00 2001 From: Pierre Bourdon Date: Tue, 20 Aug 2013 01:25:10 +0200 Subject: [PATCH] Correctly check for AVX support in x64CPUDetect It's not enough to check for the CPUID bit to know if AVX is supported since AVX requires OS support (new set of registers == more registers to be saved when context switching). If the OS does not support, the cpuid bit will still be set but using YMM registers will cause an illegal exception fault. --- Source/Core/Common/Src/x64CPUDetect.cpp | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/Source/Core/Common/Src/x64CPUDetect.cpp b/Source/Core/Common/Src/x64CPUDetect.cpp index d225262f81..b72a146167 100644 --- a/Source/Core/Common/Src/x64CPUDetect.cpp +++ b/Source/Core/Common/Src/x64CPUDetect.cpp @@ -72,6 +72,14 @@ static void __cpuid(int info[4], int x) #endif } +#define _XCR_XFEATURE_ENABLED_MASK 0 +static unsigned long long _xgetbv(unsigned int index) +{ + unsigned int eax, edx; + __asm__ __volatile__("xgetbv" : "=a"(eax), "=d"(edx) : "c"(index)); + return ((unsigned long long)edx << 32) | eax; +} + #endif #include "Common.h" @@ -149,8 +157,17 @@ void CPUInfo::Detect() if ((cpu_id[2] >> 9) & 1) bSSSE3 = true; if ((cpu_id[2] >> 19) & 1) bSSE4_1 = true; if ((cpu_id[2] >> 20) & 1) bSSE4_2 = true; - if ((cpu_id[2] >> 28) & 1) bAVX = true; if ((cpu_id[2] >> 25) & 1) bAES = true; + + // AVX support requires 3 separate checks: + // - Is the AVX bit set in CPUID? + // - Is the XSAVE bit set in CPUID? + // - XGETBV result has the XCR bit set. + if (((cpu_id[2] >> 28) & 1) && ((cpu_id[2] >> 27) & 1)) + { + if (_xgetbv(_XCR_XFEATURE_ENABLED_MASK) & 0x6) + bAVX = true; + } } if (max_ex_fn >= 0x80000004) { // Extract brand string