github.com/Schaudge/grailbase@v0.0.0-20240223061707-44c758a471c0/compress/libdeflate/cpu_features.c (about) 1 /* 2 * x86/cpu_features.c - feature detection for x86 processors 3 * 4 * Copyright 2016 Eric Biggers 5 * 6 * Permission is hereby granted, free of charge, to any person 7 * obtaining a copy of this software and associated documentation 8 * files (the "Software"), to deal in the Software without 9 * restriction, including without limitation the rights to use, 10 * copy, modify, merge, publish, distribute, sublicense, and/or sell 11 * copies of the Software, and to permit persons to whom the 12 * Software is furnished to do so, subject to the following 13 * conditions: 14 * 15 * The above copyright notice and this permission notice shall be 16 * included in all copies or substantial portions of the Software. 17 * 18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 19 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 20 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 21 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 22 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 23 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 24 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 25 * OTHER DEALINGS IN THE SOFTWARE. 26 */ 27 28 #include "cpu_features.h" 29 30 #if X86_CPU_FEATURES_ENABLED 31 32 volatile u32 _cpu_features = 0; 33 34 /* With old GCC versions we have to manually save and restore the x86_32 PIC 35 * register (ebx). See: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=47602 */ 36 #if defined(__i386__) && defined(__PIC__) 37 # define EBX_CONSTRAINT "=r" 38 #else 39 # define EBX_CONSTRAINT "=b" 40 #endif 41 42 /* Execute the CPUID instruction. */ 43 static inline void 44 cpuid(u32 leaf, u32 subleaf, u32 *a, u32 *b, u32 *c, u32 *d) 45 { 46 __asm__(".ifnc %%ebx, %1; mov %%ebx, %1; .endif\n" 47 "cpuid \n" 48 ".ifnc %%ebx, %1; xchg %%ebx, %1; .endif\n" 49 : "=a" (*a), EBX_CONSTRAINT (*b), "=c" (*c), "=d" (*d) 50 : "a" (leaf), "c" (subleaf)); 51 } 52 53 /* Read an extended control register. */ 54 static inline u64 55 read_xcr(u32 index) 56 { 57 u32 edx, eax; 58 59 /* Execute the "xgetbv" instruction. Old versions of binutils do not 60 * recognize this instruction, so list the raw bytes instead. */ 61 __asm__ (".byte 0x0f, 0x01, 0xd0" : "=d" (edx), "=a" (eax) : "c" (index)); 62 63 return ((u64)edx << 32) | eax; 64 } 65 66 #define IS_SET(reg, bit) ((reg) & ((u32)1 << (bit))) 67 68 /* Initialize _cpu_features with bits for interesting processor features. */ 69 void setup_cpu_features(void) 70 { 71 u32 features = 0; 72 u32 dummy1, dummy2, dummy3, dummy4; 73 u32 max_function; 74 u32 features_1, features_2, features_3, features_4; 75 bool os_saves_ymm_regs = false; 76 77 /* Get maximum supported function */ 78 cpuid(0, 0, &max_function, &dummy2, &dummy3, &dummy4); 79 if (max_function < 1) 80 goto out; 81 82 /* Standard feature flags */ 83 cpuid(1, 0, &dummy1, &dummy2, &features_2, &features_1); 84 85 if (IS_SET(features_1, 26)) 86 features |= X86_CPU_FEATURE_SSE2; 87 88 if (IS_SET(features_2, 1)) 89 features |= X86_CPU_FEATURE_PCLMULQDQ; 90 91 if (IS_SET(features_2, 27)) /* OSXSAVE set? */ 92 if ((read_xcr(0) & 0x6) == 0x6) 93 os_saves_ymm_regs = true; 94 95 if (os_saves_ymm_regs && IS_SET(features_2, 28)) 96 features |= X86_CPU_FEATURE_AVX; 97 98 if (max_function < 7) 99 goto out; 100 101 /* Extended feature flags */ 102 cpuid(7, 0, &dummy1, &features_3, &features_4, &dummy4); 103 104 if (os_saves_ymm_regs && IS_SET(features_3, 5)) 105 features |= X86_CPU_FEATURE_AVX2; 106 107 if (IS_SET(features_3, 8)) 108 features |= X86_CPU_FEATURE_BMI2; 109 110 out: 111 _cpu_features = features | X86_CPU_FEATURES_KNOWN; 112 } 113 114 #endif /* X86_CPU_FEATURES_ENABLED */