1 # the module will build and run cpuid utility, which store detected
2 # host processor features into cpuid.txt file in form:
3 # FEATURE [not] supported
4 # variable HAVE_CPUID_INFO set in case of success
5 # if variable HAVE_CPUID_INFO is set then it is possible
6 # to test HAVE_SSE42/HAVE_AVX2 variables
8 include (CheckCXXSourceRuns)
11 set(CMAKE_REQUIRED_FLAGS "-std=c++11")
14 check_cxx_source_runs(
17 // Compile by using: cl /EHsc /W4 InstructionSet.cpp
18 // processor: x86, x64
19 // Uses the __cpuid intrinsic to get information about
20 // CPU extended instruction set support.
23 // https://msdn.microsoft.com/en-us/library/hskdteyh.aspx
24 // https://gcc.gnu.org/git/?p=gcc.git;a=blob_plain;f=gcc/config/i386/driver-i386.c
42 // forward declarations
43 class InstructionSet_Internal;
47 static std::string Vendor(void) { return CPU_Rep.vendor_; }
48 static std::string Brand(void) { return CPU_Rep.brand_; }
50 static bool SSE3(void) { return CPU_Rep.f_1_ECX_[0]; }
51 static bool PCLMULQDQ(void) { return CPU_Rep.f_1_ECX_[1]; }
52 static bool MONITOR(void) { return CPU_Rep.f_1_ECX_[3]; }
53 static bool SSSE3(void) { return CPU_Rep.f_1_ECX_[9]; }
54 static bool FMA(void) { return CPU_Rep.f_1_ECX_[12]; }
55 static bool CMPXCHG16B(void) { return CPU_Rep.f_1_ECX_[13]; }
56 static bool SSE41(void) { return CPU_Rep.f_1_ECX_[19]; }
57 static bool SSE42(void) { return CPU_Rep.f_1_ECX_[20]; }
58 static bool MOVBE(void) { return CPU_Rep.f_1_ECX_[22]; }
59 static bool POPCNT(void) { return CPU_Rep.f_1_ECX_[23]; }
60 static bool AES(void) { return CPU_Rep.f_1_ECX_[25]; }
61 static bool XSAVE(void) { return CPU_Rep.f_1_ECX_[26]; }
62 static bool OSXSAVE(void) { return CPU_Rep.f_1_ECX_[27]; }
63 static bool AVX(void) { return CPU_Rep.f_1_ECX_[28]; }
64 static bool F16C(void) { return CPU_Rep.f_1_ECX_[29]; }
65 static bool RDRAND(void) { return CPU_Rep.f_1_ECX_[30]; }
67 static bool MSR(void) { return CPU_Rep.f_1_EDX_[5]; }
68 static bool CX8(void) { return CPU_Rep.f_1_EDX_[8]; }
69 static bool SEP(void) { return CPU_Rep.f_1_EDX_[11]; }
70 static bool CMOV(void) { return CPU_Rep.f_1_EDX_[15]; }
71 static bool CLFSH(void) { return CPU_Rep.f_1_EDX_[19]; }
72 static bool MMX(void) { return CPU_Rep.f_1_EDX_[23]; }
73 static bool FXSR(void) { return CPU_Rep.f_1_EDX_[24]; }
74 static bool SSE(void) { return CPU_Rep.f_1_EDX_[25]; }
75 static bool SSE2(void) { return CPU_Rep.f_1_EDX_[26]; }
77 static bool FSGSBASE(void) { return CPU_Rep.f_7_EBX_[0]; }
78 static bool BMI1(void) { return CPU_Rep.f_7_EBX_[3]; }
79 static bool HLE(void) { return CPU_Rep.isIntel_ && CPU_Rep.f_7_EBX_[4]; }
80 static bool AVX2(void) { return CPU_Rep.f_7_EBX_[5]; }
81 static bool BMI2(void) { return CPU_Rep.f_7_EBX_[8]; }
82 static bool ERMS(void) { return CPU_Rep.f_7_EBX_[9]; }
83 static bool INVPCID(void) { return CPU_Rep.f_7_EBX_[10]; }
84 static bool RTM(void) { return CPU_Rep.isIntel_ && CPU_Rep.f_7_EBX_[11]; }
85 static bool AVX512F(void) { return CPU_Rep.f_7_EBX_[16]; }
86 static bool RDSEED(void) { return CPU_Rep.f_7_EBX_[18]; }
87 static bool ADX(void) { return CPU_Rep.f_7_EBX_[19]; }
88 static bool AVX512PF(void) { return CPU_Rep.f_7_EBX_[26]; }
89 static bool AVX512ER(void) { return CPU_Rep.f_7_EBX_[27]; }
90 static bool AVX512CD(void) { return CPU_Rep.f_7_EBX_[28]; }
91 static bool SHA(void) { return CPU_Rep.f_7_EBX_[29]; }
93 static bool PREFETCHWT1(void) { return CPU_Rep.f_7_ECX_[0]; }
95 static bool LAHF(void) { return CPU_Rep.f_81_ECX_[0]; }
96 static bool LZCNT(void) { return CPU_Rep.isIntel_ && CPU_Rep.f_81_ECX_[5]; }
97 static bool ABM(void) { return CPU_Rep.isAMD_ && CPU_Rep.f_81_ECX_[5]; }
98 static bool SSE4a(void) { return CPU_Rep.isAMD_ && CPU_Rep.f_81_ECX_[6]; }
99 static bool XOP(void) { return CPU_Rep.isAMD_ && CPU_Rep.f_81_ECX_[11]; }
100 static bool TBM(void) { return CPU_Rep.isAMD_ && CPU_Rep.f_81_ECX_[21]; }
102 static bool SYSCALL(void) { return CPU_Rep.isIntel_ && CPU_Rep.f_81_EDX_[11]; }
103 static bool MMXEXT(void) { return CPU_Rep.isAMD_ && CPU_Rep.f_81_EDX_[22]; }
104 static bool RDTSCP(void) { return CPU_Rep.isIntel_ && CPU_Rep.f_81_EDX_[27]; }
105 static bool _3DNOWEXT(void) { return CPU_Rep.isAMD_ && CPU_Rep.f_81_EDX_[30]; }
106 static bool _3DNOW(void) { return CPU_Rep.isAMD_ && CPU_Rep.f_81_EDX_[31]; }
109 static const InstructionSet_Internal CPU_Rep;
111 class InstructionSet_Internal
114 InstructionSet_Internal()
129 std::array<int, 4> cpui;
131 std::array<unsigned int, 4> cpui;
134 // Calling __cpuid with 0x0 as the function_id argument
135 // gets the number of the highest valid function ID.
137 __cpuid(cpui.data(), 0);
139 cpui[0] = __get_cpuid_max(0, &cpui[1]);
143 for (int i = 0; i <= nIds_; ++i)
146 __cpuidex(cpui.data(), i, 0);
148 __cpuid_count(i, 0, cpui[0], cpui[1], cpui[2], cpui[3]);
151 data_.push_back(cpui);
154 // Capture vendor string
156 memset(vendor, 0, sizeof(vendor));
157 *reinterpret_cast<int*>(vendor + 0) = data_[0][1];
158 *reinterpret_cast<int*>(vendor + 4) = data_[0][3];
159 *reinterpret_cast<int*>(vendor + 8) = data_[0][2];
161 if (vendor_ == \"GenuineIntel\")
165 else if (vendor_ == \"AuthenticAMD\")
170 // load bitset with flags for function 0x00000001
173 f_1_ECX_ = data_[1][2];
174 f_1_EDX_ = data_[1][3];
177 // load bitset with flags for function 0x00000007
180 f_7_EBX_ = data_[7][1];
181 f_7_ECX_ = data_[7][2];
184 // Calling __cpuid with 0x80000000 as the function_id argument
185 // gets the number of the highest valid extended ID.
187 __cpuid(cpui.data(), 0x80000000);
189 __cpuid(0x80000000, cpui[0], cpui[1], cpui[2], cpui[3]);
194 memset(brand, 0, sizeof(brand));
196 for (int i = 0x80000000; i <= nExIds_; ++i)
199 __cpuidex(cpui.data(), i, 0);
201 __cpuid_count(i, 0, cpui[0], cpui[1], cpui[2], cpui[3]);
203 extdata_.push_back(cpui);
206 // load bitset with flags for function 0x80000001
207 if (nExIds_ >= 0x80000001)
209 f_81_ECX_ = extdata_[1][2];
210 f_81_EDX_ = extdata_[1][3];
213 // Interpret CPU brand string if reported
214 if (nExIds_ >= 0x80000004)
216 memcpy(brand + 0, extdata_[2].data(), sizeof(cpui));
217 memcpy(brand + 16, extdata_[3].data(), sizeof(cpui));
218 memcpy(brand + 32, extdata_[4].data(), sizeof(cpui));
229 std::bitset<32> f_1_ECX_;
230 std::bitset<32> f_1_EDX_;
231 std::bitset<32> f_7_EBX_;
232 std::bitset<32> f_7_ECX_;
233 std::bitset<32> f_81_ECX_;
234 std::bitset<32> f_81_EDX_;
236 std::vector<std::array<int, 4>> data_;
237 std::vector<std::array<int, 4>> extdata_;
239 std::vector<std::array<unsigned int, 4>> data_;
240 std::vector<std::array<unsigned int, 4>> extdata_;
245 // Initialize static member data
246 const InstructionSet::InstructionSet_Internal InstructionSet::CPU_Rep;
248 // Print out supported instruction set extensions
251 std::ofstream fo(\"cpuid.txt\");
252 auto& outstream = fo;//std::cout;
254 auto support_message = [&outstream](std::string isa_feature, bool is_supported) {
255 outstream << isa_feature << (is_supported ? \" supported\" : \" not supported\") << std::endl;
258 std::cout << InstructionSet::Vendor() << std::endl;
259 std::cout << InstructionSet::Brand() << std::endl;
261 support_message(\"3DNOW\", InstructionSet::_3DNOW());
262 support_message(\"3DNOWEXT\", InstructionSet::_3DNOWEXT());
263 support_message(\"ABM\", InstructionSet::ABM());
264 support_message(\"ADX\", InstructionSet::ADX());
265 support_message(\"AES\", InstructionSet::AES());
266 support_message(\"AVX\", InstructionSet::AVX());
267 support_message(\"AVX2\", InstructionSet::AVX2());
268 support_message(\"AVX512CD\", InstructionSet::AVX512CD());
269 support_message(\"AVX512F\", InstructionSet::AVX512F());
270 support_message(\"AVX512ER\", InstructionSet::AVX512ER());
271 support_message(\"AVX512PF\", InstructionSet::AVX512PF());
272 support_message(\"BMI1\", InstructionSet::BMI1());
273 support_message(\"BMI2\", InstructionSet::BMI2());
274 support_message(\"CLFSH\", InstructionSet::CLFSH());
275 support_message(\"CMPXCHG16B\", InstructionSet::CMPXCHG16B());
276 support_message(\"CX8\", InstructionSet::CX8());
277 support_message(\"ERMS\", InstructionSet::ERMS());
278 support_message(\"F16C\", InstructionSet::F16C());
279 support_message(\"FMA\", InstructionSet::FMA());
280 support_message(\"FSGSBASE\", InstructionSet::FSGSBASE());
281 support_message(\"FXSR\", InstructionSet::FXSR());
282 support_message(\"HLE\", InstructionSet::HLE());
283 support_message(\"INVPCID\", InstructionSet::INVPCID());
284 support_message(\"LAHF\", InstructionSet::LAHF());
285 support_message(\"LZCNT\", InstructionSet::LZCNT());
286 support_message(\"MMX\", InstructionSet::MMX());
287 support_message(\"MMXEXT\", InstructionSet::MMXEXT());
288 support_message(\"MONITOR\", InstructionSet::MONITOR());
289 support_message(\"MOVBE\", InstructionSet::MOVBE());
290 support_message(\"MSR\", InstructionSet::MSR());
291 support_message(\"OSXSAVE\", InstructionSet::OSXSAVE());
292 support_message(\"PCLMULQDQ\", InstructionSet::PCLMULQDQ());
293 support_message(\"POPCNT\", InstructionSet::POPCNT());
294 support_message(\"PREFETCHWT1\", InstructionSet::PREFETCHWT1());
295 support_message(\"RDRAND\", InstructionSet::RDRAND());
296 support_message(\"RDSEED\", InstructionSet::RDSEED());
297 support_message(\"RDTSCP\", InstructionSet::RDTSCP());
298 support_message(\"RTM\", InstructionSet::RTM());
299 support_message(\"SEP\", InstructionSet::SEP());
300 support_message(\"SHA\", InstructionSet::SHA());
301 support_message(\"SSE\", InstructionSet::SSE());
302 support_message(\"SSE2\", InstructionSet::SSE2());
303 support_message(\"SSE3\", InstructionSet::SSE3());
304 support_message(\"SSE4.1\", InstructionSet::SSE41());
305 support_message(\"SSE4.2\", InstructionSet::SSE42());
306 support_message(\"SSE4a\", InstructionSet::SSE4a());
307 support_message(\"SSSE3\", InstructionSet::SSSE3());
308 support_message(\"SYSCALL\", InstructionSet::SYSCALL());
309 support_message(\"TBM\", InstructionSet::TBM());
310 support_message(\"XOP\", InstructionSet::XOP());
311 support_message(\"XSAVE\", InstructionSet::XSAVE());
319 set(_CPUID_INFO "${CMAKE_BINARY_DIR}/cpuid.txt")
320 set(HAVE_AVX512F FALSE)
322 set(HAVE_SSE42 FALSE)
324 file(STRINGS ${_CPUID_INFO} _FEATURES)
326 message(STATUS "Host CPU features:")
328 foreach(FEATURE IN ITEMS ${_FEATURES})
330 message(STATUS " ${FEATURE}")
332 string(COMPARE EQUAL "${FEATURE}" "AVX512F supported" _FEATURE_FOUND)
333 if(${_FEATURE_FOUND})
334 if (NOT CMAKE_CXX_COMPILER_ID STREQUAL "GNU" OR CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 4.9)
335 set(HAVE_AVX512F ${_FEATURE_FOUND})
337 message(WARNING "Compiler doesn't support AVX512 instructuion set")
340 string(COMPARE EQUAL "${FEATURE}" "AVX2 supported" _FEATURE_FOUND)
341 if(${_FEATURE_FOUND})
342 set(HAVE_AVX2 ${_FEATURE_FOUND})
344 string(COMPARE EQUAL "${FEATURE}" "SSE4.2 supported" _FEATURE_FOUND)
345 if(${_FEATURE_FOUND})
346 set(HAVE_SSE42 ${_FEATURE_FOUND})
350 unset(_FEATURE_FOUND)