proxsuite 0.6.7
The Advanced Proximal Optimization Toolbox
Loading...
Searching...
No Matches
instruction-set.hpp
Go to the documentation of this file.
1//
2// Copyright (c) 2022 INRIA
3//
8#ifndef PROXSUITE_HELPERS_INSTRUCTION_SET_HPP
9#define PROXSUITE_HELPERS_INSTRUCTION_SET_HPP
10
11#include <vector>
12#include <bitset>
13#include <array>
14
15#ifndef _WIN32
16#include <cpuid.h>
17#else
18#include <intrin.h>
19#endif
20
21namespace proxsuite {
22namespace helpers {
23
24namespace internal {
25inline void
26cpuid(std::array<int, 4>& cpui, int level)
27{
28#ifndef _WIN32
29 __cpuid(level, cpui[0], cpui[1], cpui[2], cpui[3]);
30#else
31 __cpuid(cpui.data(), level);
32#endif
33}
34
35inline void
36cpuidex(std::array<int, 4>& cpui, int level, int count)
37{
38#ifndef _WIN32
39 __cpuid_count(level, count, cpui[0], cpui[1], cpui[2], cpui[3]);
40#else
41 __cpuidex(cpui.data(), level, count);
42#endif
43}
44
45template<typename T = void>
46struct InstructionSetBase
47{
48protected:
49 struct Data
50 {
51 Data()
52 : nIds_{ 0 }
53 , nExIds_{ 0 }
54 , isIntel_{ false }
55 , isAMD_{ false }
56 , f_1_ECX_{ 0 }
57 , f_1_EDX_{ 0 }
58 , f_7_EBX_{ 0 }
59 , f_7_ECX_{ 0 }
60 , f_81_ECX_{ 0 }
61 , f_81_EDX_{ 0 }
62 , data_{}
63 , extdata_{}
64 {
65 std::array<int, 4> cpui;
66 typedef unsigned long long bistset_equivalent_type;
67
68 // Calling __cpuid with 0x0 as the function_id argument
69 // gets the number of the highest valid function ID.
70 internal::cpuid(cpui, 0);
71 nIds_ = cpui[0];
72
73 for (int i = 0; i <= nIds_; ++i) {
74 internal::cpuidex(cpui, i, 0);
75 data_.push_back(cpui);
76 }
77
78 // Capture vendor string
79 char vendor[0x20];
80 memset(vendor, 0, sizeof(vendor));
81 *reinterpret_cast<int*>(vendor) = data_[0][1];
82 *reinterpret_cast<int*>(vendor + 4) = data_[0][3];
83 *reinterpret_cast<int*>(vendor + 8) = data_[0][2];
84 vendor_ = vendor;
85 if (vendor_ == "GenuineIntel") {
86 isIntel_ = true;
87 } else if (vendor_ == "AuthenticAMD") {
88 isAMD_ = true;
89 }
90
91 // load bitset with flags for function 0x00000001
92 if (nIds_ >= 1) {
93 f_1_ECX_ = static_cast<bistset_equivalent_type>(data_[1][2]);
94 f_1_EDX_ = static_cast<bistset_equivalent_type>(data_[1][3]);
95 }
96
97 // load bitset with flags for function 0x00000007
98 if (nIds_ >= 7) {
99 f_7_EBX_ = static_cast<bistset_equivalent_type>(data_[7][1]);
100 f_7_ECX_ = static_cast<bistset_equivalent_type>(data_[7][2]);
101 }
102
103 // Calling __cpuid with 0x80000000 as the function_id argument
104 // gets the number of the highest valid extended ID.
105 internal::cpuid(cpui, static_cast<int>(0x80000000));
106 nExIds_ = cpui[0];
107
108 char brand[0x40];
109 memset(brand, 0, sizeof(brand));
110
111 for (int i = static_cast<int>(0x80000000); i <= nExIds_; ++i) {
112 internal::cpuidex(cpui, i, 0);
113 extdata_.push_back(cpui);
114 }
115
116 // load bitset with flags for function 0x80000001
117 if (nExIds_ >= static_cast<int>(0x80000001)) {
118 f_81_ECX_ = static_cast<bistset_equivalent_type>(extdata_[1][2]);
119 f_81_EDX_ = static_cast<bistset_equivalent_type>(extdata_[1][3]);
120 }
121
122 // Interpret CPU brand string if reported
123 if (nExIds_ >= static_cast<int>(0x80000004)) {
124 memcpy(brand, extdata_[2].data(), sizeof(cpui));
125 memcpy(brand + 16, extdata_[3].data(), sizeof(cpui));
126 memcpy(brand + 32, extdata_[4].data(), sizeof(cpui));
127 brand_ = brand;
128 }
129 };
130
131 int nIds_;
132 int nExIds_;
133 std::string vendor_;
134 std::string brand_;
135 bool isIntel_;
136 bool isAMD_;
137 std::bitset<32> f_1_ECX_;
138 std::bitset<32> f_1_EDX_;
139 std::bitset<32> f_7_EBX_;
140 std::bitset<32> f_7_ECX_;
141 std::bitset<32> f_81_ECX_;
142 std::bitset<32> f_81_EDX_;
143 std::vector<std::array<int, 4>> data_;
144 std::vector<std::array<int, 4>> extdata_;
145 };
146
147 static const Data data;
148};
149
150template<>
151const typename InstructionSetBase<>::Data InstructionSetBase<>::data =
152 typename InstructionSetBase<>::Data();
153} // namespace internal
154
155// Adapted from
156// https://docs.microsoft.com/fr-fr/cpp/intrinsics/cpuid-cpuidex?view=msvc-170
157struct InstructionSet : public internal::InstructionSetBase<>
158{
159 typedef internal::InstructionSetBase<> Base;
160
161 static std::string vendor(void) { return Base::data.vendor_; }
162 static std::string brand(void) { return Base::data.brand_; }
163
164 static bool has_SSE3(void) { return Base::data.f_1_ECX_[0]; }
165 static bool has_PCLMULQDQ(void) { return Base::data.f_1_ECX_[1]; }
166 static bool has_MONITOR(void) { return Base::data.f_1_ECX_[3]; }
167 static bool has_SSSE3(void) { return Base::data.f_1_ECX_[9]; }
168 static bool has_FMA(void) { return Base::data.f_1_ECX_[12]; }
169 static bool has_CMPXCHG16B(void) { return Base::data.f_1_ECX_[13]; }
170 static bool has_SSE41(void) { return Base::data.f_1_ECX_[19]; }
171 static bool has_SSE42(void) { return Base::data.f_1_ECX_[20]; }
172 static bool has_MOVBE(void) { return Base::data.f_1_ECX_[22]; }
173 static bool has_POPCNT(void) { return Base::data.f_1_ECX_[23]; }
174 static bool has_AES(void) { return Base::data.f_1_ECX_[25]; }
175 static bool has_XSAVE(void) { return Base::data.f_1_ECX_[26]; }
176 static bool has_OSXSAVE(void) { return Base::data.f_1_ECX_[27]; }
177 static bool has_AVX(void) { return Base::data.f_1_ECX_[28]; }
178 static bool has_F16C(void) { return Base::data.f_1_ECX_[29]; }
179 static bool has_RDRAND(void) { return Base::data.f_1_ECX_[30]; }
180
181 static bool has_MSR(void) { return Base::data.f_1_EDX_[5]; }
182 static bool has_CX8(void) { return Base::data.f_1_EDX_[8]; }
183 static bool has_SEP(void) { return Base::data.f_1_EDX_[11]; }
184 static bool has_CMOV(void) { return Base::data.f_1_EDX_[15]; }
185 static bool has_CLFSH(void) { return Base::data.f_1_EDX_[19]; }
186 static bool has_MMX(void) { return Base::data.f_1_EDX_[23]; }
187 static bool has_FXSR(void) { return Base::data.f_1_EDX_[24]; }
188 static bool has_SSE(void) { return Base::data.f_1_EDX_[25]; }
189 static bool has_SSE2(void) { return Base::data.f_1_EDX_[26]; }
190
191 static bool has_FSGSBASE(void) { return Base::data.f_7_EBX_[0]; }
192 static bool has_AVX512VBMI(void) { return Base::data.f_7_EBX_[1]; }
193 static bool has_BMI1(void) { return Base::data.f_7_EBX_[3]; }
194 static bool has_HLE(void)
195 {
196 return Base::data.isIntel_ && Base::data.f_7_EBX_[4];
197 }
198 static bool has_AVX2(void) { return Base::data.f_7_EBX_[5]; }
199 static bool has_BMI2(void) { return Base::data.f_7_EBX_[8]; }
200 static bool has_ERMS(void) { return Base::data.f_7_EBX_[9]; }
201 static bool has_INVPCID(void) { return Base::data.f_7_EBX_[10]; }
202 static bool has_RTM(void)
203 {
204 return Base::data.isIntel_ && Base::data.f_7_EBX_[11];
205 }
206 static bool has_AVX512F(void) { return Base::data.f_7_EBX_[16]; }
207 static bool has_AVX512DQ(void) { return Base::data.f_7_EBX_[17]; }
208 static bool has_RDSEED(void) { return Base::data.f_7_EBX_[18]; }
209 static bool has_ADX(void) { return Base::data.f_7_EBX_[19]; }
210 static bool has_AVX512IFMA(void) { return Base::data.f_7_EBX_[21]; }
211 static bool has_AVX512PF(void) { return Base::data.f_7_EBX_[26]; }
212 static bool has_AVX512ER(void) { return Base::data.f_7_EBX_[27]; }
213 static bool has_AVX512CD(void) { return Base::data.f_7_EBX_[28]; }
214 static bool has_SHA(void) { return Base::data.f_7_EBX_[29]; }
215 static bool has_AVX512BW(void) { return Base::data.f_7_EBX_[30]; }
216 static bool has_AVX512VL(void) { return Base::data.f_7_EBX_[31]; }
217
218 static bool has_PREFETCHWT1(void) { return Base::data.f_7_ECX_[0]; }
219
220 static bool has_LAHF(void) { return Base::data.f_81_ECX_[0]; }
221 static bool has_LZCNT(void)
222 {
223 return Base::data.isIntel_ && Base::data.f_81_ECX_[5];
224 }
225 static bool has_ABM(void)
226 {
227 return Base::data.isAMD_ && Base::data.f_81_ECX_[5];
228 }
229 static bool has_SSE4a(void)
230 {
231 return Base::data.isAMD_ && Base::data.f_81_ECX_[6];
232 }
233 static bool has_XOP(void)
234 {
235 return Base::data.isAMD_ && Base::data.f_81_ECX_[11];
236 }
237 static bool has_FMA4(void)
238 {
239 return Base::data.isAMD_ && Base::data.f_81_ECX_[16];
240 }
241 static bool has_TBM(void)
242 {
243 return Base::data.isAMD_ && Base::data.f_81_ECX_[21];
244 }
245
246 static bool has_SYSCALL(void)
247 {
248 return Base::data.isIntel_ && Base::data.f_81_EDX_[11];
249 }
250 static bool has_MMXEXT(void)
251 {
252 return Base::data.isAMD_ && Base::data.f_81_EDX_[22];
253 }
254 static bool has_RDTSCP(void)
255 {
256 return Base::data.isIntel_ && Base::data.f_81_EDX_[27];
257 }
258 static bool has_x64(void)
259 {
260 return Base::data.isIntel_ && Base::data.f_81_EDX_[29];
261 }
262 static bool has_3DNOWEXT(void)
263 {
264 return Base::data.isAMD_ && Base::data.f_81_EDX_[30];
265 }
266 static bool has_3DNOW(void)
267 {
268 return Base::data.isAMD_ && Base::data.f_81_EDX_[31];
269 }
270};
271
272} // helpers
273} // proxsuite
274
275#endif // ifndef PROXSUITE_HELPERS_INSTRUCTION_SET_HPP
internal::InstructionSetBase Base