2 % (c) The AQUA Project, Glasgow University, 1993-1998
4 \section{Common subexpression}
11 #include "HsVersions.h"
13 import CmdLineOpts ( opt_D_dump_cse, opt_D_verbose_core2core )
14 import Id ( Id, idType )
15 import CoreUtils ( hashExpr, cheapEqExpr, exprIsBig, mkAltExpr )
16 import DataCon ( isUnboxedTupleCon )
17 import Type ( splitTyConApp_maybe )
18 import Subst ( InScopeSet, uniqAway, emptyInScopeSet, extendInScopeSet, elemInScopeSet )
21 import CoreLint ( beginPass, endPass )
23 import Util ( mapAccumL )
28 Simple common sub-expression
29 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
33 we build up a reverse mapping: C a b -> x1
35 and apply that to the rest of the program.
40 we replace the C a b with x1. But then we *dont* want to
41 add x1 -> y1 to the mapping. Rather, we want the reverse, y1 -> x1
42 so that a subsequent binding
44 will get transformed to C x1 b, and then to x2.
46 So we carry an extra var->var substitution which we apply *before* looking up in the
52 We have to be careful about shadowing.
54 f = \x -> let y = x+x in
58 Here we must *not* do CSE on the inner x+x! The simplifier used to guarantee no
59 shadowing, but it doesn't any more (it proved too hard), so we clone as we go.
60 We can simply add clones to the substitution already described.
62 However, we do NOT clone type variables. It's just too hard, because then we need
63 to run the substitution over types and IdInfo. No no no. Instead, we just throw
64 away the entire reverse mapping if this unusual situation ever shows up.
65 (In fact, I think the simplifier does guarantee no-shadowing for type variables.)
68 Another important wrinkle
69 ~~~~~~~~~~~~~~~~~~~~~~~~~
72 f = \x -> case x of wild {
73 (a:as) -> case a of wild1 {
74 (p,q) -> ...(wild1:as)...
76 Here, (wild1:as) is morally the same as (a:as) and hence equal to wild.
77 But that's not quite obvious. In general we want to keep it as (wild1:as),
78 but for CSE purpose that's a bad idea.
80 So we add the binding (wild1 -> a) to the extra var->var mapping.
81 Notice this is exactly backwards to what the simplifier does, which is
82 to try to replaces uses of a with uses of wild1
87 case (h x) of y -> ...(h x)...
89 We'd like to replace (h x) in the alternative, by y. But because of
90 the preceding "Another important wrinkle", we only want to add the mapping
91 scrutinee -> case binder
92 to the reverse CSE mapping if the scrutinee is a non-trivial expression.
93 (If the scrutinee is a simple variable we want to add the mapping
94 case binder -> scrutinee
98 %************************************************************************
100 \section{Common subexpression}
102 %************************************************************************
105 cseProgram :: [CoreBind] -> IO [CoreBind]
109 beginPass "Common sub-expression";
110 let { binds' = cseBinds emptyCSEnv binds };
111 endPass "Common sub-expression"
112 (opt_D_dump_cse || opt_D_verbose_core2core)
116 cseBinds :: CSEnv -> [CoreBind] -> [CoreBind]
118 cseBinds env (b:bs) = (b':bs')
120 (env1, b') = cseBind env b
121 bs' = cseBinds env1 bs
123 cseBind :: CSEnv -> CoreBind -> (CSEnv, CoreBind)
124 cseBind env (NonRec b e) = let (env', (_,e')) = do_one env (b, e)
125 in (env', NonRec b e')
126 cseBind env (Rec pairs) = let (env', pairs') = mapAccumL do_one env pairs
127 in (env', Rec pairs')
130 do_one env (id, rhs) = case lookupCSEnv env rhs' of
131 Just other_id -> (extendSubst env' id other_id, (id', Var other_id))
132 Nothing -> (addCSEnvItem env' id' rhs', (id', rhs'))
134 (env', id') = addBinder env id
135 rhs' = cseExpr env' rhs
137 tryForCSE :: CSEnv -> CoreExpr -> CoreExpr
138 tryForCSE env (Type t) = Type t
139 tryForCSE env expr = case lookupCSEnv env expr' of
143 expr' = cseExpr env expr
145 cseExpr :: CSEnv -> CoreExpr -> CoreExpr
146 cseExpr env (Type t) = Type t
147 cseExpr env (Lit lit) = Lit lit
148 cseExpr env (Var v) = Var (lookupSubst env v)
149 cseExpr env (App f a) = App (cseExpr env f) (tryForCSE env a)
150 cseExpr env (Note n e) = Note n (cseExpr env e)
151 cseExpr env (Lam b e) = let (env', b') = addBinder env b
152 in Lam b' (cseExpr env' e)
153 cseExpr env (Let bind e) = let (env', bind') = cseBind env bind
154 in Let bind' (cseExpr env' e)
155 cseExpr env (Case scrut bndr alts) = Case scrut' bndr' (cseAlts env' scrut' bndr bndr' alts)
157 scrut' = tryForCSE env scrut
158 (env', bndr') = addBinder env bndr
161 cseAlts env scrut' bndr bndr' alts
164 (con_target, alt_env)
166 Var v' -> (v', extendSubst env bndr v') -- See "another important wrinkle"
169 other -> (bndr', extendCSEnv env bndr' scrut') -- See "yet another wrinkle"
170 -- map: scrut' -> bndr'
172 arg_tys = case splitTyConApp_maybe (idType bndr) of
173 Just (_, arg_tys) -> arg_tys
174 other -> pprPanic "cseAlts" (ppr bndr)
176 cse_alt (DataAlt con, args, rhs)
177 | not (null args || isUnboxedTupleCon con)
178 -- Don't try CSE if there are no args; it just increases the number
179 -- of live vars. E.g.
180 -- case x of { True -> ....True.... }
181 -- Don't replace True by x!
182 -- Hence the 'null args', which also deal with literals and DEFAULT
183 -- And we can't CSE on unboxed tuples
184 = (DataAlt con, args', tryForCSE new_env rhs)
186 (env', args') = addBinders alt_env args
187 new_env = extendCSEnv env' con_target (mkAltExpr (DataAlt con) args' arg_tys)
189 cse_alt (con, args, rhs)
190 = (con, args', tryForCSE env' rhs)
192 (env', args') = addBinders alt_env args
196 %************************************************************************
198 \section{The CSE envt}
200 %************************************************************************
203 data CSEnv = CS CSEMap InScopeSet (IdEnv Id)
204 -- Simple substitution
206 type CSEMap = UniqFM [(Id, CoreExpr)] -- This is the reverse mapping
207 -- It maps the hash-code of an expression to list of (x,e) pairs
208 -- This means that it's good to replace e by x
209 -- INVARIANT: The expr in the range has already been CSE'd
211 emptyCSEnv = CS emptyUFM emptyInScopeSet emptyVarEnv
213 lookupCSEnv :: CSEnv -> CoreExpr -> Maybe Id
214 lookupCSEnv (CS cs _ _) expr
215 = case lookupUFM cs (hashExpr expr) of
217 Just pairs -> lookup_list pairs expr
219 lookup_list :: [(Id,CoreExpr)] -> CoreExpr -> Maybe Id
220 lookup_list [] expr = Nothing
221 lookup_list ((x,e):es) expr | cheapEqExpr e expr = Just x
222 | otherwise = lookup_list es expr
224 addCSEnvItem env id expr | exprIsBig expr = env
225 | otherwise = extendCSEnv env id expr
227 extendCSEnv (CS cs in_scope sub) id expr
228 = CS (addToUFM_C combine cs hash [(id, expr)]) in_scope sub
231 combine old new = WARN( length result > 4, text "extendCSEnv: long list:" <+> ppr result )
236 lookupSubst (CS _ _ sub) x = case lookupVarEnv sub x of
240 extendSubst (CS cs in_scope sub) x y = CS cs in_scope (extendVarEnv sub x y)
242 addBinder :: CSEnv -> Id -> (CSEnv, Id)
243 addBinder env@(CS cs in_scope sub) v
244 | not (v `elemInScopeSet` in_scope) = (CS cs (extendInScopeSet in_scope v) sub, v)
245 | isId v = (CS cs (extendInScopeSet in_scope v') (extendVarEnv sub v v'), v')
246 | not (isId v) = WARN( True, ppr v )
247 (CS emptyUFM in_scope sub, v)
248 -- This last case is the unusual situation where we have shadowing of
249 -- a type variable; we have to discard the CSE mapping
250 -- See "IMPORTANT NOTE" at the top
252 v' = uniqAway in_scope v
254 addBinders :: CSEnv -> [Id] -> (CSEnv, [Id])
255 addBinders env vs = mapAccumL addBinder env vs