2 % (c) The GRASP/AQUA Project, Glasgow University, 1992-1998
4 \section[CgBindery]{Utility functions related to doing @CgBindings@}
9 StableLoc, VolatileLoc,
11 stableAmodeIdInfo, heapIdInfo,
12 letNoEscapeIdInfo, idInfoToAmode,
19 bindNewToStack, rebindToStack,
20 bindNewToNode, bindNewToReg, bindArgsToRegs,
22 getArgAmode, getArgAmodes,
23 getCAddrModeAndInfo, getCAddrMode,
24 getCAddrModeIfVolatile, getVolatileRegs,
29 #include "HsVersions.h"
34 import CgUsages ( getHpRelOffset, getSpRelOffset, getRealSp )
35 import CgStackery ( freeStackSlots, getStackFrame )
36 import CLabel ( mkClosureLabel,
37 mkBitmapLabel, pprCLabel )
38 import ClosureInfo ( mkLFImported, mkLFArgument, LambdaFormInfo )
40 import PrimRep ( isFollowableRep, getPrimRepSize )
41 import Id ( Id, idPrimRep, idType )
42 import Type ( typePrimRep )
44 import VarSet ( varSetElems )
45 import Literal ( Literal )
46 import Maybes ( catMaybes, maybeToBool, seqMaybe )
47 import Name ( isInternalName, NamedThing(..) )
49 import PprAbsC ( pprAmode, pprMagicId )
51 import PrimRep ( PrimRep(..) )
52 import StgSyn ( StgArg, StgLiveVars, GenStgArg(..), isStgTypeArg )
53 import Unique ( Unique, Uniquable(..) )
54 import UniqSet ( elementOfUniqSet )
55 import Util ( zipWithEqual, sortLt )
60 %************************************************************************
62 \subsection[Bindery-datatypes]{Data types}
64 %************************************************************************
66 @(CgBinding a b)@ is a type of finite maps from a to b.
68 The assumption used to be that @lookupCgBind@ must get exactly one
69 match. This is {\em completely wrong} in the case of compiling
70 letrecs (where knot-tying is used). An initial binding is fed in (and
71 never evaluated); eventually, a correct binding is put into the
72 environment. So there can be two bindings for a given name.
75 type CgBindings = IdEnv CgIdInfo
78 = MkCgIdInfo Id -- Id that this is the info for
87 | RegLoc MagicId -- in one of the magic registers
88 -- (probably {Int,Float,Char,etc}Reg)
90 | VirHpLoc VirtualHeapOffset -- Hp+offset (address of closure)
92 | VirNodeLoc VirtualHeapOffset -- Cts of offset indirect from Node
96 @StableLoc@ encodes where an Id can be found, used by
97 the @CgBindings@ environment in @CgBindery@.
102 | VirStkLoc VirtualSpOffset
104 | StableAmodeLoc CAddrMode
106 -- these are so StableLoc can be abstract:
108 maybeStkLoc (VirStkLoc offset) = Just offset
109 maybeStkLoc _ = Nothing
113 instance Outputable CgIdInfo where
114 ppr (MkCgIdInfo id vol stb lf)
115 = ppr id <+> ptext SLIT("-->") <+> vcat [ppr vol, ppr stb]
117 instance Outputable VolatileLoc where
118 ppr NoVolatileLoc = empty
119 ppr (TempVarLoc u) = ptext SLIT("tmp") <+> ppr u
120 ppr (RegLoc r) = ptext SLIT("reg") <+> pprMagicId r
121 ppr (VirHpLoc v) = ptext SLIT("vh") <+> ppr v
122 ppr (VirNodeLoc v) = ptext SLIT("vn") <+> ppr v
124 instance Outputable StableLoc where
125 ppr NoStableLoc = empty
126 ppr (VirStkLoc v) = ptext SLIT("vs") <+> ppr v
127 ppr (LitLoc l) = ptext SLIT("lit") <+> ppr l
128 ppr (StableAmodeLoc a) = ptext SLIT("amode") <+> pprAmode a
131 %************************************************************************
133 \subsection[Bindery-idInfo]{Manipulating IdInfo}
135 %************************************************************************
138 stableAmodeIdInfo i amode lf_info = MkCgIdInfo i NoVolatileLoc (StableAmodeLoc amode) lf_info
139 heapIdInfo i offset lf_info = MkCgIdInfo i (VirHpLoc offset) NoStableLoc lf_info
140 tempIdInfo i uniq lf_info = MkCgIdInfo i (TempVarLoc uniq) NoStableLoc lf_info
142 letNoEscapeIdInfo i sp lf_info
143 = MkCgIdInfo i NoVolatileLoc (StableAmodeLoc (CJoinPoint sp)) lf_info
145 idInfoToAmode :: PrimRep -> CgIdInfo -> FCode CAddrMode
146 idInfoToAmode kind (MkCgIdInfo _ vol stab _) = idInfoPiecesToAmode kind vol stab
148 idInfoPiecesToAmode :: PrimRep -> VolatileLoc -> StableLoc -> FCode CAddrMode
150 idInfoPiecesToAmode kind (TempVarLoc uniq) stable_loc = returnFC (CTemp uniq kind)
151 idInfoPiecesToAmode kind (RegLoc magic_id) stable_loc = returnFC (CReg magic_id)
153 idInfoPiecesToAmode kind NoVolatileLoc (LitLoc lit) = returnFC (CLit lit)
154 idInfoPiecesToAmode kind NoVolatileLoc (StableAmodeLoc amode) = returnFC amode
156 idInfoPiecesToAmode kind (VirNodeLoc nd_off) stable_loc
157 = returnFC (CVal (nodeRel nd_off) kind)
158 -- Virtual offsets from Node increase into the closures,
159 -- and so do Node-relative offsets (which we want in the CVal),
160 -- so there is no mucking about to do to the offset.
162 idInfoPiecesToAmode kind (VirHpLoc hp_off) stable_loc
163 = getHpRelOffset hp_off `thenFC` \ rel_hp ->
164 returnFC (CAddr rel_hp)
166 idInfoPiecesToAmode kind NoVolatileLoc (VirStkLoc i)
167 = getSpRelOffset i `thenFC` \ rel_sp ->
168 returnFC (CVal rel_sp kind)
171 idInfoPiecesToAmode kind NoVolatileLoc NoStableLoc = panic "idInfoPiecesToAmode: no loc"
175 %************************************************************************
177 \subsection[CgMonad-bindery]{Monad things for fiddling with @CgBindings@}
179 %************************************************************************
181 There are three basic routines, for adding (@addBindC@), modifying
182 (@modifyBindC@) and looking up (@lookupBindC@) bindings.
184 A @Id@ is bound to a @(VolatileLoc, StableLoc)@ triple.
185 The name should not already be bound. (nice ASSERT, eh?)
188 addBindC :: Id -> CgIdInfo -> Code
189 addBindC name stuff_to_bind = do
191 setBinds $ extendVarEnv binds name stuff_to_bind
193 addBindsC :: [(Id, CgIdInfo)] -> Code
194 addBindsC new_bindings = do
196 let new_binds = foldl (\ binds (name,info) -> extendVarEnv binds name info)
201 modifyBindC :: Id -> (CgIdInfo -> CgIdInfo) -> Code
202 modifyBindC name mangle_fn = do
204 setBinds $ modifyVarEnv mangle_fn binds name
206 lookupBindC :: Id -> FCode CgIdInfo
207 lookupBindC id = do maybe_info <- lookupBindC_maybe id
209 Just info -> return info
210 Nothing -> cgLookupPanic id
212 lookupBindC_maybe :: Id -> FCode (Maybe CgIdInfo)
214 = do static_binds <- getStaticBinds
215 local_binds <- getBinds
216 return (lookupVarEnv local_binds id
218 lookupVarEnv static_binds id)
220 cgLookupPanic :: Id -> FCode a
222 = do static_binds <- getStaticBinds
223 local_binds <- getBinds
227 ptext SLIT("static binds for:"),
228 vcat [ ppr i | (MkCgIdInfo i _ _ _) <- rngVarEnv static_binds ],
229 ptext SLIT("local binds for:"),
230 vcat [ ppr i | (MkCgIdInfo i _ _ _) <- rngVarEnv local_binds ],
231 ptext SLIT("SRT label") <+> pprCLabel srt
235 %************************************************************************
237 \subsection[Bindery-nuke-volatile]{Nuking volatile bindings}
239 %************************************************************************
241 We sometimes want to nuke all the volatile bindings; we must be sure
242 we don't leave any (NoVolatile, NoStable) binds around...
245 nukeVolatileBinds :: CgBindings -> CgBindings
246 nukeVolatileBinds binds
247 = mkVarEnv (foldr keep_if_stable [] (rngVarEnv binds))
249 keep_if_stable (MkCgIdInfo i _ NoStableLoc entry_info) acc = acc
250 keep_if_stable (MkCgIdInfo i _ stable_loc entry_info) acc
251 = (i, MkCgIdInfo i NoVolatileLoc stable_loc entry_info) : acc
255 %************************************************************************
257 \subsection[lookup-interface]{Interface functions to looking up bindings}
259 %************************************************************************
261 I {\em think} all looking-up is done through @getCAddrMode(s)@.
264 getCAddrModeAndInfo :: Id -> FCode (Id, CAddrMode, LambdaFormInfo)
266 getCAddrModeAndInfo id
268 maybe_cg_id_info <- lookupBindC_maybe id
269 case maybe_cg_id_info of
271 -- Nothing => not in the environment, so should be imported
272 Nothing | isInternalName name -> cgLookupPanic id
273 | otherwise -> returnFC (id, global_amode, mkLFImported id)
275 Just (MkCgIdInfo id' volatile_loc stable_loc lf_info)
276 -> do amode <- idInfoPiecesToAmode kind volatile_loc stable_loc
277 return (id', amode, lf_info)
280 global_amode = CLbl (mkClosureLabel name) kind
283 getCAddrMode :: Id -> FCode CAddrMode
284 getCAddrMode name = do
285 (_, amode, _) <- getCAddrModeAndInfo name
290 getCAddrModeIfVolatile :: Id -> FCode (Maybe CAddrMode)
291 getCAddrModeIfVolatile name
292 -- | toplevelishId name = returnFC Nothing
295 (MkCgIdInfo _ volatile_loc stable_loc lf_info) <- lookupBindC name
297 NoStableLoc -> do -- Aha! So it is volatile!
298 amode <- idInfoPiecesToAmode (idPrimRep name) volatile_loc NoStableLoc
300 a_stable_loc -> return Nothing
303 @getVolatileRegs@ gets a set of live variables, and returns a list of
304 all registers on which these variables depend. These are the regs
305 which must be saved and restored across any C calls. If a variable is
306 both in a volatile location (depending on a register) {\em and} a
307 stable one (notably, on the stack), we modify the current bindings to
308 forget the volatile one.
311 getVolatileRegs :: StgLiveVars -> FCode [MagicId]
313 getVolatileRegs vars = do
314 stuff <- mapFCs snaffle_it (varSetElems vars)
315 returnFC $ catMaybes stuff
318 (MkCgIdInfo _ volatile_loc stable_loc lf_info) <- lookupBindC var
320 -- commoned-up code...
322 if not (isVolatileReg reg) then
323 -- Potentially dies across C calls
324 -- For now, that's everything; we leave
325 -- it to the save-macros to decide which
326 -- regs *really* need to be saved.
330 NoStableLoc -> returnFC (Just reg) -- got one!
331 is_a_stable_loc -> do
332 -- has both volatile & stable locations;
333 -- force it to rely on the stable location
334 modifyBindC var nuke_vol_bind
338 RegLoc reg -> consider_reg reg
339 VirNodeLoc _ -> consider_reg node
340 non_reg_loc -> returnFC Nothing
342 nuke_vol_bind (MkCgIdInfo i _ stable_loc lf_info)
343 = MkCgIdInfo i NoVolatileLoc stable_loc lf_info
347 getArgAmodes :: [StgArg] -> FCode [CAddrMode]
348 getArgAmodes [] = returnFC []
349 getArgAmodes (atom:atoms)
353 amode <- getArgAmode atom
354 amodes <- getArgAmodes atoms
355 return ( amode : amodes )
357 getArgAmode :: StgArg -> FCode CAddrMode
359 getArgAmode (StgVarArg var) = getCAddrMode var -- The common case
360 getArgAmode (StgLitArg lit) = returnFC (CLit lit)
363 %************************************************************************
365 \subsection[binding-and-rebinding-interface]{Interface functions for binding and re-binding names}
367 %************************************************************************
370 bindNewToStack :: (Id, VirtualSpOffset) -> Code
371 bindNewToStack (name, offset)
374 info = MkCgIdInfo name NoVolatileLoc (VirStkLoc offset) (mkLFArgument name)
376 bindNewToNode :: Id -> VirtualHeapOffset -> LambdaFormInfo -> Code
377 bindNewToNode name offset lf_info
380 info = MkCgIdInfo name (VirNodeLoc offset) NoStableLoc lf_info
382 -- Create a new temporary whose unique is that in the id,
383 -- bind the id to it, and return the addressing mode for the
385 bindNewToTemp :: Id -> FCode CAddrMode
387 = do addBindC id id_info
391 temp_amode = CTemp uniq (idPrimRep id)
392 id_info = tempIdInfo id uniq lf_info
393 lf_info = mkLFArgument id -- Always used of things we
394 -- know nothing about
396 bindNewToReg :: Id -> MagicId -> LambdaFormInfo -> Code
397 bindNewToReg name magic_id lf_info
400 info = MkCgIdInfo name (RegLoc magic_id) NoStableLoc lf_info
402 bindArgsToRegs :: [Id] -> [MagicId] -> Code
403 bindArgsToRegs args regs
404 = listCs (zipWithEqual "bindArgsToRegs" bind args regs)
406 arg `bind` reg = bindNewToReg arg reg (mkLFArgument arg)
410 rebindToStack :: Id -> VirtualSpOffset -> Code
411 rebindToStack name offset
412 = modifyBindC name replace_stable_fn
414 replace_stable_fn (MkCgIdInfo i vol stab einfo)
415 = MkCgIdInfo i vol (VirStkLoc offset) einfo
418 %************************************************************************
420 \subsection[CgBindery-liveness]{Build a liveness mask for the current stack}
422 %************************************************************************
424 There are four kinds of things on the stack:
426 - pointer variables (bound in the environment)
427 - non-pointer variables (boudn in the environment)
428 - free slots (recorded in the stack free list)
429 - non-pointer data slots (recorded in the stack free list)
431 We build up a bitmap of non-pointer slots by searching the environment
432 for all the pointer variables, and subtracting these from a bitmap
433 with initially all bits set (up to the size of the stack frame).
437 :: VirtualSpOffset -- size of the stack frame
438 -> VirtualSpOffset -- offset from which the bitmap should start
439 -> FCode Bitmap -- mask for free/unlifted slots
441 buildLivenessMask size sp = do {
442 -- find all live stack-resident pointers
444 ((vsp, _, free, _, _), heap_usage) <- getUsage;
447 rel_slots = sortLt (<)
448 [ sp - ofs -- get slots relative to top of frame
449 | (MkCgIdInfo id _ (VirStkLoc ofs) _) <- rngVarEnv binds,
450 isFollowableRep (idPrimRep id)
454 WARN( not (all (>=0) rel_slots), ppr size $$ ppr sp $$ ppr rel_slots $$ ppr binds )
455 return (intsToReverseBitmap size rel_slots)
458 -- In a continuation, we want a liveness mask that starts from just after
459 -- the return address, which is on the stack at realSp.
461 buildContLivenessMask :: Id -> FCode Liveness
462 -- The Id is used just for its unique to make a label
463 buildContLivenessMask id = do
466 frame_sp <- getStackFrame
467 -- realSp points to the frame-header for the current stack frame,
468 -- and the end of this frame is frame_sp. The size is therefore
469 -- realSp - frame_sp - 1 (subtract one for the frame-header).
470 let frame_size = realSp - frame_sp - 1
472 mask <- buildLivenessMask frame_size (realSp-1)
474 let liveness = Liveness (mkBitmapLabel (getName id)) frame_size mask
475 absC (maybeLargeBitmap liveness)
479 %************************************************************************
481 \subsection[CgMonad-deadslots]{Finding dead stack slots}
483 %************************************************************************
485 nukeDeadBindings does the following:
487 - Removes all bindings from the environment other than those
488 for variables in the argument to nukeDeadBindings.
489 - Collects any stack slots so freed, and returns them to the stack free
491 - Moves the virtual stack pointer to point to the topmost used
494 You can have multi-word slots on the stack (where a Double# used to
495 be, for instance); if dead, such a slot will be reported as *several*
496 offsets (one per word).
498 Probably *naughty* to look inside monad...
501 nukeDeadBindings :: StgLiveVars -- All the *live* variables
503 nukeDeadBindings live_vars = do
505 let (dead_stk_slots, bs') =
508 [ (i, b) | b@(MkCgIdInfo i _ _ _) <- rngVarEnv binds ]
509 setBinds $ mkVarEnv bs'
510 freeStackSlots dead_stk_slots
513 Several boring auxiliary functions to do the dirty work.
516 dead_slots :: StgLiveVars
520 -> ([VirtualSpOffset], [(Id,CgIdInfo)])
522 -- dead_slots carries accumulating parameters for
523 -- filtered bindings, dead slots
524 dead_slots live_vars fbs ds []
525 = (ds, reverse fbs) -- Finished; rm the dups, if any
527 dead_slots live_vars fbs ds ((v,i):bs)
528 | v `elementOfUniqSet` live_vars
529 = dead_slots live_vars ((v,i):fbs) ds bs
530 -- Live, so don't record it in dead slots
531 -- Instead keep it in the filtered bindings
535 MkCgIdInfo _ _ stable_loc _
536 | is_stk_loc && size > 0 ->
537 dead_slots live_vars fbs ([offset-size+1 .. offset] ++ ds) bs
539 maybe_stk_loc = maybeStkLoc stable_loc
540 is_stk_loc = maybeToBool maybe_stk_loc
541 (Just offset) = maybe_stk_loc
543 _ -> dead_slots live_vars fbs ds bs
547 size = (getPrimRepSize . typePrimRep . idType) v