X-Git-Url: http://git.megacz.com/?a=blobdiff_plain;f=ghc%2Fcompiler%2FcodeGen%2FCodeGen.lhs;h=d7f2f70c43fe16ab400b24cdc7c659f2e16e57a1;hb=423d477bfecd490de1449c59325c8776f91d7aac;hp=f9ee5b7969fed50a7d0e3f07d98f271ab0400d13;hpb=6a44ce76861d73d59badc8f8c17ffbd52eff17ba;p=ghc-hetmet.git diff --git a/ghc/compiler/codeGen/CodeGen.lhs b/ghc/compiler/codeGen/CodeGen.lhs index f9ee5b7..d7f2f70 100644 --- a/ghc/compiler/codeGen/CodeGen.lhs +++ b/ghc/compiler/codeGen/CodeGen.lhs @@ -19,83 +19,89 @@ module CodeGen ( codeGen ) where #include "HsVersions.h" +import DriverState ( v_Build_tag, v_MainModIs ) + -- Kludge (??) so that CgExpr is reached via at least one non-SOURCE -- import. Before, that wasn't the case, and CM therefore didn't -- bother to compile it. import CgExpr ( {-NOTHING!-} ) -- DO NOT DELETE THIS IMPORT +import CgProf +import CgMonad +import CgBindery ( CgIdInfo, addBindC, addBindsC, getCgIdInfo, + cgIdInfoId ) +import CgClosure ( cgTopRhsClosure ) +import CgCon ( cgTopRhsCon, cgTyCon ) +import CgUtils ( cmmRegOffW, emitRODataLits, cmmNeWord, emitRtsCall ) + +import CLabel ( mkSRTLabel, mkClosureLabel, moduleRegdLabel, + mkPlainModuleInitLabel, mkModuleInitLabel ) +import Cmm +import CmmUtils ( zeroCLit, mkIntCLit, mkLblExpr ) +import PprCmm ( pprCmms ) +import MachOp ( wordRep, MachHint(..) ) import StgSyn -import CgMonad -import AbsCSyn -import CLabel ( CLabel, mkSRTLabel, mkClosureLabel, mkModuleInitLabel ) +import PrelNames ( gHC_PRIM, rOOT_MAIN, mAIN_Name, pREL_TOP_HANDLER ) +import CmdLineOpts ( DynFlags, DynFlag(..), opt_EnsureSplittableC, + opt_SccProfilingOn ) -import PprAbsC ( dumpRealC ) -import AbsCUtils ( mkAbstractCs, flattenAbsC ) -import CgBindery ( CgIdInfo, addBindC, addBindsC, getCAddrModeAndInfo ) -import CgClosure ( cgTopRhsClosure ) -import CgCon ( cgTopRhsCon ) -import CgConTbls ( genStaticConBits ) -import ClosureInfo ( mkClosureLFInfo ) -import CmdLineOpts ( DynFlags, DynFlag(..), - opt_SccProfilingOn, opt_EnsureSplittableC ) -import CostCentre ( CostCentre, CostCentreStack ) +import HscTypes ( ForeignStubs(..), TypeEnv, typeEnvTyCons ) +import CostCentre ( CollectedCCs ) import Id ( Id, idName, setIdName ) -import Name ( globaliseName ) -import Module ( Module ) -import PrimRep ( PrimRep(..) ) -import TyCon ( TyCon, isDataTyCon ) -import BasicTypes ( TopLevelFlag(..) ) -import UniqSupply ( mkSplitUniqSupply ) +import Name ( nameSrcLoc, nameOccName, nameUnique, isInternalName, mkExternalName ) +import OccName ( mkLocalOcc ) +import TyCon ( isDataTyCon ) +import Module ( Module, mkModuleName ) import ErrUtils ( dumpIfSet_dyn, showPass ) -import Panic ( assertPanic ) +import Panic ( assertPanic, trace ) +import qualified Module ( moduleName ) #ifdef DEBUG -import Id ( idCafInfo ) -import IdInfo ( mayHaveCafRefs ) import Outputable #endif + +import DATA_IOREF ( readIORef ) \end{code} \begin{code} codeGen :: DynFlags - -> Module -- Module name - -> [Module] -- Import names - -> ([CostCentre], -- Local cost-centres needing declaring/registering - [CostCentre], -- "extern" cost-centres needing declaring - [CostCentreStack]) -- Pre-defined "singleton" cost centre stacks - -> [Id] -- foreign-exported binders - -> [TyCon] -- Local tycons, including ones from classes - -> [(StgBinding,[Id])] -- Bindings to convert, with SRTs - -> IO AbstractC -- Output - -codeGen dflags mod_name imported_modules cost_centre_info fe_binders - tycons stg_binds - = do { showPass dflags "CodeGen" - - ; fl_uniqs <- mkSplitUniqSupply 'f' - ; let - datatype_stuff = genStaticConBits cinfo data_tycons - code_stuff = initC cinfo (mapCs cgTopBinding stg_binds) - init_stuff = mkModuleInit fe_binders mod_name imported_modules - cost_centre_info - - abstractC = mkAbstractCs [ maybeSplitCode, - init_stuff, - code_stuff, - datatype_stuff] + -> Module + -> TypeEnv + -> ForeignStubs + -> [Module] -- directly-imported modules + -> CollectedCCs -- (Local/global) cost-centres needing declaring/registering. + -> [(StgBinding,[(Id,[Id])])] -- Bindings to convert, with SRTs + -> IO [Cmm] -- Output + +codeGen dflags this_mod type_env foreign_stubs imported_mods + cost_centre_info stg_binds + = do + { showPass dflags "CodeGen" + ; way <- readIORef v_Build_tag + ; mb_main_mod <- readIORef v_MainModIs + + ; let tycons = typeEnvTyCons type_env + data_tycons = filter isDataTyCon tycons + +-- Why? +-- ; mapM_ (\x -> seq x (return ())) data_tycons + + ; code_stuff <- initC this_mod $ do + { cmm_binds <- mapM (getCmm . cgTopBinding) stg_binds + ; cmm_tycons <- mapM cgTyCon data_tycons + ; cmm_init <- getCmm (mkModuleInit way cost_centre_info + this_mod mb_main_mod + foreign_stubs imported_mods) + ; return (cmm_binds ++ concat cmm_tycons ++ [cmm_init]) + } -- Put datatype_stuff after code_stuff, because the - -- datatype closure table (for enumeration types) - -- to (say) PrelBase_True_closure, which is defined in code_stuff - - flat_abstractC = flattenAbsC fl_uniqs abstractC + -- datatype closure table (for enumeration types) to + -- (say) PrelBase_True_closure, which is defined in + -- code_stuff - ; dumpIfSet_dyn dflags Opt_D_dump_absC "Abstract C" (dumpRealC abstractC) - ; return flat_abstractC - } - where - data_tycons = filter isDataTyCon tycons + ; dumpIfSet_dyn dflags Opt_D_dump_cmm "Cmm" (pprCmms code_stuff) - cinfo = MkCompInfo mod_name + ; return code_stuff } \end{code} %************************************************************************ @@ -104,41 +110,140 @@ codeGen dflags mod_name imported_modules cost_centre_info fe_binders %* * %************************************************************************ +/* ----------------------------------------------------------------------------- + Module initialisation + + The module initialisation code looks like this, roughly: + + FN(__stginit_Foo) { + JMP_(__stginit_Foo_1_p) + } + + FN(__stginit_Foo_1_p) { + ... + } + + We have one version of the init code with a module version and the + 'way' attached to it. The version number helps to catch cases + where modules are not compiled in dependency order before being + linked: if a module has been compiled since any modules which depend on + it, then the latter modules will refer to a different version in their + init blocks and a link error will ensue. + + The 'way' suffix helps to catch cases where modules compiled in different + ways are linked together (eg. profiled and non-profiled). + + We provide a plain, unadorned, version of the module init code + which just jumps to the version with the label and way attached. The + reason for this is that when using foreign exports, the caller of + startupHaskell() must supply the name of the init function for the "top" + module in the program, and we don't want to require that this name + has the version and way info appended to it. + -------------------------------------------------------------------------- */ + +We initialise the module tree by keeping a work-stack, + * pointed to by Sp + * that grows downward + * Sp points to the last occupied slot + + \begin{code} mkModuleInit - :: [Id] -- foreign exported functions - -> Module -- module name - -> [Module] -- import names - -> ([CostCentre], -- cost centre info - [CostCentre], - [CostCentreStack]) - -> AbstractC -mkModuleInit fe_binders mod imps cost_centre_info - = let - register_fes = - map (\f -> CMacroStmt REGISTER_FOREIGN_EXPORT [f]) fe_labels - - fe_labels = - map (\f -> CLbl (mkClosureLabel (idName f)) PtrRep) fe_binders - - (cc_decls, cc_regs) = mkCostCentreStuff cost_centre_info - - mk_import_register imp = - CMacroStmt REGISTER_IMPORT [ - CLbl (mkModuleInitLabel imp) AddrRep - ] - - register_imports = map mk_import_register imps - in - mkAbstractCs [ - cc_decls, - CModuleInitBlock (mkModuleInitLabel mod) - (mkAbstractCs (register_fes ++ - cc_regs : - register_imports)) - ] + :: String -- the "way" + -> CollectedCCs -- cost centre info + -> Module + -> Maybe String -- Just m ==> we have flag: -main-is Foo.baz + -> ForeignStubs + -> [Module] + -> Code +mkModuleInit way cost_centre_info this_mod mb_main_mod foreign_stubs imported_mods + = do { + + -- Allocate the static boolean that records if this + -- module has been registered already + ; emitData Data [CmmDataLabel moduleRegdLabel, + CmmStaticLit zeroCLit] + + ; emitSimpleProc real_init_lbl $ do + { -- The return-code pops the work stack by + -- incrementing Sp, and then jumpd to the popped item + ret_blk <- forkLabelledCode $ stmtsC + [ CmmAssign spReg (cmmRegOffW spReg 1) + , CmmJump (CmmLoad (cmmRegOffW spReg (-1)) wordRep) [] ] + + ; init_blk <- forkLabelledCode $ do + { mod_init_code; stmtC (CmmBranch ret_blk) } + + ; stmtC (CmmCondBranch (cmmNeWord (CmmLit zeroCLit) mod_reg_val) + ret_blk) + ; stmtC (CmmBranch init_blk) + } + + + -- Make the "plain" procedure jump to the "real" init procedure + ; emitSimpleProc plain_init_lbl jump_to_init + + -- When compiling the module in which the 'main' function lives, + -- (that is, Module.moduleName this_mod == main_mod_name) + -- we inject an extra stg_init procedure for stg_init_ZCMain, for the + -- RTS to invoke. We must consult the -main-is flag in case the + -- user specified a different function to Main.main + ; whenC (Module.moduleName this_mod == main_mod_name) + (emitSimpleProc plain_main_init_lbl jump_to_init) + } + where + plain_init_lbl = mkPlainModuleInitLabel this_mod + real_init_lbl = mkModuleInitLabel this_mod way + plain_main_init_lbl = mkPlainModuleInitLabel rOOT_MAIN + + jump_to_init = stmtC (CmmJump (mkLblExpr real_init_lbl) []) + + mod_reg_val = CmmLoad (mkLblExpr moduleRegdLabel) wordRep + + main_mod_name = case mb_main_mod of + Just mod_name -> mkModuleName mod_name + Nothing -> mAIN_Name + + -- Main refers to GHC.TopHandler.runIO, so make sure we call the + -- init function for GHC.TopHandler. + extra_imported_mods + | Module.moduleName this_mod == main_mod_name = [pREL_TOP_HANDLER] + | otherwise = [] + + mod_init_code = do + { -- Set mod_reg to 1 to record that we've been here + stmtC (CmmStore (mkLblExpr moduleRegdLabel) (CmmLit (mkIntCLit 1))) + + -- Now do local stuff + ; registerForeignExports foreign_stubs + ; initCostCentres cost_centre_info + ; mapCs (registerModuleImport way) (imported_mods++extra_imported_mods) + } + + +----------------------- +registerModuleImport :: String -> Module -> Code +registerModuleImport way mod + | mod == gHC_PRIM + = nopC + | otherwise -- Push the init procedure onto the work stack + = stmtsC [ CmmAssign spReg (cmmRegOffW spReg (-1)) + , CmmStore (CmmReg spReg) (mkLblExpr (mkModuleInitLabel mod way)) ] + +----------------------- +registerForeignExports :: ForeignStubs -> Code +registerForeignExports NoStubs + = nopC +registerForeignExports (ForeignStubs _ _ _ fe_bndrs) + = mapM_ mk_export_register fe_bndrs + where + mk_export_register bndr + = emitRtsCall SLIT("getStablePtr") + [ (CmmLit (CmmLabel (mkClosureLabel (idName bndr))), PtrHint) ] \end{code} + + Cost-centre profiling: Besides the usual stuff, we must produce declarations for the cost-centres defined in this module; @@ -146,28 +251,16 @@ declarations for the cost-centres defined in this module; code-generator.) \begin{code} -mkCostCentreStuff (local_CCs, extern_CCs, singleton_CCSs) - | not opt_SccProfilingOn = (AbsCNop, AbsCNop) - | otherwise = - ( mkAbstractCs ( - map (CCostCentreDecl True) local_CCs ++ - map (CCostCentreDecl False) extern_CCs ++ - map CCostCentreStackDecl singleton_CCSs), - mkAbstractCs (mkCcRegister local_CCs singleton_CCSs) - ) - where - mkCcRegister ccs cc_stacks - = let - register_ccs = mkAbstractCs (map mk_register ccs) - register_cc_stacks = mkAbstractCs (map mk_register_ccs cc_stacks) - in - [ register_ccs, register_cc_stacks ] - where - mk_register cc - = CCallProfCCMacro SLIT("REGISTER_CC") [mkCCostCentre cc] - - mk_register_ccs ccs - = CCallProfCCMacro SLIT("REGISTER_CCS") [mkCCostCentreStack ccs] +initCostCentres :: CollectedCCs -> Code +-- Emit the declarations, and return code to register them +initCostCentres (local_CCs, ___extern_CCs, singleton_CCSs) + | not opt_SccProfilingOn = nopC + | otherwise + = do { mapM_ emitCostCentreDecl local_CCs + ; mapM_ emitCostCentreStackDecl singleton_CCSs + ; mapM_ emitRegisterCC local_CCs + ; mapM_ emitRegisterCCS singleton_CCSs + } \end{code} %************************************************************************ @@ -187,92 +280,83 @@ style, with the increasing static environment being plumbed as a state variable. \begin{code} -cgTopBinding :: (StgBinding,[Id]) -> Code -cgTopBinding (StgNonRec srt_info id rhs, srt) - = absC maybeSplitCode `thenC` - maybeGlobaliseId id `thenFC` \ id' -> - let - srt_label = mkSRTLabel (idName id') - in - mkSRT srt_label srt [] `thenC` - setSRTLabel srt_label ( - cgTopRhs id' rhs srt_info `thenFC` \ (id, info) -> - addBindC id info - ) - -cgTopBinding (StgRec srt_info pairs, srt) - = absC maybeSplitCode `thenC` - let - (bndrs, rhss) = unzip pairs - in - mapFCs maybeGlobaliseId bndrs `thenFC` \ bndrs'@(id:_) -> - let - srt_label = mkSRTLabel (idName id) - pairs' = zip bndrs' rhss - in - mkSRT srt_label srt bndrs' `thenC` - setSRTLabel srt_label ( - fixC (\ new_binds -> - addBindsC new_binds `thenC` - mapFCs ( \ (b,e) -> cgTopRhs b e srt_info ) pairs' - ) `thenFC` \ new_binds -> nopC - ) - -mkSRT :: CLabel -> [Id] -> [Id] -> Code -mkSRT lbl [] these = nopC -mkSRT lbl ids these - = mapFCs remap ids `thenFC` \ ids -> - absC (CSRT lbl (map (mkClosureLabel . idName) ids)) +cgTopBinding :: (StgBinding,[(Id,[Id])]) -> Code +cgTopBinding (StgNonRec id rhs, srts) + = do { id' <- maybeExternaliseId id + ; mapM_ (mkSRT [id']) srts + ; (id,info) <- cgTopRhs id' rhs + ; addBindC id info -- Add the *un-externalised* Id to the envt, + -- so we find it when we look up occurrences + } + +cgTopBinding (StgRec pairs, srts) + = do { let (bndrs, rhss) = unzip pairs + ; bndrs' <- mapFCs maybeExternaliseId bndrs + ; let pairs' = zip bndrs' rhss + ; mapM_ (mkSRT bndrs') srts + ; new_binds <- fixC (\ new_binds -> do + { addBindsC new_binds + ; mapFCs ( \ (b,e) -> cgTopRhs b e ) pairs' }) + ; nopC } + +mkSRT :: [Id] -> (Id,[Id]) -> Code +mkSRT these (id,[]) = nopC +mkSRT these (id,ids) + = do { ids <- mapFCs remap ids + ; id <- remap id + ; emitRODataLits (mkSRTLabel (idName id)) + (map (CmmLabel . mkClosureLabel . idName) ids) + } where - -- sigh, better map all the ids against the environment in case they've - -- been globalised (see maybeGlobaliseId below). + -- Sigh, better map all the ids against the environment in + -- case they've been externalised (see maybeExternaliseId below). remap id = case filter (==id) these of - [] -> getCAddrModeAndInfo id - `thenFC` \ (id, _, _) -> returnFC id (id':_) -> returnFC id' + [] -> do { info <- getCgIdInfo id; return (cgIdInfoId info) } + +-- Urgh! I tried moving the forkStatics call from the rhss of cgTopRhs +-- to enclose the listFCs in cgTopBinding, but that tickled the +-- statics "error" call in initC. I DON'T UNDERSTAND WHY! --- if we're splitting the object, we need to globalise all the top-level names --- (and then make sure we only use the globalised one in any C label we use --- which refers to this name). -maybeGlobaliseId :: Id -> FCode Id -maybeGlobaliseId id - = moduleName `thenFC` \ mod -> - let - name = idName id +cgTopRhs :: Id -> StgRhs -> FCode (Id, CgIdInfo) + -- The Id is passed along for setting up a binding... + -- It's already been externalised if necessary - -- globalise the name for -split-objs, if necessary - real_name | opt_EnsureSplittableC = globaliseName name mod - | otherwise = name +cgTopRhs bndr (StgRhsCon cc con args) + = forkStatics (cgTopRhsCon bndr con args) - id' = setIdName id real_name - in - returnFC id' +cgTopRhs bndr (StgRhsClosure cc bi fvs upd_flag srt args body) + = ASSERT(null fvs) -- There should be no free variables + setSRTLabel (mkSRTLabel (idName bndr)) $ + forkStatics (cgTopRhsClosure bndr cc bi srt upd_flag args body) +\end{code} -maybeSplitCode - | opt_EnsureSplittableC = CSplitMarker - | otherwise = AbsCNop --- Urgh! I tried moving the forkStatics call from the rhss of cgTopRhs --- to enclose the listFCs in cgTopBinding, but that tickled the --- statics "error" call in initC. I DON'T UNDERSTAND WHY! +%************************************************************************ +%* * +\subsection{Stuff to support splitting} +%* * +%************************************************************************ + +If we're splitting the object, we need to externalise all the top-level names +(and then make sure we only use the externalised one in any C label we use +which refers to this name). -cgTopRhs :: Id -> StgRhs -> SRT -> FCode (Id, CgIdInfo) - -- the Id is passed along for setting up a binding... - -cgTopRhs bndr (StgRhsCon cc con args) srt - = maybeGlobaliseId bndr `thenFC` \ bndr' -> - forkStatics (cgTopRhsCon bndr con args) - -cgTopRhs bndr (StgRhsClosure cc bi fvs upd_flag args body) srt - = -- There should be no free variables - ASSERT(null fvs) - -- If the closure is a thunk, then the binder must be recorded as such. - ASSERT2(not (isUpdatable upd_flag) || mayHaveCafRefs (idCafInfo bndr), ppr bndr) - - getSRTLabel `thenFC` \srt_label -> - let lf_info = - mkClosureLFInfo bndr TopLevel [{-no fvs-}] upd_flag args srt_label srt - in - maybeGlobaliseId bndr `thenFC` \ bndr' -> - forkStatics (cgTopRhsClosure bndr' cc bi args body lf_info) +\begin{code} +maybeExternaliseId :: Id -> FCode Id +maybeExternaliseId id + | opt_EnsureSplittableC, -- Externalise the name for -split-objs + isInternalName name = do { mod <- moduleName + ; returnFC (setIdName id (externalise mod)) } + | otherwise = returnFC id + where + externalise mod = mkExternalName uniq mod new_occ Nothing loc + name = idName id + uniq = nameUnique name + new_occ = mkLocalOcc uniq (nameOccName name) + loc = nameSrcLoc name + -- We want to conjure up a name that can't clash with any + -- existing name. So we generate + -- Mod_$L243foo + -- where 243 is the unique. \end{code}