]> git.ipfire.org Git - thirdparty/zlib-ng.git/commitdiff
Check that the OS supports saving the YMM registers before enabling AVX2
authorCameron Cawley <ccawley2011@gmail.com>
Sun, 25 Sep 2022 19:11:14 +0000 (20:11 +0100)
committerHans Kristian Rosbach <hk-github@circlestorm.org>
Tue, 11 Oct 2022 10:22:24 +0000 (12:22 +0200)
arch/x86/x86_features.c
arch/x86/x86_features.h

index 72ef885e826b530d4ff85cf90d626a92d154bc0c..b8ab69cefea70c9191307cdea666e402074db2be 100644 (file)
@@ -28,6 +28,8 @@ Z_INTERNAL int x86_cpu_has_sse42;
 Z_INTERNAL int x86_cpu_has_pclmulqdq;
 Z_INTERNAL int x86_cpu_has_vpclmulqdq;
 Z_INTERNAL int x86_cpu_has_tzcnt;
+Z_INTERNAL int x86_cpu_has_os_save_ymm;
+Z_INTERNAL int x86_cpu_has_os_save_zmm;
 
 static void cpuid(int info, unsigned* eax, unsigned* ebx, unsigned* ecx, unsigned* edx) {
 #ifdef _MSC_VER
@@ -57,6 +59,16 @@ static void cpuidex(int info, int subinfo, unsigned* eax, unsigned* ebx, unsigne
 #endif
 }
 
+static uint64_t xgetbv(unsigned int xcr) {
+#ifdef _MSC_VER
+    return _xgetbv(xcr);
+#else
+    uint32_t eax, edx;
+    __asm__ ( ".byte 0x0f, 0x01, 0xd0" : "=a"(eax), "=d"(edx) : "c"(xcr));
+    return (uint64_t)(edx) << 32 | eax;
+#endif
+}
+
 void Z_INTERNAL x86_check_features(void) {
     unsigned eax, ebx, ecx, edx;
     unsigned maxbasic;
@@ -70,20 +82,44 @@ void Z_INTERNAL x86_check_features(void) {
     x86_cpu_has_sse42 = ecx & 0x100000;
     x86_cpu_has_pclmulqdq = ecx & 0x2;
 
+    if (ecx & 0x08000000) {
+        uint64_t xfeature = xgetbv(0);
+
+        x86_cpu_has_os_save_ymm = ((xfeature & 0x06) == 0x06);
+        x86_cpu_has_os_save_zmm = ((xfeature & 0xe6) == 0xe6);
+    } else {
+        x86_cpu_has_os_save_ymm = 0;
+        x86_cpu_has_os_save_zmm = 0;
+    }
+
     if (maxbasic >= 7) {
         cpuidex(7, 0, &eax, &ebx, &ecx, &edx);
 
         // check BMI1 bit
         // Reference: https://software.intel.com/sites/default/files/article/405250/how-to-detect-new-instruction-support-in-the-4th-generation-intel-core-processor-family.pdf
         x86_cpu_has_tzcnt = ebx & 0x8;
-        // check AVX2 bit
-        x86_cpu_has_avx2 = ebx & 0x20;
-        x86_cpu_has_avx512 = ebx & 0x00010000;
-        x86_cpu_has_avx512vnni = ecx & 0x800;
         x86_cpu_has_vpclmulqdq = ecx & 0x400;
+
+        // check AVX2 bit if the OS supports saving YMM registers
+        if (x86_cpu_has_os_save_ymm) {
+            x86_cpu_has_avx2 = ebx & 0x20;
+        } else {
+            x86_cpu_has_avx2 = 0;
+        }
+
+        // check AVX512 bits if the OS supports saving ZMM registers
+        if (x86_cpu_has_os_save_zmm) {
+            x86_cpu_has_avx512 = ebx & 0x00010000;
+            x86_cpu_has_avx512vnni = ecx & 0x800;
+        } else {
+            x86_cpu_has_avx512 = 0;
+            x86_cpu_has_avx512vnni = 0;
+        }
     } else {
         x86_cpu_has_tzcnt = 0;
         x86_cpu_has_avx2 = 0;
+        x86_cpu_has_avx512 = 0;
+        x86_cpu_has_avx512vnni = 0;
         x86_cpu_has_vpclmulqdq = 0;
     }
 }
index 97630ab6e6c438fd274670338ba0f30c7e33bc76..3e0d17f063303e5100fb1d77fa12ff479eeaf0b7 100644 (file)
@@ -16,6 +16,8 @@ extern int x86_cpu_has_sse42;
 extern int x86_cpu_has_pclmulqdq;
 extern int x86_cpu_has_vpclmulqdq;
 extern int x86_cpu_has_tzcnt;
+extern int x86_cpu_has_os_save_ymm;
+extern int x86_cpu_has_os_save_zmm;
 
 void Z_INTERNAL x86_check_features(void);