2 % (c) The AQUA Project, Glasgow University, 1994-1998
4 \section[LiberateCase]{Unroll recursion to allow evals to be lifted from a loop}
7 module LiberateCase ( liberateCase ) where
9 #include "HsVersions.h"
11 import CmdLineOpts ( DynFlags, DynFlag(..), dopt, opt_LiberateCaseThreshold )
12 import CoreLint ( showPass, endPass )
14 import CoreUnfold ( couldBeSmallEnoughToInline )
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.
53 Other examples we'd like to catch with this kind of transformation
59 We'd like to avoid the redundant pattern match, transforming to
63 last (x:(y:ys)) = last' y ys
66 last' _ (y:ys) = last' y ys
68 (is this necessarily an improvement)
75 drop n (x:xs) = drop (n-1) xs
77 Would like to pass n along unboxed.
80 To think about (Apr 94)
83 Main worry: duplicating code excessively. At the moment we duplicate
84 the entire binding group once at each recursive call. But there may
85 be a group of recursive calls which share a common set of evaluated
86 free variables, in which case the duplication is a plain waste.
88 Another thing we could consider adding is some unfold-threshold thing,
89 so that we'll only duplicate if the size of the group rhss isn't too
95 The ``level'' of a binder tells how many
96 recursive defns lexically enclose the binding
97 A recursive defn "encloses" its RHS, not its
100 letrec f = let g = ... in ...
105 Here, the level of @f@ is zero, the level of @g@ is one,
106 and the level of @h@ is zero (NB not one).
109 type LibCaseLevel = Int
111 topLevel :: LibCaseLevel
118 Int -- Bomb-out size for deciding if
119 -- potential liberatees are too big.
120 -- (passed in from cmd-line args)
122 LibCaseLevel -- Current level
124 (IdEnv LibCaseLevel) -- Binds all non-top-level in-scope Ids
125 -- (top-level and imported things have
128 (IdEnv CoreBind)-- Binds *only* recursively defined
129 -- Ids, to their own binding group,
130 -- and *only* in their own RHSs
132 [(Id,LibCaseLevel)] -- Each of these Ids was scrutinised by an
133 -- enclosing case expression, with the
134 -- specified number of enclosing
135 -- recursive bindings; furthermore,
136 -- the Id is bound at a lower level
137 -- than the case expression. The
138 -- order is insignificant; it's a bag
141 initEnv :: Int -> LibCaseEnv
142 initEnv bomb_size = LibCaseEnv bomb_size 0 emptyVarEnv emptyVarEnv []
144 bombOutSize (LibCaseEnv bomb_size _ _ _ _) = bomb_size
151 liberateCase :: DynFlags -> [CoreBind] -> IO [CoreBind]
152 liberateCase dflags binds
154 showPass dflags "Liberate case" ;
155 let { binds' = do_prog (initEnv opt_LiberateCaseThreshold) binds } ;
156 endPass dflags "Liberate case"
157 (dopt Opt_D_verbose_core2core dflags)
158 {- no specific flag for dumping -}
163 do_prog env (bind:binds) = bind' : do_prog env' binds
165 (env', bind') = libCaseBind env bind
172 libCaseBind :: LibCaseEnv -> CoreBind -> (LibCaseEnv, CoreBind)
174 libCaseBind env (NonRec binder rhs)
175 = (addBinders env [binder], NonRec binder (libCase env rhs))
177 libCaseBind env (Rec pairs)
178 = (env_body, Rec pairs')
180 (binders, rhss) = unzip pairs
182 env_body = addBinders env binders
184 pairs' = [(binder, libCase env_rhs rhs) | (binder,rhs) <- pairs]
186 env_rhs = if all rhs_small_enough rhss then extended_env else env
188 -- We extend the rec-env by binding each Id to its rhs, first
189 -- processing the rhs with an *un-extended* environment, so
190 -- that the same process doesn't occur for ever!
193 = addRecBinds env [ (binder, libCase env_body rhs)
194 | (binder, rhs) <- pairs ]
196 -- Why "localiseId" above? Because we're creating a new local
197 -- copy of the original binding. In particular, the original
198 -- binding might have been for a top-level, and this copy clearly
199 -- will not be top-level!
201 -- It is enough to change just the binder, because subsequent
202 -- simplification will propagate the right info from the binder.
204 -- Why does it matter? Because the codeGen keeps a separate
205 -- environment for top-level Ids, and it is disastrous for it
206 -- to think that something is top-level when it isn't.
208 -- [May 98: all this is now handled by SimplCore.tidyCore]
210 rhs_small_enough rhs = couldBeSmallEnoughToInline lIBERATE_BOMB_SIZE rhs
212 lIBERATE_BOMB_SIZE = bombOutSize env
220 libCase :: LibCaseEnv
224 libCase env (Var v) = libCaseId env v
225 libCase env (Lit lit) = Lit lit
226 libCase env (Type ty) = Type ty
227 libCase env (App fun arg) = App (libCase env fun) (libCase env arg)
228 libCase env (Note note body) = Note note (libCase env body)
230 libCase env (Lam binder body)
231 = Lam binder (libCase (addBinders env [binder]) body)
233 libCase env (Let bind body)
234 = Let bind' (libCase env_body body)
236 (env_body, bind') = libCaseBind env bind
238 libCase env (Case scrut bndr alts)
239 = Case (libCase env scrut) bndr (map (libCaseAlt env_alts) alts)
241 env_alts = addBinders env_with_scrut [bndr]
242 env_with_scrut = case scrut of
243 Var scrut_var -> addScrutedVar env scrut_var
246 libCaseAlt env (con,args,rhs) = (con, args, libCase (addBinders env args) rhs)
252 libCaseId :: LibCaseEnv -> Id -> CoreExpr
254 | maybeToBool maybe_rec_bind && -- It's a use of a recursive thing
255 there_are_free_scruts -- with free vars scrutinised in RHS
256 = Let the_bind (Var v)
262 maybe_rec_bind :: Maybe CoreBind -- The binding of the recursive thingy
263 maybe_rec_bind = lookupRecId env v
264 Just the_bind = maybe_rec_bind
266 rec_id_level = lookupLevel env v
268 there_are_free_scruts = freeScruts env rec_id_level
276 addBinders :: LibCaseEnv -> [CoreBndr] -> LibCaseEnv
277 addBinders (LibCaseEnv bomb lvl lvl_env rec_env scruts) binders
278 = LibCaseEnv bomb lvl lvl_env' rec_env scruts
280 lvl_env' = extendVarEnvList lvl_env (binders `zip` repeat lvl)
282 addRecBinds :: LibCaseEnv -> [(Id,CoreExpr)] -> LibCaseEnv
283 addRecBinds (LibCaseEnv bomb lvl lvl_env rec_env scruts) pairs
284 = LibCaseEnv bomb lvl' lvl_env' rec_env' scruts
287 lvl_env' = extendVarEnvList lvl_env [(binder,lvl) | (binder,_) <- pairs]
288 rec_env' = extendVarEnvList rec_env [(binder, Rec pairs) | (binder,_) <- pairs]
290 addScrutedVar :: LibCaseEnv
291 -> Id -- This Id is being scrutinised by a case expression
294 addScrutedVar env@(LibCaseEnv bomb lvl lvl_env rec_env scruts) scrut_var
296 = LibCaseEnv bomb lvl lvl_env rec_env scruts'
297 -- Add to scruts iff the scrut_var is being scrutinised at
298 -- a deeper level than its defn
302 scruts' = (scrut_var, lvl) : scruts
303 bind_lvl = case lookupVarEnv lvl_env scrut_var of
307 lookupRecId :: LibCaseEnv -> Id -> Maybe CoreBind
308 lookupRecId (LibCaseEnv bomb lvl lvl_env rec_env scruts) id
310 = lookupVarEnv rec_env id
312 = case (lookupVarEnv rec_env id) of
317 lookupLevel :: LibCaseEnv -> Id -> LibCaseLevel
318 lookupLevel (LibCaseEnv bomb lvl lvl_env rec_env scruts) id
319 = case lookupVarEnv lvl_env id of
323 freeScruts :: LibCaseEnv
324 -> LibCaseLevel -- Level of the recursive Id
325 -> Bool -- True <=> there is an enclosing case of a variable
326 -- bound outside (ie level <=) the recursive Id.
327 freeScruts (LibCaseEnv bomb lvl lvl_env rec_env scruts) rec_bind_lvl
328 = not (null free_scruts)
330 free_scruts = [v | (v,lvl) <- scruts, lvl > rec_bind_lvl]