[project @ 2000-11-10 15:12:50 by simonpj]
[ghc-hetmet.git] / ghc / compiler / cprAnalysis / CprAnalyse.lhs
1 \section[CprAnalyse]{Identify functions that always return a
2 constructed product result}
3
4 \begin{code}
5 module CprAnalyse ( cprAnalyse ) where
6
7 #include "HsVersions.h"
8
9 import CmdLineOpts      ( DynFlags, DynFlag(..), dopt )
10 import CoreLint         ( showPass, endPass )
11 import CoreSyn
12 import CoreUtils        ( exprIsValue )
13 import Id               ( Id, setIdCprInfo, idCprInfo, idArity,
14                           isBottomingId, idDemandInfo )
15 import IdInfo           ( CprInfo(..) )
16 import Demand           ( isStrict )
17 import VarEnv
18 import Util             ( nTimes, mapAccumL )
19 import Outputable
20
21 import Maybe
22 \end{code}
23
24 This module performs an analysis of a set of Core Bindings for the
25 Constructed Product Result (CPR) transformation.
26
27 It detects functions that always explicitly (manifestly?) construct a
28 result value with a product type.  A product type is a type which has
29 only one constructor. For example, tuples and boxed primitive values
30 have product type.
31
32 We must also ensure that the function's body starts with sufficient
33 manifest lambdas otherwise loss of sharing can occur.  See the comment
34 in @StrictAnal.lhs@.
35
36 The transformation of bindings to worker/wrapper pairs is done by the
37 worker-wrapper pass.  The worker-wrapper pass splits bindings on the
38 basis of both strictness and CPR info.  If an id has both then it can
39 combine the transformations so that only one pair is produced.
40
41 The analysis here detects nested CPR information.  For example, if a
42 function returns a constructed pair, the first element of which is a
43 constructed int, then the analysis will detect nested CPR information
44 for the int as well.  Unfortunately, the current transformations can't
45 take advantage of the nested CPR information.  They have (broken now,
46 I think) code which will flatten out nested CPR components and rebuild
47 them in the wrapper, but enabling this would lose laziness.  It is
48 possible to make use of the nested info: if we knew that a caller was
49 strict in that position then we could create a specialized version of
50 the function which flattened/reconstructed that position.
51
52 It is not known whether this optimisation would be worthwhile.
53
54 So we generate and carry round nested CPR information, but before
55 using this info to guide the creation of workers and wrappers we map
56 all components of a CPRInfo to NoCprInfo.
57
58
59 Data types
60 ~~~~~~~~~~
61
62 Within this module Id's CPR information is represented by
63 ``AbsVal''. When adding this information to the Id's pragma info field 
64 we convert the ``Absval'' to a ``CprInfo'' value.   
65
66 Abstract domains consist of a `no information' value (Top), a function
67 value (Fun) which when applied to an argument returns a new AbsVal
68 (note the argument is not used in any way), , for product types, a
69 corresponding length tuple (Tuple) of abstract values.  And finally,
70 Bot.  Bot is not a proper abstract value but a generic bottom is
71 useful for calculating fixpoints and representing divergent
72 computations.  Note that we equate Bot and Fun^n Bot (n > 0), and
73 likewise for Top.  This saves a lot of delving in types to keep
74 everything exactly correct.
75
76 Since functions abstract to constant functions we could just
77 represent them by the abstract value of their result.  However,  it
78 turns out (I know - I tried!) that this requires a lot of type
79 manipulation and the code is more straightforward if we represent
80 functions by an abstract constant function. 
81
82 \begin{code}
83 data AbsVal = Top                -- Not a constructed product
84
85             | Fun AbsVal         -- A function that takes an argument 
86                                  -- and gives AbsVal as result. 
87
88             | Tuple              -- A constructed product of values
89
90             | Bot                -- Bot'tom included for convenience
91                                  -- we could use appropriate Tuple Vals
92      deriving (Eq,Show)
93
94 isFun :: AbsVal -> Bool
95 isFun (Fun _) = True
96 isFun _       = False
97
98 -- For pretty debugging
99 instance Outputable AbsVal where
100   ppr Top       = ptext SLIT("Top")
101   ppr (Fun r)   = ptext SLIT("Fun->") <> (parens.ppr) r
102   ppr Tuple     = ptext SLIT("Tuple ")
103   ppr Bot       = ptext SLIT("Bot")
104
105
106 -- lub takes the lowest upper bound of two abstract values, standard.
107 lub :: AbsVal -> AbsVal -> AbsVal
108 lub Bot a = a
109 lub a Bot = a
110 lub Top a = Top
111 lub a Top = Top
112 lub Tuple Tuple         = Tuple
113 lub (Fun l) (Fun r)     = Fun (lub l r)
114 lub l r = panic "CPR Analysis tried to take the lub of a function and a tuple"
115
116
117 \end{code}
118
119 The environment maps Ids to their abstract CPR value.
120
121 \begin{code}
122
123 type CPREnv = VarEnv AbsVal
124
125 initCPREnv = emptyVarEnv
126
127 \end{code}
128
129 Programs
130 ~~~~~~~~
131
132 Take a list of core bindings and return a new list with CPR function
133 ids decorated with their CprInfo pragmas.
134
135 \begin{code}
136
137 cprAnalyse :: DynFlags -> [CoreBind] -> IO [CoreBind]
138 cprAnalyse dflags binds
139   = do {
140         showPass dflags "Constructed Product analysis" ;
141         let { binds_plus_cpr = do_prog binds } ;
142         endPass dflags "Constructed Product analysis" 
143                 (dopt Opt_D_dump_cpranal dflags || dopt Opt_D_verbose_core2core dflags)
144                 binds_plus_cpr
145     }
146   where
147     do_prog :: [CoreBind] -> [CoreBind]
148     do_prog binds = snd $ mapAccumL cprAnalBind initCPREnv binds
149 \end{code}
150
151 The cprAnal functions take binds/expressions and an environment which 
152 gives CPR info for visible ids and returns a new bind/expression
153 with ids decorated with their CPR info.
154  
155 \begin{code}
156 -- Return environment extended with info from this binding 
157 cprAnalBind :: CPREnv -> CoreBind -> (CPREnv, CoreBind)
158 cprAnalBind rho (NonRec b e) 
159   = (extendVarEnv rho b absval, NonRec b' e')
160   where
161     (e', absval) = cprAnalExpr rho e
162     b' = addIdCprInfo b e' absval
163
164 cprAnalBind rho (Rec prs)
165   = (final_rho, Rec (map do_pr prs))
166   where
167     do_pr (b,e) = (b', e') 
168                 where
169                   b'           = addIdCprInfo b e' absval
170                   (e', absval) = cprAnalExpr final_rho e
171
172         -- When analyzing mutually recursive bindings the iterations to find
173         -- a fixpoint is bounded by the number of bindings in the group.
174         -- for simplicity we just iterate that number of times.      
175     final_rho = nTimes (length prs) do_one_pass init_rho
176     init_rho  = rho `extendVarEnvList` [(b,Bot) | (b,e) <- prs]
177
178     do_one_pass :: CPREnv -> CPREnv
179     do_one_pass rho = foldl (\ rho (b,e) -> extendVarEnv rho b (snd (cprAnalExpr rho e)))
180                             rho prs
181
182
183 cprAnalExpr :: CPREnv -> CoreExpr -> (CoreExpr, AbsVal)
184
185 -- If Id will always diverge when given sufficient arguments then
186 -- we can just set its abs val to Bot.  Any other CPR info
187 -- from other paths will then dominate,  which is what we want.
188 -- Check in rho,  if not there it must be imported, so check 
189 -- the var's idinfo. 
190 cprAnalExpr rho e@(Var v) 
191     | isBottomingId v = (e, Bot)
192     | otherwise       = (e, case lookupVarEnv rho v of
193                              Just a_val -> a_val
194                              Nothing    -> getCprAbsVal v)
195
196 -- Literals are unboxed
197 cprAnalExpr rho (Lit l) = (Lit l, Top)
198
199 -- For apps we don't care about the argument's abs val.  This
200 -- app will return a constructed product if the function does. We strip
201 -- a Fun from the functions abs val, unless the argument is a type argument 
202 -- or it is already Top or Bot.
203 cprAnalExpr rho (App fun arg@(Type _))
204     = (App fun_cpr arg, fun_res)  
205     where 
206       (fun_cpr, fun_res)  = cprAnalExpr rho fun 
207
208 cprAnalExpr rho (App fun arg) 
209     = (App fun_cpr arg_cpr, res_res)
210     where 
211       (fun_cpr, fun_res)  = cprAnalExpr rho fun 
212       (arg_cpr, _)        = cprAnalExpr rho arg
213       res_res             = case fun_res of
214                                 Fun res_res -> res_res
215                                 Top         -> Top
216                                 Bot         -> Bot
217                                 Tuple       -> WARN( True, ppr (App fun arg) ) Top
218                                                 -- This really should not happen!
219
220
221 -- Map arguments to Top (we aren't constructing them)
222 -- Return the abstract value of the body, since functions 
223 -- are represented by the CPR value of their result, and 
224 -- add a Fun for this lambda..
225 cprAnalExpr rho (Lam b body) | isTyVar b = (Lam b body_cpr, body_aval)
226                              | otherwise = (Lam b body_cpr, Fun body_aval)
227       where 
228       (body_cpr, body_aval) = cprAnalExpr (extendVarEnv rho b Top) body
229
230 cprAnalExpr rho (Let bind body)
231     = (Let bind' body', body_aval)
232     where 
233       (rho', bind') = cprAnalBind rho bind
234       (body', body_aval) = cprAnalExpr rho' body
235
236 cprAnalExpr rho (Case scrut bndr alts)
237     = (Case scrut_cpr bndr alts_cpr, alts_aval)
238       where 
239       (scrut_cpr, scrut_aval) = cprAnalExpr rho scrut
240       (alts_cpr, alts_aval) = cprAnalCaseAlts (extendVarEnv rho bndr scrut_aval) alts
241
242 cprAnalExpr rho (Note n exp) 
243     = (Note n exp_cpr, expr_aval)
244       where
245       (exp_cpr, expr_aval) = cprAnalExpr rho exp
246
247 cprAnalExpr rho (Type t) 
248     = (Type t, Top)
249
250 cprAnalCaseAlts :: CPREnv -> [CoreAlt] -> ([CoreAlt], AbsVal)
251 cprAnalCaseAlts rho alts
252     = foldl anal_alt ([], Bot) alts
253       where 
254       anal_alt :: ([CoreAlt], AbsVal) -> CoreAlt -> ([CoreAlt], AbsVal)
255       anal_alt (done, aval) (con, binds, exp) 
256           = (done ++ [(con,binds,exp_cpr)], aval `lub` exp_aval)
257             where (exp_cpr, exp_aval) = cprAnalExpr rho' exp
258                   rho' = rho `extendVarEnvList` (zip binds (repeat Top))
259
260
261 addIdCprInfo :: Id -> CoreExpr -> AbsVal -> Id
262 addIdCprInfo bndr rhs absval
263   | useful_info && ok_to_add = setIdCprInfo bndr cpr_info
264   | otherwise                = bndr
265   where
266     cpr_info    = absToCprInfo absval
267     useful_info = case cpr_info of { ReturnsCPR -> True; NoCPRInfo -> False }
268                 
269     ok_to_add = case absval of
270                   Fun _ -> idArity bndr >= n_fun_tys absval
271                       -- Enough visible lambdas
272
273                   Tuple  -> exprIsValue rhs || isStrict (idDemandInfo bndr)
274                         -- If the rhs is a value, and returns a constructed product,
275                         -- it will be inlined at usage sites, so we give it a Tuple absval
276                         -- If it isn't a value, we won't inline it (code/work dup worries), so
277                         -- we discard its absval.
278                         -- 
279                         -- Also, if the strictness analyser has figured out that it's strict,
280                         -- the let-to-case transformation will happen, so again it's good.
281                         -- (CPR analysis runs before the simplifier has had a chance to do
282                         --  the let-to-case transform.)
283                         -- This made a big difference to PrelBase.modInt, which had something like
284                         --      modInt = \ x -> let r = ... -> I# v in
285                         --                      ...body strict in r...
286                         -- r's RHS isn't a value yet; but modInt returns r in various branches, so
287                         -- if r doesn't have the CPR property then neither does modInt
288
289                   _ -> False
290
291     n_fun_tys :: AbsVal -> Int
292     n_fun_tys (Fun av) = 1 + n_fun_tys av
293     n_fun_tys other    = 0
294
295
296 absToCprInfo :: AbsVal -> CprInfo
297 absToCprInfo Tuple   = ReturnsCPR
298 absToCprInfo (Fun r) = absToCprInfo r
299 absToCprInfo _       = NoCPRInfo
300
301
302 -- Cpr Info doesn't store the number of arguments a function has,  so the caller
303 -- must take care to add the appropriate number of Funs.
304 getCprAbsVal v = case idCprInfo v of
305                         NoCPRInfo -> Top
306                         ReturnsCPR -> nTimes arity Fun Tuple
307                where
308                  arity = idArity v
309         -- Imported (non-nullary) constructors will have the CPR property
310         -- in their IdInfo, so no need to look at their unfolding
311 \end{code}