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 import Id ( Id, setIdCafInfo, getIdCafInfo, externallyVisibleId,
14 import IdInfo ( CafInfo(..) )
22 computeSRTs :: [StgBinding] -> [(StgBinding,[Id])]
23 computeSRTs binds = srtBinds emptyUFM binds
27 srtBinds :: UniqFM CafInfo -> [StgBinding] -> [(StgBinding,[Id])]
30 srtTopBind rho b =: \(b, srt, rho) ->
31 (b,srt) : srtBinds rho bs
34 -----------------------------------------------------------------------------
35 Circular algorithm for simultaneously figuring out CafInfo and SRT
38 Our functions have type
40 :: UniqFM CafInfo -- which top-level ids don't refer to any CAfs
41 -> SrtOffset -- next free offset within the SRT
42 {- * -} -> StgExpr -- expression to analyse
44 -> (StgExpr, -- (e) newly annotated expression
45 UniqSet Id, -- (g) set of *all* global references
46 [Id], -- (s) SRT required for this expression
47 SrtOffset) -- (o) new offset
49 (g) is a set containing all local top-level and imported ids referred
50 to by the expression (e).
52 The set of all global references is used to build the environment,
53 which is passed in again. The environment is used to build the final
56 We build a single SRT for a recursive binding group, which is why the
57 SRT building is done at the binding level rather than the
60 Hence, the only argument which we can look at before returning is the
61 expression (marked with {- * -} above).
63 The SRT is built up in reverse order, to avoid too many expensive
64 appends. We therefore reverse the SRT before returning it, so that
65 the offsets will be from the beginning of the SRT.
67 -----------------------------------------------------------------------------
70 The environment contains a mapping from local top-level bindings to
71 CafInfo. The CafInfo is either
73 NoCafRefs - indicating that the id is not a CAF and furthermore
74 that it doesn't refer, even indirectly, to any CAFs.
76 MayHaveCafRefs - everything else.
78 A function whose CafInfo is NoCafRefs will have an empty SRT, and its
79 closure will not appear in the SRT of any other function (unless we're
80 compiling without optimisation and the CafInfos haven't been emitted
81 in the interface files).
83 Top-Level recursive groups
85 This gets a bit complicated, but the general idea is that we want a
86 single SRT for the whole group, and we'd rather not have recursive
87 references in it if at all possible.
89 We collect all the global references for the group, and filter out
90 those that are binders in the group and not CAFs themselves. This set
91 of references is then used to infer the CafInfo for each of the
92 binders in the group. Why is it done this way?
94 - if all the bindings in the group just refer to each other,
95 and none of them are CAFs, we'd like to get an empty SRT.
97 - if any of the bindings in the group refer to a CAF, this will
100 Hmm, that probably makes no sense.
106 -> (StgBinding, -- the new binding
107 [Id], -- the SRT for this binding
108 UniqFM CafInfo) -- the new environment
110 srtTopBind rho (StgNonRec binder rhs) =
112 -- no need to use circularity for non-recursive bindings
113 srtRhs rho 0{-initial offset-} rhs =: \(rhs, g, srt, off) ->
115 filtered_g = filter (mayHaveCafRefs rho) (uniqSetToList g)
116 caf_info = mk_caf_info rhs filtered_g
117 binder' = setIdCafInfo binder caf_info
118 rho' = addToUFM rho binder' caf_info
119 extra_refs = filter (`notElem` srt) filtered_g
120 bind_srt = reverse (extra_refs ++ srt)
123 StgRhsClosure _ _ _ _ _ _ _ ->
124 (StgNonRec binder' (attach_srt_rhs rhs 0 (length bind_srt)),
127 -- don't output an SRT for the constructor, but just remember
128 -- whether it had any caf references or not.
129 StgRhsCon _ _ _ -> (StgNonRec binder' rhs, [], rho')
132 srtTopBind rho (StgRec bs) =
133 (attach_srt_bind (StgRec (reverse new_bs')) 0 (length bind_srt),
136 (binders,rhss) = unzip bs
138 non_caf_binders = [ b | (b, rhs) <- bs, not (caf_rhs rhs) ]
140 -- circular: rho' is calculated from g below
141 (new_bs, g, srt, _) = doBinds bs [] emptyUniqSet [] 0
143 -- filter out ourselves from the global references: it makes no
144 -- sense to refer recursively to our SRT unless the recursive
145 -- reference is required by a nested SRT.
146 filtered_g = filter (\id -> id `notElem` non_caf_binders &&
147 mayHaveCafRefs rho id) (uniqSetToList g)
148 extra_refs = filter (`notElem` srt) filtered_g
149 bind_srt = reverse (extra_refs ++ srt)
150 caf_infos = map (\rhs -> mk_caf_info rhs filtered_g) rhss
151 rho' = addListToUFM rho (zip binders caf_infos)
152 binders' = zipWith setIdCafInfo binders caf_infos
154 new_bs' = zip binders' (map snd new_bs)
156 doBinds [] new_binds g srt off = (reverse new_binds, g, srt, off)
157 doBinds ((binder,rhs):binds) new_binds g srt off =
158 srtRhs rho' off rhs =: \(rhs, rhs_g, rhs_srt, off) ->
160 g' = unionUniqSets rhs_g g
161 srt' = rhs_srt ++ srt
163 doBinds binds ((binder,rhs):new_binds) g' srt' off
165 caf_rhs (StgRhsClosure _ _ _ free_vars _ [] body) = True
169 -----------------------------------------------------------------------------
170 Non-top-level bindings
173 srtBind :: UniqFM CafInfo -> Int -> StgBinding
174 -> (StgBinding, UniqSet Id, [Id], Int)
176 srtBind rho off (StgNonRec binder rhs) =
177 srtRhs rho off rhs =: \(rhs, g, srt, off) ->
178 (StgNonRec binder rhs, g, srt, off)
180 srtBind rho off (StgRec binds) =
181 (StgRec new_binds, g, srt, new_off)
183 -- process each binding
184 (new_binds, g, srt, new_off) = doBinds binds emptyUniqSet [] off []
186 doBinds [] g srt off new_binds = (reverse new_binds, g, srt, off)
187 doBinds ((binder,rhs):binds) g srt off new_binds =
188 srtRhs rho off rhs =: \(rhs, g', srt', off) ->
189 doBinds binds (unionUniqSets g g') (srt'++srt) off
190 ((binder,rhs):new_binds)
193 -----------------------------------------------------------------------------
197 srtRhs :: UniqFM CafInfo -> Int -> StgRhs
198 -> (StgRhs, UniqSet Id, [Id], Int)
200 srtRhs rho off (StgRhsClosure cc bi old_srt free_vars u args body) =
201 srtExpr rho off body =: \(body, g, srt, off) ->
202 (StgRhsClosure cc bi old_srt free_vars u args body, g, srt, off)
204 srtRhs rho off e@(StgRhsCon cc con args) =
205 (e, getGlobalRefs rho args, [], off)
208 -----------------------------------------------------------------------------
212 srtExpr :: UniqFM CafInfo -> Int -> StgExpr
213 -> (StgExpr, UniqSet Id, [Id], Int)
215 srtExpr rho off e@(StgApp f args) =
216 (e, getGlobalRefs rho (StgVarArg f:args), [], off)
218 srtExpr rho off e@(StgCon con args ty) =
219 (e, getGlobalRefs rho args, [], off)
221 srtExpr rho off (StgCase scrut live1 live2 uniq _{-srt-} alts) =
222 srtCaseAlts rho off alts =: \(alts, alts_g, alts_srt, alts_off) ->
224 extra_refs = filter (`notElem` alts_srt)
225 (filter (mayHaveCafRefs rho) (uniqSetToList alts_g))
226 this_srt = extra_refs ++ alts_srt
227 scrut_off = alts_off + length extra_refs
229 srtExpr rho scrut_off scrut =: \(scrut, scrut_g, scrut_srt, case_off) ->
231 g = unionUniqSets alts_g scrut_g
232 srt = scrut_srt ++ this_srt
233 srt_info = case length this_srt of
237 (StgCase scrut live1 live2 uniq srt_info alts, g, srt, case_off)
239 srtExpr rho off (StgLet bind body) =
240 srtLet rho off bind body StgLet
242 -- let-no-escapes are delicate, see below
243 srtExpr rho off (StgLetNoEscape live1 live2 bind body) =
244 srtLet rho off bind body (StgLetNoEscape live1 live2)
245 =: \(expr, g, srt, off') ->
247 -- find the SRT for the *whole* expression
249 all_srt | length == 0 = NoSRT
250 | otherwise = SRT off length
252 (fixLNE_srt all_srt expr, g, srt, off')
254 srtExpr rho off (StgSCC cc expr) =
255 srtExpr rho off expr =: \(expr, g, srt, off) ->
256 (StgSCC cc expr, g, srt, off)
259 -----------------------------------------------------------------------------
262 This is quite complicated stuff...
265 srtLet rho off bind body let_constr
267 -- If the bindings are all constructors, then we don't need to
268 -- buid an SRT at all...
269 | all_con_binds bind =
270 srtBind rho off bind =: \(bind, bind_g, bind_srt, off) ->
271 srtExpr rho off body =: \(body, body_g, body_srt, off) ->
273 g = unionUniqSets bind_g body_g
274 srt = body_srt ++ bind_srt
276 (let_constr bind body, g, srt, off)
278 -- we have some closure bindings...
281 -- first, find the sub-SRTs in the binding
282 srtBind rho off bind =: \(bind, bind_g, bind_srt, bind_off) ->
284 -- Construct the SRT for this binding from its sub-SRTs and any new global
285 -- references which aren't already contained in one of the sub-SRTs (and
286 -- which are "live").
288 extra_refs = filter (`notElem` bind_srt)
289 (filter (mayHaveCafRefs rho) (uniqSetToList bind_g))
290 this_srt = extra_refs ++ bind_srt
292 -- Add the length of the new entries to the
293 -- current offset to get the next free offset in the global SRT.
294 body_off = bind_off + length extra_refs
297 -- now find the SRTs in the body
298 srtExpr rho body_off body =: \(body, body_g, body_srt, let_off) ->
301 -- union all the global references together
302 let_g = unionUniqSets bind_g body_g
304 -- concatenate the sub-SRTs
305 let_srt = body_srt ++ this_srt
307 -- attach the SRT info to the binding
308 bind' = attach_srt_bind bind off (length this_srt)
310 (let_constr bind' body, let_g, let_srt, let_off)
313 -----------------------------------------------------------------------------
317 srtCaseAlts :: UniqFM CafInfo -> Int -> StgCaseAlts ->
318 (StgCaseAlts, UniqSet Id, [Id], Int)
320 srtCaseAlts rho off (StgAlgAlts t alts dflt) =
321 srtAlgAlts rho off alts [] emptyUniqSet []
322 =: \(alts, alts_g, alts_srt, off) ->
323 srtDefault rho off dflt =: \(dflt, dflt_g, dflt_srt, off) ->
325 g = unionUniqSets alts_g dflt_g
326 srt = dflt_srt ++ alts_srt
328 (StgAlgAlts t alts dflt, g, srt, off)
330 srtCaseAlts rho off (StgPrimAlts t alts dflt) =
331 srtPrimAlts rho off alts [] emptyUniqSet []
332 =: \(alts, alts_g, alts_srt, off) ->
333 srtDefault rho off dflt =: \(dflt, dflt_g, dflt_srt, off) ->
335 g = unionUniqSets alts_g dflt_g
336 srt = dflt_srt ++ alts_srt
338 (StgPrimAlts t alts dflt, g, srt, off)
340 srtAlgAlts rho off [] new_alts g srt = (reverse new_alts, g, srt, off)
341 srtAlgAlts rho off ((con,args,used,rhs):alts) new_alts g srt =
342 srtExpr rho off rhs =: \(rhs, rhs_g, rhs_srt, off) ->
344 g' = unionUniqSets rhs_g g
345 srt' = rhs_srt ++ srt
347 srtAlgAlts rho off alts ((con,args,used,rhs) : new_alts) g' srt'
349 srtPrimAlts rho off [] new_alts g srt = (reverse new_alts, g, srt, off)
350 srtPrimAlts rho off ((lit,rhs):alts) new_alts g srt =
351 srtExpr rho off rhs =: \(rhs, rhs_g, rhs_srt, off) ->
353 g' = unionUniqSets rhs_g g
354 srt' = rhs_srt ++ srt
356 srtPrimAlts rho off alts ((lit,rhs) : new_alts) g' srt'
358 srtDefault rho off StgNoDefault = (StgNoDefault,emptyUniqSet,[],off)
359 srtDefault rho off (StgBindDefault rhs) =
360 srtExpr rho off rhs =: \(rhs, g, srt, off) ->
361 (StgBindDefault rhs, g, srt, off)
364 -----------------------------------------------------------------------------
366 Decide whether a closure looks like a CAF or not. In an effort to
367 keep the number of CAFs (and hence the size of the SRTs) down, we
368 would also like to look at the expression and decide whether it
369 requires a small bounded amount of heap, so we can ignore it as a CAF.
370 In these cases, we need to use an additional CAF list to keep track of
371 non-collectable CAFs.
373 We mark real CAFs as `MayHaveCafRefs' because this information is used
374 to decide whether a particular closure needs to be referenced in an
379 :: StgRhs -- right-hand-side of the definition
380 -> [Id] -- static references
383 -- special case for expressions which are always bottom,
384 -- such as 'error "..."'. We don't need to record it as
385 -- a CAF, since it can only be entered once.
386 mk_caf_info (StgRhsClosure _ _ _ free_vars _ [] e) srt
387 | isBottomingExpr e && null srt = NoCafRefs
389 mk_caf_info (StgRhsClosure _ _ _ free_vars upd args body) srt
390 | isUpdatable upd = MayHaveCafRefs -- a real live CAF
391 | null srt = NoCafRefs -- function w/ no static references
392 | otherwise = MayHaveCafRefs -- function w/ some static references
394 mk_caf_info (StgRhsCon cc con args) srt
395 | null srt = NoCafRefs -- constructor w/ no static references
396 | otherwise = MayHaveCafRefs -- otherwise, treat as a CAF
398 isBottomingExpr (StgLet bind expr) = isBottomingExpr expr
399 isBottomingExpr (StgApp f args) = isBottomingId f
400 isBottomingExpr _ = False
403 -----------------------------------------------------------------------------
405 Here we decide which Id's to place in the static reference table. An
406 internal top-level id will be in the environment with the appropriate
407 CafInfo, so we use that if available. An imported top-level Id will
408 have the CafInfo attached. Otherwise, we just ignore the Id.
411 getGlobalRefs :: UniqFM CafInfo -> [StgArg] -> UniqSet Id
412 getGlobalRefs rho args = mkUniqSet (concat (map (globalRefArg rho) args))
414 globalRefArg :: UniqFM CafInfo -> StgArg -> [Id]
416 globalRefArg rho (StgVarArg id)
419 case lookupUFM rho id of {
420 Just _ -> [id]; -- can't look at the caf_info yet...
423 if externallyVisibleId id
424 then case getIdCafInfo id of
425 MayHaveCafRefs -> [id]
430 globalRefArg rho _ = []
434 mayHaveCafRefs rho id =
435 case lookupUFM rho id of
436 Just MayHaveCafRefs -> True
437 Just NoCafRefs -> False
441 -----------------------------------------------------------------------------
445 attach_srt_bind :: StgBinding -> Int -> Int -> StgBinding
446 attach_srt_bind (StgNonRec binder rhs) off len =
447 StgNonRec binder (attach_srt_rhs rhs off len)
448 attach_srt_bind (StgRec binds) off len =
449 StgRec [ (v,attach_srt_rhs rhs off len) | (v,rhs) <- binds ]
451 attach_srt_rhs :: StgRhs -> Int -> Int -> StgRhs
452 attach_srt_rhs (StgRhsCon cc con args) off length
453 = StgRhsCon cc con args
454 attach_srt_rhs (StgRhsClosure cc bi _ free upd args rhs) off length
455 = StgRhsClosure cc bi srt free upd args rhs
457 srt | length == 0 = NoSRT
458 | otherwise = SRT off length
461 all_con_binds (StgNonRec x rhs) = con_rhs rhs
462 all_con_binds (StgRec bs) = all con_rhs (map snd bs)
464 con_rhs (StgRhsCon _ _ _) = True
471 -----------------------------------------------------------------------------
472 Fix up the SRT's in a let-no-escape.
474 (for a description of let-no-escapes, see CgLetNoEscape.lhs)
476 Here's the problem: a let-no-escape isn't represented by an activation
477 record on the stack. It seems either very difficult or impossible to
478 get the liveness bitmap right in the info table, so we don't do it
479 this way (the liveness mask isn't constant).
481 So, the question is how does the garbage collector get access to the
482 SRT for the rhs of the let-no-escape? It can't see an info table, so
483 it must get the SRT from somewhere else. Here's an example:
485 let-no-escape x = .... f ....
487 p -> .... x ... g ....
489 (f and g are global). Suppose we garbage collect while evaluating
490 'blah'. The stack will contain an activation record for the case,
491 which will point to an SRT containing [g] (according to our SRT
492 algorithm above). But, since the case continuation can call x, and
493 hence f, the SRT should really be [f,g].
497 let-no-escape {-rec-} z = \x -> case blah of
503 if we GC while evaluating blah2, then the case continuation on the
504 stack needs to refer to [f] in its SRT, because we can reach f by
505 calling z recursively.
509 The following code fixes up a let-no-escape expression after we've run
510 the SRT algorithm. It needs to know the SRT for the *whole*
511 expression (this is plugged in instead of the SRT for case exprsesions
512 in the body). The good news is that we only need to traverse nested
513 case expressions, since the let-no-escape bound variable can't occur
514 in the rhs of a let or in a case scrutinee.
516 For recursive let-no-escapes, the body is processed as for
517 non-recursive let-no-escapes, but case expressions in the rhs of each
518 binding have their SRTs replaced with the SRT for the binding group
519 (*not* the SRT of the whole let-no-escape expression).
522 fixLNE_srt :: SRT -> StgExpr -> StgExpr
523 fixLNE_srt all_srt (StgLetNoEscape live1 live2 (StgNonRec id rhs) body)
524 = StgLetNoEscape live1 live2 (StgNonRec id rhs) (fixLNE [id] all_srt body)
526 fixLNE_srt all_srt (StgLetNoEscape live1 live2 (StgRec pairs) body)
527 = StgLetNoEscape live1 live2
528 (StgRec (map fixLNE_rec pairs)) (fixLNE binders all_srt body)
530 binders = map fst pairs
531 fixLNE_rec (id,StgRhsClosure cc bi srt fvs uf args e) =
532 (id, StgRhsClosure cc bi srt fvs uf args (fixLNE binders srt e))
533 fixLNE_rec (id,con) = (id,con)
535 fixLNE :: [Id] -> SRT -> StgExpr -> StgExpr
537 fixLNE ids srt expr@(StgCase scrut live rhs_live bndr old_srt alts)
538 | any (`elementOfUniqSet` rhs_live) ids
539 = StgCase scrut live rhs_live bndr srt (fixLNE_alts ids srt alts)
541 -- can't be in the scrutinee, because it's a let-no-escape!
543 fixLNE ids srt expr@(StgLetNoEscape live rhs_live bind body)
544 | any (`elementOfUniqSet` rhs_live) ids =
545 StgLetNoEscape live rhs_live (fixLNE_bind ids srt bind)
546 (fixLNE ids srt body)
547 | any (`elementOfUniqSet` live) ids =
548 StgLetNoEscape live rhs_live bind (fixLNE ids srt body)
551 fixLNE ids srt (StgLet bind body) = StgLet bind (fixLNE ids srt body)
552 fixLNE ids srt (StgSCC cc expr) = StgSCC cc (fixLNE ids srt expr)
553 fixLNE ids srt expr = expr
555 fixLNE_alts ids srt (StgAlgAlts t alts dflt)
556 = StgAlgAlts t (map (fixLNE_algalt ids srt) alts) (fixLNE_dflt ids srt dflt)
558 fixLNE_alts ids srt (StgPrimAlts t alts dflt)
559 = StgPrimAlts t (map (fixLNE_primalt ids srt) alts) (fixLNE_dflt ids srt dflt)
561 fixLNE_algalt ids srt (con,args,used,rhs) = (con,args,used, fixLNE ids srt rhs)
562 fixLNE_primalt ids srt (lit,rhs) = (lit, fixLNE ids srt rhs)
564 fixLNE_dflt ids srt (StgNoDefault) = StgNoDefault
565 fixLNE_dflt ids srt (StgBindDefault rhs) = StgBindDefault (fixLNE ids srt rhs)
567 fixLNE_bind ids srt (StgNonRec bndr rhs)
568 = StgNonRec bndr (fixLNE_rhs ids srt rhs)
569 fixLNE_bind ids srt (StgRec pairs)
570 = StgRec [ (bndr, fixLNE_rhs ids srt rhs) | (bndr,rhs) <- pairs ]
572 fixLNE_rhs ids srt rhs@(StgRhsClosure cc bi old_srt fvs uf args expr)
573 | any (`elem` fvs) ids
574 = StgRhsClosure cc bi srt fvs uf args (fixLNE ids srt expr)
576 fixLNE_rhs ids srt rhs@(StgRhsCon cc con args) = rhs