summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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);
+ }
}
}