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, newTempAmodeAndIdInfo,
12 letNoEscapeIdInfo, idInfoToAmode,
19 bindNewToStack, rebindToStack,
20 bindNewToNode, bindNewToReg, bindArgsToRegs,
21 bindNewToTemp, bindNewPrimToAmode,
22 getArgAmode, getArgAmodes,
23 getCAddrModeAndInfo, getCAddrMode,
24 getCAddrModeIfVolatile, getVolatileRegs,
26 buildLivenessMask, buildContLivenessMask
29 #include "HsVersions.h"
34 import CgUsages ( getHpRelOffset, getSpRelOffset, getRealSp )
35 import CgStackery ( freeStackSlots )
36 import CLabel ( mkClosureLabel,
37 mkBitmapLabel, pprCLabel )
38 import ClosureInfo ( mkLFImported, mkLFArgument, LambdaFormInfo )
39 import BitSet ( mkBS, emptyBS )
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 )
47 import Name ( isLocalName, NamedThing(..) )
49 import PprAbsC ( pprAmode )
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
112 %************************************************************************
114 \subsection[Bindery-idInfo]{Manipulating IdInfo}
116 %************************************************************************
119 stableAmodeIdInfo i amode lf_info = MkCgIdInfo i NoVolatileLoc (StableAmodeLoc amode) lf_info
120 heapIdInfo i offset lf_info = MkCgIdInfo i (VirHpLoc offset) NoStableLoc lf_info
121 tempIdInfo i uniq lf_info = MkCgIdInfo i (TempVarLoc uniq) NoStableLoc lf_info
123 letNoEscapeIdInfo i sp lf_info
124 = MkCgIdInfo i NoVolatileLoc (StableAmodeLoc (CJoinPoint sp)) lf_info
126 newTempAmodeAndIdInfo :: Id -> LambdaFormInfo -> (CAddrMode, CgIdInfo)
128 newTempAmodeAndIdInfo name lf_info
129 = (temp_amode, temp_idinfo)
131 uniq = getUnique name
132 temp_amode = CTemp uniq (idPrimRep name)
133 temp_idinfo = tempIdInfo name uniq lf_info
135 idInfoToAmode :: PrimRep -> CgIdInfo -> FCode CAddrMode
136 idInfoToAmode kind (MkCgIdInfo _ vol stab _) = idInfoPiecesToAmode kind vol stab
138 idInfoPiecesToAmode :: PrimRep -> VolatileLoc -> StableLoc -> FCode CAddrMode
140 idInfoPiecesToAmode kind (TempVarLoc uniq) stable_loc = returnFC (CTemp uniq kind)
141 idInfoPiecesToAmode kind (RegLoc magic_id) stable_loc = returnFC (CReg magic_id)
143 idInfoPiecesToAmode kind NoVolatileLoc (LitLoc lit) = returnFC (CLit lit)
144 idInfoPiecesToAmode kind NoVolatileLoc (StableAmodeLoc amode) = returnFC amode
146 idInfoPiecesToAmode kind (VirNodeLoc nd_off) stable_loc
147 = returnFC (CVal (nodeRel nd_off) kind)
148 -- Virtual offsets from Node increase into the closures,
149 -- and so do Node-relative offsets (which we want in the CVal),
150 -- so there is no mucking about to do to the offset.
152 idInfoPiecesToAmode kind (VirHpLoc hp_off) stable_loc
153 = getHpRelOffset hp_off `thenFC` \ rel_hp ->
154 returnFC (CAddr rel_hp)
156 idInfoPiecesToAmode kind NoVolatileLoc (VirStkLoc i)
157 = getSpRelOffset i `thenFC` \ rel_sp ->
158 returnFC (CVal rel_sp kind)
161 idInfoPiecesToAmode kind NoVolatileLoc NoStableLoc = panic "idInfoPiecesToAmode: no loc"
165 %************************************************************************
167 \subsection[CgMonad-bindery]{Monad things for fiddling with @CgBindings@}
169 %************************************************************************
171 There are three basic routines, for adding (@addBindC@), modifying
172 (@modifyBindC@) and looking up (@lookupBindC@) bindings.
174 A @Id@ is bound to a @(VolatileLoc, StableLoc)@ triple.
175 The name should not already be bound. (nice ASSERT, eh?)
178 addBindC :: Id -> CgIdInfo -> Code
179 addBindC name stuff_to_bind info_down (MkCgState absC binds usage)
180 = MkCgState absC (extendVarEnv binds name stuff_to_bind) usage
182 addBindsC :: [(Id, CgIdInfo)] -> Code
183 addBindsC new_bindings info_down (MkCgState absC binds usage)
184 = MkCgState absC new_binds usage
186 new_binds = foldl (\ binds (name,info) -> extendVarEnv binds name info)
190 modifyBindC :: Id -> (CgIdInfo -> CgIdInfo) -> Code
191 modifyBindC name mangle_fn info_down (MkCgState absC binds usage)
192 = MkCgState absC (modifyVarEnv mangle_fn binds name) usage
194 lookupBindC :: Id -> FCode CgIdInfo
195 lookupBindC name info_down@(MkCgInfoDown _ static_binds srt ticky _)
196 state@(MkCgState absC local_binds usage)
199 val = case (lookupVarEnv local_binds name) of
200 Nothing -> try_static
204 case (lookupVarEnv static_binds name) of
207 -> cgPanic (text "lookupBindC: no info for" <+> ppr name) info_down state
209 cgPanic :: SDoc -> CgInfoDownwards -> CgState -> a
210 cgPanic doc info_down@(MkCgInfoDown _ static_binds srt ticky _)
211 state@(MkCgState absC local_binds usage)
214 ptext SLIT("static binds for:"),
215 vcat [ ppr i | (MkCgIdInfo i _ _ _) <- rngVarEnv static_binds ],
216 ptext SLIT("local binds for:"),
217 vcat [ ppr i | (MkCgIdInfo i _ _ _) <- rngVarEnv local_binds ],
218 ptext SLIT("SRT label") <+> pprCLabel srt
222 %************************************************************************
224 \subsection[Bindery-nuke-volatile]{Nuking volatile bindings}
226 %************************************************************************
228 We sometimes want to nuke all the volatile bindings; we must be sure
229 we don't leave any (NoVolatile, NoStable) binds around...
232 nukeVolatileBinds :: CgBindings -> CgBindings
233 nukeVolatileBinds binds
234 = mkVarEnv (foldr keep_if_stable [] (rngVarEnv binds))
236 keep_if_stable (MkCgIdInfo i _ NoStableLoc entry_info) acc = acc
237 keep_if_stable (MkCgIdInfo i _ stable_loc entry_info) acc
238 = (i, MkCgIdInfo i NoVolatileLoc stable_loc entry_info) : acc
242 %************************************************************************
244 \subsection[lookup-interface]{Interface functions to looking up bindings}
246 %************************************************************************
248 I {\em think} all looking-up is done through @getCAddrMode(s)@.
251 getCAddrModeAndInfo :: Id -> FCode (Id, CAddrMode, LambdaFormInfo)
253 getCAddrModeAndInfo id
254 | not (isLocalName name)
255 = returnFC (id, global_amode, mkLFImported id)
256 -- deals with imported or locally defined but externally visible ids
257 -- (CoreTidy makes all these into global names).
259 | otherwise = -- *might* be a nested defn: in any case, it's something whose
260 -- definition we will know about...
261 lookupBindC id `thenFC` \ (MkCgIdInfo id' volatile_loc stable_loc lf_info) ->
262 idInfoPiecesToAmode kind volatile_loc stable_loc `thenFC` \ amode ->
263 returnFC (id', amode, lf_info)
266 global_amode = CLbl (mkClosureLabel name) kind
269 getCAddrMode :: Id -> FCode CAddrMode
271 = getCAddrModeAndInfo name `thenFC` \ (_, amode, _) ->
276 getCAddrModeIfVolatile :: Id -> FCode (Maybe CAddrMode)
277 getCAddrModeIfVolatile name
278 -- | toplevelishId name = returnFC Nothing
280 = lookupBindC name `thenFC` \ ~(MkCgIdInfo _ volatile_loc stable_loc lf_info) ->
282 NoStableLoc -> -- Aha! So it is volatile!
283 idInfoPiecesToAmode (idPrimRep name) volatile_loc NoStableLoc `thenFC` \ amode ->
284 returnFC (Just amode)
286 a_stable_loc -> returnFC Nothing
289 @getVolatileRegs@ gets a set of live variables, and returns a list of
290 all registers on which these variables depend. These are the regs
291 which must be saved and restored across any C calls. If a variable is
292 both in a volatile location (depending on a register) {\em and} a
293 stable one (notably, on the stack), we modify the current bindings to
294 forget the volatile one.
297 getVolatileRegs :: StgLiveVars -> FCode [MagicId]
300 = mapFCs snaffle_it (varSetElems vars) `thenFC` \ stuff ->
301 returnFC (catMaybes stuff)
304 = lookupBindC var `thenFC` \ (MkCgIdInfo _ volatile_loc stable_loc lf_info) ->
306 -- commoned-up code...
308 = if not (isVolatileReg reg) then
309 -- Potentially dies across C calls
310 -- For now, that's everything; we leave
311 -- it to the save-macros to decide which
312 -- regs *really* need to be saved.
316 NoStableLoc -> returnFC (Just reg) -- got one!
318 -- has both volatile & stable locations;
319 -- force it to rely on the stable location
320 modifyBindC var nuke_vol_bind `thenC`
324 RegLoc reg -> consider_reg reg
325 VirHpLoc _ -> consider_reg Hp
326 VirNodeLoc _ -> consider_reg node
327 non_reg_loc -> returnFC Nothing
329 nuke_vol_bind (MkCgIdInfo i _ stable_loc lf_info)
330 = MkCgIdInfo i NoVolatileLoc stable_loc lf_info
334 getArgAmodes :: [StgArg] -> FCode [CAddrMode]
335 getArgAmodes [] = returnFC []
336 getArgAmodes (atom:atoms)
340 = getArgAmode atom `thenFC` \ amode ->
341 getArgAmodes atoms `thenFC` \ amodes ->
342 returnFC ( amode : amodes )
344 getArgAmode :: StgArg -> FCode CAddrMode
346 getArgAmode (StgVarArg var) = getCAddrMode var -- The common case
347 getArgAmode (StgLitArg lit) = returnFC (CLit lit)
350 %************************************************************************
352 \subsection[binding-and-rebinding-interface]{Interface functions for binding and re-binding names}
354 %************************************************************************
357 bindNewToStack :: (Id, VirtualSpOffset) -> Code
358 bindNewToStack (name, offset)
361 info = MkCgIdInfo name NoVolatileLoc (VirStkLoc offset) mkLFArgument
363 bindNewToNode :: Id -> VirtualHeapOffset -> LambdaFormInfo -> Code
364 bindNewToNode name offset lf_info
367 info = MkCgIdInfo name (VirNodeLoc offset) NoStableLoc lf_info
369 -- Create a new temporary whose unique is that in the id,
370 -- bind the id to it, and return the addressing mode for the
372 bindNewToTemp :: Id -> FCode CAddrMode
374 = let (temp_amode, id_info) = newTempAmodeAndIdInfo name mkLFArgument
375 -- This is used only for things we don't know
376 -- anything about; values returned by a case statement,
379 addBindC name id_info `thenC`
382 bindNewToReg :: Id -> MagicId -> LambdaFormInfo -> Code
383 bindNewToReg name magic_id lf_info
386 info = MkCgIdInfo name (RegLoc magic_id) NoStableLoc lf_info
388 bindArgsToRegs :: [Id] -> [MagicId] -> Code
389 bindArgsToRegs args regs
390 = listCs (zipWithEqual "bindArgsToRegs" bind args regs)
392 arg `bind` reg = bindNewToReg arg reg mkLFArgument
395 @bindNewPrimToAmode@ works only for certain addressing modes. Making
396 this work for stack offsets is non-trivial (virt vs. real stack offset
400 bindNewPrimToAmode :: Id -> CAddrMode -> Code
401 bindNewPrimToAmode name (CReg reg)
402 = bindNewToReg name reg (panic "bindNewPrimToAmode")
404 bindNewPrimToAmode name (CTemp uniq kind)
405 = addBindC name (tempIdInfo name uniq (panic "bindNewPrimToAmode"))
408 bindNewPrimToAmode name amode
409 = pprPanic "bindNew...:" (pprAmode amode)
414 rebindToStack :: Id -> VirtualSpOffset -> Code
415 rebindToStack name offset
416 = modifyBindC name replace_stable_fn
418 replace_stable_fn (MkCgIdInfo i vol stab einfo)
419 = MkCgIdInfo i vol (VirStkLoc offset) einfo
422 %************************************************************************
424 \subsection[CgBindery-liveness]{Build a liveness mask for the current stack}
426 %************************************************************************
428 There are four kinds of things on the stack:
430 - pointer variables (bound in the environment)
431 - non-pointer variables (boudn in the environment)
432 - free slots (recorded in the stack free list)
433 - non-pointer data slots (recorded in the stack free list)
435 We build up a bitmap of non-pointer slots by looking down the
436 environment for all the non-pointer variables, and merging this with
437 the slots recorded in the stack free list.
439 There's a bit of a hack here to do with update frames: since nothing
440 is recorded in either the environment or the stack free list for an
441 update frame, the code below defaults to assuming the slots taken up
442 by an update frame contain pointers. Furthermore, update frames are
443 always in slots 0-2 at the bottom of the stack. The bitmap will
444 therefore end at slot 3, which is what we want (the update frame info
445 pointer has its own bitmap to describe the update frame).
449 :: Unique -- unique for for large bitmap label
450 -> VirtualSpOffset -- offset from which the bitmap should start
451 -> FCode Liveness -- mask for free/unlifted slots
453 buildLivenessMask uniq sp info_down
454 state@(MkCgState abs_c binds ((vsp, free, _, _), heap_usage))
455 = ASSERT(all (>=0) rel_slots)
456 livenessToAbsC uniq liveness_mask info_down state
458 -- find all unboxed stack-resident ids
461 (MkCgIdInfo id _ (VirStkLoc ofs) _) <- rngVarEnv binds,
462 let rep = idPrimRep id; size = getPrimRepSize rep,
463 not (isFollowableRep rep),
467 -- flatten this list into a list of unboxed stack slots
468 flatten_slots = sortLt (<)
469 (foldr (\(ofs,size) r -> [ofs-size+1 .. ofs] ++ r) []
472 -- merge in the free slots
473 all_slots = mergeSlots flatten_slots (map fst free) ++
474 if vsp < sp then [vsp+1 .. sp] else []
476 -- recalibrate the list to be sp-relative
477 rel_slots = reverse (map (sp-) all_slots)
480 liveness_mask = listToLivenessMask rel_slots
482 mergeSlots :: [Int] -> [Int] -> [Int]
483 mergeSlots cs [] = cs
484 mergeSlots [] ns = ns
485 mergeSlots (c:cs) (n:ns)
487 c : mergeSlots cs (n:ns)
489 n : mergeSlots (c:cs) ns
491 panic ("mergeSlots: equal slots: " ++ show (c:cs) ++ show (n:ns))
493 listToLivenessMask :: [Int] -> LivenessMask
494 listToLivenessMask [] = []
495 listToLivenessMask slots =
496 mkBS this : listToLivenessMask (map (\x -> x-32) rest)
497 where (this,rest) = span (<32) slots
499 livenessToAbsC :: Unique -> LivenessMask -> FCode Liveness
500 livenessToAbsC uniq mask =
501 absC (CBitmap lbl mask) `thenC`
502 returnFC (Liveness lbl mask)
503 where lbl = mkBitmapLabel uniq
506 In a continuation, we want a liveness mask that starts from just after
507 the return address, which is on the stack at realSp.
510 buildContLivenessMask
513 buildContLivenessMask uniq
514 = getRealSp `thenFC` \ realSp ->
515 buildLivenessMask uniq (realSp-1)
518 %************************************************************************
520 \subsection[CgMonad-deadslots]{Finding dead stack slots}
522 %************************************************************************
524 nukeDeadBindings does the following:
526 - Removes all bindings from the environment other than those
527 for variables in the argument to nukeDeadBindings.
528 - Collects any stack slots so freed, and returns them to the stack free
530 - Moves the virtual stack pointer to point to the topmost used
533 You can have multi-word slots on the stack (where a Double# used to
534 be, for instance); if dead, such a slot will be reported as *several*
535 offsets (one per word).
537 Probably *naughty* to look inside monad...
540 nukeDeadBindings :: StgLiveVars -- All the *live* variables
543 nukeDeadBindings live_vars info_down (MkCgState abs_c binds usage)
544 = freeStackSlots extra_free info_down (MkCgState abs_c (mkVarEnv bs') usage)
546 (dead_stk_slots, bs')
547 = dead_slots live_vars
549 [ (i, b) | b@(MkCgIdInfo i _ _ _) <- rngVarEnv binds ]
551 extra_free = sortLt (<) dead_stk_slots
554 Several boring auxiliary functions to do the dirty work.
557 dead_slots :: StgLiveVars
561 -> ([VirtualSpOffset], [(Id,CgIdInfo)])
563 -- dead_slots carries accumulating parameters for
564 -- filtered bindings, dead slots
565 dead_slots live_vars fbs ds []
566 = (ds, reverse fbs) -- Finished; rm the dups, if any
568 dead_slots live_vars fbs ds ((v,i):bs)
569 | v `elementOfUniqSet` live_vars
570 = dead_slots live_vars ((v,i):fbs) ds bs
571 -- Live, so don't record it in dead slots
572 -- Instead keep it in the filtered bindings
576 MkCgIdInfo _ _ stable_loc _
577 | is_stk_loc && size > 0 ->
578 dead_slots live_vars fbs ([offset-size+1 .. offset] ++ ds) bs
580 maybe_stk_loc = maybeStkLoc stable_loc
581 is_stk_loc = maybeToBool maybe_stk_loc
582 (Just offset) = maybe_stk_loc
584 _ -> dead_slots live_vars fbs ds bs
588 size = (getPrimRepSize . typePrimRep . idType) v