summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSylvain Henry <sylvain@haskus.fr>2022-03-21 14:57:43 +0100
committerMarge Bot <ben+marge-bot@smart-cactus.org>2022-05-17 20:22:02 -0400
commitef3c8d9e077a1d4ede0724075489fb1f12afa3f9 (patch)
tree9bd61626c036af10e0866aa6a5541d33cac60e4c
parent0e2d16eb76037152c96226f0f65a5ebdee64f7b6 (diff)
downloadhaskell-ef3c8d9e077a1d4ede0724075489fb1f12afa3f9.tar.gz
Don't store LlvmConfig into DynFlags
LlvmConfig contains information read from llvm-passes and llvm-targets files in GHC's top directory. Reading these files is done only when needed (i.e. when the LLVM backend is used) and cached for the whole compiler session. This patch changes the way this is done: - Split LlvmConfig into LlvmConfig and LlvmConfigCache - Store LlvmConfigCache in HscEnv instead of DynFlags: there is no good reason to store it in DynFlags. As it is fixed per session, we store it in the session state instead (HscEnv). - Initializing LlvmConfigCache required some changes to driver functions such as newHscEnv. I've used the opportunity to untangle initHscEnv from initGhcMonad (in top-level GHC module) and to move it to GHC.Driver.Main, close to newHscEnv. - I've also made `cmmPipeline` independent of HscEnv in order to remove the call to newHscEnv in regalloc_unit_tests.
-rw-r--r--compiler/GHC.hs51
-rw-r--r--compiler/GHC/Cmm/Pipeline.hs30
-rw-r--r--compiler/GHC/CmmToLlvm/Base.hs44
-rw-r--r--compiler/GHC/CmmToLlvm/Config.hs119
-rw-r--r--compiler/GHC/Driver/CodeOutput.hs12
-rw-r--r--compiler/GHC/Driver/Config/CmmToLlvm.hs12
-rw-r--r--compiler/GHC/Driver/Env/Types.hs5
-rw-r--r--compiler/GHC/Driver/GenerateCgIPEStub.hs7
-rw-r--r--compiler/GHC/Driver/LlvmConfigCache.hs26
-rw-r--r--compiler/GHC/Driver/Main.hs110
-rw-r--r--compiler/GHC/Driver/Pipeline/Execute.hs18
-rw-r--r--compiler/GHC/Driver/Session.hs23
-rw-r--r--compiler/GHC/Stg/Pipeline.hs3
-rw-r--r--compiler/GHC/SysTools.hs45
-rw-r--r--compiler/GHC/SysTools/Tasks.hs3
-rw-r--r--compiler/ghc.cabal.in1
-rw-r--r--ghc/GHCi/UI.hs5
-rw-r--r--testsuite/tests/count-deps/CountDepsAst.stdout4
-rw-r--r--testsuite/tests/count-deps/CountDepsParser.stdout4
-rw-r--r--testsuite/tests/hiefile/should_run/HieQueries.hs2
-rw-r--r--testsuite/tests/hiefile/should_run/PatTypes.hs2
-rw-r--r--testsuite/tests/regalloc/regalloc_unit_tests.hs47
-rwxr-xr-xutils/llvm-targets/gen-data-layout.sh2
23 files changed, 317 insertions, 258 deletions
diff --git a/compiler/GHC.hs b/compiler/GHC.hs
index d3e9d3978d..b532a2fa97 100644
--- a/compiler/GHC.hs
+++ b/compiler/GHC.hs
@@ -351,9 +351,6 @@ import GHC.Tc.Utils.Instantiate
import GHC.Tc.Instance.Family
import GHC.Utils.TmpFs
-import GHC.SysTools
-import GHC.SysTools.BaseDir
-
import GHC.Utils.Error
import GHC.Utils.Monad
import GHC.Utils.Misc
@@ -559,53 +556,7 @@ withCleanupSession ghc = ghc `MC.finally` cleanup
-- <http://hackage.haskell.org/package/ghc-paths>.
initGhcMonad :: GhcMonad m => Maybe FilePath -> m ()
-initGhcMonad mb_top_dir
- = do { env <- liftIO $
- do { top_dir <- findTopDir mb_top_dir
- ; mySettings <- initSysTools top_dir
- ; myLlvmConfig <- lazyInitLlvmConfig top_dir
- ; dflags <- initDynFlags (defaultDynFlags mySettings myLlvmConfig)
- ; hsc_env <- newHscEnv dflags
- ; checkBrokenTablesNextToCode (hsc_logger hsc_env) dflags
- ; setUnsafeGlobalDynFlags dflags
- -- c.f. DynFlags.parseDynamicFlagsFull, which
- -- creates DynFlags and sets the UnsafeGlobalDynFlags
- ; return hsc_env }
- ; setSession env }
-
--- | The binutils linker on ARM emits unnecessary R_ARM_COPY relocations which
--- breaks tables-next-to-code in dynamically linked modules. This
--- check should be more selective but there is currently no released
--- version where this bug is fixed.
--- See https://sourceware.org/bugzilla/show_bug.cgi?id=16177 and
--- https://gitlab.haskell.org/ghc/ghc/issues/4210#note_78333
-checkBrokenTablesNextToCode :: MonadIO m => Logger -> DynFlags -> m ()
-checkBrokenTablesNextToCode logger dflags
- = do { broken <- checkBrokenTablesNextToCode' logger dflags
- ; when broken
- $ do { _ <- liftIO $ throwIO $ mkApiErr dflags invalidLdErr
- ; liftIO $ fail "unsupported linker"
- }
- }
- where
- invalidLdErr = text "Tables-next-to-code not supported on ARM" <+>
- text "when using binutils ld (please see:" <+>
- text "https://sourceware.org/bugzilla/show_bug.cgi?id=16177)"
-
-checkBrokenTablesNextToCode' :: MonadIO m => Logger -> DynFlags -> m Bool
-checkBrokenTablesNextToCode' logger dflags
- | not (isARM arch) = return False
- | ways dflags `hasNotWay` WayDyn = return False
- | not tablesNextToCode = return False
- | otherwise = do
- linkerInfo <- liftIO $ getLinkerInfo logger dflags
- case linkerInfo of
- GnuLD _ -> return True
- _ -> return False
- where platform = targetPlatform dflags
- arch = platformArch platform
- tablesNextToCode = platformTablesNextToCode platform
-
+initGhcMonad mb_top_dir = setSession =<< liftIO (initHscEnv mb_top_dir)
-- %************************************************************************
-- %* *
diff --git a/compiler/GHC/Cmm/Pipeline.hs b/compiler/GHC/Cmm/Pipeline.hs
index 53fb4d2e36..40383bff94 100644
--- a/compiler/GHC/Cmm/Pipeline.hs
+++ b/compiler/GHC/Cmm/Pipeline.hs
@@ -1,14 +1,13 @@
{-# LANGUAGE BangPatterns #-}
module GHC.Cmm.Pipeline (
- -- | Converts C-- with an implicit stack and native C-- calls into
- -- optimized, CPS converted and native-call-less C--. The latter
- -- C-- can be used to generate assembly.
cmmPipeline
) where
import GHC.Prelude
+import GHC.Driver.Flags
+
import GHC.Cmm
import GHC.Cmm.Config
import GHC.Cmm.ContFlowOpt
@@ -22,37 +21,38 @@ import GHC.Cmm.Sink
import GHC.Cmm.Switch.Implement
import GHC.Types.Unique.Supply
-import GHC.Driver.Session
-import GHC.Driver.Config.Cmm
+
import GHC.Utils.Error
import GHC.Utils.Logger
-import GHC.Driver.Env
-import Control.Monad
import GHC.Utils.Outputable
+
import GHC.Platform
+
+import Control.Monad
import Data.Either (partitionEithers)
-----------------------------------------------------------------------------
-- | Top level driver for C-- pipeline
-----------------------------------------------------------------------------
+-- | Converts C-- with an implicit stack and native C-- calls into
+-- optimized, CPS converted and native-call-less C--. The latter
+-- C-- can be used to generate assembly.
cmmPipeline
- :: HscEnv -- Compilation env including
- -- dynamic flags: -dcmm-lint -ddump-cmm-cps
+ :: Logger
+ -> CmmConfig
-> ModuleSRTInfo -- Info about SRTs generated so far
-> CmmGroup -- Input C-- with Procedures
-> IO (ModuleSRTInfo, CmmGroupSRTs) -- Output CPS transformed C--
-cmmPipeline hsc_env srtInfo prog = do
- let logger = hsc_logger hsc_env
- let cmmConfig = initCmmConfig (hsc_dflags hsc_env)
+cmmPipeline logger cmm_config srtInfo prog = do
let forceRes (info, group) = info `seq` foldr seq () group
- let platform = cmmPlatform cmmConfig
+ let platform = cmmPlatform cmm_config
withTimingSilent logger (text "Cmm pipeline") forceRes $ do
- tops <- {-# SCC "tops" #-} mapM (cpsTop logger platform cmmConfig) prog
+ tops <- {-# SCC "tops" #-} mapM (cpsTop logger platform cmm_config) prog
let (procs, data_) = partitionEithers tops
- (srtInfo, cmms) <- {-# SCC "doSRTs" #-} doSRTs cmmConfig srtInfo procs data_
+ (srtInfo, cmms) <- {-# SCC "doSRTs" #-} doSRTs cmm_config srtInfo procs data_
dumpWith logger Opt_D_dump_cmm_cps "Post CPS Cmm" FormatCMM (pdoc platform cmms)
return (srtInfo, cmms)
diff --git a/compiler/GHC/CmmToLlvm/Base.hs b/compiler/GHC/CmmToLlvm/Base.hs
index cc4377240b..338aa3a927 100644
--- a/compiler/GHC/CmmToLlvm/Base.hs
+++ b/compiler/GHC/CmmToLlvm/Base.hs
@@ -15,10 +15,6 @@ module GHC.CmmToLlvm.Base (
LiveGlobalRegs,
LlvmUnresData, LlvmData, UnresLabel, UnresStatic,
- LlvmVersion, supportedLlvmVersionLowerBound, supportedLlvmVersionUpperBound,
- llvmVersionSupported, parseLlvmVersion,
- llvmVersionStr, llvmVersionList,
-
LlvmM,
runLlvm, withClearVars, varLookup, varInsert,
markStackReg, checkStackReg,
@@ -66,10 +62,8 @@ import GHC.Utils.Logger
import Data.Maybe (fromJust)
import Control.Monad (ap)
-import Data.Char (isDigit)
-import Data.List (sortBy, groupBy, intercalate)
+import Data.List (sortBy, groupBy)
import Data.Ord (comparing)
-import qualified Data.List.NonEmpty as NE
-- ----------------------------------------------------------------------------
-- * Some Data Types
@@ -261,42 +255,6 @@ llvmPtrBits :: Platform -> Int
llvmPtrBits platform = widthInBits $ typeWidth $ gcWord platform
-- ----------------------------------------------------------------------------
--- * Llvm Version
---
-
-parseLlvmVersion :: String -> Maybe LlvmVersion
-parseLlvmVersion =
- fmap LlvmVersion . NE.nonEmpty . go [] . dropWhile (not . isDigit)
- where
- go vs s
- | null ver_str
- = reverse vs
- | '.' : rest' <- rest
- = go (read ver_str : vs) rest'
- | otherwise
- = reverse (read ver_str : vs)
- where
- (ver_str, rest) = span isDigit s
-
--- | The (inclusive) lower bound on the LLVM Version that is currently supported.
-supportedLlvmVersionLowerBound :: LlvmVersion
-supportedLlvmVersionLowerBound = LlvmVersion (sUPPORTED_LLVM_VERSION_MIN NE.:| [])
-
--- | The (not-inclusive) upper bound bound on the LLVM Version that is currently supported.
-supportedLlvmVersionUpperBound :: LlvmVersion
-supportedLlvmVersionUpperBound = LlvmVersion (sUPPORTED_LLVM_VERSION_MAX NE.:| [])
-
-llvmVersionSupported :: LlvmVersion -> Bool
-llvmVersionSupported v =
- v >= supportedLlvmVersionLowerBound && v < supportedLlvmVersionUpperBound
-
-llvmVersionStr :: LlvmVersion -> String
-llvmVersionStr = intercalate "." . map show . llvmVersionList
-
-llvmVersionList :: LlvmVersion -> [Int]
-llvmVersionList = NE.toList . llvmVersionNE
-
--- ----------------------------------------------------------------------------
-- * Environment Handling
--
diff --git a/compiler/GHC/CmmToLlvm/Config.hs b/compiler/GHC/CmmToLlvm/Config.hs
index 84455a8b2c..f516b9787b 100644
--- a/compiler/GHC/CmmToLlvm/Config.hs
+++ b/compiler/GHC/CmmToLlvm/Config.hs
@@ -1,20 +1,35 @@
+{-# LANGUAGE CPP #-}
+
-- | Llvm code generator configuration
module GHC.CmmToLlvm.Config
( LlvmCgConfig(..)
+ , LlvmConfig(..)
+ , LlvmTarget(..)
+ , initLlvmConfig
+ -- * LLVM version
, LlvmVersion(..)
+ , supportedLlvmVersionLowerBound
+ , supportedLlvmVersionUpperBound
+ , parseLlvmVersion
+ , llvmVersionSupported
+ , llvmVersionStr
+ , llvmVersionList
)
where
+#include "ghc-llvm-version.h"
+
import GHC.Prelude
import GHC.Platform
import GHC.Utils.Outputable
-import GHC.Driver.Session
+import GHC.Settings.Utils
+import GHC.Utils.Panic
+import Data.Char (isDigit)
+import Data.List (intercalate)
import qualified Data.List.NonEmpty as NE
-
-newtype LlvmVersion = LlvmVersion { llvmVersionNE :: NE.NonEmpty Int }
- deriving (Eq, Ord)
+import System.FilePath
data LlvmCgConfig = LlvmCgConfig
{ llvmCgPlatform :: !Platform -- ^ Target platform
@@ -25,7 +40,97 @@ data LlvmCgConfig = LlvmCgConfig
, llvmCgLlvmVersion :: Maybe LlvmVersion -- ^ version of Llvm we're using
, llvmCgDoWarn :: !Bool -- ^ True ==> warn unsupported Llvm version
, llvmCgLlvmTarget :: !String -- ^ target triple passed to LLVM
- , llvmCgLlvmConfig :: !LlvmConfig -- ^ mirror DynFlags LlvmConfig.
- -- see Note [LLVM configuration] in "GHC.SysTools". This can be strict since
- -- GHC.Driver.Config.CmmToLlvm.initLlvmCgConfig verifies the files are present.
+ , llvmCgLlvmConfig :: !LlvmConfig -- ^ Supported LLVM configurations.
+ -- see Note [LLVM configuration]
+ }
+
+data LlvmTarget = LlvmTarget
+ { lDataLayout :: String
+ , lCPU :: String
+ , lAttributes :: [String]
+ }
+
+-- Note [LLVM configuration]
+-- ~~~~~~~~~~~~~~~~~~~~~~~~~
+-- The `llvm-targets` and `llvm-passes` files are shipped with GHC and contain
+-- information needed by the LLVM backend to invoke `llc` and `opt`.
+-- Specifically:
+--
+-- * llvm-targets maps autoconf host triples to the corresponding LLVM
+-- `data-layout` declarations. This information is extracted from clang using
+-- the script in utils/llvm-targets/gen-data-layout.sh and should be updated
+-- whenever we target a new version of LLVM.
+--
+-- * llvm-passes maps GHC optimization levels to sets of LLVM optimization
+-- flags that GHC should pass to `opt`.
+--
+-- This information is contained in files rather the GHC source to allow users
+-- to add new targets to GHC without having to recompile the compiler.
+--
+
+initLlvmConfig :: FilePath -> IO LlvmConfig
+initLlvmConfig top_dir
+ = do
+ targets <- readAndParse "llvm-targets"
+ passes <- readAndParse "llvm-passes"
+ return $ LlvmConfig
+ { llvmTargets = fmap mkLlvmTarget <$> targets
+ , llvmPasses = passes
+ }
+ where
+ readAndParse :: Read a => String -> IO a
+ readAndParse name = do
+ let f = top_dir </> name
+ llvmConfigStr <- readFile f
+ case maybeReadFuzzy llvmConfigStr of
+ Just s -> return s
+ Nothing -> pgmError ("Can't parse LLVM config file: " ++ show f)
+
+ mkLlvmTarget :: (String, String, String) -> LlvmTarget
+ mkLlvmTarget (dl, cpu, attrs) = LlvmTarget dl cpu (words attrs)
+
+data LlvmConfig = LlvmConfig
+ { llvmTargets :: [(String, LlvmTarget)]
+ , llvmPasses :: [(Int, String)]
}
+
+
+---------------------------------------------------------
+-- LLVM version
+---------------------------------------------------------
+
+newtype LlvmVersion = LlvmVersion { llvmVersionNE :: NE.NonEmpty Int }
+ deriving (Eq, Ord)
+
+parseLlvmVersion :: String -> Maybe LlvmVersion
+parseLlvmVersion =
+ fmap LlvmVersion . NE.nonEmpty . go [] . dropWhile (not . isDigit)
+ where
+ go vs s
+ | null ver_str
+ = reverse vs
+ | '.' : rest' <- rest
+ = go (read ver_str : vs) rest'
+ | otherwise
+ = reverse (read ver_str : vs)
+ where
+ (ver_str, rest) = span isDigit s
+
+-- | The (inclusive) lower bound on the LLVM Version that is currently supported.
+supportedLlvmVersionLowerBound :: LlvmVersion
+supportedLlvmVersionLowerBound = LlvmVersion (sUPPORTED_LLVM_VERSION_MIN NE.:| [])
+
+-- | The (not-inclusive) upper bound bound on the LLVM Version that is currently supported.
+supportedLlvmVersionUpperBound :: LlvmVersion
+supportedLlvmVersionUpperBound = LlvmVersion (sUPPORTED_LLVM_VERSION_MAX NE.:| [])
+
+llvmVersionSupported :: LlvmVersion -> Bool
+llvmVersionSupported v =
+ v >= supportedLlvmVersionLowerBound && v < supportedLlvmVersionUpperBound
+
+llvmVersionStr :: LlvmVersion -> String
+llvmVersionStr = intercalate "." . map show . llvmVersionList
+
+llvmVersionList :: LlvmVersion -> [Int]
+llvmVersionList = NE.toList . llvmVersionNE
+
diff --git a/compiler/GHC/Driver/CodeOutput.hs b/compiler/GHC/Driver/CodeOutput.hs
index 4a96967932..c073c40323 100644
--- a/compiler/GHC/Driver/CodeOutput.hs
+++ b/compiler/GHC/Driver/CodeOutput.hs
@@ -30,6 +30,7 @@ import GHC.Driver.Session
import GHC.Driver.Config.Finder (initFinderOpts)
import GHC.Driver.Config.CmmToAsm (initNCGConfig)
import GHC.Driver.Config.CmmToLlvm (initLlvmCgConfig)
+import GHC.Driver.LlvmConfigCache (LlvmConfigCache)
import GHC.Driver.Ppr
import GHC.Driver.Backend
@@ -73,6 +74,7 @@ codeOutput
:: forall a.
Logger
-> TmpFs
+ -> LlvmConfigCache
-> DynFlags
-> UnitState
-> Module
@@ -87,7 +89,7 @@ codeOutput
(Bool{-stub_h_exists-}, Maybe FilePath{-stub_c_exists-}),
[(ForeignSrcLang, FilePath)]{-foreign_fps-},
a)
-codeOutput logger tmpfs dflags unit_state this_mod filenm location genForeignStubs foreign_fps pkg_deps
+codeOutput logger tmpfs llvm_config dflags unit_state this_mod filenm location genForeignStubs foreign_fps pkg_deps
cmm_stream
=
do {
@@ -122,7 +124,7 @@ codeOutput logger tmpfs dflags unit_state this_mod filenm location genForeignStu
NCG -> outputAsm logger dflags this_mod location filenm
final_stream
ViaC -> outputC logger dflags filenm final_stream pkg_deps
- LLVM -> outputLlvm logger dflags filenm final_stream
+ LLVM -> outputLlvm logger llvm_config dflags filenm final_stream
Interpreter -> panic "codeOutput: Interpreter"
NoBackend -> panic "codeOutput: NoBackend"
; stubs_exist <- outputForeignStubs logger tmpfs dflags unit_state this_mod location stubs
@@ -209,9 +211,9 @@ outputAsm logger dflags this_mod location filenm cmm_stream = do
************************************************************************
-}
-outputLlvm :: Logger -> DynFlags -> FilePath -> Stream IO RawCmmGroup a -> IO a
-outputLlvm logger dflags filenm cmm_stream = do
- lcg_config <- initLlvmCgConfig logger dflags
+outputLlvm :: Logger -> LlvmConfigCache -> DynFlags -> FilePath -> Stream IO RawCmmGroup a -> IO a
+outputLlvm logger llvm_config dflags filenm cmm_stream = do
+ lcg_config <- initLlvmCgConfig logger llvm_config dflags
{-# SCC "llvm_output" #-} doOutput filenm $
\f -> {-# SCC "llvm_CodeGen" #-}
llvmCodeGen logger lcg_config f cmm_stream
diff --git a/compiler/GHC/Driver/Config/CmmToLlvm.hs b/compiler/GHC/Driver/Config/CmmToLlvm.hs
index 18721bf845..61ffb8bcf4 100644
--- a/compiler/GHC/Driver/Config/CmmToLlvm.hs
+++ b/compiler/GHC/Driver/Config/CmmToLlvm.hs
@@ -1,19 +1,23 @@
module GHC.Driver.Config.CmmToLlvm
( initLlvmCgConfig
- ) where
+ )
+where
import GHC.Prelude
import GHC.Driver.Session
+import GHC.Driver.LlvmConfigCache
import GHC.Platform
import GHC.CmmToLlvm.Config
import GHC.SysTools.Tasks
+
import GHC.Utils.Outputable
import GHC.Utils.Logger
-- | Initialize the Llvm code generator configuration from DynFlags
-initLlvmCgConfig :: Logger -> DynFlags -> IO LlvmCgConfig
-initLlvmCgConfig logger dflags = do
+initLlvmCgConfig :: Logger -> LlvmConfigCache -> DynFlags -> IO LlvmCgConfig
+initLlvmCgConfig logger config_cache dflags = do
version <- figureLlvmVersion logger dflags
+ llvm_config <- readLlvmConfigCache config_cache
pure $! LlvmCgConfig {
llvmCgPlatform = targetPlatform dflags
, llvmCgContext = initSDocContext dflags (PprCode CStyle)
@@ -26,5 +30,5 @@ initLlvmCgConfig logger dflags = do
, llvmCgLlvmVersion = version
, llvmCgDoWarn = wopt Opt_WarnUnsupportedLlvmVersion dflags
, llvmCgLlvmTarget = platformMisc_llvmTarget $! platformMisc dflags
- , llvmCgLlvmConfig = llvmConfig dflags
+ , llvmCgLlvmConfig = llvm_config
}
diff --git a/compiler/GHC/Driver/Env/Types.hs b/compiler/GHC/Driver/Env/Types.hs
index 9db617780b..63a5eb86cb 100644
--- a/compiler/GHC/Driver/Env/Types.hs
+++ b/compiler/GHC/Driver/Env/Types.hs
@@ -8,6 +8,8 @@ module GHC.Driver.Env.Types
import GHC.Driver.Errors.Types ( GhcMessage )
import {-# SOURCE #-} GHC.Driver.Hooks
import GHC.Driver.Session ( ContainsDynFlags(..), HasDynFlags(..), DynFlags )
+import GHC.Driver.LlvmConfigCache (LlvmConfigCache)
+
import GHC.Prelude
import GHC.Runtime.Context
import GHC.Runtime.Interpreter.Types ( Interp )
@@ -106,4 +108,7 @@ data HscEnv
, hsc_tmpfs :: !TmpFs
-- ^ Temporary files
+
+ , hsc_llvm_config :: !LlvmConfigCache
+ -- ^ LLVM configuration cache.
}
diff --git a/compiler/GHC/Driver/GenerateCgIPEStub.hs b/compiler/GHC/Driver/GenerateCgIPEStub.hs
index 96bf352e51..cf6538ef3e 100644
--- a/compiler/GHC/Driver/GenerateCgIPEStub.hs
+++ b/compiler/GHC/Driver/GenerateCgIPEStub.hs
@@ -16,11 +16,12 @@ import GHC.Cmm.Utils (toBlockList)
import GHC.Data.Maybe (firstJusts)
import GHC.Data.Stream (Stream, liftIO)
import qualified GHC.Data.Stream as Stream
-import GHC.Driver.Env (hsc_dflags)
+import GHC.Driver.Env (hsc_dflags, hsc_logger)
import GHC.Driver.Env.Types (HscEnv)
import GHC.Driver.Flags (GeneralFlag (Opt_InfoTableMap))
import GHC.Driver.Session (gopt, targetPlatform)
import GHC.Driver.Config.StgToCmm
+import GHC.Driver.Config.Cmm
import GHC.Prelude
import GHC.Runtime.Heap.Layout (isStackRep)
import GHC.Settings (Platform, platformUnregisterised)
@@ -184,7 +185,9 @@ generateCgIPEStub :: HscEnv -> Module -> InfoTableProvMap -> NameEnv TagSig -> S
generateCgIPEStub hsc_env this_mod denv tag_sigs s = do
let dflags = hsc_dflags hsc_env
platform = targetPlatform dflags
+ logger = hsc_logger hsc_env
fstate = initFCodeState platform
+ cmm_cfg = initCmmConfig dflags
cgState <- liftIO initC
-- Collect info tables, but only if -finfo-table-map is enabled, otherwise labeledInfoTablesWithTickishes is empty.
@@ -195,7 +198,7 @@ generateCgIPEStub hsc_env this_mod denv tag_sigs s = do
let denv' = denv {provInfoTables = Map.fromList (map (\(_, i, t) -> (cit_lbl i, t)) labeledInfoTablesWithTickishes)}
((ipeStub, ipeCmmGroup), _) = runC (initStgToCmmConfig dflags this_mod) fstate cgState $ getCmm (initInfoTableProv (map sndOf3 labeledInfoTablesWithTickishes) denv')
- (_, ipeCmmGroupSRTs) <- liftIO $ cmmPipeline hsc_env (emptySRT this_mod) ipeCmmGroup
+ (_, ipeCmmGroupSRTs) <- liftIO $ cmmPipeline logger cmm_cfg (emptySRT this_mod) ipeCmmGroup
Stream.yield ipeCmmGroupSRTs
return CgInfos {cgNonCafs = nonCaffySet, cgLFInfos = moduleLFInfos, cgIPEStub = ipeStub, cgTagSigs = tag_sigs}
diff --git a/compiler/GHC/Driver/LlvmConfigCache.hs b/compiler/GHC/Driver/LlvmConfigCache.hs
new file mode 100644
index 0000000000..fefd385518
--- /dev/null
+++ b/compiler/GHC/Driver/LlvmConfigCache.hs
@@ -0,0 +1,26 @@
+-- | LLVM config cache
+module GHC.Driver.LlvmConfigCache
+ ( LlvmConfigCache
+ , initLlvmConfigCache
+ , readLlvmConfigCache
+ )
+where
+
+import GHC.Prelude
+import GHC.CmmToLlvm.Config
+
+import System.IO.Unsafe
+
+-- | Cache LLVM configuration read from files in top_dir
+--
+-- See Note [LLVM configuration] in GHC.CmmToLlvm.Config
+--
+-- Currently implemented with unsafe lazy IO. But it could be implemented with
+-- an IORef as the exposed interface is in IO.
+data LlvmConfigCache = LlvmConfigCache LlvmConfig
+
+initLlvmConfigCache :: FilePath -> IO LlvmConfigCache
+initLlvmConfigCache top_dir = pure $ LlvmConfigCache (unsafePerformIO $ initLlvmConfig top_dir)
+
+readLlvmConfigCache :: LlvmConfigCache -> IO LlvmConfig
+readLlvmConfigCache (LlvmConfigCache !config) = pure config
diff --git a/compiler/GHC/Driver/Main.hs b/compiler/GHC/Driver/Main.hs
index f45cdc8020..ddc86ac3e3 100644
--- a/compiler/GHC/Driver/Main.hs
+++ b/compiler/GHC/Driver/Main.hs
@@ -39,6 +39,7 @@ module GHC.Driver.Main
-- * Making an HscEnv
newHscEnv
, newHscEnvWithHUG
+ , initHscEnv
-- * Compiling complete source files
, Messager, batchMsg, batchMultiMsg
@@ -99,10 +100,14 @@ module GHC.Driver.Main
import GHC.Prelude
+import GHC.Platform
+import GHC.Platform.Ways
+
import GHC.Driver.Plugins
import GHC.Driver.Session
import GHC.Driver.Backend
import GHC.Driver.Env
+import GHC.Driver.Env.KnotVars
import GHC.Driver.Errors
import GHC.Driver.Errors.Types
import GHC.Driver.CodeOutput
@@ -111,10 +116,13 @@ import GHC.Driver.Config.Logger (initLogFlags)
import GHC.Driver.Config.Parser (initParserOpts)
import GHC.Driver.Config.Stg.Ppr (initStgPprOpts)
import GHC.Driver.Config.Stg.Pipeline (initStgPipelineOpts)
-import GHC.Driver.Config.StgToCmm (initStgToCmmConfig)
+import GHC.Driver.Config.StgToCmm (initStgToCmmConfig)
+import GHC.Driver.Config.Cmm (initCmmConfig)
+import GHC.Driver.LlvmConfigCache (initLlvmConfigCache)
import GHC.Driver.Config.Diagnostic
import GHC.Driver.Config.Tidy
import GHC.Driver.Hooks
+import GHC.Driver.GenerateCgIPEStub (generateCgIPEStub)
import GHC.Runtime.Context
import GHC.Runtime.Interpreter ( addSptEntry )
@@ -172,6 +180,7 @@ import GHC.Tc.Utils.Zonk ( ZonkFlexi (DefaultFlexi) )
import GHC.Stg.Syntax
import GHC.Stg.Pipeline ( stg2stg )
+import GHC.Stg.InferTags
import GHC.Builtin.Utils
import GHC.Builtin.Names
@@ -215,6 +224,7 @@ import GHC.Types.Name
import GHC.Types.Name.Cache ( initNameCache )
import GHC.Types.Name.Reader
import GHC.Types.Name.Ppr
+import GHC.Types.Name.Set (NonCaffySet)
import GHC.Types.TyThing
import GHC.Types.HpcInfo
@@ -232,7 +242,11 @@ import GHC.Data.Bag
import GHC.Data.StringBuffer
import qualified GHC.Data.Stream as Stream
import GHC.Data.Stream (Stream)
+import GHC.Data.Maybe
+
import qualified GHC.SysTools
+import GHC.SysTools (initSysTools)
+import GHC.SysTools.BaseDir (findTopDir)
import Data.Data hiding (Fixity, TyCon)
import Data.List ( nub, isPrefixOf, partition )
@@ -246,14 +260,9 @@ import Data.Set (Set)
import Data.Functor
import Control.DeepSeq (force)
import Data.Bifunctor (first)
-import GHC.Data.Maybe
-import GHC.Driver.Env.KnotVars
-import GHC.Types.Name.Set (NonCaffySet)
-import GHC.Driver.GenerateCgIPEStub (generateCgIPEStub)
import Data.List.NonEmpty (NonEmpty ((:|)))
-import GHC.Stg.InferTags
{- **********************************************************************
%* *
@@ -261,36 +270,80 @@ import GHC.Stg.InferTags
%* *
%********************************************************************* -}
-newHscEnv :: DynFlags -> IO HscEnv
-newHscEnv dflags = newHscEnvWithHUG dflags (homeUnitId_ dflags) home_unit_graph
+newHscEnv :: FilePath -> DynFlags -> IO HscEnv
+newHscEnv top_dir dflags = newHscEnvWithHUG top_dir dflags (homeUnitId_ dflags) home_unit_graph
where
home_unit_graph = unitEnv_singleton
(homeUnitId_ dflags)
(mkHomeUnitEnv dflags emptyHomePackageTable Nothing)
-newHscEnvWithHUG :: DynFlags -> UnitId -> HomeUnitGraph -> IO HscEnv
-newHscEnvWithHUG top_dynflags cur_unit home_unit_graph = do
+newHscEnvWithHUG :: FilePath -> DynFlags -> UnitId -> HomeUnitGraph -> IO HscEnv
+newHscEnvWithHUG top_dir top_dynflags cur_unit home_unit_graph = do
nc_var <- initNameCache 'r' knownKeyNames
fc_var <- initFinderCache
logger <- initLogger
tmpfs <- initTmpFs
let dflags = homeUnitEnv_dflags $ unitEnv_lookup cur_unit home_unit_graph
unit_env <- initUnitEnv cur_unit home_unit_graph (ghcNameVersion dflags) (targetPlatform dflags)
- return HscEnv { hsc_dflags = top_dynflags
+ llvm_config <- initLlvmConfigCache top_dir
+ return HscEnv { hsc_dflags = top_dynflags
, hsc_logger = setLogFlags logger (initLogFlags top_dynflags)
- , hsc_targets = []
- , hsc_mod_graph = emptyMG
- , hsc_IC = emptyInteractiveContext dflags
- , hsc_NC = nc_var
- , hsc_FC = fc_var
- , hsc_type_env_vars = emptyKnotVars
- , hsc_interp = Nothing
- , hsc_unit_env = unit_env
- , hsc_plugins = emptyPlugins
- , hsc_hooks = emptyHooks
- , hsc_tmpfs = tmpfs
+ , hsc_targets = []
+ , hsc_mod_graph = emptyMG
+ , hsc_IC = emptyInteractiveContext dflags
+ , hsc_NC = nc_var
+ , hsc_FC = fc_var
+ , hsc_type_env_vars = emptyKnotVars
+ , hsc_interp = Nothing
+ , hsc_unit_env = unit_env
+ , hsc_plugins = emptyPlugins
+ , hsc_hooks = emptyHooks
+ , hsc_tmpfs = tmpfs
+ , hsc_llvm_config = llvm_config
}
+-- | Initialize HscEnv from an optional top_dir path
+initHscEnv :: Maybe FilePath -> IO HscEnv
+initHscEnv mb_top_dir = do
+ top_dir <- findTopDir mb_top_dir
+ mySettings <- initSysTools top_dir
+ dflags <- initDynFlags (defaultDynFlags mySettings)
+ hsc_env <- newHscEnv top_dir dflags
+ checkBrokenTablesNextToCode (hsc_logger hsc_env) dflags
+ setUnsafeGlobalDynFlags dflags
+ -- c.f. DynFlags.parseDynamicFlagsFull, which
+ -- creates DynFlags and sets the UnsafeGlobalDynFlags
+ return hsc_env
+
+-- | The binutils linker on ARM emits unnecessary R_ARM_COPY relocations which
+-- breaks tables-next-to-code in dynamically linked modules. This
+-- check should be more selective but there is currently no released
+-- version where this bug is fixed.
+-- See https://sourceware.org/bugzilla/show_bug.cgi?id=16177 and
+-- https://gitlab.haskell.org/ghc/ghc/issues/4210#note_78333
+checkBrokenTablesNextToCode :: Logger -> DynFlags -> IO ()
+checkBrokenTablesNextToCode logger dflags = do
+ let invalidLdErr = "Tables-next-to-code not supported on ARM \
+ \when using binutils ld (please see: \
+ \https://sourceware.org/bugzilla/show_bug.cgi?id=16177)"
+ broken <- checkBrokenTablesNextToCode' logger dflags
+ when broken (panic invalidLdErr)
+
+checkBrokenTablesNextToCode' :: Logger -> DynFlags -> IO Bool
+checkBrokenTablesNextToCode' logger dflags
+ | not (isARM arch) = return False
+ | ways dflags `hasNotWay` WayDyn = return False
+ | not tablesNextToCode = return False
+ | otherwise = do
+ linkerInfo <- liftIO $ GHC.SysTools.getLinkerInfo logger dflags
+ case linkerInfo of
+ GnuLD _ -> return True
+ _ -> return False
+ where platform = targetPlatform dflags
+ arch = platformArch platform
+ tablesNextToCode = platformTablesNextToCode platform
+
+
-- -----------------------------------------------------------------------------
getDiagnostics :: Hsc (Messages GhcMessage)
@@ -1630,6 +1683,7 @@ hscGenHardCode hsc_env cgguts location output_filename = do
logger = hsc_logger hsc_env
hooks = hsc_hooks hsc_env
tmpfs = hsc_tmpfs hsc_env
+ llvm_config = hsc_llvm_config hsc_env
profile = targetProfile dflags
data_tycons = filter isDataTyCon tycons
-- cg_tycons includes newtypes, for the benefit of External Core,
@@ -1688,7 +1742,7 @@ hscGenHardCode hsc_env cgguts location output_filename = do
(output_filename, (_stub_h_exists, stub_c_exists), foreign_fps, cg_infos)
<- {-# SCC "codeOutput" #-}
- codeOutput logger tmpfs dflags (hsc_units hsc_env) this_mod output_filename location
+ codeOutput logger tmpfs llvm_config dflags (hsc_units hsc_env) this_mod output_filename location
foreign_stubs foreign_files dependencies rawcmms1
return (output_filename, stub_c_exists, foreign_fps, Just cg_infos)
@@ -1741,6 +1795,8 @@ hscCompileCmmFile hsc_env original_filename filename output_filename = runHsc hs
profile = targetProfile dflags
home_unit = hsc_home_unit hsc_env
platform = targetPlatform dflags
+ llvm_config = hsc_llvm_config hsc_env
+ cmm_config = initCmmConfig dflags
do_info_table = gopt Opt_InfoTableMap dflags
-- Make up a module name to give the NCG. We can't pass bottom here
-- lest we reproduce #11784.
@@ -1763,7 +1819,7 @@ hscCompileCmmFile hsc_env original_filename filename output_filename = runHsc hs
-- in C we must declare before use, but SRT algorithm is free to
-- re-order [A, B] (B refers to A) when A is not CAFFY and return [B, A]
cmmgroup <-
- concatMapM (\cmm -> snd <$> cmmPipeline hsc_env (emptySRT cmm_mod) [cmm]) cmm
+ concatMapM (\cmm -> snd <$> cmmPipeline logger cmm_config (emptySRT cmm_mod) [cmm]) cmm
unless (null cmmgroup) $
putDumpFileMaybe logger Opt_D_dump_cmm "Output Cmm"
@@ -1778,7 +1834,7 @@ hscCompileCmmFile hsc_env original_filename filename output_filename = runHsc hs
in NoStubs `appendStubC` ip_init
(_output_filename, (_stub_h_exists, stub_c_exists), _foreign_fps, _caf_infos)
- <- codeOutput logger tmpfs dflags (hsc_units hsc_env) cmm_mod output_filename no_loc foreign_stubs [] S.empty
+ <- codeOutput logger tmpfs llvm_config dflags (hsc_units hsc_env) cmm_mod output_filename no_loc foreign_stubs [] S.empty
rawCmms
return stub_c_exists
where
@@ -1853,11 +1909,13 @@ doCodeGen hsc_env this_mod denv data_tycons
ppr_stream1 = Stream.mapM dump1 cmm_stream
+ cmm_config = initCmmConfig dflags
+
pipeline_stream :: Stream IO CmmGroupSRTs (NonCaffySet, ModuleLFInfos)
pipeline_stream = do
(non_cafs, lf_infos) <-
{-# SCC "cmmPipeline" #-}
- Stream.mapAccumL_ (cmmPipeline hsc_env) (emptySRT this_mod) ppr_stream1
+ Stream.mapAccumL_ (cmmPipeline logger cmm_config) (emptySRT this_mod) ppr_stream1
<&> first (srtMapNonCAFs . moduleSRTMap)
return (non_cafs, lf_infos)
diff --git a/compiler/GHC/Driver/Pipeline/Execute.hs b/compiler/GHC/Driver/Pipeline/Execute.hs
index 4f2c30c5a7..58bc1e6907 100644
--- a/compiler/GHC/Driver/Pipeline/Execute.hs
+++ b/compiler/GHC/Driver/Pipeline/Execute.hs
@@ -70,7 +70,8 @@ import Data.IORef
import GHC.Types.Name.Env
import GHC.Platform.Ways
import GHC.Platform.ArchOS
-import GHC.CmmToLlvm.Base ( llvmVersionList )
+import GHC.Driver.LlvmConfigCache (readLlvmConfigCache)
+import GHC.CmmToLlvm.Config (llvmVersionList, LlvmTarget (..), LlvmConfig (..))
import {-# SOURCE #-} GHC.Driver.Pipeline (compileForeign, compileEmptyStub)
import GHC.Settings
import System.IO
@@ -209,6 +210,7 @@ runLlvmLlcPhase pipe_env hsc_env input_fn = do
--
-- Observed at least with -mtriple=arm-unknown-linux-gnueabihf -enable-tbaa
--
+ llvm_config <- readLlvmConfigCache (hsc_llvm_config hsc_env)
let dflags = hsc_dflags hsc_env
logger = hsc_logger hsc_env
llvmOpts = case llvmOptLevel dflags of
@@ -217,7 +219,7 @@ runLlvmLlcPhase pipe_env hsc_env input_fn = do
_ -> "-O2"
defaultOptions = map GHC.SysTools.Option . concatMap words . snd
- $ unzip (llvmOptions dflags)
+ $ unzip (llvmOptions llvm_config dflags)
optFlag = if null (getOpts dflags opt_lc)
then map GHC.SysTools.Option $ words llvmOpts
else []
@@ -243,16 +245,17 @@ runLlvmOptPhase :: PipeEnv -> HscEnv -> FilePath -> IO FilePath
runLlvmOptPhase pipe_env hsc_env input_fn = do
let dflags = hsc_dflags hsc_env
logger = hsc_logger hsc_env
+ llvm_config <- readLlvmConfigCache (hsc_llvm_config hsc_env)
let -- we always (unless -optlo specified) run Opt since we rely on it to
-- fix up some pretty big deficiencies in the code we generate
optIdx = max 0 $ min 2 $ llvmOptLevel dflags -- ensure we're in [0,2]
- llvmOpts = case lookup optIdx $ llvmPasses $ llvmConfig dflags of
+ llvmOpts = case lookup optIdx $ llvmPasses llvm_config of
Just passes -> passes
Nothing -> panic ("runPhase LlvmOpt: llvm-passes file "
++ "is missing passes for level "
++ show optIdx)
defaultOptions = map GHC.SysTools.Option . concat . fmap words . fst
- $ unzip (llvmOptions dflags)
+ $ unzip (llvmOptions llvm_config dflags)
-- don't specify anything if user has specified commands. We do this
-- for opt but not llc since opt is very specifically for optimisation
@@ -867,9 +870,10 @@ getOutputFilename logger tmpfs stop_phase output basename dflags next_phase mayb
-- | LLVM Options. These are flags to be passed to opt and llc, to ensure
-- consistency we list them in pairs, so that they form groups.
-llvmOptions :: DynFlags
+llvmOptions :: LlvmConfig
+ -> DynFlags
-> [(String, String)] -- ^ pairs of (opt, llc) arguments
-llvmOptions dflags =
+llvmOptions llvm_config dflags =
[("-enable-tbaa -tbaa", "-enable-tbaa") | gopt Opt_LlvmTBAA dflags ]
++ [("-relocation-model=" ++ rmodel
,"-relocation-model=" ++ rmodel) | not (null rmodel)]
@@ -883,7 +887,7 @@ llvmOptions dflags =
++ [("", "-target-abi=" ++ abi) | not (null abi) ]
where target = platformMisc_llvmTarget $ platformMisc dflags
- Just (LlvmTarget _ mcpu mattr) = lookup target (llvmTargets $ llvmConfig dflags)
+ Just (LlvmTarget _ mcpu mattr) = lookup target (llvmTargets llvm_config)
-- Relocation models
rmodel | gopt Opt_PIC dflags = "pic"
diff --git a/compiler/GHC/Driver/Session.hs b/compiler/GHC/Driver/Session.hs
index 0af3549b7c..0f1a4b6e02 100644
--- a/compiler/GHC/Driver/Session.hs
+++ b/compiler/GHC/Driver/Session.hs
@@ -71,9 +71,6 @@ module GHC.Driver.Session (
safeDirectImpsReq, safeImplicitImpsReq,
unsafeFlags, unsafeFlagsForInfer,
- -- ** LLVM Targets
- LlvmTarget(..), LlvmConfig(..),
-
-- ** System tool settings and locations
Settings(..),
sProgramName,
@@ -452,9 +449,6 @@ data DynFlags = DynFlags {
rawSettings :: [(String, String)],
tmpDir :: TempDir,
- llvmConfig :: LlvmConfig,
- -- ^ N.B. It's important that this field is lazy since we load the LLVM
- -- configuration lazily. See Note [LLVM configuration] in "GHC.SysTools".
llvmOptLevel :: Int, -- ^ LLVM optimisation level
verbosity :: Int, -- ^ Verbosity level: see Note [Verbosity levels]
debugLevel :: Int, -- ^ How much debug information to produce
@@ -773,17 +767,6 @@ data ProfAuto
| ProfAutoCalls -- ^ annotate call-sites
deriving (Eq,Enum)
-data LlvmTarget = LlvmTarget
- { lDataLayout :: String
- , lCPU :: String
- , lAttributes :: [String]
- }
-
--- | See Note [LLVM configuration] in "GHC.SysTools".
-data LlvmConfig = LlvmConfig { llvmTargets :: [(String, LlvmTarget)]
- , llvmPasses :: [(Int, String)]
- }
-
-----------------------------------------------------------------------------
-- Accessessors from 'DynFlags'
@@ -1117,8 +1100,8 @@ initDynFlags dflags = do
-- | The normal 'DynFlags'. Note that they are not suitable for use in this form
-- and must be fully initialized by 'GHC.runGhc' first.
-defaultDynFlags :: Settings -> LlvmConfig -> DynFlags
-defaultDynFlags mySettings llvmConfig =
+defaultDynFlags :: Settings -> DynFlags
+defaultDynFlags mySettings =
-- See Note [Updating flag description in the User's Guide]
DynFlags {
ghcMode = CompManager,
@@ -1227,8 +1210,6 @@ defaultDynFlags mySettings llvmConfig =
tmpDir = panic "defaultDynFlags: uninitialized tmpDir",
- -- See Note [LLVM configuration].
- llvmConfig = llvmConfig,
llvmOptLevel = 0,
-- ghc -M values
diff --git a/compiler/GHC/Stg/Pipeline.hs b/compiler/GHC/Stg/Pipeline.hs
index e1df24c626..f6bf55d398 100644
--- a/compiler/GHC/Stg/Pipeline.hs
+++ b/compiler/GHC/Stg/Pipeline.hs
@@ -17,6 +17,8 @@ module GHC.Stg.Pipeline
import GHC.Prelude
+import GHC.Driver.Flags
+
import GHC.Stg.Syntax
import GHC.Stg.Lint ( lintStgTopBindings )
@@ -29,7 +31,6 @@ import GHC.Stg.Lift ( StgLiftConfig, stgLiftLams )
import GHC.Unit.Module ( Module )
import GHC.Runtime.Context ( InteractiveContext )
-import GHC.Driver.Flags (DumpFlag(..))
import GHC.Utils.Error
import GHC.Types.Unique.Supply
import GHC.Utils.Outputable
diff --git a/compiler/GHC/SysTools.hs b/compiler/GHC/SysTools.hs
index adc6e6c241..058fc67d12 100644
--- a/compiler/GHC/SysTools.hs
+++ b/compiler/GHC/SysTools.hs
@@ -14,7 +14,6 @@
module GHC.SysTools (
-- * Initialisation
initSysTools,
- lazyInitLlvmConfig,
-- * Interface to system tools
module GHC.SysTools.Tasks,
@@ -32,7 +31,6 @@ module GHC.SysTools (
import GHC.Prelude
-import GHC.Settings.Utils
import GHC.Utils.Panic
import GHC.Driver.Session
@@ -44,9 +42,7 @@ import GHC.SysTools.BaseDir
import GHC.Settings.IO
import Control.Monad.Trans.Except (runExceptT)
-import System.FilePath
import System.IO
-import System.IO.Unsafe (unsafeInterleaveIO)
import Foreign.Marshal.Alloc (allocaBytes)
import System.Directory (copyFile)
@@ -102,47 +98,6 @@ stuff.
************************************************************************
-}
--- Note [LLVM configuration]
--- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
--- The `llvm-targets` and `llvm-passes` files are shipped with GHC and contain
--- information needed by the LLVM backend to invoke `llc` and `opt`.
--- Specifically:
---
--- * llvm-targets maps autoconf host triples to the corresponding LLVM
--- `data-layout` declarations. This information is extracted from clang using
--- the script in utils/llvm-targets/gen-data-layout.sh and should be updated
--- whenever we target a new version of LLVM.
---
--- * llvm-passes maps GHC optimization levels to sets of LLVM optimization
--- flags that GHC should pass to `opt`.
---
--- This information is contained in files rather the GHC source to allow users
--- to add new targets to GHC without having to recompile the compiler.
---
--- Since this information is only needed by the LLVM backend we load it lazily
--- with unsafeInterleaveIO. Consequently it is important that we lazily pattern
--- match on LlvmConfig until we actually need its contents.
-
-lazyInitLlvmConfig :: String
- -> IO LlvmConfig
-lazyInitLlvmConfig top_dir
- = unsafeInterleaveIO $ do -- see Note [LLVM configuration]
- targets <- readAndParse "llvm-targets"
- passes <- readAndParse "llvm-passes"
- return $ LlvmConfig { llvmTargets = fmap mkLlvmTarget <$> targets,
- llvmPasses = passes }
- where
- readAndParse :: Read a => String -> IO a
- readAndParse name =
- do let llvmConfigFile = top_dir </> name
- llvmConfigStr <- readFile llvmConfigFile
- case maybeReadFuzzy llvmConfigStr of
- Just s -> return s
- Nothing -> pgmError ("Can't parse " ++ show llvmConfigFile)
-
- mkLlvmTarget :: (String, String, String) -> LlvmTarget
- mkLlvmTarget (dl, cpu, attrs) = LlvmTarget dl cpu (words attrs)
-
initSysTools :: String -- TopDir path
-> IO Settings -- Set all the mutable variables above, holding
diff --git a/compiler/GHC/SysTools/Tasks.hs b/compiler/GHC/SysTools/Tasks.hs
index ce741e2c1a..312ec7897a 100644
--- a/compiler/GHC/SysTools/Tasks.hs
+++ b/compiler/GHC/SysTools/Tasks.hs
@@ -14,8 +14,7 @@ import GHC.Platform
import GHC.ForeignSrcLang
import GHC.IO (catchException)
-import GHC.CmmToLlvm.Base (llvmVersionStr, supportedLlvmVersionUpperBound, parseLlvmVersion, supportedLlvmVersionLowerBound)
-import GHC.CmmToLlvm.Config (LlvmVersion)
+import GHC.CmmToLlvm.Config (LlvmVersion, llvmVersionStr, supportedLlvmVersionUpperBound, parseLlvmVersion, supportedLlvmVersionLowerBound)
import GHC.SysTools.Process
import GHC.SysTools.Info
diff --git a/compiler/ghc.cabal.in b/compiler/ghc.cabal.in
index 1036748a8a..9f0d7a81fd 100644
--- a/compiler/ghc.cabal.in
+++ b/compiler/ghc.cabal.in
@@ -407,6 +407,7 @@ Library
GHC.Driver.Flags
GHC.Driver.GenerateCgIPEStub
GHC.Driver.Hooks
+ GHC.Driver.LlvmConfigCache
GHC.Driver.Main
GHC.Driver.Make
GHC.Driver.MakeFile
diff --git a/ghc/GHCi/UI.hs b/ghc/GHCi/UI.hs
index 94fc07660b..ff607d645c 100644
--- a/ghc/GHCi/UI.hs
+++ b/ghc/GHCi/UI.hs
@@ -3005,7 +3005,7 @@ showDynFlags show_all dflags = do
is_on = test f dflags
quiet = not show_all && test f default_dflags == is_on
- default_dflags = defaultDynFlags (settings dflags) (llvmConfig dflags)
+ default_dflags = defaultDynFlags (settings dflags)
(ghciFlags,others) = partition (\f -> flagSpecFlag f `elem` flgs)
DynFlags.fFlags
@@ -3458,8 +3458,7 @@ showLanguages' show_all dflags =
is_on = test f dflags
quiet = not show_all && test f default_dflags == is_on
- default_dflags =
- defaultDynFlags (settings dflags) (llvmConfig dflags) `lang_set` Just lang
+ default_dflags = defaultDynFlags (settings dflags) `lang_set` Just lang
lang = fromMaybe GHC2021 (language dflags)
diff --git a/testsuite/tests/count-deps/CountDepsAst.stdout b/testsuite/tests/count-deps/CountDepsAst.stdout
index cdc300aa2f..2dfd8309c7 100644
--- a/testsuite/tests/count-deps/CountDepsAst.stdout
+++ b/testsuite/tests/count-deps/CountDepsAst.stdout
@@ -1,4 +1,4 @@
-Found 282 Language.Haskell.Syntax module dependencies
+Found 284 Language.Haskell.Syntax module dependencies
GHC.Builtin.Names
GHC.Builtin.PrimOps
GHC.Builtin.PrimOps.Ids
@@ -19,6 +19,7 @@ GHC.Cmm.Node
GHC.Cmm.Switch
GHC.Cmm.Type
GHC.CmmToAsm.CFG.Weight
+GHC.CmmToLlvm.Config
GHC.Core
GHC.Core.Class
GHC.Core.Coercion
@@ -96,6 +97,7 @@ GHC.Driver.Errors.Ppr
GHC.Driver.Errors.Types
GHC.Driver.Flags
GHC.Driver.Hooks
+GHC.Driver.LlvmConfigCache
GHC.Driver.Monad
GHC.Driver.Phases
GHC.Driver.Pipeline.Monad
diff --git a/testsuite/tests/count-deps/CountDepsParser.stdout b/testsuite/tests/count-deps/CountDepsParser.stdout
index ddfc30e010..8a64148831 100644
--- a/testsuite/tests/count-deps/CountDepsParser.stdout
+++ b/testsuite/tests/count-deps/CountDepsParser.stdout
@@ -1,4 +1,4 @@
-Found 289 GHC.Parser module dependencies
+Found 291 GHC.Parser module dependencies
GHC.Builtin.Names
GHC.Builtin.PrimOps
GHC.Builtin.PrimOps.Ids
@@ -19,6 +19,7 @@ GHC.Cmm.Node
GHC.Cmm.Switch
GHC.Cmm.Type
GHC.CmmToAsm.CFG.Weight
+GHC.CmmToLlvm.Config
GHC.Core
GHC.Core.Class
GHC.Core.Coercion
@@ -97,6 +98,7 @@ GHC.Driver.Errors.Ppr
GHC.Driver.Errors.Types
GHC.Driver.Flags
GHC.Driver.Hooks
+GHC.Driver.LlvmConfigCache
GHC.Driver.Monad
GHC.Driver.Phases
GHC.Driver.Pipeline.Monad
diff --git a/testsuite/tests/hiefile/should_run/HieQueries.hs b/testsuite/tests/hiefile/should_run/HieQueries.hs
index d48dd02cd0..d6b7bba1b0 100644
--- a/testsuite/tests/hiefile/should_run/HieQueries.hs
+++ b/testsuite/tests/hiefile/should_run/HieQueries.hs
@@ -47,7 +47,7 @@ makeNc = initNameCache 'z' []
dynFlagsForPrinting :: String -> IO DynFlags
dynFlagsForPrinting libdir = do
systemSettings <- initSysTools libdir
- return $ defaultDynFlags systemSettings (LlvmConfig [] [])
+ return $ defaultDynFlags systemSettings
main = do
libdir:_ <- getArgs
diff --git a/testsuite/tests/hiefile/should_run/PatTypes.hs b/testsuite/tests/hiefile/should_run/PatTypes.hs
index 67a89d1c49..e943a27cb1 100644
--- a/testsuite/tests/hiefile/should_run/PatTypes.hs
+++ b/testsuite/tests/hiefile/should_run/PatTypes.hs
@@ -38,7 +38,7 @@ makeNc = initNameCache 'z' []
dynFlagsForPrinting :: String -> IO DynFlags
dynFlagsForPrinting libdir = do
systemSettings <- initSysTools libdir
- return $ defaultDynFlags systemSettings (LlvmConfig [] [])
+ return $ defaultDynFlags systemSettings
selectPoint' :: HieFile -> (Int,Int) -> HieAST Int
selectPoint' hf loc =
diff --git a/testsuite/tests/regalloc/regalloc_unit_tests.hs b/testsuite/tests/regalloc/regalloc_unit_tests.hs
index d6ffcc3431..b414b36e59 100644
--- a/testsuite/tests/regalloc/regalloc_unit_tests.hs
+++ b/testsuite/tests/regalloc/regalloc_unit_tests.hs
@@ -26,6 +26,7 @@ import qualified GHC.CmmToAsm.X86.Instr as X86.Instr
import qualified GHC.CmmToAsm.X86 as X86
import GHC.Driver.Config.Cmm.Parser
import GHC.Driver.Config.CmmToAsm
+import GHC.Driver.Config.Cmm
import GHC.Driver.Main
import GHC.Driver.Env
import GHC.StgToCmm.CgUtils
@@ -85,13 +86,13 @@ main = do
dflags <- getDynFlags
logger <- getLogger
+ home_unit <- hsc_home_unit <$> getSession
reifyGhc $ \_ -> do
us <- unitTestUniqSupply
- runTests logger dflags us
+ runTests logger home_unit dflags us
return ()
-
-- | TODO: Make this an IORef along the lines of Data.Unique.newUnique to add
-- stronger guarantees a UniqSupply won't be accidentally reused
unitTestUniqSupply :: IO UniqSupply
@@ -118,30 +119,31 @@ assertIO = assertOr $ \msg -> void (throwIO . RegAllocTestException $ msg)
-- | compile the passed cmm file and return the register allocator stats
-- ***NOTE*** This function sets Opt_D_dump_asm_stats in the passed
-- DynFlags because it won't work without it. Handle stderr appropriately.
-compileCmmForRegAllocStats ::
- Logger ->
- DynFlags ->
- FilePath ->
- (NCGConfig ->
- NcgImpl (Alignment, RawCmmStatics) X86.Instr.Instr X86.Instr.JumpDest) ->
- UniqSupply ->
- IO [( Maybe [Color.RegAllocStats (Alignment, RawCmmStatics) X86.Instr.Instr]
+compileCmmForRegAllocStats
+ :: Logger
+ -> HomeUnit
+ -> DynFlags
+ -> FilePath
+ -> (NCGConfig ->
+ NcgImpl (Alignment, RawCmmStatics) X86.Instr.Instr X86.Instr.JumpDest)
+ -> UniqSupply
+ -> IO [( Maybe [Color.RegAllocStats (Alignment, RawCmmStatics) X86.Instr.Instr]
, Maybe [Linear.RegAllocStats])]
-compileCmmForRegAllocStats logger dflags cmmFile ncgImplF us = do
+compileCmmForRegAllocStats logger home_unit dflags cmmFile ncgImplF us = do
let ncgImpl = ncgImplF (initNCGConfig dflags thisMod)
- hscEnv <- newHscEnv dflags
+ let cmm_config = initCmmConfig dflags
-- parse the cmm file and output any warnings or errors
- let fake_mod = mkHomeModule (hsc_home_unit hscEnv) (mkModuleName "fake")
+ let fake_mod = mkHomeModule home_unit (mkModuleName "fake")
cmmpConfig = initCmmParserConfig dflags
- (warnings, errors, parsedCmm) <- parseCmmFile cmmpConfig fake_mod (hsc_home_unit hscEnv) cmmFile
+ (warnings, errors, parsedCmm) <- parseCmmFile cmmpConfig fake_mod home_unit cmmFile
-- print parser errors or warnings
let !diag_opts = initDiagOpts dflags
mapM_ (printMessages logger diag_opts) [warnings, errors]
let initTopSRT = emptySRT thisMod
- cmmGroup <- fmap snd $ cmmPipeline hscEnv initTopSRT $ fst $ fromJust parsedCmm
+ cmmGroup <- fmap snd $ cmmPipeline logger cmm_config initTopSRT $ fst $ fromJust parsedCmm
let profile = targetProfile dflags
rawCmms <- cmmToRawCmm logger profile (Stream.yield cmmGroup)
@@ -175,10 +177,11 @@ noSpillsCmmFile = "no_spills.cmm"
-- | Run each unit test in this file and notify the user of success or
-- failure.
-runTests :: Logger -> DynFlags -> UniqSupply -> IO ()
-runTests logger dflags us = testGraphNoSpills logger dflags noSpillsCmmFile us >>= \res ->
- if res then putStrLn "All tests passed."
- else hPutStr stderr "testGraphNoSpills failed!"
+runTests :: Logger -> HomeUnit -> DynFlags -> UniqSupply -> IO ()
+runTests logger home_unit dflags us = do
+ res <- testGraphNoSpills logger home_unit dflags noSpillsCmmFile us
+ if res then putStrLn "All tests passed."
+ else hPutStr stderr "testGraphNoSpills failed!"
-- | To map an unlimited number of abstract variables to a limited number of
@@ -192,10 +195,10 @@ runTests logger dflags us = testGraphNoSpills logger dflags noSpillsCmmFile us >
-- the register allocator should be able to do everything
-- (on x86) in the passed file without any spills or reloads.
--
-testGraphNoSpills :: Logger -> DynFlags -> FilePath -> UniqSupply -> IO Bool
-testGraphNoSpills logger dflags' path us = do
+testGraphNoSpills :: Logger -> HomeUnit -> DynFlags -> FilePath -> UniqSupply -> IO Bool
+testGraphNoSpills logger home_unit dflags' path us = do
colorStats <- fst . concatTupledMaybes <$>
- compileCmmForRegAllocStats logger dflags path X86.ncgX86 us
+ compileCmmForRegAllocStats logger home_unit dflags path X86.ncgX86 us
assertIO "testGraphNoSpills: color stats should not be empty"
$ not (null colorStats)
diff --git a/utils/llvm-targets/gen-data-layout.sh b/utils/llvm-targets/gen-data-layout.sh
index ed33e6c4f4..fd488d2f8b 100755
--- a/utils/llvm-targets/gen-data-layout.sh
+++ b/utils/llvm-targets/gen-data-layout.sh
@@ -16,7 +16,7 @@
# Add missing targets to the list below to have them included in
# llvm-targets file.
#
-# See Note [LLVM configuration] in GHC.SysTools for the whole story regarding LLVM
+# See Note [LLVM configuration] in GHC.CmmToLlvm.Config for the whole story regarding LLVM
# configuration data.
# Target sets for which to generate the llvm-targets file