Simon Jakobi pushed to branch wip/sjakobi/T25450-march-native at Glasgow Haskell Compiler / GHC
Commits:
-
cfca4580
by Simon Jakobi at 2026-09-05T00:32:47+02:00
17 changed files:
- + changelog.d/march-native
- changelog.d/print-enabled-cpu-features
- + compiler/GHC/Driver/CpuFeatures.hs
- compiler/GHC/Driver/DynFlags.hs
- compiler/GHC/Driver/Session.hs
- + compiler/cbits/cpu_features_x86.c
- compiler/ghc.cabal.in
- docs/users_guide/expected-undocumented-flags.txt
- docs/users_guide/using.rst
- rts/RtsSymbols.c
- testsuite/tests/codeGen/should_gen_asm/all.T
- + testsuite/tests/codeGen/should_gen_asm/march-native-enables-popcnt.asm
- + testsuite/tests/codeGen/should_gen_asm/march-native-enables-popcnt.hs
- testsuite/tests/driver/all.T
- + testsuite/tests/driver/march_native.stdout
- + testsuite/tests/driver/march_native_additive.stdout
- + testsuite/tests/driver/march_native_unsupported_arch.stderr
Changes:
| 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. |
| ... | ... | @@ -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"]} |
| 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 |
| ... | ... | @@ -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,
|
| ... | ... | @@ -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
|
| 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 |
| ... | ... | @@ -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
|
| ... | ... | @@ -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
|
| ... | ... | @@ -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 |
| ... | ... | @@ -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
|
| ... | ... | @@ -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),
|
| 1 | +popcnt(?![0-9]) |
|
| \ No newline at end of file |
| 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) |
| ... | ... | @@ -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.
|
| 1 | +SSE2 |
| 1 | +AVX2
|
|
| 2 | +AVX2 |
| 1 | +-march=native is only supported on x86 and x86_64 targets |