Commit d93c4d19 authored by bmeurer's avatar bmeurer Committed by Commit bot

[x86] Disable AVX unless the operating system explicitly claims to support it.

BUG=chromium:452033, v8:3846
LOG=y
R=jkummerow@chromium.org

Review URL: https://codereview.chromium.org/878063002

Cr-Commit-Position: refs/heads/master@{#26288}
parent cc79418b
......@@ -316,6 +316,7 @@ CPU::CPU()
has_sse41_(false),
has_sse42_(false),
is_atom_(false),
has_osxsave_(false),
has_avx_(false),
has_fma3_(false),
has_idiva_(false),
......@@ -364,8 +365,9 @@ CPU::CPU()
has_ssse3_ = (cpu_info[2] & 0x00000200) != 0;
has_sse41_ = (cpu_info[2] & 0x00080000) != 0;
has_sse42_ = (cpu_info[2] & 0x00100000) != 0;
has_osxsave_ = (cpu_info[2] & 0x08000000) != 0;
has_avx_ = (cpu_info[2] & 0x10000000) != 0;
if (has_avx_) has_fma3_ = (cpu_info[2] & 0x00001000) != 0;
has_fma3_ = (cpu_info[2] & 0x00001000) != 0;
if (family_ == 0x6) {
switch (model_) {
......
......@@ -83,6 +83,7 @@ class CPU FINAL {
bool has_ssse3() const { return has_ssse3_; }
bool has_sse41() const { return has_sse41_; }
bool has_sse42() const { return has_sse42_; }
bool has_osxsave() const { return has_osxsave_; }
bool has_avx() const { return has_avx_; }
bool has_fma3() const { return has_fma3_; }
bool is_atom() const { return is_atom_; }
......@@ -121,6 +122,7 @@ class CPU FINAL {
bool has_sse41_;
bool has_sse42_;
bool is_atom_;
bool has_osxsave_;
bool has_avx_;
bool has_fma3_;
bool has_idiva_;
......
......@@ -40,15 +40,15 @@
#if V8_TARGET_ARCH_IA32
#if V8_LIBC_MSVCRT
#include <intrin.h> // _xgetbv()
#endif
#if V8_OS_MACOSX
#include <sys/sysctl.h>
#endif
#include "src/base/bits.h"
#include "src/base/cpu.h"
#if V8_OS_WIN
#include "src/base/win32-headers.h"
#endif
#include "src/disassembler.h"
#include "src/macro-assembler.h"
#include "src/v8.h"
......@@ -61,13 +61,30 @@ namespace internal {
namespace {
bool EnableAVX() {
#if !V8_LIBC_MSVCRT
V8_INLINE uint64_t _xgetbv(unsigned int xcr) {
unsigned eax, edx;
// Check xgetbv; this uses a .byte sequence instead of the instruction
// directly because older assemblers do not include support for xgetbv and
// there is no easy way to conditionally compile based on the assembler
// used.
__asm__ volatile(".byte 0x0f, 0x01, 0xd0" : "=a"(eax), "=d"(edx) : "c"(xcr));
return static_cast<uint64_t>(eax) | (static_cast<uint64_t>(edx) << 32);
}
#define _XCR_XFEATURE_ENABLED_MASK 0
#endif // !V8_LIBC_MSVCRT
bool OSHasAVXSupport() {
#if V8_OS_MACOSX
// Mac OS X up to 10.9 has a bug where AVX transitions were indeed being
// caused by ISRs, so we detect that here and disable AVX in that case.
char buffer[128];
size_t buffer_size = arraysize(buffer);
int ctl_name[] = { CTL_KERN , KERN_OSRELEASE };
int ctl_name[] = {CTL_KERN, KERN_OSRELEASE};
if (sysctl(ctl_name, 2, buffer, &buffer_size, nullptr, 0) != 0) {
V8_Fatal(__FILE__, __LINE__, "V8 failed to get kernel version");
}
......@@ -78,21 +95,10 @@ bool EnableAVX() {
*period_pos = '\0';
long kernel_version_major = strtol(buffer, nullptr, 10); // NOLINT
if (kernel_version_major <= 13) return false;
#elif V8_OS_WIN
// The same problem seems to appear on Windows XP and Vista.
OSVERSIONINFOEX osvi;
DWORDLONG mask = 0;
memset(&osvi, 0, sizeof(osvi));
osvi.dwOSVersionInfoSize = sizeof(osvi);
osvi.dwMajorVersion = 6;
osvi.dwMinorVersion = 1;
VER_SET_CONDITION(mask, VER_MAJORVERSION, VER_GREATER_EQUAL);
VER_SET_CONDITION(mask, VER_MINORVERSION, VER_GREATER_EQUAL);
if (!VerifyVersionInfo(&osvi, VER_MAJORVERSION | VER_MINORVERSION, mask)) {
return false;
}
#endif // V8_OS_MACOSX
return FLAG_enable_avx;
// Check whether OS claims to support AVX.
uint64_t feature_mask = _xgetbv(_XCR_XFEATURE_ENABLED_MASK);
return (feature_mask & 0x6) == 0x6;
}
} // namespace
......@@ -108,8 +114,14 @@ void CpuFeatures::ProbeImpl(bool cross_compile) {
if (cpu.has_sse41() && FLAG_enable_sse4_1) supported_ |= 1u << SSE4_1;
if (cpu.has_sse3() && FLAG_enable_sse3) supported_ |= 1u << SSE3;
if (cpu.has_avx() && EnableAVX()) supported_ |= 1u << AVX;
if (cpu.has_fma3() && FLAG_enable_fma3) supported_ |= 1u << FMA3;
if (cpu.has_avx() && FLAG_enable_avx && cpu.has_osxsave() &&
OSHasAVXSupport()) {
supported_ |= 1u << AVX;
}
if (cpu.has_fma3() && FLAG_enable_fma3 && cpu.has_osxsave() &&
OSHasAVXSupport()) {
supported_ |= 1u << FMA3;
}
if (strcmp(FLAG_mcpu, "auto") == 0) {
if (cpu.is_atom()) supported_ |= 1u << ATOM;
} else if (strcmp(FLAG_mcpu, "atom") == 0) {
......
......@@ -8,14 +8,14 @@
#if V8_TARGET_ARCH_X64
#if V8_LIBC_MSVCRT
#include <intrin.h> // _xgetbv()
#endif
#if V8_OS_MACOSX
#include <sys/sysctl.h>
#endif
#include "src/base/bits.h"
#if V8_OS_WIN
#include "src/base/win32-headers.h"
#endif
#include "src/macro-assembler.h"
#include "src/v8.h"
......@@ -27,7 +27,24 @@ namespace internal {
namespace {
bool EnableAVX() {
#if !V8_LIBC_MSVCRT
V8_INLINE uint64_t _xgetbv(unsigned int xcr) {
unsigned eax, edx;
// Check xgetbv; this uses a .byte sequence instead of the instruction
// directly because older assemblers do not include support for xgetbv and
// there is no easy way to conditionally compile based on the assembler
// used.
__asm__ volatile(".byte 0x0f, 0x01, 0xd0" : "=a"(eax), "=d"(edx) : "c"(xcr));
return static_cast<uint64_t>(eax) | (static_cast<uint64_t>(edx) << 32);
}
#define _XCR_XFEATURE_ENABLED_MASK 0
#endif // !V8_LIBC_MSVCRT
bool OSHasAVXSupport() {
#if V8_OS_MACOSX
// Mac OS X up to 10.9 has a bug where AVX transitions were indeed being
// caused by ISRs, so we detect that here and disable AVX in that case.
......@@ -44,21 +61,10 @@ bool EnableAVX() {
*period_pos = '\0';
long kernel_version_major = strtol(buffer, nullptr, 10); // NOLINT
if (kernel_version_major <= 13) return false;
#elif V8_OS_WIN
// The same problem seems to appear on Windows XP and Vista.
OSVERSIONINFOEX osvi;
DWORDLONG mask = 0;
memset(&osvi, 0, sizeof(osvi));
osvi.dwOSVersionInfoSize = sizeof(osvi);
osvi.dwMajorVersion = 6;
osvi.dwMinorVersion = 1;
VER_SET_CONDITION(mask, VER_MAJORVERSION, VER_GREATER_EQUAL);
VER_SET_CONDITION(mask, VER_MINORVERSION, VER_GREATER_EQUAL);
if (!VerifyVersionInfo(&osvi, VER_MAJORVERSION | VER_MINORVERSION, mask)) {
return false;
}
#endif // V8_OS_MACOSX
return FLAG_enable_avx;
// Check whether OS claims to support AVX.
uint64_t feature_mask = _xgetbv(_XCR_XFEATURE_ENABLED_MASK);
return (feature_mask & 0x6) == 0x6;
}
} // namespace
......@@ -76,8 +82,14 @@ void CpuFeatures::ProbeImpl(bool cross_compile) {
if (cpu.has_sse3() && FLAG_enable_sse3) supported_ |= 1u << SSE3;
// SAHF is not generally available in long mode.
if (cpu.has_sahf() && FLAG_enable_sahf) supported_ |= 1u << SAHF;
if (cpu.has_avx() && EnableAVX()) supported_ |= 1u << AVX;
if (cpu.has_fma3() && FLAG_enable_fma3) supported_ |= 1u << FMA3;
if (cpu.has_avx() && FLAG_enable_avx && cpu.has_osxsave() &&
OSHasAVXSupport()) {
supported_ |= 1u << AVX;
}
if (cpu.has_fma3() && FLAG_enable_fma3 && cpu.has_osxsave() &&
OSHasAVXSupport()) {
supported_ |= 1u << FMA3;
}
if (strcmp(FLAG_mcpu, "auto") == 0) {
if (cpu.is_atom()) supported_ |= 1u << ATOM;
} else if (strcmp(FLAG_mcpu, "atom") == 0) {
......
......@@ -18,6 +18,8 @@ TEST(CPUTest, FeatureImplications) {
EXPECT_TRUE(!cpu.has_ssse3() || cpu.has_sse3());
EXPECT_TRUE(!cpu.has_sse41() || cpu.has_sse3());
EXPECT_TRUE(!cpu.has_sse42() || cpu.has_sse41());
EXPECT_TRUE(!cpu.has_avx() || cpu.has_sse2());
EXPECT_TRUE(!cpu.has_fma3() || cpu.has_avx());
// arm features
EXPECT_TRUE(!cpu.has_vfp3_d32() || cpu.has_vfp3());
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment