Publishing R3
[platform/upstream/dldt.git] / inference-engine / samples / cmake / CPUID.cmake
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
7
8 include (CheckCXXSourceRuns)
9
10 if(NOT WIN32)
11     set(CMAKE_REQUIRED_FLAGS "-std=c++11")
12 endif()
13
14 check_cxx_source_runs(
15 "
16 // InstructionSet.cpp
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.
21 //
22 // source origin:
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
25
26
27 #include <iostream>
28 #include <fstream>
29 #include <vector>
30 #include <bitset>
31 #include <array>
32 #include <string>
33 #ifdef WIN32
34 #include <intrin.h>
35 #else
36 #include <cpuid.h>
37 #include <string.h>
38 #endif
39
40 class InstructionSet
41 {
42     // forward declarations
43     class InstructionSet_Internal;
44
45 public:
46     // getters
47     static std::string Vendor(void) { return CPU_Rep.vendor_; }
48     static std::string Brand(void) { return CPU_Rep.brand_; }
49
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]; }
66
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]; }
76
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]; }
92
93     static bool PREFETCHWT1(void) { return CPU_Rep.f_7_ECX_[0]; }
94
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]; }
101
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]; }
107
108 private:
109     static const InstructionSet_Internal CPU_Rep;
110
111     class InstructionSet_Internal
112     {
113     public:
114         InstructionSet_Internal()
115             : nIds_{ 0 },
116             nExIds_{ 0 },
117             isIntel_{ false },
118             isAMD_{ false },
119             f_1_ECX_{ 0 },
120             f_1_EDX_{ 0 },
121             f_7_EBX_{ 0 },
122             f_7_ECX_{ 0 },
123             f_81_ECX_{ 0 },
124             f_81_EDX_{ 0 },
125             data_{},
126             extdata_{}
127         {
128 #ifdef WIN32
129             std::array<int, 4> cpui;
130 #else
131             std::array<unsigned int, 4> cpui;
132 #endif
133
134             // Calling __cpuid with 0x0 as the function_id argument
135             // gets the number of the highest valid function ID.
136 #ifdef WIN32
137             __cpuid(cpui.data(), 0);
138 #else
139             cpui[0] = __get_cpuid_max(0, &cpui[1]);
140 #endif
141             nIds_ = cpui[0];
142
143             for (int i = 0; i <= nIds_; ++i)
144             {
145 #ifdef WIN32
146                 __cpuidex(cpui.data(), i, 0);
147 #else
148                 __cpuid_count(i, 0, cpui[0], cpui[1], cpui[2], cpui[3]);
149 #endif
150
151                 data_.push_back(cpui);
152             }
153
154             // Capture vendor string
155             char vendor[0x20];
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];
160             vendor_ = vendor;
161             if (vendor_ == \"GenuineIntel\")
162             {
163                 isIntel_ = true;
164             }
165             else if (vendor_ == \"AuthenticAMD\")
166             {
167                 isAMD_ = true;
168             }
169
170             // load bitset with flags for function 0x00000001
171             if (nIds_ >= 1)
172             {
173                 f_1_ECX_ = data_[1][2];
174                 f_1_EDX_ = data_[1][3];
175             }
176
177             // load bitset with flags for function 0x00000007
178             if (nIds_ >= 7)
179             {
180                 f_7_EBX_ = data_[7][1];
181                 f_7_ECX_ = data_[7][2];
182             }
183
184             // Calling __cpuid with 0x80000000 as the function_id argument
185             // gets the number of the highest valid extended ID.
186 #ifdef WIN32
187             __cpuid(cpui.data(), 0x80000000);
188 #else
189             __cpuid(0x80000000, cpui[0], cpui[1], cpui[2], cpui[3]);
190 #endif
191             nExIds_ = cpui[0];
192
193             char brand[0x40];
194             memset(brand, 0, sizeof(brand));
195
196             for (int i = 0x80000000; i <= nExIds_; ++i)
197             {
198 #ifdef WIN32
199                 __cpuidex(cpui.data(), i, 0);
200 #else
201                 __cpuid_count(i, 0, cpui[0], cpui[1], cpui[2], cpui[3]);
202 #endif
203                 extdata_.push_back(cpui);
204             }
205
206             // load bitset with flags for function 0x80000001
207             if (nExIds_ >= 0x80000001)
208             {
209                 f_81_ECX_ = extdata_[1][2];
210                 f_81_EDX_ = extdata_[1][3];
211             }
212
213             // Interpret CPU brand string if reported
214             if (nExIds_ >= 0x80000004)
215             {
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));
219                 brand_ = brand;
220             }
221         };
222
223         int nIds_;
224         int nExIds_;
225         std::string vendor_;
226         std::string brand_;
227         bool isIntel_;
228         bool isAMD_;
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_;
235 #ifdef WIN32
236         std::vector<std::array<int, 4>> data_;
237         std::vector<std::array<int, 4>> extdata_;
238 #else
239         std::vector<std::array<unsigned int, 4>> data_;
240         std::vector<std::array<unsigned int, 4>> extdata_;
241 #endif
242     };
243 };
244
245 // Initialize static member data
246 const InstructionSet::InstructionSet_Internal InstructionSet::CPU_Rep;
247
248 // Print out supported instruction set extensions
249 int main()
250 {
251     std::ofstream fo(\"cpuid.txt\");
252     auto& outstream = fo;//std::cout;
253
254     auto support_message = [&outstream](std::string isa_feature, bool is_supported) {
255         outstream << isa_feature << (is_supported ? \" supported\" : \" not supported\") << std::endl;
256     };
257
258     std::cout << InstructionSet::Vendor() << std::endl;
259     std::cout << InstructionSet::Brand() << std::endl;
260
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());
312     return 0;
313 }
314 "
315 HAVE_CPUID_INFO
316 )
317
318 if(HAVE_CPUID_INFO)
319     set(_CPUID_INFO "${CMAKE_BINARY_DIR}/cpuid.txt")
320     set(HAVE_AVX512F FALSE)
321     set(HAVE_AVX2    FALSE)
322     set(HAVE_SSE42   FALSE)
323
324     file(STRINGS ${_CPUID_INFO} _FEATURES)
325
326     message(STATUS "Host CPU features:")
327
328     foreach(FEATURE IN ITEMS ${_FEATURES})
329
330         message(STATUS "  ${FEATURE}")
331
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})
336             else()
337                 message(WARNING "Compiler doesn't support AVX512 instructuion set")
338             endif()
339         endif()
340         string(COMPARE EQUAL "${FEATURE}" "AVX2 supported" _FEATURE_FOUND)
341         if(${_FEATURE_FOUND})
342             set(HAVE_AVX2 ${_FEATURE_FOUND})
343         endif()
344         string(COMPARE EQUAL "${FEATURE}" "SSE4.2 supported" _FEATURE_FOUND)
345         if(${_FEATURE_FOUND})
346             set(HAVE_SSE42 ${_FEATURE_FOUND})
347         endif()
348     endforeach(FEATURE)
349
350     unset(_FEATURE_FOUND)
351     unset(_CPUID_INFO)
352     unset(_FEATURES)
353 endif()