Marge Bot pushed to branch master at Glasgow Haskell Compiler / GHC
Commits:
-
54cf3c1e
by sheaf at 2026-11-03T07:00:23-05:00
19 changed files:
- compiler/GHC/Cmm/CallConv.hs
- compiler/GHC/CmmToAsm/Config.hs
- compiler/GHC/CmmToAsm/X86/CodeGen.hs
- compiler/GHC/CmmToAsm/X86/Instr.hs
- compiler/GHC/CmmToLlvm/CodeGen.hs
- compiler/GHC/CmmToLlvm/Config.hs
- compiler/GHC/Driver/Config/CmmToAsm.hs
- compiler/GHC/Driver/Config/CmmToLlvm.hs
- compiler/GHC/Driver/Config/StgToCmm.hs
- compiler/GHC/Driver/DynFlags.hs
- compiler/GHC/Driver/Pipeline/Execute.hs
- compiler/GHC/Driver/Session.hs
- compiler/GHC/Platform.hs
- + compiler/GHC/Platform/CpuFeatures.hs
- compiler/GHC/StgToCmm/Config.hs
- compiler/GHC/StgToCmm/Prim.hs
- compiler/GHC/SysTools/Cpp.hs
- compiler/ghc.cabal.in
- testsuite/tests/count-deps/CountDepsParser.stdout
Changes:
| ... | ... | @@ -203,11 +203,7 @@ realDoubleRegs platform = map DoubleReg $ regList (pc_MAX_Real_Double_REG (pl |
| 203 | 203 | realLongRegs platform = map LongReg $ regList (pc_MAX_Real_Long_REG (platformConstants platform))
|
| 204 | 204 | |
| 205 | 205 | realXmmRegNos :: Platform -> [Int]
|
| 206 | -realXmmRegNos platform
|
|
| 207 | - | isSse2Enabled platform || platformArch platform == ArchAArch64
|
|
| 208 | - = regList (pc_MAX_Real_XMM_REG (platformConstants platform))
|
|
| 209 | - | otherwise
|
|
| 210 | - = []
|
|
| 206 | +realXmmRegNos platform = regList (pc_MAX_Real_XMM_REG (platformConstants platform))
|
|
| 211 | 207 | |
| 212 | 208 | regList :: Int -> [Int]
|
| 213 | 209 | regList n = [1 .. n]
|
| 1 | 1 | -- | Native code generator configuration
|
| 2 | 2 | module GHC.CmmToAsm.Config
|
| 3 | 3 | ( NCGConfig(..)
|
| 4 | + , ncgX86Features
|
|
| 4 | 5 | , ncgWordWidth
|
| 5 | 6 | , ncgSpillPreallocSize
|
| 6 | 7 | , platformWordWidth
|
| ... | ... | @@ -9,10 +10,12 @@ where |
| 9 | 10 | |
| 10 | 11 | import GHC.Prelude
|
| 11 | 12 | import GHC.Platform
|
| 13 | +import GHC.Platform.CpuFeatures
|
|
| 12 | 14 | import GHC.Cmm.Type (Width(..))
|
| 13 | 15 | import GHC.CmmToAsm.CFG.Weight
|
| 14 | 16 | import GHC.Unit.Module (Module)
|
| 15 | 17 | import GHC.Utils.Outputable
|
| 18 | +import GHC.Utils.Panic
|
|
| 16 | 19 | |
| 17 | 20 | -- | Native code generator configuration
|
| 18 | 21 | data NCGConfig = NCGConfig
|
| ... | ... | @@ -29,12 +32,7 @@ data NCGConfig = NCGConfig |
| 29 | 32 | , ncgRegsGraph :: !Bool
|
| 30 | 33 | , ncgAsmLinting :: !Bool -- ^ Perform ASM linting pass
|
| 31 | 34 | , ncgDoConstantFolding :: !Bool -- ^ Perform CMM constant folding
|
| 32 | - , ncgSseAvxVersion :: Maybe SseAvxVersion -- ^ (x86) SSE and AVX instructions
|
|
| 33 | - , ncgAvx512fEnabled :: !Bool
|
|
| 34 | - , ncgAvx512vlEnabled :: !Bool
|
|
| 35 | - , ncgAvx512bwEnabled :: !Bool
|
|
| 36 | - , ncgAvx512dqEnabled :: !Bool
|
|
| 37 | - , ncgBmiVersion :: Maybe BmiVersion -- ^ (x86) BMI instructions
|
|
| 35 | + , ncgCpuFeatures :: !CpuFeatures -- ^ Enabled CPU features
|
|
| 38 | 36 | , ncgDumpRegAllocStages :: !Bool
|
| 39 | 37 | , ncgDumpAsmStats :: !Bool
|
| 40 | 38 | , ncgDumpAsmConflicts :: !Bool
|
| ... | ... | @@ -54,6 +52,13 @@ data NCGConfig = NCGConfig |
| 54 | 52 | , ncgLa664Enabled :: !Bool -- ^ la664 is equal to isav1.1
|
| 55 | 53 | }
|
| 56 | 54 | |
| 55 | +-- | X86 only: enabled x86 CPU features.
|
|
| 56 | +ncgX86Features :: NCGConfig -> X86Features
|
|
| 57 | +ncgX86Features config =
|
|
| 58 | + case ncgCpuFeatures config of
|
|
| 59 | + X86CpuFeatures feats -> feats
|
|
| 60 | + _ -> panic "ncgX86Features: not an x86 target"
|
|
| 61 | + |
|
| 57 | 62 | -- | Return Word size
|
| 58 | 63 | ncgWordWidth :: NCGConfig -> Width
|
| 59 | 64 | ncgWordWidth config = platformWordWidth (ncgPlatform config)
|
| ... | ... | @@ -56,6 +56,7 @@ import GHC.CmmToAsm.Config |
| 56 | 56 | import GHC.Platform.Reg
|
| 57 | 57 | import GHC.CmmToAsm.Reg.Target (targetClassOfReg)
|
| 58 | 58 | import GHC.Platform
|
| 59 | +import GHC.Platform.CpuFeatures
|
|
| 59 | 60 | import GHC.Platform.Reg.Class.Unified (RegClass(..))
|
| 60 | 61 | |
| 61 | 62 | -- Our intermediate code:
|
| ... | ... | @@ -99,43 +100,7 @@ import Data.Word |
| 99 | 100 | |
| 100 | 101 | import qualified Data.Map as Map
|
| 101 | 102 | |
| 102 | -is32BitPlatform :: NatM Bool
|
|
| 103 | -is32BitPlatform = do
|
|
| 104 | - platform <- getPlatform
|
|
| 105 | - return $ target32Bit platform
|
|
| 106 | - |
|
| 107 | --- These flags may be implied by other flags like -mfma or -mavx512f.
|
|
| 108 | --- See Note [Implications between X86 CPU feature flags] for details.
|
|
| 109 | -ssse3Enabled :: NatM Bool
|
|
| 110 | -ssse3Enabled = do
|
|
| 111 | - config <- getConfig
|
|
| 112 | - return (ncgSseAvxVersion config >= Just SSSE3)
|
|
| 113 | - |
|
| 114 | -sse4_1Enabled :: NatM Bool
|
|
| 115 | -sse4_1Enabled = do
|
|
| 116 | - config <- getConfig
|
|
| 117 | - return (ncgSseAvxVersion config >= Just SSE4)
|
|
| 118 | - |
|
| 119 | -sse4_2Enabled :: NatM Bool
|
|
| 120 | -sse4_2Enabled = do
|
|
| 121 | - config <- getConfig
|
|
| 122 | - return (ncgSseAvxVersion config >= Just SSE42)
|
|
| 123 | - |
|
| 124 | -avxEnabled :: NatM Bool
|
|
| 125 | -avxEnabled = do
|
|
| 126 | - config <- getConfig
|
|
| 127 | - return (ncgSseAvxVersion config >= Just AVX1)
|
|
| 128 | - |
|
| 129 | -avx2Enabled :: NatM Bool
|
|
| 130 | -avx2Enabled = do
|
|
| 131 | - config <- getConfig
|
|
| 132 | - return (ncgSseAvxVersion config >= Just AVX2)
|
|
| 133 | - |
|
| 134 | -avx512vlEnabled :: NatM Bool
|
|
| 135 | -avx512vlEnabled = ncgAvx512vlEnabled <$> getConfig
|
|
| 136 | - |
|
| 137 | -avx512dqEnabled :: NatM Bool
|
|
| 138 | -avx512dqEnabled = ncgAvx512dqEnabled <$> getConfig
|
|
| 103 | +--------------------------------------------------------------------------------
|
|
| 139 | 104 | |
| 140 | 105 | cmmTopCodeGen
|
| 141 | 106 | :: RawCmmDecl
|
| ... | ... | @@ -426,7 +391,9 @@ swizzleRegisterRep (Any _ codefn) format = Any format codefn |
| 426 | 391 | |
| 427 | 392 | getLocalRegReg :: LocalReg -> Reg
|
| 428 | 393 | getLocalRegReg (LocalReg u ty)
|
| 429 | - = -- by assuming SSE2, Int, Word, Float, Double and vectors all can be register allocated
|
|
| 394 | + = -- Int, Word, Float, Double and vectors can all be register allocated, as the
|
|
| 395 | + -- baseline instruction set includes SSE2: see 'x86BaselineSseAvx' in
|
|
| 396 | + -- GHC.Platform.CpuFeatures.
|
|
| 430 | 397 | RegVirtual (mkVirtualReg u (cmmTypeFormat ty))
|
| 431 | 398 | |
| 432 | 399 | -- | Grab the Reg for a CmmReg
|
| ... | ... | @@ -495,6 +462,20 @@ is32BitInteger i = i64 <= 0x7fffffff && i64 >= -0x80000000 |
| 495 | 462 | where i64 = fromIntegral i :: Int64
|
| 496 | 463 | |
| 497 | 464 | |
| 465 | +-- -----------------------------------------------------------------------------
|
|
| 466 | +-- NCG configuration options (e.g. enabled X86 CPU features)
|
|
| 467 | + |
|
| 468 | +is32BitPlatform :: NatM Bool
|
|
| 469 | +is32BitPlatform = do
|
|
| 470 | + platform <- getPlatform
|
|
| 471 | + return $ target32Bit platform
|
|
| 472 | + |
|
| 473 | +-- | Whether an x86 instruction set is enabled, e.g. @x86Feature x86AvxEnabled@.
|
|
| 474 | +--
|
|
| 475 | +-- See Note [CPU features] for the implication structure of X86 features.
|
|
| 476 | +x86Feature :: (X86Features -> res) -> NatM res
|
|
| 477 | +x86Feature f = f . ncgX86Features <$> getConfig
|
|
| 478 | + |
|
| 498 | 479 | -- -----------------------------------------------------------------------------
|
| 499 | 480 | -- General things for putting together code sequences
|
| 500 | 481 | |
| ... | ... | @@ -976,11 +957,11 @@ getRegister' _ _ (CmmMachOp mop []) = |
| 976 | 957 | pprPanic "getRegister(x86): nullary MachOp" (text $ show mop)
|
| 977 | 958 | |
| 978 | 959 | getRegister' platform is32Bit (CmmMachOp mop [x]) = do -- unary MachOps
|
| 979 | - sse42 <- sse4_2Enabled
|
|
| 980 | - ssse3 <- ssse3Enabled
|
|
| 981 | - avx <- avxEnabled
|
|
| 982 | - avx2 <- avx2Enabled
|
|
| 983 | - avx512vl <- avx512vlEnabled
|
|
| 960 | + sse42 <- x86Feature x86Sse4_2Enabled
|
|
| 961 | + ssse3 <- x86Feature x86Ssse3Enabled
|
|
| 962 | + avx <- x86Feature x86AvxEnabled
|
|
| 963 | + avx2 <- x86Feature x86Avx2Enabled
|
|
| 964 | + avx512vl <- x86Feature x86Avx512VLEnabled
|
|
| 984 | 965 | case mop of
|
| 985 | 966 | MO_F_Neg w -> sse2NegCode w x
|
| 986 | 967 | |
| ... | ... | @@ -1459,11 +1440,11 @@ getRegister' platform is32Bit (CmmMachOp (MO_Xor w) [x, y]) |
| 1459 | 1440 | = genBitTestCode (intFormat w) BTC opnd ix
|
| 1460 | 1441 | |
| 1461 | 1442 | getRegister' platform is32Bit (CmmMachOp mop [x, y]) = do -- dyadic MachOps
|
| 1462 | - sse4_1 <- sse4_1Enabled
|
|
| 1463 | - sse4_2 <- sse4_2Enabled
|
|
| 1464 | - avx <- avxEnabled
|
|
| 1465 | - avx512vl <- avx512vlEnabled
|
|
| 1466 | - avx512dq <- avx512dqEnabled
|
|
| 1443 | + sse4_1 <- x86Feature x86Sse4_1Enabled
|
|
| 1444 | + sse4_2 <- x86Feature x86Sse4_2Enabled
|
|
| 1445 | + avx <- x86Feature x86AvxEnabled
|
|
| 1446 | + avx512vl <- x86Feature x86Avx512VLEnabled
|
|
| 1447 | + avx512dq <- x86Feature x86Avx512DQEnabled
|
|
| 1467 | 1448 | case mop of
|
| 1468 | 1449 | MO_F_Eq _ -> condFltReg is32Bit EQQ x y
|
| 1469 | 1450 | MO_F_Ne _ -> condFltReg is32Bit NE x y
|
| ... | ... | @@ -2607,7 +2588,7 @@ getRegister' platform is32Bit (CmmMachOp mop [x, y]) = do -- dyadic MachOps |
| 2607 | 2588 | |
| 2608 | 2589 | -- PALIGNR (SSSE3) or PSLLDQ + PSRLDQ: is == [i,i+1,...,n-2,n-1;n,n+1,...,n+i-1]
|
| 2609 | 2590 | | (js, ks) <- span (< n) is, and (zipWith (==) (reverse js) [n-1,n-2..]), and (zipWith (==) ks [n..]) -> Just $ do
|
| 2610 | - ssse3 <- ssse3Enabled
|
|
| 2591 | + ssse3 <- x86Feature x86Ssse3Enabled
|
|
| 2611 | 2592 | let amountInBytes = widthInBytes * length ks
|
| 2612 | 2593 | if ssse3
|
| 2613 | 2594 | then vector_op_sse (`PALIGNR` (ImmInt amountInBytes)) fmt v2 v1
|
| ... | ... | @@ -2624,7 +2605,7 @@ getRegister' platform is32Bit (CmmMachOp mop [x, y]) = do -- dyadic MachOps |
| 2624 | 2605 | |
| 2625 | 2606 | -- PALIGNR (SSSE3) or PSLLDQ + PSRLDQ: is == [n+i,n+i+1,...,2n-2,2n-1;0,1,...,i-1]
|
| 2626 | 2607 | | (js, ks) <- span (>= n) is, and (zipWith (==) (reverse js) [2*n-1,2*n-2..]), and (zipWith (==) ks [0..]) -> Just $ do
|
| 2627 | - ssse3 <- ssse3Enabled
|
|
| 2608 | + ssse3 <- x86Feature x86Ssse3Enabled
|
|
| 2628 | 2609 | let amountInBytes = widthInBytes * length ks
|
| 2629 | 2610 | if ssse3
|
| 2630 | 2611 | then vector_op_sse (`PALIGNR` (ImmInt amountInBytes)) fmt v1 v2
|
| ... | ... | @@ -2663,7 +2644,7 @@ getRegister' platform is32Bit (CmmMachOp mop [x, y]) = do -- dyadic MachOps |
| 2663 | 2644 | vector_shuffle_int8x16 sse4_1 v1 v2 is
|
| 2664 | 2645 | | Just commonCase <- vector_shuffle_int128_common sse4_1 fmt v1 v2 is = commonCase
|
| 2665 | 2646 | | otherwise = do
|
| 2666 | - ssse3 <- ssse3Enabled
|
|
| 2647 | + ssse3 <- x86Feature x86Ssse3Enabled
|
|
| 2667 | 2648 | let fmtInt16X8 = VecFormat 8 FmtInt16
|
| 2668 | 2649 | v1IsZero = isZeroVecLit v1
|
| 2669 | 2650 | v2IsZero = isZeroVecLit v2
|
| ... | ... | @@ -3021,8 +3002,8 @@ getRegister' platform is32Bit (CmmMachOp mop [x, y]) = do -- dyadic MachOps |
| 3021 | 3002 | |
| 3022 | 3003 | |
| 3023 | 3004 | getRegister' platform _is32Bit (CmmMachOp mop [x, y, z]) = do -- ternary MachOps
|
| 3024 | - avx <- avxEnabled
|
|
| 3025 | - sse4_1 <- sse4_1Enabled
|
|
| 3005 | + avx <- x86Feature x86AvxEnabled
|
|
| 3006 | + sse4_1 <- x86Feature x86Sse4_1Enabled
|
|
| 3026 | 3007 | case mop of
|
| 3027 | 3008 | -- Floating point fused multiply-add operations @ ± x*y ± z@
|
| 3028 | 3009 | MO_FMA var l w
|
| ... | ... | @@ -3325,7 +3306,7 @@ getRegister' platform is32Bit (CmmLit lit) |
| 3325 | 3306 | is_label _ = False
|
| 3326 | 3307 | |
| 3327 | 3308 | getRegister' platform is32Bit (CmmLit lit) = do
|
| 3328 | - avx <- avxEnabled
|
|
| 3309 | + avx <- x86Feature x86AvxEnabled
|
|
| 3329 | 3310 | |
| 3330 | 3311 | -- NB: it is important that the code produced here (to load a literal into
|
| 3331 | 3312 | -- a register) doesn't clobber any registers other than the destination
|
| ... | ... | @@ -4764,7 +4745,8 @@ genCCall32 addr _conv dest_regs args = do |
| 4764 | 4745 | | isVecType ty
|
| 4765 | 4746 | = unitOL (mkRegRegMoveInstr config (cmmTypeFormat ty) xmm0 r_dest)
|
| 4766 | 4747 | | isFloatType ty =
|
| 4767 | - -- we assume SSE2
|
|
| 4748 | + -- SSE2 is in the baseline instruction set: see 'x86BaselineSseAvx'
|
|
| 4749 | + -- in GHC.Platform.CpuFeatures.
|
|
| 4768 | 4750 | let tmp_amode = AddrBaseIndex (EABaseReg esp)
|
| 4769 | 4751 | EAIndexNone
|
| 4770 | 4752 | (ImmInt 0)
|
| ... | ... | @@ -6418,7 +6400,7 @@ genCtzGeneric width dst src = do |
| 6418 | 6400 | config <- getConfig
|
| 6419 | 6401 | let bw = widthInBits width
|
| 6420 | 6402 | let dst_r = getLocalRegReg dst
|
| 6421 | - if ncgBmiVersion config >= Just BMI2
|
|
| 6403 | + if x86Bmi2Enabled (ncgX86Features config)
|
|
| 6422 | 6404 | then do
|
| 6423 | 6405 | src_r <- getNewRegNat (intFormat width)
|
| 6424 | 6406 | let instrs = appOL (code_src src_r) $ case width of
|
| ... | ... | @@ -6735,7 +6717,7 @@ genPopCnt bid width dst src = do |
| 6735 | 6717 | platform = ncgPlatform config
|
| 6736 | 6718 | format = intFormat width
|
| 6737 | 6719 | |
| 6738 | - sse4_2Enabled >>= \case
|
|
| 6720 | + x86Feature x86Sse4_2Enabled >>= \case
|
|
| 6739 | 6721 | |
| 6740 | 6722 | True -> do
|
| 6741 | 6723 | code_src <- getAnyReg src
|
| ... | ... | @@ -6771,7 +6753,7 @@ genPdep bid width dst src mask = do |
| 6771 | 6753 | platform = ncgPlatform config
|
| 6772 | 6754 | format = intFormat width
|
| 6773 | 6755 | |
| 6774 | - if ncgBmiVersion config >= Just BMI2
|
|
| 6756 | + if x86Bmi2Enabled (ncgX86Features config)
|
|
| 6775 | 6757 | then do
|
| 6776 | 6758 | code_src <- getAnyReg src
|
| 6777 | 6759 | code_mask <- getAnyReg mask
|
| ... | ... | @@ -6798,7 +6780,7 @@ genPdep bid width dst src mask = do |
| 6798 | 6780 | genPext :: BlockId -> Width -> LocalReg -> CmmExpr -> CmmExpr -> NatM InstrBlock
|
| 6799 | 6781 | genPext bid width dst src mask = do
|
| 6800 | 6782 | config <- getConfig
|
| 6801 | - if ncgBmiVersion config >= Just BMI2
|
|
| 6783 | + if x86Bmi2Enabled (ncgX86Features config)
|
|
| 6802 | 6784 | then do
|
| 6803 | 6785 | let format = intFormat width
|
| 6804 | 6786 | let dst_r = getLocalRegReg dst
|
| ... | ... | @@ -6835,7 +6817,7 @@ genClz bid width dst src = do |
| 6835 | 6817 | else do
|
| 6836 | 6818 | code_src <- getAnyReg src
|
| 6837 | 6819 | let dst_r = getLocalRegReg dst
|
| 6838 | - if ncgBmiVersion config >= Just BMI2
|
|
| 6820 | + if x86Bmi2Enabled (ncgX86Features config)
|
|
| 6839 | 6821 | then do
|
| 6840 | 6822 | src_r <- getNewRegNat (intFormat width)
|
| 6841 | 6823 | return $ appOL (code_src src_r) $ case width of
|
| ... | ... | @@ -65,6 +65,7 @@ import GHC.Utils.Constants ( debugIsOn ) |
| 65 | 65 | import GHC.Utils.Outputable
|
| 66 | 66 | import GHC.Utils.Panic
|
| 67 | 67 | import GHC.Platform
|
| 68 | +import GHC.Platform.CpuFeatures
|
|
| 68 | 69 | |
| 69 | 70 | import GHC.Cmm.CLabel
|
| 70 | 71 | import GHC.Types.Unique.Set
|
| ... | ... | @@ -1182,9 +1183,10 @@ movInstr config fmt = |
| 1182 | 1183 | = f
|
| 1183 | 1184 | |
| 1184 | 1185 | plat = ncgPlatform config
|
| 1185 | - avx = ncgSseAvxVersion config >= Just AVX1
|
|
| 1186 | - avx2 = ncgSseAvxVersion config >= Just AVX2
|
|
| 1187 | - avx512f = ncgAvx512fEnabled config
|
|
| 1186 | + feats = ncgX86Features config
|
|
| 1187 | + avx = x86AvxEnabled feats
|
|
| 1188 | + avx2 = x86Avx2Enabled feats
|
|
| 1189 | + avx512f = x86Avx512FEnabled feats
|
|
| 1188 | 1190 | avx_move sFmt =
|
| 1189 | 1191 | if isFloatScalarFormat sFmt
|
| 1190 | 1192 | then assertCompatibleRegs $
|
| ... | ... | @@ -260,12 +260,12 @@ discussion about portable pdep/pext intrinsics. |
| 260 | 260 | -}
|
| 261 | 261 | genCall (PrimTarget op@(MO_Pdep w)) [dst] args = do
|
| 262 | 262 | cfg <- getConfig
|
| 263 | - if llvmCgBmiVersion cfg >= Just BMI2
|
|
| 263 | + if llvmCgBmi2Enabled cfg
|
|
| 264 | 264 | then genCallMinimumTruncationCast W32 w op dst args
|
| 265 | 265 | else genCallSimpleCast w op dst args
|
| 266 | 266 | genCall (PrimTarget op@(MO_Pext w)) [dst] args = do
|
| 267 | 267 | cfg <- getConfig
|
| 268 | - if llvmCgBmiVersion cfg >= Just BMI2
|
|
| 268 | + if llvmCgBmi2Enabled cfg
|
|
| 269 | 269 | then genCallMinimumTruncationCast W32 w op dst args
|
| 270 | 270 | else genCallSimpleCast w op dst args
|
| 271 | 271 | |
| ... | ... | @@ -852,7 +852,7 @@ cmmPrimOpFunctions :: CallishMachOp -> LlvmM LMString |
| 852 | 852 | cmmPrimOpFunctions mop = do
|
| 853 | 853 | cfg <- getConfig
|
| 854 | 854 | platform <- getPlatform
|
| 855 | - let !isBmi2Enabled = llvmCgBmiVersion cfg >= Just BMI2
|
|
| 855 | + let !isBmi2Enabled = llvmCgBmi2Enabled cfg
|
|
| 856 | 856 | !is32bit = platformWordSize platform == PW4
|
| 857 | 857 | unsupported = panic ("cmmPrimOpFunctions: " ++ show mop
|
| 858 | 858 | ++ " not supported here")
|
| 1 | 1 | -- | Llvm code generator configuration
|
| 2 | 2 | module GHC.CmmToLlvm.Config
|
| 3 | 3 | ( LlvmCgConfig(..)
|
| 4 | + , llvmCgBmi2Enabled
|
|
| 4 | 5 | , LlvmConfig(..)
|
| 5 | 6 | , LlvmTarget(..)
|
| 6 | 7 | , initLlvmConfig
|
| ... | ... | @@ -9,6 +10,7 @@ where |
| 9 | 10 | |
| 10 | 11 | import GHC.Prelude
|
| 11 | 12 | import GHC.Platform
|
| 13 | +import GHC.Platform.CpuFeatures
|
|
| 12 | 14 | |
| 13 | 15 | import GHC.Utils.Outputable
|
| 14 | 16 | import GHC.Settings.Utils
|
| ... | ... | @@ -22,7 +24,7 @@ data LlvmCgConfig = LlvmCgConfig |
| 22 | 24 | , llvmCgContext :: !SDocContext -- ^ Context for LLVM code generation
|
| 23 | 25 | , llvmCgFillUndefWithGarbage :: !Bool -- ^ Fill undefined literals with garbage values
|
| 24 | 26 | , llvmCgSplitSection :: !Bool -- ^ Split sections
|
| 25 | - , llvmCgBmiVersion :: Maybe BmiVersion -- ^ (x86) BMI instructions
|
|
| 27 | + , llvmCgCpuFeatures :: !CpuFeatures -- ^ Enabled CPU features
|
|
| 26 | 28 | , llvmCgLlvmVersion :: Maybe LlvmVersion -- ^ version of Llvm we're using
|
| 27 | 29 | , llvmCgDoWarn :: !Bool -- ^ True ==> warn unsupported Llvm version
|
| 28 | 30 | , llvmCgLlvmTarget :: !String -- ^ target triple passed to LLVM
|
| ... | ... | @@ -30,6 +32,13 @@ data LlvmCgConfig = LlvmCgConfig |
| 30 | 32 | -- see Note [LLVM configuration]
|
| 31 | 33 | }
|
| 32 | 34 | |
| 35 | +-- | Whether BMI2 instructions are enabled (x86 only).
|
|
| 36 | +llvmCgBmi2Enabled :: LlvmCgConfig -> Bool
|
|
| 37 | +llvmCgBmi2Enabled cfg =
|
|
| 38 | + case llvmCgCpuFeatures cfg of
|
|
| 39 | + X86CpuFeatures feats -> x86Bmi2Enabled feats
|
|
| 40 | + _ -> False
|
|
| 41 | + |
|
| 33 | 42 | data LlvmTarget = LlvmTarget
|
| 34 | 43 | { lDataLayout :: String
|
| 35 | 44 | , lCPU :: String
|
| ... | ... | @@ -39,37 +39,8 @@ initNCGConfig dflags this_mod = NCGConfig |
| 39 | 39 | , ncgDumpRegAllocStages = dopt Opt_D_dump_asm_regalloc_stages dflags
|
| 40 | 40 | , ncgDumpAsmStats = dopt Opt_D_dump_asm_stats dflags
|
| 41 | 41 | , ncgDumpAsmConflicts = dopt Opt_D_dump_asm_conflicts dflags
|
| 42 | - , ncgBmiVersion = case platformArch (targetPlatform dflags) of
|
|
| 43 | - ArchX86_64 -> bmiVersion dflags
|
|
| 44 | - ArchX86 -> bmiVersion dflags
|
|
| 45 | - _ -> Nothing
|
|
| 46 | - |
|
| 47 | - -- We assume SSE1 and SSE2 operations are available on both
|
|
| 48 | - -- x86 and x86_64. Historically we didn't default to SSE2 and
|
|
| 49 | - -- SSE1 on x86, which results in defacto nondeterminism for how
|
|
| 50 | - -- rounding behaves in the associated x87 floating point instructions
|
|
| 51 | - -- because variations in the spill/fpu stack placement of arguments for
|
|
| 52 | - -- operations would change the precision and final result of what
|
|
| 53 | - -- would otherwise be the same expressions with respect to single or
|
|
| 54 | - -- double precision IEEE floating point computations.
|
|
| 55 | - |
|
| 56 | - -- ncgSseAvxVersion is set to the actual SSE/AVX version.
|
|
| 57 | - -- For example, -mfma does not set DynFlags's sseAvxVersion, but makes ncgSseAvxVersion >= AVX1.
|
|
| 58 | - -- See also Note [Implications between X86 CPU feature flags]
|
|
| 59 | - , ncgSseAvxVersion =
|
|
| 60 | - let v | isAvx2Enabled dflags = Just AVX2 -- -mavx512f does not set sseAvxVersion, but makes isAvx2Enabled true
|
|
| 61 | - | isAvxEnabled dflags = Just AVX1 -- -mfma does not set sseAvxVersion, but makes isAvxEnabled true
|
|
| 62 | - | otherwise = max (Just SSE2) (sseAvxVersion dflags)
|
|
| 63 | - in case platformArch (targetPlatform dflags) of
|
|
| 64 | - ArchX86_64 -> v
|
|
| 65 | - ArchX86 -> v
|
|
| 66 | - _ -> Nothing
|
|
| 67 | - , ncgAvx512fEnabled = isAvx512fEnabled dflags
|
|
| 68 | - , ncgAvx512vlEnabled = isAvx512vlEnabled dflags
|
|
| 69 | - , ncgAvx512bwEnabled = isAvx512bwEnabled dflags
|
|
| 70 | - , ncgAvx512dqEnabled = isAvx512dqEnabled dflags
|
|
| 71 | - |
|
| 72 | - , ncgLa664Enabled = isLa664Enabled dflags
|
|
| 42 | + , ncgCpuFeatures = targetCpuFeatures dflags
|
|
| 43 | + , ncgLa664Enabled = isLa664Enabled dflags
|
|
| 73 | 44 | |
| 74 | 45 | , ncgDwarfEnabled = osElfTarget (platformOS (targetPlatform dflags)) && debugLevel dflags > 0 && platformArch (targetPlatform dflags) /= ArchAArch64
|
| 75 | 46 | , ncgDwarfUnwindings = osElfTarget (platformOS (targetPlatform dflags)) && debugLevel dflags > 0
|
| ... | ... | @@ -23,10 +23,7 @@ initLlvmCgConfig logger config_cache dflags = do |
| 23 | 23 | , llvmCgContext = initSDocContext dflags PprCode
|
| 24 | 24 | , llvmCgFillUndefWithGarbage = gopt Opt_LlvmFillUndefWithGarbage dflags
|
| 25 | 25 | , llvmCgSplitSection = gopt Opt_SplitSections dflags
|
| 26 | - , llvmCgBmiVersion = case platformArch (targetPlatform dflags) of
|
|
| 27 | - ArchX86_64 -> bmiVersion dflags
|
|
| 28 | - ArchX86 -> bmiVersion dflags
|
|
| 29 | - _ -> Nothing
|
|
| 26 | + , llvmCgCpuFeatures = targetCpuFeatures dflags
|
|
| 30 | 27 | , llvmCgLlvmVersion = version
|
| 31 | 28 | , llvmCgDoWarn = wopt Opt_WarnUnsupportedLlvmVersion dflags
|
| 32 | 29 | , llvmCgLlvmTarget = platformMisc_llvmTarget $! platformMisc dflags
|
| ... | ... | @@ -12,6 +12,7 @@ import GHC.Cmm.MachOp ( FMASign(..)) |
| 12 | 12 | import GHC.Driver.Backend
|
| 13 | 13 | import GHC.Driver.Session
|
| 14 | 14 | import GHC.Platform
|
| 15 | +import GHC.Platform.CpuFeatures
|
|
| 15 | 16 | import GHC.Platform.Profile
|
| 16 | 17 | import GHC.Platform.Regs
|
| 17 | 18 | import GHC.Utils.Error
|
| ... | ... | @@ -63,7 +64,7 @@ initStgToCmmConfig dflags mod = StgToCmmConfig |
| 63 | 64 | , stgToCmmAllowExtendedAddSubInstrs = (ncg && (x86ish || ppc)) || llvm
|
| 64 | 65 | , stgToCmmAllowFMAInstr =
|
| 65 | 66 | if
|
| 66 | - | not (isFmaEnabled dflags)
|
|
| 67 | + | not (cpuFmaEnabled cpu_feats)
|
|
| 67 | 68 | || not (ncg || llvm)
|
| 68 | 69 | -- If we're not using the native code generator or LLVM,
|
| 69 | 70 | -- fall back to the generic implementation.
|
| ... | ... | @@ -81,12 +82,10 @@ initStgToCmmConfig dflags mod = StgToCmmConfig |
| 81 | 82 | |
| 82 | 83 | , stgToCmmAllowIntMul2Instr = (ncg && (x86ish || aarch64)) || llvm
|
| 83 | 84 | , stgToCmmAllowWordMul2Instr = (ncg && (x86ish || ppc || aarch64)) || llvm
|
| 84 | - , stgToCmmAllowIntWord64X2MinMax = (ncg && ((x86ish && isSse4_2Enabled dflags) || aarch64)) || llvm
|
|
| 85 | + , stgToCmmAllowIntWord64X2MinMax = (ncg && (sse4_2 || aarch64)) || llvm
|
|
| 85 | 86 | -- SIMD flags
|
| 86 | 87 | , stgToCmmVecInstrsErr = vec_err
|
| 87 | - , stgToCmmAvx = isAvxEnabled dflags
|
|
| 88 | - , stgToCmmAvx2 = isAvx2Enabled dflags
|
|
| 89 | - , stgToCmmAvx512f = isAvx512fEnabled dflags
|
|
| 88 | + , stgToCmmCpuFeatures = cpu_feats
|
|
| 90 | 89 | , stgToCmmUseStdApThunk = not $ gopt Opt_Ticky_AP dflags
|
| 91 | 90 | -- See Note [Saving foreign call target to local]
|
| 92 | 91 | , stgToCmmSaveFCallTargetToLocal = any (callerSaves platform) $ activeStgRegs platform
|
| ... | ... | @@ -111,6 +110,10 @@ initStgToCmmConfig dflags mod = StgToCmmConfig |
| 111 | 110 | ArchPPC -> True
|
| 112 | 111 | ArchPPC_64 _ -> True
|
| 113 | 112 | _ -> False
|
| 113 | + cpu_feats = targetCpuFeatures dflags
|
|
| 114 | + sse4_2 = case cpu_feats of
|
|
| 115 | + X86CpuFeatures feats -> x86Sse4_2Enabled feats
|
|
| 116 | + _ -> False
|
|
| 114 | 117 | vec_err = case backendSimdValidity (backend dflags) of
|
| 115 | 118 | IsValid -> Nothing
|
| 116 | 119 | NotValid msg -> Just msg |
| ... | ... | @@ -78,23 +78,7 @@ module GHC.Driver.DynFlags ( |
| 78 | 78 | initPromotionTickContext,
|
| 79 | 79 | |
| 80 | 80 | -- * Platform features
|
| 81 | - isSse3Enabled,
|
|
| 82 | - isSsse3Enabled,
|
|
| 83 | - isSse4_1Enabled,
|
|
| 84 | - isSse4_2Enabled,
|
|
| 85 | - isAvxEnabled,
|
|
| 86 | - isAvx2Enabled,
|
|
| 87 | - isAvx512bwEnabled,
|
|
| 88 | - isAvx512cdEnabled,
|
|
| 89 | - isAvx512dqEnabled,
|
|
| 90 | - isAvx512erEnabled,
|
|
| 91 | - isAvx512fEnabled,
|
|
| 92 | - isAvx512pfEnabled,
|
|
| 93 | - isAvx512vlEnabled,
|
|
| 94 | - isFmaEnabled,
|
|
| 95 | - isGfniEnabled,
|
|
| 96 | - isBmiEnabled,
|
|
| 97 | - isBmi2Enabled,
|
|
| 81 | + targetCpuFeatures,
|
|
| 98 | 82 | -- For LoongArch platform
|
| 99 | 83 | isLa664Enabled
|
| 100 | 84 | ) where
|
| ... | ... | @@ -102,6 +86,7 @@ module GHC.Driver.DynFlags ( |
| 102 | 86 | import GHC.Prelude
|
| 103 | 87 | |
| 104 | 88 | import GHC.Platform
|
| 89 | +import GHC.Platform.CpuFeatures
|
|
| 105 | 90 | import GHC.Platform.Ways
|
| 106 | 91 | import GHC.Platform.Profile
|
| 107 | 92 | |
| ... | ... | @@ -460,18 +445,9 @@ data DynFlags = DynFlags { |
| 460 | 445 | |
| 461 | 446 | interactivePrint :: Maybe String,
|
| 462 | 447 | |
| 463 | - -- | Machine dependent flags (-m\<blah> stuff)
|
|
| 464 | - sseAvxVersion :: Maybe SseAvxVersion,
|
|
| 465 | - bmiVersion :: Maybe BmiVersion,
|
|
| 466 | - avx512bw :: Bool, -- ^ Enable AVX-512BW Instructions.
|
|
| 467 | - avx512cd :: Bool, -- ^ Enable AVX-512 Conflict Detection Instructions.
|
|
| 468 | - avx512dq :: Bool, -- ^ Enable AVX-512DQ Instructions.
|
|
| 469 | - avx512er :: Bool, -- ^ Enable AVX-512 Exponential and Reciprocal Instructions.
|
|
| 470 | - avx512f :: Bool, -- ^ Enable AVX-512 instructions.
|
|
| 471 | - avx512pf :: Bool, -- ^ Enable AVX-512 PreFetch Instructions.
|
|
| 472 | - avx512vl :: Bool, -- ^ Enable AVX-512VL Instructions.
|
|
| 473 | - fma :: Bool, -- ^ Enable FMA instructions.
|
|
| 474 | - gfni :: Bool, -- ^ Enable GFNI Instructions.
|
|
| 448 | + -- Machine dependent flags (-m\<blah> stuff)
|
|
| 449 | + cpuFeatures :: EnumSet CpuFeature, -- ^ The @-m\<feature\>@ flags that were passed.
|
|
| 450 | + -- See Note [CPU features] in GHC.Platform.CpuFeatures.
|
|
| 475 | 451 | la664 :: Bool, -- ^ Enable LA664 instructions
|
| 476 | 452 | |
| 477 | 453 | -- Constants used to control the amount of optimization done.
|
| ... | ... | @@ -751,18 +727,7 @@ defaultDynFlags mySettings = |
| 751 | 727 | profAuto = NoProfAuto,
|
| 752 | 728 | callerCcFilters = [],
|
| 753 | 729 | interactivePrint = Nothing,
|
| 754 | - sseAvxVersion = Nothing,
|
|
| 755 | - bmiVersion = Nothing,
|
|
| 756 | - avx512bw = False,
|
|
| 757 | - avx512cd = False,
|
|
| 758 | - avx512dq = False,
|
|
| 759 | - avx512er = False,
|
|
| 760 | - avx512f = False,
|
|
| 761 | - avx512pf = False,
|
|
| 762 | - avx512vl = False,
|
|
| 763 | - -- Use FMA by default on AArch64
|
|
| 764 | - fma = (platformArch . sTargetPlatform $ mySettings) == ArchAArch64,
|
|
| 765 | - gfni = False,
|
|
| 730 | + cpuFeatures = EnumSet.empty,
|
|
| 766 | 731 | -- For LoongArch, la464 is used by default.
|
| 767 | 732 | la664 = False,
|
| 768 | 733 | |
| ... | ... | @@ -1621,111 +1586,16 @@ initPromotionTickContext dflags = |
| 1621 | 1586 | }
|
| 1622 | 1587 | |
| 1623 | 1588 | -- -----------------------------------------------------------------------------
|
| 1624 | --- SSE, AVX, FMA
|
|
| 1589 | +-- CPU features
|
|
| 1625 | 1590 | |
| 1626 | -isSse3Enabled :: DynFlags -> Bool
|
|
| 1627 | -isSse3Enabled dflags = sseAvxVersion dflags >= Just SSE3 || isAvxEnabled dflags
|
|
| 1628 | - |
|
| 1629 | -isSsse3Enabled :: DynFlags -> Bool
|
|
| 1630 | -isSsse3Enabled dflags = sseAvxVersion dflags >= Just SSSE3 || isAvxEnabled dflags
|
|
| 1631 | - |
|
| 1632 | -isSse4_1Enabled :: DynFlags -> Bool
|
|
| 1633 | -isSse4_1Enabled dflags = sseAvxVersion dflags >= Just SSE4 || isAvxEnabled dflags
|
|
| 1634 | - |
|
| 1635 | -isSse4_2Enabled :: DynFlags -> Bool
|
|
| 1636 | -isSse4_2Enabled dflags = sseAvxVersion dflags >= Just SSE42 || isAvxEnabled dflags
|
|
| 1637 | - |
|
| 1638 | -isAvxEnabled :: DynFlags -> Bool
|
|
| 1639 | -isAvxEnabled dflags = sseAvxVersion dflags >= Just AVX1 || (isX86 && fma dflags) || isAvx512fEnabled dflags
|
|
| 1640 | - where
|
|
| 1641 | - -- -mfma can be used on multiple platforms, but -mavx is x86-only
|
|
| 1642 | - isX86 = case platformArch (targetPlatform dflags) of
|
|
| 1643 | - ArchX86_64 -> True
|
|
| 1644 | - ArchX86 -> True
|
|
| 1645 | - _ -> False
|
|
| 1646 | - |
|
| 1647 | -isAvx2Enabled :: DynFlags -> Bool
|
|
| 1648 | -isAvx2Enabled dflags = sseAvxVersion dflags >= Just AVX2 || isAvx512fEnabled dflags
|
|
| 1649 | - |
|
| 1650 | -isAvx512bwEnabled :: DynFlags -> Bool
|
|
| 1651 | -isAvx512bwEnabled dflags = avx512bw dflags
|
|
| 1652 | - |
|
| 1653 | -isAvx512cdEnabled :: DynFlags -> Bool
|
|
| 1654 | -isAvx512cdEnabled dflags = avx512cd dflags
|
|
| 1655 | - |
|
| 1656 | -isAvx512dqEnabled :: DynFlags -> Bool
|
|
| 1657 | -isAvx512dqEnabled dflags = avx512dq dflags
|
|
| 1658 | - |
|
| 1659 | -isAvx512erEnabled :: DynFlags -> Bool
|
|
| 1660 | -isAvx512erEnabled dflags = avx512er dflags
|
|
| 1661 | - |
|
| 1662 | -isAvx512fEnabled :: DynFlags -> Bool
|
|
| 1663 | -isAvx512fEnabled dflags = avx512f dflags || avx512bw dflags || avx512cd dflags || avx512dq dflags || avx512er dflags || avx512pf dflags || avx512vl dflags
|
|
| 1664 | - |
|
| 1665 | -isAvx512pfEnabled :: DynFlags -> Bool
|
|
| 1666 | -isAvx512pfEnabled dflags = avx512pf dflags
|
|
| 1667 | - |
|
| 1668 | -isAvx512vlEnabled :: DynFlags -> Bool
|
|
| 1669 | -isAvx512vlEnabled dflags = avx512vl dflags
|
|
| 1670 | - |
|
| 1671 | -isFmaEnabled :: DynFlags -> Bool
|
|
| 1672 | -isFmaEnabled dflags = fma dflags || (isX86 && isAvx512fEnabled dflags)
|
|
| 1673 | - where
|
|
| 1674 | - -- -mfma is used on multiple platforms, but -mavx512f is x86-only
|
|
| 1675 | - isX86 = case platformArch (targetPlatform dflags) of
|
|
| 1676 | - ArchX86_64 -> True
|
|
| 1677 | - ArchX86 -> True
|
|
| 1678 | - _ -> False
|
|
| 1679 | - |
|
| 1680 | -isGfniEnabled :: DynFlags -> Bool
|
|
| 1681 | -isGfniEnabled dflags = gfni dflags
|
|
| 1682 | - |
|
| 1683 | -{- Note [Implications between X86 CPU feature flags]
|
|
| 1684 | -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
| 1685 | -Many X86 CPU feature flags (such as -mavx, -mfma or -msse4) imply other
|
|
| 1686 | -feature flags. In particular, there are straightforward linear implication
|
|
| 1687 | -structures:
|
|
| 1688 | - |
|
| 1689 | - 1. AVX2 -> AVX -> SSE4.2 -> SSE4 -> SSSE3 -> SSE3 -> SSE2 -> SSE1
|
|
| 1690 | - 2. BMI2 -> BMI1
|
|
| 1691 | - |
|
| 1692 | -together with other implications such as
|
|
| 1693 | - |
|
| 1694 | - 3. FMA -> AVX
|
|
| 1695 | - 4. AVX512{BW,CD,DQ,ER,PF,VL} -> AVX512F -> AVX2
|
|
| 1696 | - |
|
| 1697 | - |
|
| 1698 | -We handle this as follows:
|
|
| 1699 | - |
|
| 1700 | - A. When parsing command line options into `DynFlags`, we record:
|
|
| 1701 | - - an `SseAvxVersion` which gives the SSE/AVX level supported in
|
|
| 1702 | - the total order (1),
|
|
| 1703 | - - a `BmiVersion` for (2),
|
|
| 1704 | - - whether FMA is enabled,
|
|
| 1705 | - - various AVX512 flags saying which AVX512 extensions are supported
|
|
| 1706 | - |
|
| 1707 | - B. When converting these "raw" `DynFlags` into a `CmmConfig` for use
|
|
| 1708 | - in code generator backends, we handle the remaining implications (3) (4),
|
|
| 1709 | - e.g. if the user passed -mavx512f then we also set the `SseAvxVersion`
|
|
| 1710 | - to `AVX2`.
|
|
| 1711 | --}
|
|
| 1591 | +-- | The CPU features enabled for the target.
|
|
| 1592 | +--
|
|
| 1593 | +-- See Note [CPU features] in GHC.Platform.CpuFeatures.
|
|
| 1594 | +targetCpuFeatures :: DynFlags -> CpuFeatures
|
|
| 1595 | +targetCpuFeatures dflags
|
|
| 1596 | + = initCpuFeatures (platformArch (targetPlatform dflags)) (cpuFeatures dflags)
|
|
| 1712 | 1597 | |
| 1713 | 1598 | -- -----------------------------------------------------------------------------
|
| 1714 | 1599 | -- LA664
|
| 1715 | 1600 | isLa664Enabled :: DynFlags -> Bool
|
| 1716 | 1601 | isLa664Enabled dflags = la664 dflags |
| 1717 | - |
|
| 1718 | --- -----------------------------------------------------------------------------
|
|
| 1719 | --- BMI2
|
|
| 1720 | - |
|
| 1721 | -isBmiEnabled :: DynFlags -> Bool
|
|
| 1722 | -isBmiEnabled dflags = case platformArch (targetPlatform dflags) of
|
|
| 1723 | - ArchX86_64 -> bmiVersion dflags >= Just BMI1
|
|
| 1724 | - ArchX86 -> bmiVersion dflags >= Just BMI1
|
|
| 1725 | - _ -> False
|
|
| 1726 | - |
|
| 1727 | -isBmi2Enabled :: DynFlags -> Bool
|
|
| 1728 | -isBmi2Enabled dflags = case platformArch (targetPlatform dflags) of
|
|
| 1729 | - ArchX86_64 -> bmiVersion dflags >= Just BMI2
|
|
| 1730 | - ArchX86 -> bmiVersion dflags >= Just BMI2
|
|
| 1731 | - _ -> False |
| ... | ... | @@ -39,6 +39,7 @@ import GHC.Fingerprint |
| 39 | 39 | import GHC.Utils.Logger
|
| 40 | 40 | import GHC.Utils.TmpFs
|
| 41 | 41 | import GHC.Platform
|
| 42 | +import GHC.Platform.CpuFeatures
|
|
| 42 | 43 | import Data.List (intercalate, isInfixOf)
|
| 43 | 44 | import qualified Data.List.NonEmpty as NE
|
| 44 | 45 | import GHC.Unit.Env
|
| ... | ... | @@ -968,35 +969,46 @@ llvmOptions llvm_config llvm_version dflags = |
| 968 | 969 | arch = platformArch platform
|
| 969 | 970 | |
| 970 | 971 | attrs :: String
|
| 971 | - attrs = intercalate "," $ mattr
|
|
| 972 | - ++ ["+sse4.2" | isSse4_2Enabled dflags ]
|
|
| 973 | - ++ ["+popcnt" | isSse4_2Enabled dflags ]
|
|
| 974 | - -- LLVM gates POPCNT instructions behind the popcnt flag,
|
|
| 975 | - -- while the GHC NCG (as well as GCC, Clang) gates it
|
|
| 976 | - -- behind SSE4.2 instead.
|
|
| 977 | - ++ ["+sse4.1" | isSse4_1Enabled dflags ]
|
|
| 978 | - ++ ["+ssse3" | isSsse3Enabled dflags ]
|
|
| 979 | - ++ ["+sse3" | isSse3Enabled dflags ]
|
|
| 980 | - ++ ["+sse2" | isSse2Enabled platform ]
|
|
| 981 | - ++ ["+sse" | isSseEnabled platform ]
|
|
| 982 | - ++ ["+avx512f" | isAvx512fEnabled dflags ]
|
|
| 983 | - ++ ["+evex512" | isAvx512fEnabled dflags
|
|
| 984 | - , maybe False (>= LlvmVersion (18 NE.:| [])) llvm_version ]
|
|
| 985 | - -- +evex512 is recognized by LLVM 18 or newer and needed on macOS (#26410).
|
|
| 986 | - -- It may become deprecated in a future LLVM version, though.
|
|
| 987 | - ++ ["+avx2" | isAvx2Enabled dflags ]
|
|
| 988 | - ++ ["+avx" | isAvxEnabled dflags ]
|
|
| 989 | - ++ ["+avx512bw"| isAvx512bwEnabled dflags ]
|
|
| 990 | - ++ ["+avx512cd"| isAvx512cdEnabled dflags ]
|
|
| 991 | - ++ ["+avx512dq"| isAvx512dqEnabled dflags ]
|
|
| 992 | - ++ ["+avx512er"| isAvx512erEnabled dflags ]
|
|
| 993 | - ++ ["+avx512pf"| isAvx512pfEnabled dflags ]
|
|
| 994 | - ++ ["+avx512vl"| isAvx512vlEnabled dflags ]
|
|
| 995 | - -- For AArch64 +fma is not a option (it's unconditionally available).
|
|
| 996 | - ++ ["+fma" | isFmaEnabled dflags && (arch /= ArchAArch64) ]
|
|
| 997 | - ++ ["+bmi" | isBmiEnabled dflags ]
|
|
| 998 | - ++ ["+bmi2" | isBmi2Enabled dflags ]
|
|
| 999 | - ++ ["+gfni" | isGfniEnabled dflags ]
|
|
| 972 | + attrs = intercalate "," $ mattr ++ cpu_attrs
|
|
| 973 | + |
|
| 974 | + cpu_attrs :: [String]
|
|
| 975 | + cpu_attrs = case targetCpuFeatures dflags of
|
|
| 976 | + X86CpuFeatures feats@(X86Features { x86SseAvx = sseAvx, x86Bmi = bmi, x86Gfni = gfni }) ->
|
|
| 977 | + let sse = x86SseVersion sseAvx
|
|
| 978 | + avx512 = x86Avx512Exts sseAvx
|
|
| 979 | + in [ "+sse" | sse >= SSE1 ]
|
|
| 980 | + ++ [ "+sse2" | sse >= SSE2 ]
|
|
| 981 | + ++ [ "+sse3" | sse >= SSE3 ]
|
|
| 982 | + ++ [ "+ssse3" | sse >= SSSE3 ]
|
|
| 983 | + ++ [ "+sse4.1" | sse >= SSE4 ]
|
|
| 984 | + ++ [ "+sse4.2" | sse >= SSE42 ]
|
|
| 985 | + ++ [ "+popcnt" | sse >= SSE42 ]
|
|
| 986 | + -- LLVM gates POPCNT instructions behind the popcnt flag,
|
|
| 987 | + -- while the GHC NCG (as well as GCC, Clang) gates it
|
|
| 988 | + -- behind SSE4.2 instead.
|
|
| 989 | + ++ [ "+avx" | x86AvxEnabled feats ]
|
|
| 990 | + ++ [ "+avx2" | x86Avx2Enabled feats ]
|
|
| 991 | + ++ [ "+fma" | x86FmaEnabled feats ]
|
|
| 992 | + ++ ( case avx512 of
|
|
| 993 | + Nothing -> []
|
|
| 994 | + Just (Avx512Exts { avx512bw = bw, avx512cd = cd, avx512dq = dq
|
|
| 995 | + , avx512er = er, avx512pf = pf, avx512vl = vl }) ->
|
|
| 996 | + [ "+avx512f" ]
|
|
| 997 | + ++ [ "+evex512" | maybe False (>= LlvmVersion (18 NE.:| [])) llvm_version ]
|
|
| 998 | + -- +evex512 is recognized by LLVM 18 or newer and needed on macOS (#26410).
|
|
| 999 | + -- It may become deprecated in a future LLVM version, though.
|
|
| 1000 | + ++ [ "+avx512bw" | bw ]
|
|
| 1001 | + ++ [ "+avx512cd" | cd ]
|
|
| 1002 | + ++ [ "+avx512dq" | dq ]
|
|
| 1003 | + ++ [ "+avx512er" | er ]
|
|
| 1004 | + ++ [ "+avx512pf" | pf ]
|
|
| 1005 | + ++ [ "+avx512vl" | vl ] )
|
|
| 1006 | + ++ [ "+bmi" | bmi >= Just BMI1 ]
|
|
| 1007 | + ++ [ "+bmi2" | bmi >= Just BMI2 ]
|
|
| 1008 | + ++ [ "+gfni" | gfni ]
|
|
| 1009 | + GenericCpuFeatures { genericFma = fma } ->
|
|
| 1010 | + -- For AArch64 +fma is not a option (it's unconditionally available).
|
|
| 1011 | + [ "+fma" | fma && arch /= ArchAArch64 ]
|
|
| 1000 | 1012 | |
| 1001 | 1013 | abi :: String
|
| 1002 | 1014 | abi = case platformArch (targetPlatform dflags) of
|
| ... | ... | @@ -204,24 +204,8 @@ module GHC.Driver.Session ( |
| 204 | 204 | |
| 205 | 205 | setUnsafeGlobalDynFlags,
|
| 206 | 206 | |
| 207 | - -- * SSE and AVX
|
|
| 208 | - isSse3Enabled,
|
|
| 209 | - isSsse3Enabled,
|
|
| 210 | - isSse4_1Enabled,
|
|
| 211 | - isSse4_2Enabled,
|
|
| 212 | - isBmiEnabled,
|
|
| 213 | - isBmi2Enabled,
|
|
| 214 | - isAvxEnabled,
|
|
| 215 | - isAvx2Enabled,
|
|
| 216 | - isAvx512bwEnabled,
|
|
| 217 | - isAvx512cdEnabled,
|
|
| 218 | - isAvx512dqEnabled,
|
|
| 219 | - isAvx512erEnabled,
|
|
| 220 | - isAvx512fEnabled,
|
|
| 221 | - isAvx512pfEnabled,
|
|
| 222 | - isAvx512vlEnabled,
|
|
| 223 | - isFmaEnabled,
|
|
| 224 | - isGfniEnabled,
|
|
| 207 | + -- * CPU features
|
|
| 208 | + targetCpuFeatures,
|
|
| 225 | 209 | |
| 226 | 210 | -- LoongArch: ISA version: la664, la464(default)
|
| 227 | 211 | isLa664Enabled,
|
| ... | ... | @@ -241,6 +225,7 @@ module GHC.Driver.Session ( |
| 241 | 225 | import GHC.Prelude
|
| 242 | 226 | |
| 243 | 227 | import GHC.Platform
|
| 228 | +import GHC.Platform.CpuFeatures
|
|
| 244 | 229 | import GHC.Platform.Ways
|
| 245 | 230 | import GHC.Platform.Profile
|
| 246 | 231 | import GHC.Platform.ArchOS
|
| ... | ... | @@ -1724,40 +1709,6 @@ dynamic_flags_deps = [ |
| 1724 | 1709 | (setDumpFlag Opt_D_dump_faststrings)
|
| 1725 | 1710 | |
| 1726 | 1711 | ------ Machine dependent (-m<blah>) stuff ---------------------------
|
| 1727 | - -- See Note [Implications between X86 CPU feature flags]
|
|
| 1728 | - |
|
| 1729 | - , make_ord_flag defGhcFlag "msse" (noArg (\d ->
|
|
| 1730 | - d { sseAvxVersion = max (Just SSE1) (sseAvxVersion d) }))
|
|
| 1731 | - , make_ord_flag defGhcFlag "msse2" (noArg (\d ->
|
|
| 1732 | - d { sseAvxVersion = max (Just SSE2) (sseAvxVersion d) }))
|
|
| 1733 | - , make_ord_flag defGhcFlag "msse3" (noArg (\d ->
|
|
| 1734 | - d { sseAvxVersion = max (Just SSE3) (sseAvxVersion d) }))
|
|
| 1735 | - , make_ord_flag defGhcFlag "mssse3" (noArg (\d ->
|
|
| 1736 | - d { sseAvxVersion = max (Just SSSE3) (sseAvxVersion d) }))
|
|
| 1737 | - , make_ord_flag defGhcFlag "msse4" (noArg (\d ->
|
|
| 1738 | - d { sseAvxVersion = max (Just SSE4) (sseAvxVersion d) }))
|
|
| 1739 | - , make_ord_flag defGhcFlag "msse4.2" (noArg (\d ->
|
|
| 1740 | - d { sseAvxVersion = max (Just SSE42) (sseAvxVersion d) }))
|
|
| 1741 | - , make_ord_flag defGhcFlag "mbmi" (noArg (\d ->
|
|
| 1742 | - d { bmiVersion = max (Just BMI1) (bmiVersion d) }))
|
|
| 1743 | - , make_ord_flag defGhcFlag "mbmi2" (noArg (\d ->
|
|
| 1744 | - d { bmiVersion = Just BMI2 }))
|
|
| 1745 | - , make_ord_flag defGhcFlag "mavx" (noArg (\d ->
|
|
| 1746 | - d { sseAvxVersion = max (Just AVX1) (sseAvxVersion d) }))
|
|
| 1747 | - , make_ord_flag defGhcFlag "mavx2" (noArg (\d ->
|
|
| 1748 | - d { sseAvxVersion = max (Just AVX2) (sseAvxVersion d) }))
|
|
| 1749 | - , make_ord_flag defGhcFlag "mavx512bw" (noArg (\d -> d { avx512bw = True }))
|
|
| 1750 | - , make_ord_flag defGhcFlag "mavx512cd" (noArg (\d -> d { avx512cd = True }))
|
|
| 1751 | - , make_ord_flag defGhcFlag "mavx512dq" (noArg (\d -> d { avx512dq = True }))
|
|
| 1752 | - , make_dep_flag defGhcFlag "mavx512er" (noArg (\d -> d { avx512er = True }))
|
|
| 1753 | - "AVX-512ER was only available on Xeon Phi"
|
|
| 1754 | - , make_ord_flag defGhcFlag "mavx512f" (noArg (\d -> d { avx512f = True }))
|
|
| 1755 | - , make_dep_flag defGhcFlag "mavx512pf" (noArg (\d -> d { avx512pf = True }))
|
|
| 1756 | - "AVX-512PF was only available on Xeon Phi"
|
|
| 1757 | - , make_ord_flag defGhcFlag "mavx512vl" (noArg (\d -> d { avx512vl = True }))
|
|
| 1758 | - , make_ord_flag defGhcFlag "mfma" (noArg (\d -> d { fma = True }))
|
|
| 1759 | - , make_ord_flag defGhcFlag "mgfni" (noArg (\d -> d { gfni = True }))
|
|
| 1760 | - |
|
| 1761 | 1712 | |
| 1762 | 1713 | , make_ord_flag defGhcFlag "mla664" (noArg (\d -> d { la664 = True }))
|
| 1763 | 1714 | |
| ... | ... | @@ -2021,6 +1972,11 @@ dynamic_flags_deps = [ |
| 2021 | 1972 | ------ Debugging flags ----------------------------------------------
|
| 2022 | 1973 | , make_ord_flag defGhcFlag "g" (OptIntSuffix setDebugLevel)
|
| 2023 | 1974 | ]
|
| 1975 | + ------ CPU features -------------------------------------------------
|
|
| 1976 | + ++ map cpuFeatureFlagDep [minBound .. maxBound]
|
|
| 1977 | + |
|
| 1978 | + ------ Negation -----------------------------------------------------
|
|
| 1979 | + |
|
| 2024 | 1980 | ++ map (mkFlag turnOn "" setGeneralFlag ) negatableFlagsDeps
|
| 2025 | 1981 | ++ map (mkFlag turnOff "no-" unSetGeneralFlag ) negatableFlagsDeps
|
| 2026 | 1982 | ++ map (mkFlag turnOn "d" setGeneralFlag ) dFlagsDeps
|
| ... | ... | @@ -2975,6 +2931,18 @@ optIntSuffixM fn = OptIntSuffix (\mi -> updM (fn mi)) |
| 2975 | 2931 | setDumpFlag :: DumpFlag -> OptKind (CmdLineP DynFlags)
|
| 2976 | 2932 | setDumpFlag dump_flag = NoArg (setDumpFlag' dump_flag)
|
| 2977 | 2933 | |
| 2934 | +setCpuFeature :: CpuFeature -> DynFlags -> DynFlags
|
|
| 2935 | +setCpuFeature feat dflags = dflags { cpuFeatures = EnumSet.insert feat (cpuFeatures dflags) }
|
|
| 2936 | + |
|
| 2937 | +-- | The @-m\<feature\>@ flag for a 'CpuFeature'.
|
|
| 2938 | +cpuFeatureFlagDep :: CpuFeature -> (Deprecation, Flag (CmdLineP DynFlags))
|
|
| 2939 | +cpuFeatureFlagDep feat =
|
|
| 2940 | + case cpuFeatureFlag feat of
|
|
| 2941 | + (name, Nothing ) -> make_ord_flag defGhcFlag ('m' : name) set
|
|
| 2942 | + (name, Just msg) -> make_dep_flag defGhcFlag ('m' : name) set msg
|
|
| 2943 | + where
|
|
| 2944 | + set = noArg (setCpuFeature feat)
|
|
| 2945 | + |
|
| 2978 | 2946 | --------------------------
|
| 2979 | 2947 | addWayDynP :: Way -> DynP ()
|
| 2980 | 2948 | addWayDynP = upd . addWay'
|
| ... | ... | @@ -29,12 +29,7 @@ module GHC.Platform |
| 29 | 29 | , platformCConvNeedsExtension
|
| 30 | 30 | , platformHasRTSLinker
|
| 31 | 31 | , PlatformMisc(..)
|
| 32 | - , SseAvxVersion (..)
|
|
| 33 | - , BmiVersion (..)
|
|
| 34 | 32 | , wordAlignment
|
| 35 | - -- * SSE and AVX
|
|
| 36 | - , isSseEnabled
|
|
| 37 | - , isSse2Enabled
|
|
| 38 | 33 | -- * Platform constants
|
| 39 | 34 | , PlatformConstants(..)
|
| 40 | 35 | , lookupPlatformConstants
|
| ... | ... | @@ -116,33 +111,6 @@ data Platform = Platform |
| 116 | 111 | wordAlignment :: Platform -> Alignment
|
| 117 | 112 | wordAlignment platform = alignmentOf (platformWordSizeInBytes platform)
|
| 118 | 113 | |
| 119 | --- -----------------------------------------------------------------------------
|
|
| 120 | --- SSE and AVX
|
|
| 121 | - |
|
| 122 | --- TODO: Instead of using a separate predicate (i.e. isSse2Enabled) to
|
|
| 123 | --- check if SSE is enabled, we might have x86-64 imply the -msse2
|
|
| 124 | --- flag.
|
|
| 125 | - |
|
| 126 | -isSseEnabled :: Platform -> Bool
|
|
| 127 | -isSseEnabled platform = case platformArch platform of
|
|
| 128 | - ArchX86_64 -> True
|
|
| 129 | - ArchX86 -> True
|
|
| 130 | - _ -> False
|
|
| 131 | - |
|
| 132 | -isSse2Enabled :: Platform -> Bool
|
|
| 133 | -isSse2Enabled platform = case platformArch platform of
|
|
| 134 | - -- We assume SSE1 and SSE2 operations are available on both
|
|
| 135 | - -- x86 and x86_64. Historically we didn't default to SSE2 and
|
|
| 136 | - -- SSE1 on x86, which results in defacto nondeterminism for how
|
|
| 137 | - -- rounding behaves in the associated x87 floating point instructions
|
|
| 138 | - -- because variations in the spill/fpu stack placement of arguments for
|
|
| 139 | - -- operations would change the precision and final result of what
|
|
| 140 | - -- would otherwise be the same expressions with respect to single or
|
|
| 141 | - -- double precision IEEE floating point computations.
|
|
| 142 | - ArchX86_64 -> True
|
|
| 143 | - ArchX86 -> True
|
|
| 144 | - _ -> False
|
|
| 145 | - |
|
| 146 | 114 | -- -----------------------------------------------------------------------------
|
| 147 | 115 | -- Platform Constants
|
| 148 | 116 | |
| ... | ... | @@ -279,28 +247,6 @@ platformHasRTSLinker p = case archOS_arch (platformArchOS p) of |
| 279 | 247 | |
| 280 | 248 | |
| 281 | 249 | |
| 282 | ---------------------------------------------------
|
|
| 283 | --- Instruction sets
|
|
| 284 | ---------------------------------------------------
|
|
| 285 | - |
|
| 286 | --- | x86 SSE and AVX instructions
|
|
| 287 | -data SseAvxVersion
|
|
| 288 | - = SSE1
|
|
| 289 | - | SSE2
|
|
| 290 | - | SSE3
|
|
| 291 | - | SSSE3
|
|
| 292 | - | SSE4
|
|
| 293 | - | SSE42
|
|
| 294 | - | AVX1
|
|
| 295 | - | AVX2
|
|
| 296 | - deriving (Eq, Ord)
|
|
| 297 | - |
|
| 298 | --- | x86 BMI (bit manipulation) instructions
|
|
| 299 | -data BmiVersion
|
|
| 300 | - = BMI1
|
|
| 301 | - | BMI2
|
|
| 302 | - deriving (Eq, Ord)
|
|
| 303 | - |
|
| 304 | 250 | -- | Platform-specific settings formerly hard-coded in Config.hs.
|
| 305 | 251 | --
|
| 306 | 252 | -- These should probably be all be triaged whether they can be computed from
|
| 1 | +{-# LANGUAGE LambdaCase #-}
|
|
| 2 | + |
|
| 3 | +-- | CPU features and corresponding @-m\<feature\>@ flags.
|
|
| 4 | +--
|
|
| 5 | +-- See Note [CPU features].
|
|
| 6 | +module GHC.Platform.CpuFeatures
|
|
| 7 | + ( -- * Feature flags
|
|
| 8 | + CpuFeature (..)
|
|
| 9 | + , cpuFeatureFlag
|
|
| 10 | + |
|
| 11 | + -- * Enabled instruction sets
|
|
| 12 | + , CpuFeatures (..)
|
|
| 13 | + , initCpuFeatures
|
|
| 14 | + , cpuFmaEnabled
|
|
| 15 | + |
|
| 16 | + -- ** x86
|
|
| 17 | + , X86Features (..)
|
|
| 18 | + , SseAvxVersion (..)
|
|
| 19 | + , AvxLevel (..)
|
|
| 20 | + , x86SseVersion
|
|
| 21 | + , x86Avx512Exts
|
|
| 22 | + , sseAvxVersionIncludes
|
|
| 23 | + , unionSseAvxVersion
|
|
| 24 | + , sseAvxVectorRequirement
|
|
| 25 | + , x86BaselineSseAvx
|
|
| 26 | + , sseAvxVersionFlags
|
|
| 27 | + , SseVersion (..)
|
|
| 28 | + , Avx512Exts (..)
|
|
| 29 | + , noAvx512Exts
|
|
| 30 | + , BmiVersion (..)
|
|
| 31 | + |
|
| 32 | + -- *** Querying x86 features
|
|
| 33 | + -- | These are not independent; see Note [CPU features].
|
|
| 34 | + , x86Ssse3Enabled
|
|
| 35 | + , x86Sse4_1Enabled
|
|
| 36 | + , x86Sse4_2Enabled
|
|
| 37 | + , x86AvxEnabled
|
|
| 38 | + , x86Avx2Enabled
|
|
| 39 | + , x86FmaEnabled
|
|
| 40 | + , x86Avx512FEnabled
|
|
| 41 | + , x86Avx512DQEnabled
|
|
| 42 | + , x86Avx512VLEnabled
|
|
| 43 | + , x86Bmi2Enabled
|
|
| 44 | + )
|
|
| 45 | +where
|
|
| 46 | + |
|
| 47 | +import GHC.Prelude
|
|
| 48 | + |
|
| 49 | +import GHC.Platform.ArchOS
|
|
| 50 | +import GHC.Data.EnumSet (EnumSet)
|
|
| 51 | +import qualified GHC.Data.EnumSet as EnumSet
|
|
| 52 | + |
|
| 53 | +import Data.Maybe (isJust)
|
|
| 54 | + |
|
| 55 | +{- Note [CPU features]
|
|
| 56 | +~~~~~~~~~~~~~~~~~~~~~~
|
|
| 57 | +The -m<feature> flags enable CPU instruction set extensions. Many of them imply
|
|
| 58 | +others:
|
|
| 59 | + |
|
| 60 | + 1. AVX2 -> AVX -> SSE4.2 -> SSE4 -> SSSE3 -> SSE3 -> SSE2 -> SSE1
|
|
| 61 | + 2. BMI2 -> BMI1
|
|
| 62 | + 3. FMA -> AVX (on X86)
|
|
| 63 | + 4. AVX512{BW,CD,DQ,ER,PF,VL} -> AVX512F -> AVX2 + FMA
|
|
| 64 | + |
|
| 65 | +We keep two representations:
|
|
| 66 | + |
|
| 67 | + A. 'DynFlags' records the set of flags that were passed, as an
|
|
| 68 | + 'EnumSet' of 'CpuFeature'. Nothing is implied at this stage.
|
|
| 69 | + |
|
| 70 | + B. 'initCpuFeatures' turns this set into a 'CpuFeatures' value, applying the
|
|
| 71 | + implications and the baseline of the target architecture. This
|
|
| 72 | + representation makes the implications structural: 'SseAvxVersion' is a
|
|
| 73 | + point in the total order (1), FMA can only be recorded together with AVX,
|
|
| 74 | + and AVX-512 sits above AVX2 and FMA.
|
|
| 75 | + |
|
| 76 | +Code generation and the driver only consult the second representation, so
|
|
| 77 | +whether an instruction set is enabled is decided in one place.
|
|
| 78 | +-}
|
|
| 79 | + |
|
| 80 | +-- | A CPU feature flag, @-m\<feature\>@.
|
|
| 81 | +data CpuFeature
|
|
| 82 | + = Feat_SSE
|
|
| 83 | + | Feat_SSE2
|
|
| 84 | + | Feat_SSE3
|
|
| 85 | + | Feat_SSSE3
|
|
| 86 | + | Feat_SSE4
|
|
| 87 | + | Feat_SSE4_2
|
|
| 88 | + | Feat_AVX
|
|
| 89 | + | Feat_AVX2
|
|
| 90 | + | Feat_AVX512F
|
|
| 91 | + | Feat_AVX512BW
|
|
| 92 | + | Feat_AVX512CD
|
|
| 93 | + | Feat_AVX512DQ
|
|
| 94 | + | Feat_AVX512ER
|
|
| 95 | + | Feat_AVX512PF
|
|
| 96 | + | Feat_AVX512VL
|
|
| 97 | + | Feat_FMA
|
|
| 98 | + | Feat_BMI
|
|
| 99 | + | Feat_BMI2
|
|
| 100 | + | Feat_GFNI
|
|
| 101 | + deriving (Eq, Show, Enum, Bounded)
|
|
| 102 | + |
|
| 103 | +-- | The name of the @-m\<feature\>@ flag for a 'CpuFeature' (without the
|
|
| 104 | +-- leading @m@).
|
|
| 105 | +--
|
|
| 106 | +-- Additionally returns an optional deprecation message.
|
|
| 107 | +cpuFeatureFlag :: CpuFeature -> (String, Maybe String)
|
|
| 108 | +cpuFeatureFlag = \case
|
|
| 109 | + Feat_SSE -> ("sse" , Nothing)
|
|
| 110 | + Feat_SSE2 -> ("sse2" , Nothing)
|
|
| 111 | + Feat_SSE3 -> ("sse3" , Nothing)
|
|
| 112 | + Feat_SSSE3 -> ("ssse3" , Nothing)
|
|
| 113 | + Feat_SSE4 -> ("sse4" , Nothing)
|
|
| 114 | + Feat_SSE4_2 -> ("sse4.2" , Nothing)
|
|
| 115 | + Feat_AVX -> ("avx" , Nothing)
|
|
| 116 | + Feat_AVX2 -> ("avx2" , Nothing)
|
|
| 117 | + Feat_AVX512F -> ("avx512f" , Nothing)
|
|
| 118 | + Feat_AVX512BW -> ("avx512bw" , Nothing)
|
|
| 119 | + Feat_AVX512CD -> ("avx512cd" , Nothing)
|
|
| 120 | + Feat_AVX512DQ -> ("avx512dq" , Nothing)
|
|
| 121 | + Feat_AVX512ER -> ("avx512er" , Just "AVX-512ER was only available on Xeon Phi")
|
|
| 122 | + Feat_AVX512PF -> ("avx512pf" , Just "AVX-512PF was only available on Xeon Phi")
|
|
| 123 | + Feat_AVX512VL -> ("avx512vl" , Nothing)
|
|
| 124 | + Feat_FMA -> ("fma" , Nothing)
|
|
| 125 | + Feat_BMI -> ("bmi" , Nothing)
|
|
| 126 | + Feat_BMI2 -> ("bmi2" , Nothing)
|
|
| 127 | + Feat_GFNI -> ("gfni" , Nothing)
|
|
| 128 | + |
|
| 129 | +-- | The CPU features that are enabled for the target.
|
|
| 130 | +--
|
|
| 131 | +-- See Note [CPU features].
|
|
| 132 | +data CpuFeatures
|
|
| 133 | + -- | x86 and x86_64 CPU features.
|
|
| 134 | + = X86CpuFeatures !X86Features
|
|
| 135 | + -- | A generic set of CPU features.
|
|
| 136 | + --
|
|
| 137 | + -- For now, code generation for non-X86 architectures assumes a fixed
|
|
| 138 | + -- baseline ISA, with the only exception of FMA support.
|
|
| 139 | + --
|
|
| 140 | + -- In the future, we can add architecture-specific constructors, e.g. for
|
|
| 141 | + -- RISC-V (vector support, bit manipulation, etc).
|
|
| 142 | + | GenericCpuFeatures
|
|
| 143 | + { genericFma :: !Bool -- ^ are FMA operations enabled?
|
|
| 144 | + }
|
|
| 145 | + deriving (Eq, Show)
|
|
| 146 | + |
|
| 147 | +-- | The CPU features enabled by the given flags on the given architecture.
|
|
| 148 | +--
|
|
| 149 | +-- See Note [CPU features].
|
|
| 150 | +initCpuFeatures :: Arch -> EnumSet CpuFeature -> CpuFeatures
|
|
| 151 | +initCpuFeatures arch feats = case arch of
|
|
| 152 | + ArchX86 -> X86CpuFeatures (initX86Features feats)
|
|
| 153 | + ArchX86_64 -> X86CpuFeatures (initX86Features feats)
|
|
| 154 | + -- AArch64 always has fused multiply-add instructions.
|
|
| 155 | + ArchAArch64 -> GenericCpuFeatures { genericFma = True }
|
|
| 156 | + _ -> GenericCpuFeatures { genericFma = EnumSet.member Feat_FMA feats }
|
|
| 157 | + |
|
| 158 | +-- | Whether fused multiply-add instructions are enabled.
|
|
| 159 | +cpuFmaEnabled :: CpuFeatures -> Bool
|
|
| 160 | +cpuFmaEnabled = \case
|
|
| 161 | + X86CpuFeatures feats -> x86FmaEnabled feats
|
|
| 162 | + GenericCpuFeatures { genericFma = fma } -> fma
|
|
| 163 | + |
|
| 164 | +--------------------------------------------------------------------------------
|
|
| 165 | +-- x86
|
|
| 166 | + |
|
| 167 | +-- | The x86 CPU features that are enabled.
|
|
| 168 | +data X86Features = X86Features
|
|
| 169 | + { x86SseAvx :: !SseAvxVersion
|
|
| 170 | + , x86Bmi :: !(Maybe BmiVersion)
|
|
| 171 | + , x86Gfni :: !Bool
|
|
| 172 | + }
|
|
| 173 | + deriving (Eq, Show)
|
|
| 174 | + |
|
| 175 | +-- | Enabled SSE/AVX instruction sets, and whether FMA is enabled.
|
|
| 176 | +--
|
|
| 177 | +-- See Note [CPU features].
|
|
| 178 | +data SseAvxVersion
|
|
| 179 | + -- | SSE, but no AVX (and thus no FMA).
|
|
| 180 | + = Sse !SseVersion
|
|
| 181 | + -- | AVX, and potentially more (AVX2, FMA, etc).
|
|
| 182 | + | Avx !AvxLevel
|
|
| 183 | + deriving (Eq, Show)
|
|
| 184 | +-- NB: no 'Ord' instance, as this is only a partial order.
|
|
| 185 | +-- See 'sseAvxVersionIncludes'.
|
|
| 186 | + |
|
| 187 | +-- | Level of enabled AVX instruction sets, and whether FMA is enabled.
|
|
| 188 | +data AvxLevel
|
|
| 189 | + -- | AVX (with or without FMA).
|
|
| 190 | + = Avx1 { avxFma :: !Bool }
|
|
| 191 | + -- | AVX2 (with or without FMA).
|
|
| 192 | + | Avx2 { avxFma :: !Bool }
|
|
| 193 | + -- | AVX-512F (which includes AVX2 and FMA), with the given extensions.
|
|
| 194 | + | Avx512 !Avx512Exts
|
|
| 195 | + deriving (Eq, Show)
|
|
| 196 | + |
|
| 197 | +-- | x86 SSE instruction sets (each including the previous ones).
|
|
| 198 | +data SseVersion
|
|
| 199 | + = SSE1
|
|
| 200 | + | SSE2
|
|
| 201 | + | SSE3
|
|
| 202 | + | SSSE3
|
|
| 203 | + | SSE4
|
|
| 204 | + | SSE42
|
|
| 205 | + deriving (Eq, Ord, Show)
|
|
| 206 | + |
|
| 207 | +-- | The AVX-512 extensions beyond AVX-512F.
|
|
| 208 | +data Avx512Exts = Avx512Exts
|
|
| 209 | + { avx512bw :: !Bool -- ^ byte and word operations
|
|
| 210 | + , avx512cd :: !Bool -- ^ conflict detection
|
|
| 211 | + , avx512dq :: !Bool -- ^ doubleword and quadword operations
|
|
| 212 | + , avx512er :: !Bool -- ^ exponential and reciprocal
|
|
| 213 | + , avx512pf :: !Bool -- ^ prefetch
|
|
| 214 | + , avx512vl :: !Bool -- ^ AVX-512 instructions on 128-bit and 256-bit vectors
|
|
| 215 | + }
|
|
| 216 | + deriving (Eq, Show)
|
|
| 217 | + |
|
| 218 | +noAvx512Exts :: Avx512Exts
|
|
| 219 | +noAvx512Exts = Avx512Exts False False False False False False
|
|
| 220 | + |
|
| 221 | +-- | x86 BMI (bit manipulation) instruction sets (BMI2 including BMI1).
|
|
| 222 | +data BmiVersion
|
|
| 223 | + = BMI1
|
|
| 224 | + | BMI2
|
|
| 225 | + deriving (Eq, Ord, Show)
|
|
| 226 | + |
|
| 227 | + |
|
| 228 | +-- | The baseline ISA that we assume for both x86 and x86_64: SSE2.
|
|
| 229 | +--
|
|
| 230 | +-- Historical remark: prior to GHC 8.10, we used to not require SSE2 on 32-bit
|
|
| 231 | +-- x86 architectures. This resulted in defacto nondeterminism for rounding
|
|
| 232 | +-- behaviour due to oddities of the x87 stack-based floating-point implementation.
|
|
| 233 | +x86BaselineSseAvx :: SseAvxVersion
|
|
| 234 | +x86BaselineSseAvx = Sse SSE2
|
|
| 235 | + |
|
| 236 | +-- | Enable the user-specified features, on top of the X86 baseline feature set
|
|
| 237 | +-- ('x86BaselineSseAvx').
|
|
| 238 | +--
|
|
| 239 | +-- The implication structure of CPU feature flags is detailed in Note [CPU features].
|
|
| 240 | +initX86Features
|
|
| 241 | + :: EnumSet CpuFeature -- ^ user-enabled features
|
|
| 242 | + -> X86Features
|
|
| 243 | +initX86Features feats = X86Features
|
|
| 244 | + { x86SseAvx = sseAvx
|
|
| 245 | + , x86Bmi = bmi
|
|
| 246 | + , x86Gfni = has Feat_GFNI
|
|
| 247 | + }
|
|
| 248 | + where
|
|
| 249 | + has = (`EnumSet.member` feats)
|
|
| 250 | + fma = has Feat_FMA
|
|
| 251 | + avx512 = Avx512Exts
|
|
| 252 | + { avx512bw = has Feat_AVX512BW
|
|
| 253 | + , avx512cd = has Feat_AVX512CD
|
|
| 254 | + , avx512dq = has Feat_AVX512DQ
|
|
| 255 | + , avx512er = has Feat_AVX512ER
|
|
| 256 | + , avx512pf = has Feat_AVX512PF
|
|
| 257 | + , avx512vl = has Feat_AVX512VL
|
|
| 258 | + }
|
|
| 259 | + sseAvx
|
|
| 260 | + | has Feat_AVX512F || avx512 /= noAvx512Exts = Avx (Avx512 avx512)
|
|
| 261 | + | has Feat_AVX2 = Avx (Avx2 fma)
|
|
| 262 | + | has Feat_AVX || fma = Avx (Avx1 fma)
|
|
| 263 | + | has Feat_SSE4_2 = Sse SSE42
|
|
| 264 | + | has Feat_SSE4 = Sse SSE4
|
|
| 265 | + | has Feat_SSSE3 = Sse SSSE3
|
|
| 266 | + | has Feat_SSE3 = Sse SSE3
|
|
| 267 | + | otherwise = x86BaselineSseAvx
|
|
| 268 | + bmi
|
|
| 269 | + | has Feat_BMI2 = Just BMI2
|
|
| 270 | + | has Feat_BMI = Just BMI1
|
|
| 271 | + | otherwise = Nothing
|
|
| 272 | + |
|
| 273 | +x86SseVersion :: SseAvxVersion -> SseVersion
|
|
| 274 | +x86SseVersion = \case
|
|
| 275 | + Sse v -> v
|
|
| 276 | + Avx _ -> SSE42
|
|
| 277 | + |
|
| 278 | +x86Avx512Exts :: SseAvxVersion -> Maybe Avx512Exts
|
|
| 279 | +x86Avx512Exts = \case
|
|
| 280 | + Avx (Avx512 exts) -> Just exts
|
|
| 281 | + _ -> Nothing
|
|
| 282 | + |
|
| 283 | +--------------------------------------------------------------------------------
|
|
| 284 | +-- Querying x86 features
|
|
| 285 | + |
|
| 286 | +-- NB: the predicates below are not independent, because there are implications
|
|
| 287 | +-- between feature flags (e.g. AVX2 implies SSE4.2).
|
|
| 288 | +--
|
|
| 289 | +-- See Note [CPU features].
|
|
| 290 | + |
|
| 291 | +x86Ssse3Enabled :: X86Features -> Bool
|
|
| 292 | +x86Ssse3Enabled = (>= SSSE3) . x86SseVersion . x86SseAvx
|
|
| 293 | + |
|
| 294 | +x86Sse4_1Enabled :: X86Features -> Bool
|
|
| 295 | +x86Sse4_1Enabled = (>= SSE4) . x86SseVersion . x86SseAvx
|
|
| 296 | + |
|
| 297 | +x86Sse4_2Enabled :: X86Features -> Bool
|
|
| 298 | +x86Sse4_2Enabled = (>= SSE42) . x86SseVersion . x86SseAvx
|
|
| 299 | + |
|
| 300 | +x86AvxEnabled :: X86Features -> Bool
|
|
| 301 | +x86AvxEnabled feats = case x86SseAvx feats of
|
|
| 302 | + Sse _ -> False
|
|
| 303 | + Avx _ -> True
|
|
| 304 | + |
|
| 305 | +x86Avx2Enabled :: X86Features -> Bool
|
|
| 306 | +x86Avx2Enabled feats = case x86SseAvx feats of
|
|
| 307 | + Sse _ -> False
|
|
| 308 | + Avx (Avx1 _) -> False
|
|
| 309 | + Avx (Avx2 _) -> True
|
|
| 310 | + Avx (Avx512 _) -> True
|
|
| 311 | + |
|
| 312 | +x86FmaEnabled :: X86Features -> Bool
|
|
| 313 | +x86FmaEnabled feats = case x86SseAvx feats of
|
|
| 314 | + Sse _ -> False
|
|
| 315 | + Avx (Avx1 fma) -> fma
|
|
| 316 | + Avx (Avx2 fma) -> fma
|
|
| 317 | + Avx (Avx512 _) -> True
|
|
| 318 | + |
|
| 319 | +x86Avx512FEnabled :: X86Features -> Bool
|
|
| 320 | +x86Avx512FEnabled = isJust . x86Avx512Exts . x86SseAvx
|
|
| 321 | + |
|
| 322 | +x86Avx512DQEnabled :: X86Features -> Bool
|
|
| 323 | +x86Avx512DQEnabled = maybe False avx512dq . x86Avx512Exts . x86SseAvx
|
|
| 324 | + |
|
| 325 | +x86Avx512VLEnabled :: X86Features -> Bool
|
|
| 326 | +x86Avx512VLEnabled = maybe False avx512vl . x86Avx512Exts . x86SseAvx
|
|
| 327 | + |
|
| 328 | +x86Bmi2Enabled :: X86Features -> Bool
|
|
| 329 | +x86Bmi2Enabled = (>= Just BMI2) . x86Bmi
|
|
| 330 | + |
|
| 331 | +--------------------------------------------------------------------------------
|
|
| 332 | +-- Comparing x86 feature sets
|
|
| 333 | + |
|
| 334 | +-- | @enabled \`sseAvxVersionIncludes\` required@ answers whether the @enabled@
|
|
| 335 | +-- features provide everything required by @required@, taking into account
|
|
| 336 | +-- implications between instruction sets. See Note [CPU features].
|
|
| 337 | +--
|
|
| 338 | +-- This is a partial order, as FMA and the AVX-512 extensions are independent
|
|
| 339 | +-- of each other.
|
|
| 340 | +sseAvxVersionIncludes :: SseAvxVersion -> SseAvxVersion -> Bool
|
|
| 341 | +sseAvxVersionIncludes enabled required = case (enabled, required) of
|
|
| 342 | + (Sse e, Sse r) -> e >= r
|
|
| 343 | + (Avx _, Sse _) -> True
|
|
| 344 | + (Sse _, Avx _) -> False
|
|
| 345 | + (Avx e, Avx r) -> e `avxLevelIncludes` r
|
|
| 346 | + where
|
|
| 347 | + avxLevelIncludes :: AvxLevel -> AvxLevel -> Bool
|
|
| 348 | + avxLevelIncludes e r = case (e, r) of
|
|
| 349 | + (Avx512 ee, Avx512 re) -> ee `avx512ExtsInclude` re
|
|
| 350 | + (Avx512 _, _) -> True
|
|
| 351 | + (_, Avx512 _) -> False
|
|
| 352 | + (Avx1 ef, Avx1 rf) -> rf `implies` ef
|
|
| 353 | + (Avx2 ef, Avx1 rf) -> rf `implies` ef
|
|
| 354 | + (Avx2 ef, Avx2 rf) -> rf `implies` ef
|
|
| 355 | + (Avx1 _, Avx2 _) -> False
|
|
| 356 | + |
|
| 357 | + avx512ExtsInclude :: Avx512Exts -> Avx512Exts -> Bool
|
|
| 358 | + avx512ExtsInclude
|
|
| 359 | + (Avx512Exts ebw ecd edq eer epf evl)
|
|
| 360 | + (Avx512Exts rbw rcd rdq rer rpf rvl)
|
|
| 361 | + = rbw `implies` ebw
|
|
| 362 | + && rcd `implies` ecd
|
|
| 363 | + && rdq `implies` edq
|
|
| 364 | + && rer `implies` eer
|
|
| 365 | + && rpf `implies` epf
|
|
| 366 | + && rvl `implies` evl
|
|
| 367 | + |
|
| 368 | + implies :: Bool -> Bool -> Bool
|
|
| 369 | + implies a b = b || not a
|
|
| 370 | + |
|
| 371 | +-- | The least 'SseAvxVersion' providing everything that both arguments do.
|
|
| 372 | +unionSseAvxVersion :: SseAvxVersion -> SseAvxVersion -> SseAvxVersion
|
|
| 373 | +unionSseAvxVersion v1 v2 = case (v1, v2) of
|
|
| 374 | + (Sse a, Sse b) -> Sse (max a b)
|
|
| 375 | + (Sse _, Avx _) -> v2
|
|
| 376 | + (Avx _, Sse _) -> v1
|
|
| 377 | + (Avx a, Avx b) -> Avx (a `avxLevelJoin` b)
|
|
| 378 | + where
|
|
| 379 | + avxLevelJoin :: AvxLevel -> AvxLevel -> AvxLevel
|
|
| 380 | + avxLevelJoin a b = case (a, b) of
|
|
| 381 | + (Avx512 ea, Avx512 eb) -> Avx512 (ea `avx512ExtsUnion` eb)
|
|
| 382 | + (Avx512 _, _) -> a
|
|
| 383 | + (_, Avx512 _) -> b
|
|
| 384 | + (Avx1 fa, Avx1 fb) -> Avx1 (fa || fb)
|
|
| 385 | + (Avx1 fa, Avx2 fb) -> Avx2 (fa || fb)
|
|
| 386 | + (Avx2 fa, Avx1 fb) -> Avx2 (fa || fb)
|
|
| 387 | + (Avx2 fa, Avx2 fb) -> Avx2 (fa || fb)
|
|
| 388 | + avx512ExtsUnion (Avx512Exts bw1 cd1 dq1 er1 pf1 vl1) (Avx512Exts bw2 cd2 dq2 er2 pf2 vl2)
|
|
| 389 | + = Avx512Exts (bw1 || bw2) (cd1 || cd2) (dq1 || dq2) (er1 || er2) (pf1 || pf2) (vl1 || vl2)
|
|
| 390 | + |
|
| 391 | +-- | The SSE/AVX instruction sets required to operate on vectors of the given
|
|
| 392 | +-- width in bits, with floating-point or integer elements.
|
|
| 393 | +--
|
|
| 394 | +-- 128-bit vectors need SSE2 (SSE1 only covers single-precision elements).
|
|
| 395 | +sseAvxVectorRequirement
|
|
| 396 | + :: Bool -- ^ floating-point elements?
|
|
| 397 | + -> Int -- ^ width of the vector, in bits
|
|
| 398 | + -> SseAvxVersion
|
|
| 399 | +sseAvxVectorRequirement float bits
|
|
| 400 | + | bits <= 128 = Sse SSE2
|
|
| 401 | + | bits <= 256 = Avx $ if float then Avx1 False else Avx2 False
|
|
| 402 | + | otherwise = Avx $ Avx512 noAvx512Exts
|
|
| 403 | + |
|
| 404 | +-- | A minimal set of flags that imply the given 'SseAvxVersion'.
|
|
| 405 | +sseAvxVersionFlags :: SseAvxVersion -> [String]
|
|
| 406 | +sseAvxVersionFlags = \case
|
|
| 407 | + Sse v ->
|
|
| 408 | + [ case v of
|
|
| 409 | + SSE1 -> "-msse"
|
|
| 410 | + SSE2 -> "-msse2"
|
|
| 411 | + SSE3 -> "-msse3"
|
|
| 412 | + SSSE3 -> "-mssse3"
|
|
| 413 | + SSE4 -> "-msse4"
|
|
| 414 | + SSE42 -> "-msse4.2"
|
|
| 415 | + ]
|
|
| 416 | + Avx (Avx1 fma)
|
|
| 417 | + | fma -> [ "-mfma" ] -- FMA implies AVX
|
|
| 418 | + | otherwise -> [ "-mavx" ]
|
|
| 419 | + Avx (Avx2 fma) -> "-mavx2" : [ "-mfma" | fma ]
|
|
| 420 | + Avx (Avx512 (Avx512Exts bw cd dq er pf vl))
|
|
| 421 | + -- Every AVX-512 extension implies AVX-512F
|
|
| 422 | + | null exts -> [ "-mavx512f" ]
|
|
| 423 | + | otherwise -> exts
|
|
| 424 | + where
|
|
| 425 | + exts =
|
|
| 426 | + [ flag
|
|
| 427 | + | (flag, enabled) <-
|
|
| 428 | + [ ("-mavx512bw", bw)
|
|
| 429 | + , ("-mavx512cd", cd)
|
|
| 430 | + , ("-mavx512dq", dq)
|
|
| 431 | + , ("-mavx512er", er)
|
|
| 432 | + , ("-mavx512pf", pf)
|
|
| 433 | + , ("-mavx512vl", vl)
|
|
| 434 | + ]
|
|
| 435 | + , enabled ] |
| ... | ... | @@ -7,6 +7,7 @@ module GHC.StgToCmm.Config |
| 7 | 7 | |
| 8 | 8 | import GHC.Platform.Profile
|
| 9 | 9 | import GHC.Platform
|
| 10 | +import GHC.Platform.CpuFeatures
|
|
| 10 | 11 | import GHC.Unit.Module
|
| 11 | 12 | import GHC.Utils.Outputable
|
| 12 | 13 | import GHC.Utils.TmpFs
|
| ... | ... | @@ -76,16 +77,9 @@ data StgToCmmConfig = StgToCmmConfig |
| 76 | 77 | , stgToCmmUseStdApThunk :: !Bool -- ^ Use precomputed standard AP thunks in the RTS.
|
| 77 | 78 | , stgToCmmSaveFCallTargetToLocal :: !Bool -- ^ Save a foreign call target to a Cmm local, see
|
| 78 | 79 | -- Note [Saving foreign call target to local] for details
|
| 79 | - ------------------------------ SIMD flags ------------------------------------
|
|
| 80 | - -- Each of these flags checks vector compatibility with the backend requested
|
|
| 81 | - -- during compilation. In essence, this means checking for @-fllvm@ which is
|
|
| 82 | - -- the only backend that currently allows SIMD instructions, see
|
|
| 83 | - -- Ghc.StgToCmm.Prim.checkVecCompatibility for these flags only call site.
|
|
| 84 | 80 | , stgToCmmVecInstrsErr :: Maybe String -- ^ Error (if any) to raise when vector instructions are
|
| 85 | 81 | -- used, see @StgToCmm.Prim.checkVecCompatibility@
|
| 86 | - , stgToCmmAvx :: !Bool -- ^ check for Advanced Vector Extensions
|
|
| 87 | - , stgToCmmAvx2 :: !Bool -- ^ check for Advanced Vector Extensions 2
|
|
| 88 | - , stgToCmmAvx512f :: !Bool -- ^ check for Advanced Vector 512-bit Extensions
|
|
| 82 | + , stgToCmmCpuFeatures :: !CpuFeatures -- ^ Enabled CPU features
|
|
| 89 | 83 | }
|
| 90 | 84 | |
| 91 | 85 |
| ... | ... | @@ -18,6 +18,7 @@ module GHC.StgToCmm.Prim ( |
| 18 | 18 | import GHC.Prelude hiding ((<*>))
|
| 19 | 19 | |
| 20 | 20 | import GHC.Platform
|
| 21 | +import GHC.Platform.CpuFeatures
|
|
| 21 | 22 | import GHC.Platform.Profile
|
| 22 | 23 | |
| 23 | 24 | import GHC.StgToCmm.Config
|
| ... | ... | @@ -2688,45 +2689,44 @@ vecCmmCat FloatVec = cmmFloat |
| 2688 | 2689 | -- it may very well be a design perspective that helps guide improving the NCG.
|
| 2689 | 2690 | |
| 2690 | 2691 | |
| 2692 | +-- | Give up if the backend or the enabled CPU features do not support
|
|
| 2693 | +-- operations on vectors of the given category, length and element width.
|
|
| 2691 | 2694 | checkVecCompatibility :: StgToCmmConfig -> PrimOpVecCat -> Length -> Width -> FCode ()
|
| 2692 | 2695 | checkVecCompatibility cfg vcat l w =
|
| 2693 | - case stgToCmmVecInstrsErr cfg of
|
|
| 2694 | - Nothing | isX86 -> checkX86 vecWidth vcat l w
|
|
| 2695 | - | platformArch platform == ArchAArch64 -> checkAArch64 vecWidth
|
|
| 2696 | - | otherwise -> sorry "SIMD vector instructions are not supported on this architecture."
|
|
| 2697 | - Just err -> sorry err -- incompatible backend, do panic
|
|
| 2696 | + case unsupported of
|
|
| 2697 | + Nothing -> return ()
|
|
| 2698 | + Just reason -> sorry reason
|
|
| 2698 | 2699 | where
|
| 2699 | - platform = stgToCmmPlatform cfg
|
|
| 2700 | - isX86 = case platformArch platform of
|
|
| 2701 | - ArchX86_64 -> True
|
|
| 2702 | - ArchX86 -> True
|
|
| 2703 | - _ -> False
|
|
| 2704 | - checkX86 :: Width -> PrimOpVecCat -> Length -> Width -> FCode ()
|
|
| 2705 | - checkX86 W128 FloatVec 4 W32 | isSseEnabled platform = return ()
|
|
| 2706 | - | otherwise =
|
|
| 2707 | - sorry $ "128-bit wide single-precision floating point " ++
|
|
| 2708 | - "SIMD vector instructions require at least -msse."
|
|
| 2709 | - checkX86 W128 _ _ _ | not (isSse2Enabled platform) =
|
|
| 2710 | - sorry $ "128-bit wide integer and double precision " ++
|
|
| 2711 | - "SIMD vector instructions require at least -msse2."
|
|
| 2712 | - checkX86 W256 FloatVec _ _ | stgToCmmAvx cfg = return ()
|
|
| 2713 | - | otherwise =
|
|
| 2714 | - sorry $ "256-bit wide floating point " ++
|
|
| 2715 | - "SIMD vector instructions require at least -mavx."
|
|
| 2716 | - checkX86 W256 _ _ _ | not (stgToCmmAvx2 cfg) =
|
|
| 2717 | - sorry $ "256-bit wide integer " ++
|
|
| 2718 | - "SIMD vector instructions require at least -mavx2."
|
|
| 2719 | - checkX86 W512 _ _ _ | not (stgToCmmAvx512f cfg) =
|
|
| 2720 | - sorry $ "512-bit wide " ++
|
|
| 2721 | - "SIMD vector instructions require -mavx512f."
|
|
| 2722 | - checkX86 _ _ _ _ = return ()
|
|
| 2723 | - |
|
| 2724 | - checkAArch64 :: Width -> FCode ()
|
|
| 2725 | - checkAArch64 W256 = sorry $ "256-bit wide SIMD vector instructions are not supported."
|
|
| 2726 | - checkAArch64 W512 = sorry $ "512-bit wide SIMD vector instructions are not supported."
|
|
| 2727 | - checkAArch64 _ = return ()
|
|
| 2700 | + unsupported :: Maybe String
|
|
| 2701 | + unsupported
|
|
| 2702 | + -- The backend does not support vector instructions at all.
|
|
| 2703 | + | Just err <- stgToCmmVecInstrsErr cfg
|
|
| 2704 | + = Just err
|
|
| 2705 | + | otherwise
|
|
| 2706 | + = case stgToCmmCpuFeatures cfg of
|
|
| 2707 | + X86CpuFeatures feats
|
|
| 2708 | + | x86SseAvx feats `sseAvxVersionIncludes` required
|
|
| 2709 | + -> Nothing
|
|
| 2710 | + | otherwise
|
|
| 2711 | + -> Just $ bits ++ "-bit wide " ++ category ++ " SIMD vector instructions require at least "
|
|
| 2712 | + ++ unwords (sseAvxVersionFlags required) ++ "."
|
|
| 2713 | + where required = sseAvxVectorRequirement floatElems (widthInBits vecWidth)
|
|
| 2714 | + _ | platformArch (stgToCmmPlatform cfg) == ArchAArch64
|
|
| 2715 | + -> case vecWidth of
|
|
| 2716 | + W128 -> Nothing
|
|
| 2717 | + _ -> Just $ bits ++ "-bit wide SIMD vector instructions are not supported."
|
|
| 2718 | + | otherwise
|
|
| 2719 | + -> Just "SIMD vector instructions are not supported on this architecture."
|
|
| 2728 | 2720 | |
| 2729 | 2721 | vecWidth = typeWidth (vecCmmType vcat l w)
|
| 2722 | + bits = show (widthInBits vecWidth)
|
|
| 2723 | + floatElems = case vcat of
|
|
| 2724 | + FloatVec -> True
|
|
| 2725 | + IntVec -> False
|
|
| 2726 | + WordVec -> False
|
|
| 2727 | + category
|
|
| 2728 | + | floatElems = "floating-point"
|
|
| 2729 | + | otherwise = "integer"
|
|
| 2730 | 2730 | |
| 2731 | 2731 | ------------------------------------------------------------------------------
|
| 2732 | 2732 | -- Helpers for translating vector packing and unpacking.
|
| ... | ... | @@ -18,6 +18,7 @@ import GHC.Driver.Backend |
| 18 | 18 | import GHC.CmmToLlvm.Version
|
| 19 | 19 | import GHC.Platform
|
| 20 | 20 | import GHC.Platform.ArchOS
|
| 21 | +import GHC.Platform.CpuFeatures
|
|
| 21 | 22 | |
| 22 | 23 | import GHC.SysTools
|
| 23 | 24 | |
| ... | ... | @@ -151,30 +152,30 @@ doCpp logger tmpfs dflags unit_env opts input_fn output_fn = do |
| 151 | 152 | [ "-D__IO_MANAGER_WINIO__=2" | isWindows ] ++
|
| 152 | 153 | [ "-D__IO_MANAGER_MIO__=1" ]
|
| 153 | 154 | |
| 154 | - let sse_defs =
|
|
| 155 | - [ "-D__SSE__" | isSseEnabled platform ] ++
|
|
| 156 | - [ "-D__SSE2__" | isSse2Enabled platform ] ++
|
|
| 157 | - [ "-D__SSE3__" | isSse3Enabled dflags ] ++
|
|
| 158 | - [ "-D__SSSE3__" | isSsse3Enabled dflags ] ++
|
|
| 159 | - [ "-D__SSE4_1__" | isSse4_1Enabled dflags ] ++
|
|
| 160 | - [ "-D__SSE4_2__" | isSse4_2Enabled dflags ]
|
|
| 161 | - |
|
| 162 | - let fma_def =
|
|
| 163 | - [ "-D__FMA__" | isFmaEnabled dflags ]
|
|
| 164 | - |
|
| 165 | - let avx_defs =
|
|
| 166 | - [ "-D__AVX__" | isAvxEnabled dflags ] ++
|
|
| 167 | - [ "-D__AVX2__" | isAvx2Enabled dflags ] ++
|
|
| 168 | - [ "-D__AVX512BW__" | isAvx512bwEnabled dflags ] ++
|
|
| 169 | - [ "-D__AVX512CD__" | isAvx512cdEnabled dflags ] ++
|
|
| 170 | - [ "-D__AVX512DQ__" | isAvx512dqEnabled dflags ] ++
|
|
| 171 | - [ "-D__AVX512ER__" | isAvx512erEnabled dflags ] ++
|
|
| 172 | - [ "-D__AVX512F__" | isAvx512fEnabled dflags ] ++
|
|
| 173 | - [ "-D__AVX512PF__" | isAvx512pfEnabled dflags ] ++
|
|
| 174 | - [ "-D__AVX512VL__" | isAvx512vlEnabled dflags ]
|
|
| 175 | - |
|
| 176 | - let gfni_def =
|
|
| 177 | - [ "-D__GFNI__" | isGfniEnabled dflags ]
|
|
| 155 | + let cpu_feats = targetCpuFeatures dflags
|
|
| 156 | + cpu_defs =
|
|
| 157 | + [ "-D__FMA__" | cpuFmaEnabled cpu_feats ] ++
|
|
| 158 | + case cpu_feats of
|
|
| 159 | + X86CpuFeatures feats@(X86Features { x86SseAvx = sseAvx, x86Gfni = gfni }) ->
|
|
| 160 | + let sse = x86SseVersion sseAvx
|
|
| 161 | + avx512 = x86Avx512Exts sseAvx
|
|
| 162 | + in [ "-D__SSE__" | sse >= SSE1 ] ++
|
|
| 163 | + [ "-D__SSE2__" | sse >= SSE2 ] ++
|
|
| 164 | + [ "-D__SSE3__" | sse >= SSE3 ] ++
|
|
| 165 | + [ "-D__SSSE3__" | sse >= SSSE3 ] ++
|
|
| 166 | + [ "-D__SSE4_1__" | sse >= SSE4 ] ++
|
|
| 167 | + [ "-D__SSE4_2__" | sse >= SSE42 ] ++
|
|
| 168 | + [ "-D__AVX__" | x86AvxEnabled feats ] ++
|
|
| 169 | + [ "-D__AVX2__" | x86Avx2Enabled feats ] ++
|
|
| 170 | + [ "-D__AVX512F__" | isJust avx512 ] ++
|
|
| 171 | + [ "-D__AVX512BW__" | maybe False avx512bw avx512 ] ++
|
|
| 172 | + [ "-D__AVX512CD__" | maybe False avx512cd avx512 ] ++
|
|
| 173 | + [ "-D__AVX512DQ__" | maybe False avx512dq avx512 ] ++
|
|
| 174 | + [ "-D__AVX512ER__" | maybe False avx512er avx512 ] ++
|
|
| 175 | + [ "-D__AVX512PF__" | maybe False avx512pf avx512 ] ++
|
|
| 176 | + [ "-D__AVX512VL__" | maybe False avx512vl avx512 ] ++
|
|
| 177 | + [ "-D__GFNI__" | gfni ]
|
|
| 178 | + GenericCpuFeatures {} -> []
|
|
| 178 | 179 | |
| 179 | 180 | backend_defs <- applyCDefs (backendCDefs $ backend dflags) logger dflags
|
| 180 | 181 | |
| ... | ... | @@ -212,10 +213,7 @@ doCpp logger tmpfs dflags unit_env opts input_fn output_fn = do |
| 212 | 213 | ++ map GHC.SysTools.Option th_defs
|
| 213 | 214 | ++ map GHC.SysTools.Option asserts_def
|
| 214 | 215 | ++ map GHC.SysTools.Option hscpp_opts
|
| 215 | - ++ map GHC.SysTools.Option sse_defs
|
|
| 216 | - ++ map GHC.SysTools.Option fma_def
|
|
| 217 | - ++ map GHC.SysTools.Option avx_defs
|
|
| 218 | - ++ map GHC.SysTools.Option gfni_def
|
|
| 216 | + ++ map GHC.SysTools.Option cpu_defs
|
|
| 219 | 217 | ++ map GHC.SysTools.Option io_manager_defs
|
| 220 | 218 | ++ mb_macro_include
|
| 221 | 219 | ++ line_pragmas
|
| ... | ... | @@ -689,6 +689,7 @@ Library |
| 689 | 689 | GHC.Platform.ARM
|
| 690 | 690 | GHC.Platform.AArch64
|
| 691 | 691 | GHC.Platform.Constants
|
| 692 | + GHC.Platform.CpuFeatures
|
|
| 692 | 693 | GHC.Platform.LA64
|
| 693 | 694 | GHC.Platform.NoRegs
|
| 694 | 695 | GHC.Platform.PPC
|
| ... | ... | @@ -150,6 +150,7 @@ GHC.Parser.String |
| 150 | 150 | GHC.Parser.Types
|
| 151 | 151 | GHC.Platform
|
| 152 | 152 | GHC.Platform.Constants
|
| 153 | +GHC.Platform.CpuFeatures
|
|
| 153 | 154 | GHC.Platform.Profile
|
| 154 | 155 | GHC.Platform.Tag
|
| 155 | 156 | GHC.Platform.Ways
|