Line data Source code
1 : #ifdef __PLUMED_HAS_ASMJIT
2 : // This file is part of AsmJit project <https://asmjit.com>
3 : //
4 : // See asmjit.h or LICENSE.md for license and copyright information
5 : // SPDX-License-Identifier: Zlib
6 :
7 : #include "api-build_p.h"
8 : #include "cpuinfo.h"
9 : #include "support.h"
10 :
11 : #if !defined(_WIN32)
12 : #include <errno.h>
13 : #include <sys/utsname.h>
14 : #include <unistd.h>
15 : #endif
16 :
17 : // Required by `getauxval()` on Linux.
18 : #if defined(__linux__)
19 : #include <sys/auxv.h>
20 : #endif
21 :
22 : //! Required to detect CPU and features on Apple platforms.
23 : #if defined(__APPLE__)
24 : #include <mach/machine.h>
25 : #include <sys/types.h>
26 : #include <sys/sysctl.h>
27 : #endif
28 :
29 : // Required by `__cpuidex()` and `_xgetbv()`.
30 : #if defined(_MSC_VER)
31 : #include <intrin.h>
32 : #endif
33 :
34 : ASMJIT_BEGIN_NAMESPACE
35 :
36 : // CpuInfo - Detect - HW-Thread Count
37 : // ==================================
38 :
39 : #if defined(_WIN32)
40 : static inline uint32_t detectHWThreadCount() noexcept {
41 : SYSTEM_INFO info;
42 : ::GetSystemInfo(&info);
43 : return info.dwNumberOfProcessors;
44 : }
45 : #elif defined(_SC_NPROCESSORS_ONLN)
46 : static inline uint32_t detectHWThreadCount() noexcept {
47 355 : long res = ::sysconf(_SC_NPROCESSORS_ONLN);
48 355 : return res <= 0 ? uint32_t(1) : uint32_t(res);
49 : }
50 : #else
51 : static inline uint32_t detectHWThreadCount() noexcept {
52 : return 1;
53 : }
54 : #endif
55 :
56 : // CpuInfo - Detect - X86
57 : // ======================
58 :
59 : #if ASMJIT_ARCH_X86
60 :
61 : struct cpuid_t { uint32_t eax, ebx, ecx, edx; };
62 : struct xgetbv_t { uint32_t eax, edx; };
63 :
64 : // Executes `cpuid` instruction.
65 : static inline void cpuidQuery(cpuid_t* out, uint32_t inEax, uint32_t inEcx = 0) noexcept {
66 : #if defined(_MSC_VER)
67 : __cpuidex(reinterpret_cast<int*>(out), inEax, inEcx);
68 : #elif defined(__GNUC__) && ASMJIT_ARCH_X86 == 32
69 : __asm__ __volatile__(
70 : "mov %%ebx, %%edi\n"
71 : "cpuid\n"
72 : "xchg %%edi, %%ebx\n" : "=a"(out->eax), "=D"(out->ebx), "=c"(out->ecx), "=d"(out->edx) : "a"(inEax), "c"(inEcx));
73 : #elif defined(__GNUC__) && ASMJIT_ARCH_X86 == 64
74 4970 : __asm__ __volatile__(
75 : "mov %%rbx, %%rdi\n"
76 : "cpuid\n"
77 : "xchg %%rdi, %%rbx\n" : "=a"(out->eax), "=D"(out->ebx), "=c"(out->ecx), "=d"(out->edx) : "a"(inEax), "c"(inEcx));
78 : #else
79 : #error "[asmjit] x86::cpuidQuery() - Unsupported compiler."
80 : #endif
81 : }
82 :
83 : // Executes 'xgetbv' instruction.
84 : static inline void xgetbvQuery(xgetbv_t* out, uint32_t inEcx) noexcept {
85 : #if defined(_MSC_VER)
86 : uint64_t value = _xgetbv(inEcx);
87 : out->eax = uint32_t(value & 0xFFFFFFFFu);
88 : out->edx = uint32_t(value >> 32);
89 : #elif defined(__GNUC__)
90 : uint32_t outEax;
91 : uint32_t outEdx;
92 :
93 : // Replaced, because the world is not perfect:
94 : // __asm__ __volatile__("xgetbv" : "=a"(outEax), "=d"(outEdx) : "c"(inEcx));
95 355 : __asm__ __volatile__(".byte 0x0F, 0x01, 0xD0" : "=a"(outEax), "=d"(outEdx) : "c"(inEcx));
96 :
97 : out->eax = outEax;
98 : out->edx = outEdx;
99 : #else
100 : out->eax = 0;
101 : out->edx = 0;
102 : #endif
103 355 : }
104 :
105 : // Map a 12-byte vendor string returned by `cpuid` into a `CpuInfo::Vendor` ID.
106 355 : static inline void simplifyCpuVendor(CpuInfo& cpu, uint32_t d0, uint32_t d1, uint32_t d2) noexcept {
107 : struct Vendor {
108 : char normalized[8];
109 : union { char text[12]; uint32_t d[3]; };
110 : };
111 :
112 : static const Vendor table[] = {
113 : { { 'A', 'M', 'D' }, {{ 'A', 'u', 't', 'h', 'e', 'n', 't', 'i', 'c', 'A', 'M', 'D' }} },
114 : { { 'I', 'N', 'T', 'E', 'L' }, {{ 'G', 'e', 'n', 'u', 'i', 'n', 'e', 'I', 'n', 't', 'e', 'l' }} },
115 : { { 'V', 'I', 'A' }, {{ 'C', 'e', 'n', 't', 'a', 'u', 'r', 'H', 'a', 'u', 'l', 's' }} },
116 : { { 'V', 'I', 'A' }, {{ 'V', 'I', 'A', 0 , 'V', 'I', 'A', 0 , 'V', 'I', 'A', 0 }} },
117 : { { 'U', 'N', 'K', 'N', 'O', 'W', 'N' }, {{ 0 }} }
118 : };
119 :
120 : uint32_t i;
121 355 : for (i = 0; i < ASMJIT_ARRAY_SIZE(table) - 1; i++)
122 355 : if (table[i].d[0] == d0 && table[i].d[1] == d1 && table[i].d[2] == d2)
123 : break;
124 355 : memcpy(cpu._vendor.str, table[i].normalized, 8);
125 355 : }
126 :
127 355 : static ASMJIT_FAVOR_SIZE void simplifyCpuBrand(char* s) noexcept {
128 : char* d = s;
129 :
130 355 : char c = s[0];
131 : char prev = 0;
132 :
133 : // Used to always clear the current character to ensure that the result
134 : // doesn't contain garbage after a new null terminator is placed at the end.
135 355 : s[0] = '\0';
136 :
137 : for (;;) {
138 17040 : if (!c)
139 : break;
140 :
141 16685 : if (!(c == ' ' && (prev == '@' || s[1] == ' ' || s[1] == '@'))) {
142 11360 : *d++ = c;
143 : prev = c;
144 : }
145 :
146 16685 : c = *++s;
147 16685 : s[0] = '\0';
148 : }
149 :
150 355 : d[0] = '\0';
151 355 : }
152 :
153 355 : static ASMJIT_FAVOR_SIZE void detectX86Cpu(CpuInfo& cpu) noexcept {
154 : using Support::bitTest;
155 :
156 : cpuid_t regs;
157 : xgetbv_t xcr0 { 0, 0 };
158 : CpuFeatures::X86& features = cpu.features().x86();
159 :
160 355 : cpu._wasDetected = true;
161 355 : cpu._maxLogicalProcessors = 1;
162 :
163 : // We are gonna execute CPUID, which was introduced by I486, so it's the requirement.
164 : features.add(CpuFeatures::X86::kI486);
165 :
166 : // CPUID EAX=0
167 : // -----------
168 :
169 : // Get vendor string/id.
170 : cpuidQuery(®s, 0x0);
171 :
172 : uint32_t maxId = regs.eax;
173 : uint32_t maxSubLeafId_0x7 = 0;
174 :
175 355 : simplifyCpuVendor(cpu, regs.ebx, regs.edx, regs.ecx);
176 :
177 : // CPUID EAX=1
178 : // -----------
179 :
180 355 : if (maxId >= 0x1) {
181 : // Get feature flags in ECX/EDX and family/model in EAX.
182 : cpuidQuery(®s, 0x1);
183 :
184 : // Fill family and model fields.
185 355 : uint32_t modelId = (regs.eax >> 4) & 0x0F;
186 355 : uint32_t familyId = (regs.eax >> 8) & 0x0F;
187 :
188 : // Use extended family and model fields.
189 355 : if (familyId == 0x06u || familyId == 0x0Fu)
190 355 : modelId += (((regs.eax >> 16) & 0x0Fu) << 4);
191 :
192 355 : if (familyId == 0x0Fu)
193 355 : familyId += ((regs.eax >> 20) & 0xFFu);
194 :
195 355 : cpu._modelId = modelId;
196 355 : cpu._familyId = familyId;
197 355 : cpu._brandId = ((regs.ebx ) & 0xFF);
198 355 : cpu._processorType = ((regs.eax >> 12) & 0x03);
199 355 : cpu._maxLogicalProcessors = ((regs.ebx >> 16) & 0xFF);
200 355 : cpu._stepping = ((regs.eax ) & 0x0F);
201 710 : cpu._cacheLineSize = ((regs.ebx >> 8) & 0xFF) * 8;
202 :
203 : features.addIf(bitTest(regs.ecx, 0), CpuFeatures::X86::kSSE3);
204 : features.addIf(bitTest(regs.ecx, 1), CpuFeatures::X86::kPCLMULQDQ);
205 : features.addIf(bitTest(regs.ecx, 3), CpuFeatures::X86::kMONITOR);
206 : features.addIf(bitTest(regs.ecx, 5), CpuFeatures::X86::kVMX);
207 : features.addIf(bitTest(regs.ecx, 6), CpuFeatures::X86::kSMX);
208 : features.addIf(bitTest(regs.ecx, 9), CpuFeatures::X86::kSSSE3);
209 : features.addIf(bitTest(regs.ecx, 13), CpuFeatures::X86::kCMPXCHG16B);
210 : features.addIf(bitTest(regs.ecx, 19), CpuFeatures::X86::kSSE4_1);
211 : features.addIf(bitTest(regs.ecx, 20), CpuFeatures::X86::kSSE4_2);
212 : features.addIf(bitTest(regs.ecx, 22), CpuFeatures::X86::kMOVBE);
213 : features.addIf(bitTest(regs.ecx, 23), CpuFeatures::X86::kPOPCNT);
214 : features.addIf(bitTest(regs.ecx, 25), CpuFeatures::X86::kAESNI);
215 : features.addIf(bitTest(regs.ecx, 26), CpuFeatures::X86::kXSAVE);
216 : features.addIf(bitTest(regs.ecx, 27), CpuFeatures::X86::kOSXSAVE);
217 : features.addIf(bitTest(regs.ecx, 30), CpuFeatures::X86::kRDRAND);
218 : features.addIf(bitTest(regs.edx, 0), CpuFeatures::X86::kFPU);
219 : features.addIf(bitTest(regs.edx, 4), CpuFeatures::X86::kRDTSC);
220 : features.addIf(bitTest(regs.edx, 5), CpuFeatures::X86::kMSR);
221 : features.addIf(bitTest(regs.edx, 8), CpuFeatures::X86::kCMPXCHG8B);
222 : features.addIf(bitTest(regs.edx, 15), CpuFeatures::X86::kCMOV);
223 : features.addIf(bitTest(regs.edx, 19), CpuFeatures::X86::kCLFLUSH);
224 : features.addIf(bitTest(regs.edx, 23), CpuFeatures::X86::kMMX);
225 : features.addIf(bitTest(regs.edx, 24), CpuFeatures::X86::kFXSR);
226 : features.addIf(bitTest(regs.edx, 25), CpuFeatures::X86::kSSE);
227 : features.addIf(bitTest(regs.edx, 25), CpuFeatures::X86::kSSE, CpuFeatures::X86::kSSE2);
228 : features.addIf(bitTest(regs.edx, 28), CpuFeatures::X86::kMT);
229 :
230 : // Get the content of XCR0 if supported by the CPU and enabled by the OS.
231 355 : if (features.hasXSAVE() && features.hasOSXSAVE()) {
232 : xgetbvQuery(&xcr0, 0);
233 : }
234 :
235 : // Detect AVX+.
236 355 : if (bitTest(regs.ecx, 28)) {
237 : // - XCR0[2:1] == 11b
238 : // XMM & YMM states need to be enabled by OS.
239 355 : if ((xcr0.eax & 0x00000006u) == 0x00000006u) {
240 : features.add(CpuFeatures::X86::kAVX);
241 : features.addIf(bitTest(regs.ecx, 12), CpuFeatures::X86::kFMA);
242 : features.addIf(bitTest(regs.ecx, 29), CpuFeatures::X86::kF16C);
243 : }
244 : }
245 : }
246 :
247 : constexpr uint32_t kXCR0_AMX_Bits = 0x3u << 17;
248 355 : bool amxEnabledByOS = (xcr0.eax & kXCR0_AMX_Bits) == kXCR0_AMX_Bits;
249 :
250 : #if defined(__APPLE__)
251 : // Apple platform provides on-demand AVX512 support. When an AVX512 instruction is used the first time it results
252 : // in #UD, which would cause the thread being promoted to use AVX512 support by the OS in addition to enabling the
253 : // necessary bits in XCR0 register.
254 : bool avx512EnabledByOS = true;
255 : #else
256 : // - XCR0[2:1] == 11b - XMM/YMM states need to be enabled by OS.
257 : // - XCR0[7:5] == 111b - Upper 256-bit of ZMM0-XMM15 and ZMM16-ZMM31 need to be enabled by OS.
258 : constexpr uint32_t kXCR0_AVX512_Bits = (0x3u << 1) | (0x7u << 5);
259 355 : bool avx512EnabledByOS = (xcr0.eax & kXCR0_AVX512_Bits) == kXCR0_AVX512_Bits;
260 : #endif
261 :
262 : // CPUID EAX=7 ECX=0
263 : // -----------------
264 :
265 : // Detect new features if the processor supports CPUID-07.
266 : bool maybeMPX = false;
267 :
268 355 : if (maxId >= 0x7) {
269 : cpuidQuery(®s, 0x7);
270 :
271 : maybeMPX = bitTest(regs.ebx, 14);
272 : maxSubLeafId_0x7 = regs.eax;
273 :
274 : features.addIf(bitTest(regs.ebx, 0), CpuFeatures::X86::kFSGSBASE);
275 : features.addIf(bitTest(regs.ebx, 3), CpuFeatures::X86::kBMI);
276 : features.addIf(bitTest(regs.ebx, 4), CpuFeatures::X86::kHLE);
277 : features.addIf(bitTest(regs.ebx, 7), CpuFeatures::X86::kSMEP);
278 : features.addIf(bitTest(regs.ebx, 8), CpuFeatures::X86::kBMI2);
279 : features.addIf(bitTest(regs.ebx, 9), CpuFeatures::X86::kERMS);
280 : features.addIf(bitTest(regs.ebx, 11), CpuFeatures::X86::kRTM);
281 : features.addIf(bitTest(regs.ebx, 18), CpuFeatures::X86::kRDSEED);
282 : features.addIf(bitTest(regs.ebx, 19), CpuFeatures::X86::kADX);
283 : features.addIf(bitTest(regs.ebx, 20), CpuFeatures::X86::kSMAP);
284 : features.addIf(bitTest(regs.ebx, 23), CpuFeatures::X86::kCLFLUSHOPT);
285 : features.addIf(bitTest(regs.ebx, 24), CpuFeatures::X86::kCLWB);
286 : features.addIf(bitTest(regs.ebx, 29), CpuFeatures::X86::kSHA);
287 : features.addIf(bitTest(regs.ecx, 0), CpuFeatures::X86::kPREFETCHWT1);
288 : features.addIf(bitTest(regs.ecx, 4), CpuFeatures::X86::kOSPKE);
289 : features.addIf(bitTest(regs.ecx, 5), CpuFeatures::X86::kWAITPKG);
290 : features.addIf(bitTest(regs.ecx, 7), CpuFeatures::X86::kCET_SS);
291 : features.addIf(bitTest(regs.ecx, 8), CpuFeatures::X86::kGFNI);
292 : features.addIf(bitTest(regs.ecx, 9), CpuFeatures::X86::kVAES);
293 : features.addIf(bitTest(regs.ecx, 10), CpuFeatures::X86::kVPCLMULQDQ);
294 : features.addIf(bitTest(regs.ecx, 22), CpuFeatures::X86::kRDPID);
295 : features.addIf(bitTest(regs.ecx, 25), CpuFeatures::X86::kCLDEMOTE);
296 : features.addIf(bitTest(regs.ecx, 27), CpuFeatures::X86::kMOVDIRI);
297 : features.addIf(bitTest(regs.ecx, 28), CpuFeatures::X86::kMOVDIR64B);
298 : features.addIf(bitTest(regs.ecx, 29), CpuFeatures::X86::kENQCMD);
299 : features.addIf(bitTest(regs.edx, 5), CpuFeatures::X86::kUINTR);
300 : features.addIf(bitTest(regs.edx, 14), CpuFeatures::X86::kSERIALIZE);
301 : features.addIf(bitTest(regs.edx, 16), CpuFeatures::X86::kTSXLDTRK);
302 : features.addIf(bitTest(regs.edx, 18), CpuFeatures::X86::kPCONFIG);
303 : features.addIf(bitTest(regs.edx, 20), CpuFeatures::X86::kCET_IBT);
304 :
305 : // Detect 'TSX' - Requires at least one of `HLE` and `RTM` features.
306 355 : if (features.hasHLE() || features.hasRTM())
307 : features.add(CpuFeatures::X86::kTSX);
308 :
309 : // Detect 'AVX2' - Requires AVX as well.
310 355 : if (bitTest(regs.ebx, 5) && features.hasAVX())
311 : features.add(CpuFeatures::X86::kAVX2);
312 :
313 : // Detect 'AVX512'.
314 355 : if (avx512EnabledByOS && bitTest(regs.ebx, 16)) {
315 : features.add(CpuFeatures::X86::kAVX512_F);
316 :
317 : features.addIf(bitTest(regs.ebx, 17), CpuFeatures::X86::kAVX512_DQ);
318 : features.addIf(bitTest(regs.ebx, 21), CpuFeatures::X86::kAVX512_IFMA);
319 : features.addIf(bitTest(regs.ebx, 26), CpuFeatures::X86::kAVX512_PFI);
320 : features.addIf(bitTest(regs.ebx, 27), CpuFeatures::X86::kAVX512_ERI);
321 : features.addIf(bitTest(regs.ebx, 28), CpuFeatures::X86::kAVX512_CDI);
322 : features.addIf(bitTest(regs.ebx, 30), CpuFeatures::X86::kAVX512_BW);
323 : features.addIf(bitTest(regs.ebx, 31), CpuFeatures::X86::kAVX512_VL);
324 : features.addIf(bitTest(regs.ecx, 1), CpuFeatures::X86::kAVX512_VBMI);
325 : features.addIf(bitTest(regs.ecx, 6), CpuFeatures::X86::kAVX512_VBMI2);
326 : features.addIf(bitTest(regs.ecx, 11), CpuFeatures::X86::kAVX512_VNNI);
327 : features.addIf(bitTest(regs.ecx, 12), CpuFeatures::X86::kAVX512_BITALG);
328 : features.addIf(bitTest(regs.ecx, 14), CpuFeatures::X86::kAVX512_VPOPCNTDQ);
329 : features.addIf(bitTest(regs.edx, 2), CpuFeatures::X86::kAVX512_4VNNIW);
330 : features.addIf(bitTest(regs.edx, 3), CpuFeatures::X86::kAVX512_4FMAPS);
331 : features.addIf(bitTest(regs.edx, 8), CpuFeatures::X86::kAVX512_VP2INTERSECT);
332 : features.addIf(bitTest(regs.edx, 23), CpuFeatures::X86::kAVX512_FP16);
333 : }
334 :
335 : // Detect 'AMX'.
336 355 : if (amxEnabledByOS) {
337 : features.addIf(bitTest(regs.edx, 22), CpuFeatures::X86::kAMX_BF16);
338 : features.addIf(bitTest(regs.edx, 24), CpuFeatures::X86::kAMX_TILE);
339 : features.addIf(bitTest(regs.edx, 25), CpuFeatures::X86::kAMX_INT8);
340 : }
341 : }
342 :
343 : // CPUID EAX=7 ECX=1
344 : // -----------------
345 :
346 355 : if (features.hasAVX512_F() && maxSubLeafId_0x7 >= 1) {
347 : cpuidQuery(®s, 0x7, 1);
348 :
349 : features.addIf(bitTest(regs.eax, 3), CpuFeatures::X86::kAVX_VNNI);
350 : features.addIf(bitTest(regs.eax, 5), CpuFeatures::X86::kAVX512_BF16);
351 : features.addIf(bitTest(regs.eax, 22), CpuFeatures::X86::kHRESET);
352 : }
353 :
354 : // CPUID EAX=13 ECX=0
355 : // ------------------
356 :
357 355 : if (maxId >= 0xD) {
358 : cpuidQuery(®s, 0xD, 0);
359 :
360 : // Both CPUID result and XCR0 has to be enabled to have support for MPX.
361 355 : if (((regs.eax & xcr0.eax) & 0x00000018u) == 0x00000018u && maybeMPX)
362 : features.add(CpuFeatures::X86::kMPX);
363 :
364 : cpuidQuery(®s, 0xD, 1);
365 :
366 : features.addIf(bitTest(regs.eax, 0), CpuFeatures::X86::kXSAVEOPT);
367 : features.addIf(bitTest(regs.eax, 1), CpuFeatures::X86::kXSAVEC);
368 : features.addIf(bitTest(regs.eax, 3), CpuFeatures::X86::kXSAVES);
369 : }
370 :
371 : // CPUID EAX=14 ECX=0
372 : // ------------------
373 :
374 355 : if (maxId >= 0xE) {
375 : cpuidQuery(®s, 0xE, 0);
376 :
377 : features.addIf(bitTest(regs.ebx, 4), CpuFeatures::X86::kPTWRITE);
378 : }
379 :
380 : // CPUID EAX=0x80000000...maxId
381 : // ----------------------------
382 :
383 : maxId = 0x80000000u;
384 : uint32_t i = maxId;
385 :
386 : // The highest EAX that we understand.
387 : constexpr uint32_t kHighestProcessedEAX = 0x8000001Fu;
388 :
389 : // Several CPUID calls are required to get the whole branc string. It's easier
390 : // to copy one DWORD at a time instead of copying the string a byte by byte.
391 355 : uint32_t* brand = cpu._brand.u32;
392 : do {
393 : cpuidQuery(®s, i);
394 2485 : switch (i) {
395 : case 0x80000000u:
396 : maxId = Support::min<uint32_t>(regs.eax, kHighestProcessedEAX);
397 355 : break;
398 :
399 355 : case 0x80000001u:
400 : features.addIf(bitTest(regs.ecx, 0), CpuFeatures::X86::kLAHFSAHF);
401 : features.addIf(bitTest(regs.ecx, 2), CpuFeatures::X86::kSVM);
402 : features.addIf(bitTest(regs.ecx, 5), CpuFeatures::X86::kLZCNT);
403 : features.addIf(bitTest(regs.ecx, 6), CpuFeatures::X86::kSSE4A);
404 : features.addIf(bitTest(regs.ecx, 7), CpuFeatures::X86::kMSSE);
405 : features.addIf(bitTest(regs.ecx, 8), CpuFeatures::X86::kPREFETCHW);
406 : features.addIf(bitTest(regs.ecx, 12), CpuFeatures::X86::kSKINIT);
407 : features.addIf(bitTest(regs.ecx, 15), CpuFeatures::X86::kLWP);
408 : features.addIf(bitTest(regs.ecx, 21), CpuFeatures::X86::kTBM);
409 : features.addIf(bitTest(regs.ecx, 29), CpuFeatures::X86::kMONITORX);
410 : features.addIf(bitTest(regs.edx, 20), CpuFeatures::X86::kNX);
411 : features.addIf(bitTest(regs.edx, 21), CpuFeatures::X86::kFXSROPT);
412 : features.addIf(bitTest(regs.edx, 22), CpuFeatures::X86::kMMX2);
413 : features.addIf(bitTest(regs.edx, 27), CpuFeatures::X86::kRDTSCP);
414 : features.addIf(bitTest(regs.edx, 29), CpuFeatures::X86::kPREFETCHW);
415 : features.addIf(bitTest(regs.edx, 30), CpuFeatures::X86::k3DNOW2, CpuFeatures::X86::kMMX2);
416 : features.addIf(bitTest(regs.edx, 31), CpuFeatures::X86::kPREFETCHW);
417 :
418 355 : if (features.hasAVX()) {
419 : features.addIf(bitTest(regs.ecx, 11), CpuFeatures::X86::kXOP);
420 : features.addIf(bitTest(regs.ecx, 16), CpuFeatures::X86::kFMA4);
421 : }
422 :
423 : // This feature seems to be only supported by AMD.
424 355 : if (cpu.isVendor("AMD")) {
425 : features.addIf(bitTest(regs.ecx, 4), CpuFeatures::X86::kALTMOVCR8);
426 : }
427 : break;
428 :
429 1065 : case 0x80000002u:
430 : case 0x80000003u:
431 : case 0x80000004u:
432 1065 : *brand++ = regs.eax;
433 1065 : *brand++ = regs.ebx;
434 1065 : *brand++ = regs.ecx;
435 1065 : *brand++ = regs.edx;
436 :
437 : // Go directly to the next one we are interested in.
438 1065 : if (i == 0x80000004u)
439 : i = 0x80000008u - 1;
440 : break;
441 :
442 355 : case 0x80000008u:
443 : features.addIf(bitTest(regs.ebx, 0), CpuFeatures::X86::kCLZERO);
444 : features.addIf(bitTest(regs.ebx, 0), CpuFeatures::X86::kRDPRU);
445 : features.addIf(bitTest(regs.ebx, 8), CpuFeatures::X86::kMCOMMIT);
446 : features.addIf(bitTest(regs.ebx, 9), CpuFeatures::X86::kWBNOINVD);
447 :
448 : // Go directly to the next one we are interested in.
449 : i = 0x8000001Fu - 1;
450 355 : break;
451 :
452 355 : case 0x8000001Fu:
453 : features.addIf(bitTest(regs.eax, 4), CpuFeatures::X86::kSNP);
454 355 : break;
455 : }
456 2485 : } while (++i <= maxId);
457 :
458 : // Simplify CPU brand string a bit by removing some unnecessary spaces.
459 355 : simplifyCpuBrand(cpu._brand.str);
460 355 : }
461 :
462 : #endif // ASMJIT_ARCH_X86
463 :
464 : // CpuInfo - Detect - ARM
465 : // ======================
466 :
467 : // The most relevant and accurate information can be found here:
468 : // https://github.com/llvm-project/llvm/blob/master/lib/Target/AArch64/AArch64.td
469 : // https://github.com/apple/llvm-project/blob/apple/main/llvm/lib/Target/AArch64/AArch64.td (Apple fork)
470 : //
471 : // Other resources:
472 : // https://en.wikipedia.org/wiki/AArch64
473 : // https://en.wikipedia.org/wiki/Apple_silicon#List_of_Apple_processors
474 : // https://developer.arm.com/architectures/learn-the-architecture/understanding-the-armv8-x-extensions/single-page
475 :
476 : #if ASMJIT_ARCH_ARM
477 :
478 : static inline void populateBaseARMFeatures(CpuInfo& cpu) noexcept {
479 : #if ASMJIT_ARCH_ARM == 32
480 : // No baseline flags at the moment.
481 : DebugUtils::unused(cpu);
482 : #else
483 : // AArch64 is based on ARMv8-A and later.
484 : cpu.addFeature(CpuFeatures::ARM::kARMv6);
485 : cpu.addFeature(CpuFeatures::ARM::kARMv7);
486 : cpu.addFeature(CpuFeatures::ARM::kARMv8a);
487 :
488 : // AArch64 comes with these features by default.
489 : cpu.addFeature(CpuFeatures::ARM::kVFPv2);
490 : cpu.addFeature(CpuFeatures::ARM::kVFPv3);
491 : cpu.addFeature(CpuFeatures::ARM::kVFPv4);
492 : cpu.addFeature(CpuFeatures::ARM::kASIMD);
493 : cpu.addFeature(CpuFeatures::ARM::kIDIVA);
494 : #endif
495 : }
496 :
497 : // Detects ARM version by macros defined at compile time. This means that AsmJit will report features forced at
498 : // compile time that should always be provided by the target CPU. This also means that if we don't provide any
499 : // means to detect CPU features the features reported by AsmJit will at least not report less features than the
500 : // target it was compiled to.
501 : ASMJIT_MAYBE_UNUSED
502 : static ASMJIT_FAVOR_SIZE void detectARMFeaturesViaCompilerFlags(CpuInfo& cpu) noexcept {
503 : DebugUtils::unused(cpu);
504 :
505 : #if ASMJIT_ARCH_ARM == 32
506 :
507 : // ARM targets have no baseline at the moment.
508 : # if defined(__ARM_ARCH_7A__)
509 : cpu.addFeature(CpuFeatures::ARM::kARMv7);
510 : # endif
511 : # if defined(__ARM_ARCH_8A__)
512 : cpu.addFeature(CpuFeatures::ARM::kARMv8a);
513 : # endif
514 :
515 : # if defined(__TARGET_ARCH_THUMB)
516 : cpu.addFeature(CpuFeatures::ARM::kTHUMB);
517 : # if __TARGET_ARCH_THUMB >= 4
518 : cpu.addFeature(CpuFeatures::ARM::kTHUMBv2);
519 : # endif
520 : # endif
521 :
522 : # if defined(__ARM_FEATURE_FMA)
523 : cpu.addFeature(CpuFeatures::ARM::kVFPv3);
524 : cpu.addFeature(CpuFeatures::ARM::kVFPv4);
525 : # endif
526 :
527 : # if defined(__ARM_NEON)
528 : cpu.addFeature(CpuFeatures::ARM::kASIMD);
529 : # endif
530 :
531 : # if defined(__ARM_FEATURE_IDIV) && defined(__TARGET_ARCH_THUMB)
532 : cpu.addFeature(CpuFeatures::ARM::kIDIVT);
533 : #endif
534 : # if defined(__ARM_FEATURE_IDIV) && !defined(__TARGET_ARCH_THUMB)
535 : cpu.addFeature(CpuFeatures::ARM::kIDIVA);
536 : # endif
537 :
538 : #endif
539 :
540 : #if defined(__ARM_ARCH_8_1A__)
541 : cpu.addFeature(CpuFeatures::ARM::kARMv8_1a);
542 : #endif
543 : #if defined(__ARM_ARCH_8_2A__)
544 : cpu.addFeature(CpuFeatures::ARM::kARMv8_2a);
545 : #endif
546 : #if defined(__ARM_ARCH_8_3A__)
547 : cpu.addFeature(CpuFeatures::ARM::kARMv8_3a);
548 : #endif
549 : #if defined(__ARM_ARCH_8_4A__)
550 : cpu.addFeature(CpuFeatures::ARM::kARMv8_4a);
551 : #endif
552 : #if defined(__ARM_ARCH_8_5A__)
553 : cpu.addFeature(CpuFeatures::ARM::kARMv8_5a);
554 : #endif
555 : #if defined(__ARM_ARCH_8_6A__)
556 : cpu.addFeature(CpuFeatures::ARM::kARMv8_6a);
557 : #endif
558 : #if defined(__ARM_ARCH_8_7A__)
559 : cpu.addFeature(CpuFeatures::ARM::kARMv8_7a);
560 : #endif
561 :
562 : #if defined(__ARM_FEATURE_AES)
563 : cpu.addFeature(CpuFeatures::ARM::kAES);
564 : #endif
565 :
566 : #if defined(__ARM_FEATURE_BF16_SCALAR_ARITHMETIC) && defined(__ARM_FEATURE_BF16_VECTOR_ARITHMETIC)
567 : cpu.addFeature(CpuFeatures::ARM::kBF16);
568 : #endif
569 :
570 : #if defined(__ARM_FEATURE_CRC32)
571 : cpu.addFeature(CpuFeatures::ARM::kCRC32);
572 : #endif
573 :
574 : #if defined(__ARM_FEATURE_CRYPTO)
575 : cpu.addFeature(CpuFeatures::ARM::kAES,
576 : CpuFeatures::ARM::kSHA1,
577 : CpuFeatures::ARM::kSHA2);
578 : #endif
579 :
580 : #if defined(__ARM_FEATURE_DOTPROD)
581 : cpu.addFeature(CpuFeatures::ARM::kDOTPROD);
582 : #endif
583 :
584 : #if defined(__ARM_FEATURE_FP16FML) || defined(__ARM_FEATURE_FP16_FML)
585 : cpu.addFeature(CpuFeatures::ARM::kFP16FML);
586 : #endif
587 :
588 : #if defined(__ARM_FEATURE_FP16_SCALAR_ARITHMETIC)
589 : cpu.addFeature(CpuFeatures::ARM::kFP16FULL);
590 : #endif
591 :
592 : #if defined(__ARM_FEATURE_FRINT)
593 : cpu.addFeature(CpuFeatures::ARM::kFRINT);
594 : #endif
595 :
596 : #if defined(__ARM_FEATURE_JCVT)
597 : cpu.addFeature(CpuFeatures::ARM::kFJCVTZS);
598 : #endif
599 :
600 : #if defined(__ARM_FEATURE_MATMUL_INT8)
601 : cpu.addFeature(CpuFeatures::ARM::kI8MM);
602 : #endif
603 :
604 : #if defined(__ARM_FEATURE_ATOMICS)
605 : cpu.addFeature(CpuFeatures::ARM::kLSE);
606 : #endif
607 :
608 : #if defined(__ARM_FEATURE_MEMORY_TAGGING)
609 : cpu.addFeature(CpuFeatures::ARM::kMTE);
610 : #endif
611 :
612 : #if defined(__ARM_FEATURE_QRDMX)
613 : cpu.addFeature(CpuFeatures::ARM::kRDM);
614 : #endif
615 :
616 : #if defined(__ARM_FEATURE_RNG)
617 : cpu.addFeature(CpuFeatures::ARM::kRNG);
618 : #endif
619 :
620 : #if defined(__ARM_FEATURE_SHA2)
621 : cpu.addFeature(CpuFeatures::ARM::kSHA2);
622 : #endif
623 :
624 : #if defined(__ARM_FEATURE_SHA3)
625 : cpu.addFeature(CpuFeatures::ARM::kSHA3);
626 : #endif
627 :
628 : #if defined(__ARM_FEATURE_SHA512)
629 : cpu.addFeature(CpuFeatures::ARM::kSHA512);
630 : #endif
631 :
632 : #if defined(__ARM_FEATURE_SM3)
633 : cpu.addFeature(CpuFeatures::ARM::kSM3);
634 : #endif
635 :
636 : #if defined(__ARM_FEATURE_SM4)
637 : cpu.addFeature(CpuFeatures::ARM::kSM4);
638 : #endif
639 :
640 : #if defined(__ARM_FEATURE_SVE) || defined(__ARM_FEATURE_SVE_VECTOR_OPERATORS)
641 : cpu.addFeature(CpuFeatures::ARM::kSVE);
642 : #endif
643 :
644 : #if defined(__ARM_FEATURE_SVE_MATMUL_INT8)
645 : cpu.addFeature(CpuFeatures::ARM::kSVE_I8MM);
646 : #endif
647 :
648 : #if defined(__ARM_FEATURE_SVE_MATMUL_FP32)
649 : cpu.addFeature(CpuFeatures::ARM::kSVE_F32MM);
650 : #endif
651 :
652 : #if defined(__ARM_FEATURE_SVE_MATMUL_FP64)
653 : cpu.addFeature(CpuFeatures::ARM::kSVE_F64MM);
654 : #endif
655 :
656 : #if defined(__ARM_FEATURE_SVE2)
657 : cpu.addFeature(CpuFeatures::ARM::kSVE2);
658 : #endif
659 :
660 : #if defined(__ARM_FEATURE_SVE2_AES)
661 : cpu.addFeature(CpuFeatures::ARM::kSVE2_AES);
662 : #endif
663 :
664 : #if defined(__ARM_FEATURE_SVE2_BITPERM)
665 : cpu.addFeature(CpuFeatures::ARM::kSVE2_BITPERM);
666 : #endif
667 :
668 : #if defined(__ARM_FEATURE_SVE2_SHA3)
669 : cpu.addFeature(CpuFeatures::ARM::kSVE2_SHA3);
670 : #endif
671 :
672 : #if defined(__ARM_FEATURE_SVE2_SM4)
673 : cpu.addFeature(CpuFeatures::ARM::kSVE2_SM4);
674 : #endif
675 :
676 : #if defined(__ARM_FEATURE_TME)
677 : cpu.addFeature(CpuFeatures::ARM::kTME);
678 : #endif
679 : }
680 :
681 : ASMJIT_MAYBE_UNUSED
682 : static ASMJIT_FAVOR_SIZE void expandARMFeaturesByVersion(CpuInfo& cpu) noexcept {
683 : CpuFeatures::ARM& features = cpu.features().arm();
684 :
685 : if (features.hasARMv8_7a()) {
686 : features.add(CpuFeatures::ARM::kARMv8_6a);
687 : }
688 :
689 : if (features.hasARMv8_6a()) {
690 : features.add(CpuFeatures::ARM::kARMv8_5a,
691 : CpuFeatures::ARM::kBF16);
692 :
693 : if (features.hasSVE())
694 : features.add(CpuFeatures::ARM::kSVE_I8MM);
695 : }
696 :
697 : if (features.hasARMv8_5a()) {
698 : features.add(CpuFeatures::ARM::kARMv8_4a,
699 : CpuFeatures::ARM::kALTNZCV,
700 : CpuFeatures::ARM::kBTI,
701 : CpuFeatures::ARM::kFRINT,
702 : CpuFeatures::ARM::kSB,
703 : CpuFeatures::ARM::kSSBS);
704 : }
705 :
706 : if (features.hasARMv8_4a()) {
707 : features.add(CpuFeatures::ARM::kARMv8_3a,
708 : CpuFeatures::ARM::kDIT,
709 : CpuFeatures::ARM::kDOTPROD,
710 : CpuFeatures::ARM::kFLAGM,
711 : CpuFeatures::ARM::kPMU,
712 : CpuFeatures::ARM::kRCPC_IMMO);
713 : }
714 :
715 : if (features.hasARMv8_3a()) {
716 : features.add(CpuFeatures::ARM::kARMv8_2a,
717 : CpuFeatures::ARM::kFCMA,
718 : CpuFeatures::ARM::kFJCVTZS);
719 : }
720 :
721 : if (features.hasARMv8_2a()) {
722 : features.add(CpuFeatures::ARM::kARMv8_1a);
723 : }
724 :
725 : if (features.hasARMv8_1a()) {
726 : features.add(CpuFeatures::ARM::kARMv8a,
727 : CpuFeatures::ARM::kCRC32,
728 : CpuFeatures::ARM::kLSE,
729 : CpuFeatures::ARM::kRDM);
730 : }
731 :
732 : if (features.hasARMv8a()) {
733 : features.add(CpuFeatures::ARM::kARMv7,
734 : CpuFeatures::ARM::kVFPv2,
735 : CpuFeatures::ARM::kVFPv3,
736 : CpuFeatures::ARM::kVFPv4,
737 : CpuFeatures::ARM::kVFP_D32,
738 : CpuFeatures::ARM::kASIMD,
739 : CpuFeatures::ARM::kIDIVA);
740 : }
741 : }
742 :
743 : // CpuInfo - Detect - ARM [Windows]
744 : // ================================
745 :
746 : #if defined(_WIN32)
747 : struct WinPFPMapping {
748 : uint8_t featureId;
749 : uint8_t pfpFeatureId;
750 : };
751 :
752 : static ASMJIT_FAVOR_SIZE void detectPFPFeatures(CpuInfo& cpu, const WinPFPMapping* mapping, size_t size) noexcept {
753 : for (size_t i = 0; i < size; i++)
754 : if (::IsProcessorFeaturePresent(mapping[i].pfpFeatureId))
755 : cpu.addFeature(mapping[i].featureId);
756 : }
757 :
758 : //! Detect ARM CPU features on Windows.
759 : //!
760 : //! The detection is based on `IsProcessorFeaturePresent()` API call.
761 : static ASMJIT_FAVOR_SIZE void detectARMCpu(CpuInfo& cpu) noexcept {
762 : cpu._wasDetected = true;
763 : populateBaseARMFeatures(cpu);
764 :
765 : CpuFeatures::ARM& features = cpu.features().arm();
766 :
767 : // Win32 for ARM requires ARMv7 with DSP extensions, VFPv3, and uses THUMBv2 by default.
768 : #if ASMJIT_ARCH_ARM == 32
769 : features.add(CpuFeatures::ARM::kTHUMB);
770 : features.add(CpuFeatures::ARM::kTHUMBv2);
771 : features.add(CpuFeatures::ARM::kARMv6);
772 : features.add(CpuFeatures::ARM::kARMv7);
773 : features.add(CpuFeatures::ARM::kEDSP);
774 : features.add(CpuFeatures::ARM::kVFPv2);
775 : features.add(CpuFeatures::ARM::kVFPv3);
776 : #endif
777 :
778 : // Windows for ARM requires ASIMD.
779 : features.add(CpuFeatures::ARM::kASIMD);
780 :
781 : // Detect additional CPU features by calling `IsProcessorFeaturePresent()`.
782 : static const WinPFPMapping mapping[] = {
783 : #if ASMJIT_ARCH_ARM == 32
784 : { uint8_t(CpuFeatures::ARM::kVFP_D32) , 18 }, // PF_ARM_VFP_32_REGISTERS_AVAILABLE
785 : { uint8_t(CpuFeatures::ARM::kIDIVT) , 24 }, // PF_ARM_DIVIDE_INSTRUCTION_AVAILABLE
786 : { uint8_t(CpuFeatures::ARM::kVFPv4) , 27 }, // PF_ARM_FMAC_INSTRUCTIONS_AVAILABLE
787 : { uint8_t(CpuFeatures::ARM::kARMv8a) , 29 }, // PF_ARM_V8_INSTRUCTIONS_AVAILABLE
788 : #endif
789 : { uint8_t(CpuFeatures::ARM::kAES) , 30 }, // PF_ARM_V8_CRYPTO_INSTRUCTIONS_AVAILABLE
790 : { uint8_t(CpuFeatures::ARM::kCRC32) , 31 }, // PF_ARM_V8_CRC32_INSTRUCTIONS_AVAILABLE
791 : { uint8_t(CpuFeatures::ARM::kLSE) , 34 } // PF_ARM_V81_ATOMIC_INSTRUCTIONS_AVAILABLE
792 :
793 : };
794 : detectPFPFeatures(cpu, mapping, ASMJIT_ARRAY_SIZE(mapping));
795 :
796 : // Windows provides several instructions under a single flag:
797 : if (features.hasAES()) {
798 : features.add(CpuFeatures::ARM::kSHA1,
799 : CpuFeatures::ARM::kSHA2);
800 : }
801 :
802 : expandARMFeaturesByVersion(cpu);
803 : }
804 :
805 : // CpuInfo - Detect - ARM [Linux]
806 : // ==============================
807 :
808 : #elif defined(__linux__)
809 :
810 : struct LinuxHWCapMapping {
811 : uint8_t featureId;
812 : uint8_t hwCapBit;
813 : };
814 :
815 : static ASMJIT_FAVOR_SIZE void detectHWCaps(CpuInfo& cpu, unsigned long type, const LinuxHWCapMapping* mapping, size_t size) noexcept {
816 : unsigned long mask = getauxval(type);
817 : for (size_t i = 0; i < size; i++)
818 : cpu.features().addIf(Support::bitTest(mask, mapping[i].hwCapBit), mapping[i].featureId);
819 : }
820 :
821 : #if ASMJIT_ARCH_ARM == 32
822 :
823 : // `AT_HWCAP` provides ARMv7 (and less) related flags.
824 : static const LinuxHWCapMapping hwCapMapping[] = {
825 : { uint8_t(CpuFeatures::ARM::kVFPv2) , 6 }, // HWCAP_VFP
826 : { uint8_t(CpuFeatures::ARM::kEDSP) , 7 }, // HWCAP_EDSP
827 : { uint8_t(CpuFeatures::ARM::kASIMD) , 12 }, // HWCAP_NEON
828 : { uint8_t(CpuFeatures::ARM::kVFPv3) , 13 }, // HWCAP_VFPv3
829 : { uint8_t(CpuFeatures::ARM::kVFPv4) , 16 }, // HWCAP_VFPv4
830 : { uint8_t(CpuFeatures::ARM::kIDIVA) , 17 }, // HWCAP_IDIVA
831 : { uint8_t(CpuFeatures::ARM::kIDIVT) , 18 }, // HWCAP_IDIVT
832 : { uint8_t(CpuFeatures::ARM::kVFP_D32) , 19 } // HWCAP_VFPD32
833 : };
834 :
835 : // `AT_HWCAP2` provides ARMv8+ related flags.
836 : static const LinuxHWCapMapping hwCap2Mapping[] = {
837 : { uint8_t(CpuFeatures::ARM::kAES) , 0 }, // HWCAP2_AES
838 : { uint8_t(CpuFeatures::ARM::kPMULL) , 1 }, // HWCAP2_PMULL
839 : { uint8_t(CpuFeatures::ARM::kSHA1) , 2 }, // HWCAP2_SHA1
840 : { uint8_t(CpuFeatures::ARM::kSHA2) , 3 }, // HWCAP2_SHA2
841 : { uint8_t(CpuFeatures::ARM::kCRC32) , 4 } // HWCAP2_CRC32
842 : };
843 :
844 : static ASMJIT_FAVOR_SIZE void detectARMCpu(CpuInfo& cpu) noexcept {
845 : cpu._wasDetected = true;
846 :
847 : populateBaseARMFeatures(cpu);
848 :
849 : CpuFeatures::ARM& features = cpu.features().arm();
850 :
851 : detectHWCaps(cpu, AT_HWCAP, hwCapMapping, ASMJIT_ARRAY_SIZE(hwCapMapping));
852 : detectHWCaps(cpu, AT_HWCAP2, hwCap2Mapping, ASMJIT_ARRAY_SIZE(hwCap2Mapping));
853 :
854 : // VFPv3 implies VFPv2.
855 : if (features.hasVFPv3())
856 : features.add(CpuFeatures::ARM::kVFPv2);
857 :
858 : // VFPv2 implies ARMv6.
859 : if (features.hasVFPv2())
860 : features.add(CpuFeatures::ARM::kARMv6);
861 :
862 : // ARMv7 provides VFPv3|ASIMD.
863 : if (features.hasVFPv3() || features.hasASIMD())
864 : features.add(CpuFeatures::ARM::kARMv7);
865 :
866 : // ARMv8 provives AES, CRC32, PMULL, SHA1, and SHA2.
867 : if (features.hasAES() || features.hasCRC32() || features.hasPMULL() || features.hasSHA1() || features.hasSHA2())
868 : features.add(CpuFeatures::ARM::kARMv8a);
869 : }
870 :
871 : #else
872 :
873 : // `AT_HWCAP` provides ARMv8+ related flags.
874 : static const LinuxHWCapMapping hwCapMapping[] = {
875 : /*
876 : { uint8_t(CpuFeatures::ARM::k) , 0 }, // HWCAP_FP
877 : */
878 : { uint8_t(CpuFeatures::ARM::kASIMD) , 1 }, // HWCAP_ASIMD
879 : /*
880 : { uint8_t(CpuFeatures::ARM::k) , 2 }, // HWCAP_EVTSTRM
881 : */
882 : { uint8_t(CpuFeatures::ARM::kAES) , 3 }, // HWCAP_AES
883 : { uint8_t(CpuFeatures::ARM::kPMULL) , 4 }, // HWCAP_PMULL
884 : { uint8_t(CpuFeatures::ARM::kSHA1) , 5 }, // HWCAP_SHA1
885 : { uint8_t(CpuFeatures::ARM::kSHA2) , 6 }, // HWCAP_SHA2
886 : { uint8_t(CpuFeatures::ARM::kCRC32) , 7 }, // HWCAP_CRC32
887 : { uint8_t(CpuFeatures::ARM::kLSE) , 8 }, // HWCAP_ATOMICS
888 : { uint8_t(CpuFeatures::ARM::kFP16CONV) , 9 }, // HWCAP_FPHP
889 : { uint8_t(CpuFeatures::ARM::kFP16FULL) , 10 }, // HWCAP_ASIMDHP
890 : { uint8_t(CpuFeatures::ARM::kCPUID) , 11 }, // HWCAP_CPUID
891 : { uint8_t(CpuFeatures::ARM::kRDM) , 12 }, // HWCAP_ASIMDRDM
892 : { uint8_t(CpuFeatures::ARM::kFJCVTZS) , 13 }, // HWCAP_JSCVT
893 : { uint8_t(CpuFeatures::ARM::kFCMA) , 14 }, // HWCAP_FCMA
894 : /*
895 : { uint8_t(CpuFeatures::ARM::k) , 15 }, // HWCAP_LRCPC
896 : { uint8_t(CpuFeatures::ARM::k) , 16 }, // HWCAP_DCPOP
897 : */
898 : { uint8_t(CpuFeatures::ARM::kSHA3) , 17 }, // HWCAP_SHA3
899 : { uint8_t(CpuFeatures::ARM::kSM3) , 18 }, // HWCAP_SM3
900 : { uint8_t(CpuFeatures::ARM::kSM4) , 19 }, // HWCAP_SM4
901 : { uint8_t(CpuFeatures::ARM::kDOTPROD) , 20 }, // HWCAP_ASIMDDP
902 : { uint8_t(CpuFeatures::ARM::kSHA512) , 21 }, // HWCAP_SHA512
903 : { uint8_t(CpuFeatures::ARM::kSVE) , 22 }, // HWCAP_SVE
904 : { uint8_t(CpuFeatures::ARM::kFP16FML) , 23 }, // HWCAP_ASIMDFHM
905 : { uint8_t(CpuFeatures::ARM::kDIT) , 24 }, // HWCAP_DIT
906 : /*
907 : { uint8_t(CpuFeatures::ARM::k) , 25 }, // HWCAP_USCAT
908 : { uint8_t(CpuFeatures::ARM::k) , 26 }, // HWCAP_ILRCPC
909 : */
910 : { uint8_t(CpuFeatures::ARM::kFLAGM) , 27 }, // HWCAP_FLAGM
911 : { uint8_t(CpuFeatures::ARM::kSSBS) , 28 }, // HWCAP_SSBS
912 : { uint8_t(CpuFeatures::ARM::kSB) , 29 } // HWCAP_SB
913 : /*
914 : { uint8_t(CpuFeatures::ARM::k) , 30 }, // HWCAP_PACA
915 : { uint8_t(CpuFeatures::ARM::k) , 31 } // HWCAP_PACG
916 : */
917 : };
918 :
919 : // `AT_HWCAP2` provides ARMv8+ related flags.
920 : static const LinuxHWCapMapping hwCapMapping2[] = {
921 : /*
922 : { uint8_t(CpuFeatures::ARM::k) , 0 }, // HWCAP2_DCPODP
923 : */
924 : { uint8_t(CpuFeatures::ARM::kSVE2) , 1 }, // HWCAP2_SVE2
925 : { uint8_t(CpuFeatures::ARM::kSVE2_AES) , 2 }, // HWCAP2_SVEAES
926 : { uint8_t(CpuFeatures::ARM::kSVE_PMULL) , 3 }, // HWCAP2_SVEPMULL
927 : { uint8_t(CpuFeatures::ARM::kSVE2_BITPERM), 4 }, // HWCAP2_SVEBITPERM
928 : { uint8_t(CpuFeatures::ARM::kSVE2_SHA3) , 5 }, // HWCAP2_SVESHA3
929 : { uint8_t(CpuFeatures::ARM::kSVE2_SM4) , 6 }, // HWCAP2_SVESM4
930 : { uint8_t(CpuFeatures::ARM::kALTNZCV) , 7 }, // HWCAP2_FLAGM2
931 : { uint8_t(CpuFeatures::ARM::kFRINT) , 8 }, // HWCAP2_FRINT
932 : { uint8_t(CpuFeatures::ARM::kSVE_I8MM) , 9 }, // HWCAP2_SVEI8MM
933 : { uint8_t(CpuFeatures::ARM::kSVE_F32MM) , 10 }, // HWCAP2_SVEF32MM
934 : { uint8_t(CpuFeatures::ARM::kSVE_F64MM) , 11 }, // HWCAP2_SVEF64MM
935 : { uint8_t(CpuFeatures::ARM::kSVE_BF16) , 12 }, // HWCAP2_SVEBF16
936 : { uint8_t(CpuFeatures::ARM::kI8MM) , 13 }, // HWCAP2_I8MM
937 : { uint8_t(CpuFeatures::ARM::kBF16) , 14 }, // HWCAP2_BF16
938 : { uint8_t(CpuFeatures::ARM::kDGH) , 15 }, // HWCAP2_DGH
939 : { uint8_t(CpuFeatures::ARM::kRNG) , 16 }, // HWCAP2_RNG
940 : { uint8_t(CpuFeatures::ARM::kBTI) , 17 }, // HWCAP2_BTI
941 : { uint8_t(CpuFeatures::ARM::kMTE) , 18 } // HWCAP2_MTE
942 : };
943 :
944 : static ASMJIT_FAVOR_SIZE void detectARMCpu(CpuInfo& cpu) noexcept {
945 : cpu._wasDetected = true;
946 : populateBaseARMFeatures(cpu);
947 :
948 : detectHWCaps(cpu, AT_HWCAP, hwCapMapping, ASMJIT_ARRAY_SIZE(hwCapMapping));
949 : detectHWCaps(cpu, AT_HWCAP2, hwCapMapping2, ASMJIT_ARRAY_SIZE(hwCapMapping2));
950 : }
951 :
952 : #endif
953 :
954 : // CpuInfo - Detect - ARM [Apple]
955 : // ==============================
956 :
957 : #elif defined(__APPLE__)
958 :
959 : namespace AppleHWId {
960 : enum CpuFamily : uint32_t {
961 : // Generic ARM.
962 : kCpuFamily_ARM_9 = 0xE73283AEu,
963 : kCpuFamily_ARM_11 = 0x8FF620D8u,
964 : kCpuFamily_ARM_12 = 0xBD1B0AE9u,
965 : kCpuFamily_ARM_13 = 0x0CC90E64u,
966 : kCpuFamily_ARM_14 = 0x96077EF1u,
967 : kCpuFamily_ARM_15 = 0xA8511BCAu,
968 :
969 : // Apple design.
970 : kCpuFamily_SWIFT = 0x1E2D6381u,
971 : kCpuFamily_CYCLONE = 0x37A09642u,
972 : kCpuFamily_TYPHOON = 0x2C91A47Eu,
973 : kCpuFamily_TWISTER = 0x92FB37C8u,
974 : kCpuFamily_HURRICANE = 0x67CEEE93u,
975 : kCpuFamily_MONSOON_MISTRAL = 0xE81E7EF6u,
976 : kCpuFamily_VORTEX_TEMPEST = 0x07D34B9Fu,
977 : kCpuFamily_LIGHTNING_THUNDER = 0x462504D2u,
978 : kCpuFamily_FIRESTORM_ICESTORM = 0x1B588BB3u
979 : };
980 : };
981 :
982 : static ASMJIT_FAVOR_SIZE uint32_t queryARMCpuFamilyId() noexcept {
983 : uint32_t result = 0;
984 : size_t size = sizeof(result);
985 :
986 : int res = sysctlbyname("hw.cpufamily", &result, &size, nullptr, 0);
987 : if (res != 0)
988 : return 0;
989 : else
990 : return result;
991 : }
992 :
993 : static ASMJIT_FAVOR_SIZE void detectARMCpu(CpuInfo& cpu) noexcept {
994 : cpu._wasDetected = true;
995 : populateBaseARMFeatures(cpu);
996 :
997 : uint32_t cpuFamilyId = queryARMCpuFamilyId();
998 : CpuFeatures::ARM& features = cpu.features().arm();
999 :
1000 : switch (cpuFamilyId) {
1001 : case AppleHWId::kCpuFamily_ARM_9:
1002 : case AppleHWId::kCpuFamily_ARM_11:
1003 : case AppleHWId::kCpuFamily_ARM_12:
1004 : break;
1005 :
1006 : // ARM Cortex A8.
1007 : case AppleHWId::kCpuFamily_ARM_13:
1008 : break;
1009 :
1010 : // ARM Cortex A9.
1011 : case AppleHWId::kCpuFamily_ARM_14:
1012 : break;
1013 :
1014 : // ARM Cortex A7 - ARMv7k.
1015 : case AppleHWId::kCpuFamily_ARM_15:
1016 : features.add(CpuFeatures::ARM::kARMv7);
1017 : break;
1018 :
1019 : // Apple A6/A6X - ARMv7s.
1020 : case AppleHWId::kCpuFamily_SWIFT:
1021 : features.add(CpuFeatures::ARM::kARMv7);
1022 : break;
1023 :
1024 : // Apple A7 - ARMv8.0-A.
1025 : case AppleHWId::kCpuFamily_CYCLONE:
1026 : features.add(CpuFeatures::ARM::kARMv8a,
1027 : CpuFeatures::ARM::kAES,
1028 : CpuFeatures::ARM::kSHA1,
1029 : CpuFeatures::ARM::kSHA2);
1030 : break;
1031 :
1032 : // Apple A8 - ARMv8.0-A.
1033 : case AppleHWId::kCpuFamily_TYPHOON:
1034 : features.add(CpuFeatures::ARM::kARMv8a,
1035 : CpuFeatures::ARM::kAES,
1036 : CpuFeatures::ARM::kSHA1,
1037 : CpuFeatures::ARM::kSHA2);
1038 : break;
1039 :
1040 : // Apple A9 - ARMv8.0-A.
1041 : case AppleHWId::kCpuFamily_TWISTER:
1042 : features.add(CpuFeatures::ARM::kARMv8a,
1043 : CpuFeatures::ARM::kAES,
1044 : CpuFeatures::ARM::kSHA1,
1045 : CpuFeatures::ARM::kSHA2);
1046 : break;
1047 :
1048 : // Apple A10 - ARMv8.1-A.
1049 : case AppleHWId::kCpuFamily_HURRICANE:
1050 : features.add(CpuFeatures::ARM::kARMv8_1a,
1051 : CpuFeatures::ARM::kAES,
1052 : CpuFeatures::ARM::kRDM,
1053 : CpuFeatures::ARM::kSHA1,
1054 : CpuFeatures::ARM::kSHA2);
1055 :
1056 : break;
1057 :
1058 : // Apple A11 - ARMv8.2-A.
1059 : case AppleHWId::kCpuFamily_MONSOON_MISTRAL:
1060 : features.add(CpuFeatures::ARM::kARMv8_2a,
1061 : CpuFeatures::ARM::kAES,
1062 : CpuFeatures::ARM::kFP16FULL,
1063 : CpuFeatures::ARM::kSHA1,
1064 : CpuFeatures::ARM::kSHA2);
1065 : break;
1066 :
1067 : // Apple A12 - ARMv8.3-A.
1068 : case AppleHWId::kCpuFamily_VORTEX_TEMPEST:
1069 : features.add(CpuFeatures::ARM::kARMv8_3a,
1070 : CpuFeatures::ARM::kAES,
1071 : CpuFeatures::ARM::kFP16FULL,
1072 : CpuFeatures::ARM::kSHA1,
1073 : CpuFeatures::ARM::kSHA2);
1074 : break;
1075 :
1076 : // Apple A13 - ARMv8.4-A.
1077 : case AppleHWId::kCpuFamily_LIGHTNING_THUNDER:
1078 : features.add(CpuFeatures::ARM::kARMv8_4a,
1079 : CpuFeatures::ARM::kAES,
1080 : CpuFeatures::ARM::kFP16FML,
1081 : CpuFeatures::ARM::kFP16FULL,
1082 : CpuFeatures::ARM::kSHA1,
1083 : CpuFeatures::ARM::kSHA2,
1084 : CpuFeatures::ARM::kSHA3,
1085 : CpuFeatures::ARM::kSHA512);
1086 : break;
1087 :
1088 : // Apple A14/M1 - ARMv8.5-A.
1089 : case AppleHWId::kCpuFamily_FIRESTORM_ICESTORM:
1090 : features.add(CpuFeatures::ARM::kARMv8_4a,
1091 : CpuFeatures::ARM::kAES,
1092 : CpuFeatures::ARM::kALTNZCV,
1093 : CpuFeatures::ARM::kFP16FML,
1094 : CpuFeatures::ARM::kFP16FULL,
1095 : CpuFeatures::ARM::kFRINT,
1096 : CpuFeatures::ARM::kSB,
1097 : CpuFeatures::ARM::kSHA1,
1098 : CpuFeatures::ARM::kSHA2,
1099 : CpuFeatures::ARM::kSHA3,
1100 : CpuFeatures::ARM::kSHA512,
1101 : CpuFeatures::ARM::kSSBS);
1102 : break;
1103 :
1104 : default:
1105 : cpu._wasDetected = false;
1106 : break;
1107 : }
1108 :
1109 : expandARMFeaturesByVersion(cpu);
1110 : }
1111 :
1112 : // CpuInfo - Detect - ARM [Unknown]
1113 : // ================================
1114 :
1115 : #else
1116 :
1117 : #if ASMJIT_ARCH_ARM == 64
1118 : #pragma message("[asmjit] Disabling runtime CPU detection - unsupported OS/CPU combination (Unknown OS with AArch64 CPU)")
1119 : #else
1120 : #pragma message("[asmjit] Disabling runtime CPU detection - unsupported OS/CPU combination (Unknown OS with ARM CPU)")
1121 : #endif
1122 :
1123 : static ASMJIT_FAVOR_SIZE void detectARMCpu(CpuInfo& cpu) noexcept {
1124 : populateBaseARMFeatures(cpu);
1125 : detectARMFeaturesViaCompilerFlags(cpu);
1126 : expandARMFeaturesByVersion(cpu);
1127 : }
1128 : #endif
1129 :
1130 : #endif
1131 :
1132 : // CpuInfo - Detect - Host
1133 : // =======================
1134 :
1135 : static uint32_t cpuInfoInitialized;
1136 : static CpuInfo cpuInfoGlobal(Globals::NoInit);
1137 :
1138 27492 : const CpuInfo& CpuInfo::host() noexcept {
1139 : // This should never cause a problem as the resulting information should always be the same. In the worst case we
1140 : // would just overwrite it non-atomically.
1141 27492 : if (!cpuInfoInitialized) {
1142 : CpuInfo cpuInfoLocal;
1143 :
1144 355 : cpuInfoLocal._arch = Arch::kHost;
1145 355 : cpuInfoLocal._subArch = SubArch::kHost;
1146 :
1147 : #if ASMJIT_ARCH_X86
1148 355 : detectX86Cpu(cpuInfoLocal);
1149 : #elif ASMJIT_ARCH_ARM
1150 : detectARMCpu(cpuInfoLocal);
1151 : #else
1152 : #pragma message("[asmjit] Disabling runtime CPU detection - unsupported OS/CPU combination (Unknown CPU)")
1153 : #endif
1154 :
1155 355 : cpuInfoLocal._hwThreadCount = detectHWThreadCount();
1156 355 : cpuInfoGlobal = cpuInfoLocal;
1157 355 : cpuInfoInitialized = 1;
1158 : }
1159 :
1160 27492 : return cpuInfoGlobal;
1161 : }
1162 :
1163 : ASMJIT_END_NAMESPACE
1164 :
1165 : #endif // __PLUMED_HAS_ASMJIT
|