X-Git-Url: http://git.megacz.com/?a=blobdiff_plain;f=ghc%2Fcompiler%2FcodeGen%2FCodeGen.lhs;h=056fb1ef5060b9fd6e9946b1ac5e1ffe06521295;hb=ef5b4b146aa172d8ac10f39b5eb3d7a0f948d8f1;hp=0cbb76ff72add201a29bd461600e7f2b208a56d3;hpb=567b2505b2d3d5874f3bf3641fd8d82b3207ea94;p=ghc-hetmet.git diff --git a/ghc/compiler/codeGen/CodeGen.lhs b/ghc/compiler/codeGen/CodeGen.lhs index 0cbb76f..056fb1e 100644 --- a/ghc/compiler/codeGen/CodeGen.lhs +++ b/ghc/compiler/codeGen/CodeGen.lhs @@ -19,81 +19,87 @@ module CodeGen ( codeGen ) where #include "HsVersions.h" -import StgSyn -import CgMonad -import AbsCSyn -import CLabel ( CLabel, mkSRTLabel, mkClosureLabel, - mkModuleInitLabel, labelDynamic ) +import DriverState ( v_Build_tag, v_MainModIs ) -import PprAbsC ( dumpRealC ) -import AbsCUtils ( mkAbstractCs, flattenAbsC ) -import CgBindery ( CgIdInfo, addBindC, addBindsC ) +-- 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 ) -import CgConTbls ( genStaticConBits ) -import ClosureInfo ( mkClosureLFInfo ) -import CmdLineOpts ( opt_SccProfilingOn, opt_EnsureSplittableC, - opt_D_dump_absC - ) -import CostCentre ( CostCentre, CostCentreStack ) -import Id ( Id, idName ) -import Module ( Module, moduleString, moduleName, - ModuleName ) -import PrimRep ( getPrimRepSize, PrimRep(..) ) -import Type ( Type ) -import TyCon ( TyCon, isDataTyCon ) -import Class ( Class, classTyCon ) -import BasicTypes ( TopLevelFlag(..) ) -import UniqSupply ( mkSplitUniqSupply ) -import ErrUtils ( dumpIfSet ) -import Util +import CgCon ( cgTopRhsCon, cgTyCon ) +import CgUtils ( cmmRegOffW, emitRODataLits, cmmNeWord, emitRtsCall ) + +import CLabel +import Cmm +import CmmUtils ( zeroCLit, mkIntCLit, mkLblExpr ) +import PprCmm ( pprCmms ) +import MachOp ( wordRep, MachHint(..) ) + +import StgSyn +import PrelNames ( gHC_PRIM, rOOT_MAIN, mAIN, pREL_TOP_HANDLER ) +import CmdLineOpts ( DynFlags, DynFlag(..), opt_EnsureSplittableC, + opt_SccProfilingOn ) + +import HscTypes ( ForeignStubs(..), TypeEnv, typeEnvTyCons ) +import CostCentre ( CollectedCCs ) +import Id ( Id, idName, setIdName ) +import Name ( nameSrcLoc, nameOccName, nameUnique, isInternalName, mkExternalName ) +import OccName ( mkLocalOcc ) +import TyCon ( isDataTyCon ) +import Module ( Module, mkModule ) +import ErrUtils ( dumpIfSet_dyn, showPass ) import Panic ( assertPanic ) -\end{code} -\begin{code} +#ifdef DEBUG +import Outputable +#endif +import DATA_IOREF ( readIORef ) +\end{code} -codeGen :: 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] -> [Class] -- Local tycons and classes - -> [(StgBinding,[Id])] -- Bindings to convert, with SRTs - -> IO AbstractC -- Output - -codeGen mod_name imported_modules cost_centre_info fe_binders - tycons classes stg_binds - = mkSplitUniqSupply 'f' >>= \ fl_uniqs -> -- absC flattener - let - datatype_stuff = genStaticConBits cinfo data_tycons - code_stuff = initC cinfo (cgTopBindings maybe_split stg_binds) - init_stuff = mkModuleInit fe_binders mod_name imported_modules - cost_centre_info - - abstractC = mkAbstractCs [ maybe_split, - init_stuff, - code_stuff, - datatype_stuff] +\begin{code} +codeGen :: DynFlags + -> 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 dflags this_mod $ do + { cmm_binds <- mapM (getCmm . cgTopBinding dflags) stg_binds + ; cmm_tycons <- mapM cgTyCon data_tycons + ; cmm_init <- getCmm (mkModuleInit dflags 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 + -- datatype closure table (for enumeration types) to + -- (say) PrelBase_True_closure, which is defined in + -- code_stuff - flat_abstractC = flattenAbsC fl_uniqs abstractC - in - dumpIfSet opt_D_dump_absC "Abstract C" (dumpRealC abstractC) >> - return flat_abstractC + ; dumpIfSet_dyn dflags Opt_D_dump_cmm "Cmm" (pprCmms code_stuff) - where - data_tycons = filter isDataTyCon (tycons ++ map classTyCon classes) - -- Generate info tables for the data constrs arising - -- from class decls as well - - maybe_split = if opt_EnsureSplittableC - then CSplitMarker - else AbsCNop - cinfo = MkCompInfo mod_name + ; return code_stuff } \end{code} %************************************************************************ @@ -102,41 +108,143 @@ codeGen 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)) - ] + :: DynFlags + -> String -- the "way" + -> CollectedCCs -- cost centre info + -> Module + -> Maybe String -- Just m ==> we have flag: -main-is Foo.baz + -> ForeignStubs + -> [Module] + -> Code +mkModuleInit dflags 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, this_mod == main_mod) + -- 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 (this_mod == main_mod) + (emitSimpleProc plain_main_init_lbl jump_to_init) + } + where + plain_init_lbl = mkPlainModuleInitLabel dflags this_mod + real_init_lbl = mkModuleInitLabel dflags this_mod way + plain_main_init_lbl = mkPlainModuleInitLabel dflags rOOT_MAIN + + jump_to_init = stmtC (CmmJump (mkLblExpr real_init_lbl) []) + + mod_reg_val = CmmLoad (mkLblExpr moduleRegdLabel) wordRep + + main_mod = case mb_main_mod of + Just mod_name -> mkModule mod_name + Nothing -> mAIN + + -- Main refers to GHC.TopHandler.runIO, so make sure we call the + -- init function for GHC.TopHandler. + extra_imported_mods + | this_mod == main_mod = [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 dflags way) + (imported_mods++extra_imported_mods) + } + + +----------------------- +registerModuleImport :: DynFlags -> String -> Module -> Code +registerModuleImport dflags 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 dflags 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 (mkLocalClosureLabel (idName bndr))), + PtrHint) ] \end{code} + + Cost-centre profiling: Besides the usual stuff, we must produce declarations for the cost-centres defined in this module; @@ -144,28 +252,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} %************************************************************************ @@ -174,7 +270,7 @@ mkCostCentreStuff (local_CCs, extern_CCs, singleton_CCSs) %* * %************************************************************************ -@cgTopBindings@ is only used for top-level bindings, since they need +@cgTopBinding@ is only used for top-level bindings, since they need to be allocated statically (not in the heap) and need to be labelled. No unboxed bindings can happen at top level. @@ -185,53 +281,83 @@ style, with the increasing static environment being plumbed as a state variable. \begin{code} -cgTopBindings :: AbstractC -> [(StgBinding,[Id])] -> Code - -cgTopBindings split bindings = mapCs (cgTopBinding split) bindings - -cgTopBinding :: AbstractC -> (StgBinding,[Id]) -> Code - -cgTopBinding split ((StgNonRec name rhs), srt) - = absC split `thenC` - absC (mkSRT srt_label srt) `thenC` - setSRTLabel srt_label ( - cgTopRhs name rhs `thenFC` \ (name, info) -> - addBindC name info - ) - where - srt_label = mkSRTLabel (idName name) - -cgTopBinding split ((StgRec pairs@((name,rhs):_)), srt) - = absC split `thenC` - absC (mkSRT srt_label srt) `thenC` - setSRTLabel srt_label ( - fixC (\ new_binds -> addBindsC new_binds `thenC` - mapFCs ( \ (b,e) -> cgTopRhs b e ) pairs - ) `thenFC` \ new_binds -> - addBindsC new_binds - ) +cgTopBinding :: DynFlags -> (StgBinding,[(Id,[Id])]) -> Code +cgTopBinding dflags (StgNonRec id rhs, srts) + = do { id' <- maybeExternaliseId id + ; mapM_ (mkSRT dflags [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 dflags (StgRec pairs, srts) + = do { let (bndrs, rhss) = unzip pairs + ; bndrs' <- mapFCs maybeExternaliseId bndrs + ; let pairs' = zip bndrs' rhss + ; mapM_ (mkSRT dflags bndrs') srts + ; new_binds <- fixC (\ new_binds -> do + { addBindsC new_binds + ; mapFCs ( \ (b,e) -> cgTopRhs b e ) pairs' }) + ; nopC } + +mkSRT :: DynFlags -> [Id] -> (Id,[Id]) -> Code +mkSRT dflags these (id,[]) = nopC +mkSRT dflags these (id,ids) + = do { ids <- mapFCs remap ids + ; id <- remap id + ; emitRODataLits (mkSRTLabel (idName id)) + (map (CmmLabel . mkClosureLabel dflags . idName) ids) + } where - srt_label = mkSRTLabel (idName name) - -mkSRT :: CLabel -> [Id] -> AbstractC -mkSRT lbl [] = AbsCNop -mkSRT lbl ids = CSRT lbl (map (mkClosureLabel . idName) ids) + -- 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 + (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! cgTopRhs :: Id -> StgRhs -> FCode (Id, CgIdInfo) - -- the Id is passed along for setting up a binding... + -- The Id is passed along for setting up a binding... + -- It's already been externalised if necessary cgTopRhs bndr (StgRhsCon cc con args) = forkStatics (cgTopRhsCon bndr con args) -cgTopRhs bndr (StgRhsClosure cc bi srt fvs upd_flag args body) - = ASSERT(null fvs) -- There should be no free variables - getSRTLabel `thenFC` \srt_label -> - let lf_info = - mkClosureLFInfo bndr TopLevel [{-no fvs-}] upd_flag args srt_label srt - in - forkStatics (cgTopRhsClosure bndr cc bi args body lf_info) +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} + + +%************************************************************************ +%* * +\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). + +\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}