module GHC.StgToCmm ( codeGen ) where
#include "HsVersions.h"
import GHC.Prelude as Prelude
import GHC.Driver.Backend
import GHC.Driver.Session
import GHC.StgToCmm.Prof (initInfoTableProv, initCostCentres, ldvEnter)
import GHC.StgToCmm.Monad
import GHC.StgToCmm.Env
import GHC.StgToCmm.Bind
import GHC.StgToCmm.DataCon
import GHC.StgToCmm.Layout
import GHC.StgToCmm.Utils
import GHC.StgToCmm.Closure
import GHC.StgToCmm.Hpc
import GHC.StgToCmm.Ticky
import GHC.StgToCmm.Types (ModuleLFInfos)
import GHC.Cmm
import GHC.Cmm.Utils
import GHC.Cmm.CLabel
import GHC.Cmm.Graph
import GHC.Stg.Syntax
import GHC.Types.CostCentre
import GHC.Types.IPE
import GHC.Types.HpcInfo
import GHC.Types.Id
import GHC.Types.Id.Info
import GHC.Types.RepType
import GHC.Types.Basic
import GHC.Types.Var.Set ( isEmptyDVarSet )
import GHC.Types.Unique.FM
import GHC.Types.Name.Env
import GHC.Types.ForeignStubs
import GHC.Core.DataCon
import GHC.Core.TyCon
import GHC.Core.Multiplicity
import GHC.Unit.Module
import GHC.Utils.Error
import GHC.Utils.Outputable
import GHC.Utils.Panic
import GHC.Utils.Logger
import GHC.Utils.TmpFs
import GHC.Data.Stream
import GHC.Data.OrdList
import GHC.Types.Unique.Map
import Control.Monad (when,void, forM_)
import GHC.Utils.Misc
import System.IO.Unsafe
import qualified Data.ByteString as BS
import Data.Maybe
import Data.IORef
data CodeGenState = CodeGenState { codegen_used_info :: !(OrdList CmmInfoTable)
, codegen_state :: !CgState }
codeGen :: Logger
-> TmpFs
-> DynFlags
-> Module
-> InfoTableProvMap
-> [TyCon]
-> CollectedCCs
-> [CgStgTopBinding]
-> HpcInfo
-> Stream IO CmmGroup (CStub, ModuleLFInfos)
codeGen logger tmpfs dflags this_mod ip_map@(InfoTableProvMap (UniqMap denv) _) data_tycons
cost_centre_info stg_binds hpc_info
= do {
; cgref <- liftIO $ initC >>= \s -> newIORef (CodeGenState mempty s)
; let cg :: FCode a -> Stream IO CmmGroup a
cg fcode = do
(a, cmm) <- liftIO . withTimingSilent logger dflags (text "STG -> Cmm") (`seq` ()) $ do
CodeGenState ts st <- readIORef cgref
let (a,st') = runC dflags this_mod st (getCmm fcode)
let !used_info
| gopt Opt_InfoTableMap dflags = toOL (mapMaybe topInfoTable (snd a)) `mappend` ts
| otherwise = mempty
writeIORef cgref $!
CodeGenState used_info
(st'{ cgs_tops = nilOL,
cgs_stmts = mkNop
})
return a
yield cmm
return a
; cg (mkModuleInit cost_centre_info this_mod hpc_info)
; mapM_ (cg . cgTopBinding logger tmpfs dflags) stg_binds
; let do_tycon tycon = do
when (isEnumerationTyCon tycon) $ cg (cgEnumerationTyCon tycon)
mapM_ (cg . cgDataCon DefinitionSite) (tyConDataCons tycon)
; mapM_ do_tycon data_tycons
; mapM_ (\(dc, ns) -> forM_ ns $ \(k, _ss) -> cg (cgDataCon (UsageSite this_mod k) dc)) (nonDetEltsUFM denv)
; final_state <- liftIO (readIORef cgref)
; let cg_id_infos = cgs_binds . codegen_state $ final_state
used_info = fromOL . codegen_used_info $ final_state
; !foreign_stub <- cg (initInfoTableProv used_info ip_map this_mod)
; let extractInfo info = (name, lf)
where
!name = idName (cg_id info)
!lf = cg_lf info
!generatedInfo
| gopt Opt_OmitInterfacePragmas dflags
= emptyNameEnv
| otherwise
= mkNameEnv (Prelude.map extractInfo (eltsUFM cg_id_infos))
; return (foreign_stub, generatedInfo)
}
cgTopBinding :: Logger -> TmpFs -> DynFlags -> CgStgTopBinding -> FCode ()
cgTopBinding logger tmpfs dflags = \case
StgTopLifted (StgNonRec id rhs) -> do
let (info, fcode) = cgTopRhs dflags NonRecursive id rhs
fcode
addBindC info
StgTopLifted (StgRec pairs) -> do
let (bndrs, rhss) = unzip pairs
let pairs' = zip bndrs rhss
r = unzipWith (cgTopRhs dflags Recursive) pairs'
(infos, fcodes) = unzip r
addBindsC infos
sequence_ fcodes
StgTopStringLit id str -> do
let label = mkBytesLabel (idName id)
let isNCG = backend dflags == NCG
isSmall = fromIntegral (BS.length str) <= binBlobThreshold dflags
asString = binBlobThreshold dflags == 0 || isSmall
(lit,decl) = if not isNCG || asString
then mkByteStringCLit label str
else mkFileEmbedLit label $ unsafePerformIO $ do
bFile <- newTempName logger tmpfs dflags TFL_CurrentModule ".dat"
BS.writeFile bFile str
return bFile
emitDecl decl
addBindC (litIdInfo (targetPlatform dflags) id mkLFStringLit lit)
cgTopRhs :: DynFlags -> RecFlag -> Id -> CgStgRhs -> (CgIdInfo, FCode ())
cgTopRhs dflags _rec bndr (StgRhsCon _cc con mn _ts args)
= cgTopRhsCon dflags bndr con mn (assertNonVoidStgArgs args)
cgTopRhs dflags rec bndr (StgRhsClosure fvs cc upd_flag args body)
= ASSERT(isEmptyDVarSet fvs)
cgTopRhsClosure (targetPlatform dflags) rec bndr cc upd_flag args body
mkModuleInit
:: CollectedCCs
-> Module
-> HpcInfo
-> FCode ()
mkModuleInit cost_centre_info this_mod hpc_info
= do { initHpc this_mod hpc_info
; initCostCentres cost_centre_info
}
cgEnumerationTyCon :: TyCon -> FCode ()
cgEnumerationTyCon tycon
= do platform <- getPlatform
emitRODataLits (mkLocalClosureTableLabel (tyConName tycon) NoCafRefs)
[ CmmLabelOff (mkLocalClosureLabel (dataConName con) NoCafRefs)
(tagForCon platform con)
| con <- tyConDataCons tycon]
cgDataCon :: ConInfoTableLocation -> DataCon -> FCode ()
cgDataCon mn data_con
= do { MASSERT( not (isUnboxedTupleDataCon data_con || isUnboxedSumDataCon data_con) )
; profile <- getProfile
; platform <- getPlatform
; let
(tot_wds,
ptr_wds)
= mkVirtConstrSizes profile arg_reps
nonptr_wds = tot_wds ptr_wds
dyn_info_tbl =
mkDataConInfoTable profile data_con mn False ptr_wds nonptr_wds
arg_reps :: [NonVoid PrimRep]
arg_reps = [ NonVoid rep_ty
| ty <- dataConRepArgTys data_con
, rep_ty <- typePrimRep (scaledThing ty)
, not (isVoidRep rep_ty) ]
; emitClosureAndInfoTable platform dyn_info_tbl NativeDirectCall [] $
do { tickyEnterDynCon
; ldvEnter (CmmReg nodeReg)
; tickyReturnOldCon (length arg_reps)
; void $ emitReturn [cmmOffsetB platform (CmmReg nodeReg) (tagForCon platform data_con)]
}
}