LCOV - code coverage report
Current view: top level - asmjit - cpuinfo.cpp (source / functions) Hit Total Coverage
Test: plumed test coverage (other modules) Lines: 80 80 100.0 %
Date: 2026-11-05 10:19:06 Functions: 4 4 100.0 %

          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(&regs, 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(&regs, 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(&regs, 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(&regs, 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(&regs, 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(&regs, 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(&regs, 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(&regs, 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

Generated by: LCOV version 1.16