Simon Jakobi pushed to branch wip/sjakobi/T25450-march-native at Glasgow Haskell Compiler / GHC

Commits:

2 changed files:

Changes:

  • compiler/GHC/Driver/CpuFeatures.hs
    ... ... @@ -32,7 +32,10 @@ data X86CpuFeature
    32 32
     
    
    33 33
     -- | Decode the bitmask returned by 'ghc_detect_x86_cpu_features'.
    
    34 34
     --
    
    35
    --- NOTE: Bit positions must match the enum in @compiler/cbits/cpu_features_x86.c@.
    
    35
    +-- NOTE: Bit positions are LLVM\/GCC's @__builtin_cpu_supports@ feature
    
    36
    +-- numbering, i.e. @enum ProcessorFeatures@ vendored in
    
    37
    +-- @compiler/cbits/cpu_features_x86.c@. The C side returns the first 64
    
    38
    +-- feature bits of that numbering.
    
    36 39
     decodeX86CpuFeatureMask :: Word64 -> [X86CpuFeature]
    
    37 40
     decodeX86CpuFeatureMask mask =
    
    38 41
       [ feat
    
    ... ... @@ -61,24 +64,27 @@ cachedX86CpuFeatures :: [X86CpuFeature]
    61 64
     cachedX86CpuFeatures = unsafePerformIO detectX86CpuFeatures
    
    62 65
     {-# NOINLINE cachedX86CpuFeatures #-}
    
    63 66
     
    
    67
    +-- | See the NOTE on 'decodeX86CpuFeatureMask' for where these bit positions
    
    68
    +-- come from. The constant names on the C side are upstream's: @FEATURE_SSE2@,
    
    69
    +-- @FEATURE_BMI@ (= 'BMI1'), etc.
    
    64 70
     cpuFeatureBitLayout :: [(Int, X86CpuFeature)]
    
    65 71
     cpuFeatureBitLayout =
    
    66
    -  [ (0,  SSE2)
    
    67
    -  , (1,  SSE3)
    
    68
    -  , (2,  SSSE3)
    
    69
    -  , (3,  SSE4_1)
    
    70
    -  , (4,  SSE4_2)
    
    71
    -  , (5,  AVX)
    
    72
    -  , (6,  AVX2)
    
    73
    -  , (7,  AVX512F)
    
    74
    -  , (8,  AVX512BW)
    
    75
    -  , (9,  AVX512CD)
    
    76
    -  , (10, AVX512DQ)
    
    77
    -  , (11, AVX512VL)
    
    78
    -  , (12, BMI1)
    
    79
    -  , (13, BMI2)
    
    80
    -  , (14, FMA)
    
    81
    -  , (15, GFNI)
    
    72
    +  [ (4,  SSE2)     -- FEATURE_SSE2
    
    73
    +  , (5,  SSE3)     -- FEATURE_SSE3
    
    74
    +  , (6,  SSSE3)    -- FEATURE_SSSE3
    
    75
    +  , (7,  SSE4_1)   -- FEATURE_SSE4_1
    
    76
    +  , (8,  SSE4_2)   -- FEATURE_SSE4_2
    
    77
    +  , (9,  AVX)      -- FEATURE_AVX
    
    78
    +  , (10, AVX2)     -- FEATURE_AVX2
    
    79
    +  , (14, FMA)      -- FEATURE_FMA
    
    80
    +  , (15, AVX512F)  -- FEATURE_AVX512F
    
    81
    +  , (16, BMI1)     -- FEATURE_BMI
    
    82
    +  , (17, BMI2)     -- FEATURE_BMI2
    
    83
    +  , (20, AVX512VL) -- FEATURE_AVX512VL
    
    84
    +  , (21, AVX512BW) -- FEATURE_AVX512BW
    
    85
    +  , (22, AVX512DQ) -- FEATURE_AVX512DQ
    
    86
    +  , (23, AVX512CD) -- FEATURE_AVX512CD
    
    87
    +  , (32, GFNI)     -- FEATURE_GFNI
    
    82 88
       ]
    
    83 89
     
    
    84 90
     #if !defined(javascript_HOST_ARCH)
    

  • compiler/cbits/cpu_features_x86.c
    1
    +/* Host x86 CPU feature detection, used to implement -march=native.
    
    2
    + *
    
    3
    + * The detection code is vendored from LLVM's compiler-rt, where it implements
    
    4
    + * the runtime support for __builtin_cpu_supports/__builtin_cpu_is
    
    5
    + * (__cpu_model, __cpu_indicator_init):
    
    6
    + *
    
    7
    + *   compiler-rt/lib/builtins/cpu_model/x86.c
    
    8
    + *   at tag llvmorg-20.1.0 (LLVM 20.1.0)
    
    9
    + *   https://github.com/llvm/llvm-project/blob/llvmorg-20.1.0/compiler-rt/lib/builtins/cpu_model/x86.c
    
    10
    + *
    
    11
    + * LLVM is licensed under Apache-2.0 WITH LLVM-exception. Upstream notes that
    
    12
    + * this file is itself a copy of llvm/lib/TargetParser/Host.cpp -- the code
    
    13
    + * behind clang's -march=native -- and that the two are kept in sync.
    
    14
    + *
    
    15
    + * Vendored verbatim: enum ProcessorFeatures, getX86CpuIDAndInfo,
    
    16
    + * getX86CpuIDAndInfoEx, getX86XCR0 and getAvailableFeatures, the latter with
    
    17
    + * a single marked GHC deviation that additionally gates FEATURE_FMA on OS
    
    18
    + * support for saving the AVX register state.
    
    19
    + *
    
    20
    + * Adaptations around the vendored code:
    
    21
    + *
    
    22
    + *   - ghc_detect_x86_cpu_features stands in for __cpu_indicator_init as the
    
    23
    + *     driver: it performs the same CPUID call sequence, but returns the first
    
    24
    + *     64 feature bits as a mask -- which covers every feature GHC decodes,
    
    25
    + *     see GHC.Driver.CpuFeatures -- instead of filling in the __cpu_model
    
    26
    + *     globals.
    
    27
    + *   - On non-x86 hosts the driver compiles to a stub returning 0 instead of
    
    28
    + *     upstream's "#error This file is intended only for x86-based targets".
    
    29
    + */
    
    30
    +
    
    1 31
     #include <HsFFI.h>
    
    2
    -#include <stdint.h>
    
    32
    +#include <stdbool.h>
    
    3 33
     
    
    4
    -#if defined(_MSC_VER) && (defined(_M_IX86) || defined(_M_X64))
    
    5
    -#include <immintrin.h>
    
    6
    -#include <intrin.h>
    
    34
    +#if defined(__i386__) || defined(_M_IX86) || defined(__x86_64__) || \
    
    35
    +    defined(_M_X64)
    
    36
    +#define GHC_HOST_IS_X86 1
    
    7 37
     #endif
    
    8 38
     
    
    9
    -#if !defined(_MSC_VER) && (defined(__i386__) || defined(__x86_64__))
    
    39
    +#if defined(GHC_HOST_IS_X86)
    
    40
    +
    
    41
    +#if (defined(__GNUC__) || defined(__clang__)) && !defined(_MSC_VER)
    
    10 42
     #include <cpuid.h>
    
    11 43
     #endif
    
    12 44
     
    
    13
    -#if defined(__APPLE__) && (defined(__i386__) || defined(__x86_64__))
    
    14
    -#include <sys/sysctl.h>
    
    45
    +#ifdef _MSC_VER
    
    46
    +#include <intrin.h>
    
    15 47
     #endif
    
    16 48
     
    
    17
    -enum {
    
    18
    -  GHC_X86_FEAT_SSE2 = 0,
    
    19
    -  GHC_X86_FEAT_SSE3,
    
    20
    -  GHC_X86_FEAT_SSSE3,
    
    21
    -  GHC_X86_FEAT_SSE4_1,
    
    22
    -  GHC_X86_FEAT_SSE4_2,
    
    23
    -  GHC_X86_FEAT_AVX,
    
    24
    -  GHC_X86_FEAT_AVX2,
    
    25
    -  GHC_X86_FEAT_AVX512F,
    
    26
    -  GHC_X86_FEAT_AVX512BW,
    
    27
    -  GHC_X86_FEAT_AVX512CD,
    
    28
    -  GHC_X86_FEAT_AVX512DQ,
    
    29
    -  GHC_X86_FEAT_AVX512VL,
    
    30
    -  GHC_X86_FEAT_BMI1,
    
    31
    -  GHC_X86_FEAT_BMI2,
    
    32
    -  GHC_X86_FEAT_FMA,
    
    33
    -  GHC_X86_FEAT_GFNI
    
    49
    +/* NOTE: The feature bit positions below are LLVM/GCC's stable
    
    50
    + * __builtin_cpu_supports feature numbering. cpuFeatureBitLayout in
    
    51
    + * GHC.Driver.CpuFeatures must use the same values. */
    
    52
    +enum ProcessorFeatures {
    
    53
    +  FEATURE_CMOV = 0,
    
    54
    +  FEATURE_MMX,
    
    55
    +  FEATURE_POPCNT,
    
    56
    +  FEATURE_SSE,
    
    57
    +  FEATURE_SSE2,
    
    58
    +  FEATURE_SSE3,
    
    59
    +  FEATURE_SSSE3,
    
    60
    +  FEATURE_SSE4_1,
    
    61
    +  FEATURE_SSE4_2,
    
    62
    +  FEATURE_AVX,
    
    63
    +  FEATURE_AVX2,
    
    64
    +  FEATURE_SSE4_A,
    
    65
    +  FEATURE_FMA4,
    
    66
    +  FEATURE_XOP,
    
    67
    +  FEATURE_FMA,
    
    68
    +  FEATURE_AVX512F,
    
    69
    +  FEATURE_BMI,
    
    70
    +  FEATURE_BMI2,
    
    71
    +  FEATURE_AES,
    
    72
    +  FEATURE_PCLMUL,
    
    73
    +  FEATURE_AVX512VL,
    
    74
    +  FEATURE_AVX512BW,
    
    75
    +  FEATURE_AVX512DQ,
    
    76
    +  FEATURE_AVX512CD,
    
    77
    +  FEATURE_AVX512ER,
    
    78
    +  FEATURE_AVX512PF,
    
    79
    +  FEATURE_AVX512VBMI,
    
    80
    +  FEATURE_AVX512IFMA,
    
    81
    +  FEATURE_AVX5124VNNIW,
    
    82
    +  FEATURE_AVX5124FMAPS,
    
    83
    +  FEATURE_AVX512VPOPCNTDQ,
    
    84
    +  FEATURE_AVX512VBMI2,
    
    85
    +  FEATURE_GFNI,
    
    86
    +  FEATURE_VPCLMULQDQ,
    
    87
    +  FEATURE_AVX512VNNI,
    
    88
    +  FEATURE_AVX512BITALG,
    
    89
    +  FEATURE_AVX512BF16,
    
    90
    +  FEATURE_AVX512VP2INTERSECT,
    
    91
    +  // FIXME: Below Features has some missings comparing to gcc, it's because gcc
    
    92
    +  // has some not one-to-one mapped in llvm.
    
    93
    +  // FEATURE_3DNOW,
    
    94
    +  // FEATURE_3DNOWP,
    
    95
    +  FEATURE_ADX = 40,
    
    96
    +  // FEATURE_ABM,
    
    97
    +  FEATURE_CLDEMOTE = 42,
    
    98
    +  FEATURE_CLFLUSHOPT,
    
    99
    +  FEATURE_CLWB,
    
    100
    +  FEATURE_CLZERO,
    
    101
    +  FEATURE_CMPXCHG16B,
    
    102
    +  // FIXME: Not adding FEATURE_CMPXCHG8B is a workaround to make 'generic' as
    
    103
    +  // a cpu string with no X86_FEATURE_COMPAT features, which is required in
    
    104
    +  // current implementantion of cpu_specific/cpu_dispatch FMV feature.
    
    105
    +  // FEATURE_CMPXCHG8B,
    
    106
    +  FEATURE_ENQCMD = 48,
    
    107
    +  FEATURE_F16C,
    
    108
    +  FEATURE_FSGSBASE,
    
    109
    +  // FEATURE_FXSAVE,
    
    110
    +  // FEATURE_HLE,
    
    111
    +  // FEATURE_IBT,
    
    112
    +  FEATURE_LAHF_LM = 54,
    
    113
    +  FEATURE_LM,
    
    114
    +  FEATURE_LWP,
    
    115
    +  FEATURE_LZCNT,
    
    116
    +  FEATURE_MOVBE,
    
    117
    +  FEATURE_MOVDIR64B,
    
    118
    +  FEATURE_MOVDIRI,
    
    119
    +  FEATURE_MWAITX,
    
    120
    +  // FEATURE_OSXSAVE,
    
    121
    +  FEATURE_PCONFIG = 63,
    
    122
    +  FEATURE_PKU,
    
    123
    +  FEATURE_PREFETCHWT1,
    
    124
    +  FEATURE_PRFCHW,
    
    125
    +  FEATURE_PTWRITE,
    
    126
    +  FEATURE_RDPID,
    
    127
    +  FEATURE_RDRND,
    
    128
    +  FEATURE_RDSEED,
    
    129
    +  FEATURE_RTM,
    
    130
    +  FEATURE_SERIALIZE,
    
    131
    +  FEATURE_SGX,
    
    132
    +  FEATURE_SHA,
    
    133
    +  FEATURE_SHSTK,
    
    134
    +  FEATURE_TBM,
    
    135
    +  FEATURE_TSXLDTRK,
    
    136
    +  FEATURE_VAES,
    
    137
    +  FEATURE_WAITPKG,
    
    138
    +  FEATURE_WBNOINVD,
    
    139
    +  FEATURE_XSAVE,
    
    140
    +  FEATURE_XSAVEC,
    
    141
    +  FEATURE_XSAVEOPT,
    
    142
    +  FEATURE_XSAVES,
    
    143
    +  FEATURE_AMX_TILE,
    
    144
    +  FEATURE_AMX_INT8,
    
    145
    +  FEATURE_AMX_BF16,
    
    146
    +  FEATURE_UINTR,
    
    147
    +  FEATURE_HRESET,
    
    148
    +  FEATURE_KL,
    
    149
    +  // FEATURE_AESKLE,
    
    150
    +  FEATURE_WIDEKL = 92,
    
    151
    +  FEATURE_AVXVNNI,
    
    152
    +  FEATURE_AVX512FP16,
    
    153
    +  FEATURE_X86_64_BASELINE,
    
    154
    +  FEATURE_X86_64_V2,
    
    155
    +  FEATURE_X86_64_V3,
    
    156
    +  FEATURE_X86_64_V4,
    
    157
    +  FEATURE_AVXIFMA,
    
    158
    +  FEATURE_AVXVNNIINT8,
    
    159
    +  FEATURE_AVXNECONVERT,
    
    160
    +  FEATURE_CMPCCXADD,
    
    161
    +  FEATURE_AMX_FP16,
    
    162
    +  FEATURE_PREFETCHI,
    
    163
    +  FEATURE_RAOINT,
    
    164
    +  FEATURE_AMX_COMPLEX,
    
    165
    +  FEATURE_AVXVNNIINT16,
    
    166
    +  FEATURE_SM3,
    
    167
    +  FEATURE_SHA512,
    
    168
    +  FEATURE_SM4,
    
    169
    +  FEATURE_APXF,
    
    170
    +  FEATURE_USERMSR,
    
    171
    +  FEATURE_AVX10_1_256,
    
    172
    +  FEATURE_AVX10_1_512,
    
    173
    +  FEATURE_AVX10_2_256,
    
    174
    +  FEATURE_AVX10_2_512,
    
    175
    +  FEATURE_MOVRS,
    
    176
    +  CPU_FEATURE_MAX
    
    34 177
     };
    
    35 178
     
    
    36
    -#define SET_FEAT(mask, bit) ((mask) |= ((HsWord64)1ULL << (bit)))
    
    179
    +// This code is copied from lib/Support/Host.cpp.
    
    180
    +// Changes to either file should be mirrored in the other.
    
    37 181
     
    
    38
    -static int ghc_cpuid_count(uint32_t leaf, uint32_t subleaf,
    
    39
    -                           uint32_t *a, uint32_t *b, uint32_t *c, uint32_t *d)
    
    40
    -{
    
    41
    -#if defined(_MSC_VER) && (defined(_M_IX86) || defined(_M_X64))
    
    42
    -  int regs[4];
    
    43
    -  __cpuidex(regs, (int)leaf, (int)subleaf);
    
    44
    -  *a = (uint32_t)regs[0];
    
    45
    -  *b = (uint32_t)regs[1];
    
    46
    -  *c = (uint32_t)regs[2];
    
    47
    -  *d = (uint32_t)regs[3];
    
    48
    -  return 1;
    
    49
    -#elif defined(__i386__) || defined(__x86_64__)
    
    50
    -  return __get_cpuid_count(leaf, subleaf, a, b, c, d);
    
    182
    +/// getX86CpuIDAndInfo - Execute the specified cpuid and return the 4 values in
    
    183
    +/// the specified arguments.  If we can't run cpuid on the host, return true.
    
    184
    +static bool getX86CpuIDAndInfo(unsigned value, unsigned *rEAX, unsigned *rEBX,
    
    185
    +                               unsigned *rECX, unsigned *rEDX) {
    
    186
    +#if (defined(__GNUC__) || defined(__clang__)) && !defined(_MSC_VER)
    
    187
    +  return !__get_cpuid(value, rEAX, rEBX, rECX, rEDX);
    
    188
    +#elif defined(_MSC_VER)
    
    189
    +  // The MSVC intrinsic is portable across x86 and x64.
    
    190
    +  int registers[4];
    
    191
    +  __cpuid(registers, value);
    
    192
    +  *rEAX = registers[0];
    
    193
    +  *rEBX = registers[1];
    
    194
    +  *rECX = registers[2];
    
    195
    +  *rEDX = registers[3];
    
    196
    +  return false;
    
    51 197
     #else
    
    52
    -  (void)leaf;
    
    53
    -  (void)subleaf;
    
    54
    -  (void)a;
    
    55
    -  (void)b;
    
    56
    -  (void)c;
    
    57
    -  (void)d;
    
    58
    -  return 0;
    
    198
    +  return true;
    
    59 199
     #endif
    
    60 200
     }
    
    61 201
     
    
    62
    -static uint64_t ghc_xgetbv0(void)
    
    63
    -{
    
    64
    -#if defined(_MSC_VER) && (defined(_M_IX86) || defined(_M_X64))
    
    65
    -  return (uint64_t)_xgetbv(0);
    
    66
    -#elif defined(__i386__) || defined(__x86_64__)
    
    67
    -  uint32_t eax, edx;
    
    68
    -  __asm__ volatile(".byte 0x0f, 0x01, 0xd0" /* xgetbv */
    
    69
    -                   : "=a"(eax), "=d"(edx)
    
    70
    -                   : "c"(0));
    
    71
    -  return ((uint64_t)edx << 32) | (uint64_t)eax;
    
    202
    +/// getX86CpuIDAndInfoEx - Execute the specified cpuid with subleaf and return
    
    203
    +/// the 4 values in the specified arguments.  If we can't run cpuid on the host,
    
    204
    +/// return true.
    
    205
    +static bool getX86CpuIDAndInfoEx(unsigned value, unsigned subleaf,
    
    206
    +                                 unsigned *rEAX, unsigned *rEBX, unsigned *rECX,
    
    207
    +                                 unsigned *rEDX) {
    
    208
    +  // TODO(boomanaiden154): When the minimum toolchain versions for gcc and clang
    
    209
    +  // are such that __cpuidex is defined within cpuid.h for both, we can remove
    
    210
    +  // the __get_cpuid_count function and share the MSVC implementation between
    
    211
    +  // all three.
    
    212
    +#if (defined(__GNUC__) || defined(__clang__)) && !defined(_MSC_VER)
    
    213
    +  return !__get_cpuid_count(value, subleaf, rEAX, rEBX, rECX, rEDX);
    
    214
    +#elif defined(_MSC_VER)
    
    215
    +  int registers[4];
    
    216
    +  __cpuidex(registers, value, subleaf);
    
    217
    +  *rEAX = registers[0];
    
    218
    +  *rEBX = registers[1];
    
    219
    +  *rECX = registers[2];
    
    220
    +  *rEDX = registers[3];
    
    221
    +  return false;
    
    72 222
     #else
    
    73
    -  return 0;
    
    223
    +  return true;
    
    74 224
     #endif
    
    75 225
     }
    
    76 226
     
    
    77
    -#if defined(__APPLE__) && (defined(__i386__) || defined(__x86_64__))
    
    78
    -/* Query a macOS CPU-capability sysctl, e.g. "hw.optional.avx512f". */
    
    79
    -static int ghc_macos_sysctl_flag(const char *name)
    
    80
    -{
    
    81
    -  int result = 0;
    
    82
    -  size_t len = sizeof(result);
    
    83
    -  if (sysctlbyname(name, &result, &len, NULL, 0) != 0) {
    
    84
    -    return 0;
    
    85
    -  }
    
    86
    -  return result != 0;
    
    87
    -}
    
    227
    +// Read control register 0 (XCR0). Used to detect features such as AVX.
    
    228
    +static bool getX86XCR0(unsigned *rEAX, unsigned *rEDX) {
    
    229
    +  // TODO(boomanaiden154): When the minimum toolchain versions for gcc and clang
    
    230
    +  // are such that _xgetbv is supported by both, we can unify the implementation
    
    231
    +  // with MSVC and remove all inline assembly.
    
    232
    +#if defined(__GNUC__) || defined(__clang__)
    
    233
    +  // Check xgetbv; this uses a .byte sequence instead of the instruction
    
    234
    +  // directly because older assemblers do not include support for xgetbv and
    
    235
    +  // there is no easy way to conditionally compile based on the assembler used.
    
    236
    +  __asm__(".byte 0x0f, 0x01, 0xd0" : "=a"(*rEAX), "=d"(*rEDX) : "c"(0));
    
    237
    +  return false;
    
    238
    +#elif defined(_MSC_FULL_VER) && defined(_XCR_XFEATURE_ENABLED_MASK)
    
    239
    +  unsigned long long Result = _xgetbv(_XCR_XFEATURE_ENABLED_MASK);
    
    240
    +  *rEAX = Result;
    
    241
    +  *rEDX = Result >> 32;
    
    242
    +  return false;
    
    243
    +#else
    
    244
    +  return true;
    
    88 245
     #endif
    
    246
    +}
    
    89 247
     
    
    90
    -HsWord64 ghc_detect_x86_cpu_features(void)
    
    91
    -{
    
    92
    -  HsWord64 feats = 0;
    
    248
    +static void getAvailableFeatures(unsigned ECX, unsigned EDX, unsigned MaxLeaf,
    
    249
    +                                 unsigned *Features) {
    
    250
    +  unsigned EAX = 0, EBX = 0;
    
    93 251
     
    
    94
    -#if defined(_M_IX86) || defined(_M_X64) || defined(__i386__) || defined(__x86_64__)
    
    95
    -  uint32_t a, b, c, d;
    
    96
    -  uint32_t max_basic = 0;
    
    252
    +#define hasFeature(F) ((Features[F / 32] >> (F % 32)) & 1)
    
    253
    +#define setFeature(F) Features[F / 32] |= 1U << (F % 32)
    
    97 254
     
    
    98
    -  if (!ghc_cpuid_count(0, 0, &a, &b, &c, &d)) {
    
    99
    -    return 0;
    
    100
    -  }
    
    101
    -  max_basic = a;
    
    102
    -  if (max_basic < 1) {
    
    103
    -    return 0;
    
    104
    -  }
    
    255
    +  if ((EDX >> 15) & 1)
    
    256
    +    setFeature(FEATURE_CMOV);
    
    257
    +  if ((EDX >> 23) & 1)
    
    258
    +    setFeature(FEATURE_MMX);
    
    259
    +  if ((EDX >> 25) & 1)
    
    260
    +    setFeature(FEATURE_SSE);
    
    261
    +  if ((EDX >> 26) & 1)
    
    262
    +    setFeature(FEATURE_SSE2);
    
    105 263
     
    
    106
    -  ghc_cpuid_count(1, 0, &a, &b, &c, &d);
    
    107
    -
    
    108
    -  {
    
    109
    -    int has_sse2    = !!(d & (1u << 26));
    
    110
    -    int has_sse3    = !!(c & (1u << 0));
    
    111
    -    int has_ssse3   = !!(c & (1u << 9));
    
    112
    -    int has_sse4_1  = !!(c & (1u << 19));
    
    113
    -    int has_sse4_2  = !!(c & (1u << 20));
    
    114
    -    int has_fma_hw  = !!(c & (1u << 12));
    
    115
    -    int has_avx_hw  = !!(c & (1u << 28));
    
    116
    -    int has_osxsave = !!(c & (1u << 27));
    
    117
    -
    
    118
    -    int avx_usable = 0;
    
    119
    -    int avx512_usable = 0;
    
    120
    -
    
    121
    -    if (has_osxsave) {
    
    122
    -      uint64_t xcr0 = ghc_xgetbv0();
    
    123
    -      avx_usable = ((xcr0 & 0x6u) == 0x6u);      /* XMM + YMM state */
    
    124
    -      avx512_usable = ((xcr0 & 0xE6u) == 0xE6u); /* XMM+YMM+opmask+ZMM */
    
    125
    -    }
    
    264
    +  if ((ECX >> 0) & 1)
    
    265
    +    setFeature(FEATURE_SSE3);
    
    266
    +  if ((ECX >> 1) & 1)
    
    267
    +    setFeature(FEATURE_PCLMUL);
    
    268
    +  if ((ECX >> 9) & 1)
    
    269
    +    setFeature(FEATURE_SSSE3);
    
    270
    +  if ((ECX >> 12) & 1)
    
    271
    +    setFeature(FEATURE_FMA);
    
    272
    +  if ((ECX >> 13) & 1)
    
    273
    +    setFeature(FEATURE_CMPXCHG16B);
    
    274
    +  if ((ECX >> 19) & 1)
    
    275
    +    setFeature(FEATURE_SSE4_1);
    
    276
    +  if ((ECX >> 20) & 1)
    
    277
    +    setFeature(FEATURE_SSE4_2);
    
    278
    +  if ((ECX >> 22) & 1)
    
    279
    +    setFeature(FEATURE_MOVBE);
    
    280
    +  if ((ECX >> 23) & 1)
    
    281
    +    setFeature(FEATURE_POPCNT);
    
    282
    +  if ((ECX >> 25) & 1)
    
    283
    +    setFeature(FEATURE_AES);
    
    284
    +  if ((ECX >> 29) & 1)
    
    285
    +    setFeature(FEATURE_F16C);
    
    286
    +  if ((ECX >> 30) & 1)
    
    287
    +    setFeature(FEATURE_RDRND);
    
    126 288
     
    
    289
    +  // If CPUID indicates support for XSAVE, XRESTORE and AVX, and XGETBV
    
    290
    +  // indicates that the AVX registers will be saved and restored on context
    
    291
    +  // switch, then we have full AVX support.
    
    292
    +  const unsigned AVXBits = (1 << 27) | (1 << 28);
    
    293
    +  bool HasAVXSave = ((ECX & AVXBits) == AVXBits) && !getX86XCR0(&EAX, &EDX) &&
    
    294
    +                    ((EAX & 0x6) == 0x6);
    
    127 295
     #if defined(__APPLE__)
    
    128
    -    /* On x86_64 macOS the kernel enables AVX-512 XSAVE state lazily: XCR0
    
    129
    -       reads back with the opmask/ZMM bits clear until a process first faults
    
    130
    -       on an AVX-512 instruction, so the XCR0 check above is a false negative
    
    131
    -       on AVX-512-capable Macs. Use the OS feature query instead. Checking
    
    132
    -       AVX512F alone suffices here; the AVX-512 sub-features (BW/CD/DQ/VL) are
    
    133
    -       still decoded from CPUID leaf 7 below.
    
    134
    -
    
    135
    -       Refs:
    
    136
    -         https://zenn.dev/mod_poppo/articles/detect-processor-features-x86?locale=en#notes-on-detecting-avx-512-on-macos
    
    137
    -         https://github.com/minoki/haskell-cpu-features */
    
    138
    -    avx512_usable = ghc_macos_sysctl_flag("hw.optional.avx512f");
    
    296
    +  // Darwin lazily saves the AVX512 context on first use: trust that the OS will
    
    297
    +  // save the AVX512 context if we use AVX512 instructions, even the bit is not
    
    298
    +  // set right now.
    
    299
    +  bool HasAVX512Save = true;
    
    300
    +#else
    
    301
    +  // AVX512 requires additional context to be saved by the OS.
    
    302
    +  bool HasAVX512Save = HasAVXSave && ((EAX & 0xe0) == 0xe0);
    
    139 303
     #endif
    
    304
    +  // AMX requires additional context to be saved by the OS.
    
    305
    +  const unsigned AMXBits = (1 << 17) | (1 << 18);
    
    306
    +  bool HasXSave = ((ECX >> 27) & 1) && !getX86XCR0(&EAX, &EDX);
    
    307
    +  bool HasAMXSave = HasXSave && ((EAX & AMXBits) == AMXBits);
    
    140 308
     
    
    141
    -    if (has_sse2) {
    
    142
    -      SET_FEAT(feats, GHC_X86_FEAT_SSE2);
    
    143
    -    }
    
    144
    -    if (has_sse3) {
    
    145
    -      SET_FEAT(feats, GHC_X86_FEAT_SSE3);
    
    146
    -    }
    
    147
    -    if (has_ssse3) {
    
    148
    -      SET_FEAT(feats, GHC_X86_FEAT_SSSE3);
    
    149
    -    }
    
    150
    -    if (has_sse4_1) {
    
    151
    -      SET_FEAT(feats, GHC_X86_FEAT_SSE4_1);
    
    152
    -    }
    
    153
    -    if (has_sse4_2) {
    
    154
    -      SET_FEAT(feats, GHC_X86_FEAT_SSE4_2);
    
    155
    -    }
    
    156
    -    if (has_avx_hw && avx_usable) {
    
    157
    -      SET_FEAT(feats, GHC_X86_FEAT_AVX);
    
    309
    +  // GHC deviation from upstream: FMA instructions are VEX-encoded and
    
    310
    +  // unusable unless the OS saves the AVX register state, so FEATURE_FMA (set
    
    311
    +  // from the raw CPUID bit above) is cleared again when full AVX support is
    
    312
    +  // missing. This matches llvm/lib/TargetParser/Host.cpp ("fma") and GCC's
    
    313
    +  // gcc/common/config/i386/cpuinfo.h (FEATURE_FMA under avx_usable).
    
    314
    +  if (!HasAVXSave)
    
    315
    +    Features[FEATURE_FMA / 32] &= ~(1U << (FEATURE_FMA % 32));
    
    316
    +
    
    317
    +  if (HasAVXSave)
    
    318
    +    setFeature(FEATURE_AVX);
    
    319
    +
    
    320
    +  if (((ECX >> 26) & 1) && HasAVXSave)
    
    321
    +    setFeature(FEATURE_XSAVE);
    
    322
    +
    
    323
    +  bool HasLeaf7 =
    
    324
    +      MaxLeaf >= 0x7 && !getX86CpuIDAndInfoEx(0x7, 0x0, &EAX, &EBX, &ECX, &EDX);
    
    325
    +
    
    326
    +  if (HasLeaf7 && ((EBX >> 0) & 1))
    
    327
    +    setFeature(FEATURE_FSGSBASE);
    
    328
    +  if (HasLeaf7 && ((EBX >> 2) & 1))
    
    329
    +    setFeature(FEATURE_SGX);
    
    330
    +  if (HasLeaf7 && ((EBX >> 3) & 1))
    
    331
    +    setFeature(FEATURE_BMI);
    
    332
    +  if (HasLeaf7 && ((EBX >> 5) & 1) && HasAVXSave)
    
    333
    +    setFeature(FEATURE_AVX2);
    
    334
    +  if (HasLeaf7 && ((EBX >> 8) & 1))
    
    335
    +    setFeature(FEATURE_BMI2);
    
    336
    +  if (HasLeaf7 && ((EBX >> 11) & 1))
    
    337
    +    setFeature(FEATURE_RTM);
    
    338
    +  if (HasLeaf7 && ((EBX >> 16) & 1) && HasAVX512Save)
    
    339
    +    setFeature(FEATURE_AVX512F);
    
    340
    +  if (HasLeaf7 && ((EBX >> 17) & 1) && HasAVX512Save)
    
    341
    +    setFeature(FEATURE_AVX512DQ);
    
    342
    +  if (HasLeaf7 && ((EBX >> 18) & 1))
    
    343
    +    setFeature(FEATURE_RDSEED);
    
    344
    +  if (HasLeaf7 && ((EBX >> 19) & 1))
    
    345
    +    setFeature(FEATURE_ADX);
    
    346
    +  if (HasLeaf7 && ((EBX >> 21) & 1) && HasAVX512Save)
    
    347
    +    setFeature(FEATURE_AVX512IFMA);
    
    348
    +  if (HasLeaf7 && ((EBX >> 24) & 1))
    
    349
    +    setFeature(FEATURE_CLWB);
    
    350
    +  if (HasLeaf7 && ((EBX >> 26) & 1) && HasAVX512Save)
    
    351
    +    setFeature(FEATURE_AVX512PF);
    
    352
    +  if (HasLeaf7 && ((EBX >> 27) & 1) && HasAVX512Save)
    
    353
    +    setFeature(FEATURE_AVX512ER);
    
    354
    +  if (HasLeaf7 && ((EBX >> 28) & 1) && HasAVX512Save)
    
    355
    +    setFeature(FEATURE_AVX512CD);
    
    356
    +  if (HasLeaf7 && ((EBX >> 29) & 1))
    
    357
    +    setFeature(FEATURE_SHA);
    
    358
    +  if (HasLeaf7 && ((EBX >> 30) & 1) && HasAVX512Save)
    
    359
    +    setFeature(FEATURE_AVX512BW);
    
    360
    +  if (HasLeaf7 && ((EBX >> 31) & 1) && HasAVX512Save)
    
    361
    +    setFeature(FEATURE_AVX512VL);
    
    362
    +
    
    363
    +  if (HasLeaf7 && ((ECX >> 0) & 1))
    
    364
    +    setFeature(FEATURE_PREFETCHWT1);
    
    365
    +  if (HasLeaf7 && ((ECX >> 1) & 1) && HasAVX512Save)
    
    366
    +    setFeature(FEATURE_AVX512VBMI);
    
    367
    +  if (HasLeaf7 && ((ECX >> 4) & 1))
    
    368
    +    setFeature(FEATURE_PKU);
    
    369
    +  if (HasLeaf7 && ((ECX >> 5) & 1))
    
    370
    +    setFeature(FEATURE_WAITPKG);
    
    371
    +  if (HasLeaf7 && ((ECX >> 6) & 1) && HasAVX512Save)
    
    372
    +    setFeature(FEATURE_AVX512VBMI2);
    
    373
    +  if (HasLeaf7 && ((ECX >> 7) & 1))
    
    374
    +    setFeature(FEATURE_SHSTK);
    
    375
    +  if (HasLeaf7 && ((ECX >> 8) & 1))
    
    376
    +    setFeature(FEATURE_GFNI);
    
    377
    +  if (HasLeaf7 && ((ECX >> 9) & 1) && HasAVXSave)
    
    378
    +    setFeature(FEATURE_VAES);
    
    379
    +  if (HasLeaf7 && ((ECX >> 10) & 1) && HasAVXSave)
    
    380
    +    setFeature(FEATURE_VPCLMULQDQ);
    
    381
    +  if (HasLeaf7 && ((ECX >> 11) & 1) && HasAVX512Save)
    
    382
    +    setFeature(FEATURE_AVX512VNNI);
    
    383
    +  if (HasLeaf7 && ((ECX >> 12) & 1) && HasAVX512Save)
    
    384
    +    setFeature(FEATURE_AVX512BITALG);
    
    385
    +  if (HasLeaf7 && ((ECX >> 14) & 1) && HasAVX512Save)
    
    386
    +    setFeature(FEATURE_AVX512VPOPCNTDQ);
    
    387
    +  if (HasLeaf7 && ((ECX >> 22) & 1))
    
    388
    +    setFeature(FEATURE_RDPID);
    
    389
    +  if (HasLeaf7 && ((ECX >> 23) & 1))
    
    390
    +    setFeature(FEATURE_KL);
    
    391
    +  if (HasLeaf7 && ((ECX >> 25) & 1))
    
    392
    +    setFeature(FEATURE_CLDEMOTE);
    
    393
    +  if (HasLeaf7 && ((ECX >> 27) & 1))
    
    394
    +    setFeature(FEATURE_MOVDIRI);
    
    395
    +  if (HasLeaf7 && ((ECX >> 28) & 1))
    
    396
    +    setFeature(FEATURE_MOVDIR64B);
    
    397
    +  if (HasLeaf7 && ((ECX >> 29) & 1))
    
    398
    +    setFeature(FEATURE_ENQCMD);
    
    399
    +
    
    400
    +  if (HasLeaf7 && ((EDX >> 2) & 1) && HasAVX512Save)
    
    401
    +    setFeature(FEATURE_AVX5124VNNIW);
    
    402
    +  if (HasLeaf7 && ((EDX >> 3) & 1) && HasAVX512Save)
    
    403
    +    setFeature(FEATURE_AVX5124FMAPS);
    
    404
    +  if (HasLeaf7 && ((EDX >> 5) & 1))
    
    405
    +    setFeature(FEATURE_UINTR);
    
    406
    +  if (HasLeaf7 && ((EDX >> 8) & 1) && HasAVX512Save)
    
    407
    +    setFeature(FEATURE_AVX512VP2INTERSECT);
    
    408
    +  if (HasLeaf7 && ((EDX >> 14) & 1))
    
    409
    +    setFeature(FEATURE_SERIALIZE);
    
    410
    +  if (HasLeaf7 && ((EDX >> 16) & 1))
    
    411
    +    setFeature(FEATURE_TSXLDTRK);
    
    412
    +  if (HasLeaf7 && ((EDX >> 18) & 1))
    
    413
    +    setFeature(FEATURE_PCONFIG);
    
    414
    +  if (HasLeaf7 && ((EDX >> 22) & 1) && HasAMXSave)
    
    415
    +    setFeature(FEATURE_AMX_BF16);
    
    416
    +  if (HasLeaf7 && ((EDX >> 23) & 1) && HasAVX512Save)
    
    417
    +    setFeature(FEATURE_AVX512FP16);
    
    418
    +  if (HasLeaf7 && ((EDX >> 24) & 1) && HasAMXSave)
    
    419
    +    setFeature(FEATURE_AMX_TILE);
    
    420
    +  if (HasLeaf7 && ((EDX >> 25) & 1) && HasAMXSave)
    
    421
    +    setFeature(FEATURE_AMX_INT8);
    
    422
    +
    
    423
    +  // EAX from subleaf 0 is the maximum subleaf supported. Some CPUs don't
    
    424
    +  // return all 0s for invalid subleaves so check the limit.
    
    425
    +  bool HasLeaf7Subleaf1 =
    
    426
    +      HasLeaf7 && EAX >= 1 &&
    
    427
    +      !getX86CpuIDAndInfoEx(0x7, 0x1, &EAX, &EBX, &ECX, &EDX);
    
    428
    +  if (HasLeaf7Subleaf1 && ((EAX >> 0) & 1))
    
    429
    +    setFeature(FEATURE_SHA512);
    
    430
    +  if (HasLeaf7Subleaf1 && ((EAX >> 1) & 1))
    
    431
    +    setFeature(FEATURE_SM3);
    
    432
    +  if (HasLeaf7Subleaf1 && ((EAX >> 2) & 1))
    
    433
    +    setFeature(FEATURE_SM4);
    
    434
    +  if (HasLeaf7Subleaf1 && ((EAX >> 3) & 1))
    
    435
    +    setFeature(FEATURE_RAOINT);
    
    436
    +  if (HasLeaf7Subleaf1 && ((EAX >> 4) & 1) && HasAVXSave)
    
    437
    +    setFeature(FEATURE_AVXVNNI);
    
    438
    +  if (HasLeaf7Subleaf1 && ((EAX >> 5) & 1) && HasAVX512Save)
    
    439
    +    setFeature(FEATURE_AVX512BF16);
    
    440
    +  if (HasLeaf7Subleaf1 && ((EAX >> 7) & 1))
    
    441
    +    setFeature(FEATURE_CMPCCXADD);
    
    442
    +  if (HasLeaf7Subleaf1 && ((EAX >> 21) & 1) && HasAMXSave)
    
    443
    +    setFeature(FEATURE_AMX_FP16);
    
    444
    +  if (HasLeaf7Subleaf1 && ((EAX >> 22) & 1))
    
    445
    +    setFeature(FEATURE_HRESET);
    
    446
    +  if (HasLeaf7Subleaf1 && ((EAX >> 23) & 1) && HasAVXSave)
    
    447
    +    setFeature(FEATURE_AVXIFMA);
    
    448
    +  if (HasLeaf7Subleaf1 && ((EAX >> 31) & 1))
    
    449
    +    setFeature(FEATURE_MOVRS);
    
    450
    +
    
    451
    +  if (HasLeaf7Subleaf1 && ((EDX >> 4) & 1) && HasAVXSave)
    
    452
    +    setFeature(FEATURE_AVXVNNIINT8);
    
    453
    +  if (HasLeaf7Subleaf1 && ((EDX >> 5) & 1) && HasAVXSave)
    
    454
    +    setFeature(FEATURE_AVXNECONVERT);
    
    455
    +  if (HasLeaf7Subleaf1 && ((EDX >> 8) & 1) && HasAMXSave)
    
    456
    +    setFeature(FEATURE_AMX_COMPLEX);
    
    457
    +  if (HasLeaf7Subleaf1 && ((EDX >> 10) & 1) && HasAVXSave)
    
    458
    +    setFeature(FEATURE_AVXVNNIINT16);
    
    459
    +  if (HasLeaf7Subleaf1 && ((EDX >> 14) & 1))
    
    460
    +    setFeature(FEATURE_PREFETCHI);
    
    461
    +  if (HasLeaf7Subleaf1 && ((EDX >> 15) & 1))
    
    462
    +    setFeature(FEATURE_USERMSR);
    
    463
    +  if (HasLeaf7Subleaf1 && ((EDX >> 21) & 1))
    
    464
    +    setFeature(FEATURE_APXF);
    
    465
    +
    
    466
    +  unsigned MaxLevel = 0;
    
    467
    +  getX86CpuIDAndInfo(0, &MaxLevel, &EBX, &ECX, &EDX);
    
    468
    +  bool HasLeafD = MaxLevel >= 0xd &&
    
    469
    +                  !getX86CpuIDAndInfoEx(0xd, 0x1, &EAX, &EBX, &ECX, &EDX);
    
    470
    +  if (HasLeafD && ((EAX >> 0) & 1) && HasAVXSave)
    
    471
    +    setFeature(FEATURE_XSAVEOPT);
    
    472
    +  if (HasLeafD && ((EAX >> 1) & 1) && HasAVXSave)
    
    473
    +    setFeature(FEATURE_XSAVEC);
    
    474
    +  if (HasLeafD && ((EAX >> 3) & 1) && HasAVXSave)
    
    475
    +    setFeature(FEATURE_XSAVES);
    
    476
    +
    
    477
    +  bool HasLeaf24 =
    
    478
    +      MaxLevel >= 0x24 && !getX86CpuIDAndInfo(0x24, &EAX, &EBX, &ECX, &EDX);
    
    479
    +  if (HasLeaf7Subleaf1 && ((EDX >> 19) & 1) && HasLeaf24) {
    
    480
    +    bool Has512Len = (EBX >> 18) & 1;
    
    481
    +    int AVX10Ver = EBX & 0xff;
    
    482
    +    if (AVX10Ver >= 2) {
    
    483
    +      setFeature(FEATURE_AVX10_2_256);
    
    484
    +      if (Has512Len)
    
    485
    +        setFeature(FEATURE_AVX10_2_512);
    
    158 486
         }
    
    159
    -    if (has_fma_hw && avx_usable) {
    
    160
    -      SET_FEAT(feats, GHC_X86_FEAT_FMA);
    
    487
    +    if (AVX10Ver >= 1) {
    
    488
    +      setFeature(FEATURE_AVX10_1_256);
    
    489
    +      if (Has512Len)
    
    490
    +        setFeature(FEATURE_AVX10_1_512);
    
    161 491
         }
    
    492
    +  }
    
    162 493
     
    
    163
    -    if (max_basic >= 7 && ghc_cpuid_count(7, 0, &a, &b, &c, &d)) {
    
    164
    -      int has_bmi1     = !!(b & (1u << 3));
    
    165
    -      int has_avx2_hw  = !!(b & (1u << 5));
    
    166
    -      int has_bmi2     = !!(b & (1u << 8));
    
    167
    -      int has_avx512f  = !!(b & (1u << 16));
    
    168
    -      int has_avx512dq = !!(b & (1u << 17));
    
    169
    -      int has_avx512cd = !!(b & (1u << 28));
    
    170
    -      int has_avx512bw = !!(b & (1u << 30));
    
    171
    -      int has_avx512vl = !!(b & (1u << 31));
    
    172
    -      int has_gfni     = !!(c & (1u << 8));
    
    173
    -
    
    174
    -      if (has_bmi1) {
    
    175
    -        SET_FEAT(feats, GHC_X86_FEAT_BMI1);
    
    176
    -      }
    
    177
    -      if (has_bmi2) {
    
    178
    -        SET_FEAT(feats, GHC_X86_FEAT_BMI2);
    
    179
    -      }
    
    180
    -      if (avx_usable && has_avx2_hw) {
    
    181
    -        SET_FEAT(feats, GHC_X86_FEAT_AVX2);
    
    182
    -      }
    
    494
    +  unsigned MaxExtLevel = 0;
    
    495
    +  getX86CpuIDAndInfo(0x80000000, &MaxExtLevel, &EBX, &ECX, &EDX);
    
    183 496
     
    
    184
    -      if (avx512_usable && has_avx512f) {
    
    185
    -        SET_FEAT(feats, GHC_X86_FEAT_AVX512F);
    
    186
    -        if (has_avx512bw) {
    
    187
    -          SET_FEAT(feats, GHC_X86_FEAT_AVX512BW);
    
    188
    -        }
    
    189
    -        if (has_avx512cd) {
    
    190
    -          SET_FEAT(feats, GHC_X86_FEAT_AVX512CD);
    
    191
    -        }
    
    192
    -        if (has_avx512dq) {
    
    193
    -          SET_FEAT(feats, GHC_X86_FEAT_AVX512DQ);
    
    194
    -        }
    
    195
    -        if (has_avx512vl) {
    
    196
    -          SET_FEAT(feats, GHC_X86_FEAT_AVX512VL);
    
    197
    -        }
    
    198
    -      }
    
    497
    +  bool HasExtLeaf1 = MaxExtLevel >= 0x80000001 &&
    
    498
    +                     !getX86CpuIDAndInfo(0x80000001, &EAX, &EBX, &ECX, &EDX);
    
    499
    +  if (HasExtLeaf1) {
    
    500
    +    if (ECX & 1)
    
    501
    +      setFeature(FEATURE_LAHF_LM);
    
    502
    +    if ((ECX >> 5) & 1)
    
    503
    +      setFeature(FEATURE_LZCNT);
    
    504
    +    if (((ECX >> 6) & 1))
    
    505
    +      setFeature(FEATURE_SSE4_A);
    
    506
    +    if (((ECX >> 8) & 1))
    
    507
    +      setFeature(FEATURE_PRFCHW);
    
    508
    +    if (((ECX >> 11) & 1))
    
    509
    +      setFeature(FEATURE_XOP);
    
    510
    +    if (((ECX >> 15) & 1))
    
    511
    +      setFeature(FEATURE_LWP);
    
    512
    +    if (((ECX >> 16) & 1))
    
    513
    +      setFeature(FEATURE_FMA4);
    
    514
    +    if (((ECX >> 21) & 1))
    
    515
    +      setFeature(FEATURE_TBM);
    
    516
    +    if (((ECX >> 29) & 1))
    
    517
    +      setFeature(FEATURE_MWAITX);
    
    518
    +
    
    519
    +    if (((EDX >> 29) & 1))
    
    520
    +      setFeature(FEATURE_LM);
    
    521
    +  }
    
    522
    +
    
    523
    +  bool HasExtLeaf8 = MaxExtLevel >= 0x80000008 &&
    
    524
    +                     !getX86CpuIDAndInfo(0x80000008, &EAX, &EBX, &ECX, &EDX);
    
    525
    +  if (HasExtLeaf8 && ((EBX >> 0) & 1))
    
    526
    +    setFeature(FEATURE_CLZERO);
    
    527
    +  if (HasExtLeaf8 && ((EBX >> 9) & 1))
    
    528
    +    setFeature(FEATURE_WBNOINVD);
    
    529
    +
    
    530
    +  bool HasLeaf14 = MaxLevel >= 0x14 &&
    
    531
    +                   !getX86CpuIDAndInfoEx(0x14, 0x0, &EAX, &EBX, &ECX, &EDX);
    
    532
    +  if (HasLeaf14 && ((EBX >> 4) & 1))
    
    533
    +    setFeature(FEATURE_PTWRITE);
    
    199 534
     
    
    200
    -      if (has_gfni) {
    
    201
    -        SET_FEAT(feats, GHC_X86_FEAT_GFNI);
    
    535
    +  bool HasLeaf19 =
    
    536
    +      MaxLevel >= 0x19 && !getX86CpuIDAndInfo(0x19, &EAX, &EBX, &ECX, &EDX);
    
    537
    +  if (HasLeaf7 && HasLeaf19 && ((EBX >> 2) & 1))
    
    538
    +    setFeature(FEATURE_WIDEKL);
    
    539
    +
    
    540
    +  if (hasFeature(FEATURE_LM) && hasFeature(FEATURE_SSE2)) {
    
    541
    +    setFeature(FEATURE_X86_64_BASELINE);
    
    542
    +    if (hasFeature(FEATURE_CMPXCHG16B) && hasFeature(FEATURE_POPCNT) &&
    
    543
    +        hasFeature(FEATURE_LAHF_LM) && hasFeature(FEATURE_SSE4_2)) {
    
    544
    +      setFeature(FEATURE_X86_64_V2);
    
    545
    +      if (hasFeature(FEATURE_AVX2) && hasFeature(FEATURE_BMI) &&
    
    546
    +          hasFeature(FEATURE_BMI2) && hasFeature(FEATURE_F16C) &&
    
    547
    +          hasFeature(FEATURE_FMA) && hasFeature(FEATURE_LZCNT) &&
    
    548
    +          hasFeature(FEATURE_MOVBE)) {
    
    549
    +        setFeature(FEATURE_X86_64_V3);
    
    550
    +        if (hasFeature(FEATURE_AVX512BW) && hasFeature(FEATURE_AVX512CD) &&
    
    551
    +            hasFeature(FEATURE_AVX512DQ) && hasFeature(FEATURE_AVX512VL))
    
    552
    +          setFeature(FEATURE_X86_64_V4);
    
    202 553
           }
    
    203 554
         }
    
    204 555
       }
    
    205
    -#endif
    
    206 556
     
    
    207
    -  return feats;
    
    557
    +#undef hasFeature
    
    558
    +#undef setFeature
    
    559
    +}
    
    560
    +
    
    561
    +#endif /* GHC_HOST_IS_X86 */
    
    562
    +
    
    563
    +/* The driver, modeled on upstream's __cpu_indicator_init: same CPUID call
    
    564
    + * sequence, but the first 64 feature bits are returned to the caller (see
    
    565
    + * GHC.Driver.CpuFeatures) instead of being stored in the __cpu_model
    
    566
    + * globals. */
    
    567
    +HsWord64 ghc_detect_x86_cpu_features(void)
    
    568
    +{
    
    569
    +#if defined(GHC_HOST_IS_X86)
    
    570
    +  unsigned EAX = 0, EBX = 0, ECX = 0, EDX = 0;
    
    571
    +  unsigned MaxLeaf = 5;
    
    572
    +  unsigned Features[(CPU_FEATURE_MAX + 31) / 32] = {0};
    
    573
    +
    
    574
    +  if (getX86CpuIDAndInfo(0, &MaxLeaf, &EBX, &ECX, &EDX) || MaxLeaf < 1)
    
    575
    +    return 0;
    
    576
    +
    
    577
    +  getX86CpuIDAndInfo(1, &EAX, &EBX, &ECX, &EDX);
    
    578
    +
    
    579
    +  // Find available features.
    
    580
    +  getAvailableFeatures(ECX, EDX, MaxLeaf, &Features[0]);
    
    581
    +
    
    582
    +  return ((HsWord64)Features[1] << 32) | (HsWord64)Features[0];
    
    583
    +#else
    
    584
    +  return 0;
    
    585
    +#endif
    
    208 586
     }