diff options
author | Nikita Popov <nikita.ppv@gmail.com> | 2020-11-27 11:54:39 +0100 |
---|---|---|
committer | Nikita Popov <nikita.ppv@gmail.com> | 2020-11-27 14:49:31 +0100 |
commit | 4e30ab33d84232ba2686e7ed5b125861db63142d (patch) | |
tree | 75c325bda8de2979c6c81934f4ae5b2648c99a41 | |
parent | 07c5efbd76faa0aa43fa3ddded0b562876a88e5a (diff) | |
download | php-git-4e30ab33d84232ba2686e7ed5b125861db63142d.tar.gz |
Fix AVX detection
Our CPU detection code currently only checks whether hardware
support for AVX exists. However, we also need to check for operating
system support for XSAVE, as well as whether XCR0 has the SSE and
AVX bits set.
If this is not the case, unset the AVX and AVX2 bits in the cpuinfo
structure.
Hopefully this resolves our issues with CPU support detection.
Closes GH-6460.
-rw-r--r-- | Zend/zend_cpuinfo.c | 37 |
1 files changed, 37 insertions, 0 deletions
diff --git a/Zend/zend_cpuinfo.c b/Zend/zend_cpuinfo.c index 8851764f57..fa14618950 100644 --- a/Zend/zend_cpuinfo.c +++ b/Zend/zend_cpuinfo.c @@ -73,6 +73,38 @@ static void __zend_cpuid(uint32_t func, uint32_t subfunc, zend_cpu_info *cpuinfo } #endif +/* Function based on compiler-rt implementation. */ +static unsigned get_xcr0_eax() { +#if defined(__GNUC__) || defined(__clang__) + // 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. + unsigned eax, edx; + __asm__(".byte 0x0f, 0x01, 0xd0" : "=a"(eax), "=d"(edx) : "c"(0)); + return eax; +#elif defined(ZEND_WIN32) && defined(_XCR_XFEATURE_ENABLED_MASK) + return _xgetbv(_XCR_XFEATURE_ENABLED_MASK); +#else + return 0; +#endif +} + +static zend_bool is_avx_supported() { + if (!(cpuinfo.ecx & ZEND_CPU_FEATURE_AVX)) { + /* No support for AVX */ + return 0; + } + if (!(cpuinfo.ecx & ZEND_CPU_FEATURE_OSXSAVE)) { + /* The operating system does not support XSAVE. */ + return 0; + } + if ((get_xcr0_eax() & 0x6) != 0x6) { + /* XCR0 SSE and AVX bits must be set. */ + return 0; + } + return 1; +} + void zend_cpu_startup(void) { if (!cpuinfo.initialized) { @@ -95,6 +127,11 @@ void zend_cpu_startup(void) } else { cpuinfo.ebx = 0; } + + if (!is_avx_supported()) { + cpuinfo.edx &= ~ZEND_CPU_FEATURE_AVX; + cpuinfo.ebx &= ~(ZEND_CPU_FEATURE_AVX2 & ~ZEND_CPU_EBX_MASK); + } } } |