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 )
17 import UniqFM ( ufmToList )
22 This module walks over @Core@, and looks for @case@ on free variables.
24 if there is case on a free on the route to the recursive call,
25 then the recursive call is replaced with an unfolding.
34 => the inner f is replaced.
43 (note the NEED for shadowing)
54 Better code, because 'a' is free inside the inner letrec, rather
55 than needing projection from v.
57 Other examples we'd like to catch with this kind of transformation
63 We'd like to avoid the redundant pattern match, transforming to
67 last (x:(y:ys)) = last' y ys
70 last' _ (y:ys) = last' y ys
72 (is this necessarily an improvement)
79 drop n (x:xs) = drop (n-1) xs
81 Would like to pass n along unboxed.
84 To think about (Apr 94)
87 Main worry: duplicating code excessively. At the moment we duplicate
88 the entire binding group once at each recursive call. But there may
89 be a group of recursive calls which share a common set of evaluated
90 free variables, in which case the duplication is a plain waste.
92 Another thing we could consider adding is some unfold-threshold thing,
93 so that we'll only duplicate if the size of the group rhss isn't too
99 The ``level'' of a binder tells how many
100 recursive defns lexically enclose the binding
101 A recursive defn "encloses" its RHS, not its
104 letrec f = let g = ... in ...
109 Here, the level of @f@ is zero, the level of @g@ is one,
110 and the level of @h@ is zero (NB not one).
113 type LibCaseLevel = Int
115 topLevel :: LibCaseLevel
122 Int -- Bomb-out size for deciding if
123 -- potential liberatees are too big.
124 -- (passed in from cmd-line args)
126 LibCaseLevel -- Current level
128 (IdEnv LibCaseLevel) -- Binds all non-top-level in-scope Ids
129 -- (top-level and imported things have
132 (IdEnv CoreBind) -- Binds *only* recursively defined
133 -- Ids, to their own binding group,
134 -- and *only* in their own RHSs
136 [(Id,LibCaseLevel)] -- Each of these Ids was scrutinised by an
137 -- enclosing case expression, with the
138 -- specified number of enclosing
139 -- recursive bindings; furthermore,
140 -- the Id is bound at a lower level
141 -- than the case expression. The
142 -- order is insignificant; it's a bag
145 initEnv :: Int -> LibCaseEnv
146 initEnv bomb_size = LibCaseEnv bomb_size 0 emptyVarEnv emptyVarEnv []
148 pprEnv :: LibCaseEnv -> SDoc
149 pprEnv (LibCaseEnv _ lvl lvl_env _ scruts)
150 = vcat [text "LibCaseEnv" <+> int lvl,
151 fsep (map ppr (ufmToList lvl_env)),
152 fsep (map ppr scruts)]
154 bombOutSize (LibCaseEnv bomb_size _ _ _ _) = bomb_size
161 liberateCase :: DynFlags -> [CoreBind] -> IO [CoreBind]
162 liberateCase dflags binds
164 showPass dflags "Liberate case" ;
165 let { binds' = do_prog (initEnv opt_LiberateCaseThreshold) binds } ;
166 endPass dflags "Liberate case" Opt_D_verbose_core2core binds'
167 {- no specific flag for dumping -}
171 do_prog env (bind:binds) = bind' : do_prog env' binds
173 (env', bind') = libCaseBind env bind
180 libCaseBind :: LibCaseEnv -> CoreBind -> (LibCaseEnv, CoreBind)
182 libCaseBind env (NonRec binder rhs)
183 = (addBinders env [binder], NonRec binder (libCase env rhs))
185 libCaseBind env (Rec pairs)
186 = (env_body, Rec pairs')
188 (binders, rhss) = unzip pairs
190 env_body = addBinders env binders
192 pairs' = [(binder, libCase env_rhs rhs) | (binder,rhs) <- pairs]
194 env_rhs = if all rhs_small_enough rhss then extended_env else env
196 -- We extend the rec-env by binding each Id to its rhs, first
197 -- processing the rhs with an *un-extended* environment, so
198 -- that the same process doesn't occur for ever!
200 extended_env = addRecBinds env [ (binder, libCase env_body rhs)
201 | (binder, rhs) <- pairs ]
203 rhs_small_enough rhs = couldBeSmallEnoughToInline lIBERATE_BOMB_SIZE rhs
204 lIBERATE_BOMB_SIZE = bombOutSize env
212 libCase :: LibCaseEnv
216 libCase env (Var v) = libCaseId env v
217 libCase env (Lit lit) = Lit lit
218 libCase env (Type ty) = Type ty
219 libCase env (App fun arg) = App (libCase env fun) (libCase env arg)
220 libCase env (Note note body) = Note note (libCase env body)
222 libCase env (Lam binder body)
223 = Lam binder (libCase (addBinders env [binder]) body)
225 libCase env (Let bind body)
226 = Let bind' (libCase env_body body)
228 (env_body, bind') = libCaseBind env bind
230 libCase env (Case scrut bndr alts)
231 = Case (libCase env scrut) bndr (map (libCaseAlt env_alts) alts)
233 env_alts = addBinders env_with_scrut [bndr]
234 env_with_scrut = case scrut of
235 Var scrut_var -> addScrutedVar env scrut_var
238 libCaseAlt env (con,args,rhs) = (con, args, libCase (addBinders env args) rhs)
244 libCaseId :: LibCaseEnv -> Id -> CoreExpr
246 | Just the_bind <- lookupRecId env v -- It's a use of a recursive thing
247 , not (null free_scruts) -- with free vars scrutinised in RHS
248 = Let the_bind (Var v)
254 rec_id_level = lookupLevel env v
255 free_scruts = freeScruts env rec_id_level
263 addBinders :: LibCaseEnv -> [CoreBndr] -> LibCaseEnv
264 addBinders (LibCaseEnv bomb lvl lvl_env rec_env scruts) binders
265 = LibCaseEnv bomb lvl lvl_env' rec_env scruts
267 lvl_env' = extendVarEnvList lvl_env (binders `zip` repeat lvl)
269 addRecBinds :: LibCaseEnv -> [(Id,CoreExpr)] -> LibCaseEnv
270 addRecBinds (LibCaseEnv bomb lvl lvl_env rec_env scruts) pairs
271 = LibCaseEnv bomb lvl' lvl_env' rec_env' scruts
274 lvl_env' = extendVarEnvList lvl_env [(binder,lvl) | (binder,_) <- pairs]
275 rec_env' = extendVarEnvList rec_env [(binder, Rec pairs) | (binder,_) <- pairs]
277 addScrutedVar :: LibCaseEnv
278 -> Id -- This Id is being scrutinised by a case expression
281 addScrutedVar env@(LibCaseEnv bomb lvl lvl_env rec_env scruts) scrut_var
283 = LibCaseEnv bomb lvl lvl_env rec_env scruts'
284 -- Add to scruts iff the scrut_var is being scrutinised at
285 -- a deeper level than its defn
289 scruts' = (scrut_var, lvl) : scruts
290 bind_lvl = case lookupVarEnv lvl_env scrut_var of
294 lookupRecId :: LibCaseEnv -> Id -> Maybe CoreBind
295 lookupRecId (LibCaseEnv bomb lvl lvl_env rec_env scruts) id
296 = lookupVarEnv rec_env id
298 lookupLevel :: LibCaseEnv -> Id -> LibCaseLevel
299 lookupLevel (LibCaseEnv bomb lvl lvl_env rec_env scruts) id
300 = case lookupVarEnv lvl_env id of
304 freeScruts :: LibCaseEnv
305 -> LibCaseLevel -- Level of the recursive Id
306 -> [Id] -- Ids that are scrutinised between the binding
307 -- of the recursive Id and here
308 freeScruts (LibCaseEnv bomb lvl lvl_env rec_env scruts) rec_bind_lvl
309 = [v | (v,scrut_lvl) <- scruts, scrut_lvl > rec_bind_lvl]