[project @ 2003-06-23 10:35:15 by simonpj]
[ghc-hetmet.git] / ghc / compiler / codeGen / CodeGen.lhs
index 95926aa..fd5ef9d 100644 (file)
@@ -19,122 +19,189 @@ module CodeGen ( codeGen ) where
 
 #include "HsVersions.h"
 
 
 #include "HsVersions.h"
 
+-- 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, v_MainModIs )
 import StgSyn
 import CgMonad
 import AbsCSyn
 import StgSyn
 import CgMonad
 import AbsCSyn
-import CLabel          ( CLabel, mkSRTLabel, mkClosureLabel )
-
+import PrelNames       ( gHC_PRIM, dOLLAR_MAIN, mAIN_Name )
+import CLabel          ( mkSRTLabel, mkClosureLabel, 
+                         mkPlainModuleInitLabel, mkModuleInitLabel )
 import PprAbsC         ( dumpRealC )
 import PprAbsC         ( dumpRealC )
-import AbsCUtils       ( mkAbstractCs, mkAbsCStmts, flattenAbsC )
-import CgBindery       ( CgIdInfo, addBindC, addBindsC )
+import AbsCUtils       ( mkAbstractCs, flattenAbsC )
+import CgBindery       ( CgIdInfo, addBindC, addBindsC, getCAddrModeAndInfo )
 import CgClosure       ( cgTopRhsClosure )
 import CgCon           ( cgTopRhsCon )
 import CgConTbls       ( genStaticConBits )
 import ClosureInfo     ( mkClosureLFInfo )
 import CgClosure       ( cgTopRhsClosure )
 import CgCon           ( cgTopRhsCon )
 import CgConTbls       ( genStaticConBits )
 import ClosureInfo     ( mkClosureLFInfo )
-import CmdLineOpts     ( opt_SccProfilingOn, opt_EnsureSplittableC, 
-                         opt_D_dump_absC,    opt_SccGroup
-                       )
-import CostCentre       ( CostCentre, CostCentreStack )
-import FiniteMap       ( FiniteMap )
-import Id               ( Id, idName )
-import Module           ( Module, moduleString, ModuleName, moduleNameString )
-import PrimRep         ( getPrimRepSize, PrimRep(..) )
-import Type             ( Type )
-import TyCon            ( TyCon, isDataTyCon )
-import Class           ( Class, classTyCon )
+import CmdLineOpts     ( DynFlags, DynFlag(..),
+                         opt_SccProfilingOn, opt_EnsureSplittableC )
+import HscTypes                ( ForeignStubs(..), TypeEnv, typeEnvTyCons )
+import CostCentre       ( CollectedCCs )
+import Id               ( Id, idName, setIdName )
+import Name            ( nameSrcLoc, nameOccName, nameUnique, isInternalName, mkExternalName )
+import OccName         ( mkLocalOcc )
+import PrimRep         ( PrimRep(..) )
+import TyCon            ( isDataTyCon )
+import Module          ( Module, mkModuleName )
 import BasicTypes      ( TopLevelFlag(..) )
 import UniqSupply      ( mkSplitUniqSupply )
 import BasicTypes      ( TopLevelFlag(..) )
 import UniqSupply      ( mkSplitUniqSupply )
-import ErrUtils                ( dumpIfSet )
-import Util
+import ErrUtils                ( dumpIfSet_dyn, showPass )
 import Panic           ( assertPanic )
 import Panic           ( assertPanic )
+import qualified Module ( moduleName )
+
+#ifdef DEBUG
+import Outputable
+#endif
+
+import DATA_IOREF      ( readIORef )
 \end{code}
 
 \begin{code}
 \end{code}
 
 \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 AbstractC         -- Output
 
 
