Simon Jakobi pushed to branch wip/sjakobi/T25450-march-native at Glasgow Haskell Compiler / GHC
Commits:
-
d177606f
by Simon Jakobi at 2026-06-01T22:51:53+02:00
-
4851f684
by Simon Jakobi at 2026-06-02T00:37:14+02:00
-
69bd97c5
by Simon Jakobi at 2026-06-02T00:37:14+02:00
-
58057a37
by Simon Jakobi at 2026-06-02T00:37:15+02:00
-
2ebb98e7
by Simon Jakobi at 2026-06-02T00:37:15+02:00
-
dcf90d0a
by Simon Jakobi at 2026-06-02T00:37:15+02:00
-
fc53b0c8
by Simon Jakobi at 2026-06-02T00:37:15+02:00
-
d56edd5c
by Simon Jakobi at 2026-06-02T00:37:15+02:00
-
7aa7eb43
by Simon Jakobi at 2026-06-02T00:48:27+02:00
-
10d359b2
by Simon Jakobi at 2026-06-02T01:26:06+02:00
25 changed files:
- + PLAN.md
- + 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/using.rst
- ghc/GHC/Driver/Session/Lint.hs
- ghc/GHC/Driver/Session/Mode.hs
- ghc/Main.hs
- 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
- + testsuite/tests/driver/print_enabled_cpu_features.stdout
- + testsuite/tests/driver/print_enabled_cpu_features_avx2.stdout
- + testsuite/tests/driver/print_enabled_cpu_features_avx512.stdout
- + testsuite/tests/driver/print_enabled_cpu_features_bmi2.stdout
- + testsuite/tests/driver/print_enabled_cpu_features_fma.stdout
- + testsuite/tests/driver/print_enabled_cpu_features_unknown_flag.stderr
Changes:
| 1 | +# Implement `-march=native` for x86/x86_64 Using `GHC.Driver.CpuFeatures`
|
|
| 2 | + |
|
| 3 | +## Summary
|
|
| 4 | +Add support for `-march=native` (x86/x86_64, native compiler only). The flag probes the
|
|
| 5 | +host CPU at parse time via an in-process CPUID/XGETBV helper and enables the matching
|
|
| 6 | +CPU-feature `DynFlags`, so the effect applies to both the NCG and LLVM backends.
|
|
| 7 | + |
|
| 8 | +This branch is based on `wip/sjakobi/T25450-print-cpu`, which already provides
|
|
| 9 | +`ghc --print-enabled-cpu-features` and the `enabledCpuFeatures` / `showEnabledCpuFeatures`
|
|
| 10 | +machinery in `GHC.Driver.Session`. That print mode is the primary tool for verifying and
|
|
| 11 | +testing `-march=native`: detection sets `DynFlags`, the print mode reports them.
|
|
| 12 | + |
|
| 13 | +## Public Interface Changes
|
|
| 14 | +1. New dynamic flag: `-march=native`.
|
|
| 15 | +2. New users-guide docs entry under platform flags.
|
|
| 16 | +3. Behavior constraints:
|
|
| 17 | + - Supported only for target `x86`/`x86_64`.
|
|
| 18 | + - Rejected for cross-compilation (host CPU is irrelevant to a different target).
|
|
| 19 | + - Additive: applied once after the whole flag fold, it enables host features
|
|
| 20 | + *in addition* to any explicit `-m...` flags (order-independent, never disables).
|
|
| 21 | + |
|
| 22 | +## Module / Architecture Changes
|
|
| 23 | +1. `compiler/cbits/cpu_features_x86.c` — in-process CPUID/XGETBV probe (done).
|
|
| 24 | +2. `compiler/GHC/Driver/CpuFeatures.hs` — mask decoder + naming (done). Build wiring in
|
|
| 25 | + `compiler/ghc.cabal.in` (done).
|
|
| 26 | +3. `compiler/GHC/Driver/DynFlags.hs` — add a marker field `marchNative :: Bool` (default
|
|
| 27 | + `False`).
|
|
| 28 | +4. `compiler/GHC/Driver/Session.hs` — flag registration + the IO application step (see below).
|
|
| 29 | + |
|
| 30 | +## Detailed Implementation
|
|
| 31 | + |
|
| 32 | +### 1. Flag parsing — pure marker only
|
|
| 33 | +- File: `compiler/GHC/Driver/Session.hs`, near the existing `-m...` flags (~line 1710).
|
|
| 34 | +- `make_ord_flag defGhcFlag "march=native" (noArg (\d -> d { marchNative = True }))`.
|
|
| 35 | +- IMPORTANT: flag handlers run in `DynP = EwM (CmdLineP DynFlags)`, which is **pure** — they
|
|
| 36 | + cannot run the CPUID probe. The handler only records the request via the marker field.
|
|
| 37 | +- Flag-surface note: a literal `"march=native"` entry means `-march=<other>` falls through to
|
|
| 38 | + a generic "unrecognised flag" error. For v1 this is acceptable; document that only `native`
|
|
| 39 | + is supported. (Optionally parse the `=value` later to emit a targeted message.)
|
|
| 40 | + |
|
| 41 | +### 2. Feature application — the IO step
|
|
| 42 | +- File: `compiler/GHC/Driver/Session.hs`, inside `parseDynamicFlagsFull`.
|
|
| 43 | +- `parseDynamicFlagsFull` is already `MonadIO` and already performs `liftIO` work between the
|
|
| 44 | + pure flag fold (`dflags1`) and `makeDynFlagsConsistent` (`dflags2`/`dflags3`). Insert the
|
|
| 45 | + application there: after `dflags1`, before `makeDynFlagsConsistent`.
|
|
| 46 | + - If `marchNative dflags1` is set:
|
|
| 47 | + - Validate target arch is `ArchX86`/`ArchX86_64`; otherwise hard error.
|
|
| 48 | + - Validate not cross-compiling; otherwise hard error. (See open question on detection.)
|
|
| 49 | + - `feats <- liftIO detectX86CpuFeatures` (cached — see §4).
|
|
| 50 | + - Apply `feats` to `DynFlags` via a dedicated mapping helper (see §3), producing `dflags1'`.
|
|
| 51 | + - `makeDynFlagsConsistent` then propagates feature implications — do not reimplement them.
|
|
| 52 | +- This path is shared with `parseDynamicFilePragma`, so the same logic also covers
|
|
| 53 | + `{-# OPTIONS_GHC -march=native #-}`. Decide whether to permit that; if so, caching matters.
|
|
| 54 | + |
|
| 55 | +### 3. Mapping detected features to `DynFlags`
|
|
| 56 | +The detected list is granular (`SSE2, SSE3, …, AVX2, BMI1, BMI2, …`), but several `DynFlags`
|
|
| 57 | +fields are single ordered levels, so the mapper must **collapse ladders to their maximum**:
|
|
| 58 | +- SSE/AVX ladder → highest present → `sseAvxVersion :: Maybe SseAvxVersion`
|
|
| 59 | + (`DynFlags.hs:461`). The `is*Enabled` predicates (`DynFlags.hs:1621-1642`) already imply the
|
|
| 60 | + lower rungs, so only the max level needs to be set.
|
|
| 61 | +- BMI1/BMI2 → highest present → `bmiVersion :: Maybe BmiVersion`.
|
|
| 62 | +- `AVX512F` + per-extension features → the individual bools `avx512f`, `avx512bw`,
|
|
| 63 | + `avx512cd`, `avx512dq`, `avx512vl`.
|
|
| 64 | +- `FMA` → `fma`; `GFNI` → `gfni`.
|
|
| 65 | +- `SSE2` is the x86_64 baseline (determined by the platform, not a flag) — nothing to set.
|
|
| 66 | + |
|
| 67 | +### 4. Probe caching
|
|
| 68 | +CPUID results are constant for the lifetime of the process, but `parseDynamicFlagsFull` runs
|
|
| 69 | +per command-line *and* per file pragma. Memoize the probe once (top-level CAF backed by
|
|
| 70 | +`unsafePerformIO` with `{-# NOINLINE #-}`, or detect once and thread the result) so repeated
|
|
| 71 | +`-march=native` uses don't re-probe.
|
|
| 72 | + |
|
| 73 | +### 5. Diagnostics and errors
|
|
| 74 | +- Unsupported arch: clear error that `-march=native` is x86/x86_64-only.
|
|
| 75 | +- Cross mode: clear error that `-march=native` is unavailable for cross-compilation.
|
|
| 76 | +- The probe is in-process and returns a `Word64`; there is no subprocess, command, or stderr
|
|
| 77 | + to report. The only anomaly is a probe returning `0` (or lacking SSE2 on x86_64, where it is
|
|
| 78 | + baseline) — treat that as an internal error with a short diagnostic. (The earlier
|
|
| 79 | + "failing command + brief stderr" wording referred to an abandoned toolchain-probe approach
|
|
| 80 | + and no longer applies.)
|
|
| 81 | + |
|
| 82 | +### 6. Backend behavior
|
|
| 83 | +- NCG and LLVM are both driven by the same CPU-feature `DynFlags`, so no backend wiring
|
|
| 84 | + changes are needed — populating the fields in §3 is sufficient.
|
|
| 85 | + |
|
| 86 | +### 7. Verification via `--print-enabled-cpu-features`
|
|
| 87 | +- The base branch already prints effective enabled features as single-line JSON:
|
|
| 88 | + `{"tag":"enabled-cpu-features","version":1,"target":<triple>,"features":[…],"as_m_flags":[…]}`
|
|
| 89 | + with conventional names (`SSE4.2`, `AVX2`, `BMI2`) in canonical order.
|
|
| 90 | +- `-march=native` must update the same `DynFlags` fields this mode reads, so its effect is
|
|
| 91 | + observable through `ghc -march=native --print-enabled-cpu-features`.
|
|
| 92 | + |
|
| 93 | +### 8. Documentation
|
|
| 94 | +- File: `docs/users_guide/using.rst`, alongside the other `-m...` options.
|
|
| 95 | +- Describe: host CPU detection, x86/x86_64 only, non-cross only, positional, equivalent to
|
|
| 96 | + enabling the matching `-m...` options automatically.
|
|
| 97 | +- Add a `changelog.d/` entry (the base branch already adds `changelog.d/print-enabled-cpu-features`).
|
|
| 98 | + |
|
| 99 | +## Tests and Scenarios
|
|
| 100 | +Lead with `--print-enabled-cpu-features` for deterministic, host-independent assertions.
|
|
| 101 | + |
|
| 102 | +1. **Baseline (deterministic):** on x86_64, `ghc -march=native --print-enabled-cpu-features`
|
|
| 103 | + always lists `SSE2` in `features`.
|
|
| 104 | +2. **Superset:** `features(-march=native)` ⊇ `features()` (run the print mode with and without
|
|
| 105 | + the flag and compare). Avoids hard-coding host-specific feature sets.
|
|
| 106 | +3. **Additive:** an explicit `-m...` combined with `-march=native` yields the union (the
|
|
| 107 | + explicit feature is still present regardless of flag order).
|
|
| 108 | +4. **Arch / cross guards:** compile-fail test for a non-x86 target and/or a cross context,
|
|
| 109 | + asserting the §5 error messages.
|
|
| 110 | +5. **Optional NCG end-to-end:** one host-gated asm-grep test under
|
|
| 111 | + `testsuite/tests/codeGen/should_gen_asm` showing `-march=native` enables an expected x86
|
|
| 112 | + instruction path. Keep it secondary to the print-mode tests; do not rely on it as the main
|
|
| 113 | + signal. (There is no longer a meaningful probe-failure compile-fail test, since the probe
|
|
| 114 | + has no external tool to break.)
|
|
| 115 | + |
|
| 116 | +## Open Questions
|
|
| 117 | +1. **Cross-compilation detection.** *Resolved.* The guard compares the target arch against the
|
|
| 118 | + build-host arch: `arch == hostPlatformArch` in `applyMarchNative` (`Session.hs:3831`). A
|
|
| 119 | + mismatch raises the cross-compilation error from §5.
|
|
| 120 | +2. **File-pragma scope.** *Resolved (permitted).* `applyMarchNative` runs in the shared
|
|
| 121 | + `parseDynamicFlagsFull` (`Session.hs:913`), so `-march=native` also takes effect in
|
|
| 122 | + `{-# OPTIONS_GHC #-}`. Repeated probing is harmless because the probe is memoized
|
|
| 123 | + (`cachedX86CpuFeatures`, §4).
|
|
| 124 | + |
|
| 125 | +## Status
|
|
| 126 | +1. Done: CPUID/XGETBV probe in `compiler/cbits/cpu_features_x86.c`.
|
|
| 127 | +2. Done: decoder + naming in `compiler/GHC/Driver/CpuFeatures.hs`.
|
|
| 128 | +3. Done: cabal wiring in `compiler/ghc.cabal.in`.
|
|
| 129 | +4. Done (base branch): `--print-enabled-cpu-features` + `enabledCpuFeatures` reporting.
|
|
| 130 | +5. Done: `marchNative` marker field in `DynFlags` (`DynFlags.hs:473,765`); flag registration
|
|
| 131 | + in `Session.hs:1752`.
|
|
| 132 | +6. Done: IO application step `applyMarchNative` in `parseDynamicFlagsFull`
|
|
| 133 | + (`Session.hs:3816`) — arch guard, cross guard, and the ladder mapping in
|
|
| 134 | + `applyX86CpuFeatures` (`Session.hs:3839`).
|
|
| 135 | +7. Done: probe caching via `cachedX86CpuFeatures` (top-level CAF, `NOINLINE`,
|
|
| 136 | + `CpuFeatures.hs:89`).
|
|
| 137 | +8. Done: docs (`docs/users_guide/using.rst:1857`) and changelog (`changelog.d/march-native`).
|
|
| 138 | +9. Tests. In `testsuite/tests/driver`: baseline SSE2 (`march_native`, §1), arch guard
|
|
| 139 | + (`march_native_unsupported_arch`, §4), superset (`march_native_superset`, §2), and additive
|
|
| 140 | + (`march_native_additive`, §3). In `testsuite/tests/codeGen/should_gen_asm`: NCG asm-grep
|
|
| 141 | + (`march-native-enables-popcnt`, §5) — gated on the host having SSE4.2 via
|
|
| 142 | + `have_cpu_feature`, so it deterministically expects a `popcnt` instruction. |
| 1 | +section: compiler
|
|
| 2 | +synopsis: Add -march=native flag
|
|
| 3 | +issues: #25450
|
|
| 4 | + |
|
| 5 | +description:
|
|
| 6 | + GHC now supports ``-march=native`` on x86 and x86_64. It probes the CPU of the
|
|
| 7 | + machine running GHC and enables all of the corresponding ``-m...`` CPU-feature
|
|
| 8 | + options automatically (such as ``-msse4.2``, ``-mavx2``, ``-mbmi2`` and
|
|
| 9 | + ``-mfma``), for both the native code generator and the LLVM backend. The
|
|
| 10 | + detected features are enabled in addition to any explicitly requested feature
|
|
| 11 | + flags. The flag is rejected for non-x86 targets and when cross-compiling. |
| 1 | +section: compiler
|
|
| 2 | +synopsis: Add --print-enabled-cpu-features flag
|
|
| 3 | +issues: #25450
|
|
| 4 | +mrs: !16117
|
|
| 5 | + |
|
| 6 | +description:
|
|
| 7 | + GHC now supports a new mode flag ``--print-enabled-cpu-features``, which
|
|
| 8 | + prints a JSON object describing the CPU features currently enabled for code
|
|
| 9 | + generation, together with a set of ``-m...`` flags that reproduce the
|
|
| 10 | + effective feature set for the current target.
|
|
| 11 | + Dynamic options such as ``-mavx2`` and ``-mbmi2`` are respected. ::
|
|
| 12 | + |
|
| 13 | + $ ghc -mavx2 --print-enabled-cpu-features
|
|
| 14 | + {"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"]} |
| 1 | +{-# LANGUAGE CPP #-}
|
|
| 2 | + |
|
| 3 | +module GHC.Driver.CpuFeatures
|
|
| 4 | + ( X86CpuFeature(..)
|
|
| 5 | + , detectX86CpuFeatureMask
|
|
| 6 | + , detectX86CpuFeatures
|
|
| 7 | + , cachedX86CpuFeatures
|
|
| 8 | + , decodeX86CpuFeatureMask
|
|
| 9 | + , x86CpuFeatureConventionalName
|
|
| 10 | + ) where
|
|
| 11 | + |
|
| 12 | +import GHC.Prelude
|
|
| 13 | + |
|
| 14 | +import Data.Bits (testBit)
|
|
| 15 | +import Data.Word (Word64)
|
|
| 16 | +import System.IO.Unsafe (unsafePerformIO)
|
|
| 17 | + |
|
| 18 | +-- | x86 CPU features understood by GHC's native CPU feature probe.
|
|
| 19 | +--
|
|
| 20 | +-- The constructor order and decode order below are canonicalized for stable
|
|
| 21 | +-- debug output.
|
|
| 22 | +data X86CpuFeature
|
|
| 23 | + = SSE2
|
|
| 24 | + | SSE3
|
|
| 25 | + | SSSE3
|
|
| 26 | + | SSE4_1
|
|
| 27 | + | SSE4_2
|
|
| 28 | + | AVX
|
|
| 29 | + | AVX2
|
|
| 30 | + | AVX512F
|
|
| 31 | + | AVX512BW
|
|
| 32 | + | AVX512CD
|
|
| 33 | + | AVX512DQ
|
|
| 34 | + | AVX512VL
|
|
| 35 | + | BMI1
|
|
| 36 | + | BMI2
|
|
| 37 | + | FMA
|
|
| 38 | + | GFNI
|
|
| 39 | + deriving (Eq, Ord, Show)
|
|
| 40 | + |
|
| 41 | +-- | Human-readable names used in the JSON/debug output.
|
|
| 42 | +x86CpuFeatureConventionalName :: X86CpuFeature -> String
|
|
| 43 | +x86CpuFeatureConventionalName feat = case feat of
|
|
| 44 | + SSE2 -> "SSE2"
|
|
| 45 | + SSE3 -> "SSE3"
|
|
| 46 | + SSSE3 -> "SSSE3"
|
|
| 47 | + SSE4_1 -> "SSE4.1"
|
|
| 48 | + SSE4_2 -> "SSE4.2"
|
|
| 49 | + AVX -> "AVX"
|
|
| 50 | + AVX2 -> "AVX2"
|
|
| 51 | + AVX512F -> "AVX512F"
|
|
| 52 | + AVX512BW -> "AVX512BW"
|
|
| 53 | + AVX512CD -> "AVX512CD"
|
|
| 54 | + AVX512DQ -> "AVX512DQ"
|
|
| 55 | + AVX512VL -> "AVX512VL"
|
|
| 56 | + BMI1 -> "BMI1"
|
|
| 57 | + BMI2 -> "BMI2"
|
|
| 58 | + FMA -> "FMA"
|
|
| 59 | + GFNI -> "GFNI"
|
|
| 60 | + |
|
| 61 | +-- | Decode the bitmask returned by 'ghc_detect_x86_cpu_features'.
|
|
| 62 | +--
|
|
| 63 | +-- NOTE: Bit positions must match the enum in @compiler/cbits/cpu_features_x86.c@.
|
|
| 64 | +decodeX86CpuFeatureMask :: Word64 -> [X86CpuFeature]
|
|
| 65 | +decodeX86CpuFeatureMask mask =
|
|
| 66 | + [ feat
|
|
| 67 | + | (bit_ix, feat) <- cpuFeatureBitLayout
|
|
| 68 | + , testBit mask bit_ix
|
|
| 69 | + ]
|
|
| 70 | + |
|
| 71 | +-- | Low-level FFI access to the C probe.
|
|
| 72 | +detectX86CpuFeatureMask :: IO Word64
|
|
| 73 | +#if defined(javascript_HOST_ARCH)
|
|
| 74 | +detectX86CpuFeatureMask = pure 0
|
|
| 75 | +#else
|
|
| 76 | +detectX86CpuFeatureMask = c_ghc_detect_x86_cpu_features
|
|
| 77 | +#endif
|
|
| 78 | + |
|
| 79 | +-- | Probe host x86 CPU features and decode them into an ordered feature list.
|
|
| 80 | +detectX86CpuFeatures :: IO [X86CpuFeature]
|
|
| 81 | +detectX86CpuFeatures = decodeX86CpuFeatureMask <$> detectX86CpuFeatureMask
|
|
| 82 | + |
|
| 83 | +-- | The host's x86 CPU features, probed once and memoized.
|
|
| 84 | +--
|
|
| 85 | +-- CPUID results are constant for the lifetime of the process, so probing more
|
|
| 86 | +-- than once (e.g. once per @-march=native@ in a command line or file pragma)
|
|
| 87 | +-- is wasteful. This is referentially transparent despite the FFI call.
|
|
| 88 | +cachedX86CpuFeatures :: [X86CpuFeature]
|
|
| 89 | +cachedX86CpuFeatures = unsafePerformIO detectX86CpuFeatures
|
|
| 90 | +{-# NOINLINE cachedX86CpuFeatures #-}
|
|
| 91 | + |
|
| 92 | +cpuFeatureBitLayout :: [(Int, X86CpuFeature)]
|
|
| 93 | +cpuFeatureBitLayout =
|
|
| 94 | + [ (0, SSE2)
|
|
| 95 | + , (1, SSE3)
|
|
| 96 | + , (2, SSSE3)
|
|
| 97 | + , (3, SSE4_1)
|
|
| 98 | + , (4, SSE4_2)
|
|
| 99 | + , (5, AVX)
|
|
| 100 | + , (6, AVX2)
|
|
| 101 | + , (7, AVX512F)
|
|
| 102 | + , (8, AVX512BW)
|
|
| 103 | + , (9, AVX512CD)
|
|
| 104 | + , (10, AVX512DQ)
|
|
| 105 | + , (11, AVX512VL)
|
|
| 106 | + , (12, BMI1)
|
|
| 107 | + , (13, BMI2)
|
|
| 108 | + , (14, FMA)
|
|
| 109 | + , (15, GFNI)
|
|
| 110 | + ]
|
|
| 111 | + |
|
| 112 | +#if !defined(javascript_HOST_ARCH)
|
|
| 113 | +foreign import ccall unsafe "ghc_detect_x86_cpu_features"
|
|
| 114 | + c_ghc_detect_x86_cpu_features :: IO Word64
|
|
| 115 | +#endif |
| ... | ... | @@ -470,6 +470,8 @@ data DynFlags = DynFlags { |
| 470 | 470 | fma :: Bool, -- ^ Enable FMA instructions.
|
| 471 | 471 | gfni :: Bool, -- ^ Enable GFNI Instructions.
|
| 472 | 472 | la664 :: Bool, -- ^ Enable LA664 instructions
|
| 473 | + marchNative :: Bool, -- ^ @-march=native@ was requested; the host
|
|
| 474 | + -- CPU features are applied during flag parsing.
|
|
| 473 | 475 | |
| 474 | 476 | -- Constants used to control the amount of optimization done.
|
| 475 | 477 | |
| ... | ... | @@ -760,6 +762,7 @@ defaultDynFlags mySettings = |
| 760 | 762 | gfni = False,
|
| 761 | 763 | -- For LoongArch, la464 is used by default.
|
| 762 | 764 | la664 = False,
|
| 765 | + marchNative = False,
|
|
| 763 | 766 | |
| 764 | 767 | maxInlineAllocSize = 128,
|
| 765 | 768 | maxInlineMemcpyInsns = 32,
|
| ... | ... | @@ -1615,6 +1618,7 @@ initPromotionTickContext dflags = |
| 1615 | 1618 | |
| 1616 | 1619 | -- -----------------------------------------------------------------------------
|
| 1617 | 1620 | -- SSE, AVX, FMA
|
| 1621 | +-- See Note [Keeping enabledCpuFeatures in sync] in GHC.Driver.Session
|
|
| 1618 | 1622 | |
| 1619 | 1623 | isSse3Enabled :: DynFlags -> Bool
|
| 1620 | 1624 | isSse3Enabled dflags = sseAvxVersion dflags >= Just SSE3 || isAvxEnabled dflags
|
| ... | ... | @@ -1705,11 +1709,14 @@ We handle this as follows: |
| 1705 | 1709 | |
| 1706 | 1710 | -- -----------------------------------------------------------------------------
|
| 1707 | 1711 | -- LA664
|
| 1712 | +-- See Note [Keeping enabledCpuFeatures in sync] in GHC.Driver.Session
|
|
| 1713 | + |
|
| 1708 | 1714 | isLa664Enabled :: DynFlags -> Bool
|
| 1709 | 1715 | isLa664Enabled dflags = la664 dflags
|
| 1710 | 1716 | |
| 1711 | 1717 | -- -----------------------------------------------------------------------------
|
| 1712 | 1718 | -- BMI2
|
| 1719 | +-- See Note [Keeping enabledCpuFeatures in sync] in GHC.Driver.Session
|
|
| 1713 | 1720 | |
| 1714 | 1721 | isBmiEnabled :: DynFlags -> Bool
|
| 1715 | 1722 | isBmiEnabled dflags = case platformArch (targetPlatform dflags) of
|
| ... | ... | @@ -196,6 +196,8 @@ module GHC.Driver.Session ( |
| 196 | 196 | |
| 197 | 197 | -- * Compiler configuration suitable for display to the user
|
| 198 | 198 | compilerInfo,
|
| 199 | + showEnabledCpuFeatures,
|
|
| 200 | + enabledCpuFeatures,
|
|
| 199 | 201 | |
| 200 | 202 | targetHasRTSWays,
|
| 201 | 203 | |
| ... | ... | @@ -243,6 +245,8 @@ import GHC.Platform |
| 243 | 245 | import GHC.Platform.Ways
|
| 244 | 246 | import GHC.Platform.Profile
|
| 245 | 247 | import GHC.Platform.ArchOS
|
| 248 | +import GHC.Platform.Host (hostPlatformArch)
|
|
| 249 | +import qualified GHC.Driver.CpuFeatures as Cpu
|
|
| 246 | 250 | |
| 247 | 251 | import GHC.Unit.Types
|
| 248 | 252 | import GHC.Unit.Parser
|
| ... | ... | @@ -277,6 +281,7 @@ import GHC.Utils.TmpFs |
| 277 | 281 | import GHC.Utils.Fingerprint
|
| 278 | 282 | import GHC.Utils.Outputable
|
| 279 | 283 | import GHC.Utils.Error (emptyDiagOpts, logInfo)
|
| 284 | +import GHC.Utils.Json
|
|
| 280 | 285 | import GHC.Settings
|
| 281 | 286 | import GHC.CmmToAsm.CFG.Weight
|
| 282 | 287 | import GHC.Core.Opt.CallerCC
|
| ... | ... | @@ -903,8 +908,12 @@ parseDynamicFlagsFull activeFlags cmdline logger dflags0 args = do |
| 903 | 908 | unless (null errs) $ liftIO $ throwGhcExceptionIO $ errorsToGhcException $
|
| 904 | 909 | map ((rdr . ppr . getLoc &&& unLoc) . errMsg) $ errs
|
| 905 | 910 | |
| 911 | + -- Apply -march=native: probe the host CPU and enable the matching feature
|
|
| 912 | + -- flags. This needs IO (CPUID), so it cannot live in the pure flag handlers.
|
|
| 913 | + dflags1' <- applyMarchNative dflags1
|
|
| 914 | + |
|
| 906 | 915 | -- check for disabled flags in safe haskell
|
| 907 | - let (dflags2, sh_warns) = safeFlagCheck cmdline dflags1
|
|
| 916 | + let (dflags2, sh_warns) = safeFlagCheck cmdline dflags1'
|
|
| 908 | 917 | theWays = ways dflags2
|
| 909 | 918 | |
| 910 | 919 | unless (allowed_combination theWays) $ liftIO $
|
| ... | ... | @@ -1740,6 +1749,7 @@ dynamic_flags_deps = [ |
| 1740 | 1749 | , make_ord_flag defGhcFlag "mavx512vl" (noArg (\d -> d { avx512vl = True }))
|
| 1741 | 1750 | , make_ord_flag defGhcFlag "mfma" (noArg (\d -> d { fma = True }))
|
| 1742 | 1751 | , make_ord_flag defGhcFlag "mgfni" (noArg (\d -> d { gfni = True }))
|
| 1752 | + , make_ord_flag defGhcFlag "march=native" (noArg (\d -> d { marchNative = True }))
|
|
| 1743 | 1753 | |
| 1744 | 1754 | |
| 1745 | 1755 | , make_ord_flag defGhcFlag "mla664" (noArg (\d -> d { la664 = True }))
|
| ... | ... | @@ -3677,6 +3687,185 @@ compilerInfo dflags |
| 3677 | 3687 | queryCmdMaybe p f = expandDirectories (query (maybe "" (prgPath . p) . f))
|
| 3678 | 3688 | queryFlagsMaybe p f = query (maybe "" (unwords . map escapeArg . prgFlags . p) . f)
|
| 3679 | 3689 | |
| 3690 | +showEnabledCpuFeatures :: DynFlags -> String
|
|
| 3691 | +showEnabledCpuFeatures dflags = showSDocUnsafe $ renderJSON $ JSObject
|
|
| 3692 | + [ ("tag", JSString "enabled-cpu-features")
|
|
| 3693 | + -- Schema version of this JSON object; bump it whenever the shape or
|
|
| 3694 | + -- meaning of the fields changes, so consumers can detect incompatibility.
|
|
| 3695 | + , ("version", JSInt 1)
|
|
| 3696 | + , ("target", JSString (platformMisc_targetPlatformString (platformMisc dflags)))
|
|
| 3697 | + , ("features", JSArray (map JSString features))
|
|
| 3698 | + -- A set of `-m...` flags that, passed to GHC for this target, reproduce
|
|
| 3699 | + -- the effective feature set above. Note this need not be the flags the
|
|
| 3700 | + -- user actually passed: implied features are folded in, and a feature
|
|
| 3701 | + -- enabled by default may be reproduced by the empty set.
|
|
| 3702 | + , ("as_m_flags", JSArray (map JSString asMFlags))
|
|
| 3703 | + ]
|
|
| 3704 | + where
|
|
| 3705 | + (features, asMFlags) = enabledCpuFeatures dflags
|
|
| 3706 | + |
|
| 3707 | +{- Note [Keeping enabledCpuFeatures in sync]
|
|
| 3708 | +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
| 3709 | +`enabledCpuFeatures` must be updated whenever a new CPU feature flag is added
|
|
| 3710 | +to GHC. The three places to touch are, all in GHC.Driver.DynFlags:
|
|
| 3711 | + |
|
| 3712 | + 1. The flag registration (e.g. `make_ord_flag defGhcFlag "mnewfeat" ...`)
|
|
| 3713 | + 2. The corresponding `is*Enabled` predicate
|
|
| 3714 | + 3. The `enabledCpuFeatures` function below — add the feature to `features`
|
|
| 3715 | + and, if it has a GHC `-m...` flag, to `as_m_flags` via the appropriate
|
|
| 3716 | + architecture branch.
|
|
| 3717 | + |
|
| 3718 | +See Note [Implications between X86 CPU feature flags] in GHC.Driver.DynFlags
|
|
| 3719 | +for the implication structure that `x86FeaturesAndFlags` and `x86AsMFlags`
|
|
| 3720 | +must respect.
|
|
| 3721 | +-}
|
|
| 3722 | + |
|
| 3723 | +enabledCpuFeatures :: DynFlags -> ([String], [String])
|
|
| 3724 | +enabledCpuFeatures dflags = case platformArch (targetPlatform dflags) of
|
|
| 3725 | + ArchX86_64 -> x86FeaturesAndFlags dflags
|
|
| 3726 | + ArchX86 -> x86FeaturesAndFlags dflags
|
|
| 3727 | + ArchLoongArch64 ->
|
|
| 3728 | + ( fmaFeature ++ [ "LA664" | isLa664Enabled dflags ]
|
|
| 3729 | + , fmaFlag ++ [ "-mla664" | isLa664Enabled dflags ]
|
|
| 3730 | + )
|
|
| 3731 | + _ -> (fmaFeature, fmaFlag)
|
|
| 3732 | + where
|
|
| 3733 | + -- `-mfma` is a cross-platform flag. On x86 it is folded into the
|
|
| 3734 | + -- SSE/AVX hierarchy (handled in x86FeaturesAndFlags); on every other
|
|
| 3735 | + -- architecture FMA stands on its own and gates FMA codegen via
|
|
| 3736 | + -- isFmaEnabled in stgToCmmAllowFMAInstr. `fma dflags` is the source of
|
|
| 3737 | + -- truth (it defaults to True on AArch64).
|
|
| 3738 | + fmaFeature = [ "FMA" | fma dflags ]
|
|
| 3739 | + fmaFlag = [ "-mfma" | fma dflags ]
|
|
| 3740 | + |
|
| 3741 | +x86FeaturesAndFlags :: DynFlags -> ([String], [String])
|
|
| 3742 | +x86FeaturesAndFlags dflags =
|
|
| 3743 | + -- SSE/SSE2 are determined by the target platform rather than a dynamic
|
|
| 3744 | + -- flag, hence those predicates take Platform while the others take DynFlags.
|
|
| 3745 | + ( [ "SSE" | isSseEnabled platform ]
|
|
| 3746 | + ++ [ "SSE2" | isSse2Enabled platform ]
|
|
| 3747 | + ++ [ "SSE3" | isSse3Enabled dflags ]
|
|
| 3748 | + ++ [ "SSSE3" | isSsse3Enabled dflags ]
|
|
| 3749 | + ++ [ "SSE4.1" | isSse4_1Enabled dflags ]
|
|
| 3750 | + ++ [ "SSE4.2" | isSse4_2Enabled dflags ]
|
|
| 3751 | + ++ [ "AVX" | isAvxEnabled dflags ]
|
|
| 3752 | + ++ [ "AVX2" | isAvx2Enabled dflags ]
|
|
| 3753 | + ++ [ "AVX512F" | isAvx512fEnabled dflags ]
|
|
| 3754 | + ++ [ "AVX512BW" | isAvx512bwEnabled dflags ]
|
|
| 3755 | + ++ [ "AVX512CD" | isAvx512cdEnabled dflags ]
|
|
| 3756 | + ++ [ "AVX512DQ" | isAvx512dqEnabled dflags ]
|
|
| 3757 | + ++ [ "AVX512ER" | isAvx512erEnabled dflags ]
|
|
| 3758 | + ++ [ "AVX512PF" | isAvx512pfEnabled dflags ]
|
|
| 3759 | + ++ [ "AVX512VL" | isAvx512vlEnabled dflags ]
|
|
| 3760 | + ++ [ "BMI1" | isBmiEnabled dflags ]
|
|
| 3761 | + ++ [ "BMI2" | isBmi2Enabled dflags ]
|
|
| 3762 | + ++ [ "FMA" | isFmaEnabled dflags ]
|
|
| 3763 | + ++ [ "GFNI" | isGfniEnabled dflags ]
|
|
| 3764 | + , x86AsMFlags dflags
|
|
| 3765 | + )
|
|
| 3766 | + where
|
|
| 3767 | + platform = targetPlatform dflags
|
|
| 3768 | + |
|
| 3769 | +x86AsMFlags :: DynFlags -> [String]
|
|
| 3770 | +x86AsMFlags dflags =
|
|
| 3771 | + avx512Flags
|
|
| 3772 | + ++ vectorFlags
|
|
| 3773 | + ++ bmiFlags
|
|
| 3774 | + ++ fmaFlags
|
|
| 3775 | + ++ gfniFlags
|
|
| 3776 | + where
|
|
| 3777 | + avx512Extensions =
|
|
| 3778 | + [ ("-mavx512bw", avx512bw dflags)
|
|
| 3779 | + , ("-mavx512cd", avx512cd dflags)
|
|
| 3780 | + , ("-mavx512dq", avx512dq dflags)
|
|
| 3781 | + , ("-mavx512er", avx512er dflags)
|
|
| 3782 | + , ("-mavx512pf", avx512pf dflags)
|
|
| 3783 | + , ("-mavx512vl", avx512vl dflags)
|
|
| 3784 | + ]
|
|
| 3785 | + |
|
| 3786 | + hasAvx512Extension = any snd avx512Extensions
|
|
| 3787 | + hasAvx512 = avx512f dflags || hasAvx512Extension
|
|
| 3788 | + |
|
| 3789 | + avx512Flags =
|
|
| 3790 | + [ "-mavx512f" | avx512f dflags && not hasAvx512Extension ]
|
|
| 3791 | + ++ [ flag | (flag, True) <- avx512Extensions ]
|
|
| 3792 | + |
|
| 3793 | + vectorFlags
|
|
| 3794 | + | hasAvx512 = []
|
|
| 3795 | + | otherwise =
|
|
| 3796 | + case sseAvxVersion dflags of
|
|
| 3797 | + Just AVX2 -> ["-mavx2"]
|
|
| 3798 | + Just AVX1 -> ["-mavx"]
|
|
| 3799 | + Just SSE42 -> ["-msse4.2"]
|
|
| 3800 | + Just SSE4 -> ["-msse4"]
|
|
| 3801 | + Just SSSE3 -> ["-mssse3"]
|
|
| 3802 | + Just SSE3 -> ["-msse3"]
|
|
| 3803 | + _ -> []
|
|
| 3804 | + |
|
| 3805 | + bmiFlags = case bmiVersion dflags of
|
|
| 3806 | + Just BMI2 -> ["-mbmi2"]
|
|
| 3807 | + Just BMI1 -> ["-mbmi"]
|
|
| 3808 | + Nothing -> []
|
|
| 3809 | + |
|
| 3810 | + fmaFlags
|
|
| 3811 | + | fma dflags && not hasAvx512 = ["-mfma"]
|
|
| 3812 | + | otherwise = []
|
|
| 3813 | + |
|
| 3814 | + gfniFlags = [ "-mgfni" | gfni dflags ]
|
|
| 3815 | + |
|
| 3816 | +-- | Apply a requested @-march=native@ by probing the host CPU and enabling the
|
|
| 3817 | +-- matching CPU-feature flags.
|
|
| 3818 | +--
|
|
| 3819 | +-- This runs in 'parseDynamicFlagsFull' rather than in a flag handler because the
|
|
| 3820 | +-- CPUID probe needs 'IO', whereas flag handlers are pure. The detected features
|
|
| 3821 | +-- are folded into the existing feature 'DynFlags' so that 'makeDynFlagsConsistent'
|
|
| 3822 | +-- and the backends treat them exactly like the corresponding @-m...@ flags.
|
|
| 3823 | +applyMarchNative :: MonadIO m => DynFlags -> m DynFlags
|
|
| 3824 | +applyMarchNative dflags
|
|
| 3825 | + | not (marchNative dflags) = return dflags
|
|
| 3826 | + | otherwise = do
|
|
| 3827 | + let arch = platformArch (targetPlatform dflags)
|
|
| 3828 | + unless (arch == ArchX86 || arch == ArchX86_64) $ liftIO $
|
|
| 3829 | + throwGhcExceptionIO $ CmdLineError
|
|
| 3830 | + "-march=native is only supported on x86 and x86_64 targets"
|
|
| 3831 | + unless (arch == hostPlatformArch) $ liftIO $
|
|
| 3832 | + throwGhcExceptionIO $ CmdLineError
|
|
| 3833 | + "-march=native is not supported when cross-compiling"
|
|
| 3834 | + return (applyX86CpuFeatures Cpu.cachedX86CpuFeatures dflags)
|
|
| 3835 | + |
|
| 3836 | +-- | Enable the 'DynFlags' CPU-feature fields corresponding to a probed set of
|
|
| 3837 | +-- host x86 features. SSE/AVX and BMI levels are collapsed to their maximum,
|
|
| 3838 | +-- since 'sseAvxVersion' and 'bmiVersion' each record a single level.
|
|
| 3839 | +applyX86CpuFeatures :: [Cpu.X86CpuFeature] -> DynFlags -> DynFlags
|
|
| 3840 | +applyX86CpuFeatures feats dflags = dflags
|
|
| 3841 | + { sseAvxVersion = foldr (max . Just) (sseAvxVersion dflags) sseLevels
|
|
| 3842 | + , bmiVersion = foldr (max . Just) (bmiVersion dflags) bmiLevels
|
|
| 3843 | + , avx512f = avx512f dflags || has Cpu.AVX512F
|
|
| 3844 | + , avx512bw = avx512bw dflags || has Cpu.AVX512BW
|
|
| 3845 | + , avx512cd = avx512cd dflags || has Cpu.AVX512CD
|
|
| 3846 | + , avx512dq = avx512dq dflags || has Cpu.AVX512DQ
|
|
| 3847 | + , avx512vl = avx512vl dflags || has Cpu.AVX512VL
|
|
| 3848 | + , fma = fma dflags || has Cpu.FMA
|
|
| 3849 | + , gfni = gfni dflags || has Cpu.GFNI
|
|
| 3850 | + }
|
|
| 3851 | + where
|
|
| 3852 | + has feat = feat `elem` feats
|
|
| 3853 | + sseLevels = [ lvl | feat <- feats, Just lvl <- [sseLevelOf feat] ]
|
|
| 3854 | + bmiLevels = [ lvl | feat <- feats, Just lvl <- [bmiLevelOf feat] ]
|
|
| 3855 | + sseLevelOf feat = case feat of
|
|
| 3856 | + Cpu.SSE2 -> Just SSE2
|
|
| 3857 | + Cpu.SSE3 -> Just SSE3
|
|
| 3858 | + Cpu.SSSE3 -> Just SSSE3
|
|
| 3859 | + Cpu.SSE4_1 -> Just SSE4
|
|
| 3860 | + Cpu.SSE4_2 -> Just SSE42
|
|
| 3861 | + Cpu.AVX -> Just AVX1
|
|
| 3862 | + Cpu.AVX2 -> Just AVX2
|
|
| 3863 | + _ -> Nothing
|
|
| 3864 | + bmiLevelOf feat = case feat of
|
|
| 3865 | + Cpu.BMI1 -> Just BMI1
|
|
| 3866 | + Cpu.BMI2 -> Just BMI2
|
|
| 3867 | + _ -> Nothing
|
|
| 3868 | + |
|
| 3680 | 3869 | -- | Query if the target RTS has the given 'Ways'. It's computed from
|
| 3681 | 3870 | -- the @"RTS ways"@ field in the settings file.
|
| 3682 | 3871 | targetHasRTSWays :: DynFlags -> Ways -> Bool
|
| 1 | +#include <HsFFI.h>
|
|
| 2 | +#include <stdint.h>
|
|
| 3 | + |
|
| 4 | +#if defined(_MSC_VER) && (defined(_M_IX86) || defined(_M_X64))
|
|
| 5 | +#include <immintrin.h>
|
|
| 6 | +#include <intrin.h>
|
|
| 7 | +#endif
|
|
| 8 | + |
|
| 9 | +#if !defined(_MSC_VER) && (defined(__i386__) || defined(__x86_64__))
|
|
| 10 | +#include <cpuid.h>
|
|
| 11 | +#endif
|
|
| 12 | + |
|
| 13 | +enum {
|
|
| 14 | + GHC_X86_FEAT_SSE2 = 0,
|
|
| 15 | + GHC_X86_FEAT_SSE3,
|
|
| 16 | + GHC_X86_FEAT_SSSE3,
|
|
| 17 | + GHC_X86_FEAT_SSE4_1,
|
|
| 18 | + GHC_X86_FEAT_SSE4_2,
|
|
| 19 | + GHC_X86_FEAT_AVX,
|
|
| 20 | + GHC_X86_FEAT_AVX2,
|
|
| 21 | + GHC_X86_FEAT_AVX512F,
|
|
| 22 | + GHC_X86_FEAT_AVX512BW,
|
|
| 23 | + GHC_X86_FEAT_AVX512CD,
|
|
| 24 | + GHC_X86_FEAT_AVX512DQ,
|
|
| 25 | + GHC_X86_FEAT_AVX512VL,
|
|
| 26 | + GHC_X86_FEAT_BMI1,
|
|
| 27 | + GHC_X86_FEAT_BMI2,
|
|
| 28 | + GHC_X86_FEAT_FMA,
|
|
| 29 | + GHC_X86_FEAT_GFNI
|
|
| 30 | +};
|
|
| 31 | + |
|
| 32 | +#define SET_FEAT(mask, bit) ((mask) |= ((HsWord64)1ULL << (bit)))
|
|
| 33 | + |
|
| 34 | +static int ghc_cpuid_count(uint32_t leaf, uint32_t subleaf,
|
|
| 35 | + uint32_t *a, uint32_t *b, uint32_t *c, uint32_t *d)
|
|
| 36 | +{
|
|
| 37 | +#if defined(_MSC_VER) && (defined(_M_IX86) || defined(_M_X64))
|
|
| 38 | + int regs[4];
|
|
| 39 | + __cpuidex(regs, (int)leaf, (int)subleaf);
|
|
| 40 | + *a = (uint32_t)regs[0];
|
|
| 41 | + *b = (uint32_t)regs[1];
|
|
| 42 | + *c = (uint32_t)regs[2];
|
|
| 43 | + *d = (uint32_t)regs[3];
|
|
| 44 | + return 1;
|
|
| 45 | +#elif defined(__i386__) || defined(__x86_64__)
|
|
| 46 | + return __get_cpuid_count(leaf, subleaf, a, b, c, d);
|
|
| 47 | +#else
|
|
| 48 | + (void)leaf;
|
|
| 49 | + (void)subleaf;
|
|
| 50 | + (void)a;
|
|
| 51 | + (void)b;
|
|
| 52 | + (void)c;
|
|
| 53 | + (void)d;
|
|
| 54 | + return 0;
|
|
| 55 | +#endif
|
|
| 56 | +}
|
|
| 57 | + |
|
| 58 | +static uint64_t ghc_xgetbv0(void)
|
|
| 59 | +{
|
|
| 60 | +#if defined(_MSC_VER) && (defined(_M_IX86) || defined(_M_X64))
|
|
| 61 | + return (uint64_t)_xgetbv(0);
|
|
| 62 | +#elif defined(__i386__) || defined(__x86_64__)
|
|
| 63 | + uint32_t eax, edx;
|
|
| 64 | + __asm__ volatile(".byte 0x0f, 0x01, 0xd0" /* xgetbv */
|
|
| 65 | + : "=a"(eax), "=d"(edx)
|
|
| 66 | + : "c"(0));
|
|
| 67 | + return ((uint64_t)edx << 32) | (uint64_t)eax;
|
|
| 68 | +#else
|
|
| 69 | + return 0;
|
|
| 70 | +#endif
|
|
| 71 | +}
|
|
| 72 | + |
|
| 73 | +HsWord64 ghc_detect_x86_cpu_features(void)
|
|
| 74 | +{
|
|
| 75 | + HsWord64 feats = 0;
|
|
| 76 | + |
|
| 77 | +#if defined(_M_IX86) || defined(_M_X64) || defined(__i386__) || defined(__x86_64__)
|
|
| 78 | + uint32_t a, b, c, d;
|
|
| 79 | + uint32_t max_basic = 0;
|
|
| 80 | + |
|
| 81 | + if (!ghc_cpuid_count(0, 0, &a, &b, &c, &d)) {
|
|
| 82 | + return 0;
|
|
| 83 | + }
|
|
| 84 | + max_basic = a;
|
|
| 85 | + if (max_basic < 1) {
|
|
| 86 | + return 0;
|
|
| 87 | + }
|
|
| 88 | + |
|
| 89 | + ghc_cpuid_count(1, 0, &a, &b, &c, &d);
|
|
| 90 | + |
|
| 91 | + {
|
|
| 92 | + int has_sse2 = !!(d & (1u << 26));
|
|
| 93 | + int has_sse3 = !!(c & (1u << 0));
|
|
| 94 | + int has_ssse3 = !!(c & (1u << 9));
|
|
| 95 | + int has_sse4_1 = !!(c & (1u << 19));
|
|
| 96 | + int has_sse4_2 = !!(c & (1u << 20));
|
|
| 97 | + int has_fma_hw = !!(c & (1u << 12));
|
|
| 98 | + int has_avx_hw = !!(c & (1u << 28));
|
|
| 99 | + int has_osxsave = !!(c & (1u << 27));
|
|
| 100 | + |
|
| 101 | + int avx_usable = 0;
|
|
| 102 | + int avx512_usable = 0;
|
|
| 103 | + |
|
| 104 | + if (has_osxsave) {
|
|
| 105 | + uint64_t xcr0 = ghc_xgetbv0();
|
|
| 106 | + avx_usable = ((xcr0 & 0x6u) == 0x6u); /* XMM + YMM state */
|
|
| 107 | + avx512_usable = ((xcr0 & 0xE6u) == 0xE6u); /* XMM+YMM+opmask+ZMM */
|
|
| 108 | + }
|
|
| 109 | + |
|
| 110 | + if (has_sse2) {
|
|
| 111 | + SET_FEAT(feats, GHC_X86_FEAT_SSE2);
|
|
| 112 | + }
|
|
| 113 | + if (has_sse3) {
|
|
| 114 | + SET_FEAT(feats, GHC_X86_FEAT_SSE3);
|
|
| 115 | + }
|
|
| 116 | + if (has_ssse3) {
|
|
| 117 | + SET_FEAT(feats, GHC_X86_FEAT_SSSE3);
|
|
| 118 | + }
|
|
| 119 | + if (has_sse4_1) {
|
|
| 120 | + SET_FEAT(feats, GHC_X86_FEAT_SSE4_1);
|
|
| 121 | + }
|
|
| 122 | + if (has_sse4_2) {
|
|
| 123 | + SET_FEAT(feats, GHC_X86_FEAT_SSE4_2);
|
|
| 124 | + }
|
|
| 125 | + if (has_avx_hw && avx_usable) {
|
|
| 126 | + SET_FEAT(feats, GHC_X86_FEAT_AVX);
|
|
| 127 | + }
|
|
| 128 | + if (has_fma_hw && avx_usable) {
|
|
| 129 | + SET_FEAT(feats, GHC_X86_FEAT_FMA);
|
|
| 130 | + }
|
|
| 131 | + |
|
| 132 | + if (max_basic >= 7 && ghc_cpuid_count(7, 0, &a, &b, &c, &d)) {
|
|
| 133 | + int has_bmi1 = !!(b & (1u << 3));
|
|
| 134 | + int has_avx2_hw = !!(b & (1u << 5));
|
|
| 135 | + int has_bmi2 = !!(b & (1u << 8));
|
|
| 136 | + int has_avx512f = !!(b & (1u << 16));
|
|
| 137 | + int has_avx512dq = !!(b & (1u << 17));
|
|
| 138 | + int has_avx512cd = !!(b & (1u << 28));
|
|
| 139 | + int has_avx512bw = !!(b & (1u << 30));
|
|
| 140 | + int has_avx512vl = !!(b & (1u << 31));
|
|
| 141 | + int has_gfni = !!(c & (1u << 8));
|
|
| 142 | + |
|
| 143 | + if (has_bmi1) {
|
|
| 144 | + SET_FEAT(feats, GHC_X86_FEAT_BMI1);
|
|
| 145 | + }
|
|
| 146 | + if (has_bmi2) {
|
|
| 147 | + SET_FEAT(feats, GHC_X86_FEAT_BMI2);
|
|
| 148 | + }
|
|
| 149 | + if (avx_usable && has_avx2_hw) {
|
|
| 150 | + SET_FEAT(feats, GHC_X86_FEAT_AVX2);
|
|
| 151 | + }
|
|
| 152 | + |
|
| 153 | + if (avx512_usable && has_avx512f) {
|
|
| 154 | + SET_FEAT(feats, GHC_X86_FEAT_AVX512F);
|
|
| 155 | + if (has_avx512bw) {
|
|
| 156 | + SET_FEAT(feats, GHC_X86_FEAT_AVX512BW);
|
|
| 157 | + }
|
|
| 158 | + if (has_avx512cd) {
|
|
| 159 | + SET_FEAT(feats, GHC_X86_FEAT_AVX512CD);
|
|
| 160 | + }
|
|
| 161 | + if (has_avx512dq) {
|
|
| 162 | + SET_FEAT(feats, GHC_X86_FEAT_AVX512DQ);
|
|
| 163 | + }
|
|
| 164 | + if (has_avx512vl) {
|
|
| 165 | + SET_FEAT(feats, GHC_X86_FEAT_AVX512VL);
|
|
| 166 | + }
|
|
| 167 | + }
|
|
| 168 | + |
|
| 169 | + if (has_gfni) {
|
|
| 170 | + SET_FEAT(feats, GHC_X86_FEAT_GFNI);
|
|
| 171 | + }
|
|
| 172 | + }
|
|
| 173 | + }
|
|
| 174 | +#endif
|
|
| 175 | + |
|
| 176 | + return feats;
|
|
| 177 | +} |
| ... | ... | @@ -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 | |
| ... | ... | @@ -514,6 +515,7 @@ Library |
| 514 | 515 | GHC.Driver.Config.StgToCmm
|
| 515 | 516 | GHC.Driver.Config.Tidy
|
| 516 | 517 | GHC.Driver.Config.StgToJS
|
| 518 | + GHC.Driver.CpuFeatures
|
|
| 517 | 519 | GHC.Driver.DynFlags
|
| 518 | 520 | GHC.Driver.IncludeSpecs
|
| 519 | 521 | GHC.Driver.Downsweep
|
| ... | ... | @@ -488,6 +488,16 @@ The available mode flags are: |
| 488 | 488 | List the flags passed to the C compiler for the linking step
|
| 489 | 489 | during GHC build.
|
| 490 | 490 | |
| 491 | +.. ghc-flag:: --print-enabled-cpu-features
|
|
| 492 | + :shortdesc: display the effective enabled CPU features for code generation
|
|
| 493 | + :type: mode
|
|
| 494 | + :category: modes
|
|
| 495 | + |
|
| 496 | + Print a JSON object describing the CPU features currently enabled for code
|
|
| 497 | + generation, together with a set of ``-m...`` flags that reproduce the
|
|
| 498 | + effective feature set for the current target.
|
|
| 499 | + Dynamic options such as ``-mavx2`` and ``-mbmi2`` are respected.
|
|
| 500 | + |
|
| 491 | 501 | .. ghc-flag:: --print-debug-on
|
| 492 | 502 | :shortdesc: print whether GHC was built with ``-DDEBUG``
|
| 493 | 503 | :type: mode
|
| ... | ... | @@ -1844,6 +1854,30 @@ Some flags only make sense for particular target platforms. |
| 1844 | 1854 | so this flag has no effect when used with the :ref:`native code generator <native-code-gen>`
|
| 1845 | 1855 | or the :ref:`LLVM backend <llvm-code-gen>`.
|
| 1846 | 1856 | |
| 1857 | +.. ghc-flag:: -march=native
|
|
| 1858 | + :shortdesc: (x86 only) Enable all CPU features supported by the host
|
|
| 1859 | + :type: dynamic
|
|
| 1860 | + :category: platform-options
|
|
| 1861 | + |
|
| 1862 | + (x86/x86_64 only) Probe the CPU of the machine running GHC and enable all of
|
|
| 1863 | + the corresponding ``-m...`` CPU-feature options automatically (for example
|
|
| 1864 | + ``-msse4.2``, ``-mavx2``, ``-mbmi2``, ``-mfma``). The detected features apply
|
|
| 1865 | + to both the :ref:`native code generator <native-code-gen>` and the
|
|
| 1866 | + :ref:`LLVM backend <llvm-code-gen>`.
|
|
| 1867 | + |
|
| 1868 | + The detected features are enabled *in addition* to any CPU-feature flags you
|
|
| 1869 | + pass explicitly, regardless of their order on the command line; ``-march=native``
|
|
| 1870 | + never disables a feature.
|
|
| 1871 | + |
|
| 1872 | + .. warning::
|
|
| 1873 | + |
|
| 1874 | + Code compiled with ``-march=native`` may use instructions that are not
|
|
| 1875 | + available on other CPUs, and is therefore not portable to a different
|
|
| 1876 | + machine.
|
|
| 1877 | + |
|
| 1878 | + This flag is rejected when compiling for a non-x86 target or when
|
|
| 1879 | + cross-compiling, since the host CPU is then unrelated to the target.
|
|
| 1880 | + |
|
| 1847 | 1881 | Haddock
|
| 1848 | 1882 | -------
|
| 1849 | 1883 |
| 1 | 1 | {-# LANGUAGE CPP #-}
|
| 2 | 2 | {-# LANGUAGE NondecreasingIndentation #-}
|
| 3 | -module GHC.Driver.Session.Lint (checkOptions) where
|
|
| 3 | +module GHC.Driver.Session.Lint (checkOptions, unknownFlagsErr) where
|
|
| 4 | 4 | |
| 5 | 5 | import GHC.Driver.Backend
|
| 6 | 6 | import GHC.Driver.Phases
|
| ... | ... | @@ -77,6 +77,7 @@ isShowGhciUsageMode _ = False |
| 77 | 77 | |
| 78 | 78 | data PostLoadMode
|
| 79 | 79 | = ShowInterface FilePath -- ghc --show-iface
|
| 80 | + | PrintEnabledCpuFeatures -- ghc --print-enabled-cpu-features
|
|
| 80 | 81 | | DoMkDependHS -- ghc -M
|
| 81 | 82 | | StopBefore StopPhase -- ghc -E | -C | -S
|
| 82 | 83 | -- StopBefore StopLn is the default
|
| ... | ... | @@ -90,12 +91,13 @@ data PostLoadMode |
| 90 | 91 | | DoFrontend ModuleName -- ghc --frontend Plugin.Module
|
| 91 | 92 | |
| 92 | 93 | doMkDependHSMode, doMakeMode, doInteractiveMode, doRunMode,
|
| 93 | - doAbiHashMode, showUnitsMode :: Mode
|
|
| 94 | + doAbiHashMode, printEnabledCpuFeaturesMode, showUnitsMode :: Mode
|
|
| 94 | 95 | doMkDependHSMode = mkPostLoadMode DoMkDependHS
|
| 95 | 96 | doMakeMode = mkPostLoadMode DoMake
|
| 96 | 97 | doInteractiveMode = mkPostLoadMode DoInteractive
|
| 97 | 98 | doRunMode = mkPostLoadMode DoRun
|
| 98 | 99 | doAbiHashMode = mkPostLoadMode DoAbiHash
|
| 100 | +printEnabledCpuFeaturesMode = mkPostLoadMode PrintEnabledCpuFeatures
|
|
| 99 | 101 | showUnitsMode = mkPostLoadMode ShowPackages
|
| 100 | 102 | |
| 101 | 103 | showInterfaceMode :: FilePath -> Mode
|
| ... | ... | @@ -203,6 +205,8 @@ mode_flags = |
| 203 | 205 | , defFlag "-show-options" (PassFlag (setMode showOptionsMode))
|
| 204 | 206 | , defFlag "-supported-languages" (PassFlag (setMode showSupportedExtensionsMode))
|
| 205 | 207 | , defFlag "-supported-extensions" (PassFlag (setMode showSupportedExtensionsMode))
|
| 208 | + , defFlag "-print-enabled-cpu-features"
|
|
| 209 | + (PassFlag (setMode printEnabledCpuFeaturesMode))
|
|
| 206 | 210 | , defFlag "-show-packages" (PassFlag (setMode showUnitsMode))
|
| 207 | 211 | ] ++
|
| 208 | 212 | [ defFlag k' (PassFlag (setMode (printSetting k)))
|
| ... | ... | @@ -229,55 +229,64 @@ main' postLoadMode units dflags0 args flagWarnings = do |
| 229 | 229 | liftIO $ exitWith (ExitFailure 1)) $ do
|
| 230 | 230 | liftIO $ printOrThrowDiagnostics logger4 (initPrintConfig dflags4) diag_opts flagWarnings'
|
| 231 | 231 | |
| 232 | - liftIO $ showBanner postLoadMode dflags4
|
|
| 233 | - |
|
| 234 | - let (dflags5, srcs, objs) = parseTargetFiles dflags4 (map unLoc fileish_args)
|
|
| 235 | - |
|
| 236 | - -- we've finished manipulating the DynFlags, update the session
|
|
| 237 | - _ <- GHC.setSessionDynFlags dflags5
|
|
| 238 | - dflags6 <- GHC.getSessionDynFlags
|
|
| 239 | - |
|
| 240 | - -- Must do this before loading plugins
|
|
| 241 | - liftIO $ initUniqSupply (initialUnique dflags6) (uniqueIncrement dflags6)
|
|
| 242 | - |
|
| 243 | - -- Initialise plugins here because the plugin author might already expect this
|
|
| 244 | - -- subsequent call to `getLogger` to be affected by a plugin.
|
|
| 245 | - initializeSessionPlugins
|
|
| 246 | - hsc_env <- getSession
|
|
| 247 | - logger <- getLogger
|
|
| 248 | - |
|
| 249 | - |
|
| 250 | - ---------------- Display configuration -----------
|
|
| 251 | - case verbosity dflags6 of
|
|
| 252 | - v | v == 4 -> liftIO $ dumpUnitsSimple hsc_env
|
|
| 253 | - | v >= 5 -> liftIO $ dumpUnits hsc_env
|
|
| 254 | - | otherwise -> return ()
|
|
| 255 | - |
|
| 256 | - ---------------- Final sanity checking -----------
|
|
| 257 | - liftIO $ checkOptions postLoadMode dflags6 srcs objs units
|
|
| 258 | - |
|
| 259 | - ---------------- Do the business -----------
|
|
| 260 | - handleSourceError (\e -> do
|
|
| 261 | - GHC.printException e
|
|
| 262 | - liftIO $ exitWith (ExitFailure 1)) $ do
|
|
| 263 | - case postLoadMode of
|
|
| 264 | - ShowInterface f -> liftIO $ showIface logger
|
|
| 265 | - (hsc_dflags hsc_env)
|
|
| 266 | - (hsc_units hsc_env)
|
|
| 267 | - (hsc_NC hsc_env)
|
|
| 268 | - f
|
|
| 269 | - DoMake -> doMake units srcs
|
|
| 270 | - DoMkDependHS -> doMkDependHS (map fst srcs)
|
|
| 271 | - StopBefore p -> liftIO (oneShot hsc_env p srcs)
|
|
| 272 | - DoInteractive -> ghciUI units srcs Nothing
|
|
| 273 | - DoEval exprs -> ghciUI units srcs $ Just $ reverse exprs
|
|
| 274 | - DoRun -> doRun units srcs args
|
|
| 275 | - DoAbiHash -> abiHash (map fst srcs)
|
|
| 276 | - ShowPackages -> liftIO $ showUnits hsc_env
|
|
| 277 | - DoFrontend f -> doFrontend f srcs
|
|
| 278 | - DoBackpack -> doBackpack (map fst srcs)
|
|
| 279 | - |
|
| 280 | - liftIO $ dumpFinalStats logger
|
|
| 232 | + case postLoadMode of
|
|
| 233 | + PrintEnabledCpuFeatures -> liftIO $ do
|
|
| 234 | + -- This mode bypasses parseTargetFiles/checkOptions, so reject any
|
|
| 235 | + -- leftover flag-like arguments (e.g. a mistyped -mavx22) ourselves;
|
|
| 236 | + -- otherwise the typo would be silently ignored.
|
|
| 237 | + let unknown_opts = [ f | f@('-':_) <- map unLoc fileish_args ]
|
|
| 238 | + when (not (null unknown_opts)) (unknownFlagsErr unknown_opts)
|
|
| 239 | + putStrLn (showEnabledCpuFeatures dflags4)
|
|
| 240 | + _ -> do
|
|
| 241 | + liftIO $ showBanner postLoadMode dflags4
|
|
| 242 | + |
|
| 243 | + let (dflags5, srcs, objs) = parseTargetFiles dflags4 (map unLoc fileish_args)
|
|
| 244 | + |
|
| 245 | + -- we've finished manipulating the DynFlags, update the session
|
|
| 246 | + _ <- GHC.setSessionDynFlags dflags5
|
|
| 247 | + dflags6 <- GHC.getSessionDynFlags
|
|
| 248 | + |
|
| 249 | + -- Must do this before loading plugins
|
|
| 250 | + liftIO $ initUniqSupply (initialUnique dflags6) (uniqueIncrement dflags6)
|
|
| 251 | + |
|
| 252 | + -- Initialise plugins here because the plugin author might already expect this
|
|
| 253 | + -- subsequent call to `getLogger` to be affected by a plugin.
|
|
| 254 | + initializeSessionPlugins
|
|
| 255 | + hsc_env <- getSession
|
|
| 256 | + logger <- getLogger
|
|
| 257 | + |
|
| 258 | + |
|
| 259 | + ---------------- Display configuration -----------
|
|
| 260 | + case verbosity dflags6 of
|
|
| 261 | + v | v == 4 -> liftIO $ dumpUnitsSimple hsc_env
|
|
| 262 | + | v >= 5 -> liftIO $ dumpUnits hsc_env
|
|
| 263 | + | otherwise -> return ()
|
|
| 264 | + |
|
| 265 | + ---------------- Final sanity checking -----------
|
|
| 266 | + liftIO $ checkOptions postLoadMode dflags6 srcs objs units
|
|
| 267 | + |
|
| 268 | + ---------------- Do the business -----------
|
|
| 269 | + handleSourceError (\e -> do
|
|
| 270 | + GHC.printException e
|
|
| 271 | + liftIO $ exitWith (ExitFailure 1)) $ do
|
|
| 272 | + case postLoadMode of
|
|
| 273 | + ShowInterface f -> liftIO $ showIface logger
|
|
| 274 | + (hsc_dflags hsc_env)
|
|
| 275 | + (hsc_units hsc_env)
|
|
| 276 | + (hsc_NC hsc_env)
|
|
| 277 | + f
|
|
| 278 | + DoMake -> doMake units srcs
|
|
| 279 | + DoMkDependHS -> doMkDependHS (map fst srcs)
|
|
| 280 | + StopBefore p -> liftIO (oneShot hsc_env p srcs)
|
|
| 281 | + DoInteractive -> ghciUI units srcs Nothing
|
|
| 282 | + DoEval exprs -> ghciUI units srcs $ Just $ reverse exprs
|
|
| 283 | + DoRun -> doRun units srcs args
|
|
| 284 | + DoAbiHash -> abiHash (map fst srcs)
|
|
| 285 | + ShowPackages -> liftIO $ showUnits hsc_env
|
|
| 286 | + DoFrontend f -> doFrontend f srcs
|
|
| 287 | + DoBackpack -> doBackpack (map fst srcs)
|
|
| 288 | + |
|
| 289 | + liftIO $ dumpFinalStats logger
|
|
| 281 | 290 | |
| 282 | 291 | doRun :: [String] -> [(FilePath, Maybe Phase)] -> [Located String] -> Ghc ()
|
| 283 | 292 | doRun units srcs args = do
|
| ... | ... | @@ -515,4 +524,3 @@ abiHash strs = do |
| 515 | 524 | f <- fingerprintBinMem bh
|
| 516 | 525 | |
| 517 | 526 | putStrLn (showPpr dflags f) |
| 518 | - |
| ... | ... | @@ -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) |
| 1 | +def normalise_enabled_cpu_target(msg):
|
|
| 2 | + return re.sub(r'"target":"[^"]+"', '"target":"TARGET"', msg)
|
|
| 3 | + |
|
| 4 | +def normalise_unknown_flag(msg):
|
|
| 5 | + # Keep only the stable 'unrecognised flag' line; the program-name prefix,
|
|
| 6 | + # the suggestion list, and the usage trailer vary across configurations.
|
|
| 7 | + m = re.search(r'unrecognised flag: \S+', msg)
|
|
| 8 | + return m.group(0) + '\n' if m else msg
|
|
| 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 | + |
|
| 1 | 16 | test('driver011', [extra_files(['A011.hs'])], makefile_test, ['test011'])
|
| 2 | 17 | |
| 3 | 18 | test('driver012', [extra_files(['A012.hs'])], makefile_test, ['test012'])
|
| ... | ... | @@ -221,6 +236,77 @@ test('T9938B', [], makefile_test, []) |
| 221 | 236 | test('T9963', exit_code(1), run_command,
|
| 222 | 237 | ['{compiler} --interactive -ignore-dot-ghci --print-libdir'])
|
| 223 | 238 | |
| 239 | +test('print_enabled_cpu_features',
|
|
| 240 | + [unless(arch('x86_64') or arch('i386'), skip),
|
|
| 241 | + normalise_fun(normalise_enabled_cpu_target)],
|
|
| 242 | + run_command,
|
|
| 243 | + ['{compiler} --print-enabled-cpu-features'])
|
|
| 244 | + |
|
| 245 | +test('print_enabled_cpu_features_avx2',
|
|
| 246 | + [unless(arch('x86_64') or arch('i386'), skip),
|
|
| 247 | + normalise_fun(normalise_enabled_cpu_target)],
|
|
| 248 | + run_command,
|
|
| 249 | + ['{compiler} -mavx2 --print-enabled-cpu-features'])
|
|
| 250 | + |
|
| 251 | +test('print_enabled_cpu_features_bmi2',
|
|
| 252 | + [unless(arch('x86_64') or arch('i386'), skip),
|
|
| 253 | + normalise_fun(normalise_enabled_cpu_target)],
|
|
| 254 | + run_command,
|
|
| 255 | + ['{compiler} -mbmi2 --print-enabled-cpu-features'])
|
|
| 256 | + |
|
| 257 | +test('print_enabled_cpu_features_fma',
|
|
| 258 | + [unless(arch('x86_64') or arch('i386'), skip),
|
|
| 259 | + normalise_fun(normalise_enabled_cpu_target)],
|
|
| 260 | + run_command,
|
|
| 261 | + ['{compiler} -mfma --print-enabled-cpu-features'])
|
|
| 262 | + |
|
| 263 | +test('print_enabled_cpu_features_avx512',
|
|
| 264 | + [unless(arch('x86_64'), skip),
|
|
| 265 | + normalise_fun(normalise_enabled_cpu_target)],
|
|
| 266 | + run_command,
|
|
| 267 | + ['{compiler} -mavx512dq -mavx512vl --print-enabled-cpu-features'])
|
|
| 268 | + |
|
| 269 | +test('print_enabled_cpu_features_unknown_flag',
|
|
| 270 | + [normalise_fun(normalise_unknown_flag), exit_code(1)],
|
|
| 271 | + run_command,
|
|
| 272 | + ['{compiler} -mavx22 --print-enabled-cpu-features'])
|
|
| 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_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: its feature set is a superset of the default set.
|
|
| 289 | +# We extract the "features" arrays with and without the flag and assert that no
|
|
| 290 | +# baseline feature is dropped (comm -23 prints baseline-only entries; expect none).
|
|
| 291 | +# This avoids hard-coding the host-specific feature set.
|
|
| 292 | +test('march_native_superset',
|
|
| 293 | + [unless(arch('x86_64') or arch('i386'), skip)],
|
|
| 294 | + run_command,
|
|
| 295 | + ['{compiler} --print-enabled-cpu-features | '
|
|
| 296 | + 'sed \'s/.*"features":\\[//;s/].*//;s/"//g\' | tr \',\' \'\\n\' | sort > base.txt && '
|
|
| 297 | + '{compiler} -march=native --print-enabled-cpu-features | '
|
|
| 298 | + 'sed \'s/.*"features":\\[//;s/].*//;s/"//g\' | tr \',\' \'\\n\' | sort > native.txt && '
|
|
| 299 | + 'comm -23 base.txt native.txt'])
|
|
| 300 | + |
|
| 301 | +# -march=native is additive with explicit -m flags, regardless of order: an
|
|
| 302 | +# explicitly requested feature (here AVX2, forced on independent of the host) is
|
|
| 303 | +# still present whether the flag comes before or after -march=native.
|
|
| 304 | +test('march_native_additive',
|
|
| 305 | + [unless(arch('x86_64') or arch('i386'), skip)],
|
|
| 306 | + run_command,
|
|
| 307 | + ['{compiler} -mavx2 -march=native --print-enabled-cpu-features | grep -o AVX2 && '
|
|
| 308 | + '{compiler} -march=native -mavx2 --print-enabled-cpu-features | grep -o AVX2'])
|
|
| 309 | + |
|
| 224 | 310 | test('T10219', normal, run_command,
|
| 225 | 311 | # `-x hspp` in make mode should work.
|
| 226 | 312 | # 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 |
| 1 | +{"tag":"enabled-cpu-features","version":1,"target":"TARGET","features":["SSE","SSE2"],"as_m_flags":[]} |
| 1 | +{"tag":"enabled-cpu-features","version":1,"target":"TARGET","features":["SSE","SSE2","SSE3","SSSE3","SSE4.1","SSE4.2","AVX","AVX2"],"as_m_flags":["-mavx2"]} |
| 1 | +{"tag":"enabled-cpu-features","version":1,"target":"TARGET","features":["SSE","SSE2","SSE3","SSSE3","SSE4.1","SSE4.2","AVX","AVX2","AVX512F","AVX512DQ","AVX512VL","FMA"],"as_m_flags":["-mavx512dq","-mavx512vl"]} |
| 1 | +{"tag":"enabled-cpu-features","version":1,"target":"TARGET","features":["SSE","SSE2","BMI1","BMI2"],"as_m_flags":["-mbmi2"]} |
| 1 | +{"tag":"enabled-cpu-features","version":1,"target":"TARGET","features":["SSE","SSE2","SSE3","SSSE3","SSE4.1","SSE4.2","AVX","FMA"],"as_m_flags":["-mfma"]} |
| 1 | +ghc: unrecognised flag: -mavx22
|
|
| 2 | +did you mean one of:
|
|
| 3 | + -mavx2
|
|
| 4 | + -mavx
|
|
| 5 | + |
|
| 6 | +Usage: For basic information, try the `--help' option. |