Index: base/cpu.cc |
diff --git a/base/cpu.cc b/base/cpu.cc |
index 78064e2815f4bed5da737174289374748707e6e5..dec98bd7a1e82b5e8162a163200de415a513dfde 100644 |
--- a/base/cpu.cc |
+++ b/base/cpu.cc |
@@ -8,11 +8,13 @@ |
#include <algorithm> |
+#include "base/basictypes.h" |
#include "build/build_config.h" |
#if defined(ARCH_CPU_X86_FAMILY) |
#if defined(_MSC_VER) |
#include <intrin.h> |
+#include <immintrin.h> // For _xgetbv() |
#endif |
#endif |
@@ -33,11 +35,15 @@ CPU::CPU() |
has_ssse3_(false), |
has_sse41_(false), |
has_sse42_(false), |
+ has_avx_(false), |
+ has_avx_hardware_(false), |
has_non_stop_time_stamp_counter_(false), |
cpu_vendor_("unknown") { |
Initialize(); |
} |
+namespace { |
+ |
#if defined(ARCH_CPU_X86_FAMILY) |
#ifndef _MSC_VER |
@@ -53,16 +59,6 @@ void __cpuid(int cpu_info[4], int info_type) { |
); |
} |
-void __cpuidex(int cpu_info[4], int info_type, int info_index) { |
- __asm__ volatile ( |
- "mov %%ebx, %%edi\n" |
- "cpuid\n" |
- "xchg %%edi, %%ebx\n" |
- : "=a"(cpu_info[0]), "=D"(cpu_info[1]), "=c"(cpu_info[2]), "=d"(cpu_info[3]) |
- : "a"(info_type), "c"(info_index) |
- ); |
-} |
- |
#else |
void __cpuid(int cpu_info[4], int info_type) { |
@@ -73,18 +69,22 @@ void __cpuid(int cpu_info[4], int info_type) { |
); |
} |
-void __cpuidex(int cpu_info[4], int info_type, int info_index) { |
- __asm__ volatile ( |
- "cpuid \n\t" |
- : "=a"(cpu_info[0]), "=b"(cpu_info[1]), "=c"(cpu_info[2]), "=d"(cpu_info[3]) |
- : "a"(info_type), "c"(info_index) |
- ); |
-} |
- |
#endif |
-#endif // _MSC_VER |
+ |
+// _xgetbv returns the value of an Intel Extended Control Register (XCR). |
+// Currently only XCR0 is defined by Intel so |xcr| should always be zero. |
+uint64 _xgetbv(uint32 xcr) { |
+ uint32 eax, edx; |
+ |
+ __asm__ volatile ("xgetbv" : "=a" (eax), "=d" (edx) : "c" (xcr)); |
+ return (static_cast<uint64>(edx) << 32) | eax; |
+} |
+ |
+#endif // !_MSC_VER |
#endif // ARCH_CPU_X86_FAMILY |
+} // anonymous namespace |
+ |
void CPU::Initialize() { |
#if defined(ARCH_CPU_X86_FAMILY) |
int cpu_info[4] = {-1}; |
@@ -113,14 +113,24 @@ void CPU::Initialize() { |
type_ = (cpu_info[0] >> 12) & 0x3; |
ext_model_ = (cpu_info[0] >> 16) & 0xf; |
ext_family_ = (cpu_info[0] >> 20) & 0xff; |
- has_mmx_ = (cpu_info[3] & 0x00800000) != 0; |
- has_sse_ = (cpu_info[3] & 0x02000000) != 0; |
- has_sse2_ = (cpu_info[3] & 0x04000000) != 0; |
- has_sse3_ = (cpu_info[2] & 0x00000001) != 0; |
+ has_mmx_ = (cpu_info[3] & 0x00800000) != 0; |
+ has_sse_ = (cpu_info[3] & 0x02000000) != 0; |
+ has_sse2_ = (cpu_info[3] & 0x04000000) != 0; |
+ has_sse3_ = (cpu_info[2] & 0x00000001) != 0; |
has_ssse3_ = (cpu_info[2] & 0x00000200) != 0; |
has_sse41_ = (cpu_info[2] & 0x00080000) != 0; |
has_sse42_ = (cpu_info[2] & 0x00100000) != 0; |
- has_avx_ = (cpu_info[2] & 0x10000000) != 0; |
+ has_avx_hardware_ = |
+ (cpu_info[2] & 0x10000000) != 0; |
+ // AVX instructions will generate an illegal instruction exception unless |
+ // a) they are supported by the CPU, |
+ // b) XSAVE is supported by the CPU and |
+ // c) XSAVE is enabled by the kernel. |
+ // See http://software.intel.com/en-us/blogs/2011/04/14/is-avx-enabled |
+ has_avx_ = |
+ has_avx_hardware_ && |
+ (cpu_info[2] & 0x08000000) != 0 /* OSXSAVE */ && |
+ (_xgetbv(0) & 6) == 6 /* XSAVE enabled by kernel */; |
} |
// Get the brand string of the cpu. |