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 219882 19edf4b9d338c8004a1a9d8905894b47c28d53a3
parent 219881 6a3a0e3bfaf61160e0b415fbdc4b739b781e6554
child 219883 f073ba9ff1fbb935419c631113b617749ed9d18c
push id10419
push usercbook@mozilla.com
push dateTue, 16 Dec 2014 12:45:27 +0000
treeherderfx-team@ec87657146eb [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbbouvier
bugs1110570
milestone37.0a1
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);
+    }
 }