2 % (c) The GRASP/AQUA Project, Glasgow University, 1992-1996
4 %************************************************************************
6 \section[OccurAnal]{Occurrence analysis pass}
8 %************************************************************************
10 The occurrence analyser re-typechecks a core expression, returning a new
11 core expression with (hopefully) improved usage information.
15 occurAnalyseBinds, occurAnalyseExpr, occurAnalyseGlobalExpr
18 #include "HsVersions.h"
21 import CmdLineOpts ( opt_D_dump_occur_anal, SimplifierSwitch(..) )
23 import Digraph ( stronglyConnCompR, SCC(..) )
24 import Id ( idWantsToBeINLINEd, addNoInlinePragma, nukeNoInlinePragma,
26 emptyIdSet, unionIdSets, mkIdSet,
29 nullIdEnv, unitIdEnv, combineIdEnvs,
30 delOneFromIdEnv, delManyFromIdEnv, isNullIdEnv,
31 mapIdEnv, lookupIdEnv, IdEnv
33 import Specialise ( idSpecVars )
34 import Name ( isExported, isLocallyDefined )
35 import Type ( splitFunTy_maybe, splitForAllTys )
36 import Maybes ( maybeToBool )
39 import UniqFM ( keysUFM )
40 import Util ( zipWithEqual )
45 %************************************************************************
47 \subsection[OccurAnal-types]{Data types}
49 %************************************************************************
54 Bool -- IgnoreINLINEPragma flag
55 -- False <=> OK to use INLINEPragma information
56 -- True <=> ignore INLINEPragma information
58 (Id -> IdSet -> Bool) -- Tells whether an Id occurrence is interesting,
59 -- given the set of in-scope variables
64 addNewCands :: OccEnv -> [Id] -> OccEnv
65 addNewCands (OccEnv ip ifun cands) ids
66 = OccEnv ip ifun (cands `unionIdSets` mkIdSet ids)
68 addNewCand :: OccEnv -> Id -> OccEnv
69 addNewCand (OccEnv ip ifun cands) id
70 = OccEnv ip ifun (addOneToIdSet cands id)
72 isCandidate :: OccEnv -> Id -> Bool
73 isCandidate (OccEnv _ ifun cands) id = ifun id cands
75 inlineMe :: OccEnv -> Id -> Bool
77 = {- See comments with simplIdWantsToBeINLINEd in SimplUtils.lhs
78 not ignore_inline_prag &&
83 type UsageDetails = IdEnv BinderInfo -- A finite map from ids to their usage
85 combineUsageDetails, combineAltsUsageDetails
86 :: UsageDetails -> UsageDetails -> UsageDetails
88 combineUsageDetails usage1 usage2
89 = combineIdEnvs addBinderInfo usage1 usage2
91 combineAltsUsageDetails usage1 usage2
92 = combineIdEnvs orBinderInfo usage1 usage2
94 addOneOcc :: UsageDetails -> Id -> BinderInfo -> UsageDetails
95 addOneOcc usage id info
96 = combineIdEnvs addBinderInfo usage (unitIdEnv id info)
97 -- ToDo: make this more efficient
99 emptyDetails = (nullIdEnv :: UsageDetails)
101 unitDetails id info = (unitIdEnv id info :: UsageDetails)
103 tagBinders :: UsageDetails -- Of scope
105 -> (UsageDetails, -- Details with binders removed
106 [(Id,BinderInfo)]) -- Tagged binders
108 tagBinders usage binders =
110 usage' = usage `delManyFromIdEnv` binders
111 uss = [ (binder, usage_of usage binder) | binder <- binders ]
113 if isNullIdEnv usage' then
118 = (usage `delManyFromIdEnv` binders,
119 [ (binder, usage_of usage binder) | binder <- binders ]
122 tagBinder :: UsageDetails -- Of scope
124 -> (UsageDetails, -- Details with binders removed
125 (Id,BinderInfo)) -- Tagged binders
127 tagBinder usage binder =
129 usage' = usage `delOneFromIdEnv` binder
130 us = usage_of usage binder
132 if isNullIdEnv usage' then -- Bogus test to force evaluation.
133 (usage', (binder, us))
135 (usage', (binder, us))
137 if isDeadOcc us then -- Ditto
143 usage_of usage binder
145 = noBinderInfo -- Visible-elsewhere things count as many
147 = case (lookupIdEnv usage binder) of
148 Nothing -> deadOccurrence
151 isNeeded env usage binder = not (isDeadOcc (usage_of usage binder))
155 %************************************************************************
157 \subsection[OccurAnal-main]{Counting occurrences: main function}
159 %************************************************************************
161 Here's the externally-callable interface:
165 :: [CoreBinding] -- input
166 -> (SimplifierSwitch -> Bool)
167 -> [SimplifiableCoreBinding] -- output
169 occurAnalyseBinds binds simplifier_sw_chkr
170 | opt_D_dump_occur_anal = pprTrace "OccurAnal:"
171 (vcat (map ppr_bind binds'))
175 (_, binds') = doo initial_env binds
177 initial_env = OccEnv (simplifier_sw_chkr IgnoreINLINEPragma)
178 (\id in_scope -> isLocallyDefined id) -- Anything local is interesting
179 emptyIdSet -- Not actually used
181 doo env [] = (emptyDetails, [])
183 = (final_usage, new_binds ++ the_rest)
185 new_env = env `addNewCands` (bindersOf bind)
186 (binds_usage, the_rest) = doo new_env binds
187 (final_usage, new_binds) = occAnalBind env bind binds_usage
189 -- This really ought to be done properly by PprCore, but
190 -- it isn't. pprCoreBinding only works on Id binders, and
191 -- the general case is complicated by the fact that it has to work
192 -- for interface files too. Sigh
194 ppr_bind bind@(NonRec binder expr)
197 ppr_bind bind@(Rec binds)
198 = vcat [ptext SLIT("Rec {"),
200 ptext SLIT("end Rec }")]
204 occurAnalyseExpr :: (Id -> Bool) -- Tells if a variable is interesting
206 -> (IdEnv BinderInfo, -- Occ info for interesting free vars
207 SimplifiableCoreExpr)
209 occurAnalyseExpr interesting expr
210 = occAnal initial_env expr
212 initial_env = OccEnv False {- Do not ignore INLINE Pragma -}
213 (\id locals -> interesting id || elementOfIdSet id locals)
216 occurAnalyseGlobalExpr :: CoreExpr -> SimplifiableCoreExpr
217 occurAnalyseGlobalExpr expr
218 = -- Top level expr, so no interesting free vars, and
219 -- discard occurence info returned
220 snd (occurAnalyseExpr (\_ -> False) expr)
223 %************************************************************************
225 \subsection[OccurAnal-main]{Counting occurrences: main function}
227 %************************************************************************
233 type Node details = (details, Int, [Int]) -- The Ints are gotten from the Unique,
234 -- which is gotten from the Id.
235 type Details1 = (Id, UsageDetails, SimplifiableCoreExpr)
236 type Details2 = ((Id, BinderInfo), SimplifiableCoreExpr)
239 occAnalBind :: OccEnv
241 -> UsageDetails -- Usage details of scope
242 -> (UsageDetails, -- Of the whole let(rec)
243 [SimplifiableCoreBinding])
245 occAnalBind env (NonRec binder rhs) body_usage
246 | isNeeded env body_usage binder -- It's mentioned in body
247 = (final_body_usage `combineUsageDetails` rhs_usage,
248 [NonRec tagged_binder rhs'])
250 | otherwise -- Not mentioned, so drop dead code
254 binder' = nukeNoInlinePragma binder
255 (rhs_usage, rhs') = occAnalRhs env binder' rhs
256 (final_body_usage, tagged_binder) = tagBinder body_usage binder'
259 Dropping dead code for recursive bindings is done in a very simple way:
261 the entire set of bindings is dropped if none of its binders are
262 mentioned in its body; otherwise none are.
264 This seems to miss an obvious improvement.
279 Now @f@ is unused. But dependency analysis will sort this out into a
280 @letrec@ for @g@ and a @let@ for @f@, and then @f@ will get dropped.
281 It isn't easy to do a perfect job in one blow. Consider
295 occAnalBind env (Rec pairs) body_usage
296 = foldr (_scc_ "occAnalBind.dofinal" do_final_bind) (body_usage, []) sccs
298 pp_item (_, bndr, _) = ppr bndr
300 binders = map fst pairs
301 new_env = env `addNewCands` binders
303 analysed_pairs :: [Details1]
304 analysed_pairs = [ (nukeNoInlinePragma bndr, rhs_usage, rhs')
305 | (bndr, rhs) <- pairs,
306 let (rhs_usage, rhs') = occAnalRhs new_env bndr rhs
309 sccs :: [SCC (Node Details1)]
310 sccs = _scc_ "occAnalBind.scc" stronglyConnCompR edges
313 ---- stuff for dependency analysis of binds -------------------------------
314 edges :: [Node Details1]
315 edges = _scc_ "occAnalBind.assoc"
316 [ (details, IBOX(u2i (idUnique id)), edges_from rhs_usage)
317 | details@(id, rhs_usage, rhs) <- analysed_pairs
320 -- (a -> b) means a mentions b
321 -- Given the usage details (a UFM that gives occ info for each free var of
322 -- the RHS) we can get the list of free vars -- or rather their Int keys --
323 -- by just extracting the keys from the finite map. Grimy, but fast.
324 -- Previously we had this:
325 -- [ bndr | bndr <- bndrs,
326 -- maybeToBool (lookupIdEnv rhs_usage bndr)]
327 -- which has n**2 cost, and this meant that edges_from alone
328 -- consumed 10% of total runtime!
329 edges_from :: UsageDetails -> [Int]
330 edges_from rhs_usage = _scc_ "occAnalBind.edges_from"
333 ---- stuff to "re-constitute" bindings from dependency-analysis info ------
336 do_final_bind (AcyclicSCC ((bndr, rhs_usage, rhs'), _, _)) (body_usage, binds_so_far)
337 | isNeeded env body_usage bndr
338 = (combined_usage, new_bind : binds_so_far)
340 = (body_usage, binds_so_far) -- Dead code
342 total_usage = combineUsageDetails body_usage rhs_usage
343 (combined_usage, tagged_bndr) = tagBinder total_usage bndr
344 new_bind = NonRec tagged_bndr rhs'
347 do_final_bind (CyclicSCC cycle) (body_usage, binds_so_far)
348 | any (isNeeded env body_usage) bndrs
349 = (combined_usage, final_bind:binds_so_far)
351 = (body_usage, binds_so_far) -- Dead code
353 details = [details | (details, _, _) <- cycle]
354 bndrs = [bndr | (bndr, _, _) <- details]
355 rhs_usages = [rhs_usage | (_, rhs_usage, _) <- details]
356 total_usage = foldr combineUsageDetails body_usage rhs_usages
357 (combined_usage, tagged_binders) = tagBinders total_usage bndrs
358 final_bind = Rec (reOrderRec env new_cycle)
360 new_cycle = CyclicSCC (zipWithEqual "occAnalBind" mk_new_bind tagged_binders cycle)
361 mk_new_bind (bndr, occ_info) ((_, _, rhs'), key, keys) = (((bndr, occ_info), rhs'), key, keys)
364 @reOrderRec@ is applied to the list of (binder,rhs) pairs for a cyclic
365 strongly connected component (there's guaranteed to be a cycle). It returns the
367 a) in a better order,
368 b) with some of the Ids having a IMustNotBeINLINEd pragma
370 The "no-inline" Ids are sufficient to break all cycles in the SCC. This means
371 that the simplifier can guarantee not to loop provided it never records an inlining
372 for these no-inline guys.
374 Furthermore, the order of the binds is such that if we neglect dependencies
375 on the no-inline Ids then the binds are topologically sorted. This means
376 that the simplifier will generally do a good job if it works from top bottom,
377 recording inlinings for any Ids which aren't marked as "no-inline" as it goes.
379 Here's a case that bit me:
387 Re-ordering doesn't change the order of bindings, but there was no loop-breaker.
389 My solution was to make a=b bindings record b as Many, rather like INLINE bindings.
390 Perhaps something cleverer would suffice.
392 You might think that you can prevent non-termination simply by making
393 sure that we simplify a recursive binding's RHS in an environment that
394 simply clones the recursive Id. But no. Consider
396 letrec f = \x -> let z = f x' in ...
403 We bind n to its *simplified* RHS, we then *re-simplify* it when
404 we inline n. Then we may well inline f; and then the same thing
407 I don't think it's possible to prevent non-termination by environment
408 manipulation in this way. Apart from anything else, successive
409 iterations of the simplifier may unroll recursive loops in cases like
410 that above. The idea of beaking every recursive loop with an
411 IMustNotBeINLINEd pragma is much much better.
417 -> SCC (Node Details2)
419 -- Sorted into a plausible order. Enough of the Ids have
420 -- dontINLINE pragmas that there are no loops left.
422 -- Non-recursive case
423 reOrderRec env (AcyclicSCC (bind, _, _)) = [bind]
425 -- Common case of simple self-recursion
426 reOrderRec env (CyclicSCC [bind])
427 = [((addNoInlinePragma bndr, occ_info), rhs)]
429 (((bndr, occ_info), rhs), _, _) = bind
431 reOrderRec env (CyclicSCC binds)
432 = -- Choose a loop breaker, mark it no-inline,
433 -- do SCC analysis on the rest, and recursively sort them out
434 concat (map (reOrderRec env) (stronglyConnCompR unchosen))
436 [((addNoInlinePragma bndr, occ_info), rhs)]
439 (chosen_pair, unchosen) = choose_loop_breaker binds
440 ((bndr,occ_info), rhs) = chosen_pair
442 -- Choosing the loop breaker; heursitic
443 choose_loop_breaker (bind@(details, _, _) : rest)
446 = (chosen, bind : unchosen) -- Don't pick it
447 | otherwise -- Pick it
450 (chosen, unchosen) = choose_loop_breaker rest
452 bad_choice ((bndr, occ_info), rhs)
453 = var_rhs rhs -- Dont pick var RHS
454 || inlineMe env bndr -- Dont pick INLINE thing
455 || isOneFunOcc occ_info -- Dont pick single-occ thing
456 || not_fun_ty (idType bndr) -- Dont pick data-ty thing
458 -- isOneFunOcc looks for one textual occurrence, whether inside lambda or whatever.
459 -- We stick to just FunOccs because if we're not going to be able
460 -- to inline the thing on this round it might be better to pick
461 -- this one as the loop breaker. Real example (the Enum Ordering instance
463 -- rec f = \ x -> case d of (p,q,r) -> p x
464 -- g = \ x -> case d of (p,q,r) -> q x
467 -- Here, f and g occur just once; but we can't inline them into d.
468 -- On the other hand we *could* simplify those case expressions if
469 -- we didn't stupidly choose d as the loop breaker.
471 not_fun_ty ty = not (maybeToBool (splitFunTy_maybe rho_ty))
473 (_, rho_ty) = splitForAllTys ty
476 var_rhs (Var v) = True
477 var_rhs other_rhs = False
480 @occAnalRhs@ deals with the question of bindings where the Id is marked
481 by an INLINE pragma. For these we record that anything which occurs
482 in its RHS occurs many times. This pessimistically assumes that ths
483 inlined binder also occurs many times in its scope, but if it doesn't
484 we'll catch it next time round. At worst this costs an extra simplifier pass.
485 ToDo: try using the occurrence info for the inline'd binder.
487 [March 97] We do the same for atomic RHSs. Reason: see notes with reOrderRec.
489 [March 98] A new wrinkle is that if the binder has specialisations inside
490 it then we count the specialised Ids as "extra rhs's". That way
491 the "parent" keeps the specialised "children" alive. If the parent
492 dies (because it isn't referenced any more), then the children will
493 die too unless they are already referenced directly.
497 -> Id -> CoreExpr -- Binder and rhs
498 -> (UsageDetails, SimplifiableCoreExpr)
500 occAnalRhs env id (Var v)
502 = (unitIdEnv v (markMany (funOccurrence 0)), Var v)
505 = (emptyDetails, Var v)
507 occAnalRhs env id rhs
509 = (mapIdEnv markMany total_usage, rhs')
512 = (total_usage, rhs')
515 (rhs_usage, rhs') = occAnal env rhs
516 total_usage = foldr add rhs_usage (idSpecVars id)
517 add v u = addOneOcc u v (argOccurrence 0)
525 -> (UsageDetails, -- Gives info only about the "interesting" Ids
526 SimplifiableCoreExpr)
530 = (unitIdEnv v (funOccurrence 0), Var v)
533 = (emptyDetails, Var v)
535 occAnal env (Lit lit) = (emptyDetails, Lit lit)
536 occAnal env (Prim op args) = (occAnalArgs env args, Prim op args)
539 We regard variables that occur as constructor arguments as "dangerousToDup":
543 f x = let y = expensive x in
545 (case z of {(p,q)->q}, case z of {(p,q)->q})
548 We feel free to duplicate the WHNF (True,y), but that means
549 that y may be duplicated thereby.
551 If we aren't careful we duplicate the (expensive x) call!
552 Constructors are rather like lambdas in this way.
555 occAnal env (Con con args) = (mapIdEnv markDangerousToDup (occAnalArgs env args),
558 occAnal env (SCC cc body)
559 = (mapIdEnv markInsideSCC usage, SCC cc body')
561 (usage, body') = occAnal env body
563 occAnal env (Coerce c ty body)
564 = (usage, Coerce c ty body')
566 (usage, body') = occAnal env body
568 occAnal env (App fun arg)
569 = (fun_usage `combineUsageDetails` arg_usage, App fun' arg)
571 (fun_usage, fun') = occAnal env fun
572 arg_usage = occAnalArg env arg
574 -- For value lambdas we do a special hack. Consider
576 -- If we did nothing, x is used inside the \y, so would be marked
577 -- as dangerous to dup. But in the common case where the abstraction
578 -- is applied to two arguments this is over-pessimistic.
579 -- So instead we don't take account of the \y when dealing with x's usage;
580 -- instead, the simplifier is careful when partially applying lambdas
582 occAnal env expr@(Lam (ValBinder binder) body)
583 = (mapIdEnv markDangerousToDup final_usage,
584 foldr ( \v b -> Lam (ValBinder v) b) body' tagged_binders)
586 (binders,body) = collectValBinders expr
587 (body_usage, body') = occAnal (env `addNewCands` binders) body
588 (final_usage, tagged_binders) = tagBinders body_usage binders
590 -- ANDY: WE MUST THINK ABOUT THIS! (ToDo)
591 occAnal env (Lam (TyBinder tyvar) body)
592 = case occAnal env body of { (body_usage, body') ->
593 (mapIdEnv markDangerousToDup body_usage,
594 Lam (TyBinder tyvar) body') }
596 -- (body_usage, body') = occAnal env body
598 occAnal env (Case scrut alts)
599 = case occAnalAlts env alts of { (alts_usage, alts') ->
600 case occAnal env scrut of { (scrut_usage, scrut') ->
602 det = scrut_usage `combineUsageDetails` alts_usage
604 if isNullIdEnv det then
605 (det, Case scrut' alts')
607 (det, Case scrut' alts') }}
609 (scrut_usage `combineUsageDetails` alts_usage,
612 (scrut_usage, scrut') = occAnal env scrut
613 (alts_usage, alts') = occAnalAlts env alts
616 occAnal env (Let bind body)
617 = case occAnal new_env body of { (body_usage, body') ->
618 case occAnalBind env bind body_usage of { (final_usage, new_binds) ->
619 (final_usage, foldr Let body' new_binds) }} -- mkCoLet* wants Core... (sigh)
621 new_env = env `addNewCands` (bindersOf bind)
622 -- (body_usage, body') = occAnal new_env body
623 -- (final_usage, new_binds) = occAnalBind env bind body_usage
629 occAnalAlts env (AlgAlts alts deflt)
630 = (foldr combineAltsUsageDetails deflt_usage alts_usage,
631 -- Note: combine*Alts*UsageDetails...
632 AlgAlts alts' deflt')
634 (alts_usage, alts') = unzip (map do_alt alts)
635 (deflt_usage, deflt') = occAnalDeflt env deflt
637 do_alt (con, args, rhs)
638 = (final_usage, (con, tagged_args, rhs'))
640 new_env = env `addNewCands` args
641 (rhs_usage, rhs') = occAnal new_env rhs
642 (final_usage, tagged_args) = tagBinders rhs_usage args
644 occAnalAlts env (PrimAlts alts deflt)
645 = (foldr combineAltsUsageDetails deflt_usage alts_usage,
646 -- Note: combine*Alts*UsageDetails...
647 PrimAlts alts' deflt')
649 (alts_usage, alts') = unzip (map do_alt alts)
650 (deflt_usage, deflt') = occAnalDeflt env deflt
653 = (rhs_usage, (lit, rhs'))
655 (rhs_usage, rhs') = occAnal env rhs
657 occAnalDeflt env NoDefault = (emptyDetails, NoDefault)
659 occAnalDeflt env (BindDefault binder rhs)
660 = (final_usage, BindDefault tagged_binder rhs')
662 new_env = env `addNewCand` binder
663 (rhs_usage, rhs') = occAnal new_env rhs
664 (final_usage, tagged_binder) = tagBinder rhs_usage binder
671 occAnalArgs :: OccEnv -> [CoreArg] -> UsageDetails
673 occAnalArgs env atoms
674 = foldr do_one_atom emptyDetails atoms
676 do_one_atom (VarArg v) usage
677 | isCandidate env v = addOneOcc usage v (argOccurrence 0)
679 do_one_atom other_arg usage = usage
682 occAnalArg :: OccEnv -> CoreArg -> UsageDetails
684 occAnalArg env (VarArg v)
685 | isCandidate env v = unitDetails v (argOccurrence 0)
686 | otherwise = emptyDetails
687 occAnalArg _ _ = emptyDetails