2 % (c) The AQUA Project, Glasgow University, 1994
4 \section[LiberateCase]{Unroll recursion to allow evals to be lifted from a loop}
8 #include "HsVersions.h"
10 module LiberateCase ( liberateCase ) where
12 import CoreUnfold ( UnfoldingGuidance(..) )
13 import Id ( localiseId, toplevelishId{-debugging-} )
20 This module walks over @Core@, and looks for @case@ on free variables.
22 if there is case on a free on the route to the recursive call,
23 then the recursive call is replaced with an unfolding.
32 => the inner f is replaced.
41 (note the NEED for shadowing)
43 => Run Andr\'e's wonder pass ...
50 Better code, because 'a' is free inside the inner letrec, rather
51 than needing projection from v.
54 To think about (Apr 94)
57 Main worry: duplicating code excessively. At the moment we duplicate
58 the entire binding group once at each recursive call. But there may
59 be a group of recursive calls which share a common set of evaluated
60 free variables, in which case the duplication is a plain waste.
62 Another thing we could consider adding is some unfold-threshold thing,
63 so that we'll only duplicate if the size of the group rhss isn't too
69 The ``level'' of a binder tells how many
70 recursive defns lexically enclose the binding
71 A recursive defn "encloses" its RHS, not its
74 letrec f = let g = ... in ...
79 Here, the level of @f@ is zero, the level of @g@ is one,
80 and the level of @h@ is zero (NB not one).
83 type LibCaseLevel = Int
85 topLevel :: LibCaseLevel
92 Int -- Bomb-out size for deciding if
93 -- potential liberatees are too big.
94 -- (passed in from cmd-line args)
96 LibCaseLevel -- Current level
98 (IdEnv LibCaseLevel) -- Binds all non-top-level in-scope Ids
99 -- (top-level and imported things have
102 (IdEnv CoreBinding)-- Binds *only* recursively defined
103 -- Ids, to their own binding group,
104 -- and *only* in their own RHSs
106 [(Id,LibCaseLevel)] -- Each of these Ids was scrutinised by an
107 -- enclosing case expression, with the
108 -- specified number of enclosing
109 -- recursive bindings; furthermore,
110 -- the Id is bound at a lower level
111 -- than the case expression. The
112 -- order is insignificant; it's a bag
115 initEnv :: Int -> LibCaseEnv
116 initEnv bomb_size = LibCaseEnv bomb_size 0 nullIdEnv nullIdEnv []
118 bombOutSize (LibCaseEnv bomb_size _ _ _ _) = bomb_size
125 liberateCase :: Int -> [CoreBinding] -> [CoreBinding]
126 liberateCase bomb_size prog
127 = do_prog (initEnv bomb_size) prog
130 do_prog env (bind:binds) = bind' : do_prog env' binds
132 (env', bind') = libCaseBind env bind
139 libCaseBind :: LibCaseEnv -> CoreBinding -> (LibCaseEnv, CoreBinding)
141 libCaseBind env (NonRec binder rhs)
142 = (addBinders env [binder], NonRec binder (libCase env rhs))
144 libCaseBind env (Rec pairs)
145 = (env_body, Rec pairs')
147 (binders, rhss) = unzip pairs
149 env_body = addBinders env binders
151 pairs' = [(binder, libCase env_rhs rhs) | (binder,rhs) <- pairs]
153 env_rhs = if all rhs_small_enough rhss then extended_env else env
155 -- We extend the rec-env by binding each Id to its rhs, first
156 -- processing the rhs with an *un-extended* environment, so
157 -- that the same process doesn't occur for ever!
160 = addRecBinds env [ (localiseId binder, libCase env_body rhs)
161 | (binder, rhs) <- pairs ]
163 -- Why "localiseId" above? Because we're creating a new local
164 -- copy of the original binding. In particular, the original
165 -- binding might have been for a TopLevId, and this copy clearly
166 -- will not be top-level!
168 -- It is enough to change just the binder, because subsequent
169 -- simplification will propagate the right info from the binder.
171 -- Why does it matter? Because the codeGen keeps a separate
172 -- environment for top-level Ids, and it is disastrous for it
173 -- to think that something is top-level when it isn't.
176 = case (calcUnfoldingGuidance True{-sccs OK-} lIBERATE_BOMB_SIZE rhs) of
178 _ -> True -- we didn't BOMB, so it must be OK
180 lIBERATE_BOMB_SIZE = bombOutSize env
188 libCase :: LibCaseEnv
192 libCase env (Lit lit) = Lit lit
193 libCase env (Var v) = mkCoLetsNoUnboxed (libCaseId env v) (Var v)
194 libCase env (App fun arg) = mkCoLetsNoUnboxed (libCaseAtom env arg) (App (libCase env fun) arg)
195 libCase env (CoTyApp fun ty) = CoTyApp (libCase env fun) ty
196 libCase env (Con con tys args) = mkCoLetsNoUnboxed (libCaseAtoms env args) (Con con tys args)
197 libCase env (Prim op tys args) = mkCoLetsNoUnboxed (libCaseAtoms env args) (Prim op tys args)
198 libCase env (CoTyLam tyvar body) = CoTyLam tyvar (libCase env body)
199 libCase env (SCC cc body) = SCC cc (libCase env body)
201 libCase env (Lam binder body)
202 = Lam binder (libCase (addBinders env [binder]) body)
204 libCase env (Let bind body)
205 = Let bind' (libCase env_body body)
207 (env_body, bind') = libCaseBind env bind
209 libCase env (Case scrut alts)
210 = Case (libCase env scrut) (libCaseAlts env_alts alts)
212 env_alts = case scrut of
213 Var scrut_var -> addScrutedVar env scrut_var
222 libCaseAlts env (AlgAlts alts deflt)
223 = AlgAlts (map do_alt alts) (libCaseDeflt env deflt)
225 do_alt (con,args,rhs) = (con, args, libCase (addBinders env args) rhs)
227 libCaseAlts env (PrimAlts alts deflt)
228 = PrimAlts (map do_alt alts) (libCaseDeflt env deflt)
230 do_alt (lit,rhs) = (lit, libCase env rhs)
232 libCaseDeflt env NoDefault
234 libCaseDeflt env (BindDefault binder rhs)
235 = BindDefault binder (libCase (addBinders env [binder]) rhs)
241 libCaseAtoms :: LibCaseEnv -> [CoreArg] -> [CoreBinding]
242 libCaseAtoms env atoms = concat [libCaseAtom env atom | atom <- atoms]
244 libCaseAtom :: LibCaseEnv -> CoreArg -> [CoreBinding]
245 libCaseAtom env (VarArg arg_id) = libCaseId env arg_id
246 libCaseAtom env (LitArg lit) = []
248 libCaseId :: LibCaseEnv -> Id -> [CoreBinding]
250 | maybeToBool maybe_rec_bind && -- It's a use of a recursive thing
251 there_are_free_scruts -- with free vars scrutinised in RHS
258 maybe_rec_bind :: Maybe CoreBinding -- The binding of the recursive thingy
259 maybe_rec_bind = lookupRecId env v
260 Just the_bind = maybe_rec_bind
262 rec_id_level = lookupLevel env v
264 there_are_free_scruts = freeScruts env rec_id_level
272 addBinders :: LibCaseEnv -> [Id] -> LibCaseEnv
273 addBinders (LibCaseEnv bomb lvl lvl_env rec_env scruts) binders
274 = LibCaseEnv bomb lvl lvl_env' rec_env scruts
276 lvl_env' = growIdEnvList lvl_env (binders `zip` repeat lvl)
278 addRecBinds :: LibCaseEnv -> [(Id,CoreExpr)] -> LibCaseEnv
279 addRecBinds (LibCaseEnv bomb lvl lvl_env rec_env scruts) pairs
280 = LibCaseEnv bomb lvl' lvl_env' rec_env' scruts
283 lvl_env' = growIdEnvList lvl_env [(binder,lvl) | (binder,_) <- pairs]
284 rec_env' = growIdEnvList rec_env [(binder, Rec pairs) | (binder,_) <- pairs]
286 addScrutedVar :: LibCaseEnv
287 -> Id -- This Id is being scrutinised by a case expression
290 addScrutedVar env@(LibCaseEnv bomb lvl lvl_env rec_env scruts) scrut_var
292 = LibCaseEnv bomb lvl lvl_env rec_env scruts'
293 -- Add to scruts iff the scrut_var is being scrutinised at
294 -- a deeper level than its defn
298 scruts' = (scrut_var, lvl) : scruts
299 bind_lvl = case lookupIdEnv lvl_env scrut_var of
301 Nothing -> --false: ASSERT(toplevelishId scrut_var)
304 lookupRecId :: LibCaseEnv -> Id -> Maybe CoreBinding
305 lookupRecId (LibCaseEnv bomb lvl lvl_env rec_env scruts) id
307 = lookupIdEnv rec_env id
309 = case (lookupIdEnv rec_env id) of
311 xxx -> --false: ASSERT(toplevelishId id)
315 lookupLevel :: LibCaseEnv -> Id -> LibCaseLevel
316 lookupLevel (LibCaseEnv bomb lvl lvl_env rec_env scruts) id
317 = case lookupIdEnv lvl_env id of
319 Nothing -> ASSERT(toplevelishId id)
322 freeScruts :: LibCaseEnv
323 -> LibCaseLevel -- Level of the recursive Id
324 -> Bool -- True <=> there is an enclosing case of a variable
325 -- bound outside (ie level <=) the recursive Id.
326 freeScruts (LibCaseEnv bomb lvl lvl_env rec_env scruts) rec_bind_lvl
327 = not (null free_scruts)
329 free_scruts = [v | (v,lvl) <- scruts, lvl > rec_bind_lvl]