summaryrefslogtreecommitdiff
path: root/ghc/compiler/codeGen/CgBindery.lhs
diff options
context:
space:
mode:
Diffstat (limited to 'ghc/compiler/codeGen/CgBindery.lhs')
-rw-r--r--ghc/compiler/codeGen/CgBindery.lhs416
1 files changed, 416 insertions, 0 deletions
diff --git a/ghc/compiler/codeGen/CgBindery.lhs b/ghc/compiler/codeGen/CgBindery.lhs
new file mode 100644
index 0000000000..fbc2fc9e21
--- /dev/null
+++ b/ghc/compiler/codeGen/CgBindery.lhs
@@ -0,0 +1,416 @@
+%
+% (c) The GRASP/AQUA Project, Glasgow University, 1992-1995
+%
+\section[CgBindery]{Utility functions related to doing @CgBindings@}
+
+\begin{code}
+#include "HsVersions.h"
+
+module CgBindery (
+ CgBindings(..), CgIdInfo(..){-dubiously concrete-},
+ StableLoc, VolatileLoc, LambdaFormInfo{-re-exported-},
+
+ maybeAStkLoc, maybeBStkLoc,
+
+ stableAmodeIdInfo, heapIdInfo, newTempAmodeAndIdInfo,
+ letNoEscapeIdInfo, idInfoToAmode,
+
+ nukeVolatileBinds,
+
+ bindNewToAStack, bindNewToBStack,
+ bindNewToNode, bindNewToReg, bindArgsToRegs,
+--UNUSED: bindNewToSameAsOther,
+ bindNewToTemp, bindNewPrimToAmode,
+ getAtomAmode, getAtomAmodes,
+ getCAddrModeAndInfo, getCAddrMode,
+ getCAddrModeIfVolatile, getVolatileRegs,
+ rebindToAStack, rebindToBStack,
+--UNUSED: rebindToTemp,
+
+ -- and to make a self-sufficient interface...
+ AbstractC, CAddrMode, HeapOffset, MagicId, CLabel, CgState,
+ BasicLit, IdEnv(..), UniqFM,
+ Id, Maybe, Unique, StgAtom, UniqSet(..)
+ ) where
+
+IMPORT_Trace -- ToDo: rm (debugging only)
+import Outputable
+import Unpretty
+import PprAbsC
+
+import AbsCSyn
+import CgMonad
+
+import CgUsages ( getHpRelOffset, getSpARelOffset, getSpBRelOffset )
+import CLabelInfo ( mkClosureLabel, CLabel )
+import ClosureInfo
+import Id ( getIdKind, toplevelishId, isDataCon, Id )
+import IdEnv -- used to build CgBindings
+import Maybes ( catMaybes, Maybe(..) )
+import UniqSet -- ( setToList )
+import StgSyn
+import Util
+\end{code}
+
+
+%************************************************************************
+%* *
+\subsection[Bindery-datatypes]{Data types}
+%* *
+%************************************************************************
+
+@(CgBinding a b)@ is a type of finite maps from a to b.
+
+The assumption used to be that @lookupCgBind@ must get exactly one
+match. This is {\em completely wrong} in the case of compiling
+letrecs (where knot-tying is used). An initial binding is fed in (and
+never evaluated); eventually, a correct binding is put into the
+environment. So there can be two bindings for a given name.
+
+\begin{code}
+type CgBindings = IdEnv CgIdInfo
+
+data CgIdInfo
+ = MkCgIdInfo Id -- Id that this is the info for
+ VolatileLoc
+ StableLoc
+ LambdaFormInfo
+
+data VolatileLoc
+ = NoVolatileLoc
+ | TempVarLoc Unique
+
+ | RegLoc MagicId -- in one of the magic registers
+ -- (probably {Int,Float,Char,etc}Reg
+
+ | VirHpLoc VirtualHeapOffset -- Hp+offset (address of closure)
+
+ | VirNodeLoc VirtualHeapOffset -- Cts of offset indirect from Node
+ -- ie *(Node+offset)
+
+data StableLoc
+ = NoStableLoc
+ | VirAStkLoc VirtualSpAOffset
+ | VirBStkLoc VirtualSpBOffset
+ | LitLoc BasicLit
+ | StableAmodeLoc CAddrMode
+
+-- these are so StableLoc can be abstract:
+
+maybeAStkLoc (VirAStkLoc offset) = Just offset
+maybeAStkLoc _ = Nothing
+
+maybeBStkLoc (VirBStkLoc offset) = Just offset
+maybeBStkLoc _ = Nothing
+\end{code}
+
+%************************************************************************
+%* *
+\subsection[Bindery-idInfo]{Manipulating IdInfo}
+%* *
+%************************************************************************
+
+\begin{code}
+stableAmodeIdInfo i amode lf_info = MkCgIdInfo i NoVolatileLoc (StableAmodeLoc amode) lf_info
+heapIdInfo i offset lf_info = MkCgIdInfo i (VirHpLoc offset) NoStableLoc lf_info
+tempIdInfo i uniq lf_info = MkCgIdInfo i (TempVarLoc uniq) NoStableLoc lf_info
+
+letNoEscapeIdInfo i spa spb lf_info
+ = MkCgIdInfo i NoVolatileLoc (StableAmodeLoc (CJoinPoint spa spb)) lf_info
+
+newTempAmodeAndIdInfo :: Id -> LambdaFormInfo -> (CAddrMode, CgIdInfo)
+
+newTempAmodeAndIdInfo name lf_info
+ = (temp_amode, temp_idinfo)
+ where
+ uniq = getTheUnique name
+ temp_amode = CTemp uniq (getIdKind name)
+ temp_idinfo = tempIdInfo name uniq lf_info
+
+idInfoToAmode :: PrimKind -> CgIdInfo -> FCode CAddrMode
+idInfoToAmode kind (MkCgIdInfo _ vol stab _) = idInfoPiecesToAmode kind vol stab
+
+idInfoPiecesToAmode :: PrimKind -> VolatileLoc -> StableLoc -> FCode CAddrMode
+
+idInfoPiecesToAmode kind (TempVarLoc uniq) stable_loc = returnFC (CTemp uniq kind)
+idInfoPiecesToAmode kind (RegLoc magic_id) stable_loc = returnFC (CReg magic_id)
+
+idInfoPiecesToAmode kind NoVolatileLoc (LitLoc lit) = returnFC (CLit lit)
+idInfoPiecesToAmode kind NoVolatileLoc (StableAmodeLoc amode) = returnFC amode
+
+idInfoPiecesToAmode kind (VirNodeLoc nd_off) stable_loc
+ = returnFC (CVal (NodeRel nd_off) kind)
+ -- Virtual offsets from Node increase into the closures,
+ -- and so do Node-relative offsets (which we want in the CVal),
+ -- so there is no mucking about to do to the offset.
+
+idInfoPiecesToAmode kind (VirHpLoc hp_off) stable_loc
+ = getHpRelOffset hp_off `thenFC` \ rel_hp ->
+ returnFC (CAddr rel_hp)
+
+idInfoPiecesToAmode kind NoVolatileLoc (VirAStkLoc i)
+ = getSpARelOffset i `thenFC` \ rel_spA ->
+ returnFC (CVal rel_spA kind)
+
+idInfoPiecesToAmode kind NoVolatileLoc (VirBStkLoc i)
+ = getSpBRelOffset i `thenFC` \ rel_spB ->
+ returnFC (CVal rel_spB kind)
+
+idInfoPiecesToAmode kind NoVolatileLoc NoStableLoc = panic "idInfoPiecesToAmode: no loc"
+\end{code}
+
+%************************************************************************
+%* *
+\subsection[Bindery-nuke-volatile]{Nuking volatile bindings}
+%* *
+%************************************************************************
+
+We sometimes want to nuke all the volatile bindings; we must be sure
+we don't leave any (NoVolatile, NoStable) binds around...
+
+\begin{code}
+nukeVolatileBinds :: CgBindings -> CgBindings
+nukeVolatileBinds binds
+ = mkIdEnv (foldr keep_if_stable [] (rngIdEnv binds))
+ where
+ keep_if_stable (MkCgIdInfo i _ NoStableLoc entry_info) acc = acc
+ keep_if_stable (MkCgIdInfo i _ stable_loc entry_info) acc
+ = (i, MkCgIdInfo i NoVolatileLoc stable_loc entry_info) : acc
+\end{code}
+
+
+%************************************************************************
+%* *
+\subsection[lookup-interface]{Interface functions to looking up bindings}
+%* *
+%************************************************************************
+
+I {\em think} all looking-up is done through @getCAddrMode(s)@.
+
+\begin{code}
+getCAddrModeAndInfo :: Id -> FCode (CAddrMode, LambdaFormInfo)
+
+getCAddrModeAndInfo name
+ | not (isLocallyDefined name)
+ = returnFC (global_amode, mkLFImported name)
+
+ | isDataCon name
+ = returnFC (global_amode, mkConLFInfo name)
+
+ | otherwise = -- *might* be a nested defn: in any case, it's something whose
+ -- definition we will know about...
+ lookupBindC name `thenFC` \ (MkCgIdInfo _ volatile_loc stable_loc lf_info) ->
+ idInfoPiecesToAmode kind volatile_loc stable_loc `thenFC` \ amode ->
+ returnFC (amode, lf_info)
+ where
+ global_amode = CLbl (mkClosureLabel name) kind
+ kind = getIdKind name
+
+getCAddrMode :: Id -> FCode CAddrMode
+getCAddrMode name
+ = getCAddrModeAndInfo name `thenFC` \ (amode, _) ->
+ returnFC amode
+\end{code}
+
+\begin{code}
+getCAddrModeIfVolatile :: Id -> FCode (Maybe CAddrMode)
+getCAddrModeIfVolatile name
+ | toplevelishId name = returnFC Nothing
+ | otherwise
+ = lookupBindC name `thenFC` \ ~(MkCgIdInfo _ volatile_loc stable_loc lf_info) ->
+ case stable_loc of
+ NoStableLoc -> -- Aha! So it is volatile!
+ idInfoPiecesToAmode (getIdKind name) volatile_loc NoStableLoc `thenFC` \ amode ->
+ returnFC (Just amode)
+
+ a_stable_loc -> returnFC Nothing
+\end{code}
+
+@getVolatileRegs@ gets a set of live variables, and returns a list of
+all registers on which these variables depend. These are the regs
+which must be saved and restored across any C calls. If a variable is
+both in a volatile location (depending on a register) {\em and} a
+stable one (notably, on the stack), we modify the current bindings to
+forget the volatile one.
+
+\begin{code}
+getVolatileRegs :: PlainStgLiveVars -> FCode [MagicId]
+
+getVolatileRegs vars
+ = mapFCs snaffle_it (uniqSetToList vars) `thenFC` \ stuff ->
+ returnFC (catMaybes stuff)
+ where
+ snaffle_it var
+ = lookupBindC var `thenFC` \ (MkCgIdInfo _ volatile_loc stable_loc lf_info) ->
+ let
+ -- commoned-up code...
+ consider_reg reg
+ = if not (isVolatileReg reg) then
+ -- Potentially dies across C calls
+ -- For now, that's everything; we leave
+ -- it to the save-macros to decide which
+ -- regs *really* need to be saved.
+ returnFC Nothing
+ else
+ case stable_loc of
+ NoStableLoc -> returnFC (Just reg) -- got one!
+ is_a_stable_loc ->
+ -- has both volatile & stable locations;
+ -- force it to rely on the stable location
+ modifyBindC var nuke_vol_bind `thenC`
+ returnFC Nothing
+ in
+ case volatile_loc of
+ RegLoc reg -> consider_reg reg
+ VirHpLoc _ -> consider_reg Hp
+ VirNodeLoc _ -> consider_reg node
+ non_reg_loc -> returnFC Nothing
+
+ nuke_vol_bind (MkCgIdInfo i _ stable_loc lf_info)
+ = MkCgIdInfo i NoVolatileLoc stable_loc lf_info
+\end{code}
+
+\begin{code}
+getAtomAmodes :: [PlainStgAtom] -> FCode [CAddrMode]
+getAtomAmodes [] = returnFC []
+getAtomAmodes (atom:atoms)
+ = getAtomAmode atom `thenFC` \ amode ->
+ getAtomAmodes atoms `thenFC` \ amodes ->
+ returnFC ( amode : amodes )
+
+getAtomAmode :: PlainStgAtom -> FCode CAddrMode
+
+getAtomAmode (StgVarAtom var) = getCAddrMode var
+getAtomAmode (StgLitAtom lit) = returnFC (CLit lit)
+\end{code}
+
+%************************************************************************
+%* *
+\subsection[binding-and-rebinding-interface]{Interface functions for binding and re-binding names}
+%* *
+%************************************************************************
+
+\begin{code}
+bindNewToAStack :: (Id, VirtualSpAOffset) -> Code
+bindNewToAStack (name, offset)
+ = addBindC name info
+ where
+ info = MkCgIdInfo name NoVolatileLoc (VirAStkLoc offset) mkLFArgument
+
+bindNewToBStack :: (Id, VirtualSpBOffset) -> Code
+bindNewToBStack (name, offset)
+ = addBindC name info
+ where
+ info = MkCgIdInfo name NoVolatileLoc (VirBStkLoc offset) (panic "bindNewToBStack")
+ -- B-stack things shouldn't need lambda-form info!
+
+bindNewToNode :: Id -> VirtualHeapOffset -> LambdaFormInfo -> Code
+bindNewToNode name offset lf_info
+ = addBindC name info
+ where
+ info = MkCgIdInfo name (VirNodeLoc offset) NoStableLoc lf_info
+
+-- Create a new temporary whose unique is that in the id,
+-- bind the id to it, and return the addressing mode for the
+-- temporary.
+bindNewToTemp :: Id -> FCode CAddrMode
+bindNewToTemp name
+ = let (temp_amode, id_info) = newTempAmodeAndIdInfo name mkLFArgument
+ -- This is used only for things we don't know
+ -- anything about; values returned by a case statement,
+ -- for example.
+ in
+ addBindC name id_info `thenC`
+ returnFC temp_amode
+
+bindNewToReg :: Id -> MagicId -> LambdaFormInfo -> Code
+bindNewToReg name magic_id lf_info
+ = addBindC name info
+ where
+ info = MkCgIdInfo name (RegLoc magic_id) NoStableLoc lf_info
+
+bindNewToLit name lit
+ = addBindC name info
+ where
+ info = MkCgIdInfo name NoVolatileLoc (LitLoc lit) (error "bindNewToLit")
+
+bindArgsToRegs :: [Id] -> [MagicId] -> Code
+bindArgsToRegs args regs
+ = listCs (zipWith bind args regs)
+ where
+ arg `bind` reg = bindNewToReg arg reg mkLFArgument
+
+{- UNUSED:
+bindNewToSameAsOther :: Id -> PlainStgAtom -> Code
+bindNewToSameAsOther name (StgVarAtom old_name)
+#ifdef DEBUG
+ | toplevelishId old_name = panic "bindNewToSameAsOther: global old name"
+ | otherwise
+#endif
+ = lookupBindC old_name `thenFC` \ old_stuff ->
+ addBindC name old_stuff
+
+bindNewToSameAsOther name (StgLitAtom lit)
+ = addBindC name info
+ where
+ info = MkCgIdInfo name NoVolatileLoc (LitLoc lit) (panic "bindNewToSameAsOther")
+-}
+\end{code}
+
+@bindNewPrimToAmode@ works only for certain addressing modes, because
+those are the only ones we've needed so far!
+
+\begin{code}
+bindNewPrimToAmode :: Id -> CAddrMode -> Code
+bindNewPrimToAmode name (CReg reg) = bindNewToReg name reg (panic "bindNewPrimToAmode")
+ -- was: mkLFArgument
+ -- LFinfo is irrelevant for primitives
+bindNewPrimToAmode name (CTemp uniq kind)
+ = addBindC name (tempIdInfo name uniq (panic "bindNewPrimToAmode"))
+ -- LFinfo is irrelevant for primitives
+
+bindNewPrimToAmode name (CLit lit) = bindNewToLit name lit
+
+bindNewPrimToAmode name (CVal (SpBRel _ offset) _)
+ = bindNewToBStack (name, offset)
+
+bindNewPrimToAmode name (CVal (NodeRel offset) _)
+ = bindNewToNode name offset (panic "bindNewPrimToAmode node")
+ -- See comment on idInfoPiecesToAmode for VirNodeLoc
+
+#ifdef DEBUG
+bindNewPrimToAmode name amode
+ = panic ("bindNew...:"++(uppShow 80 (pprAmode PprDebug amode)))
+#endif
+\end{code}
+
+\begin{code}
+rebindToAStack :: Id -> VirtualSpAOffset -> Code
+rebindToAStack name offset
+ = modifyBindC name replace_stable_fn
+ where
+ replace_stable_fn (MkCgIdInfo i vol stab einfo)
+ = MkCgIdInfo i vol (VirAStkLoc offset) einfo
+
+rebindToBStack :: Id -> VirtualSpBOffset -> Code
+rebindToBStack name offset
+ = modifyBindC name replace_stable_fn
+ where
+ replace_stable_fn (MkCgIdInfo i vol stab einfo)
+ = MkCgIdInfo i vol (VirBStkLoc offset) einfo
+
+{- UNUSED:
+rebindToTemp :: Id -> FCode CAddrMode
+rebindToTemp name
+ = let
+ (temp_amode, MkCgIdInfo _ new_vol _ _ {-LF info discarded-})
+ = newTempAmodeAndIdInfo name (panic "rebindToTemp")
+ in
+ modifyBindC name (replace_volatile_fn new_vol) `thenC`
+ returnFC temp_amode
+ where
+ replace_volatile_fn new_vol (MkCgIdInfo i vol stab einfo)
+ = MkCgIdInfo i new_vol stab einfo
+-}
+\end{code}
+