2 % (c) The GRASP/AQUA Project, Glasgow University, 1992-1996
4 %************************************************************************
6 \section[FloatIn]{Floating Inwards pass}
8 %************************************************************************
10 The main purpose of @floatInwards@ is floating into branches of a
11 case, so that we don't allocate things, save them on the stack, and
12 then discover that they aren't needed in the chosen branch.
15 #include "HsVersions.h"
20 -- and to make the interface self-sufficient...
29 import Id ( emptyIdSet, unionIdSets, unionManyIdSets,
30 elementOfIdSet, IdSet(..)
35 Top-level interface function, @floatInwards@. Note that we do not
36 actually float any bindings downwards from the top-level.
39 floatInwards :: [CoreBinding] -> [CoreBinding]
42 = map fi_top_bind binds
44 fi_top_bind (NonRec binder rhs)
45 = NonRec binder (fiExpr [] (freeVars rhs))
46 fi_top_bind (Rec pairs)
47 = Rec [ (b, fiExpr [] (freeVars rhs)) | (b, rhs) <- pairs ]
50 %************************************************************************
52 \subsection{Mail from Andr\'e [edited]}
54 %************************************************************************
56 {\em Will wrote: What??? I thought the idea was to float as far
57 inwards as possible, no matter what. This is dropping all bindings
58 every time it sees a lambda of any kind. Help! }
60 You are assuming we DO DO full laziness AFTER floating inwards! We
61 have to [not float inside lambdas] if we don't.
63 If we indeed do full laziness after the floating inwards (we could
64 check the compilation flags for that) then I agree we could be more
65 aggressive and do float inwards past lambdas.
67 Actually we are not doing a proper full laziness (see below), which
68 was another reason for not floating inwards past a lambda.
70 This can easily be fixed.
71 The problem is that we float lets outwards,
72 but there are a few expressions which are not
73 let bound, like case scrutinees and case alternatives.
74 After floating inwards the simplifier could decide to inline
75 the let and the laziness would be lost, e.g.
77 let a = expensive ==> \b -> case expensive of ...
78 in \ b -> case a of ...
83 to let bind the algebraic case scrutinees (done, I think) and
84 the case alternatives (except the ones with an
85 unboxed type)(not done, I think). This is best done in the
86 SetLevels.lhs module, which tags things with their level numbers.
88 do the full laziness pass (floating lets outwards).
90 simplify. The simplifier inlines the (trivial) lets that were
91 created but were not floated outwards.
94 With the fix I think Will's suggestion that we can gain even more from
95 strictness by floating inwards past lambdas makes sense.
97 We still gain even without going past lambdas, as things may be
98 strict in the (new) context of a branch (where it was floated to) or
101 let a = something case x of
102 in case x of alt1 -> case something of a -> a + a
103 alt1 -> a + a ==> alt2 -> b
106 let a = something let b = case something of a -> a + a
107 in let b = a + a ==> in (b,b)
110 Also, even if a is not found to be strict in the new context and is
111 still left as a let, if the branch is not taken (or b is not entered)
112 the closure for a is not built.
114 %************************************************************************
116 \subsection{Main floating-inwards code}
118 %************************************************************************
121 type FreeVarsSet = IdSet
123 type FloatingBinds = [(CoreBinding, FreeVarsSet)]
124 -- In dependency order (outermost first)
126 -- The FreeVarsSet is the free variables of the binding. In the case
127 -- of recursive bindings, the set doesn't include the bound
130 fiExpr :: FloatingBinds -- binds we're trying to drop
131 -- as far "inwards" as possible
132 -> CoreExprWithFVs -- input expr
133 -> CoreExpr -- result
135 fiExpr to_drop (_,AnnVar v) = mkCoLets' to_drop (Var v)
137 fiExpr to_drop (_,AnnLit k) = mkCoLets' to_drop (Lit k)
139 fiExpr to_drop (_,AnnCon c atoms)
140 = mkCoLets' to_drop (Con c atoms)
142 fiExpr to_drop (_,AnnPrim c atoms)
143 = mkCoLets' to_drop (Prim c atoms)
146 Here we are not floating inside lambda (type lambdas are OK):
148 fiExpr to_drop (_,AnnLam (UsageBinder binder) body)
149 = panic "FloatIn.fiExpr:AnnLam UsageBinder"
151 fiExpr to_drop (_,AnnLam b@(ValBinder binder) body)
152 = mkCoLets' to_drop (Lam b (fiExpr [] body))
154 fiExpr to_drop (_,AnnLam b@(TyBinder tyvar) body)
156 -- we do not float into type lambdas if they are followed by
157 -- a whnf (actually we check for lambdas and constructors).
158 -- The reason is that a let binding will get stuck
159 -- in between the type lambda and the whnf and the simplifier
160 -- does not know how to pull it back out from a type lambda.
163 -- in let f = /\t -> \a -> ...
165 -- let f = /\t -> let v = ... in \a -> ...
166 -- which is bad as now f is an updatable closure (update PAP)
167 -- and has arity 0. This example comes from cichelli.
169 = mkCoLets' to_drop (Lam b (fiExpr [] body))
171 = Lam b (fiExpr to_drop body)
173 whnf :: CoreExprWithFVs -> Bool
175 whnf (_,AnnLit _) = True
176 whnf (_,AnnCon _ _) = True
177 whnf (_,AnnLam (ValBinder _) _) = True
178 whnf (_,AnnLam _ e) = whnf e
179 whnf (_,AnnSCC _ e) = whnf e
183 Applications: we could float inside applications, but it's probably
184 not worth it (a purely practical choice, hunch- [not experience-]
187 fiExpr to_drop (_,AnnApp fun arg)
189 = mkCoLets' to_drop (App (fiExpr [] fun) arg)
191 = App (fiExpr to_drop fun) arg
194 We don't float lets inwards past an SCC.
196 ToDo: SCC: {\em should} keep info on current cc, and when passing
197 one, if it is not the same, annotate all lets in binds with current
198 cc, change current cc to the new one and float binds into expr.
200 fiExpr to_drop (_, AnnSCC cc expr)
201 = mkCoLets' to_drop (SCC cc (fiExpr [] expr))
204 For @Lets@, the possible ``drop points'' for the \tr{to_drop}
205 bindings are: (a)~in the body, (b1)~in the RHS of a NonRec binding,
206 or~(b2), in each of the RHSs of the pairs of a @Rec@.
208 Note that we do {\em weird things} with this let's binding. Consider:
217 Look at the inner \tr{let}. As \tr{w} is used in both the bind and
218 body of the inner let, we could panic and leave \tr{w}'s binding where
219 it is. But \tr{v} is floatable into the body of the inner let, and
220 {\em then} \tr{w} will also be only in the body of that inner let.
222 So: rather than drop \tr{w}'s binding here, we add it onto the list of
223 things to drop in the outer let's body, and let nature take its
227 fiExpr to_drop (_,AnnLet (AnnNonRec id rhs) body)
228 = fiExpr new_to_drop body
230 rhs_fvs = freeVarsOf rhs
231 body_fvs = freeVarsOf body
233 ([rhs_binds, body_binds], shared_binds) = sepBindsByDropPoint [rhs_fvs, body_fvs] to_drop
235 new_to_drop = body_binds ++ -- the bindings used only in the body
236 [(NonRec id rhs', rhs_fvs')] ++ -- the new binding itself
237 shared_binds -- the bindings used both in rhs and body
239 -- Push rhs_binds into the right hand side of the binding
240 rhs' = fiExpr rhs_binds rhs
241 rhs_fvs' = rhs_fvs `unionIdSets` floatedBindsFVs rhs_binds
243 fiExpr to_drop (_,AnnLet (AnnRec bindings) body)
244 = fiExpr new_to_drop body
246 (binders, rhss) = unzip bindings
248 rhss_fvs = map freeVarsOf rhss
249 body_fvs = freeVarsOf body
251 (body_binds:rhss_binds, shared_binds)
252 = sepBindsByDropPoint (body_fvs:rhss_fvs) to_drop
254 new_to_drop = -- the bindings used only in the body
256 -- the new binding itself
257 [(Rec (fi_bind rhss_binds bindings), rhs_fvs')] ++
258 -- the bindings used both in rhs and body or in more than one rhs
261 rhs_fvs' = unionIdSets (unionManyIdSets rhss_fvs)
262 (unionManyIdSets (map floatedBindsFVs rhss_binds))
264 -- Push rhs_binds into the right hand side of the binding
265 fi_bind :: [FloatingBinds] -- one per "drop pt" conjured w/ fvs_of_rhss
266 -> [(Id, CoreExprWithFVs)]
269 fi_bind to_drops pairs
270 = [ (binder, fiExpr to_drop rhs) | ((binder, rhs), to_drop) <- zip pairs to_drops ]
273 For @Case@, the possible ``drop points'' for the \tr{to_drop}
274 bindings are: (a)~inside the scrutinee, (b)~inside one of the
275 alternatives/default [default FVs always {\em first}!].
278 fiExpr to_drop (_, AnnCase scrut alts)
280 fvs_scrut = freeVarsOf scrut
281 drop_pts_fvs = fvs_scrut : (get_fvs_from_deflt_and_alts alts)
283 case (sepBindsByDropPoint drop_pts_fvs to_drop)
284 of (scrut_drops : deflt_drops : alts_drops, drop_here) ->
285 mkCoLets' drop_here (Case (fiExpr scrut_drops scrut)
286 (fi_alts deflt_drops alts_drops alts))
289 ----------------------------
290 -- pin default FVs on first!
292 get_fvs_from_deflt_and_alts (AnnAlgAlts alts deflt)
293 = get_deflt_fvs deflt : [ freeVarsOf rhs | (_, _, rhs) <- alts ]
295 get_fvs_from_deflt_and_alts (AnnPrimAlts alts deflt)
296 = get_deflt_fvs deflt : [ freeVarsOf rhs | (_, rhs) <- alts]
298 get_deflt_fvs AnnNoDefault = emptyIdSet
299 get_deflt_fvs (AnnBindDefault b rhs) = freeVarsOf rhs
301 ----------------------------
302 fi_alts to_drop_deflt to_drop_alts (AnnAlgAlts alts deflt)
304 [ (con, params, fiExpr to_drop rhs)
305 | ((con, params, rhs), to_drop) <- alts `zip` to_drop_alts ]
306 (fi_default to_drop_deflt deflt)
308 fi_alts to_drop_deflt to_drop_alts (AnnPrimAlts alts deflt)
310 [ (lit, fiExpr to_drop rhs)
311 | ((lit, rhs), to_drop) <- alts `zip` to_drop_alts ]
312 (fi_default to_drop_deflt deflt)
314 fi_default to_drop AnnNoDefault = NoDefault
315 fi_default to_drop (AnnBindDefault b e) = BindDefault b (fiExpr to_drop e)
318 %************************************************************************
320 \subsection{@sepBindsByDropPoint@}
322 %************************************************************************
324 This is the crucial function. The idea is: We have a wad of bindings
325 that we'd like to distribute inside a collection of {\em drop points};
326 insides the alternatives of a \tr{case} would be one example of some
327 drop points; the RHS and body of a non-recursive \tr{let} binding
328 would be another (2-element) collection.
330 So: We're given a list of sets-of-free-variables, one per drop point,
331 and a list of floating-inwards bindings. If a binding can go into
332 only one drop point (without suddenly making something out-of-scope),
333 in it goes. If a binding is used inside {\em multiple} drop points,
334 then it has to go in a you-must-drop-it-above-all-these-drop-points
337 We have to maintain the order on these drop-point-related lists.
341 :: [FreeVarsSet] -- one set of FVs per drop point
342 -> FloatingBinds -- candidate floaters
343 -> ([FloatingBinds], -- floaters that *can* be floated into
344 -- the corresponding drop point
345 FloatingBinds) -- everything else, bindings which must
346 -- not be floated inside any drop point
348 sepBindsByDropPoint drop_pts []
349 = ([[] | p <- drop_pts], []) -- cut to the chase scene; it happens
351 sepBindsByDropPoint drop_pts floaters
353 (per_drop_pt, must_stay_here, _)
354 --= sep drop_pts emptyIdSet{-fvs of prev drop_pts-} floaters
355 = split' drop_pts floaters [] empty_boxes
356 empty_boxes = take (length drop_pts) (repeat [])
359 (map reverse per_drop_pt, reverse must_stay_here)
361 split' drop_pts_fvs [] mult_branch drop_boxes
362 = (drop_boxes, mult_branch, drop_pts_fvs)
364 -- only in a or unused
365 split' (a:as) (bind:binds) mult_branch (drop_box_a:drop_boxes)
366 | all (\b -> {-b `elementOfIdSet` a &&-}
367 not (b `elementOfIdSet` (unionManyIdSets as)))
368 (bindersOf (fst bind))
369 = split' (a':as) binds mult_branch ((bind:drop_box_a):drop_boxes)
371 a' = a `unionIdSets` fvsOfBind bind
374 split' (a:as) (bind:binds) mult_branch (drop_box_a:drop_boxes)
375 | all (\b -> not (b `elementOfIdSet` a)) (bindersOf (fst bind))
376 = split' (a:as') binds mult_branch' (drop_box_a:drop_boxes')
378 (drop_boxes',mult_branch',as') = split' as [bind] mult_branch drop_boxes
381 split' aas@(a:as) (bind:binds) mult_branch drop_boxes
382 = split' aas' binds (bind : mult_branch) drop_boxes
384 aas' = map (unionIdSets (fvsOfBind bind)) aas
386 -------------------------
387 fvsOfBind (_,fvs) = fvs
390 floatedBindsFVs binds = unionManyIdSets (map snd binds)
392 --mkCoLets' :: [FloatingBinds] -> CoreExpr -> CoreExpr
393 mkCoLets' to_drop e = mkCoLetsNoUnboxed (reverse (map fst to_drop)) e