2 * x86_cpu_features.c - feature detection for x86 processors
4 * The following copying information applies to this specific source code file:
6 * Written in 2015 by Eric Biggers <ebiggers3@gmail.com>
8 * To the extent possible under law, the author(s) have dedicated all copyright
9 * and related and neighboring rights to this software to the public domain
10 * worldwide via the Creative Commons Zero 1.0 Universal Public Domain
11 * Dedication (the "CC0").
13 * This software is distributed in the hope that it will be useful, but WITHOUT
14 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
15 * FOR A PARTICULAR PURPOSE. See the CC0 for more details.
17 * You should have received a copy of the CC0 along with this software; if not
18 * see <http://creativecommons.org/publicdomain/zero/1.0/>.
25 #include "wimlib/x86_cpu_features.h"
27 #if defined(__i386__) || defined(__x86_64__)
35 u32 _x86_cpu_features = 0;
37 /* With old GCC versions we have to manually save and restore the x86_32 PIC
38 * register (ebx). See: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=47602 */
39 #if defined(__i386__) && defined(__PIC__)
40 # define EBX_CONSTRAINT "=r"
42 # define EBX_CONSTRAINT "=b"
45 /* Execute the CPUID instruction. */
47 cpuid(u32 leaf, u32 subleaf, u32 *a, u32 *b, u32 *c, u32 *d)
49 __asm__(".ifnc %%ebx, %1; mov %%ebx, %1; .endif\n"
51 ".ifnc %%ebx, %1; xchg %%ebx, %1; .endif\n"
52 : "=a" (*a), EBX_CONSTRAINT (*b), "=c" (*c), "=d" (*d)
53 : "a" (leaf), "c" (subleaf));
56 /* Read an extended control register. */
62 /* Execute the "xgetbv" instruction. Old versions of binutils do not
63 * recognize this instruction, so list the raw bytes instead. */
64 __asm__ (".byte 0x0f, 0x01, 0xd0" : "=d" (edx), "=a" (eax) : "c" (index));
66 return ((u64)edx << 32) | eax;
69 #define IS_SET(reg, bit) ((reg) & ((u32)1 << (bit)))
71 /* Initialize _x86_cpu_features with bits for interesting processor features. */
73 x86_setup_cpu_features(void)
76 u32 dummy1, dummy2, dummy3, dummy4;
78 u32 features_1, features_2, features_3, features_4;
79 bool os_saves_ymm_regs = false;
81 /* Get maximum supported function */
82 cpuid(0, 0, &max_function, &dummy2, &dummy3, &dummy4);
86 /* Standard feature flags */
87 cpuid(1, 0, &dummy1, &dummy2, &features_2, &features_1);
89 if (IS_SET(features_1, 25))
90 features |= X86_CPU_FEATURE_SSE;
92 if (IS_SET(features_1, 26))
93 features |= X86_CPU_FEATURE_SSE2;
95 if (IS_SET(features_2, 0))
96 features |= X86_CPU_FEATURE_SSE3;
98 if (IS_SET(features_2, 9))
99 features |= X86_CPU_FEATURE_SSSE3;
101 if (IS_SET(features_2, 19))
102 features |= X86_CPU_FEATURE_SSE4_1;
104 if (IS_SET(features_2, 20))
105 features |= X86_CPU_FEATURE_SSE4_2;
107 if (IS_SET(features_2, 27)) /* OSXSAVE set? */
108 if ((read_xcr(0) & 0x6) == 0x6)
109 os_saves_ymm_regs = true;
111 if (os_saves_ymm_regs && IS_SET(features_2, 28))
112 features |= X86_CPU_FEATURE_AVX;
114 if (max_function < 7)
117 /* Extended feature flags */
118 cpuid(7, 0, &dummy1, &features_3, &features_4, &dummy4);
120 if (IS_SET(features_3, 3))
121 features |= X86_CPU_FEATURE_BMI;
123 if (os_saves_ymm_regs && IS_SET(features_3, 5))
124 features |= X86_CPU_FEATURE_AVX2;
126 if (IS_SET(features_3, 8))
127 features |= X86_CPU_FEATURE_BMI2;
132 printf("Detected x86 CPU features: ");
133 if (features & X86_CPU_FEATURE_SSE)
135 if (features & X86_CPU_FEATURE_SSE2)
137 if (features & X86_CPU_FEATURE_SSE3)
139 if (features & X86_CPU_FEATURE_SSSE3)
141 if (features & X86_CPU_FEATURE_SSE4_1)
143 if (features & X86_CPU_FEATURE_SSE4_2)
145 if (features & X86_CPU_FEATURE_BMI)
147 if (features & X86_CPU_FEATURE_AVX)
149 if (features & X86_CPU_FEATURE_BMI2)
151 if (features & X86_CPU_FEATURE_AVX2)
156 _x86_cpu_features = features | X86_CPU_FEATURES_KNOWN;
159 #endif /* __i386__ || __x86_64__ */