+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
+       mb_main_mod <- readIORef v_MainModIs
 
 
-codeGen :: Module              -- Module name
-       -> [ModuleName]         -- Import names
-       -> ([CostCentre],       -- Local cost-centres needing declaring/registering
-           [CostCentre],       -- "extern" cost-centres needing declaring
-           [CostCentreStack])  -- Pre-defined "singleton" cost centre stacks
-       -> [TyCon] -> [Class]   -- Local tycons and classes
-       -> [(StgBinding,[Id])]  -- Bindings to convert, with SRTs
-       -> IO AbstractC         -- Output
+       let
+           tycons         = typeEnvTyCons type_env
+           data_tycons    = filter isDataTyCon tycons
 
 
-codeGen mod_name imported_modules cost_centre_info
-       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)
-       cost_centre_stuff = mkCostCentreStuff mod_name imported_modules cost_centre_info
+       mapM_ (\x -> seq x (return ())) data_tycons
 
 
-       abstractC = mkAbstractCs [ cost_centre_stuff, 
-                                  datatype_stuff,
-                                  code_stuff ]
+       let
 
 
-       flat_abstractC = flattenAbsC fl_uniqs abstractC
-    in
-    dumpIfSet opt_D_dump_absC "Abstract C" (dumpRealC abstractC)       >>
-    return flat_abstractC
+           cinfo          = MkCompInfo this_mod
 
 
-  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
-\end{code}
+           datatype_stuff = genStaticConBits cinfo data_tycons
+           code_stuff     = initC cinfo (mapCs cgTopBinding stg_binds)
+           init_stuff     = mkModuleInit way cost_centre_info 
+                                         this_mod mb_main_mod
+                                         foreign_stubs imported_mods
+
+           abstractC = mkAbstractCs [ maybeSplitCode,
+                                      init_stuff, 
+                                      code_stuff,
+                                      datatype_stuff]
+               -- 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
 
 
-Cost-centre profiling:
-Besides the usual stuff, we must produce:
+       dumpIfSet_dyn dflags Opt_D_dump_absC "Abstract C" (dumpRealC abstractC)
 
 
-* 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).
+       return $! flattenAbsC fl_uniqs abstractC
+\end{code}
 
 
-(The local cost-centres involved in this are passed
-into the code-generator, as are the imported-modules' names.)
+%************************************************************************
+%*                                                                     *
+\subsection[codegen-init]{Module initialisation code}
+%*                                                                     *
+%************************************************************************
 
 \begin{code}
 
 \begin{code}
-mkCostCentreStuff mod_name import_names (local_CCs, extern_CCs, singleton_CCSs)
-  | not opt_SccProfilingOn = AbsCNop
-  | otherwise = mkAbstractCs (
-                   map (CCostCentreDecl True)   local_CCs ++
-                   map (CCostCentreDecl False)  extern_CCs ++
-                   map CCostCentreStackDecl     singleton_CCSs ++
-                   mkCcRegister local_CCs singleton_CCSs import_names
-               )
+mkModuleInit 
+       :: String               -- the "way"
+       -> CollectedCCs         -- cost centre info
+       -> Module
+       -> Maybe String         -- Just m ==> we have flag: -main-is Foo.baz 
+       -> ForeignStubs
+       -> [Module]
+       -> AbstractC
+mkModuleInit way cost_centre_info this_mod mb_main_mod foreign_stubs imported_mods
+  = let
+       (cc_decls, cc_regs) = mkCostCentreStuff cost_centre_info
+
+       register_foreign_exports 
+               = case foreign_stubs of
+                       NoStubs                     -> []
+                       ForeignStubs _ _ _ fe_bndrs -> map mk_export_register fe_bndrs
+
+       mk_export_register bndr
+         = CMacroStmt REGISTER_FOREIGN_EXPORT [lbl]
+         where
+           lbl = CLbl (mkClosureLabel (idName bndr)) PtrRep
+               -- we don't want/need to init GHC.Prim, so filter it out
+
+       mk_import_register mod
+           | mod == gHC_PRIM = AbsCNop
+           | otherwise       = CMacroStmt REGISTER_IMPORT [
+                                  CLbl (mkModuleInitLabel mod way) AddrRep
+                               ]
+
+       register_mod_imports = map mk_import_register imported_mods
+
+       -- When compiling the module in which the 'main' function lives,
+       -- we inject an extra stg_init procedure for stg_init_zdMain, for the 
+       -- RTS to invoke.  We must consult the -main-is flag in case the
+       -- user specified a different function to Main.main
+       main_mod_name = case mb_main_mod of
+                         Just mod_name -> mkModuleName mod_name
+                         Nothing       -> mAIN_Name
+       main_init_block
+         | Module.moduleName this_mod /= main_mod_name 
+         = AbsCNop     -- The normal case
+         | otherwise   -- this_mod contains the main function
+         = CModuleInitBlock (mkPlainModuleInitLabel dOLLAR_MAIN)
+                            (mkModuleInitLabel dOLLAR_MAIN way)
+                            (mk_import_register this_mod)
+    in
+    mkAbstractCs [
+       cc_decls,
+        CModuleInitBlock (mkPlainModuleInitLabel this_mod)
+                        (mkModuleInitLabel this_mod way)
+                        (mkAbstractCs (register_foreign_exports ++
+                                       cc_regs :
+                                       register_mod_imports)),
+       main_init_block
+    ]
+\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}
+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
   where
-    mkCcRegister ccs cc_stacks import_names
+    mkCcRegister ccs cc_stacks
       = let
       = let
-           register_ccs     = mkAbstractCs (map mk_register ccs)
-           register_imports
-             = foldr (mkAbsCStmts . mk_import_register) AbsCNop import_names
+           register_ccs       = mkAbstractCs (map mk_register ccs)
            register_cc_stacks = mkAbstractCs (map mk_register_ccs cc_stacks)
        in
            register_cc_stacks = mkAbstractCs (map mk_register_ccs cc_stacks)
        in
