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 ( stronglyConnComp, stronglyConnCompR, SCC(..) )
24 import Id ( idWantsToBeINLINEd, addNoInlinePragma, nukeNoInlinePragma,
26 emptyIdSet, unionIdSets, mkIdSet,
27 unitIdSet, elementOfIdSet,
29 nullIdEnv, unitIdEnv, combineIdEnvs,
30 delOneFromIdEnv, delManyFromIdEnv, isNullIdEnv,
31 mapIdEnv, lookupIdEnv, IdEnv,
34 import Name ( isExported, isLocallyDefined )
35 import Type ( splitFunTy_maybe, splitForAllTys )
36 import Maybes ( maybeToBool )
38 import PprType ( GenType{-instance Outputable-}, GenTyVar{-ditto-} )
39 import TyVar ( GenTyVar{-instance Eq-} )
40 import Unique ( Unique{-instance Eq-}, u2i )
41 import UniqFM ( keysUFM )
42 import Util ( assoc, zipEqual, zipWithEqual )
44 import List ( partition )
46 isSpecPragmaId_maybe x = Nothing -- ToDo:!trace "OccurAnal.isSpecPragmaId_maybe"
50 %************************************************************************
52 \subsection[OccurAnal-types]{Data types}
54 %************************************************************************
59 Bool -- Keep-unused-bindings flag
60 -- False <=> OK to chuck away binding
61 -- and ignore occurrences within it
62 Bool -- Keep-spec-pragma-ids flag
63 -- False <=> OK to chuck away spec pragma bindings
64 -- and ignore occurrences within it
65 Bool -- Keep-conjurable flag
66 -- False <=> OK to throw away *dead*
67 -- "conjurable" Ids; at the moment, that
68 -- *only* means constant methods, which
69 -- are top-level. A use of a "conjurable"
70 -- Id may appear out of thin air -- e.g.,
71 -- specialiser conjuring up refs to const methods.
72 Bool -- IgnoreINLINEPragma flag
73 -- False <=> OK to use INLINEPragma information
74 -- True <=> ignore INLINEPragma information
76 (Id -> IdSet -> Bool) -- Tells whether an Id occurrence is interesting,
77 -- given the set of in-scope variables
82 addNewCands :: OccEnv -> [Id] -> OccEnv
83 addNewCands (OccEnv kd ks kc ip ifun cands) ids
84 = OccEnv kd ks kc ip ifun (cands `unionIdSets` mkIdSet ids)
86 addNewCand :: OccEnv -> Id -> OccEnv
87 addNewCand (OccEnv ks kd kc ip ifun cands) id
88 = OccEnv kd ks kc ip ifun (addOneToIdSet cands id)
90 isCandidate :: OccEnv -> Id -> Bool
91 isCandidate (OccEnv _ _ _ _ ifun cands) id = ifun id cands
93 inlineMe :: OccEnv -> Id -> Bool
95 = {- See comments with simplIdWantsToBeINLINEd in SimplUtils.lhs
96 not ignore_inline_prag &&
100 keepUnusedBinding :: OccEnv -> Id -> Bool
101 keepUnusedBinding (OccEnv keep_dead keep_spec keep_conjurable _ _ _) binder
102 = keep_dead || (keep_spec && maybeToBool (isSpecPragmaId_maybe binder))
104 keepBecauseConjurable :: OccEnv -> Id -> Bool
105 keepBecauseConjurable (OccEnv _ _ keep_conjurable _ _ _) binder
107 {- keep_conjurable && isConstMethodId binder -}
109 type UsageDetails = IdEnv BinderInfo -- A finite map from ids to their usage
111 combineUsageDetails, combineAltsUsageDetails
112 :: UsageDetails -> UsageDetails -> UsageDetails
114 combineUsageDetails usage1 usage2
115 = combineIdEnvs addBinderInfo usage1 usage2
117 combineAltsUsageDetails usage1 usage2
118 = combineIdEnvs orBinderInfo usage1 usage2
120 addOneOcc :: UsageDetails -> Id -> BinderInfo -> UsageDetails
121 addOneOcc usage id info
122 = combineIdEnvs addBinderInfo usage (unitIdEnv id info)
123 -- ToDo: make this more efficient
125 emptyDetails = (nullIdEnv :: UsageDetails)
127 unitDetails id info = (unitIdEnv id info :: UsageDetails)
129 tagBinders :: UsageDetails -- Of scope
131 -> (UsageDetails, -- Details with binders removed
132 [(Id,BinderInfo)]) -- Tagged binders
134 tagBinders usage binders =
136 usage' = usage `delManyFromIdEnv` binders
137 uss = [ (binder, usage_of usage binder) | binder <- binders ]
139 if isNullIdEnv usage' then
144 = (usage `delManyFromIdEnv` binders,
145 [ (binder, usage_of usage binder) | binder <- binders ]
148 tagBinder :: UsageDetails -- Of scope
150 -> (UsageDetails, -- Details with binders removed
151 (Id,BinderInfo)) -- Tagged binders
153 tagBinder usage binder =
155 usage' = usage `delOneFromIdEnv` binder
156 us = usage_of usage binder
158 if isNullIdEnv usage' then -- Bogus test to force evaluation.
159 (usage', (binder, us))
161 (usage', (binder, us))
163 if isDeadOcc us then -- Ditto
169 usage_of usage binder
170 | isExported binder = noBinderInfo -- Visible-elsewhere things count as many
172 = case (lookupIdEnv usage binder) of
173 Nothing -> deadOccurrence
176 isNeeded env usage binder
177 = if isDeadOcc (usage_of usage binder) then
178 keepUnusedBinding env binder -- Maybe keep it anyway
184 %************************************************************************
186 \subsection[OccurAnal-main]{Counting occurrences: main function}
188 %************************************************************************
190 Here's the externally-callable interface:
194 :: [CoreBinding] -- input
195 -> (SimplifierSwitch -> Bool)
196 -> [SimplifiableCoreBinding] -- output
198 occurAnalyseBinds binds simplifier_sw_chkr
199 | opt_D_dump_occur_anal = pprTrace "OccurAnal:"
200 (vcat (map ppr_bind binds'))
204 (_, binds') = doo initial_env binds
206 initial_env = OccEnv (simplifier_sw_chkr KeepUnusedBindings)
207 (simplifier_sw_chkr KeepSpecPragmaIds)
208 (not (simplifier_sw_chkr SimplMayDeleteConjurableIds))
209 (simplifier_sw_chkr IgnoreINLINEPragma)
210 (\id in_scope -> isLocallyDefined id) -- Anything local is interesting
211 emptyIdSet -- Not actually used
213 doo env [] = (emptyDetails, [])
215 = (final_usage, new_binds ++ the_rest)
217 new_env = env `addNewCands` (bindersOf bind)
218 (binds_usage, the_rest) = doo new_env binds
219 (final_usage, new_binds) = occAnalBind env bind binds_usage
221 -- This really ought to be done properly by PprCore, but
222 -- it isn't. pprCoreBinding only works on Id binders, and
223 -- the general case is complicated by the fact that it has to work
224 -- for interface files too. Sigh
226 ppr_bind bind@(NonRec binder expr)
229 ppr_bind bind@(Rec binds)
230 = vcat [ptext SLIT("Rec {"),
232 ptext SLIT("end Rec }")]
236 occurAnalyseExpr :: (Id -> Bool) -- Tells if a variable is interesting
238 -> (IdEnv BinderInfo, -- Occ info for interesting free vars
239 SimplifiableCoreExpr)
241 occurAnalyseExpr interesting expr
242 = occAnal initial_env expr
244 initial_env = OccEnv False {- Drop unused bindings -}
245 False {- Drop SpecPragmaId bindings -}
246 True {- Keep conjurable Ids -}
247 False {- Do not ignore INLINE Pragma -}
248 (\id locals -> interesting id || elementOfIdSet id locals)
251 occurAnalyseGlobalExpr :: CoreExpr -> SimplifiableCoreExpr
252 occurAnalyseGlobalExpr expr
253 = -- Top level expr, so no interesting free vars, and
254 -- discard occurence info returned
255 snd (occurAnalyseExpr (\_ -> False) expr)
258 %************************************************************************
260 \subsection[OccurAnal-main]{Counting occurrences: main function}
262 %************************************************************************
268 type Node details = (details, Int, [Int]) -- The Ints are gotten from the Unique,
269 -- which is gotten from the Id.
270 type Details1 = (Id, (UsageDetails, SimplifiableCoreExpr))
271 type Details2 = ((Id, BinderInfo), SimplifiableCoreExpr)
274 occAnalBind :: OccEnv
276 -> UsageDetails -- Usage details of scope
277 -> (UsageDetails, -- Of the whole let(rec)
278 [SimplifiableCoreBinding])
280 occAnalBind env (NonRec binder rhs) body_usage
281 | isNeeded env body_usage binder -- It's mentioned in body
282 = (final_body_usage `combineUsageDetails` rhs_usage,
283 [NonRec tagged_binder rhs'])
285 | otherwise -- Not mentioned, so drop dead code
289 binder' = nukeNoInlinePragma binder
290 (rhs_usage, rhs') = occAnalRhs env binder' rhs
291 (final_body_usage, tagged_binder) = tagBinder body_usage binder'
294 Dropping dead code for recursive bindings is done in a very simple way:
296 the entire set of bindings is dropped if none of its binders are
297 mentioned in its body; otherwise none are.
299 This seems to miss an obvious improvement.
314 Now @f@ is unused. But dependency analysis will sort this out into a
315 @letrec@ for @g@ and a @let@ for @f@, and then @f@ will get dropped.
316 It isn't easy to do a perfect job in one blow. Consider
330 occAnalBind env (Rec pairs) body_usage
331 = foldr (_scc_ "occAnalBind.dofinal" do_final_bind) (body_usage, []) sccs
333 pp_scc (CyclicSCC cycle) = hcat [text "Cyclic ", hcat (punctuate comma (map pp_item cycle))]
334 pp_scc (AcyclicSCC item) = hcat [text "Acyclic ", pp_item item]
335 pp_item (_, bndr, _) = ppr bndr
337 binders = map fst pairs
338 new_env = env `addNewCands` binders
340 analysed_pairs :: [Details1]
341 analysed_pairs = [(nukeNoInlinePragma bndr, occAnalRhs new_env bndr rhs) | (bndr,rhs) <- pairs]
343 sccs :: [SCC (Node Details1)]
344 sccs = _scc_ "occAnalBind.scc" stronglyConnCompR edges
347 ---- stuff for dependency analysis of binds -------------------------------
348 edges :: [Node Details1]
349 edges = _scc_ "occAnalBind.assoc"
350 [ (pair, IBOX(u2i (idUnique id)), edges_from rhs_usage)
351 | pair@(id, (rhs_usage, rhs)) <- analysed_pairs
354 -- (a -> b) means a mentions b
355 -- Given the usage details (a UFM that gives occ info for each free var of
356 -- the RHS) we can get the list of free vars -- or rather their Int keys --
357 -- by just extracting the keys from the finite map. Grimy, but fast.
358 -- Previously we had this:
359 -- [ bndr | bndr <- bndrs,
360 -- maybeToBool (lookupIdEnv rhs_usage bndr)]
361 -- which has n**2 cost, and this meant that edges_from alone
362 -- consumed 10% of total runtime!
363 edges_from :: UsageDetails -> [Int]
364 edges_from rhs_usage = _scc_ "occAnalBind.edges_from"
367 ---- stuff to "re-constitute" bindings from dependency-analysis info ------
370 do_final_bind (AcyclicSCC ((bndr, (rhs_usage, rhs')), _, _)) (body_usage, binds_so_far)
371 | isNeeded env body_usage bndr
372 = (combined_usage, new_bind : binds_so_far)
374 = (body_usage, binds_so_far) -- Dead code
376 total_usage = combineUsageDetails body_usage rhs_usage
377 (combined_usage, tagged_bndr) = tagBinder total_usage bndr
378 new_bind = NonRec tagged_bndr rhs'
381 do_final_bind (CyclicSCC cycle) (body_usage, binds_so_far)
382 | any (isNeeded env body_usage) bndrs
383 = (combined_usage, final_bind:binds_so_far)
385 = (body_usage, binds_so_far) -- Dead code
387 pairs = [pair | (pair, _, _) <- cycle]
388 bndrs = [bndr | (bndr, _) <- pairs]
389 rhs_usages = [rhs_usage | (_, (rhs_usage, _)) <- pairs]
390 total_usage = foldr combineUsageDetails body_usage rhs_usages
391 (combined_usage, tagged_binders) = tagBinders total_usage bndrs
392 final_bind = Rec (reOrderRec env new_cycle)
394 new_cycle = CyclicSCC (zipWithEqual "occAnalBind" mk_new_bind tagged_binders cycle)
395 mk_new_bind tagged_bndr ((_, (_, rhs')), key, keys) = ((tagged_bndr, rhs'), key, keys)
398 @reOrderRec@ is applied to the list of (binder,rhs) pairs for a cyclic
399 strongly connected component (there's guaranteed to be a cycle). It returns the
401 a) in a better order,
402 b) with some of the Ids having a IMustNotBeINLINEd pragma
404 The "no-inline" Ids are sufficient to break all cycles in the SCC. This means
405 that the simplifier can guarantee not to loop provided it never records an inlining
406 for these no-inline guys.
408 Furthermore, the order of the binds is such that if we neglect dependencies
409 on the no-inline Ids then the binds are topologically sorted. This means
410 that the simplifier will generally do a good job if it works from top bottom,
411 recording inlinings for any Ids which aren't marked as "no-inline" as it goes.
413 Here's a case that bit me:
421 Re-ordering doesn't change the order of bindings, but there was no loop-breaker.
423 My solution was to make a=b bindings record b as Many, rather like INLINE bindings.
424 Perhaps something cleverer would suffice.
426 You might think that you can prevent non-termination simply by making
427 sure that we simplify a recursive binding's RHS in an environment that
428 simply clones the recursive Id. But no. Consider
430 letrec f = \x -> let z = f x' in ...
437 We bind n to its *simplified* RHS, we then *re-simplify* it when
438 we inline n. Then we may well inline f; and then the same thing
441 I don't think it's possible to prevent non-termination by environment
442 manipulation in this way. Apart from anything else, successive
443 iterations of the simplifier may unroll recursive loops in cases like
444 that above. The idea of beaking every recursive loop with an
445 IMustNotBeINLINEd pragma is much much better.
451 -> SCC (Node Details2)
453 -- Sorted into a plausible order. Enough of the Ids have
454 -- dontINLINE pragmas that there are no loops left.
456 -- Non-recursive case
457 reOrderRec env (AcyclicSCC (pair, _, _)) = [pair]
459 -- Common case of simple self-recursion
460 reOrderRec env (CyclicSCC [bind])
461 = [((addNoInlinePragma bndr, occ_info), rhs)]
463 (((bndr,occ_info), rhs), _, _) = bind
465 reOrderRec env (CyclicSCC binds)
466 = -- Choose a loop breaker, mark it no-inline,
467 -- do SCC analysis on the rest, and recursively sort them out
468 concat (map (reOrderRec env) (stronglyConnCompR unchosen))
470 [((addNoInlinePragma bndr, occ_info), rhs)]
473 (chosen_pair, unchosen) = choose_loop_breaker binds
474 ((bndr,occ_info), rhs) = chosen_pair
476 -- Choosing the loop breaker; heursitic
477 choose_loop_breaker (bind@(pair, _, _) : rest)
480 = (chosen, bind : unchosen) -- Don't pick it
481 | otherwise -- Pick it
484 (chosen, unchosen) = choose_loop_breaker rest
486 bad_choice ((bndr, occ_info), rhs)
487 = var_rhs rhs -- Dont pick var RHS
488 || inlineMe env bndr -- Dont pick INLINE thing
489 || isOneFunOcc occ_info -- Dont pick single-occ thing
490 || not_fun_ty (idType bndr) -- Dont pick data-ty thing
492 -- isOneFunOcc looks for one textual occurrence, whether inside lambda or whatever.
493 -- We stick to just FunOccs because if we're not going to be able
494 -- to inline the thing on this round it might be better to pick
495 -- this one as the loop breaker. Real example (the Enum Ordering instance
497 -- rec f = \ x -> case d of (p,q,r) -> p x
498 -- g = \ x -> case d of (p,q,r) -> q x
501 -- Here, f and g occur just once; but we can't inline them into d.
502 -- On the other hand we *could* simplify those case expressions if
503 -- we didn't stupidly choose d as the loop breaker.
505 not_fun_ty ty = not (maybeToBool (splitFunTy_maybe rho_ty))
507 (_, rho_ty) = splitForAllTys ty
510 var_rhs (Var v) = True
511 var_rhs other_rhs = False
514 @occAnalRhs@ deals with the question of bindings where the Id is marked
515 by an INLINE pragma. For these we record that anything which occurs
516 in its RHS occurs many times. This pessimistically assumes that ths
517 inlined binder also occurs many times in its scope, but if it doesn't
518 we'll catch it next time round. At worst this costs an extra simplifier pass.
519 ToDo: try using the occurrence info for the inline'd binder.
521 [March 97] We do the same for atomic RHSs. Reason: see notes with reOrderRec.
525 -> Id -> CoreExpr -- Binder and rhs
526 -> (UsageDetails, SimplifiableCoreExpr)
528 occAnalRhs env id (Var v)
530 = (unitIdEnv v (markMany (funOccurrence 0)), Var v)
533 = (emptyDetails, Var v)
535 occAnalRhs env id rhs
537 = (mapIdEnv markMany rhs_usage, rhs')
543 (rhs_usage, rhs') = occAnal env rhs
551 -> (UsageDetails, -- Gives info only about the "interesting" Ids
552 SimplifiableCoreExpr)
556 = (unitIdEnv v (funOccurrence 0), Var v)
559 = (emptyDetails, Var v)
561 occAnal env (Lit lit) = (emptyDetails, Lit lit)
562 occAnal env (Prim op args) = (occAnalArgs env args, Prim op args)
565 We regard variables that occur as constructor arguments as "dangerousToDup":
569 f x = let y = expensive x in
571 (case z of {(p,q)->q}, case z of {(p,q)->q})
574 We feel free to duplicate the WHNF (True,y), but that means
575 that y may be duplicated thereby.
577 If we aren't careful we duplicate the (expensive x) call!
578 Constructors are rather like lambdas in this way.
581 occAnal env (Con con args) = (mapIdEnv markDangerousToDup (occAnalArgs env args),
584 occAnal env (SCC cc body)
585 = (mapIdEnv markInsideSCC usage, SCC cc body')
587 (usage, body') = occAnal env body
589 occAnal env (Coerce c ty body)
590 = (usage, Coerce c ty body')
592 (usage, body') = occAnal env body
594 occAnal env (App fun arg)
595 = (fun_usage `combineUsageDetails` arg_usage, App fun' arg)
597 (fun_usage, fun') = occAnal env fun
598 arg_usage = occAnalArg env arg
600 -- For value lambdas we do a special hack. Consider
602 -- If we did nothing, x is used inside the \y, so would be marked
603 -- as dangerous to dup. But in the common case where the abstraction
604 -- is applied to two arguments this is over-pessimistic.
605 -- So instead we don't take account of the \y when dealing with x's usage;
606 -- instead, the simplifier is careful when partially applying lambdas
608 occAnal env expr@(Lam (ValBinder binder) body)
609 = (mapIdEnv markDangerousToDup final_usage,
610 foldr ( \v b -> Lam (ValBinder v) b) body' tagged_binders)
612 (binders,body) = collectValBinders expr
613 (body_usage, body') = occAnal (env `addNewCands` binders) body
614 (final_usage, tagged_binders) = tagBinders body_usage binders
616 -- ANDY: WE MUST THINK ABOUT THIS! (ToDo)
617 occAnal env (Lam (TyBinder tyvar) body)
618 = case occAnal env body of { (body_usage, body') ->
619 (mapIdEnv markDangerousToDup body_usage,
620 Lam (TyBinder tyvar) body') }
622 -- (body_usage, body') = occAnal env body
624 occAnal env (Case scrut alts)
625 = case occAnalAlts env alts of { (alts_usage, alts') ->
626 case occAnal env scrut of { (scrut_usage, scrut') ->
628 det = scrut_usage `combineUsageDetails` alts_usage
630 if isNullIdEnv det then
631 (det, Case scrut' alts')
633 (det, Case scrut' alts') }}
635 (scrut_usage `combineUsageDetails` alts_usage,
638 (scrut_usage, scrut') = occAnal env scrut
639 (alts_usage, alts') = occAnalAlts env alts
642 occAnal env (Let bind body)
643 = case occAnal new_env body of { (body_usage, body') ->
644 case occAnalBind env bind body_usage of { (final_usage, new_binds) ->
645 (final_usage, foldr Let body' new_binds) }} -- mkCoLet* wants Core... (sigh)
647 new_env = env `addNewCands` (bindersOf bind)
648 -- (body_usage, body') = occAnal new_env body
649 -- (final_usage, new_binds) = occAnalBind env bind body_usage
655 occAnalAlts env (AlgAlts alts deflt)
656 = (foldr combineAltsUsageDetails deflt_usage alts_usage,
657 -- Note: combine*Alts*UsageDetails...
658 AlgAlts alts' deflt')
660 (alts_usage, alts') = unzip (map do_alt alts)
661 (deflt_usage, deflt') = occAnalDeflt env deflt
663 do_alt (con, args, rhs)
664 = (final_usage, (con, tagged_args, rhs'))
666 new_env = env `addNewCands` args
667 (rhs_usage, rhs') = occAnal new_env rhs
668 (final_usage, tagged_args) = tagBinders rhs_usage args
670 occAnalAlts env (PrimAlts alts deflt)
671 = (foldr combineAltsUsageDetails deflt_usage alts_usage,
672 -- Note: combine*Alts*UsageDetails...
673 PrimAlts alts' deflt')
675 (alts_usage, alts') = unzip (map do_alt alts)
676 (deflt_usage, deflt') = occAnalDeflt env deflt
679 = (rhs_usage, (lit, rhs'))
681 (rhs_usage, rhs') = occAnal env rhs
683 occAnalDeflt env NoDefault = (emptyDetails, NoDefault)
685 occAnalDeflt env (BindDefault binder rhs)
686 = (final_usage, BindDefault tagged_binder rhs')
688 new_env = env `addNewCand` binder
689 (rhs_usage, rhs') = occAnal new_env rhs
690 (final_usage, tagged_binder) = tagBinder rhs_usage binder
697 occAnalArgs :: OccEnv -> [CoreArg] -> UsageDetails
699 occAnalArgs env atoms
700 = foldr do_one_atom emptyDetails atoms
702 do_one_atom (VarArg v) usage
703 | isCandidate env v = addOneOcc usage v (argOccurrence 0)
705 do_one_atom other_arg usage = usage
708 occAnalArg :: OccEnv -> CoreArg -> UsageDetails
710 occAnalArg env (VarArg v)
711 | isCandidate env v = unitDetails v (argOccurrence 0)
712 | otherwise = emptyDetails
713 occAnalArg _ _ = emptyDetails