24 #if defined(__x86_64__) || defined(_M_X64) || defined(__i386) || defined(_M_IX86) 25 #if defined(_WIN32) && ( !defined(__MINGW32__) || ( !defined(__i386) && !defined(_M_IX86) ) ) 26 #include "cpu_x86_Windows.ipp" 27 #elif defined(__GNUC__) || defined(__clang__) 28 #include "cpu_x86_Linux.ipp" 38 #ifndef _XCR_XFEATURE_ENABLED_MASK 39 #define _XCR_XFEATURE_ENABLED_MASK 0 42 #ifndef DOXYGEN_SHOULD_SKIP_THIS 43 namespace FeatureDetector
53 void cpu_x86::print(
const char *label,
bool yes)
56 cout << (yes ?
"Yes" :
"No") << endl;
64 memset(
this, 0,
sizeof(*
this));
67 bool cpu_x86::detect_OS_AVX()
72 bool avxSupported =
false;
77 bool osUsesXSAVE_XRSTORE = (cpuInfo[2] & (1 << 27)) != 0;
78 bool cpuAVXSuport = (cpuInfo[2] & (1 << 28)) != 0;
80 if (osUsesXSAVE_XRSTORE && cpuAVXSuport) {
81 uint64_t xcrFeatureMask = xgetbv(_XCR_XFEATURE_ENABLED_MASK);
82 avxSupported = (xcrFeatureMask & 0x6) == 0x6;
90 bool cpu_x86::detect_OS_AVX512()
96 uint64_t xcrFeatureMask = xgetbv(_XCR_XFEATURE_ENABLED_MASK);
97 return (xcrFeatureMask & 0xe6) == 0xe6;
102 std::string cpu_x86::get_vendor_string()
109 memcpy(name + 0, &CPUInfo[1], 4);
110 memcpy(name + 4, &CPUInfo[3], 4);
111 memcpy(name + 8, &CPUInfo[2], 4);
116 return std::string();
123 void cpu_x86::detect_host()
127 OS_x64 = detect_OS_x64();
128 OS_AVX = detect_OS_AVX();
129 OS_AVX512 = detect_OS_AVX512();
132 std::string vendor(get_vendor_string());
133 if (vendor ==
"GenuineIntel") {
135 }
else if (vendor ==
"AuthenticAMD") {
143 cpuid(info, 0x80000000);
144 uint32_t nExIds = info[0];
147 if (nIds >= 0x00000001) {
148 cpuid(info, 0x00000001);
149 HW_MMX = (info[3] & ((int)1 << 23)) != 0;
150 HW_SSE = (info[3] & ((int)1 << 25)) != 0;
151 HW_SSE2 = (info[3] & ((int)1 << 26)) != 0;
152 HW_SSE3 = (info[2] & ((int)1 << 0)) != 0;
154 HW_SSSE3 = (info[2] & ((int)1 << 9)) != 0;
155 HW_SSE41 = (info[2] & ((int)1 << 19)) != 0;
156 HW_SSE42 = (info[2] & ((int)1 << 20)) != 0;
157 HW_AES = (info[2] & ((int)1 << 25)) != 0;
159 HW_AVX = (info[2] & ((int)1 << 28)) != 0;
160 HW_FMA3 = (info[2] & ((int)1 << 12)) != 0;
162 HW_RDRAND = (info[2] & ((int)1 << 30)) != 0;
164 if (nIds >= 0x00000007) {
165 cpuid(info, 0x00000007);
166 HW_AVX2 = (info[1] & ((int)1 << 5)) != 0;
168 HW_BMI1 = (info[1] & ((int)1 << 3)) != 0;
169 HW_BMI2 = (info[1] & ((int)1 << 8)) != 0;
170 HW_ADX = (info[1] & ((int)1 << 19)) != 0;
171 HW_MPX = (info[1] & ((int)1 << 14)) != 0;
172 HW_SHA = (info[1] & ((int)1 << 29)) != 0;
173 HW_PREFETCHWT1 = (info[2] & ((int)1 << 0)) != 0;
175 HW_AVX512_F = (info[1] & ((int)1 << 16)) != 0;
176 HW_AVX512_CD = (info[1] & ((int)1 << 28)) != 0;
177 HW_AVX512_PF = (info[1] & ((int)1 << 26)) != 0;
178 HW_AVX512_ER = (info[1] & ((int)1 << 27)) != 0;
179 HW_AVX512_VL = (info[1] & ((int)1 << 31)) != 0;
180 HW_AVX512_BW = (info[1] & ((int)1 << 30)) != 0;
181 HW_AVX512_DQ = (info[1] & ((int)1 << 17)) != 0;
182 HW_AVX512_IFMA = (info[1] & ((int)1 << 21)) != 0;
183 HW_AVX512_VBMI = (info[2] & ((int)1 << 1)) != 0;
185 if (nExIds >= 0x80000001) {
186 cpuid(info, 0x80000001);
187 HW_x64 = (info[3] & ((int)1 << 29)) != 0;
188 HW_ABM = (info[2] & ((int)1 << 5)) != 0;
189 HW_SSE4a = (info[2] & ((int)1 << 6)) != 0;
190 HW_FMA4 = (info[2] & ((int)1 << 16)) != 0;
191 HW_XOP = (info[2] & ((int)1 << 11)) != 0;
195 void cpu_x86::print()
const 197 cout <<
"CPU Vendor:" << endl;
198 print(
" AMD = ", Vendor_AMD);
199 print(
" Intel = ", Vendor_Intel);
202 cout <<
"OS Features:" << endl;
204 print(
" 64-bit = ", OS_x64);
206 print(
" OS AVX = ", OS_AVX);
207 print(
" OS AVX512 = ", OS_AVX512);
210 cout <<
"Hardware Features:" << endl;
211 print(
" MMX = ", HW_MMX);
212 print(
" x64 = ", HW_x64);
213 print(
" ABM = ", HW_ABM);
214 print(
" RDRAND = ", HW_RDRAND);
215 print(
" BMI1 = ", HW_BMI1);
216 print(
" BMI2 = ", HW_BMI2);
217 print(
" ADX = ", HW_ADX);
218 print(
" MPX = ", HW_MPX);
219 print(
" PREFETCHWT1 = ", HW_PREFETCHWT1);
222 cout <<
"SIMD: 128-bit" << endl;
223 print(
" SSE = ", HW_SSE);
224 print(
" SSE2 = ", HW_SSE2);
225 print(
" SSE3 = ", HW_SSE3);
226 print(
" SSSE3 = ", HW_SSSE3);
227 print(
" SSE4a = ", HW_SSE4a);
228 print(
" SSE4.1 = ", HW_SSE41);
229 print(
" SSE4.2 = ", HW_SSE42);
230 print(
" AES-NI = ", HW_AES);
231 print(
" SHA = ", HW_SHA);
234 cout <<
"SIMD: 256-bit" << endl;
235 print(
" AVX = ", HW_AVX);
236 print(
" XOP = ", HW_XOP);
237 print(
" FMA3 = ", HW_FMA3);
238 print(
" FMA4 = ", HW_FMA4);
239 print(
" AVX2 = ", HW_AVX2);
242 cout <<
"SIMD: 512-bit" << endl;
243 print(
" AVX512-F = ", HW_AVX512_F);
244 print(
" AVX512-CD = ", HW_AVX512_CD);
245 print(
" AVX512-PF = ", HW_AVX512_PF);
246 print(
" AVX512-ER = ", HW_AVX512_ER);
247 print(
" AVX512-VL = ", HW_AVX512_VL);
248 print(
" AVX512-BW = ", HW_AVX512_BW);
249 print(
" AVX512-DQ = ", HW_AVX512_DQ);
250 print(
" AVX512-IFMA = ", HW_AVX512_IFMA);
251 print(
" AVX512-VBMI = ", HW_AVX512_VBMI);
254 cout <<
"Summary:" << endl;
255 print(
" Safe to use AVX: ", HW_AVX && OS_AVX);
256 print(
" Safe to use AVX512: ", HW_AVX512_F && OS_AVX512);