X-Git-Url: http://git.megacz.com/?a=blobdiff_plain;f=ghc%2Fcompiler%2FcodeGen%2FCodeGen.lhs;h=d7f2f70c43fe16ab400b24cdc7c659f2e16e57a1;hb=423d477bfecd490de1449c59325c8776f91d7aac;hp=f1a0d30e9583bdf2451b8d6fa0ce00f72a89894e;hpb=b4255f2c320f852d7dfb0afc0bc9f64765aece0c;p=ghc-hetmet.git diff --git a/ghc/compiler/codeGen/CodeGen.lhs b/ghc/compiler/codeGen/CodeGen.lhs index f1a0d30..d7f2f70 100644 --- a/ghc/compiler/codeGen/CodeGen.lhs +++ b/ghc/compiler/codeGen/CodeGen.lhs @@ -1,5 +1,5 @@ % -% (c) The GRASP/AQUA Project, Glasgow University, 1992-1996 +% (c) The GRASP/AQUA Project, Glasgow University, 1992-1998 % \section[CodeGen]{@CodeGen@: main module of the code generator} @@ -15,103 +15,252 @@ functions drive the mangling of top-level bindings. %************************************************************************ \begin{code} +module CodeGen ( codeGen ) where + #include "HsVersions.h" -module CodeGen ( codeGen ) where +import DriverState ( v_Build_tag, v_MainModIs ) -import Ubiq{-uitous-} +-- 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 PrelNames ( gHC_PRIM, rOOT_MAIN, mAIN_Name, pREL_TOP_HANDLER ) +import CmdLineOpts ( DynFlags, DynFlag(..), opt_EnsureSplittableC, + opt_SccProfilingOn ) -import AbsCUtils ( mkAbstractCs, mkAbsCStmts ) -import Bag ( foldBag ) -import CgClosure ( cgTopRhsClosure ) -import CgCon ( cgTopRhsCon ) -import CgConTbls ( genStaticConBits ) -import ClosureInfo ( mkClosureLFInfo ) -import CmdLineOpts ( opt_SccProfilingOn, opt_CompilingPrelude, - opt_EnsureSplittableC, opt_SccGroup - ) -import CStrings ( modnameToC ) -import Maybes ( maybeToBool ) -import PrimRep ( getPrimRepSize, PrimRep(..) ) -import Util ( panic, assertPanic ) +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, mkModuleName ) +import ErrUtils ( dumpIfSet_dyn, showPass ) +import Panic ( assertPanic, trace ) +import qualified Module ( moduleName ) + +#ifdef DEBUG +import Outputable +#endif + +import DATA_IOREF ( readIORef ) \end{code} \begin{code} -codeGen :: FAST_STRING -- module name - -> ([CostCentre], -- local cost-centres needing declaring/registering - [CostCentre]) -- "extern" cost-centres needing declaring - -> [Module] -- import names - -> [TyCon] -- tycons with data constructors to convert - -> FiniteMap TyCon [(Bool, [Maybe Type])] - -- tycon specialisation info - -> [StgBinding] -- bindings to convert - -> AbstractC -- output - -codeGen mod_name (local_CCs, extern_CCs) import_names gen_tycons tycon_specs stg_pgm - = let - doing_profiling = opt_SccProfilingOn - compiling_prelude = opt_CompilingPrelude - maybe_split = if maybeToBool (opt_EnsureSplittableC) - then CSplitMarker - else AbsCNop - - cinfo = MkCompInfo mod_name - in - if not doing_profiling then - mkAbstractCs [ - genStaticConBits cinfo gen_tycons tycon_specs, - initC cinfo (cgTopBindings maybe_split stg_pgm) ] - - else -- yes, cost-centre profiling: - -- Besides the usual stuff, we must produce: - -- - -- * Declarations for the cost-centres defined in this module; - -- * Code to participate in "registering" all the cost-centres - -- in the program (done at startup time when the pgm is run). - -- - -- (The local cost-centres involved in this are passed - -- into the code-generator, as are the imported-modules' names.) - -- - -- Note: we don't register/etc if compiling Prelude bits. - - mkAbstractCs [ - if compiling_prelude - then AbsCNop - else mkAbstractCs [mkAbstractCs (map (CCostCentreDecl True) local_CCs), - mkAbstractCs (map (CCostCentreDecl False) extern_CCs), - mkCcRegister local_CCs import_names], - - genStaticConBits cinfo gen_tycons tycon_specs, - initC cinfo (cgTopBindings maybe_split stg_pgm) ] +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 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 + + ; dumpIfSet_dyn dflags Opt_D_dump_cmm "Cmm" (pprCmms code_stuff) + + ; return code_stuff } +\end{code} + +%************************************************************************ +%* * +\subsection[codegen-init]{Module initialisation code} +%* * +%************************************************************************ + +/* ----------------------------------------------------------------------------- + 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 + :: 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 - ----------------- - grp_name = case opt_SccGroup of - Just xx -> xx - Nothing -> mod_name -- default: module name - - ----------------- - mkCcRegister ccs import_names - = let - register_ccs = mkAbstractCs (map mk_register ccs) - register_imports - = foldr (mkAbsCStmts . mk_import_register) AbsCNop import_names - in - mkAbstractCs [ - CCallProfCCMacro SLIT("START_REGISTER_CCS") [CLitLit (modnameToC (SLIT("_reg") _APPEND_ mod_name)) AddrRep], - register_ccs, - register_imports, - CCallProfCCMacro SLIT("END_REGISTER_CCS") [] - ] - where - mk_register cc - = CCallProfCCMacro SLIT("REGISTER_CC") [mkCCostCentre cc] - - mk_import_register import_name - = CCallProfCCMacro SLIT("REGISTER_IMPORT") [CLitLit (modnameToC (SLIT("_reg") _APPEND_ import_name)) AddrRep] + 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; + +(The local cost-centres involved in this are passed into the +code-generator.) + +\begin{code} +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} %************************************************************************ @@ -120,7 +269,7 @@ codeGen mod_name (local_CCs, extern_CCs) import_names gen_tycons tycon_specs stg %* * %************************************************************************ -@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. @@ -131,39 +280,83 @@ style, with the increasing static environment being plumbed as a state variable. \begin{code} -cgTopBindings :: AbstractC -> [StgBinding] -> Code - -cgTopBindings split bindings = mapCs (cgTopBinding split) bindings - -cgTopBinding :: AbstractC -> StgBinding -> Code +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 split (StgNonRec name rhs) - = absC split `thenC` - cgTopRhs name rhs `thenFC` \ (name, info) -> - addBindC name info +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 } -cgTopBinding split (StgRec pairs) - = absC split `thenC` - fixC (\ new_binds -> addBindsC new_binds `thenC` - mapFCs ( \ (b,e) -> cgTopRhs b e ) pairs - ) `thenFC` \ new_binds -> - addBindsC new_binds +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 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 name (StgRhsCon cc con args) - = forkStatics (cgTopRhsCon name con args (all zero_size args)) - where - zero_size atom = getPrimRepSize (getArgPrimRep atom) == 0 +cgTopRhs bndr (StgRhsCon cc con args) + = forkStatics (cgTopRhsCon bndr con args) + +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} -cgTopRhs name (StgRhsClosure cc bi fvs upd_flag args body) - = ASSERT(null fvs) -- There should be no free variables - forkStatics (cgTopRhsClosure name cc bi args body lf_info) + +%************************************************************************ +%* * +\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 - lf_info = mkClosureLFInfo True{-top level-} [{-no fvs-}] upd_flag args body + 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}