[project @ 2004-11-26 16:19:45 by simonmar]
[ghc-hetmet.git] / ghc / compiler / codeGen / CodeGen.lhs
index e7c53c1..056fb1e 100644 (file)
@@ -19,37 +19,38 @@ 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 DriverState     ( v_Build_tag )
-import StgSyn
+import CgProf
 import CgMonad
-import AbsCSyn
-import PrelNames       ( gHC_PRIM )
-import CLabel          ( CLabel, mkSRTLabel, mkClosureLabel, 
-                         mkPlainModuleInitLabel, mkModuleInitLabel )
-
-import PprAbsC         ( dumpRealC )
-import AbsCUtils       ( mkAbstractCs, flattenAbsC )
-import CgBindery       ( CgIdInfo, addBindC, addBindsC, getCAddrModeAndInfo )
+import CgBindery       ( CgIdInfo, addBindC, addBindsC, getCgIdInfo,
+                         cgIdInfoId )
 import CgClosure       ( cgTopRhsClosure )
-import CgCon           ( cgTopRhsCon )
-import CgConTbls       ( genStaticConBits )
-import ClosureInfo     ( mkClosureLFInfo )
-import CmdLineOpts     ( DynFlags, DynFlag(..),
-                         opt_SccProfilingOn, opt_EnsureSplittableC )
+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 Module           ( Module )
-import PrimRep         ( PrimRep(..) )
-import TyCon            ( TyCon, isDataTyCon )
-import BasicTypes      ( TopLevelFlag(..), Version )
-import UniqSupply      ( mkSplitUniqSupply )
+import TyCon            ( isDataTyCon )
+import Module          ( Module, mkModule )
 import ErrUtils                ( dumpIfSet_dyn, showPass )
 import Panic           ( assertPanic )
 
@@ -57,48 +58,48 @@ import Panic                ( assertPanic )
 import Outputable
 #endif
 
-import IOExts          ( readIORef )
+import DATA_IOREF      ( readIORef )
 \end{code}
 
 \begin{code}
 codeGen :: DynFlags
-       -> Module               -- Module name
-       -> Version              -- Module version
-       -> [(Module,Version)]   -- Import names & versions
+       -> Module
+       -> TypeEnv
+       -> ForeignStubs
+       -> [Module]             -- directly-imported modules
        -> CollectedCCs         -- (Local/global) cost-centres needing declaring/registering.
-       -> [Id]                 -- foreign-exported binders
-       -> [TyCon]              -- Local tycons, including ones from classes
-       -> [(StgBinding,[Id])]  -- Bindings to convert, with SRTs
-       -> IO AbstractC         -- Output
+       -> [(StgBinding,[(Id,[Id])])]   -- Bindings to convert, with SRTs
+       -> IO [Cmm]             -- Output
 
-codeGen dflags mod_name mod_ver imported_modules cost_centre_info fe_binders
-       tycons stg_binds
+codeGen dflags this_mod type_env foreign_stubs imported_mods 
+       cost_centre_info stg_binds
   = do 
-       showPass dflags "CodeGen"
-       fl_uniqs <- mkSplitUniqSupply 'f'
-       way <- readIORef v_Build_tag
-
-       let
-           data_tycons    = filter isDataTyCon tycons
-           cinfo          = MkCompInfo mod_name
-
-           datatype_stuff = genStaticConBits cinfo data_tycons
-           code_stuff     = initC cinfo (mapCs cgTopBinding stg_binds)
-           init_stuff     = mkModuleInit fe_binders mod_name mod_ver way
-                               imported_modules cost_centre_info
-
-           abstractC = mkAbstractCs [ maybeSplitCode,
-                                      init_stuff, 
-                                      code_stuff,
-                                      datatype_stuff]
+  { 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
 
-       dumpIfSet_dyn dflags Opt_D_dump_absC "Abstract C" (dumpRealC abstractC)
+  ; dumpIfSet_dyn dflags Opt_D_dump_cmm "Cmm" (pprCmms code_stuff)
 
-       return $! flattenAbsC fl_uniqs abstractC
+  ; return code_stuff }
 \end{code}
 
 %************************************************************************
