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.
14 #include "HsVersions.h"
17 occurAnalyseBinds, occurAnalyseExpr, occurAnalyseGlobalExpr
21 IMPORT_1_3(List(partition))
24 import CmdLineOpts ( opt_D_dump_occur_anal, SimplifierSwitch(..) )
26 import Digraph ( stronglyConnComp, stronglyConnCompR, SCC(..) )
27 import Id ( idWantsToBeINLINEd, addNoInlinePragma, nukeNoInlinePragma,
28 idType, idUnique, SYN_IE(Id),
29 emptyIdSet, unionIdSets, mkIdSet,
30 unitIdSet, elementOfIdSet,
31 addOneToIdSet, SYN_IE(IdSet),
32 nullIdEnv, unitIdEnv, combineIdEnvs,
33 delOneFromIdEnv, delManyFromIdEnv, isNullIdEnv,
34 mapIdEnv, lookupIdEnv, SYN_IE(IdEnv),
37 import Name ( isExported, isLocallyDefined )
38 import Type ( getFunTy_maybe, splitForAllTy )
39 import Maybes ( maybeToBool )
40 import Outputable ( PprStyle(..), Outputable(..){-instance * (,) -} )
42 import PprType ( GenType{-instance Outputable-}, GenTyVar{-ditto-} )
43 import Pretty ( Doc, vcat, ptext, nest, punctuate, comma, hcat, text )
44 import TyVar ( GenTyVar{-instance Eq-} )
45 import Unique ( Unique{-instance Eq-}, u2i )
46 import UniqFM ( keysUFM )
47 import Util ( assoc, zipEqual, zipWithEqual, Ord3(..)
54 isSpecPragmaId_maybe x = Nothing -- ToDo:!trace "OccurAnal.isSpecPragmaId_maybe"
58 %************************************************************************
60 \subsection[OccurAnal-types]{Data types}
62 %************************************************************************
67 Bool -- Keep-unused-bindings flag
68 -- False <=> OK to chuck away binding
69 -- and ignore occurrences within it
70 Bool -- Keep-spec-pragma-ids flag
71 -- False <=> OK to chuck away spec pragma bindings
72 -- and ignore occurrences within it
73 Bool -- Keep-conjurable flag
74 -- False <=> OK to throw away *dead*
75 -- "conjurable" Ids; at the moment, that
76 -- *only* means constant methods, which
77 -- are top-level. A use of a "conjurable"
78 -- Id may appear out of thin air -- e.g.,
79 -- specialiser conjuring up refs to const methods.
80 Bool -- IgnoreINLINEPragma flag
81 -- False <=> OK to use INLINEPragma information
82 -- True <=> ignore INLINEPragma information
84 (Id -> IdSet -> Bool) -- Tells whether an Id occurrence is interesting,
85 -- given the set of in-scope variables
90 addNewCands :: OccEnv -> [Id] -> OccEnv
91 addNewCands (OccEnv kd ks kc ip ifun cands) ids
92 = OccEnv kd ks kc ip ifun (cands `unionIdSets` mkIdSet ids)
94 addNewCand :: OccEnv -> Id -> OccEnv
95 addNewCand (OccEnv ks kd kc ip ifun cands) id
96 = OccEnv kd ks kc ip ifun (addOneToIdSet cands id)
98 isCandidate :: OccEnv -> Id -> Bool
99 isCandidate (OccEnv _ _ _ _ ifun cands) id = ifun id cands
101 inlineMe :: OccEnv -> Id -> Bool
103 = {- See comments with simplIdWantsToBeINLINEd in SimplUtils.lhs
104 not ignore_inline_prag &&
106 idWantsToBeINLINEd id
108 keepUnusedBinding :: OccEnv -> Id -> Bool
109 keepUnusedBinding (OccEnv keep_dead keep_spec keep_conjurable _ _ _) binder
110 = keep_dead || (keep_spec && maybeToBool (isSpecPragmaId_maybe binder))
112 keepBecauseConjurable :: OccEnv -> Id -> Bool
113 keepBecauseConjurable (OccEnv _ _ keep_conjurable _ _ _) binder
115 {- keep_conjurable && isConstMethodId binder -}
117 type UsageDetails = IdEnv BinderInfo -- A finite map from ids to their usage
119 combineUsageDetails, combineAltsUsageDetails
120 :: UsageDetails -> UsageDetails -> UsageDetails
122 combineUsageDetails usage1 usage2
123 = combineIdEnvs addBinderInfo usage1 usage2
125 combineAltsUsageDetails usage1 usage2
126 = combineIdEnvs orBinderInfo usage1 usage2
128 addOneOcc :: UsageDetails -> Id -> BinderInfo -> UsageDetails
129 addOneOcc usage id info
130 = combineIdEnvs addBinderInfo usage (unitIdEnv id info)
131 -- ToDo: make this more efficient
133 emptyDetails = (nullIdEnv :: UsageDetails)
135 unitDetails id info = (unitIdEnv id info :: UsageDetails)
137 tagBinders :: UsageDetails -- Of scope
139 -> (UsageDetails, -- Details with binders removed
140 [(Id,BinderInfo)]) -- Tagged binders
142 tagBinders usage binders =
144 usage' = usage `delManyFromIdEnv` binders
145 uss = [ (binder, usage_of usage binder) | binder <- binders ]
147 if isNullIdEnv usage' then
152 = (usage `delManyFromIdEnv` binders,
153 [ (binder, usage_of usage binder) | binder <- binders ]
156 tagBinder :: UsageDetails -- Of scope
158 -> (UsageDetails, -- Details with binders removed
159 (Id,BinderInfo)) -- Tagged binders
161 tagBinder usage binder =
163 usage' = usage `delOneFromIdEnv` binder
164 us = usage_of usage binder
166 if isNullIdEnv usage' then -- bogus test to force evaluation.
167 (usage', (binder, us))
169 (usage', (binder, us))
171 case us of { DeadCode -> cont; _ -> cont }
173 -- (binder, usage_of usage binder)
176 usage_of usage binder
177 | isExported binder = ManyOcc 0 -- Visible-elsewhere things count as many
179 = case (lookupIdEnv usage binder) of
183 isNeeded env usage binder
184 = case (usage_of usage binder) of
185 DeadCode -> keepUnusedBinding env binder -- Maybe keep it anyway
190 %************************************************************************
192 \subsection[OccurAnal-main]{Counting occurrences: main function}
194 %************************************************************************
196 Here's the externally-callable interface:
200 :: [CoreBinding] -- input
201 -> (SimplifierSwitch -> Bool)
202 -> [SimplifiableCoreBinding] -- output
204 occurAnalyseBinds binds simplifier_sw_chkr
205 | opt_D_dump_occur_anal = pprTrace "OccurAnal:"
206 (vcat (map ppr_bind binds'))
210 (_, binds') = doo initial_env binds
212 initial_env = OccEnv (simplifier_sw_chkr KeepUnusedBindings)
213 (simplifier_sw_chkr KeepSpecPragmaIds)
214 (not (simplifier_sw_chkr SimplMayDeleteConjurableIds))
215 (simplifier_sw_chkr IgnoreINLINEPragma)
216 (\id in_scope -> isLocallyDefined id) -- Anything local is interesting
217 emptyIdSet -- Not actually used
219 doo env [] = (emptyDetails, [])
221 = (final_usage, new_binds ++ the_rest)
223 new_env = env `addNewCands` (bindersOf bind)
224 (binds_usage, the_rest) = doo new_env binds
225 (final_usage, new_binds) = occAnalBind env bind binds_usage
227 -- This really ought to be done properly by PprCore, but
228 -- it isn't. pprCoreBinding only works on Id binders, and
229 -- the general case is complicated by the fact that it has to work
230 -- for interface files too. Sigh
232 ppr_bind bind@(NonRec binder expr)
235 ppr_bind bind@(Rec binds)
236 = vcat [ptext SLIT("Rec {"),
237 nest 2 (ppr PprDebug bind),
238 ptext SLIT("end Rec }")]
242 occurAnalyseExpr :: (Id -> Bool) -- Tells if a variable is interesting
244 -> (IdEnv BinderInfo, -- Occ info for interesting free vars
245 SimplifiableCoreExpr)
247 occurAnalyseExpr interesting expr
248 = occAnal initial_env expr
250 initial_env = OccEnv False {- Drop unused bindings -}
251 False {- Drop SpecPragmaId bindings -}
252 True {- Keep conjurable Ids -}
253 False {- Do not ignore INLINE Pragma -}
254 (\id locals -> interesting id || elementOfIdSet id locals)
257 occurAnalyseGlobalExpr :: CoreExpr -> SimplifiableCoreExpr
258 occurAnalyseGlobalExpr expr
259 = -- Top level expr, so no interesting free vars, and
260 -- discard occurence info returned
261 snd (occurAnalyseExpr (\_ -> False) expr)
264 %************************************************************************
266 \subsection[OccurAnal-main]{Counting occurrences: main function}
268 %************************************************************************
274 type Node details = (details, Int, [Int]) -- The Ints are gotten from the Unique,
275 -- which is gotten from the Id.
276 type Details1 = (Id, (UsageDetails, SimplifiableCoreExpr))
277 type Details2 = ((Id, BinderInfo), SimplifiableCoreExpr)
280 occAnalBind :: OccEnv
282 -> UsageDetails -- Usage details of scope
283 -> (UsageDetails, -- Of the whole let(rec)
284 [SimplifiableCoreBinding])
286 occAnalBind env (NonRec binder rhs) body_usage
287 | isNeeded env body_usage binder -- It's mentioned in body
288 = (final_body_usage `combineUsageDetails` rhs_usage,
289 [NonRec tagged_binder rhs'])
291 | otherwise -- Not mentioned, so drop dead code
295 binder' = nukeNoInlinePragma binder
296 (rhs_usage, rhs') = occAnalRhs env binder' rhs
297 (final_body_usage, tagged_binder) = tagBinder body_usage binder'
300 Dropping dead code for recursive bindings is done in a very simple way:
302 the entire set of bindings is dropped if none of its binders are
303 mentioned in its body; otherwise none are.
305 This seems to miss an obvious improvement.
320 Now @f@ is unused. But dependency analysis will sort this out into a
321 @letrec@ for @g@ and a @let@ for @f@, and then @f@ will get dropped.
322 It isn't easy to do a perfect job in one blow. Consider
336 occAnalBind env (Rec pairs) body_usage
337 = foldr (_scc_ "occAnalBind.dofinal" do_final_bind) (body_usage, []) sccs
339 pp_scc (CyclicSCC cycle) = hcat [text "Cyclic ", hcat (punctuate comma (map pp_item cycle))]
340 pp_scc (AcyclicSCC item) = hcat [text "Acyclic ", pp_item item]
341 pp_item (_, bndr, _) = ppr PprDebug bndr
343 binders = map fst pairs
344 new_env = env `addNewCands` binders
346 analysed_pairs :: [Details1]
347 analysed_pairs = [(nukeNoInlinePragma bndr, occAnalRhs new_env bndr rhs) | (bndr,rhs) <- pairs]
349 sccs :: [SCC (Node Details1)]
350 sccs = _scc_ "occAnalBind.scc" stronglyConnCompR edges
353 ---- stuff for dependency analysis of binds -------------------------------
354 edges :: [Node Details1]
355 edges = _scc_ "occAnalBind.assoc"
356 [ (pair, IBOX(u2i (idUnique id)), edges_from rhs_usage)
357 | pair@(id, (rhs_usage, rhs)) <- analysed_pairs
360 -- (a -> b) means a mentions b
361 -- Given the usage details (a UFM that gives occ info for each free var of
362 -- the RHS) we can get the list of free vars -- or rather their Int keys --
363 -- by just extracting the keys from the finite map. Grimy, but fast.
364 -- Previously we had this:
365 -- [ bndr | bndr <- bndrs,
366 -- maybeToBool (lookupIdEnv rhs_usage bndr)]
367 -- which has n**2 cost, and this meant that edges_from alone
368 -- consumed 10% of total runtime!
369 edges_from :: UsageDetails -> [Int]
370 edges_from rhs_usage = _scc_ "occAnalBind.edges_from"
373 ---- stuff to "re-constitute" bindings from dependency-analysis info ------
376 do_final_bind (AcyclicSCC ((bndr, (rhs_usage, rhs')), _, _)) (body_usage, binds_so_far)
377 | isNeeded env body_usage bndr
378 = (combined_usage, new_bind : binds_so_far)
380 = (body_usage, binds_so_far) -- Dead code
382 total_usage = combineUsageDetails body_usage rhs_usage
383 (combined_usage, tagged_bndr) = tagBinder total_usage bndr
384 new_bind = NonRec tagged_bndr rhs'
387 do_final_bind (CyclicSCC cycle) (body_usage, binds_so_far)
388 | any (isNeeded env body_usage) bndrs
389 = (combined_usage, final_bind:binds_so_far)
391 = (body_usage, binds_so_far) -- Dead code
393 pairs = [pair | (pair, _, _) <- cycle]
394 bndrs = [bndr | (bndr, _) <- pairs]
395 rhs_usages = [rhs_usage | (_, (rhs_usage, _)) <- pairs]
396 total_usage = foldr combineUsageDetails body_usage rhs_usages
397 (combined_usage, tagged_binders) = tagBinders total_usage bndrs
398 final_bind = Rec (reOrderRec env new_cycle)
400 new_cycle = CyclicSCC (zipWithEqual "occAnalBind" mk_new_bind tagged_binders cycle)
401 mk_new_bind tagged_bndr ((_, (_, rhs')), key, keys) = ((tagged_bndr, rhs'), key, keys)
404 @reOrderRec@ is applied to the list of (binder,rhs) pairs for a cyclic
405 strongly connected component (there's guaranteed to be a cycle). It returns the
407 a) in a better order,
408 b) with some of the Ids having a IMustNotBeINLINEd pragma
410 The "no-inline" Ids are sufficient to break all cycles in the SCC. This means
411 that the simplifier can guarantee not to loop provided it never records an inlining
412 for these no-inline guys.
414 Furthermore, the order of the binds is such that if we neglect dependencies
415 on the no-inline Ids then the binds are topologically sorted. This means
416 that the simplifier will generally do a good job if it works from top bottom,
417 recording inlinings for any Ids which aren't marked as "no-inline" as it goes.
419 Here's a case that bit me:
427 Re-ordering doesn't change the order of bindings, but there was no loop-breaker.
429 My solution was to make a=b bindings record b as Many, rather like INLINE bindings.
430 Perhaps something cleverer would suffice.
432 You might think that you can prevent non-termination simply by making
433 sure that we simplify a recursive binding's RHS in an environment that
434 simply clones the recursive Id. But no. Consider
436 letrec f = \x -> let z = f x' in ...
443 We bind n to its *simplified* RHS, we then *re-simplify* it when
444 we inline n. Then we may well inline f; and then the same thing
447 I don't think it's possible to prevent non-termination by environment
448 manipulation in this way. Apart from anything else, successive
449 iterations of the simplifier may unroll recursive loops in cases like
450 that above. The idea of beaking every recursive loop with an
451 IMustNotBeINLINEd pragma is much much better.
457 -> SCC (Node Details2)
459 -- Sorted into a plausible order. Enough of the Ids have
460 -- dontINLINE pragmas that there are no loops left.
462 -- Non-recursive case
463 reOrderRec env (AcyclicSCC (pair, _, _)) = [pair]
465 -- Common case of simple self-recursion
466 reOrderRec env (CyclicSCC [bind])
467 = [((addNoInlinePragma bndr, occ_info), rhs)]
469 (((bndr,occ_info), rhs), _, _) = bind
471 reOrderRec env (CyclicSCC binds)
472 = -- Choose a loop breaker, mark it no-inline,
473 -- do SCC analysis on the rest, and recursively sort them out
474 concat (map (reOrderRec env) (stronglyConnCompR unchosen))
476 [((addNoInlinePragma bndr, occ_info), rhs)]
479 (chosen_pair, unchosen) = choose_loop_breaker binds
480 ((bndr,occ_info), rhs) = chosen_pair
482 -- Choosing the loop breaker; heursitic
483 choose_loop_breaker (bind@(pair, _, _) : rest)
486 = (chosen, bind : unchosen) -- Don't pick it
487 | otherwise -- Pick it
490 (chosen, unchosen) = choose_loop_breaker rest
492 bad_choice ((bndr, occ_info), rhs)
493 = var_rhs rhs -- Dont pick var RHS
494 || inlineMe env bndr -- Dont pick INLINE thing
495 || one_occ occ_info -- Dont pick single-occ thing
496 || not_fun_ty (idType bndr) -- Dont pick data-ty thing
498 not_fun_ty ty = not (maybeToBool (getFunTy_maybe rho_ty))
500 (_, rho_ty) = splitForAllTy ty
503 var_rhs (Var v) = True
504 var_rhs other_rhs = False
506 -- One textual occurrence, whether inside lambda or whatever
507 -- We stick to just FunOccs because if we're not going to be able
508 -- to inline the thing on this round it might be better to pick
509 -- this one as the loop breaker. Real example (the Enum Ordering instance
511 -- rec f = \ x -> case d of (p,q,r) -> p x
512 -- g = \ x -> case d of (p,q,r) -> q x
515 -- Here, f and g occur just once; but we can't inline them into d.
516 -- On the other hand we *could* simplify those case expressions if
517 -- we didn't stupidly choose d as the loop breaker.
519 one_occ (OneOcc fun_or_arg _ _ _ _) = isFun fun_or_arg
520 one_occ other_bind = False
523 @occAnalRhs@ deals with the question of bindings where the Id is marked
524 by an INLINE pragma. For these we record that anything which occurs
525 in its RHS occurs many times. This pessimistically assumes that ths
526 inlined binder also occurs many times in its scope, but if it doesn't
527 we'll catch it next time round. At worst this costs an extra simplifier pass.
528 ToDo: try using the occurrence info for the inline'd binder.
530 [March 97] We do the same for atomic RHSs. Reason: see notes with reOrderRec.
534 -> Id -> CoreExpr -- Binder and rhs
535 -> (UsageDetails, SimplifiableCoreExpr)
537 occAnalRhs env id (Var v)
539 = (unitIdEnv v (markMany (funOccurrence 0)), Var v)
542 = (emptyDetails, Var v)
544 occAnalRhs env id rhs
546 = (mapIdEnv markMany rhs_usage, rhs')
552 (rhs_usage, rhs') = occAnal env rhs
560 -> (UsageDetails, -- Gives info only about the "interesting" Ids
561 SimplifiableCoreExpr)
565 = (unitIdEnv v (funOccurrence 0), Var v)
568 = (emptyDetails, Var v)
570 occAnal env (Lit lit) = (emptyDetails, Lit lit)
571 occAnal env (Prim op args) = (occAnalArgs env args, Prim op args)
574 We regard variables that occur as constructor arguments as "dangerousToDup":
578 f x = let y = expensive x in
580 (case z of {(p,q)->q}, case z of {(p,q)->q})
583 We feel free to duplicate the WHNF (True,y), but that means
584 that y may be duplicated thereby.
586 If we aren't careful we duplicate the (expensive x) call!
587 Constructors are rather like lambdas in this way.
590 occAnal env (Con con args) = (mapIdEnv markDangerousToDup (occAnalArgs env args),
593 occAnal env (SCC cc body)
594 = (mapIdEnv markInsideSCC usage, SCC cc body')
596 (usage, body') = occAnal env body
598 occAnal env (Coerce c ty body)
599 = (usage, Coerce c ty body')
601 (usage, body') = occAnal env body
603 occAnal env (App fun arg)
604 = (fun_usage `combineUsageDetails` arg_usage, App fun' arg)
606 (fun_usage, fun') = occAnal env fun
607 arg_usage = occAnalArg env arg
609 -- For value lambdas we do a special hack. Consider
611 -- If we did nothing, x is used inside the \y, so would be marked
612 -- as dangerous to dup. But in the common case where the abstraction
613 -- is applied to two arguments this is over-pessimistic.
614 -- So instead we don't take account of the \y when dealing with x's usage;
615 -- instead, the simplifier is careful when partially applying lambdas
617 occAnal env expr@(Lam (ValBinder binder) body)
618 = (mapIdEnv markDangerousToDup final_usage,
619 foldr ( \v b -> Lam (ValBinder v) b) body' tagged_binders)
621 (binders,body) = collectValBinders expr
622 (body_usage, body') = occAnal (env `addNewCands` binders) body
623 (final_usage, tagged_binders) = tagBinders body_usage binders
625 -- ANDY: WE MUST THINK ABOUT THIS! (ToDo)
626 occAnal env (Lam (TyBinder tyvar) body)
627 = case occAnal env body of { (body_usage, body') ->
628 (mapIdEnv markDangerousToDup body_usage,
629 Lam (TyBinder tyvar) body') }
631 -- (body_usage, body') = occAnal env body
633 occAnal env (Lam (UsageBinder _) _) = panic "OccurAnal.occAnal Lam UsageBinder"
635 occAnal env (Case scrut alts)
636 = case occAnalAlts env alts of { (alts_usage, alts') ->
637 case occAnal env scrut of { (scrut_usage, scrut') ->
639 det = scrut_usage `combineUsageDetails` alts_usage
641 if isNullIdEnv det then
642 (det, Case scrut' alts')
644 (det, Case scrut' alts') }}
646 (scrut_usage `combineUsageDetails` alts_usage,
649 (scrut_usage, scrut') = occAnal env scrut
650 (alts_usage, alts') = occAnalAlts env alts
653 occAnal env (Let bind body)
654 = case occAnal new_env body of { (body_usage, body') ->
655 case occAnalBind env bind body_usage of { (final_usage, new_binds) ->
656 (final_usage, foldr Let body' new_binds) }} -- mkCoLet* wants Core... (sigh)
658 new_env = env `addNewCands` (bindersOf bind)
659 -- (body_usage, body') = occAnal new_env body
660 -- (final_usage, new_binds) = occAnalBind env bind body_usage
666 occAnalAlts env (AlgAlts alts deflt)
667 = (foldr combineAltsUsageDetails deflt_usage alts_usage,
668 -- Note: combine*Alts*UsageDetails...
669 AlgAlts alts' deflt')
671 (alts_usage, alts') = unzip (map do_alt alts)
672 (deflt_usage, deflt') = occAnalDeflt env deflt
674 do_alt (con, args, rhs)
675 = (final_usage, (con, tagged_args, rhs'))
677 new_env = env `addNewCands` args
678 (rhs_usage, rhs') = occAnal new_env rhs
679 (final_usage, tagged_args) = tagBinders rhs_usage args
681 occAnalAlts env (PrimAlts alts deflt)
682 = (foldr combineAltsUsageDetails deflt_usage alts_usage,
683 -- Note: combine*Alts*UsageDetails...
684 PrimAlts alts' deflt')
686 (alts_usage, alts') = unzip (map do_alt alts)
687 (deflt_usage, deflt') = occAnalDeflt env deflt
690 = (rhs_usage, (lit, rhs'))
692 (rhs_usage, rhs') = occAnal env rhs
694 occAnalDeflt env NoDefault = (emptyDetails, NoDefault)
696 occAnalDeflt env (BindDefault binder rhs)
697 = (final_usage, BindDefault tagged_binder rhs')
699 new_env = env `addNewCand` binder
700 (rhs_usage, rhs') = occAnal new_env rhs
701 (final_usage, tagged_binder) = tagBinder rhs_usage binder
708 occAnalArgs :: OccEnv -> [CoreArg] -> UsageDetails
710 occAnalArgs env atoms
711 = foldr do_one_atom emptyDetails atoms
713 do_one_atom (VarArg v) usage
714 | isCandidate env v = addOneOcc usage v (argOccurrence 0)
716 do_one_atom other_arg usage = usage
719 occAnalArg :: OccEnv -> CoreArg -> UsageDetails
721 occAnalArg env (VarArg v)
722 | isCandidate env v = unitDetails v (argOccurrence 0)
723 | otherwise = emptyDetails
724 occAnalArg _ _ = emptyDetails