summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNikita Popov <nikita.ppv@gmail.com>2020-11-27 11:54:39 +0100
committerNikita Popov <nikita.ppv@gmail.com>2020-11-27 14:49:31 +0100
commit4e30ab33d84232ba2686e7ed5b125861db63142d (patch)
tree75c325bda8de2979c6c81934f4ae5b2648c99a41
parent07c5efbd76faa0aa43fa3ddded0b562876a88e5a (diff)
downloadphp-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.c37
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);
+ }
}
}