54#if defined(__x86_64__) || defined(_M_X64) || defined(__i386) || defined(_M_IX86)
55#if defined(_WIN32) && (!defined(__MINGW32__) || (!defined(__i386) && !defined(_M_IX86)))
56#include "cpu_x86_Windows.ipp"
57#elif defined(__GNUC__) || defined(__clang__)
58#include "cpu_x86_Linux.ipp"
68#ifndef _XCR_XFEATURE_ENABLED_MASK
69#define _XCR_XFEATURE_ENABLED_MASK 0
72#ifndef DOXYGEN_SHOULD_SKIP_THIS
73namespace FeatureDetector
83void cpu_x86::print(
const char *label,
bool yes)
86 cout << (yes ?
"Yes" :
"No") << endl;
94 memset(
this, 0,
sizeof(*
this));
97bool cpu_x86::detect_OS_AVX()
102 bool avxSupported =
false;
107 bool osUsesXSAVE_XRSTORE = (cpuInfo[2] & (1 << 27)) != 0;
108 bool cpuAVXSuport = (cpuInfo[2] & (1 << 28)) != 0;
110 if (osUsesXSAVE_XRSTORE && cpuAVXSuport) {
111 uint64_t xcrFeatureMask = xgetbv(_XCR_XFEATURE_ENABLED_MASK);
112 avxSupported = (xcrFeatureMask & 0x6) == 0x6;
120bool cpu_x86::detect_OS_AVX512()
123 if (!detect_OS_AVX())
126 uint64_t xcrFeatureMask = xgetbv(_XCR_XFEATURE_ENABLED_MASK);
127 return (xcrFeatureMask & 0xe6) == 0xe6;
132std::string cpu_x86::get_vendor_string()
139 memcpy(name + 0, &CPUInfo[1], 4);
140 memcpy(name + 4, &CPUInfo[3], 4);
141 memcpy(name + 8, &CPUInfo[2], 4);
146 return std::string();
153void cpu_x86::detect_host()
157 OS_x64 = detect_OS_x64();
158 OS_AVX = detect_OS_AVX();
159 OS_AVX512 = detect_OS_AVX512();
162 std::string vendor(get_vendor_string());
163 if (vendor ==
"GenuineIntel") {
166 else if (vendor ==
"AuthenticAMD") {
174 cpuid(info, 0x80000000);
175 uint32_t nExIds = info[0];
178 if (nIds >= 0x00000001) {
179 cpuid(info, 0x00000001);
180 HW_MMX = (info[3] & ((int)1 << 23)) != 0;
181 HW_SSE = (info[3] & ((int)1 << 25)) != 0;
182 HW_SSE2 = (info[3] & ((int)1 << 26)) != 0;
183 HW_SSE3 = (info[2] & ((int)1 << 0)) != 0;
185 HW_SSSE3 = (info[2] & ((int)1 << 9)) != 0;
186 HW_SSE41 = (info[2] & ((int)1 << 19)) != 0;
187 HW_SSE42 = (info[2] & ((int)1 << 20)) != 0;
188 HW_AES = (info[2] & ((int)1 << 25)) != 0;
190 HW_AVX = (info[2] & ((int)1 << 28)) != 0;
191 HW_FMA3 = (info[2] & ((int)1 << 12)) != 0;
193 HW_RDRAND = (info[2] & ((int)1 << 30)) != 0;
195 if (nIds >= 0x00000007) {
196 cpuid(info, 0x00000007);
197 HW_AVX2 = (info[1] & ((int)1 << 5)) != 0;
199 HW_BMI1 = (info[1] & ((int)1 << 3)) != 0;
200 HW_BMI2 = (info[1] & ((int)1 << 8)) != 0;
201 HW_ADX = (info[1] & ((int)1 << 19)) != 0;
202 HW_MPX = (info[1] & ((int)1 << 14)) != 0;
203 HW_SHA = (info[1] & ((int)1 << 29)) != 0;
204 HW_PREFETCHWT1 = (info[2] & ((int)1 << 0)) != 0;
206 HW_AVX512_F = (info[1] & ((int)1 << 16)) != 0;
207 HW_AVX512_CD = (info[1] & ((int)1 << 28)) != 0;
208 HW_AVX512_PF = (info[1] & ((int)1 << 26)) != 0;
209 HW_AVX512_ER = (info[1] & ((int)1 << 27)) != 0;
210 HW_AVX512_VL = (info[1] & ((int)1 << 31)) != 0;
211 HW_AVX512_BW = (info[1] & ((int)1 << 30)) != 0;
212 HW_AVX512_DQ = (info[1] & ((int)1 << 17)) != 0;
213 HW_AVX512_IFMA = (info[1] & ((int)1 << 21)) != 0;
214 HW_AVX512_VBMI = (info[2] & ((int)1 << 1)) != 0;
216 if (nExIds >= 0x80000001) {
217 cpuid(info, 0x80000001);
218 HW_x64 = (info[3] & ((int)1 << 29)) != 0;
219 HW_ABM = (info[2] & ((int)1 << 5)) != 0;
220 HW_SSE4a = (info[2] & ((int)1 << 6)) != 0;
221 HW_FMA4 = (info[2] & ((int)1 << 16)) != 0;
222 HW_XOP = (info[2] & ((int)1 << 11)) != 0;
226void cpu_x86::print()
const
228 cout <<
"CPU Vendor:" << endl;
229 print(
" AMD = ", Vendor_AMD);
230 print(
" Intel = ", Vendor_Intel);
233 cout <<
"OS Features:" << endl;
235 print(
" 64-bit = ", OS_x64);
237 print(
" OS AVX = ", OS_AVX);
238 print(
" OS AVX512 = ", OS_AVX512);
241 cout <<
"Hardware Features:" << endl;
242 print(
" MMX = ", HW_MMX);
243 print(
" x64 = ", HW_x64);
244 print(
" ABM = ", HW_ABM);
245 print(
" RDRAND = ", HW_RDRAND);
246 print(
" BMI1 = ", HW_BMI1);
247 print(
" BMI2 = ", HW_BMI2);
248 print(
" ADX = ", HW_ADX);
249 print(
" MPX = ", HW_MPX);
250 print(
" PREFETCHWT1 = ", HW_PREFETCHWT1);
253 cout <<
"SIMD: 128-bit" << endl;
254 print(
" SSE = ", HW_SSE);
255 print(
" SSE2 = ", HW_SSE2);
256 print(
" SSE3 = ", HW_SSE3);
257 print(
" SSSE3 = ", HW_SSSE3);
258 print(
" SSE4a = ", HW_SSE4a);
259 print(
" SSE4.1 = ", HW_SSE41);
260 print(
" SSE4.2 = ", HW_SSE42);
261 print(
" AES-NI = ", HW_AES);
262 print(
" SHA = ", HW_SHA);
265 cout <<
"SIMD: 256-bit" << endl;
266 print(
" AVX = ", HW_AVX);
267 print(
" XOP = ", HW_XOP);
268 print(
" FMA3 = ", HW_FMA3);
269 print(
" FMA4 = ", HW_FMA4);
270 print(
" AVX2 = ", HW_AVX2);
273 cout <<
"SIMD: 512-bit" << endl;
274 print(
" AVX512-F = ", HW_AVX512_F);
275 print(
" AVX512-CD = ", HW_AVX512_CD);
276 print(
" AVX512-PF = ", HW_AVX512_PF);
277 print(
" AVX512-ER = ", HW_AVX512_ER);
278 print(
" AVX512-VL = ", HW_AVX512_VL);
279 print(
" AVX512-BW = ", HW_AVX512_BW);
280 print(
" AVX512-DQ = ", HW_AVX512_DQ);
281 print(
" AVX512-IFMA = ", HW_AVX512_IFMA);
282 print(
" AVX512-VBMI = ", HW_AVX512_VBMI);
285 cout <<
"Summary:" << endl;
286 print(
" Safe to use AVX: ", HW_AVX && OS_AVX);
287 print(
" Safe to use AVX512: ", HW_AVX512_F && OS_AVX512);