LCOV - code coverage report
Current view: top level - src - processor_x86.cpp (source / functions) Hit Total Coverage
Test: [test only] commit 0f242327d2cc9bd130497f44b6350c924185606a Lines: 250 430 58.1 %
Date: 2022-07-16 23:42:53 Functions: 32 38 84.2 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 104 275 37.8 %

           Branch data     Line data    Source code
       1                 :            : // This file is a part of Julia. License is MIT: https://julialang.org/license
       2                 :            : 
       3                 :            : // X86 specific processor detection and dispatch
       4                 :            : 
       5                 :            : // CPUID
       6                 :            : 
       7                 :       3484 : extern "C" JL_DLLEXPORT void jl_cpuid(int32_t CPUInfo[4], int32_t InfoType)
       8                 :            : {
       9                 :            :     asm volatile (
      10                 :            : #if defined(__i386__) && defined(__PIC__)
      11                 :            :         "xchg %%ebx, %%esi;"
      12                 :            :         "cpuid;"
      13                 :            :         "xchg %%esi, %%ebx;" :
      14                 :            :         "=S" (CPUInfo[1]),
      15                 :            : #else
      16                 :            :         "cpuid" :
      17                 :       3484 :         "=b" (CPUInfo[1]),
      18                 :            : #endif
      19                 :            :         "=a" (CPUInfo[0]),
      20                 :       3484 :         "=c" (CPUInfo[2]),
      21                 :       3484 :         "=d" (CPUInfo[3]) :
      22                 :            :         "a" (InfoType)
      23                 :       3484 :         );
      24                 :       3484 : }
      25                 :            : 
      26                 :       2850 : extern "C" JL_DLLEXPORT void jl_cpuidex(int32_t CPUInfo[4], int32_t InfoType, int32_t subInfoType)
      27                 :            : {
      28                 :            :     asm volatile (
      29                 :            : #if defined(__i386__) && defined(__PIC__)
      30                 :            :         "xchg %%ebx, %%esi;"
      31                 :            :         "cpuid;"
      32                 :            :         "xchg %%esi, %%ebx;" :
      33                 :            :         "=S" (CPUInfo[1]),
      34                 :            : #else
      35                 :            :         "cpuid" :
      36                 :       2850 :         "=b" (CPUInfo[1]),
      37                 :            : #endif
      38                 :            :         "=a" (CPUInfo[0]),
      39                 :       2850 :         "=c" (CPUInfo[2]),
      40                 :       2850 :         "=d" (CPUInfo[3]) :
      41                 :            :         "a" (InfoType),
      42                 :            :         "c" (subInfoType)
      43                 :       2850 :         );
      44                 :       2850 : }
      45                 :            : 
      46                 :            : namespace X86 {
      47                 :            : 
      48                 :            : enum class CPU : uint32_t {
      49                 :            :     generic = 0,
      50                 :            :     intel_nocona,
      51                 :            :     intel_prescott,
      52                 :            :     intel_atom_bonnell,
      53                 :            :     intel_atom_silvermont,
      54                 :            :     intel_atom_goldmont,
      55                 :            :     intel_atom_goldmont_plus,
      56                 :            :     intel_atom_tremont,
      57                 :            :     intel_core2,
      58                 :            :     intel_core2_penryn,
      59                 :            :     intel_yonah,
      60                 :            :     intel_corei7_nehalem,
      61                 :            :     intel_corei7_westmere,
      62                 :            :     intel_corei7_sandybridge,
      63                 :            :     intel_corei7_ivybridge,
      64                 :            :     intel_corei7_haswell,
      65                 :            :     intel_corei7_broadwell,
      66                 :            :     intel_corei7_skylake,
      67                 :            :     intel_corei7_skylake_avx512,
      68                 :            :     intel_corei7_cascadelake,
      69                 :            :     intel_corei7_cooperlake,
      70                 :            :     intel_corei7_cannonlake,
      71                 :            :     intel_corei7_icelake_client,
      72                 :            :     intel_corei7_icelake_server,
      73                 :            :     intel_corei7_tigerlake,
      74                 :            :     intel_corei7_alderlake,
      75                 :            :     intel_corei7_sapphirerapids,
      76                 :            :     intel_knights_landing,
      77                 :            :     intel_knights_mill,
      78                 :            : 
      79                 :            :     amd_fam10h,
      80                 :            :     amd_athlon_fx,
      81                 :            :     amd_athlon_64,
      82                 :            :     amd_athlon_64_sse3,
      83                 :            :     amd_bdver1,
      84                 :            :     amd_bdver2,
      85                 :            :     amd_bdver3,
      86                 :            :     amd_bdver4,
      87                 :            :     amd_btver1,
      88                 :            :     amd_btver2,
      89                 :            :     amd_k8,
      90                 :            :     amd_k8_sse3,
      91                 :            :     amd_opteron,
      92                 :            :     amd_opteron_sse3,
      93                 :            :     amd_barcelona,
      94                 :            :     amd_znver1,
      95                 :            :     amd_znver2,
      96                 :            :     amd_znver3,
      97                 :            : };
      98                 :            : 
      99                 :            : static constexpr size_t feature_sz = 11;
     100                 :            : static constexpr FeatureName feature_names[] = {
     101                 :            : #define JL_FEATURE_DEF(name, bit, llvmver) {#name, bit, llvmver},
     102                 :            : #define JL_FEATURE_DEF_NAME(name, bit, llvmver, str) {str, bit, llvmver},
     103                 :            : #include "features_x86.h"
     104                 :            : #undef JL_FEATURE_DEF
     105                 :            : #undef JL_FEATURE_DEF_NAME
     106                 :            : };
     107                 :            : static constexpr uint32_t nfeature_names = sizeof(feature_names) / sizeof(FeatureName);
     108                 :            : 
     109                 :            : template<typename... Args>
     110                 :            : static inline constexpr FeatureList<feature_sz> get_feature_masks(Args... args)
     111                 :            : {
     112                 :            :     return ::get_feature_masks<feature_sz>(args...);
     113                 :            : }
     114                 :            : 
     115                 :            : #define JL_FEATURE_DEF_NAME(name, bit, llvmver, str) JL_FEATURE_DEF(name, bit, llvmver)
     116                 :            : static constexpr auto feature_masks = get_feature_masks(
     117                 :            : #define JL_FEATURE_DEF(name, bit, llvmver) bit,
     118                 :            : #include "features_x86.h"
     119                 :            : #undef JL_FEATURE_DEF
     120                 :            :     -1);
     121                 :            : 
     122                 :            : namespace Feature {
     123                 :            : enum : uint32_t {
     124                 :            : #define JL_FEATURE_DEF(name, bit, llvmver) name = bit,
     125                 :            : #include "features_x86.h"
     126                 :            : #undef JL_FEATURE_DEF
     127                 :            : };
     128                 :            : #undef JL_FEATURE_DEF_NAME
     129                 :            : static constexpr FeatureDep deps[] = {
     130                 :            :     {ssse3, sse3},
     131                 :            :     {fma, avx},
     132                 :            :     {sse41, ssse3},
     133                 :            :     {sse42, sse41},
     134                 :            :     {avx, sse42},
     135                 :            :     {f16c, avx},
     136                 :            :     {avx2, avx},
     137                 :            :     {vaes, avx},
     138                 :            :     {vaes, aes},
     139                 :            :     {vpclmulqdq, avx},
     140                 :            :     {vpclmulqdq, pclmul},
     141                 :            :     {avxvnni, avx2},
     142                 :            :     {avx512f, avx2},
     143                 :            :     {avx512dq, avx512f},
     144                 :            :     {avx512ifma, avx512f},
     145                 :            :     {avx512pf, avx512f},
     146                 :            :     {avx512er, avx512f},
     147                 :            :     {avx512cd, avx512f},
     148                 :            :     {avx512bw, avx512f},
     149                 :            :     {avx512bf16, avx512bw},
     150                 :            :     {avx512bitalg, avx512bw},
     151                 :            :     {avx512vl, avx512f},
     152                 :            :     {avx512vbmi, avx512bw},
     153                 :            :     {avx512vbmi2, avx512bw},
     154                 :            :     {avx512vnni, avx512f},
     155                 :            :     {avx512vp2intersect, avx512f},
     156                 :            :     {avx512vpopcntdq, avx512f},
     157                 :            :     {amx_int8, amx_tile},
     158                 :            :     {amx_bf16, amx_tile},
     159                 :            :     {sse4a, sse3},
     160                 :            :     {xop, fma4},
     161                 :            :     {fma4, avx},
     162                 :            :     {fma4, sse4a},
     163                 :            :     {xsaveopt, xsave},
     164                 :            :     {xsavec, xsave},
     165                 :            :     {xsaves, xsave},
     166                 :            : };
     167                 :            : 
     168                 :            : // We require cx16 on 64bit by default. This can be overwritten with `-cx16`
     169                 :            : // This isn't really compatible with 32bit but we mask it off there with required LLVM version
     170                 :            : constexpr auto generic = get_feature_masks(cx16);
     171                 :            : constexpr auto bonnell = get_feature_masks(sse3, ssse3, cx16, movbe, sahf);
     172                 :            : constexpr auto silvermont = bonnell | get_feature_masks(sse41, sse42, popcnt,
     173                 :            :                                                         pclmul, prfchw, rdrnd);
     174                 :            : constexpr auto goldmont = silvermont | get_feature_masks(aes, sha, rdseed, xsave, xsaveopt,
     175                 :            :                                                          xsavec, xsaves, clflushopt, fsgsbase);
     176                 :            : constexpr auto goldmont_plus = goldmont | get_feature_masks(ptwrite, rdpid); // sgx
     177                 :            : constexpr auto tremont = goldmont_plus | get_feature_masks(clwb, gfni);
     178                 :            : constexpr auto knl = get_feature_masks(sse3, ssse3, sse41, sse42, cx16, sahf, popcnt,
     179                 :            :                                        aes, pclmul, avx, xsave, xsaveopt, rdrnd, f16c, fsgsbase,
     180                 :            :                                        avx2, bmi, bmi2, fma, lzcnt, movbe, adx, rdseed, prfchw,
     181                 :            :                                        avx512f, avx512er, avx512cd, avx512pf, prefetchwt1);
     182                 :            : constexpr auto knm = knl | get_feature_masks(avx512vpopcntdq);
     183                 :            : constexpr auto yonah = get_feature_masks(sse3);
     184                 :            : constexpr auto prescott = yonah;
     185                 :            : constexpr auto core2 = get_feature_masks(sse3, ssse3, cx16, sahf);
     186                 :            : constexpr auto nocona = get_feature_masks(sse3, cx16);
     187                 :            : constexpr auto penryn = nocona | get_feature_masks(ssse3, sse41, sahf);
     188                 :            : constexpr auto nehalem = penryn | get_feature_masks(sse42, popcnt);
     189                 :            : constexpr auto westmere = nehalem | get_feature_masks(pclmul);
     190                 :            : constexpr auto sandybridge = westmere | get_feature_masks(avx, xsave, xsaveopt);
     191                 :            : constexpr auto ivybridge = sandybridge | get_feature_masks(rdrnd, f16c, fsgsbase);
     192                 :            : constexpr auto haswell = ivybridge | get_feature_masks(avx2, bmi, bmi2, fma, lzcnt, movbe);
     193                 :            : constexpr auto broadwell = haswell | get_feature_masks(adx, rdseed, prfchw);
     194                 :            : constexpr auto skylake = broadwell | get_feature_masks(aes, xsavec, xsaves, clflushopt); // sgx
     195                 :            : constexpr auto skx = skylake | get_feature_masks(avx512f, avx512cd, avx512dq, avx512bw, avx512vl,
     196                 :            :                                                  pku, clwb);
     197                 :            : constexpr auto cascadelake = skx | get_feature_masks(avx512vnni);
     198                 :            : constexpr auto cooperlake = cascadelake | get_feature_masks(avx512bf16);
     199                 :            : constexpr auto cannonlake = skylake | get_feature_masks(avx512f, avx512cd, avx512dq, avx512bw,
     200                 :            :                                                         avx512vl, pku, avx512vbmi, avx512ifma,
     201                 :            :                                                         sha); // sgx
     202                 :            : constexpr auto icelake = cannonlake | get_feature_masks(avx512bitalg, vaes, avx512vbmi2,
     203                 :            :                                                         vpclmulqdq, avx512vpopcntdq,
     204                 :            :                                                         gfni, clwb, rdpid);
     205                 :            : constexpr auto icelake_server = icelake | get_feature_masks(pconfig, wbnoinvd);
     206                 :            : constexpr auto tigerlake = icelake | get_feature_masks(avx512vp2intersect, movdiri,
     207                 :            :                                                        movdir64b, shstk);
     208                 :            : constexpr auto alderlake = skylake | get_feature_masks(clwb, sha, waitpkg, shstk, gfni, vaes, vpclmulqdq, pconfig,
     209                 :            :                                                        rdpid, movdiri, pku, movdir64b, serialize, ptwrite, avxvnni);
     210                 :            : constexpr auto sapphirerapids = icelake_server |
     211                 :            :     get_feature_masks(amx_tile, amx_int8, amx_bf16, avx512bf16, serialize, cldemote, waitpkg,
     212                 :            :                       ptwrite, tsxldtrk, enqcmd, shstk, avx512vp2intersect, movdiri, movdir64b);
     213                 :            : 
     214                 :            : constexpr auto k8_sse3 = get_feature_masks(sse3, cx16);
     215                 :            : constexpr auto amdfam10 = k8_sse3 | get_feature_masks(sse4a, lzcnt, popcnt, sahf);
     216                 :            : 
     217                 :            : constexpr auto btver1 = amdfam10 | get_feature_masks(ssse3, prfchw);
     218                 :            : constexpr auto btver2 = btver1 | get_feature_masks(sse41, sse42, avx, aes, pclmul, bmi, f16c,
     219                 :            :                                                    movbe, xsave, xsaveopt);
     220                 :            : 
     221                 :            : constexpr auto bdver1 = amdfam10 | get_feature_masks(xop, fma4, avx, ssse3, sse41, sse42, aes,
     222                 :            :                                                      prfchw, pclmul, xsave, lwp);
     223                 :            : constexpr auto bdver2 = bdver1 | get_feature_masks(f16c, bmi, tbm, fma);
     224                 :            : constexpr auto bdver3 = bdver2 | get_feature_masks(xsaveopt, fsgsbase);
     225                 :            : constexpr auto bdver4 = bdver3 | get_feature_masks(avx2, bmi2, mwaitx, movbe, rdrnd);
     226                 :            : 
     227                 :            : constexpr auto znver1 = haswell | get_feature_masks(adx, aes, clflushopt, clzero, mwaitx, prfchw,
     228                 :            :                                                     rdseed, sha, sse4a, xsavec, xsaves);
     229                 :            : constexpr auto znver2 = znver1 | get_feature_masks(clwb, rdpid, wbnoinvd);
     230                 :            : constexpr auto znver3 = znver2 | get_feature_masks(shstk, pku, vaes, vpclmulqdq);
     231                 :            : 
     232                 :            : }
     233                 :            : 
     234                 :            : static constexpr CPUSpec<CPU, feature_sz> cpus[] = {
     235                 :            :     {"generic", CPU::generic, CPU::generic, 0, Feature::generic},
     236                 :            :     {"bonnell", CPU::intel_atom_bonnell, CPU::generic, 0, Feature::bonnell},
     237                 :            :     {"silvermont", CPU::intel_atom_silvermont, CPU::generic, 0, Feature::silvermont},
     238                 :            :     {"goldmont", CPU::intel_atom_goldmont, CPU::generic, 0, Feature::goldmont},
     239                 :            :     {"goldmont-plus", CPU::intel_atom_goldmont_plus, CPU::generic, 0, Feature::goldmont_plus},
     240                 :            :     {"tremont", CPU::intel_atom_tremont, CPU::generic, 0, Feature::tremont},
     241                 :            :     {"core2", CPU::intel_core2, CPU::generic, 0, Feature::core2},
     242                 :            :     {"yonah", CPU::intel_yonah, CPU::generic, 0, Feature::yonah},
     243                 :            :     {"prescott", CPU::intel_prescott, CPU::generic, 0, Feature::prescott},
     244                 :            :     {"nocona", CPU::intel_nocona, CPU::generic, 0, Feature::nocona},
     245                 :            :     {"penryn", CPU::intel_core2_penryn, CPU::generic, 0, Feature::penryn},
     246                 :            :     {"nehalem", CPU::intel_corei7_nehalem, CPU::generic, 0, Feature::nehalem},
     247                 :            :     {"westmere", CPU::intel_corei7_westmere, CPU::generic, 0, Feature::westmere},
     248                 :            :     {"sandybridge", CPU::intel_corei7_sandybridge, CPU::generic, 0, Feature::sandybridge},
     249                 :            :     {"ivybridge", CPU::intel_corei7_ivybridge, CPU::generic, 0, Feature::ivybridge},
     250                 :            :     {"haswell", CPU::intel_corei7_haswell, CPU::generic, 0, Feature::haswell},
     251                 :            :     {"broadwell", CPU::intel_corei7_broadwell, CPU::generic, 0, Feature::broadwell},
     252                 :            :     {"skylake", CPU::intel_corei7_skylake, CPU::generic, 0, Feature::skylake},
     253                 :            :     {"knl", CPU::intel_knights_landing, CPU::generic, 0, Feature::knl},
     254                 :            :     {"knm", CPU::intel_knights_mill, CPU::generic, 0, Feature::knm},
     255                 :            :     {"skylake-avx512", CPU::intel_corei7_skylake_avx512, CPU::generic, 0, Feature::skx},
     256                 :            :     {"cascadelake", CPU::intel_corei7_cascadelake, CPU::generic, 0, Feature::cascadelake},
     257                 :            :     {"cooperlake", CPU::intel_corei7_cooperlake, CPU::generic, 0, Feature::cooperlake},
     258                 :            :     {"cannonlake", CPU::intel_corei7_cannonlake, CPU::generic, 0, Feature::cannonlake},
     259                 :            :     {"icelake-client", CPU::intel_corei7_icelake_client, CPU::generic, 0, Feature::icelake},
     260                 :            :     {"icelake-server", CPU::intel_corei7_icelake_server, CPU::generic, 0,
     261                 :            :      Feature::icelake_server},
     262                 :            :     {"tigerlake", CPU::intel_corei7_tigerlake, CPU::intel_corei7_icelake_client, 100000,
     263                 :            :      Feature::tigerlake},
     264                 :            :     {"alderlake", CPU::intel_corei7_alderlake, CPU::intel_corei7_skylake, 120000,
     265                 :            :      Feature::alderlake},
     266                 :            :     {"sapphirerapids", CPU::intel_corei7_sapphirerapids, CPU::intel_corei7_icelake_server, 120000,
     267                 :            :      Feature::sapphirerapids},
     268                 :            : 
     269                 :            :     {"athlon64", CPU::amd_athlon_64, CPU::generic, 0, Feature::generic},
     270                 :            :     {"athlon-fx", CPU::amd_athlon_fx, CPU::generic, 0, Feature::generic},
     271                 :            :     {"k8", CPU::amd_k8, CPU::generic, 0, Feature::generic},
     272                 :            :     {"opteron", CPU::amd_opteron, CPU::generic, 0, Feature::generic},
     273                 :            : 
     274                 :            :     {"athlon64-sse3", CPU::amd_athlon_64_sse3, CPU::generic, 0, Feature::k8_sse3},
     275                 :            :     {"k8-sse3", CPU::amd_k8_sse3, CPU::generic, 0, Feature::k8_sse3},
     276                 :            :     {"opteron-sse3", CPU::amd_opteron_sse3, CPU::generic, 0, Feature::k8_sse3},
     277                 :            : 
     278                 :            :     {"amdfam10", CPU::amd_fam10h, CPU::generic, 0, Feature::amdfam10},
     279                 :            :     {"barcelona", CPU::amd_barcelona, CPU::generic, 0, Feature::amdfam10},
     280                 :            : 
     281                 :            :     {"btver1", CPU::amd_btver1, CPU::generic, 0, Feature::btver1},
     282                 :            :     {"btver2", CPU::amd_btver2, CPU::generic, 0, Feature::btver2},
     283                 :            : 
     284                 :            :     {"bdver1", CPU::amd_bdver1, CPU::generic, 0, Feature::bdver1},
     285                 :            :     {"bdver2", CPU::amd_bdver2, CPU::generic, 0, Feature::bdver2},
     286                 :            :     {"bdver3", CPU::amd_bdver3, CPU::generic, 0, Feature::bdver3},
     287                 :            :     {"bdver4", CPU::amd_bdver4, CPU::generic, 0, Feature::bdver4},
     288                 :            : 
     289                 :            :     {"znver1", CPU::amd_znver1, CPU::generic, 0, Feature::znver1},
     290                 :            :     {"znver2", CPU::amd_znver2, CPU::generic, 0, Feature::znver2},
     291                 :            :     {"znver3", CPU::amd_znver3, CPU::amd_znver2, 120000, Feature::znver3},
     292                 :            : };
     293                 :            : static constexpr size_t ncpu_names = sizeof(cpus) / sizeof(cpus[0]);
     294                 :            : 
     295                 :            : // For CPU model and feature detection on X86
     296                 :            : 
     297                 :            : const int SIG_INTEL = 0x756e6547; // Genu
     298                 :            : const int SIG_AMD = 0x68747541; // Auth
     299                 :            : 
     300                 :        570 : static uint64_t get_xcr0(void)
     301                 :            : {
     302                 :            :     uint32_t eax, edx;
     303                 :        570 :     asm volatile ("xgetbv" : "=a" (eax), "=d" (edx) : "c" (0));
     304                 :        570 :     return (uint64_t(edx) << 32) | eax;
     305                 :            : }
     306                 :            : 
     307                 :        570 : static CPU get_intel_processor_name(uint32_t family, uint32_t model, uint32_t brand_id,
     308                 :            :                                     const uint32_t *features)
     309                 :            : {
     310         [ -  + ]:        570 :     if (brand_id != 0)
     311                 :          0 :         return CPU::generic;
     312   [ -  +  -  - ]:        570 :     switch (family) {
     313                 :          0 :     case 3:
     314                 :            :     case 4:
     315                 :            :     case 5:
     316                 :          0 :         return CPU::generic;
     317                 :        570 :     case 6:
     318   [ -  -  -  -  :        570 :         switch (model) {
          -  -  -  -  -  
          -  +  -  -  -  
          -  -  -  -  -  
          -  -  -  -  -  
                   -  - ]
     319                 :          0 :         case 0x01: // Pentium Pro processor
     320                 :            :         case 0x03: // Intel Pentium II OverDrive processor, Pentium II processor, model 03
     321                 :            :         case 0x05: // Pentium II processor, model 05, Pentium II Xeon processor,
     322                 :            :             // model 05, and Intel Celeron processor, model 05
     323                 :            :         case 0x06: // Celeron processor, model 06
     324                 :            :         case 0x07: // Pentium III processor, model 07, and Pentium III Xeon processor, model 07
     325                 :            :         case 0x08: // Pentium III processor, model 08, Pentium III Xeon processor,
     326                 :            :             // model 08, and Celeron processor, model 08
     327                 :            :         case 0x0a: // Pentium III Xeon processor, model 0Ah
     328                 :            :         case 0x0b: // Pentium III processor, model 0Bh
     329                 :            :         case 0x09: // Intel Pentium M processor, Intel Celeron M processor model 09.
     330                 :            :         case 0x0d: // Intel Pentium M processor, Intel Celeron M processor, model
     331                 :            :             // 0Dh. All processors are manufactured using the 90 nm process.
     332                 :            :         case 0x15: // Intel EP80579 Integrated Processor and Intel EP80579
     333                 :            :             // Integrated Processor with Intel QuickAssist Technology
     334                 :          0 :             return CPU::generic;
     335                 :          0 :         case 0x0e: // Intel Core Duo processor, Intel Core Solo processor, model
     336                 :            :             // 0Eh. All processors are manufactured using the 65 nm process.
     337                 :          0 :             return CPU::intel_yonah;
     338                 :          0 :         case 0x0f: // Intel Core 2 Duo processor, Intel Core 2 Duo mobile
     339                 :            :             // processor, Intel Core 2 Quad processor, Intel Core 2 Quad
     340                 :            :             // mobile processor, Intel Core 2 Extreme processor, Intel
     341                 :            :             // Pentium Dual-Core processor, Intel Xeon processor, model
     342                 :            :             // 0Fh. All processors are manufactured using the 65 nm process.
     343                 :            :         case 0x16: // Intel Celeron processor model 16h. All processors are
     344                 :            :             // manufactured using the 65 nm process
     345                 :          0 :             return CPU::intel_core2;
     346                 :          0 :         case 0x17: // Intel Core 2 Extreme processor, Intel Xeon processor, model
     347                 :            :             // 17h. All processors are manufactured using the 45 nm process.
     348                 :            :             //
     349                 :            :             // 45nm: Penryn , Wolfdale, Yorkfield (XE)
     350                 :            :         case 0x1d: // Intel Xeon processor MP. All processors are manufactured using
     351                 :            :             // the 45 nm process.
     352                 :          0 :             return CPU::intel_core2_penryn;
     353                 :          0 :         case 0x1a: // Intel Core i7 processor and Intel Xeon processor. All
     354                 :            :             // processors are manufactured using the 45 nm process.
     355                 :            :         case 0x1e: // Intel(R) Core(TM) i7 CPU         870  @ 2.93GHz.
     356                 :            :             // As found in a Summer 2010 model iMac.
     357                 :            :         case 0x1f:
     358                 :            :         case 0x2e: // Nehalem EX
     359                 :          0 :             return CPU::intel_corei7_nehalem;
     360                 :          0 :         case 0x25: // Intel Core i7, laptop version.
     361                 :            :         case 0x2c: // Intel Core i7 processor and Intel Xeon processor. All
     362                 :            :             // processors are manufactured using the 32 nm process.
     363                 :            :         case 0x2f: // Westmere EX
     364                 :          0 :             return CPU::intel_corei7_westmere;
     365                 :          0 :         case 0x2a: // Intel Core i7 processor. All processors are manufactured
     366                 :            :             // using the 32 nm process.
     367                 :            :         case 0x2d:
     368                 :          0 :             return CPU::intel_corei7_sandybridge;
     369                 :          0 :         case 0x3a:
     370                 :            :         case 0x3e: // Ivy Bridge EP
     371                 :          0 :             return CPU::intel_corei7_ivybridge;
     372                 :            : 
     373                 :            :             // Haswell:
     374                 :          0 :         case 0x3c:
     375                 :            :         case 0x3f:
     376                 :            :         case 0x45:
     377                 :            :         case 0x46:
     378                 :          0 :             return CPU::intel_corei7_haswell;
     379                 :            : 
     380                 :            :             // Broadwell:
     381                 :          0 :         case 0x3d:
     382                 :            :         case 0x47:
     383                 :            :         case 0x4f:
     384                 :            :         case 0x56:
     385                 :          0 :             return CPU::intel_corei7_broadwell;
     386                 :            : 
     387                 :            :             // Skylake:
     388                 :        570 :         case 0x4e: // Skylake mobile
     389                 :            :         case 0x5e: // Skylake desktop
     390                 :            :         case 0x8e: // Kaby Lake mobile
     391                 :            :         case 0x9e: // Kaby Lake desktop
     392                 :            :         case 0xa5: // Comet Lake-H/S
     393                 :            :         case 0xa6: // Comet Lake-U
     394                 :        570 :             return CPU::intel_corei7_skylake;
     395                 :            : 
     396                 :            :             // Skylake Xeon:
     397                 :          0 :         case 0x55:
     398         [ #  # ]:          0 :             if (test_nbit(features, Feature::avx512bf16))
     399                 :          0 :                 return CPU::intel_corei7_cooperlake;
     400         [ #  # ]:          0 :             if (test_nbit(features, Feature::avx512vnni))
     401                 :          0 :                 return CPU::intel_corei7_cascadelake;
     402                 :          0 :             return CPU::intel_corei7_skylake_avx512;
     403                 :            : 
     404                 :            :             // Cannonlake:
     405                 :          0 :         case 0x66:
     406                 :          0 :             return CPU::intel_corei7_cannonlake;
     407                 :            : 
     408                 :            :             // Icelake:
     409                 :          0 :         case 0x7d:
     410                 :            :         case 0x7e:
     411                 :            :         case 0x9d:
     412                 :          0 :             return CPU::intel_corei7_icelake_client;
     413                 :            : 
     414                 :            :             // Icelake Xeon:
     415                 :          0 :         case 0x6a:
     416                 :            :         case 0x6c:
     417                 :          0 :             return CPU::intel_corei7_icelake_server;
     418                 :            : 
     419                 :            :             // Tiger Lake
     420                 :          0 :         case 0x8c:
     421                 :            :         case 0x8d:
     422                 :          0 :             return CPU::intel_corei7_tigerlake;
     423                 :            :             //Alder Lake
     424                 :          0 :         case 0x97:
     425                 :            :         case 0x9a:
     426                 :          0 :             return CPU::intel_corei7_alderlake;
     427                 :            : 
     428                 :            :             // Sapphire Rapids
     429                 :          0 :         case 0x8f:
     430                 :          0 :             return CPU::intel_corei7_sapphirerapids;
     431                 :            : 
     432                 :          0 :         case 0x1c: // Most 45 nm Intel Atom processors
     433                 :            :         case 0x26: // 45 nm Atom Lincroft
     434                 :            :         case 0x27: // 32 nm Atom Medfield
     435                 :            :         case 0x35: // 32 nm Atom Midview
     436                 :            :         case 0x36: // 32 nm Atom Midview
     437                 :          0 :             return CPU::intel_atom_bonnell;
     438                 :            : 
     439                 :            :             // Atom Silvermont codes from the Intel software optimization guide.
     440                 :          0 :         case 0x37:
     441                 :            :         case 0x4a:
     442                 :            :         case 0x4d:
     443                 :            :         case 0x5d:
     444                 :            :             // Airmont
     445                 :            :         case 0x4c:
     446                 :            :         case 0x5a:
     447                 :            :         case 0x75:
     448                 :          0 :             return CPU::intel_atom_silvermont;
     449                 :            : 
     450                 :            :             // Goldmont:
     451                 :          0 :         case 0x5c:
     452                 :            :         case 0x5f:
     453                 :          0 :             return CPU::intel_atom_goldmont;
     454                 :          0 :         case 0x7a:
     455                 :          0 :             return CPU::intel_atom_goldmont_plus;
     456                 :          0 :         case 0x86:
     457                 :            :         case 0x96:
     458                 :            :         case 0x9c:
     459                 :          0 :             return CPU::intel_atom_tremont;
     460                 :            : 
     461                 :          0 :         case 0x57:
     462                 :          0 :             return CPU::intel_knights_landing;
     463                 :            : 
     464                 :          0 :         case 0x85:
     465                 :          0 :             return CPU::intel_knights_mill;
     466                 :            : 
     467                 :          0 :         default:
     468                 :          0 :             return CPU::generic;
     469                 :            :         }
     470                 :            :         break;
     471                 :          0 :     case 15: {
     472         [ #  # ]:          0 :         switch (model) {
     473                 :          0 :         case 0: // Pentium 4 processor, Intel Xeon processor. All processors are
     474                 :            :             // model 00h and manufactured using the 0.18 micron process.
     475                 :            :         case 1: // Pentium 4 processor, Intel Xeon processor, Intel Xeon
     476                 :            :             // processor MP, and Intel Celeron processor. All processors are
     477                 :            :             // model 01h and manufactured using the 0.18 micron process.
     478                 :            :         case 2: // Pentium 4 processor, Mobile Intel Pentium 4 processor - M,
     479                 :            :             // Intel Xeon processor, Intel Xeon processor MP, Intel Celeron
     480                 :            :             // processor, and Mobile Intel Celeron processor. All processors
     481                 :            :             // are model 02h and manufactured using the 0.13 micron process.
     482                 :            :         default:
     483                 :          0 :             return CPU::generic;
     484                 :            : 
     485                 :          0 :         case 3: // Pentium 4 processor, Intel Xeon processor, Intel Celeron D
     486                 :            :             // processor. All processors are model 03h and manufactured using
     487                 :            :             // the 90 nm process.
     488                 :            :         case 4: // Pentium 4 processor, Pentium 4 processor Extreme Edition,
     489                 :            :             // Pentium D processor, Intel Xeon processor, Intel Xeon
     490                 :            :             // processor MP, Intel Celeron D processor. All processors are
     491                 :            :             // model 04h and manufactured using the 90 nm process.
     492                 :            :         case 6: // Pentium 4 processor, Pentium D processor, Pentium processor
     493                 :            :             // Extreme Edition, Intel Xeon processor, Intel Xeon processor
     494                 :            :             // MP, Intel Celeron D processor. All processors are model 06h
     495                 :            :             // and manufactured using the 65 nm process.
     496                 :            : #ifdef _CPU_X86_64_
     497                 :          0 :             return CPU::intel_nocona;
     498                 :            : #else
     499                 :            :             return CPU::intel_prescott;
     500                 :            : #endif
     501                 :            :         }
     502                 :            :     }
     503                 :          0 :     default:
     504                 :          0 :         break; /*"generic"*/
     505                 :            :     }
     506                 :          0 :     return CPU::generic;
     507                 :            : }
     508                 :            : 
     509                 :          0 : static CPU get_amd_processor_name(uint32_t family, uint32_t model, const uint32_t *features)
     510                 :            : {
     511   [ #  #  #  #  :          0 :     switch (family) {
             #  #  #  # ]
     512                 :          0 :     case 4:
     513                 :            :     case 5:
     514                 :            :     case 6:
     515                 :            :     default:
     516                 :          0 :         return CPU::generic;
     517                 :          0 :     case 15:
     518         [ #  # ]:          0 :         if (test_nbit(features, Feature::sse3))
     519                 :          0 :             return CPU::amd_k8_sse3;
     520      [ #  #  # ]:          0 :         switch (model) {
     521                 :          0 :         case 1:
     522                 :          0 :             return CPU::amd_opteron;
     523                 :          0 :         case 5:
     524                 :          0 :             return CPU::amd_athlon_fx;
     525                 :          0 :         default:
     526                 :          0 :             return CPU::amd_athlon_64;
     527                 :            :         }
     528                 :          0 :     case 16:
     529         [ #  # ]:          0 :         switch (model) {
     530                 :          0 :         case 2:
     531                 :          0 :             return CPU::amd_barcelona;
     532                 :          0 :         case 4:
     533                 :            :         case 8:
     534                 :            :         default:
     535                 :          0 :             return CPU::amd_fam10h;
     536                 :            :         }
     537                 :          0 :     case 20:
     538                 :          0 :         return CPU::amd_btver1;
     539                 :          0 :     case 21:
     540   [ #  #  #  # ]:          0 :         if (model >= 0x50 && model <= 0x6f)
     541                 :          0 :             return CPU::amd_bdver4;
     542   [ #  #  #  # ]:          0 :         if (model >= 0x30 && model <= 0x3f)
     543                 :          0 :             return CPU::amd_bdver3;
     544   [ #  #  #  # ]:          0 :         if (model >= 0x10 && model <= 0x1f)
     545                 :          0 :             return CPU::amd_bdver2;
     546         [ #  # ]:          0 :         if (model <= 0x0f)
     547                 :          0 :             return CPU::amd_bdver1;
     548                 :          0 :         return CPU::amd_btver1; // fallback
     549                 :          0 :     case 22:
     550                 :          0 :         return CPU::amd_btver2;
     551                 :          0 :     case 23:
     552                 :            :         // Known models:
     553                 :            :         // Zen: 1, 17
     554                 :            :         // Zen+: 8, 24
     555                 :            :         // Zen2: 96, 113
     556         [ #  # ]:          0 :         if (model >= 0x30)
     557                 :          0 :             return CPU::amd_znver2;
     558                 :          0 :         return CPU::amd_znver1;
     559                 :          0 :     case 0x19:  // AMD Family 19h
     560   [ #  #  #  # ]:          0 :         if (model <= 0x0f || model == 0x21)
     561                 :          0 :             return CPU::amd_znver3;  // 00h-0Fh, 21h: Zen3
     562                 :          0 :         return CPU::amd_znver3; // fallback
     563                 :            :     }
     564                 :            : }
     565                 :            : 
     566                 :            : template<typename T>
     567                 :        570 : static inline void features_disable_avx512(T &features)
     568                 :            : {
     569                 :            :     using namespace Feature;
     570                 :        570 :     unset_bits(features, avx512f, avx512dq, avx512ifma, avx512pf, avx512er, avx512cd,
     571                 :            :                avx512bw, avx512vl, avx512vbmi, avx512vpopcntdq, avx512vbmi2, avx512vnni,
     572                 :            :                avx512bitalg, avx512vp2intersect, avx512bf16);
     573                 :        570 : }
     574                 :            : 
     575                 :            : template<typename T>
     576                 :          0 : static inline void features_disable_avx(T &features)
     577                 :            : {
     578                 :            :     using namespace Feature;
     579                 :          0 :     unset_bits(features, avx, Feature::fma, f16c, xsave, avx2, xop, fma4,
     580                 :            :                xsaveopt, xsavec, xsaves, vaes, vpclmulqdq);
     581                 :          0 : }
     582                 :            : 
     583                 :            : template<typename T>
     584                 :        570 : static inline void features_disable_amx(T &features)
     585                 :            : {
     586                 :            :     using namespace Feature;
     587                 :        570 :     unset_bits(features, amx_bf16, amx_tile, amx_int8);
     588                 :        570 : }
     589                 :            : 
     590                 :        570 : static NOINLINE std::pair<uint32_t,FeatureList<feature_sz>> _get_host_cpu(void)
     591                 :            : {
     592                 :        570 :     FeatureList<feature_sz> features = {};
     593                 :            : 
     594                 :            :     int32_t info0[4];
     595                 :        570 :     jl_cpuid(info0, 0);
     596                 :        570 :     uint32_t maxleaf = info0[0];
     597         [ -  + ]:        570 :     if (maxleaf < 1)
     598                 :          0 :         return std::make_pair(uint32_t(CPU::generic), features);
     599                 :            :     int32_t info1[4];
     600                 :        570 :     jl_cpuid(info1, 1);
     601                 :            : 
     602                 :        570 :     auto vendor = info0[1];
     603                 :        570 :     auto brand_id = info1[1] & 0xff;
     604                 :            : 
     605                 :        570 :     auto family = (info1[0] >> 8) & 0xf; // Bits 8 - 11
     606                 :        570 :     auto model = (info1[0] >> 4) & 0xf;  // Bits 4 - 7
     607   [ -  +  -  - ]:        570 :     if (family == 6 || family == 0xf) {
     608         [ -  + ]:        570 :         if (family == 0xf)
     609                 :            :             // Examine extended family ID if family ID is F.
     610                 :          0 :             family += (info1[0] >> 20) & 0xff; // Bits 20 - 27
     611                 :            :         // Examine extended model ID if family ID is 6 or F.
     612                 :        570 :         model += ((info1[0] >> 16) & 0xf) << 4; // Bits 16 - 19
     613                 :            :     }
     614                 :            : 
     615                 :            :     // Fill in the features
     616                 :        570 :     features[0] = info1[2];
     617                 :        570 :     features[1] = info1[3];
     618         [ +  - ]:        570 :     if (maxleaf >= 7) {
     619                 :            :         int32_t info7[4];
     620                 :        570 :         jl_cpuidex(info7, 7, 0);
     621                 :        570 :         features[2] = info7[1];
     622                 :        570 :         features[3] = info7[2];
     623                 :        570 :         features[4] = info7[3];
     624                 :            :     }
     625                 :            :     int32_t infoex0[4];
     626                 :        570 :     jl_cpuid(infoex0, 0x80000000);
     627                 :        570 :     uint32_t maxexleaf = infoex0[0];
     628         [ +  - ]:        570 :     if (maxexleaf >= 0x80000001) {
     629                 :            :         int32_t infoex1[4];
     630                 :        570 :         jl_cpuid(infoex1, 0x80000001);
     631                 :        570 :         features[5] = infoex1[2];
     632                 :        570 :         features[6] = infoex1[3];
     633                 :            :     }
     634         [ +  - ]:        570 :     if (maxleaf >= 0xd) {
     635                 :            :         int32_t infod[4];
     636                 :        570 :         jl_cpuidex(infod, 0xd, 0x1);
     637                 :        570 :         features[7] = infod[0];
     638                 :            :     }
     639         [ +  - ]:        570 :     if (maxexleaf >= 0x80000008) {
     640                 :            :         int32_t infoex8[4];
     641                 :        570 :         jl_cpuidex(infoex8, 0x80000008, 0);
     642                 :        570 :         features[8] = infoex8[1];
     643                 :            :     }
     644         [ +  - ]:        570 :     if (maxleaf >= 7) {
     645                 :            :         int32_t info7[4];
     646                 :        570 :         jl_cpuidex(info7, 7, 1);
     647                 :        570 :         features[9] = info7[0];
     648                 :            :     }
     649         [ +  - ]:        570 :     if (maxleaf >= 0x14) {
     650                 :            :         int32_t info14[4];
     651                 :        570 :         jl_cpuidex(info14, 0x14, 0);
     652                 :        570 :         features[10] = info14[1];
     653                 :            :     }
     654                 :            : 
     655                 :            :     // Fix up AVX bits to account for OS support and match LLVM model
     656                 :        570 :     uint64_t xcr0 = 0;
     657                 :        570 :     bool hasxsave = test_all_bits(features[0], 1 << 27);
     658         [ +  - ]:        570 :     if (hasxsave) {
     659                 :        570 :         xcr0 = get_xcr0();
     660                 :        570 :         hasxsave = test_all_bits(xcr0, 0x6);
     661                 :            :     }
     662   [ +  -  +  - ]:        570 :     bool hasavx = hasxsave && test_all_bits(features[0], 1 << 28);
     663                 :        570 :     unset_bits(features, 32 + 27);
     664         [ -  + ]:        570 :     if (!hasavx)
     665                 :          0 :         features_disable_avx(features);
     666                 :            : #ifdef _OS_DARWIN_
     667                 :            :     // See https://github.com/llvm/llvm-project/commit/82921bf2baed96b700f90b090d5dc2530223d9c0
     668                 :            :     // and https://github.com/apple/darwin-xnu/blob/a449c6a3b8014d9406c2ddbdc81795da24aa7443/osfmk/i386/fpu.c#L174
     669                 :            :     // Darwin lazily saves the AVX512 context on first use
     670                 :            :     bool hasavx512save = hasavx;
     671                 :            : #else
     672   [ +  -  -  + ]:        570 :     bool hasavx512save = hasavx && test_all_bits(xcr0, 0xe0);
     673                 :            : #endif
     674         [ +  - ]:        570 :     if (!hasavx512save)
     675                 :        570 :         features_disable_avx512(features);
     676                 :            :     // AMX requires additional context to be saved by the OS.
     677   [ +  -  -  + ]:        570 :     bool hasamxsave = hasxsave && test_all_bits(xcr0, (1 << 17) | (1 << 18));
     678         [ +  - ]:        570 :     if (!hasamxsave)
     679                 :        570 :         features_disable_amx(features);
     680                 :            :     // Ignore feature bits that we are not interested in.
     681                 :        570 :     mask_features(feature_masks, &features[0]);
     682                 :            : 
     683                 :            :     uint32_t cpu;
     684         [ +  - ]:        570 :     if (vendor == SIG_INTEL) {
     685                 :        570 :         cpu = uint32_t(get_intel_processor_name(family, model, brand_id, &features[0]));
     686                 :            :     }
     687         [ #  # ]:          0 :     else if (vendor == SIG_AMD) {
     688                 :          0 :         cpu = uint32_t(get_amd_processor_name(family, model, &features[0]));
     689                 :            :     }
     690                 :            :     else {
     691                 :          0 :         cpu = uint32_t(CPU::generic);
     692                 :            :     }
     693                 :            : 
     694                 :        570 :     return std::make_pair(cpu, features);
     695                 :            : }
     696                 :            : 
     697                 :       8000 : static inline const std::pair<uint32_t,FeatureList<feature_sz>> &get_host_cpu()
     698                 :            : {
     699   [ +  +  +  - ]:       8000 :     static auto host_cpu = _get_host_cpu();
     700                 :       8000 :     return host_cpu;
     701                 :            : }
     702                 :            : 
     703                 :          0 : static inline const CPUSpec<CPU,feature_sz> *find_cpu(uint32_t cpu)
     704                 :            : {
     705                 :          0 :     return ::find_cpu(cpu, cpus, ncpu_names);
     706                 :            : }
     707                 :            : 
     708                 :        571 : static inline const CPUSpec<CPU,feature_sz> *find_cpu(llvm::StringRef name)
     709                 :            : {
     710                 :        571 :     return ::find_cpu(name, cpus, ncpu_names);
     711                 :            : }
     712                 :            : 
     713                 :        567 : static inline const char *find_cpu_name(uint32_t cpu)
     714                 :            : {
     715                 :        567 :     return ::find_cpu_name(cpu, cpus, ncpu_names);
     716                 :            : }
     717                 :            : 
     718                 :       1130 : static inline const std::string &host_cpu_name()
     719                 :            : {
     720                 :            :     static std::string name =
     721                 :       1134 :         (CPU)get_host_cpu().first != CPU::generic ?
     722                 :       1134 :         std::string(find_cpu_name(get_host_cpu().first)) :
     723   [ +  +  +  -  :       1130 :         jl_get_cpu_name_llvm();
             +  -  +  - ]
     724                 :       1130 :     return name;
     725                 :            : }
     726                 :            : 
     727                 :       1692 : static inline const char *normalize_cpu_name(llvm::StringRef name)
     728                 :            : {
     729         [ -  + ]:       1692 :     if (name == "atom")
     730                 :          0 :         return "bonnell";
     731         [ -  + ]:       1692 :     if (name == "slm")
     732                 :          0 :         return "silvermont";
     733         [ -  + ]:       1692 :     if (name == "glm")
     734                 :          0 :         return "goldmont";
     735         [ -  + ]:       1692 :     if (name == "corei7")
     736                 :          0 :         return "nehalem";
     737         [ -  + ]:       1692 :     if (name == "corei7-avx")
     738                 :          0 :         return "sandybridge";
     739         [ -  + ]:       1692 :     if (name == "core-avx-i")
     740                 :          0 :         return "ivybridge";
     741         [ -  + ]:       1692 :     if (name == "core-avx2")
     742                 :          0 :         return "haswell";
     743         [ -  + ]:       1692 :     if (name == "skx")
     744                 :          0 :         return "skylake-avx512";
     745                 :            : #ifdef _CPU_X86_
     746                 :            :     // i686 isn't a supported target but it's a common default one so just make it mean pentium4.
     747                 :            :     if (name == "pentium4" || name == "i686")
     748                 :            :         return "generic";
     749                 :            : #else
     750   [ +  -  -  +  :       1692 :     if (name == "x86-64" || name == "x86_64")
                   -  + ]
     751                 :          0 :         return "generic";
     752                 :            : #endif
     753                 :       1692 :     return nullptr;
     754                 :            : }
     755                 :            : 
     756                 :            : template<size_t n>
     757                 :        570 : static inline void enable_depends(FeatureList<n> &features)
     758                 :            : {
     759                 :        570 :     ::enable_depends(features, Feature::deps, sizeof(Feature::deps) / sizeof(FeatureDep));
     760                 :        570 : }
     761                 :            : 
     762                 :            : template<size_t n>
     763                 :        571 : static inline void disable_depends(FeatureList<n> &features)
     764                 :            : {
     765                 :        571 :     ::disable_depends(features, Feature::deps, sizeof(Feature::deps) / sizeof(FeatureDep));
     766                 :        571 : }
     767                 :            : 
     768                 :       1129 : static const std::vector<TargetData<feature_sz>> &get_cmdline_targets(void)
     769                 :            : {
     770                 :          0 :     auto feature_cb = [] (const char *str, size_t len, FeatureList<feature_sz> &list) {
     771                 :          0 :         auto fbit = find_feature_bit(feature_names, nfeature_names, str, len);
     772         [ #  # ]:          0 :         if (fbit == (uint32_t)-1)
     773                 :          0 :             return false;
     774                 :          0 :         set_bit(list, fbit, true);
     775                 :          0 :         return true;
     776                 :            :     };
     777                 :       1129 :     auto &targets = ::get_cmdline_targets<feature_sz>(feature_cb);
     778         [ +  + ]:       2258 :     for (auto &t: targets) {
     779         [ -  + ]:       1129 :         if (auto nname = normalize_cpu_name(t.name)) {
     780                 :          0 :             t.name = nname;
     781                 :            :         }
     782                 :            :     }
     783                 :       1129 :     return targets;
     784                 :            : }
     785                 :            : 
     786                 :            : static std::vector<TargetData<feature_sz>> jit_targets;
     787                 :            : 
     788                 :        570 : static TargetData<feature_sz> arg_target_data(const TargetData<feature_sz> &arg, bool require_host)
     789                 :            : {
     790                 :        570 :     TargetData<feature_sz> res = arg;
     791                 :        570 :     const FeatureList<feature_sz> *cpu_features = nullptr;
     792         [ +  + ]:        570 :     if (res.name == "native") {
     793                 :        567 :         res.name = host_cpu_name();
     794                 :        567 :         cpu_features = &get_host_cpu().second;
     795                 :            :     }
     796         [ -  + ]:          3 :     else if (auto spec = find_cpu(res.name)) {
     797                 :          0 :         cpu_features = &spec->features;
     798                 :            :     }
     799                 :            :     else {
     800                 :          3 :         res.en.flags |= JL_TARGET_UNKNOWN_NAME;
     801                 :            :     }
     802         [ +  + ]:        570 :     if (cpu_features) {
     803         [ +  + ]:       6804 :         for (size_t i = 0; i < feature_sz; i++) {
     804                 :       6237 :             res.en.features[i] |= (*cpu_features)[i];
     805                 :            :         }
     806                 :            :     }
     807                 :        570 :     enable_depends(res.en.features);
     808                 :            :     // Mask our rdrand/rdseed/rtm/xsaveopt features that LLVM doesn't use and rr disables
     809                 :        570 :     unset_bits(res.en.features, Feature::rdrnd, Feature::rdseed, Feature::rtm, Feature::xsaveopt);
     810         [ +  + ]:       6840 :     for (size_t i = 0; i < feature_sz; i++)
     811                 :       6270 :         res.en.features[i] &= ~res.dis.features[i];
     812         [ +  - ]:        570 :     if (require_host) {
     813         [ +  + ]:       6840 :         for (size_t i = 0; i < feature_sz; i++) {
     814                 :       6270 :             res.en.features[i] &= get_host_cpu().second[i];
     815                 :            :         }
     816                 :            :     }
     817                 :        570 :     disable_depends(res.en.features);
     818         [ +  + ]:        570 :     if (cpu_features) {
     819                 :            :         // If the base feature if known, fill in the disable features
     820         [ +  + ]:       6804 :         for (size_t i = 0; i < feature_sz; i++) {
     821                 :       6237 :             res.dis.features[i] = feature_masks[i] & ~res.en.features[i];
     822                 :            :         }
     823                 :            :     }
     824                 :        570 :     return res;
     825                 :            : }
     826                 :            : 
     827                 :       1120 : static int max_vector_size(const FeatureList<feature_sz> &features)
     828                 :            : {
     829         [ -  + ]:       1120 :     if (test_nbit(features, Feature::avx512f))
     830                 :          0 :         return 64;
     831         [ +  - ]:       1120 :     if (test_nbit(features, Feature::avx))
     832                 :       1120 :         return 32;
     833                 :            :     // SSE is required
     834                 :          0 :     return 16;
     835                 :            : }
     836                 :            : 
     837                 :        563 : static uint32_t sysimg_init_cb(const void *id)
     838                 :            : {
     839                 :            :     // First see what target is requested for the JIT.
     840                 :        563 :     auto &cmdline = get_cmdline_targets();
     841                 :       1123 :     TargetData<feature_sz> target = arg_target_data(cmdline[0], true);
     842                 :            :     // Then find the best match in the sysimg
     843                 :        563 :     auto sysimg = deserialize_target_data<feature_sz>((const uint8_t*)id);
     844                 :            :     // We translate `generic` to `pentium4` or `x86-64` before sending it to LLVM
     845                 :            :     // (see `get_llvm_target_noext`) which will be serialized into the sysimg target data.
     846                 :            :     // Translate them back so we can actually match them.
     847                 :            :     // We also track to see if the sysimg allows -cx16, however if the user does
     848                 :            :     // something silly like add +cx16 on a 32bit target, we want to disable this
     849                 :            :     // check, hence the pointer size check.
     850                 :        563 :     bool sysimg_allows_no_cx16 = sizeof(void *) == 4;;
     851         [ +  + ]:       1126 :     for (auto &t: sysimg) {
     852         [ -  + ]:        563 :         if (auto nname = normalize_cpu_name(t.name)) {
     853                 :          0 :             t.name = nname;
     854                 :            :         }
     855                 :            : 
     856                 :            :         // Take note to see if the sysimg explicitly allows an architecture without cx16
     857                 :        563 :         sysimg_allows_no_cx16 |= !test_nbit(t.en.features, Feature::cx16);
     858                 :            :     }
     859   [ +  -  +  +  :        563 :     if (!sysimg_allows_no_cx16 && !test_nbit(target.en.features, Feature::cx16)) {
                   +  + ]
     860                 :          3 :         jl_error("Your CPU does not support the CX16 instruction, which is required "
     861                 :            :                  "by this version of Julia!  This is often due to running inside of a "
     862                 :            :                  "virtualized environment.  Please read "
     863                 :            :                  "https://docs.julialang.org/en/v1/devdocs/sysimg/ for more.");
     864                 :            :     }
     865                 :        560 :     auto match = match_sysimg_targets(sysimg, target, max_vector_size);
     866                 :            :     // Now we've decided on which sysimg version to use.
     867                 :            :     // Make sure the JIT target is compatible with it and save the JIT target.
     868   [ -  +  -  + ]:        560 :     if (match.vreg_size != max_vector_size(target.en.features) &&
     869         [ #  # ]:          0 :         (sysimg[match.best_idx].en.flags & JL_TARGET_VEC_CALL)) {
     870         [ #  # ]:          0 :         if (match.vreg_size < 64) {
     871                 :          0 :             features_disable_avx512(target.en.features);
     872                 :            :         }
     873         [ #  # ]:          0 :         if (match.vreg_size < 32) {
     874                 :          0 :             features_disable_avx(target.en.features);
     875                 :            :         }
     876                 :            :     }
     877                 :        560 :     jit_targets.push_back(std::move(target));
     878                 :        560 :     return match.best_idx;
     879                 :            : }
     880                 :            : 
     881                 :        566 : static void ensure_jit_target(bool imaging)
     882                 :            : {
     883                 :        566 :     auto &cmdline = get_cmdline_targets();
     884                 :        566 :     check_cmdline(cmdline, imaging);
     885         [ +  + ]:        566 :     if (!jit_targets.empty())
     886                 :        559 :         return;
     887         [ +  + ]:         14 :     for (auto &arg: cmdline) {
     888                 :         14 :         auto data = arg_target_data(arg, jit_targets.empty());
     889                 :          7 :         jit_targets.push_back(std::move(data));
     890                 :            :     }
     891                 :          7 :     auto ntargets = jit_targets.size();
     892                 :            :     // Now decide the clone condition.
     893         [ -  + ]:          7 :     for (size_t i = 1; i < ntargets; i++) {
     894                 :          0 :         auto &t = jit_targets[i];
     895         [ #  # ]:          0 :         if (t.en.flags & JL_TARGET_CLONE_ALL)
     896                 :          0 :             continue;
     897                 :            :         // Always clone when code checks CPU features
     898                 :          0 :         t.en.flags |= JL_TARGET_CLONE_CPU;
     899                 :            :         // The most useful one in general...
     900                 :          0 :         t.en.flags |= JL_TARGET_CLONE_LOOP;
     901                 :          0 :         auto &features0 = jit_targets[t.base].en.features;
     902                 :            :         // Special case for KNL/KNM since they're so different
     903         [ #  # ]:          0 :         if (!(t.dis.flags & JL_TARGET_CLONE_ALL)) {
     904   [ #  #  #  # ]:          0 :             if ((t.name == "knl" || t.name == "knm") &&
     905   [ #  #  #  #  :          0 :                 jit_targets[t.base].name != "knl" && jit_targets[t.base].name != "knm") {
                   #  # ]
     906                 :          0 :                 t.en.flags |= JL_TARGET_CLONE_ALL;
     907                 :          0 :                 break;
     908                 :            :             }
     909                 :            :         }
     910                 :            :         static constexpr uint32_t clone_math[] = {Feature::fma, Feature::fma4};
     911                 :            :         static constexpr uint32_t clone_simd[] = {Feature::sse3, Feature::ssse3,
     912                 :            :                                                   Feature::sse41, Feature::sse42,
     913                 :            :                                                   Feature::avx, Feature::avx2,
     914                 :            :                                                   Feature::vaes, Feature::vpclmulqdq,
     915                 :            :                                                   Feature::sse4a, Feature::avx512f,
     916                 :            :                                                   Feature::avx512dq, Feature::avx512ifma,
     917                 :            :                                                   Feature::avx512pf, Feature::avx512er,
     918                 :            :                                                   Feature::avx512cd, Feature::avx512bw,
     919                 :            :                                                   Feature::avx512vl, Feature::avx512vbmi,
     920                 :            :                                                   Feature::avx512vpopcntdq,
     921                 :            :                                                   Feature::avx512vbmi2, Feature::avx512vnni,
     922                 :            :                                                   Feature::avx512bitalg, Feature::avx512bf16,
     923                 :            :                                                   Feature::avx512vp2intersect};
     924         [ #  # ]:          0 :         for (auto fe: clone_math) {
     925   [ #  #  #  #  :          0 :             if (!test_nbit(features0, fe) && test_nbit(t.en.features, fe)) {
                   #  # ]
     926                 :          0 :                 t.en.flags |= JL_TARGET_CLONE_MATH;
     927                 :          0 :                 break;
     928                 :            :             }
     929                 :            :         }
     930         [ #  # ]:          0 :         for (auto fe: clone_simd) {
     931   [ #  #  #  #  :          0 :             if (!test_nbit(features0, fe) && test_nbit(t.en.features, fe)) {
                   #  # ]
     932                 :          0 :                 t.en.flags |= JL_TARGET_CLONE_SIMD;
     933                 :          0 :                 break;
     934                 :            :             }
     935                 :            :         }
     936                 :            :     }
     937                 :            : }
     938                 :            : 
     939                 :            : static std::pair<std::string,std::vector<std::string>>
     940                 :        568 : get_llvm_target_noext(const TargetData<feature_sz> &data)
     941                 :            : {
     942                 :       1136 :     std::string name = data.name;
     943                 :        568 :     auto *spec = find_cpu(name);
     944         [ +  - ]:        568 :     while (spec) {
     945         [ +  - ]:        568 :         if (spec->llvmver <= JL_LLVM_VERSION)
     946                 :        568 :             break;
     947                 :          0 :         spec = find_cpu((uint32_t)spec->fallback);
     948                 :          0 :         name = spec->name;
     949                 :            :     }
     950         [ +  + ]:        568 :     if (name == "generic") {
     951                 :            :         // Use translate `generic` into what we actually require
     952                 :            : #ifdef _CPU_X86_
     953                 :            :         name = "pentium4";
     954                 :            : #else
     955                 :          1 :         name = "x86-64";
     956                 :            : #endif
     957                 :            :     }
     958                 :       1136 :     std::vector<std::string> features;
     959         [ +  + ]:      42032 :     for (auto &fename: feature_names) {
     960         [ -  + ]:      41464 :         if (fename.llvmver > JL_LLVM_VERSION)
     961                 :          0 :             continue;
     962         [ +  + ]:      41464 :         if (test_nbit(data.en.features, fename.bit)) {
     963                 :      13681 :             features.insert(features.begin(), std::string("+") + fename.name);
     964                 :            :         }
     965         [ +  - ]:      27783 :         else if (test_nbit(data.dis.features, fename.bit)) {
     966                 :      27783 :             features.push_back(std::string("-") + fename.name);
     967                 :            :         }
     968                 :            :     }
     969                 :        568 :     features.push_back("+sse2");
     970                 :        568 :     features.push_back("+mmx");
     971                 :        568 :     features.push_back("+fxsr");
     972                 :            : #ifdef _CPU_X86_64_
     973                 :            :     // This is required to make LLVM happy if LLVM's feature based CPU arch guess
     974                 :            :     // returns a value that may not have 64bit support.
     975                 :            :     // This can happen with virtualization.
     976                 :        568 :     features.push_back("+64bit");
     977                 :            : #endif
     978                 :        568 :     features.push_back("+cx8");
     979                 :        568 :     return std::make_pair(std::move(name), std::move(features));
     980                 :            : }
     981                 :            : 
     982                 :            : static std::pair<std::string,std::vector<std::string>>
     983                 :        566 : get_llvm_target_vec(const TargetData<feature_sz> &data)
     984                 :            : {
     985                 :        566 :     auto res0 = get_llvm_target_noext(data);
     986                 :        566 :     append_ext_features(res0.second, data.ext_features);
     987                 :        566 :     return res0;
     988                 :            : }
     989                 :            : 
     990                 :            : static std::pair<std::string,std::string>
     991                 :          2 : get_llvm_target_str(const TargetData<feature_sz> &data)
     992                 :            : {
     993                 :          4 :     auto res0 = get_llvm_target_noext(data);
     994                 :          4 :     auto features = join_feature_strs(res0.second);
     995                 :          2 :     append_ext_features(features, data.ext_features);
     996                 :          2 :     return std::make_pair(std::move(res0.first), std::move(features));
     997                 :            : }
     998                 :            : 
     999                 :            : }
    1000                 :            : 
    1001                 :            : using namespace X86;
    1002                 :            : 
    1003                 :          0 : JL_DLLEXPORT void jl_dump_host_cpu(void)
    1004                 :            : {
    1005                 :          0 :     dump_cpu_spec(get_host_cpu().first, get_host_cpu().second, feature_names, nfeature_names,
    1006                 :            :                   cpus, ncpu_names);
    1007                 :          0 : }
    1008                 :            : 
    1009                 :        563 : JL_DLLEXPORT jl_value_t *jl_get_cpu_name(void)
    1010                 :            : {
    1011                 :        563 :     return jl_cstr_to_string(host_cpu_name().c_str());
    1012                 :            : }
    1013                 :            : 
    1014                 :        563 : jl_sysimg_fptrs_t jl_init_processor_sysimg(void *hdl)
    1015                 :            : {
    1016         [ -  + ]:        563 :     if (!jit_targets.empty())
    1017                 :          0 :         jl_error("JIT targets already initialized");
    1018                 :        563 :     return parse_sysimg(hdl, sysimg_init_cb);
    1019                 :            : }
    1020                 :            : 
    1021                 :        566 : extern "C" JL_DLLEXPORT std::pair<std::string,std::vector<std::string>> jl_get_llvm_target(bool imaging, uint32_t &flags)
    1022                 :            : {
    1023                 :        566 :     ensure_jit_target(imaging);
    1024                 :        566 :     flags = jit_targets[0].en.flags;
    1025                 :        566 :     return get_llvm_target_vec(jit_targets[0]);
    1026                 :            : }
    1027                 :            : 
    1028                 :          3 : extern "C" JL_DLLEXPORT const std::pair<std::string,std::string> &jl_get_llvm_disasm_target(void)
    1029                 :            : {
    1030                 :          2 :     static const auto res = get_llvm_target_str(TargetData<feature_sz>{"generic", "",
    1031   [ +  +  +  - ]:          4 :             {feature_masks, 0}, {{}, 0}, 0});
    1032                 :          3 :     return res;
    1033                 :            : }
    1034                 :            : 
    1035                 :          1 : extern "C" JL_DLLEXPORT std::vector<jl_target_spec_t> jl_get_llvm_clone_targets(void)
    1036                 :            : {
    1037         [ -  + ]:          1 :     if (jit_targets.empty())
    1038                 :          0 :         jl_error("JIT targets not initialized");
    1039                 :          1 :     std::vector<jl_target_spec_t> res;
    1040         [ +  + ]:          2 :     for (auto &target: jit_targets) {
    1041                 :          1 :         auto features_en = target.en.features;
    1042                 :          1 :         auto features_dis = target.dis.features;
    1043         [ +  + ]:         74 :         for (auto &fename: feature_names) {
    1044         [ -  + ]:         73 :             if (fename.llvmver > JL_LLVM_VERSION) {
    1045                 :          0 :                 unset_bits(features_en, fename.bit);
    1046                 :          0 :                 unset_bits(features_dis, fename.bit);
    1047                 :            :             }
    1048                 :            :         }
    1049                 :          1 :         X86::disable_depends(features_en);
    1050                 :          2 :         jl_target_spec_t ele;
    1051                 :          1 :         std::tie(ele.cpu_name, ele.cpu_features) = get_llvm_target_str(target);
    1052                 :          2 :         ele.data = serialize_target_data(target.name, features_en, features_dis,
    1053                 :          2 :                                          target.ext_features);
    1054                 :          1 :         ele.flags = target.en.flags;
    1055                 :          1 :         ele.base = target.base;
    1056                 :          1 :         res.push_back(ele);
    1057                 :            :     }
    1058                 :          1 :     return res;
    1059                 :            : }
    1060                 :            : 
    1061                 :         29 : extern "C" int jl_test_cpu_feature(jl_cpu_feature_t feature)
    1062                 :            : {
    1063         [ -  + ]:         29 :     if (feature >= 32 * feature_sz)
    1064                 :          0 :         return 0;
    1065                 :         29 :     return test_nbit(&get_host_cpu().second[0], feature);
    1066                 :            : }
    1067                 :            : 
    1068                 :            : // -- set/clear the FZ/DAZ flags on x86 & x86-64 --
    1069                 :            : 
    1070                 :            : // Cache of information recovered from `cpuid` since executing `cpuid` it at runtime is slow.
    1071                 :        602 : static uint32_t subnormal_flags = [] {
    1072                 :            :     int32_t info[4];
    1073                 :        602 :     jl_cpuid(info, 0);
    1074         [ +  - ]:        602 :     if (info[0] >= 1) {
    1075                 :        602 :         jl_cpuid(info, 1);
    1076         [ +  - ]:        602 :         if (info[3] & (1 << 26)) {
    1077                 :            :             // SSE2 supports both FZ and DAZ
    1078                 :        602 :             return 0x00008040;
    1079                 :            :         }
    1080         [ #  # ]:          0 :         else if (info[3] & (1 << 25)) {
    1081                 :            :             // SSE supports only the FZ flag
    1082                 :          0 :             return 0x00008000;
    1083                 :            :         }
    1084                 :            :     }
    1085                 :          0 :     return 0;
    1086                 :            : }();
    1087                 :            : 
    1088                 :            : // Returns non-zero if subnormals go to 0; zero otherwise.
    1089                 :          2 : extern "C" JL_DLLEXPORT int32_t jl_get_zero_subnormals(void)
    1090                 :            : {
    1091                 :          2 :     return _mm_getcsr() & subnormal_flags;
    1092                 :            : }
    1093                 :            : 
    1094                 :            : // Return zero on success, non-zero on failure.
    1095                 :        575 : extern "C" JL_DLLEXPORT int32_t jl_set_zero_subnormals(int8_t isZero)
    1096                 :            : {
    1097                 :        575 :     uint32_t flags = subnormal_flags;
    1098         [ +  - ]:        575 :     if (flags) {
    1099                 :        575 :         uint32_t state = _mm_getcsr();
    1100         [ +  + ]:        575 :         if (isZero)
    1101                 :          1 :             state |= flags;
    1102                 :            :         else
    1103                 :        574 :             state &= ~flags;
    1104                 :            :         _mm_setcsr(state);
    1105                 :        575 :         return 0;
    1106                 :            :     }
    1107                 :            :     else {
    1108                 :            :         // Report a failure only if user is trying to enable FTZ/DAZ.
    1109                 :          0 :         return isZero;
    1110                 :            :     }
    1111                 :            : }
    1112                 :            : 
    1113                 :            : // X86 does not support default NaNs
    1114                 :          0 : extern "C" JL_DLLEXPORT int32_t jl_get_default_nans(void)
    1115                 :            : {
    1116                 :          0 :     return 0;
    1117                 :            : }
    1118                 :            : 
    1119                 :        573 : extern "C" JL_DLLEXPORT int32_t jl_set_default_nans(int8_t isDefault)
    1120                 :            : {
    1121                 :        573 :     return isDefault;
    1122                 :            : }

Generated by: LCOV version 1.14