-       [
-           CCallProfCCMacro SLIT("START_REGISTER_CCS") 
-              [ CLitLit (_PK_ ("_reg" ++ moduleString mod_name)) AddrRep],
-           register_ccs,
-           register_cc_stacks,
-           register_imports,
-           CCallProfCCMacro SLIT("END_REGISTER_CCS") []
-       ]
+       [ register_ccs, register_cc_stacks ]
       where
        mk_register cc
       where
        mk_register cc
-         = CCallProfCCMacro SLIT("REGISTER_CC") [mkCCostCentre cc]
+         = CCallProfCCMacro FSLIT("REGISTER_CC") [mkCCostCentre cc]
 
        mk_register_ccs ccs
 
        mk_register_ccs ccs
-         = CCallProfCCMacro SLIT("REGISTER_CCS") [mkCCostCentreStack ccs]
-
-       mk_import_register import_name
-         = CCallProfCCMacro SLIT("REGISTER_IMPORT") 
-             [CLitLit (_PK_ ("_reg" ++ moduleNameString import_name)) AddrRep]
+         = CCallProfCCMacro FSLIT("REGISTER_CCS") [mkCCostCentreStack ccs]
 \end{code}
 
 %************************************************************************
 \end{code}
 
 %************************************************************************
@@ -143,7 +210,7 @@ mkCostCentreStuff mod_name import_names (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.
 
 to be allocated statically (not in the heap) and need to be labelled.
 No unboxed bindings can happen at top level.
 
@@ -154,55 +221,98 @@ style, with the increasing static environment being plumbed as a state
 variable.
 
 \begin{code}
 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 :: (StgBinding,[(Id,[Id])]) -> Code
+cgTopBinding (StgNonRec id rhs, srts)
+  = absC maybeSplitCode                `thenC`
+    maybeExternaliseId id      `thenFC` \ id' ->
+    mapM_ (mkSRT [id']) srts   `thenC`
+    cgTopRhs id' rhs           `thenFC` \ (id, info) ->
+    addBindC id info           `thenC`
+       -- Add the un-externalised Id to the envt, so we
+       -- find it when we look up occurrences
+    nopC
+
+cgTopBinding (StgRec pairs, srts)
+  = absC maybeSplitCode                        `thenC`
+    let
+        (bndrs, rhss) = unzip pairs
+    in
+    mapFCs maybeExternaliseId bndrs    `thenFC` \ bndrs' ->
+    let
+       pairs' = zip bndrs' rhss
+    in
+    mapM_ (mkSRT bndrs')  srts         `thenC`
+    fixC (\ new_binds -> 
+               addBindsC new_binds             `thenC`
+               mapFCs ( \ (b,e) -> cgTopRhs b e ) pairs'
+     )  `thenFC` \ new_binds -> 
+     nopC
+
+mkSRT :: [Id] -> (Id,[Id]) -> Code
+mkSRT these (id,[])  = nopC
+mkSRT these (id,ids)
+  = mapFCs remap ids `thenFC` \ ids ->
+    remap id        `thenFC` \ id ->
+    absC (CSRT (mkSRTLabel (idName id)) (map (mkClosureLabel . idName) ids))
   where
   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
+               [] ->  getCAddrModeAndInfo id 
+                               `thenFC` \ (id, _, _) -> returnFC id
+               (id':_) -> returnFC id'
 
 -- 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)
 
 -- 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)
 
 cgTopRhs bndr (StgRhsCon cc con args)
-  = forkStatics (cgTopRhsCon bndr con args (all zero_size args))
-  where
-    zero_size atom = getPrimRepSize (getArgPrimRep atom) == 0
+  = 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
+cgTopRhs bndr (StgRhsClosure cc bi fvs upd_flag srt args body)
+  = ASSERT(null fvs)    -- There should be no free variables
+    let 
+       srt_label = mkSRTLabel (idName bndr)
+       lf_info = mkClosureLFInfo bndr TopLevel [{-no fvs-}] upd_flag args
     in
     in
-    forkStatics (cgTopRhsClosure bndr cc bi args body lf_info)
+    setSRTLabel srt_label $ 
+      forkStatics (cgTopRhsClosure bndr cc bi srt args body lf_info)
+\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
+  = moduleName                          `thenFC` \ mod ->
+    returnFC (setIdName id (mkExternalName uniq mod new_occ (nameSrcLoc name)))
+  | otherwise          
+  = returnFC id
+  where
+    name       = idName id
+    uniq       = nameUnique name
+    new_occ    = mkLocalOcc uniq (nameOccName 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}
 \end{code}