@@ -73,6 +73,38 @@ static void __zend_cpuid(uint32_t func, uint32_t subfunc, zend_cpu_info *cpuinfo
73
73
}
74
74
#endif
75
75
76
+ /* Function based on compiler-rt implementation. */
77
+ static unsigned get_xcr0_eax () {
78
+ #if defined(__GNUC__ ) || defined(__clang__ )
79
+ // Check xgetbv; this uses a .byte sequence instead of the instruction
80
+ // directly because older assemblers do not include support for xgetbv and
81
+ // there is no easy way to conditionally compile based on the assembler used.
82
+ unsigned eax , edx ;
83
+ __asm__(".byte 0x0f, 0x01, 0xd0" : "=a" (eax ), "=d" (edx ) : "c" (0 ));
84
+ return eax ;
85
+ #elif defined(ZEND_WIN32 ) && defined(_XCR_XFEATURE_ENABLED_MASK )
86
+ return _xgetbv (_XCR_XFEATURE_ENABLED_MASK );
87
+ #else
88
+ return 0 ;
89
+ #endif
90
+ }
91
+
92
+ static zend_bool is_avx_supported () {
93
+ if (!(cpuinfo .ecx & ZEND_CPU_FEATURE_AVX )) {
94
+ /* No support for AVX */
95
+ return 0 ;
96
+ }
97
+ if (!(cpuinfo .ecx & ZEND_CPU_FEATURE_OSXSAVE )) {
98
+ /* The operating system does not support XSAVE. */
99
+ return 0 ;
100
+ }
101
+ if ((get_xcr0_eax () & 0x6 ) != 0x6 ) {
102
+ /* XCR0 SSE and AVX bits must be set. */
103
+ return 0 ;
104
+ }
105
+ return 1 ;
106
+ }
107
+
76
108
void zend_cpu_startup (void )
77
109
{
78
110
if (!cpuinfo .initialized ) {
@@ -95,6 +127,11 @@ void zend_cpu_startup(void)
95
127
} else {
96
128
cpuinfo .ebx = 0 ;
97
129
}
130
+
131
+ if (!is_avx_supported ()) {
132
+ cpuinfo .edx &= ~ZEND_CPU_FEATURE_AVX ;
133
+ cpuinfo .ebx &= ~(ZEND_CPU_FEATURE_AVX2 & ~ZEND_CPU_EBX_MASK );
134
+ }
98
135
}
99
136
}
100
137
0 commit comments