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