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() ...@@ -316,6 +316,7 @@ CPU::CPU()
has_sse41_(false), has_sse41_(false),
has_sse42_(false), has_sse42_(false),
is_atom_(false), is_atom_(false),
has_osxsave_(false),
has_avx_(false), has_avx_(false),
has_fma3_(false), has_fma3_(false),
has_idiva_(false), has_idiva_(false),
...@@ -364,8 +365,9 @@ CPU::CPU() ...@@ -364,8 +365,9 @@ CPU::CPU()
has_ssse3_ = (cpu_info[2] & 0x00000200) != 0; has_ssse3_ = (cpu_info[2] & 0x00000200) != 0;
has_sse41_ = (cpu_info[2] & 0x00080000) != 0; has_sse41_ = (cpu_info[2] & 0x00080000) != 0;
has_sse42_ = (cpu_info[2] & 0x00100000) != 0; has_sse42_ = (cpu_info[2] & 0x00100000) != 0;
has_osxsave_ = (cpu_info[2] & 0x08000000) != 0;
has_avx_ = (cpu_info[2] & 0x10000000) != 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) { if (family_ == 0x6) {
switch (model_) { switch (model_) {
......
...@@ -83,6 +83,7 @@ class CPU FINAL { ...@@ -83,6 +83,7 @@ class CPU FINAL {
bool has_ssse3() const { return has_ssse3_; } bool has_ssse3() const { return has_ssse3_; }
bool has_sse41() const { return has_sse41_; } bool has_sse41() const { return has_sse41_; }
bool has_sse42() const { return has_sse42_; } bool has_sse42() const { return has_sse42_; }
bool has_osxsave() const { return has_osxsave_; }
bool has_avx() const { return has_avx_; } bool has_avx() const { return has_avx_; }
bool has_fma3() const { return has_fma3_; } bool has_fma3() const { return has_fma3_; }
bool is_atom() const { return is_atom_; } bool is_atom() const { return is_atom_; }
...@@ -121,6 +122,7 @@ class CPU FINAL { ...@@ -121,6 +122,7 @@ class CPU FINAL {
bool has_sse41_; bool has_sse41_;
bool has_sse42_; bool has_sse42_;
bool is_atom_; bool is_atom_;
bool has_osxsave_;
bool has_avx_; bool has_avx_;
bool has_fma3_; bool has_fma3_;
bool has_idiva_; bool has_idiva_;
......
...@@ -40,15 +40,15 @@ ...@@ -40,15 +40,15 @@
#if V8_TARGET_ARCH_IA32 #if V8_TARGET_ARCH_IA32
#if V8_LIBC_MSVCRT
#include <intrin.h> // _xgetbv()
#endif
#if V8_OS_MACOSX #if V8_OS_MACOSX
#include <sys/sysctl.h> #include <sys/sysctl.h>
#endif #endif
#include "src/base/bits.h" #include "src/base/bits.h"
#include "src/base/cpu.h" #include "src/base/cpu.h"
#if V8_OS_WIN
#include "src/base/win32-headers.h"
#endif
#include "src/disassembler.h" #include "src/disassembler.h"
#include "src/macro-assembler.h" #include "src/macro-assembler.h"
#include "src/v8.h" #include "src/v8.h"
...@@ -61,13 +61,30 @@ namespace internal { ...@@ -61,13 +61,30 @@ namespace internal {
namespace { 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 #if V8_OS_MACOSX
// Mac OS X up to 10.9 has a bug where AVX transitions were indeed being // 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. // caused by ISRs, so we detect that here and disable AVX in that case.
char buffer[128]; char buffer[128];
size_t buffer_size = arraysize(buffer); 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) { if (sysctl(ctl_name, 2, buffer, &buffer_size, nullptr, 0) != 0) {
V8_Fatal(__FILE__, __LINE__, "V8 failed to get kernel version"); V8_Fatal(__FILE__, __LINE__, "V8 failed to get kernel version");
} }
...@@ -78,21 +95,10 @@ bool EnableAVX() { ...@@ -78,21 +95,10 @@ bool EnableAVX() {
*period_pos = '\0'; *period_pos = '\0';
long kernel_version_major = strtol(buffer, nullptr, 10); // NOLINT long kernel_version_major = strtol(buffer, nullptr, 10); // NOLINT
if (kernel_version_major <= 13) return false; 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 #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 } // namespace
...@@ -108,8 +114,14 @@ void CpuFeatures::ProbeImpl(bool cross_compile) { ...@@ -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_sse41() && FLAG_enable_sse4_1) supported_ |= 1u << SSE4_1;
if (cpu.has_sse3() && FLAG_enable_sse3) supported_ |= 1u << SSE3; if (cpu.has_sse3() && FLAG_enable_sse3) supported_ |= 1u << SSE3;
if (cpu.has_avx() && EnableAVX()) supported_ |= 1u << AVX; if (cpu.has_avx() && FLAG_enable_avx && cpu.has_osxsave() &&
if (cpu.has_fma3() && FLAG_enable_fma3) supported_ |= 1u << FMA3; 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 (strcmp(FLAG_mcpu, "auto") == 0) {
if (cpu.is_atom()) supported_ |= 1u << ATOM; if (cpu.is_atom()) supported_ |= 1u << ATOM;
} else if (strcmp(FLAG_mcpu, "atom") == 0) { } else if (strcmp(FLAG_mcpu, "atom") == 0) {
......
...@@ -8,14 +8,14 @@ ...@@ -8,14 +8,14 @@
#if V8_TARGET_ARCH_X64 #if V8_TARGET_ARCH_X64
#if V8_LIBC_MSVCRT
#include <intrin.h> // _xgetbv()
#endif
#if V8_OS_MACOSX #if V8_OS_MACOSX
#include <sys/sysctl.h> #include <sys/sysctl.h>
#endif #endif
#include "src/base/bits.h" #include "src/base/bits.h"
#if V8_OS_WIN
#include "src/base/win32-headers.h"
#endif
#include "src/macro-assembler.h" #include "src/macro-assembler.h"
#include "src/v8.h" #include "src/v8.h"
...@@ -27,7 +27,24 @@ namespace internal { ...@@ -27,7 +27,24 @@ namespace internal {
namespace { 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 #if V8_OS_MACOSX
// Mac OS X up to 10.9 has a bug where AVX transitions were indeed being // 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. // caused by ISRs, so we detect that here and disable AVX in that case.
...@@ -44,21 +61,10 @@ bool EnableAVX() { ...@@ -44,21 +61,10 @@ bool EnableAVX() {
*period_pos = '\0'; *period_pos = '\0';
long kernel_version_major = strtol(buffer, nullptr, 10); // NOLINT long kernel_version_major = strtol(buffer, nullptr, 10); // NOLINT
if (kernel_version_major <= 13) return false; 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 #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 } // namespace
...@@ -76,8 +82,14 @@ void CpuFeatures::ProbeImpl(bool cross_compile) { ...@@ -76,8 +82,14 @@ void CpuFeatures::ProbeImpl(bool cross_compile) {
if (cpu.has_sse3() && FLAG_enable_sse3) supported_ |= 1u << SSE3; if (cpu.has_sse3() && FLAG_enable_sse3) supported_ |= 1u << SSE3;
// SAHF is not generally available in long mode. // SAHF is not generally available in long mode.
if (cpu.has_sahf() && FLAG_enable_sahf) supported_ |= 1u << SAHF; if (cpu.has_sahf() && FLAG_enable_sahf) supported_ |= 1u << SAHF;
if (cpu.has_avx() && EnableAVX()) supported_ |= 1u << AVX; if (cpu.has_avx() && FLAG_enable_avx && cpu.has_osxsave() &&
if (cpu.has_fma3() && FLAG_enable_fma3) supported_ |= 1u << FMA3; 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 (strcmp(FLAG_mcpu, "auto") == 0) {
if (cpu.is_atom()) supported_ |= 1u << ATOM; if (cpu.is_atom()) supported_ |= 1u << ATOM;
} else if (strcmp(FLAG_mcpu, "atom") == 0) { } else if (strcmp(FLAG_mcpu, "atom") == 0) {
......
...@@ -18,6 +18,8 @@ TEST(CPUTest, FeatureImplications) { ...@@ -18,6 +18,8 @@ TEST(CPUTest, FeatureImplications) {
EXPECT_TRUE(!cpu.has_ssse3() || cpu.has_sse3()); EXPECT_TRUE(!cpu.has_ssse3() || cpu.has_sse3());
EXPECT_TRUE(!cpu.has_sse41() || cpu.has_sse3()); EXPECT_TRUE(!cpu.has_sse41() || cpu.has_sse3());
EXPECT_TRUE(!cpu.has_sse42() || cpu.has_sse41()); 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 // arm features
EXPECT_TRUE(!cpu.has_vfp3_d32() || cpu.has_vfp3()); 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