2 % (c) The GRASP/AQUA Project, Glasgow University, 1992-1998
4 \section[SpecConstr]{Specialise over constructors}
11 #include "HsVersions.h"
14 import CoreLint ( showPass, endPass )
15 import CoreUtils ( exprType, exprIsConApp_maybe, eqExpr )
16 import CoreFVs ( exprsFreeVars )
17 import DataCon ( dataConRepArity )
18 import Type ( tyConAppArgs )
19 import PprCore ( pprCoreRules )
20 import Id ( Id, idName, idType, idSpecialisation,
22 mkUserLocal, mkSysLocal )
26 import Name ( nameOccName, nameSrcLoc )
27 import Rules ( addIdSpecialisations )
28 import OccName ( mkSpecOcc )
29 import ErrUtils ( dumpIfSet_dyn )
30 import CmdLineOpts ( DynFlags, DynFlag(..) )
33 import Maybes ( orElse )
34 import Util ( mapAccumL )
35 import List ( nubBy, partition )
40 -----------------------------------------------------
42 -----------------------------------------------------
47 drop n (x:xs) = drop (n-1) xs
49 After the first time round, we could pass n unboxed. This happens in
50 numerical code too. Here's what it looks like in Core:
52 drop n xs = case xs of
57 _ -> drop (I# (n# -# 1#)) xs
59 Notice that the recursive call has an explicit constructor as argument.
60 Noticing this, we can make a specialised version of drop
62 RULE: drop (I# n#) xs ==> drop' n# xs
64 drop' n# xs = let n = I# n# in ...orig RHS...
66 Now the simplifier will apply the specialisation in the rhs of drop', giving
68 drop' n# xs = case xs of
72 _ -> drop (n# -# 1#) xs
76 We'd also like to catch cases where a parameter is carried along unchanged,
77 but evaluated each time round the loop:
79 f i n = if i>0 || i>n then i else f (i*2) n
81 Here f isn't strict in n, but we'd like to avoid evaluating it each iteration.
82 In Core, by the time we've w/wd (f is strict in i) we get
84 f i# n = case i# ># 0 of
86 True -> case n of n' { I# n# ->
89 True -> f (i# *# 2#) n'
91 At the call to f, we see that the argument, n is know to be (I# n#),
92 and n is evaluated elsewhere in the body of f, so we can play the same
93 trick as above. However we don't want to do that if the boxed version
94 of n is needed (else we'd avoid the eval but pay more for re-boxing n).
95 So in this case we want that the *only* uses of n are in case statements.
100 * A self-recursive function. Ignore mutual recursion for now,
101 because it's less common, and the code is simpler for self-recursion.
105 a) At a recursive call, one or more parameters is an explicit
106 constructor application
108 That same parameter is scrutinised by a case somewhere in
109 the RHS of the function
113 b) At a recursive call, one or more parameters has an unfolding
114 that is an explicit constructor application
116 That same parameter is scrutinised by a case somewhere in
117 the RHS of the function
119 Those are the only uses of the parameter
122 There's a bit of a complication with type arguments. If the call
125 f p = ...f ((:) [a] x xs)...
127 then our specialised function look like
129 f_spec x xs = let p = (:) [a] x xs in ....as before....
131 This only makes sense if either
132 a) the type variable 'a' is in scope at the top of f, or
133 b) the type variable 'a' is an argument to f (and hence fs)
135 Actually, (a) may hold for value arguments too, in which case
136 we may not want to pass them. Supose 'x' is in scope at f's
137 defn, but xs is not. Then we'd like
139 f_spec xs = let p = (:) [a] x xs in ....as before....
141 Similarly (b) may hold too. If x is already an argument at the
142 call, no need to pass it again.
144 Finally, if 'a' is not in scope at the call site, we could abstract
145 it as we do the term variables:
147 f_spec a x xs = let p = (:) [a] x xs in ...as before...
149 So the grand plan is:
151 * abstract the call site to a constructor-only pattern
152 e.g. C x (D (f p) (g q)) ==> C s1 (D s2 s3)
154 * Find the free variables of the abstracted pattern
156 * Pass these variables, less any that are in scope at
160 NOTICE that we only abstract over variables that are not in scope,
161 so we're in no danger of shadowing variables used in "higher up"
165 %************************************************************************
167 \subsection{Top level wrapper stuff}
169 %************************************************************************
172 specConstrProgram :: DynFlags -> UniqSupply -> [CoreBind] -> IO [CoreBind]
173 specConstrProgram dflags us binds
175 showPass dflags "SpecConstr"
177 let (binds', _) = initUs us (go emptyScEnv binds)
179 endPass dflags "SpecConstr" Opt_D_dump_spec binds'
181 dumpIfSet_dyn dflags Opt_D_dump_rules "Top-level specialisations"
182 (vcat (map dump_specs (concat (map bindersOf binds'))))
186 go env [] = returnUs []
187 go env (bind:binds) = scBind env bind `thenUs` \ (env', _, bind') ->
188 go env' binds `thenUs` \ binds' ->
189 returnUs (bind' : binds')
191 dump_specs var = pprCoreRules var (idSpecialisation var)
195 %************************************************************************
197 \subsection{Environment: goes downwards}
199 %************************************************************************
202 data ScEnv = SCE { scope :: VarEnv HowBound,
203 -- Binds all non-top-level variables in scope
208 type ConstrEnv = IdEnv (AltCon, [CoreArg])
209 -- Variables known to be bound to a constructor
210 -- in a particular case alternative
212 emptyScEnv = SCE { scope = emptyVarEnv, cons = emptyVarEnv }
214 data HowBound = RecFun -- These are the recursive functions for which
215 -- we seek interesting call patterns
217 | RecArg -- These are those functions' arguments; we are
218 -- interested to see if those arguments are scrutinised
220 | Other -- We track all others so we know what's in scope
221 -- This is used in spec_one to check what needs to be
222 -- passed as a parameter and what is in scope at the
223 -- function definition site
225 lookupScopeEnv env v = lookupVarEnv (scope env) v
227 extendBndrs env bndrs = env { scope = extendVarEnvList (scope env) [(b,Other) | b <- bndrs] }
228 extendBndr env bndr = env { scope = extendVarEnv (scope env) bndr Other }
233 -- we want to bind b, and perhaps scrut too, to (C x y)
234 extendCaseBndr env case_bndr scrut con alt_bndrs
236 Var v -> -- Bind the scrutinee in the ConstrEnv if it's a variable
237 -- Also forget if the scrutinee is a RecArg, because we're
238 -- now in the branch of a case, and we don't want to
239 -- record a non-scrutinee use of v if we have
240 -- case v of { (a,b) -> ...(f v)... }
241 SCE { scope = extendVarEnv (scope env1) v Other,
242 cons = extendVarEnv (cons env1) v (con,args) }
246 env1 = SCE { scope = extendVarEnvList (scope env) [(b,Other) | b <- case_bndr : alt_bndrs],
247 cons = extendVarEnv (cons env) case_bndr (con,args) }
249 args = map Type (tyConAppArgs (idType case_bndr)) ++
250 map varToCoreExpr alt_bndrs
252 -- When we encounter a recursive function binding
254 -- we want to extend the scope env with bindings
255 -- that record that f is a RecFn and x,y are RecArgs
256 extendRecBndr env fn bndrs
257 = env { scope = scope env `extendVarEnvList`
258 ((fn,RecFun): [(bndr,RecArg) | bndr <- bndrs]) }
262 %************************************************************************
264 \subsection{Usage information: flows upwards}
266 %************************************************************************
271 calls :: !(IdEnv ([Call])), -- Calls
272 -- The functions are a subset of the
273 -- RecFuns in the ScEnv
275 occs :: !(IdEnv ArgOcc) -- Information on argument occurrences
276 } -- The variables are a subset of the
277 -- RecArg in the ScEnv
279 type Call = (ConstrEnv, [CoreArg])
280 -- The arguments of the call, together with the
281 -- env giving the constructor bindings at the call site
283 nullUsage = SCU { calls = emptyVarEnv, occs = emptyVarEnv }
285 combineUsage u1 u2 = SCU { calls = plusVarEnv_C (++) (calls u1) (calls u2),
286 occs = plusVarEnv_C combineOcc (occs u1) (occs u2) }
288 combineUsages [] = nullUsage
289 combineUsages us = foldr1 combineUsage us
291 data ArgOcc = CaseScrut
295 instance Outputable ArgOcc where
296 ppr CaseScrut = ptext SLIT("case-scrut")
297 ppr OtherOcc = ptext SLIT("other-occ")
298 ppr Both = ptext SLIT("case-scrut and other")
300 combineOcc CaseScrut CaseScrut = CaseScrut
301 combineOcc OtherOcc OtherOcc = OtherOcc
302 combineOcc _ _ = Both
306 %************************************************************************
308 \subsection{The main recursive function}
310 %************************************************************************
312 The main recursive function gathers up usage information, and
313 creates specialised versions of functions.
316 scExpr :: ScEnv -> CoreExpr -> UniqSM (ScUsage, CoreExpr)
317 -- The unique supply is needed when we invent
318 -- a new name for the specialised function and its args
320 scExpr env e@(Type t) = returnUs (nullUsage, e)
321 scExpr env e@(Lit l) = returnUs (nullUsage, e)
322 scExpr env e@(Var v) = returnUs (varUsage env v OtherOcc, e)
323 scExpr env (Note n e) = scExpr env e `thenUs` \ (usg,e') ->
324 returnUs (usg, Note n e')
325 scExpr env (Lam b e) = scExpr (extendBndr env b) e `thenUs` \ (usg,e') ->
326 returnUs (usg, Lam b e')
328 scExpr env (Case scrut b alts)
329 = sc_scrut scrut `thenUs` \ (scrut_usg, scrut') ->
330 mapAndUnzipUs sc_alt alts `thenUs` \ (alts_usgs, alts') ->
331 returnUs (combineUsages alts_usgs `combineUsage` scrut_usg,
334 sc_scrut e@(Var v) = returnUs (varUsage env v CaseScrut, e)
335 sc_scrut e = scExpr env e
337 sc_alt (con,bs,rhs) = scExpr env1 rhs `thenUs` \ (usg,rhs') ->
338 returnUs (usg, (con,bs,rhs'))
340 env1 = extendCaseBndr env b scrut con bs
342 scExpr env (Let bind body)
343 = scBind env bind `thenUs` \ (env', bind_usg, bind') ->
344 scExpr env' body `thenUs` \ (body_usg, body') ->
345 returnUs (bind_usg `combineUsage` body_usg, Let bind' body')
347 scExpr env e@(App _ _)
349 (fn, args) = collectArgs e
351 mapAndUnzipUs (scExpr env) args `thenUs` \ (usgs, args') ->
353 arg_usg = combineUsages usgs
354 fn_usg | Var f <- fn,
355 Just RecFun <- lookupScopeEnv env f
356 = SCU { calls = unitVarEnv f [(cons env, args)],
361 returnUs (arg_usg `combineUsage` fn_usg, mkApps fn args')
362 -- Don't bother to look inside fn;
363 -- it's almost always a variable
365 ----------------------
366 scBind :: ScEnv -> CoreBind -> UniqSM (ScEnv, ScUsage, CoreBind)
367 scBind env (Rec [(fn,rhs)])
368 | not (null val_bndrs)
369 = scExpr env' body `thenUs` \ (usg, body') ->
371 SCU { calls = calls, occs = occs } = usg
373 specialise env fn bndrs body usg `thenUs` \ (rules, spec_prs) ->
374 returnUs (extendBndrs env bndrs,
375 SCU { calls = calls `delVarEnv` fn, occs = occs `delVarEnvList` val_bndrs},
376 Rec ((fn `addIdSpecialisations` rules, mkLams bndrs body') : spec_prs))
378 (bndrs,body) = collectBinders rhs
379 val_bndrs = filter isId bndrs
380 env' = extendRecBndr env fn bndrs
383 = mapAndUnzipUs do_one prs `thenUs` \ (usgs, prs') ->
384 returnUs (extendBndrs env (map fst prs), combineUsages usgs, Rec prs')
386 do_one (bndr,rhs) = scExpr env rhs `thenUs` \ (usg, rhs') ->
387 returnUs (usg, (bndr,rhs'))
389 scBind env (NonRec bndr rhs)
390 = scExpr env rhs `thenUs` \ (usg, rhs') ->
391 returnUs (extendBndr env bndr, usg, NonRec bndr rhs')
393 ----------------------
395 | Just RecArg <- lookupScopeEnv env v = SCU { calls = emptyVarEnv,
396 occs = unitVarEnv v use }
397 | otherwise = nullUsage
401 %************************************************************************
403 \subsection{The specialiser}
405 %************************************************************************
410 -> [CoreBndr] -> CoreExpr -- Its RHS
411 -> ScUsage -- Info on usage
412 -> UniqSM ([CoreRule], -- Rules
413 [(Id,CoreExpr)]) -- Bindings
415 specialise env fn bndrs body (SCU {calls=calls, occs=occs})
416 = getUs `thenUs` \ us ->
418 all_calls = lookupVarEnv calls fn `orElse` []
420 good_calls :: [[CoreArg]]
422 | (con_env, call_args) <- all_calls,
423 length call_args >= n_bndrs, -- App is saturated
424 let call = (bndrs `zip` call_args),
425 any (good_arg con_env occs) call, -- At least one arg is a constr app
426 let (_, pats) = argsToPats con_env us call_args
429 pprTrace "specialise" (ppr all_calls $$ ppr good_calls) $
430 mapAndUnzipUs (spec_one env fn (mkLams bndrs body))
431 (nubBy same_call good_calls `zip` [1..])
433 n_bndrs = length bndrs
434 same_call as1 as2 = and (zipWith eqExpr as1 as2)
436 ---------------------
437 good_arg :: ConstrEnv -> IdEnv ArgOcc -> (CoreBndr, CoreArg) -> Bool
438 good_arg con_env arg_occs (bndr, arg)
439 = case is_con_app_maybe con_env arg of
440 Just _ -> bndr_usg_ok arg_occs bndr arg
443 bndr_usg_ok :: IdEnv ArgOcc -> Var -> CoreArg -> Bool
444 bndr_usg_ok arg_occs bndr arg
445 = pprTrace "bndr_ok" (ppr bndr <+> ppr (lookupVarEnv arg_occs bndr)) $
446 case lookupVarEnv arg_occs bndr of
447 Just CaseScrut -> True -- Used only by case scrutiny
448 Just Both -> case arg of -- Used by case and elsewhere
449 App _ _ -> True -- so the arg should be an explicit con app
451 other -> False -- Not used, or used wonkily
454 ---------------------
457 -> CoreExpr -- Rhs of the original function
459 -> UniqSM (CoreRule, (Id,CoreExpr)) -- Rule and binding
461 -- spec_one creates a specialised copy of the function, together
462 -- with a rule for using it. I'm very proud of how short this
463 -- function is, considering what it does :-).
469 f = /\b \y::[(a,b)] -> ....f (b,c) ((:) (a,(b,c)) v (h v))...
470 [c is presumably bound by the (...) part]
472 f_spec = /\ b c \ v::(a,(b,c)) ->
473 (...entire RHS of f...) (b,c) ((:) (a,(b,c)) v (h v))
478 h::(a,(b,c))->[(a,(b,c))] .
480 f (b,c) ((:) (a,(b,c)) v (h v)) = f_spec b c v
483 spec_one env fn rhs (pats, n)
484 = getUniqueUs `thenUs` \ spec_uniq ->
487 fn_loc = nameSrcLoc fn_name
488 spec_occ = mkSpecOcc (nameOccName fn_name)
489 pat_fvs = varSetElems (exprsFreeVars pats)
490 vars_to_bind = filter not_avail pat_fvs
491 not_avail v = not (v `elemVarEnv` scope env)
492 -- Put the type variables first just for tidiness
493 (tvs, ids) = partition isTyVar vars_to_bind
496 rule_name = _PK_ ("SC:" ++ showSDoc (ppr fn <> int n))
497 spec_rhs = mkLams bndrs (mkApps rhs pats)
498 spec_id = mkUserLocal spec_occ spec_uniq (exprType spec_rhs) fn_loc
499 rule = Rule rule_name pat_fvs pats (mkVarApps (Var spec_id) bndrs)
501 returnUs (rule, (spec_id, spec_rhs))
504 %************************************************************************
506 \subsection{Argument analysis}
508 %************************************************************************
510 This code deals with analysing call-site arguments to see whether
511 they are constructor applications.
514 -- argToPat takes an actual argument, and returns an abstracted
515 -- version, consisting of just the "constructor skeleton" of the
516 -- argument, with non-constructor sub-expression replaced by new
517 -- placeholder variables. For example:
518 -- C a (D (f x) (g y)) ==> C p1 (D p2 p3)
520 argToPat :: ConstrEnv -> UniqSupply -> CoreArg -> (UniqSupply, CoreExpr)
521 argToPat env us (Type ty)
525 | Just (dc,args) <- is_con_app_maybe env arg
527 (us',args') = argsToPats env us args
529 (us', mk_con_app dc args')
531 argToPat env us (Var v) -- Don't uniqify existing vars,
532 = (us, Var v) -- so that we can spot when we pass them twice
535 = (us1, Var (mkSysLocal SLIT("sc") (uniqFromSupply us2) (exprType arg)))
537 (us1,us2) = splitUniqSupply us
539 argsToPats :: ConstrEnv -> UniqSupply -> [CoreArg] -> (UniqSupply, [CoreExpr])
540 argsToPats env us args = mapAccumL (argToPat env) us args
545 is_con_app_maybe :: ConstrEnv -> CoreExpr -> Maybe (AltCon, [CoreExpr])
546 is_con_app_maybe env (Var v)
548 -- You might think we could look in the idUnfolding here
549 -- but that doesn't take account of which branch of a
550 -- case we are in, which is the whole point
552 is_con_app_maybe env (Lit lit)
553 = Just (LitAlt lit, [])
555 is_con_app_maybe env expr
556 = case collectArgs expr of
557 (Var fun, args) | Just con <- isDataConId_maybe fun,
558 length args >= dataConRepArity con
559 -- Might be > because the arity excludes type args
560 -> Just (DataAlt con,args)
564 mk_con_app :: AltCon -> [CoreArg] -> CoreExpr
565 mk_con_app (LitAlt lit) [] = Lit lit
566 mk_con_app (DataAlt con) args = mkConApp con args