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

Commits:

17 changed files:

Changes:

  • changelog.d/march-native
    1
    +section: compiler
    
    2
    +synopsis: Add -march=native flag
    
    3
    +issues: #25450
    
    4
    +mrs: !16126
    
    5
    +
    
    6
    +description:
    
    7
    +  GHC now supports ``-march=native`` on x86 and x86_64. It probes the CPU of the
    
    8
    +  machine running GHC and enables all of the corresponding ``-m...`` CPU-feature
    
    9
    +  options automatically (such as ``-msse4.2``, ``-mavx2``, ``-mbmi2`` and
    
    10
    +  ``-mfma``), for both the native code generator and the LLVM backend. The
    
    11
    +  detected features are enabled in addition to any explicitly requested feature
    
    12
    +  flags. The flag is rejected for non-x86 targets and when cross-compiling.

  • changelog.d/print-enabled-cpu-features
    ... ... @@ -8,9 +8,11 @@ description:
    8 8
       prints a JSON object describing the CPU features currently enabled for code
    
    9 9
       generation, together with a set of ``-m...`` flags that reproduce the
    
    10 10
       effective feature set for the current target.
    
    11
    -  Dynamic options such as ``-mavx2`` and ``-mbmi2`` are respected. ::
    
    11
    +  Dynamic options such as ``-mavx2`` and ``-mbmi2`` are respected, so the flag
    
    12
    +  can also be used to inspect which features :ghc-flag:`-march=native` detected
    
    13
    +  and enabled. ::
    
    12 14
     
    
    13
    -    $ ghc -mavx2 --print-enabled-cpu-features
    
    15
    +    $ ghc -march=native --print-enabled-cpu-features
    
    14 16
         {"tag":"enabled-cpu-features","version":1,"target":"x86_64-linux-gnu",
    
    15
    -     "features":["SSE","SSE2","SSE3","SSSE3","SSE4.1","SSE4.2","AVX","AVX2"],
    
    16
    -     "as_m_flags":["-mavx2"]}
    17
    +     "features":["SSE","SSE2","SSE3","SSSE3","SSE4.1","SSE4.2","AVX","AVX2","BMI1","BMI2","FMA"],
    
    18
    +     "as_m_flags":["-mavx2","-mbmi2","-mfma"]}

  • compiler/GHC/Driver/CpuFeatures.hs
    1
    +{-# LANGUAGE CPP #-}
    
    2
    +
    
    3
    +module GHC.Driver.CpuFeatures
    
    4
    +  ( X86CpuFeature(..)
    
    5
    +  , cachedX86CpuFeatures
    
    6
    +  ) where
    
    7
    +
    
    8
    +import GHC.Prelude
    
    9
    +
    
    10
    +import Data.Word (Word64)
    
    11
    +import System.IO.Unsafe (unsafePerformIO)
    
    12
    +
    
    13
    +-- | x86 CPU features understood by GHC's native CPU feature probe.
    
    14
    +data X86CpuFeature
    
    15
    +  = SSE2
    
    16
    +  | SSE3
    
    17
    +  | SSSE3
    
    18
    +  | SSE4_1
    
    19
    +  | SSE4_2
    
    20
    +  | AVX
    
    21
    +  | AVX2
    
    22
    +  | AVX512F
    
    23
    +  | AVX512BW
    
    24
    +  | AVX512CD
    
    25
    +  | AVX512DQ
    
    26
    +  | AVX512VL
    
    27
    +  | BMI1
    
    28
    +  | BMI2
    
    29
    +  | FMA
    
    30
    +  | GFNI
    
    31
    +  deriving (Eq, Ord, Show, Enum, Bounded)
    
    32
    +
    
    33
    +-- | Decode the bitmask returned by 'ghc_detect_x86_cpu_features'.
    
    34
    +--
    
    35
    +-- Bit positions are constructor order, which must match the enum in
    
    36
    +-- @compiler/cbits/cpu_features_x86.c@.
    
    37
    +decodeX86CpuFeatureMask :: Word64 -> [X86CpuFeature]
    
    38
    +decodeX86CpuFeatureMask mask =
    
    39
    +  [ feat
    
    40
    +  | feat <- [minBound .. maxBound]
    
    41
    +  , testBit mask (fromEnum feat)
    
    42
    +  ]
    
    43
    +
    
    44
    +-- | Low-level FFI access to the C probe.
    
    45
    +detectX86CpuFeatureMask :: IO Word64
    
    46
    +#if defined(javascript_HOST_ARCH)
    
    47
    +detectX86CpuFeatureMask = pure 0
    
    48
    +#else
    
    49
    +detectX86CpuFeatureMask = c_ghc_detect_x86_cpu_features
    
    50
    +#endif
    
    51
    +
    
    52
    +-- | Probe host x86 CPU features and decode them into an ordered feature list.
    
    53
    +detectX86CpuFeatures :: IO [X86CpuFeature]
    
    54
    +detectX86CpuFeatures = decodeX86CpuFeatureMask <$> detectX86CpuFeatureMask
    
    55
    +
    
    56
    +-- | The host's x86 CPU features, probed once and memoized.
    
    57
    +cachedX86CpuFeatures :: [X86CpuFeature]
    
    58
    +cachedX86CpuFeatures = unsafePerformIO detectX86CpuFeatures
    
    59
    +{-# NOINLINE cachedX86CpuFeatures #-}
    
    60
    +
    
    61
    +#if !defined(javascript_HOST_ARCH)
    
    62
    +foreign import ccall unsafe "ghc_detect_x86_cpu_features"
    
    63
    +  c_ghc_detect_x86_cpu_features :: IO Word64
    
    64
    +#endif

  • compiler/GHC/Driver/DynFlags.hs
    ... ... @@ -473,6 +473,8 @@ data DynFlags = DynFlags {
    473 473
       fma                   :: Bool, -- ^ Enable FMA instructions.
    
    474 474
       gfni                  :: Bool, -- ^ Enable GFNI Instructions.
    
    475 475
       la664                 :: Bool, -- ^ Enable LA664 instructions
    
    476
    +  marchNative           :: Bool, -- ^ @-march=native@ was requested; the host
    
    477
    +                                 -- CPU features are applied during flag parsing.
    
    476 478
     
    
    477 479
       -- Constants used to control the amount of optimization done.
    
    478 480
     
    
    ... ... @@ -765,6 +767,7 @@ defaultDynFlags mySettings =
    765 767
             gfni = False,
    
    766 768
             -- For LoongArch, la464 is used by default.
    
    767 769
             la664 = False,
    
    770
    +        marchNative = False,
    
    768 771
     
    
    769 772
             maxInlineAllocSize = 128,
    
    770 773
             maxInlineMemcpyInsns = 32,
    

  • compiler/GHC/Driver/Session.hs
    ... ... @@ -245,6 +245,8 @@ import GHC.Platform
    245 245
     import GHC.Platform.Ways
    
    246 246
     import GHC.Platform.Profile
    
    247 247
     import GHC.Platform.ArchOS
    
    248
    +import GHC.Platform.Host (hostPlatformArch)
    
    249
    +import qualified GHC.Driver.CpuFeatures as Cpu
    
    248 250
     
    
    249 251
     import GHC.Unit.Types
    
    250 252
     import GHC.Unit.Parser
    
    ... ... @@ -907,8 +909,10 @@ parseDynamicFlagsFull activeFlags cmdline logger dflags0 args = do
    907 909
       unless (null errs) $ liftIO $ throwGhcExceptionIO $ errorsToGhcException $
    
    908 910
         map ((rdr . ppr . getLoc &&& unLoc) . errMsg) $ errs
    
    909 911
     
    
    912
    +  dflags1' <- applyMarchNative dflags1
    
    913
    +
    
    910 914
       -- check for disabled flags in safe haskell
    
    911
    -  let (dflags2, sh_warns) = safeFlagCheck cmdline dflags1
    
    915
    +  let (dflags2, sh_warns) = safeFlagCheck cmdline dflags1'
    
    912 916
           theWays = ways dflags2
    
    913 917
     
    
    914 918
       unless (allowed_combination theWays) $ liftIO $
    
    ... ... @@ -1743,6 +1747,7 @@ dynamic_flags_deps = [
    1743 1747
       , make_ord_flag defGhcFlag "mavx512vl"    (noArg (\d -> d { avx512vl = True }))
    
    1744 1748
       , make_ord_flag defGhcFlag "mfma"         (noArg (\d -> d { fma = True }))
    
    1745 1749
       , make_ord_flag defGhcFlag "mgfni"        (noArg (\d -> d { gfni = True }))
    
    1750
    +  , make_ord_flag defGhcFlag "march=native" (noArg (\d -> d { marchNative = True }))
    
    1746 1751
     
    
    1747 1752
     
    
    1748 1753
       , make_ord_flag defGhcFlag "mla664"       (noArg (\d -> d { la664 = True }))
    
    ... ... @@ -3826,6 +3831,53 @@ x86AsMFlags dflags =
    3826 3831
     
    
    3827 3832
         gfniFlags = [ "-mgfni" | gfni dflags ]
    
    3828 3833
     
    
    3834
    +-- | Apply a requested @-march=native@ by probing the host CPU and enabling the
    
    3835
    +-- matching CPU-feature flags.
    
    3836
    +applyMarchNative :: MonadIO m => DynFlags -> m DynFlags
    
    3837
    +applyMarchNative dflags
    
    3838
    +  | not (marchNative dflags) = return dflags
    
    3839
    +  | otherwise = do
    
    3840
    +      let arch = platformArch (targetPlatform dflags)
    
    3841
    +      unless (arch == ArchX86 || arch == ArchX86_64) $ liftIO $
    
    3842
    +        throwGhcExceptionIO $ CmdLineError
    
    3843
    +          "-march=native is only supported on x86 and x86_64 targets"
    
    3844
    +      unless (arch == hostPlatformArch) $ liftIO $
    
    3845
    +        throwGhcExceptionIO $ CmdLineError
    
    3846
    +          "-march=native is not supported when cross-compiling"
    
    3847
    +      return (applyX86CpuFeatures Cpu.cachedX86CpuFeatures dflags)
    
    3848
    +
    
    3849
    +-- | Enable the 'DynFlags' CPU-feature fields corresponding to a probed set of
    
    3850
    +-- host x86 features.
    
    3851
    +applyX86CpuFeatures :: [Cpu.X86CpuFeature] -> DynFlags -> DynFlags
    
    3852
    +applyX86CpuFeatures feats dflags = dflags
    
    3853
    +  { sseAvxVersion = foldr (max . Just) (sseAvxVersion dflags) sseLevels
    
    3854
    +  , bmiVersion    = foldr (max . Just) (bmiVersion dflags)    bmiLevels
    
    3855
    +  , avx512f  = avx512f dflags  || has Cpu.AVX512F
    
    3856
    +  , avx512bw = avx512bw dflags || has Cpu.AVX512BW
    
    3857
    +  , avx512cd = avx512cd dflags || has Cpu.AVX512CD
    
    3858
    +  , avx512dq = avx512dq dflags || has Cpu.AVX512DQ
    
    3859
    +  , avx512vl = avx512vl dflags || has Cpu.AVX512VL
    
    3860
    +  , fma      = fma dflags      || has Cpu.FMA
    
    3861
    +  , gfni     = gfni dflags     || has Cpu.GFNI
    
    3862
    +  }
    
    3863
    +  where
    
    3864
    +    has feat = feat `elem` feats
    
    3865
    +    sseLevels = [ lvl | feat <- feats, Just lvl <- [sseLevelOf feat] ]
    
    3866
    +    bmiLevels = [ lvl | feat <- feats, Just lvl <- [bmiLevelOf feat] ]
    
    3867
    +    sseLevelOf feat = case feat of
    
    3868
    +      Cpu.SSE2   -> Just SSE2
    
    3869
    +      Cpu.SSE3   -> Just SSE3
    
    3870
    +      Cpu.SSSE3  -> Just SSSE3
    
    3871
    +      Cpu.SSE4_1 -> Just SSE4
    
    3872
    +      Cpu.SSE4_2 -> Just SSE42
    
    3873
    +      Cpu.AVX    -> Just AVX1
    
    3874
    +      Cpu.AVX2   -> Just AVX2
    
    3875
    +      _          -> Nothing
    
    3876
    +    bmiLevelOf feat = case feat of
    
    3877
    +      Cpu.BMI1 -> Just BMI1
    
    3878
    +      Cpu.BMI2 -> Just BMI2
    
    3879
    +      _        -> Nothing
    
    3880
    +
    
    3829 3881
     -- | Query if the target RTS has the given 'Ways'. It's computed from
    
    3830 3882
     -- the @"RTS ways"@ field in the settings file.
    
    3831 3883
     targetHasRTSWays :: DynFlags -> Ways -> Bool
    

  • compiler/cbits/cpu_features_x86.c
    1
    +#include <HsFFI.h>
    
    2
    +
    
    3
    +/* Runtime x86 CPU feature detection backing GHC.Driver.CpuFeatures
    
    4
    +   (-march=native).
    
    5
    +
    
    6
    +   The bit positions in the returned mask are GHC's own; the enum below
    
    7
    +   must match the constructor order of X86CpuFeature in
    
    8
    +   GHC.Driver.CpuFeatures.
    
    9
    +
    
    10
    +   The __builtin_cpu_* calls below compile to references to libgcc/compiler-rt
    
    11
    +   symbols (__cpu_model & co.), which GHCi's runtime linker can only resolve
    
    12
    +   because the RTS exports them: see RTS_X86_CPU_MODEL_SYMBOLS in
    
    13
    +   rts/RtsSymbols.c and keep its guards in sync with this file's. */
    
    14
    +
    
    15
    +enum {
    
    16
    +  GHC_X86_FEAT_SSE2 = 0,
    
    17
    +  GHC_X86_FEAT_SSE3,
    
    18
    +  GHC_X86_FEAT_SSSE3,
    
    19
    +  GHC_X86_FEAT_SSE4_1,
    
    20
    +  GHC_X86_FEAT_SSE4_2,
    
    21
    +  GHC_X86_FEAT_AVX,
    
    22
    +  GHC_X86_FEAT_AVX2,
    
    23
    +  GHC_X86_FEAT_AVX512F,
    
    24
    +  GHC_X86_FEAT_AVX512BW,
    
    25
    +  GHC_X86_FEAT_AVX512CD,
    
    26
    +  GHC_X86_FEAT_AVX512DQ,
    
    27
    +  GHC_X86_FEAT_AVX512VL,
    
    28
    +  GHC_X86_FEAT_BMI1,
    
    29
    +  GHC_X86_FEAT_BMI2,
    
    30
    +  GHC_X86_FEAT_FMA,
    
    31
    +  GHC_X86_FEAT_GFNI
    
    32
    +};
    
    33
    +
    
    34
    +#if (defined(__i386__) || defined(__x86_64__)) \
    
    35
    +    && (defined(__GNUC__) || defined(__clang__))
    
    36
    +
    
    37
    +/* GFNI joined the __builtin_cpu_supports feature lists later than the
    
    38
    +   other features here (GCC 11; compiler-rt's cpu_model in LLVM 12).
    
    39
    +   Under an older bootstrap compiler we conservatively report no GFNI. */
    
    40
    +#if (defined(__clang_major__) && __clang_major__ >= 12) \
    
    41
    +    || (!defined(__clang__) && defined(__GNUC__) && __GNUC__ >= 11)
    
    42
    +#define GHC_HAS_CPU_SUPPORTS_GFNI 1
    
    43
    +#else
    
    44
    +#define GHC_HAS_CPU_SUPPORTS_GFNI 0
    
    45
    +#endif
    
    46
    +
    
    47
    +HsWord64 ghc_detect_x86_cpu_features(void)
    
    48
    +{
    
    49
    +  __builtin_cpu_init();
    
    50
    +
    
    51
    +  HsWord64 feats = 0;
    
    52
    +
    
    53
    +  /* __builtin_cpu_supports returns the feature's (nonzero) mask bit,
    
    54
    +     not 0/1, so it must be normalized before shifting. */
    
    55
    +#define GHC_CPU_FEATURE(name, bit) \
    
    56
    +  if (__builtin_cpu_supports(name)) { feats |= ((HsWord64)1 << (bit)); }
    
    57
    +
    
    58
    +  GHC_CPU_FEATURE("sse2",     GHC_X86_FEAT_SSE2)
    
    59
    +  GHC_CPU_FEATURE("sse3",     GHC_X86_FEAT_SSE3)
    
    60
    +  GHC_CPU_FEATURE("ssse3",    GHC_X86_FEAT_SSSE3)
    
    61
    +  GHC_CPU_FEATURE("sse4.1",   GHC_X86_FEAT_SSE4_1)
    
    62
    +  GHC_CPU_FEATURE("sse4.2",   GHC_X86_FEAT_SSE4_2)
    
    63
    +  GHC_CPU_FEATURE("avx",      GHC_X86_FEAT_AVX)
    
    64
    +  GHC_CPU_FEATURE("avx2",     GHC_X86_FEAT_AVX2)
    
    65
    +  GHC_CPU_FEATURE("avx512f",  GHC_X86_FEAT_AVX512F)
    
    66
    +  GHC_CPU_FEATURE("avx512bw", GHC_X86_FEAT_AVX512BW)
    
    67
    +  GHC_CPU_FEATURE("avx512cd", GHC_X86_FEAT_AVX512CD)
    
    68
    +  GHC_CPU_FEATURE("avx512dq", GHC_X86_FEAT_AVX512DQ)
    
    69
    +  GHC_CPU_FEATURE("avx512vl", GHC_X86_FEAT_AVX512VL)
    
    70
    +  GHC_CPU_FEATURE("bmi",      GHC_X86_FEAT_BMI1)
    
    71
    +  GHC_CPU_FEATURE("bmi2",     GHC_X86_FEAT_BMI2)
    
    72
    +
    
    73
    +  /* FMA is usable only when the OS saves the AVX register state.  However
    
    74
    +     compiler-rt's cpu_model/x86.c reports "fma" from the raw CPUID bit. */
    
    75
    +  if (__builtin_cpu_supports("fma") && __builtin_cpu_supports("avx")) {
    
    76
    +    feats |= ((HsWord64)1 << GHC_X86_FEAT_FMA);
    
    77
    +  }
    
    78
    +
    
    79
    +#if GHC_HAS_CPU_SUPPORTS_GFNI
    
    80
    +  GHC_CPU_FEATURE("gfni",     GHC_X86_FEAT_GFNI)
    
    81
    +#endif
    
    82
    +
    
    83
    +#undef GHC_CPU_FEATURE
    
    84
    +
    
    85
    +  return feats;
    
    86
    +}
    
    87
    +
    
    88
    +#else
    
    89
    +
    
    90
    +/* Non-x86 host, or a compiler without __builtin_cpu_supports (e.g. MSVC):
    
    91
    +   report no features. */
    
    92
    +HsWord64 ghc_detect_x86_cpu_features(void)
    
    93
    +{
    
    94
    +  return 0;
    
    95
    +}
    
    96
    +
    
    97
    +#endif

  • compiler/ghc.cabal.in
    ... ... @@ -187,6 +187,7 @@ Library
    187 187
         else
    
    188 188
           c-sources:
    
    189 189
             cbits/cutils.c
    
    190
    +        cbits/cpu_features_x86.c
    
    190 191
             cbits/genSym.c
    
    191 192
             cbits/keepCAFsForGHCi.c
    
    192 193
     
    
    ... ... @@ -518,6 +519,7 @@ Library
    518 519
             GHC.Driver.Config.StgToCmm
    
    519 520
             GHC.Driver.Config.Tidy
    
    520 521
             GHC.Driver.Config.StgToJS
    
    522
    +        GHC.Driver.CpuFeatures
    
    521 523
             GHC.Driver.DynFlags
    
    522 524
             GHC.Driver.IncludeSpecs
    
    523 525
             GHC.Driver.Downsweep
    

  • docs/users_guide/expected-undocumented-flags.txt
    ... ... @@ -74,6 +74,7 @@
    74 74
     -instantiated-with
    
    75 75
     -keep-hi-file
    
    76 76
     -keep-o-file
    
    77
    +-march=native
    
    77 78
     -n
    
    78 79
     -no-keep-hi-file
    
    79 80
     -no-keep-o-file
    

  • docs/users_guide/using.rst
    ... ... @@ -539,7 +539,9 @@ The available mode flags are:
    539 539
         Print a JSON object describing the CPU features currently enabled for code
    
    540 540
         generation, together with a set of ``-m...`` flags that reproduce the
    
    541 541
         effective feature set for the current target.
    
    542
    -    Dynamic options such as ``-mavx2`` and ``-mbmi2`` are respected.
    
    542
    +    Dynamic options such as ``-mavx2`` and ``-mbmi2`` are respected, so this flag
    
    543
    +    can also be used to inspect which features :ghc-flag:`-march=native` detected
    
    544
    +    and enabled.
    
    543 545
     
    
    544 546
     .. ghc-flag:: --print-debug-on
    
    545 547
         :shortdesc: print whether GHC was built with ``-DDEBUG``
    
    ... ... @@ -1897,6 +1899,34 @@ Some flags only make sense for particular target platforms.
    1897 1899
         so this flag has no effect when used with the :ref:`native code generator <native-code-gen>`
    
    1898 1900
         or the :ref:`LLVM backend <llvm-code-gen>`.
    
    1899 1901
     
    
    1902
    +.. ghc-flag:: -march=native
    
    1903
    +    :shortdesc: (x86 only) Enable all CPU features supported by the host
    
    1904
    +    :type: dynamic
    
    1905
    +    :category: platform-options
    
    1906
    +
    
    1907
    +    (x86/x86_64 only) Probe the CPU of the machine running GHC and enable all of
    
    1908
    +    the corresponding ``-m...`` CPU-feature options automatically (for example
    
    1909
    +    ``-msse4.2``, ``-mavx2``, ``-mbmi2``, ``-mfma``). The detected features apply
    
    1910
    +    to both the :ref:`native code generator <native-code-gen>` and the
    
    1911
    +    :ref:`LLVM backend <llvm-code-gen>`.
    
    1912
    +
    
    1913
    +    The detected features are enabled *in addition* to any CPU-feature flags you
    
    1914
    +    pass explicitly, regardless of their order on the command line; ``-march=native``
    
    1915
    +    never disables a feature.
    
    1916
    +
    
    1917
    +    The features that were detected and enabled can be inspected with
    
    1918
    +    :ghc-flag:`--print-enabled-cpu-features`.
    
    1919
    +
    
    1920
    +    .. warning::
    
    1921
    +
    
    1922
    +        Code compiled with ``-march=native`` may use instructions that are not
    
    1923
    +        available on other CPUs, and is therefore not portable to a different
    
    1924
    +        machine.
    
    1925
    +
    
    1926
    +    Only x86 and x86_64 targets are supported so far; the flag is rejected on
    
    1927
    +    other targets. It is also rejected when cross-compiling, since the host CPU
    
    1928
    +    is then unrelated to the target.
    
    1929
    +
    
    1900 1930
     Haddock
    
    1901 1931
     -------
    
    1902 1932
     
    

  • rts/RtsSymbols.c
    ... ... @@ -1039,6 +1039,30 @@ extern char **environ;
    1039 1039
     #define RTS_ARM_OUTLINE_ATOMIC_SYMBOLS
    
    1040 1040
     #endif
    
    1041 1041
     
    
    1042
    +// libgcc/compiler-rt symbols behind __builtin_cpu_supports/__builtin_cpu_init,
    
    1043
    +// referenced by compiler/cbits/cpu_features_x86.c (-march=native).
    
    1044
    +// Without them the runtime linker cannot load the ghc library's object code
    
    1045
    +// (e.g. for plugins in a statically linked GHCi). Keep the guards in sync
    
    1046
    +// with cpu_features_x86.c.
    
    1047
    +#if (defined(i386_HOST_ARCH) || defined(x86_64_HOST_ARCH)) \
    
    1048
    +    && (defined(__GNUC__) || defined(__clang__))
    
    1049
    +// __cpu_features2 holds the feature words beyond the first 32 (e.g. GFNI)
    
    1050
    +// and only exists in the runtimes of GCC >= 11 resp. LLVM >= 12.
    
    1051
    +#if (defined(__clang_major__) && __clang_major__ >= 12) \
    
    1052
    +    || (!defined(__clang__) && defined(__GNUC__) && __GNUC__ >= 11)
    
    1053
    +#define RTS_X86_CPU_FEATURES2_SYMBOLS \
    
    1054
    +      SymI_NeedsDataProto(__cpu_features2)
    
    1055
    +#else
    
    1056
    +#define RTS_X86_CPU_FEATURES2_SYMBOLS
    
    1057
    +#endif
    
    1058
    +#define RTS_X86_CPU_MODEL_SYMBOLS \
    
    1059
    +      SymI_NeedsProto(__cpu_indicator_init) \
    
    1060
    +      SymI_NeedsDataProto(__cpu_model) \
    
    1061
    +      RTS_X86_CPU_FEATURES2_SYMBOLS
    
    1062
    +#else
    
    1063
    +#define RTS_X86_CPU_MODEL_SYMBOLS
    
    1064
    +#endif
    
    1065
    +
    
    1042 1066
     // Symbols defined by libc
    
    1043 1067
     #define RTS_LIBC_SYMBOLS                               \
    
    1044 1068
           SymI_HasProto_redirect(atexit, atexit, STRENGTH_STRONG, SYM_TYPE_CODE) /* See Note [Strong symbols] */ \
    
    ... ... @@ -1199,6 +1223,7 @@ RTS_OPENBSD_ONLY_SYMBOLS
    1199 1223
     RTS_LIBC_SYMBOLS
    
    1200 1224
     RTS_LIBGCC_SYMBOLS
    
    1201 1225
     RTS_ARCH_LIBGCC_SYMBOLS
    
    1226
    +RTS_X86_CPU_MODEL_SYMBOLS
    
    1202 1227
     RTS_FINI_ARRAY_SYMBOLS
    
    1203 1228
     RTS_LIBFFI_SYMBOLS
    
    1204 1229
     RTS_ARM_OUTLINE_ATOMIC_SYMBOLS
    
    ... ... @@ -1254,6 +1279,7 @@ void initLinkerRtsSyms (StrHashTable *symhash) {
    1254 1279
           RTS_OPENBSD_ONLY_SYMBOLS
    
    1255 1280
           RTS_LIBGCC_SYMBOLS
    
    1256 1281
           RTS_ARCH_LIBGCC_SYMBOLS
    
    1282
    +      RTS_X86_CPU_MODEL_SYMBOLS
    
    1257 1283
           RTS_FINI_ARRAY_SYMBOLS
    
    1258 1284
           RTS_LIBFFI_SYMBOLS
    
    1259 1285
           RTS_ARM_OUTLINE_ATOMIC_SYMBOLS
    

  • testsuite/tests/codeGen/should_gen_asm/all.T
    ... ... @@ -17,6 +17,11 @@ test('msse-option-order', [unless(arch('x86_64') or arch('i386'), skip),
    17 17
                                when(unregisterised(), skip)], compile_grep_asm, ['hs', False, '-msse4.2 -msse2'])
    
    18 18
     test('mavx-should-enable-popcnt', [unless(arch('x86_64') or arch('i386'), skip),
    
    19 19
                                        when(unregisterised(), skip)], compile_grep_asm, ['hs', False, '-mavx'])
    
    20
    +# -march=native probes the host CPU, so gate on the host actually having SSE4.2
    
    21
    +# (have_cpu_feature reports nothing under cross, skipping the test there too).
    
    22
    +test('march-native-enables-popcnt',
    
    23
    +     [unless((arch('x86_64') or arch('i386')) and have_cpu_feature('sse4_2'), skip),
    
    24
    +      when(unregisterised(), skip)], compile_grep_asm, ['hs', False, '-march=native'])
    
    20 25
     test('avx512-int64-mul', [unless(arch('x86_64'), skip),
    
    21 26
                               when(unregisterised(), skip)], compile_grep_asm, ['hs', True, '-mavx512dq -mavx512vl'])
    
    22 27
     test('avx512-int64-minmax', [unless(arch('x86_64'), skip),
    

  • testsuite/tests/codeGen/should_gen_asm/march-native-enables-popcnt.asm
    1
    +popcnt(?![0-9])
    \ No newline at end of file

  • testsuite/tests/codeGen/should_gen_asm/march-native-enables-popcnt.hs
    1
    +-- `-march=native` enables the host's CPU features. On a host with SSE4.2
    
    2
    +-- (gated in all.T via have_cpu_feature) this makes popCount compile to a
    
    3
    +-- `popcnt` instruction rather than the SSE2-baseline software fallback.
    
    4
    +import Data.Bits
    
    5
    +
    
    6
    +{-# NOINLINE foo #-}
    
    7
    +foo :: Int -> Int
    
    8
    +foo x = 1 + popCount x
    
    9
    +
    
    10
    +main :: IO ()
    
    11
    +main = print (foo 42)

  • testsuite/tests/driver/all.T
    ... ... @@ -7,6 +7,12 @@ def normalise_unknown_flag(msg):
    7 7
         m = re.search(r'unrecognised flag: \S+', msg)
    
    8 8
         return m.group(0) + '\n' if m else msg
    
    9 9
     
    
    10
    +def normalise_march_native_error(msg):
    
    11
    +    # Keep only the stable '-march=native ...' diagnostic; the program-name
    
    12
    +    # prefix and any usage trailer vary across configurations.
    
    13
    +    m = re.search(r'-march=native is [^\n]+', msg)
    
    14
    +    return m.group(0) + '\n' if m else msg
    
    15
    +
    
    10 16
     test('driver011', [extra_files(['A011.hs'])], makefile_test, ['test011'])
    
    11 17
     
    
    12 18
     test('driver012', [extra_files(['A012.hs'])], makefile_test, ['test012'])
    
    ... ... @@ -265,6 +271,29 @@ test('print_enabled_cpu_features_unknown_flag',
    265 271
          run_command,
    
    266 272
          ['{compiler} -mavx22 --print-enabled-cpu-features'])
    
    267 273
     
    
    274
    +# -march=native enables at least the x86_64 baseline (SSE2). The full feature
    
    275
    +# set is host-dependent, so we only assert the always-present baseline.
    
    276
    +test('march_native',
    
    277
    +     [unless(arch('x86_64') or arch('i386'), skip)],
    
    278
    +     run_command,
    
    279
    +     ['{compiler} -march=native --print-enabled-cpu-features | grep -o SSE2'])
    
    280
    +
    
    281
    +# On non-x86 targets -march=native must be rejected.
    
    282
    +test('march_native_unsupported_arch',
    
    283
    +     [when(arch('x86_64') or arch('i386'), skip),
    
    284
    +      normalise_errmsg_fun(normalise_march_native_error), exit_code(1)],
    
    285
    +     run_command,
    
    286
    +     ['{compiler} -march=native --print-enabled-cpu-features'])
    
    287
    +
    
    288
    +# -march=native is additive with explicit -m flags, regardless of order: an
    
    289
    +# explicitly requested feature (here AVX2, forced on independent of the host) is
    
    290
    +# still present whether the flag comes before or after -march=native.
    
    291
    +test('march_native_additive',
    
    292
    +     [unless(arch('x86_64') or arch('i386'), skip)],
    
    293
    +     run_command,
    
    294
    +     ['{compiler} -mavx2 -march=native --print-enabled-cpu-features | grep -o AVX2 && '
    
    295
    +      '{compiler} -march=native -mavx2 --print-enabled-cpu-features | grep -o AVX2'])
    
    296
    +
    
    268 297
     test('T10219', normal, run_command,
    
    269 298
          # `-x hspp` in make mode should work.
    
    270 299
          # Note: need to specify `-x hspp` before the filename.
    

  • testsuite/tests/driver/march_native.stdout
    1
    +SSE2

  • testsuite/tests/driver/march_native_additive.stdout
    1
    +AVX2
    
    2
    +AVX2

  • testsuite/tests/driver/march_native_unsupported_arch.stderr
    1
    +-march=native is only supported on x86 and x86_64 targets