@@ -107,44 +108,143 @@ codeGen dflags mod_name mod_ver 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
-       -> Version              -- module version
+       :: DynFlags
        -> String               -- the "way"
-       -> [(Module,Version)]   -- import names & versions
        -> CollectedCCs         -- cost centre info
-       -> AbstractC
-mkModuleInit fe_binders mod ver way 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
-
-       -- we don't want/need to init GHC.Prim, so filter it out
-       mk_import_register (imp,ver)
-           | imp == gHC_PRIM = AbsCNop
-           | otherwise = CMacroStmt REGISTER_IMPORT [
-                               CLbl (mkModuleInitLabel imp ver way) AddrRep
-                         ]
-
-       register_imports = map mk_import_register imps
-    in
-    mkAbstractCs [
-       cc_decls,
-        CModuleInitBlock (mkPlainModuleInitLabel mod)
-                        (mkModuleInitLabel mod ver way)
-                        (mkAbstractCs (register_fes ++
-                                       cc_regs :
-                                       register_imports))
-    ]
+       -> 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;
 
@@ -152,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 FSLIT("REGISTER_CC") [mkCCostCentre cc]
-
-       mk_register_ccs ccs
-         = CCallProfCCMacro FSLIT("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}
 
 %************************************************************************
@@ -193,68 +281,55 @@ 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`
-    maybeExternaliseId 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   -- Add the un-externalised Id to the envt, so we
-                       -- find it when we look up occurrences
-    )
-
-cgTopBinding (StgRec srt_info pairs, srt)
-  = absC maybeSplitCode                        `thenC`
-    let
-        (bndrs, rhss) = unzip pairs
-    in
-    mapFCs maybeExternaliseId 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 :: 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
-       -- sigh, better map all the ids against the environment in case they've
-       -- been externalised (see maybeExternaliseId 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!
 
-cgTopRhs :: Id -> StgRhs -> SRT -> FCode (Id, CgIdInfo)
+cgTopRhs :: Id -> StgRhs -> FCode (Id, CgIdInfo)
        -- The Id is passed along for setting up a binding...
        -- It's already been externalised if necessary
 
-cgTopRhs bndr (StgRhsCon cc con args) srt
-  = forkStatics (cgTopRhsCon bndr con args srt)
+cgTopRhs bndr (StgRhsCon cc con args)
+  = forkStatics (cgTopRhsCon bndr con args)
 
-cgTopRhs bndr (StgRhsClosure cc bi fvs upd_flag args body) srt
+cgTopRhs bndr (StgRhsClosure cc bi fvs upd_flag srt args body)
   = ASSERT(null fvs)    -- There should be no free variables
-    let 
-       lf_info = mkClosureLFInfo bndr TopLevel [{-no fvs-}] upd_flag args
-    in
-    forkStatics (cgTopRhsClosure bndr cc bi srt args body lf_info)
+    setSRTLabel (mkSRTLabel (idName bndr)) $ 
+    forkStatics (cgTopRhsClosure bndr cc bi srt upd_flag args body)
 \end{code}
 
 
@@ -272,21 +347,17 @@ which refers to this name).
 maybeExternaliseId :: Id -> FCode Id
 maybeExternaliseId id
   | opt_EnsureSplittableC,     -- Externalise the name for -split-objs
-    isInternalName name
-  = moduleName                          `thenFC` \ mod ->
-    returnFC (setIdName id (mkExternalName uniq mod new_occ (nameSrcLoc name)))
-  | otherwise          
-  = returnFC id
+    isInternalName name = do { mod <- moduleName
+                            ; returnFC (setIdName id (externalise mod)) }
+  | otherwise          = returnFC id
   where
-    name       = idName id
-    uniq       = nameUnique name
-    new_occ    = mkLocalOcc uniq (nameOccName name)
+    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.
-
-maybeSplitCode
-  | opt_EnsureSplittableC = CSplitMarker 
-  | otherwise             = AbsCNop
 \end{code}