Bug 1110570 - Test xgetbv xcr0 to determine whether the OS supports AVX r=bbouvier
authorDan Gohman <sunfish@mozilla.com>
Mon, 15 Dec 2014 20:53:58 -0800
changeset 219847 19edf4b9d338c8004a1a9d8905894b47c28d53a3
parent 219846 6a3a0e3bfaf61160e0b415fbdc4b739b781e6554
child 219848 f073ba9ff1fbb935419c631113b617749ed9d18c
push id27970
push usercbook@mozilla.com
push dateTue, 16 Dec 2014 12:35:21 +0000
treeherdermozilla-central@365c02fb0c5f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbbouvier
bugs1110570
milestone37.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1110570 - Test xgetbv xcr0 to determine whether the OS supports AVX r=bbouvier
js/src/jit/shared/Assembler-x86-shared.cpp
--- a/js/src/jit/shared/Assembler-x86-shared.cpp
+++ b/js/src/jit/shared/Assembler-x86-shared.cpp
@@ -11,16 +11,19 @@
 #elif defined(JS_CODEGEN_X64)
 # include "jit/x64/MacroAssembler-x64.h"
 #else
 # error "Wrong architecture. Only x86 and x64 should build this file!"
 #endif
 
 #ifdef _MSC_VER
 # include <intrin.h> // for __cpuid
+# if defined(_M_X64) && (_MSC_FULL_VER >= 160040219)
+#  include <immintrin.h> // for _xgetbv
+# endif
 #endif
 
 using namespace js;
 using namespace js::jit;
 
 void
 AssemblerX86Shared::copyJumpRelocationTable(uint8_t *dest)
 {
@@ -136,16 +139,40 @@ AssemblerX86Shared::InvertCondition(Cond
     }
 }
 
 CPUInfo::SSEVersion CPUInfo::maxSSEVersion = UnknownSSE;
 CPUInfo::SSEVersion CPUInfo::maxEnabledSSEVersion = UnknownSSE;
 bool CPUInfo::avxPresent = false;
 bool CPUInfo::avxEnabled = true;
 
+static uintptr_t
+ReadXGETBV()
+{
+    // We use a variety of low-level mechanisms to get at the xgetbv
+    // instruction, including spelling out the xgetbv instruction as bytes,
+    // because older compilers and assemblers may not recognize the instruction
+    // by name.
+    size_t xcr0EAX = 0;
+#if defined(_XCR_XFEATURE_ENABLED_MASK)
+    xcr0EAX = _xgetbv(_XCR_XFEATURE_ENABLED_MASK);
+#elif defined(__GNUC__)
+    // xgetbv returns its results in %eax and %edx, and for our purposes here,
+    // we're only interested in the %eax value.
+    asm(".byte 0x0f, 0x01, 0xd0" : "=a"(xcr0EAX) : "c"(0) : "%edx");
+#elif defined(_MSC_VER) && defined(_M_IX86)
+    __asm {
+        xor ecx, ecx
+        _asm _emit 0x0f _asm _emit 0x01 _asm _emit 0xd0
+        mov xcr0EAX, eax
+    }
+#endif
+    return xcr0EAX;
+}
+
 void
 CPUInfo::SetSSEVersion()
 {
     int flagsEDX = 0;
     int flagsECX = 0;
 
 #ifdef _MSC_VER
     int cpuinfo[4];
@@ -197,9 +224,17 @@ CPUInfo::SetSSEVersion()
     else                          maxSSEVersion = NoSSE;
 
     if (maxEnabledSSEVersion != UnknownSSE)
         maxSSEVersion = Min(maxSSEVersion, maxEnabledSSEVersion);
 
     static const int AVXBit = 1 << 28;
     static const int XSAVEBit = 1 << 27;
     avxPresent = (flagsECX & AVXBit) && (flagsECX & XSAVEBit) && avxEnabled;
+
+    // If the hardware supports AVX, check whether the OS supports it too.
+    if (avxPresent) {
+        size_t xcr0EAX = ReadXGETBV();
+        static const int xcr0SSEBit = 1 << 1;
+        static const int xcr0AVXBit = 1 << 2;
+        avxPresent = (xcr0EAX & xcr0SSEBit) && (xcr0EAX & xcr0AVXBit);
+    }
 }