2 * x86_cpu_features.c - feature detection for x86 processors
4 * Copyright 2022 Eric Biggers
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
15 * The above copyright notice and this permission notice shall be
16 * included in all copies or substantial portions of the Software.
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.
32 #include "wimlib/x86_cpu_features.h"
34 #if defined(__i386__) || defined(__x86_64__)
42 u32 _x86_cpu_features = 0;
44 /* With old GCC versions we have to manually save and restore the x86_32 PIC
45 * register (ebx). See: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=47602 */
46 #if defined(__i386__) && defined(__PIC__)
47 # define EBX_CONSTRAINT "=r"
49 # define EBX_CONSTRAINT "=b"
52 /* Execute the CPUID instruction. */
54 cpuid(u32 leaf, u32 subleaf, u32 *a, u32 *b, u32 *c, u32 *d)
56 __asm__(".ifnc %%ebx, %1; mov %%ebx, %1; .endif\n"
58 ".ifnc %%ebx, %1; xchg %%ebx, %1; .endif\n"
59 : "=a" (*a), EBX_CONSTRAINT (*b), "=c" (*c), "=d" (*d)
60 : "a" (leaf), "c" (subleaf));
63 /* Read an extended control register. */
69 /* Execute the "xgetbv" instruction. Old versions of binutils do not
70 * recognize this instruction, so list the raw bytes instead. */
71 __asm__ (".byte 0x0f, 0x01, 0xd0" : "=d" (edx), "=a" (eax) : "c" (index));
73 return ((u64)edx << 32) | eax;
76 #define IS_SET(reg, bit) ((reg) & ((u32)1 << (bit)))
78 /* Initialize _x86_cpu_features with bits for interesting processor features. */
80 x86_setup_cpu_features(void)
83 u32 dummy1, dummy2, dummy3, dummy4;
85 u32 features_1, features_2, features_3, features_4;
86 bool os_saves_ymm_regs = false;
88 /* Get maximum supported function */
89 cpuid(0, 0, &max_function, &dummy2, &dummy3, &dummy4);
93 /* Standard feature flags */
94 cpuid(1, 0, &dummy1, &dummy2, &features_2, &features_1);
96 if (IS_SET(features_1, 25))
97 features |= X86_CPU_FEATURE_SSE;
99 if (IS_SET(features_1, 26))
100 features |= X86_CPU_FEATURE_SSE2;
102 if (IS_SET(features_2, 0))
103 features |= X86_CPU_FEATURE_SSE3;
105 if (IS_SET(features_2, 9))
106 features |= X86_CPU_FEATURE_SSSE3;
108 if (IS_SET(features_2, 19))
109 features |= X86_CPU_FEATURE_SSE4_1;
111 if (IS_SET(features_2, 20))
112 features |= X86_CPU_FEATURE_SSE4_2;
114 if (IS_SET(features_2, 27)) /* OSXSAVE set? */
115 if ((read_xcr(0) & 0x6) == 0x6)
116 os_saves_ymm_regs = true;
118 if (os_saves_ymm_regs && IS_SET(features_2, 28))
119 features |= X86_CPU_FEATURE_AVX;
121 if (max_function < 7)
124 /* Extended feature flags */
125 cpuid(7, 0, &dummy1, &features_3, &features_4, &dummy4);
127 if (IS_SET(features_3, 3))
128 features |= X86_CPU_FEATURE_BMI;
130 if (os_saves_ymm_regs && IS_SET(features_3, 5))
131 features |= X86_CPU_FEATURE_AVX2;
133 if (IS_SET(features_3, 8))
134 features |= X86_CPU_FEATURE_BMI2;
139 printf("Detected x86 CPU features: ");
140 if (features & X86_CPU_FEATURE_SSE)
142 if (features & X86_CPU_FEATURE_SSE2)
144 if (features & X86_CPU_FEATURE_SSE3)
146 if (features & X86_CPU_FEATURE_SSSE3)
148 if (features & X86_CPU_FEATURE_SSE4_1)
150 if (features & X86_CPU_FEATURE_SSE4_2)
152 if (features & X86_CPU_FEATURE_BMI)
154 if (features & X86_CPU_FEATURE_AVX)
156 if (features & X86_CPU_FEATURE_BMI2)
158 if (features & X86_CPU_FEATURE_AVX2)
163 _x86_cpu_features = features | X86_CPU_FEATURES_KNOWN;
166 #endif /* __i386__ || __x86_64__ */