2 % (c) The GRASP/AQUA Project, Glasgow University, 1998
5 Run through the STG code and compute the Static Reference Table for
6 each let-binding. At the same time, we figure out which top-level
7 bindings have no CAF references, and record the fact in their IdInfo.
12 #include "HsVersions.h"
14 import Id ( Id, idCafInfo )
15 import IdInfo ( CafInfo(..) )
28 computeSRTs :: [StgBinding] -> [(StgBinding,[Id])]
29 computeSRTs binds = map srtTopBind binds
32 -----------------------------------------------------------------------------
33 Algorithm for figuring out SRT layout.
35 Our functions have type
37 :: SrtOffset -- next free offset within the SRT
38 -> (UniqSet Id, -- global refs in the continuation
39 UniqFM (UniqSet Id))-- global refs in let-no-escaped variables
40 {- * -} -> StgExpr -- expression to analyse
42 -> (StgExpr, -- (e) newly annotated expression
43 UniqSet Id, -- (g) global refs from this expression
44 [Id], -- (s) SRT required for this expression
45 SrtOffset) -- (o) new offset
47 (g) is a set containing all local top-level and imported ids referred
48 to by the expression (e), which have MayHaveCafRefs in their CafInfo.
50 We build a single SRT for a recursive binding group, which is why the
51 SRT building is done at the binding level rather than the
54 The SRT is built up in reverse order, to avoid too many expensive
55 appends. We therefore reverse the SRT before returning it, so that
56 the offsets will be from the beginning of the SRT.
58 -----------------------------------------------------------------------------
61 A function whose CafInfo is NoCafRefs will have an empty SRT, and its
62 closure will not appear in the SRT of any other function (unless we're
63 compiling without optimisation and the CafInfos haven't been emitted
64 in the interface files).
66 Top-Level recursive groups
68 This gets a bit complicated, but the general idea is that we want a
69 single SRT for the whole group, and we'd rather not have recursive
70 references in it if at all possible.
72 We collect all the global references for the group, and filter out
73 those that are binders in the group and not CAFs themselves. Why is
76 - if all the bindings in the group just refer to each other,
77 and none of them are CAFs, we'd like to get an empty SRT.
79 - if any of the bindings in the group refer to a CAF, this will
82 Hmm, that probably makes no sense.
87 -> (StgBinding, -- the new binding
88 [Id]) -- the SRT for this binding
90 srtTopBind (StgNonRec binder rhs) =
92 -- no need to use circularity for non-recursive bindings
93 srtRhs (emptyUniqSet,emptyUFM) 0{-initial offset-} rhs
94 =: \(rhs, g, srt, off) ->
96 filtered_g = uniqSetToList g
97 extra_refs = filter (`notElem` srt) filtered_g
98 bind_srt = reverse (extra_refs ++ srt)
100 ASSERT2(null bind_srt || mayHaveCafRefs binder, ppr binder)
103 StgRhsClosure _ _ _ _ _ _ _ ->
104 (StgNonRec binder (attach_srt_rhs rhs 0 (length bind_srt)),
107 -- don't output an SRT for the constructor
108 StgRhsCon _ _ _ -> (StgNonRec binder rhs, [])
111 srtTopBind (StgRec bs) =
112 ASSERT(null bind_srt || all mayHaveCafRefs binders)
113 (attach_srt_bind (StgRec new_bs) 0 (length bind_srt), bind_srt)
115 (binders,rhss) = unzip bs
117 non_caf_binders = [ b | (b, rhs) <- bs, not (caf_rhs rhs) ]
119 (new_bs, g, srt, _) = doBinds bs [] emptyUniqSet [] 0
121 -- filter out ourselves from the global references: it makes no
122 -- sense to refer recursively to our SRT unless the recursive
123 -- reference is required by a nested SRT.
124 filtered_g = filter (\id -> id `notElem` non_caf_binders) (uniqSetToList g)
125 extra_refs = filter (`notElem` srt) filtered_g
126 bind_srt = reverse (extra_refs ++ srt)
128 doBinds [] new_binds g srt off = (reverse new_binds, g, srt, off)
129 doBinds ((binder,rhs):binds) new_binds g srt off =
130 srtRhs (emptyUniqSet,emptyUFM) off rhs
131 =: \(rhs, rhs_g, rhs_srt, off) ->
133 g' = unionUniqSets rhs_g g
134 srt' = rhs_srt ++ srt
136 doBinds binds ((binder,rhs):new_binds) g' srt' off
138 caf_rhs (StgRhsClosure _ _ _ free_vars _ [] body) = True
142 -----------------------------------------------------------------------------
143 Non-top-level bindings
146 srtBind :: (UniqSet Id, UniqFM (UniqSet Id))
147 -> Int -> StgBinding -> (StgBinding, UniqSet Id, [Id], Int)
149 srtBind cont_refs off (StgNonRec binder rhs) =
150 srtRhs cont_refs off rhs =: \(rhs, g, srt, off) ->
151 (StgNonRec binder rhs, g, srt, off)
153 srtBind cont_refs off (StgRec binds) =
154 (StgRec new_binds, g, srt, new_off)
156 -- process each binding
157 (new_binds, g, srt, new_off) = doBinds binds emptyUniqSet [] off []
159 doBinds [] g srt off new_binds = (reverse new_binds, g, srt, off)
160 doBinds ((binder,rhs):binds) g srt off new_binds =
161 srtRhs cont_refs off rhs =: \(rhs, g', srt', off) ->
162 doBinds binds (unionUniqSets g g') (srt'++srt) off
163 ((binder,rhs):new_binds)
166 -----------------------------------------------------------------------------
170 srtRhs :: (UniqSet Id, UniqFM (UniqSet Id))
171 -> Int -> StgRhs -> (StgRhs, UniqSet Id, [Id], Int)
173 srtRhs cont off (StgRhsClosure cc bi old_srt free_vars u args body) =
174 srtExpr cont off body =: \(body, g, srt, off) ->
175 (StgRhsClosure cc bi old_srt free_vars u args body, g, srt, off)
177 srtRhs cont off e@(StgRhsCon cc con args) =
178 (e, getGlobalRefs args, [], off)
181 -----------------------------------------------------------------------------
185 srtExpr :: (UniqSet Id, UniqFM (UniqSet Id))
186 -> Int -> StgExpr -> (StgExpr, UniqSet Id, [Id], Int)
188 srtExpr (cont,lne) off e@(StgApp f args) = (e, global_refs, [], off)
191 getGlobalRefs (StgVarArg f:args) `unionUniqSets`
192 lookupPossibleLNE lne f
194 srtExpr (cont,lne) off e@(StgLit l) = (e, cont, [], off)
196 srtExpr (cont,lne) off e@(StgConApp con args) =
197 (e, cont `unionUniqSets` getGlobalRefs args, [], off)
199 srtExpr (cont,lne) off e@(StgPrimApp op args ty) =
200 (e, cont `unionUniqSets` getGlobalRefs args, [], off)
202 srtExpr c@(cont,lne) off (StgCase scrut live1 live2 uniq _{-srt-} alts) =
203 srtCaseAlts c off alts =: \(alts, alts_g, alts_srt, alts_off) ->
205 -- construct the SRT for this case
206 let (this_srt, scrut_off) = construct_srt alts_g alts_srt alts_off in
208 -- global refs in the continuation is alts_g.
209 srtExpr (alts_g,lne) scrut_off scrut
210 =: \(scrut, scrut_g, scrut_srt, case_off) ->
212 g = unionUniqSets alts_g scrut_g
213 srt = scrut_srt ++ this_srt
214 srt_info = case length this_srt of
218 (StgCase scrut live1 live2 uniq srt_info alts, g, srt, case_off)
220 srtExpr cont off (StgLet bind body) =
221 srtLet cont off bind body StgLet (\_ cont -> cont)
223 srtExpr cont off (StgLetNoEscape live1 live2 b@(StgNonRec bndr rhs) body)
224 = srtLet cont off b body (StgLetNoEscape live1 live2) calc_cont
225 where calc_cont g (cont,lne) = (cont,addToUFM lne bndr g)
227 -- for recursive let-no-escapes, we do *two* passes, the first time
228 -- just to extract the list of global refs, and the second time we actually
229 -- construct the SRT now that we know what global refs should be in
230 -- the various let-no-escape continuations.
231 srtExpr conts@(cont,lne) off
232 (StgLetNoEscape live1 live2 bind@(StgRec pairs) body)
233 = srtBind conts off bind =: \(_, g, _, _) ->
235 lne' = addListToUFM lne [ (bndr,g) | (bndr,_) <- pairs ]
236 calc_cont _ conts = conts
238 srtLet (cont,lne') off bind body (StgLetNoEscape live1 live2) calc_cont
241 srtExpr cont off (StgSCC cc expr) =
242 srtExpr cont off expr =: \(expr, g, srt, off) ->
243 (StgSCC cc expr, g, srt, off)
246 srtExpr cont off expr = pprPanic "srtExpr" (ppr expr)
248 srtExpr cont off expr = panic "srtExpr"
252 -----------------------------------------------------------------------------
255 This is quite complicated stuff...
258 srtLet cont off bind body let_constr calc_cont
260 -- If the bindings are all constructors, then we don't need to
261 -- buid an SRT at all...
262 | all_con_binds bind =
263 srtBind cont off bind =: \(bind, bind_g, bind_srt, off) ->
264 srtExpr cont off body =: \(body, body_g, body_srt, off) ->
266 g = unionUniqSets bind_g body_g
267 srt = body_srt ++ bind_srt
269 (let_constr bind body, g, srt, off)
271 -- we have some closure bindings...
274 -- first, find the sub-SRTs in the binding
275 srtBind cont off bind =: \(bind, bind_g, bind_srt, bind_off) ->
277 -- construct the SRT for this binding
278 let (this_srt, body_off) = construct_srt bind_g bind_srt bind_off in
280 -- get the new continuation information (if a let-no-escape)
281 let new_cont = calc_cont bind_g cont in
283 -- now find the SRTs in the body
284 srtExpr new_cont body_off body =: \(body, body_g, body_srt, let_off) ->
287 -- union all the global references together
288 let_g = unionUniqSets bind_g body_g
290 -- concatenate the sub-SRTs
291 let_srt = body_srt ++ this_srt
293 -- attach the SRT info to the binding
294 bind' = attach_srt_bind bind off (length this_srt)
296 (let_constr bind' body, let_g, let_srt, let_off)
299 -----------------------------------------------------------------------------
302 Construct the SRT at this point from its sub-SRTs and any new global
303 references which aren't already contained in one of the sub-SRTs (and
307 construct_srt global_refs sub_srt current_offset
309 extra_refs = filter (`notElem` sub_srt) (uniqSetToList global_refs)
310 this_srt = extra_refs ++ sub_srt
312 -- Add the length of the new entries to the
313 -- current offset to get the next free offset in the global SRT.
314 new_offset = current_offset + length extra_refs
315 in (this_srt, new_offset)
318 -----------------------------------------------------------------------------
322 srtCaseAlts :: (UniqSet Id, UniqFM (UniqSet Id))
323 -> Int -> StgCaseAlts -> (StgCaseAlts, UniqSet Id, [Id], Int)
325 srtCaseAlts cont off (StgAlgAlts t alts dflt) =
326 srtAlgAlts cont off alts [] emptyUniqSet []
327 =: \(alts, alts_g, alts_srt, off) ->
328 srtDefault cont off dflt =: \(dflt, dflt_g, dflt_srt, off) ->
330 g = unionUniqSets alts_g dflt_g
331 srt = dflt_srt ++ alts_srt
333 (StgAlgAlts t alts dflt, g, srt, off)
335 srtCaseAlts cont off (StgPrimAlts t alts dflt) =
336 srtPrimAlts cont off alts [] emptyUniqSet []
337 =: \(alts, alts_g, alts_srt, off) ->
338 srtDefault cont off dflt =: \(dflt, dflt_g, dflt_srt, off) ->
340 g = unionUniqSets alts_g dflt_g
341 srt = dflt_srt ++ alts_srt
343 (StgPrimAlts t alts dflt, g, srt, off)
345 srtAlgAlts cont off [] new_alts g srt = (reverse new_alts, g, srt, off)
346 srtAlgAlts cont off ((con,args,used,rhs):alts) new_alts g srt =
347 srtExpr cont off rhs =: \(rhs, rhs_g, rhs_srt, off) ->
349 g' = unionUniqSets rhs_g g
350 srt' = rhs_srt ++ srt
352 srtAlgAlts cont off alts ((con,args,used,rhs) : new_alts) g' srt'
354 srtPrimAlts cont off [] new_alts g srt = (reverse new_alts, g, srt, off)
355 srtPrimAlts cont off ((lit,rhs):alts) new_alts g srt =
356 srtExpr cont off rhs =: \(rhs, rhs_g, rhs_srt, off) ->
358 g' = unionUniqSets rhs_g g
359 srt' = rhs_srt ++ srt
361 srtPrimAlts cont off alts ((lit,rhs) : new_alts) g' srt'
363 srtDefault cont off StgNoDefault = (StgNoDefault,emptyUniqSet,[],off)
364 srtDefault cont off (StgBindDefault rhs) =
365 srtExpr cont off rhs =: \(rhs, g, srt, off) ->
366 (StgBindDefault rhs, g, srt, off)
369 -----------------------------------------------------------------------------
371 Here we decide which Id's to place in the static reference table. An
372 internal top-level id will be in the environment with the appropriate
373 CafInfo, so we use that if available. An imported top-level Id will
374 have the CafInfo attached. Otherwise, we just ignore the Id.
377 getGlobalRefs :: [StgArg] -> UniqSet Id
378 getGlobalRefs args = mkUniqSet (concat (map globalRefArg args))
380 globalRefArg :: StgArg -> [Id]
381 globalRefArg (StgVarArg id)
382 | mayHaveCafRefs id = [id]
387 = case idCafInfo id of
388 MayHaveCafRefs -> True
392 -----------------------------------------------------------------------------
396 attach_srt_bind :: StgBinding -> Int -> Int -> StgBinding
397 attach_srt_bind (StgNonRec binder rhs) off len =
398 StgNonRec binder (attach_srt_rhs rhs off len)
399 attach_srt_bind (StgRec binds) off len =
400 StgRec [ (v,attach_srt_rhs rhs off len) | (v,rhs) <- binds ]
402 attach_srt_rhs :: StgRhs -> Int -> Int -> StgRhs
403 attach_srt_rhs (StgRhsCon cc con args) off length
404 = StgRhsCon cc con args
405 attach_srt_rhs (StgRhsClosure cc bi _ free upd args rhs) off length
406 = StgRhsClosure cc bi srt free upd args rhs
408 srt | length == 0 = NoSRT
409 | otherwise = SRT off length
412 all_con_binds (StgNonRec x rhs) = con_rhs rhs
413 all_con_binds (StgRec bs) = all con_rhs (map snd bs)
415 con_rhs (StgRhsCon _ _ _) = True
422 -----------------------------------------------------------------------------
423 Fix up the SRT's in a let-no-escape.
425 (for a description of let-no-escapes, see CgLetNoEscape.lhs)
427 Here's the problem: a let-no-escape isn't represented by an activation
428 record on the stack. It seems either very difficult or impossible to
429 get the liveness bitmap right in the info table, so we don't do it
430 this way (the liveness mask isn't constant).
432 So, the question is how does the garbage collector get access to the
433 SRT for the rhs of the let-no-escape? It can't see an info table, so
434 it must get the SRT from somewhere else. Here's an example:
436 let-no-escape x = .... f ....
438 p -> .... x ... g ....
440 (f and g are global). Suppose we garbage collect while evaluating
441 'blah'. The stack will contain an activation record for the case,
442 which will point to an SRT containing [g] (according to our SRT
443 algorithm above). But, since the case continuation can call x, and
444 hence f, the SRT should really be [f,g].
448 let-no-escape {-rec-} z = \x -> case blah of
454 if we GC while evaluating blah2, then the case continuation on the
455 stack needs to refer to [f] in its SRT, because we can reach f by
456 calling z recursively.
460 We keep track of the global references made by each let-no-escape in
461 scope, so we can expand them every time the let-no-escape is
465 lookupPossibleLNE lne_env f =
466 case lookupUFM lne_env f of
467 Nothing -> emptyUniqSet