2 % (c) The GRASP/AQUA Project, Glasgow University, 1993-1996
4 \section[StrictAnal]{``Simple'' Mycroft-style strictness analyser}
6 The original version(s) of all strictness-analyser code (except the
7 Semantique analyser) was written by Andy Gill.
10 module StrictAnal ( saWwTopBinds ) where
12 #include "HsVersions.h"
14 import CmdLineOpts ( opt_D_dump_stranal, opt_D_simplifier_stats
17 import Id ( idType, addIdStrictness,
18 getIdDemandInfo, addIdDemandInfo,
21 import IdInfo ( mkStrictnessInfo, mkBottomStrictnessInfo,
22 mkDemandInfo, willBeDemanded, DemandInfo
24 import PprCore ( pprCoreBinding )
27 import WorkWrap -- "back-end" of strictness analyser
28 import Unique ( Unique{-instance Eq -} )
29 import UniqSupply ( UniqSupply )
30 import Util ( zipWith4Equal )
34 %************************************************************************
36 \subsection[Thoughts]{Random thoughts}
38 %************************************************************************
40 A note about worker-wrappering. If we have
43 f = let v = <expensive>
46 and we deduce that f is strict, it is nevertheless NOT safe to worker-wapper to
48 f = \x -> case x of Int x# -> fw x#
49 fw = \x# -> let x = Int x#
54 because this obviously loses laziness, since now <expensive>
55 is done each time. Alas.
57 WATCH OUT! This can mean that something is unboxed only to be
58 boxed again. For example
62 Here g is strict, and *will* split into worker-wrapper. A call to
63 g, with the wrapper inlined will then be
65 case arg of Int a# -> gw a#
67 Now g calls f, which has no wrapper, so it has to box it.
69 gw = \a# -> f (Int a#)
74 %************************************************************************
76 \subsection[iface-StrictAnal]{Interface to the outside world}
78 %************************************************************************
81 saWwTopBinds :: UniqSupply
88 -- mark each binder with its strictness
89 #ifndef OMIT_STRANAL_STATS
90 (binds_w_strictness, sa_stats)
91 = saTopBinds binds nullSaStats
94 = saTopBindsBinds binds
97 -- possibly show what we decided about strictness...
98 (if opt_D_dump_stranal
99 then pprTrace "Strictness:\n" (vcat (
100 map (pprCoreBinding) binds_w_strictness))
103 -- possibly show how many things we marked as demanded...
104 ((if opt_D_simplifier_stats
105 #ifndef OMIT_STRANAL_STATS
106 then pp_stats sa_stats
112 -- create worker/wrappers, and mark binders with their
113 -- "strictness info" [which encodes their
114 -- worker/wrapper-ness]
115 (workersAndWrappers binds_w_strictness us))
116 #ifndef OMIT_STRANAL_STATS
118 pp_stats (SaStats tlam dlam tc dc tlet dlet)
119 = pprTrace "Binders marked demanded: "
120 (hcat [ptext SLIT("Lambda vars: "), int IBOX(dlam), char '/', int IBOX(tlam),
121 ptext SLIT("; Case vars: "), int IBOX(dc), char '/', int IBOX(tc),
122 ptext SLIT("; Let vars: "), int IBOX(dlet), char '/', int IBOX(tlet)
127 %************************************************************************
129 \subsection[saBinds]{Strictness analysis of bindings}
131 %************************************************************************
133 [Some of the documentation about types, etc., in \tr{SaLib} may be
134 helpful for understanding this module.]
136 @saTopBinds@ tags each binder in the program with its @Demand@.
137 That tells how each binder is {\em used}; if @Strict@, then the binder
138 is sure to be evaluated to HNF; if @NonStrict@ it may or may not be;
139 if @Absent@, then it certainly is not used. [DATED; ToDo: update]
141 (The above info is actually recorded for posterity in each binder's
142 IdInfo, notably its @DemandInfo@.)
144 We proceed by analysing the bindings top-to-bottom, building up an
145 environment which maps @Id@s to their abstract values (i.e., an
146 @AbsValEnv@ maps an @Id@ to its @AbsVal@).
149 saTopBinds :: [CoreBinding] -> SaM [CoreBinding] -- not exported
153 starting_abs_env = nullAbsValEnv
155 do_it starting_abs_env starting_abs_env binds
157 do_it _ _ [] = returnSa []
158 do_it senv aenv (b:bs)
159 = saTopBind senv aenv b `thenSa` \ (senv2, aenv2, new_b) ->
160 do_it senv2 aenv2 bs `thenSa` \ new_bs ->
161 returnSa (new_b : new_bs)
164 @saTopBind@ is only used for the top level. We don't add any demand
165 info to these ids because we can't work it out. In any case, it
166 doesn't do us any good to know whether top-level binders are sure to
167 be used; we can't turn top-level @let@s into @case@s.
170 saTopBind :: StrictEnv -> AbsenceEnv
172 -> SaM (StrictEnv, AbsenceEnv, CoreBinding)
174 saTopBind str_env abs_env (NonRec binder rhs)
175 = saExpr str_env abs_env rhs `thenSa` \ new_rhs ->
177 str_rhs = absEval StrAnal rhs str_env
178 abs_rhs = absEval AbsAnal rhs abs_env
180 widened_str_rhs = widen StrAnal str_rhs
181 widened_abs_rhs = widen AbsAnal abs_rhs
182 -- The widening above is done for efficiency reasons.
183 -- See notes on Let case in SaAbsInt.lhs
186 = addStrictnessInfoToId
187 widened_str_rhs widened_abs_rhs
191 -- Augment environments with a mapping of the
192 -- binder to its abstract values, computed by absEval
193 new_str_env = addOneToAbsValEnv str_env binder widened_str_rhs
194 new_abs_env = addOneToAbsValEnv abs_env binder widened_abs_rhs
196 returnSa (new_str_env, new_abs_env, NonRec new_binder new_rhs)
198 saTopBind str_env abs_env (Rec pairs)
200 (binders,rhss) = unzip pairs
201 str_rhss = fixpoint StrAnal binders rhss str_env
202 abs_rhss = fixpoint AbsAnal binders rhss abs_env
203 -- fixpoint returns widened values
204 new_str_env = growAbsValEnvList str_env (binders `zip` str_rhss)
205 new_abs_env = growAbsValEnvList abs_env (binders `zip` abs_rhss)
206 new_binders = zipWith4Equal "saTopBind" addStrictnessInfoToId
207 str_rhss abs_rhss binders rhss
209 mapSa (saExpr new_str_env new_abs_env) rhss `thenSa` \ new_rhss ->
211 new_pairs = new_binders `zip` new_rhss
213 returnSa (new_str_env, new_abs_env, Rec new_pairs)
216 %************************************************************************
218 \subsection[saExpr]{Strictness analysis of an expression}
220 %************************************************************************
222 @saExpr@ computes the strictness of an expression within a given
226 saExpr :: StrictEnv -> AbsenceEnv -> CoreExpr -> SaM CoreExpr
228 saExpr _ _ e@(Var _) = returnSa e
229 saExpr _ _ e@(Lit _) = returnSa e
230 saExpr _ _ e@(Con _ _) = returnSa e
231 saExpr _ _ e@(Prim _ _) = returnSa e
233 saExpr str_env abs_env (Lam (ValBinder arg) body)
234 = saExpr str_env abs_env body `thenSa` \ new_body ->
236 new_arg = addDemandInfoToId str_env abs_env body arg
238 tickLambda new_arg `thenSa_` -- stats
239 returnSa (Lam (ValBinder new_arg) new_body)
241 saExpr str_env abs_env (Lam other_binder expr)
242 = saExpr str_env abs_env expr `thenSa` \ new_expr ->
243 returnSa (Lam other_binder new_expr)
245 saExpr str_env abs_env (App fun arg)
246 = saExpr str_env abs_env fun `thenSa` \ new_fun ->
247 returnSa (App new_fun arg)
249 saExpr str_env abs_env (Note note expr)
250 = saExpr str_env abs_env expr `thenSa` \ new_expr ->
251 returnSa (Note note new_expr)
253 saExpr str_env abs_env (Case expr (AlgAlts alts deflt))
254 = saExpr str_env abs_env expr `thenSa` \ new_expr ->
255 saDefault str_env abs_env deflt `thenSa` \ new_deflt ->
256 mapSa sa_alt alts `thenSa` \ new_alts ->
257 returnSa (Case new_expr (AlgAlts new_alts new_deflt))
259 sa_alt (con, binders, rhs)
260 = saExpr str_env abs_env rhs `thenSa` \ new_rhs ->
262 new_binders = addDemandInfoToIds str_env abs_env rhs binders
264 tickCases new_binders `thenSa_` -- stats
265 returnSa (con, new_binders, new_rhs)
267 saExpr str_env abs_env (Case expr (PrimAlts alts deflt))
268 = saExpr str_env abs_env expr `thenSa` \ new_expr ->
269 saDefault str_env abs_env deflt `thenSa` \ new_deflt ->
270 mapSa sa_alt alts `thenSa` \ new_alts ->
271 returnSa (Case new_expr (PrimAlts new_alts new_deflt))
274 = saExpr str_env abs_env rhs `thenSa` \ new_rhs ->
275 returnSa (lit, new_rhs)
277 saExpr str_env abs_env (Let (NonRec binder rhs) body)
278 = -- Analyse the RHS in the environment at hand
279 saExpr str_env abs_env rhs `thenSa` \ new_rhs ->
281 -- Bind this binder to the abstract value of the RHS; analyse
282 -- the body of the `let' in the extended environment.
283 str_rhs_val = absEval StrAnal rhs str_env
284 abs_rhs_val = absEval AbsAnal rhs abs_env
286 widened_str_rhs = widen StrAnal str_rhs_val
287 widened_abs_rhs = widen AbsAnal abs_rhs_val
288 -- The widening above is done for efficiency reasons.
289 -- See notes on Let case in SaAbsInt.lhs
291 new_str_env = addOneToAbsValEnv str_env binder widened_str_rhs
292 new_abs_env = addOneToAbsValEnv abs_env binder widened_abs_rhs
294 -- Now determine the strictness of this binder; use that info
295 -- to record DemandInfo/StrictnessInfo in the binder.
296 new_binder = addStrictnessInfoToId
297 widened_str_rhs widened_abs_rhs
298 (addDemandInfoToId str_env abs_env body binder)
301 tickLet new_binder `thenSa_` -- stats
302 saExpr new_str_env new_abs_env body `thenSa` \ new_body ->
303 returnSa (Let (NonRec new_binder new_rhs) new_body)
305 saExpr str_env abs_env (Let (Rec pairs) body)
307 (binders,rhss) = unzip pairs
308 str_vals = fixpoint StrAnal binders rhss str_env
309 abs_vals = fixpoint AbsAnal binders rhss abs_env
310 -- fixpoint returns widened values
311 new_str_env = growAbsValEnvList str_env (binders `zip` str_vals)
312 new_abs_env = growAbsValEnvList abs_env (binders `zip` abs_vals)
314 saExpr new_str_env new_abs_env body `thenSa` \ new_body ->
315 mapSa (saExpr new_str_env new_abs_env) rhss `thenSa` \ new_rhss ->
317 -- new_binders = addDemandInfoToIds new_str_env new_abs_env body binders
318 -- DON'T add demand info in a Rec!
319 -- a) it's useless: we can't do let-to-case
320 -- b) it's incorrect. Consider
321 -- letrec x = ...y...
324 -- When we ask whether y is demanded we'll bind y to bottom and
325 -- evaluate the body of the letrec. But that will result in our
326 -- deciding that y is absent, which is plain wrong!
327 -- It's much easier simply not to do this.
329 improved_binders = zipWith4Equal "saExpr" addStrictnessInfoToId
330 str_vals abs_vals binders rhss
332 whiter_than_white_binders = launder improved_binders
334 new_pairs = whiter_than_white_binders `zip` new_rhss
336 returnSa (Let (Rec new_pairs) new_body)
338 launder me = {-still-} me
342 saDefault str_env abs_env NoDefault = returnSa NoDefault
344 saDefault str_env abs_env (BindDefault bdr rhs)
345 = saExpr str_env abs_env rhs `thenSa` \ new_rhs ->
347 new_bdr = addDemandInfoToId str_env abs_env rhs bdr
349 tickCases [new_bdr] `thenSa_` -- stats
350 returnSa (BindDefault new_bdr new_rhs)
354 %************************************************************************
356 \subsection[computeInfos]{Add computed info to binders}
358 %************************************************************************
360 Important note (Sept 93). @addStrictnessInfoToId@ is used only for
361 let(rec) bound variables, and is use to attach the strictness (not
362 demand) info to the binder. We are careful to restrict this
363 strictness info to the lambda-bound arguments which are actually
364 visible, at the top level, lest we accidentally lose laziness by
365 eagerly looking for an "extra" argument. So we "dig for lambdas" in a
366 rather syntactic way.
368 A better idea might be to have some kind of arity analysis to
369 tell how many args could safely be grabbed.
372 addStrictnessInfoToId
373 :: AbsVal -- Abstract strictness value
374 -> AbsVal -- Ditto absence
376 -> CoreExpr -- Its RHS
377 -> Id -- Augmented with strictness
379 addStrictnessInfoToId str_val abs_val binder body
382 = binder `addIdStrictness` mkBottomStrictnessInfo
385 = case (collectBinders body) of
386 (_, [], rhs) -> binder
387 (_, lambda_bounds, rhs) -> binder `addIdStrictness`
388 mkStrictnessInfo strictness False
390 tys = map idType lambda_bounds
391 strictness = findStrictness tys str_val abs_val
395 addDemandInfoToId :: StrictEnv -> AbsenceEnv
396 -> CoreExpr -- The scope of the id
398 -> Id -- Id augmented with Demand info
400 addDemandInfoToId str_env abs_env expr binder
401 = binder `addIdDemandInfo` (mkDemandInfo (findDemand str_env abs_env expr binder))
403 addDemandInfoToIds :: StrictEnv -> AbsenceEnv -> CoreExpr -> [Id] -> [Id]
405 addDemandInfoToIds str_env abs_env expr binders
406 = map (addDemandInfoToId str_env abs_env expr) binders
409 %************************************************************************
411 \subsection{Monad used herein for stats}
413 %************************************************************************
417 = SaStats FAST_INT FAST_INT -- total/marked-demanded lambda-bound
418 FAST_INT FAST_INT -- total/marked-demanded case-bound
419 FAST_INT FAST_INT -- total/marked-demanded let-bound
420 -- (excl. top-level; excl. letrecs)
422 nullSaStats = SaStats ILIT(0) ILIT(0) ILIT(0) ILIT(0) ILIT(0) ILIT(0)
424 thenSa :: SaM a -> (a -> SaM b) -> SaM b
425 thenSa_ :: SaM a -> SaM b -> SaM b
426 returnSa :: a -> SaM a
428 {-# INLINE thenSa #-}
429 {-# INLINE thenSa_ #-}
430 {-# INLINE returnSa #-}
432 tickLambda :: Id -> SaM ()
433 tickCases :: [Id] -> SaM ()
434 tickLet :: Id -> SaM ()
436 #ifndef OMIT_STRANAL_STATS
437 type SaM a = SaStats -> (a, SaStats)
439 thenSa expr cont stats
440 = case (expr stats) of { (result, stats1) ->
443 thenSa_ expr cont stats
444 = case (expr stats) of { (_, stats1) ->
447 returnSa x stats = (x, stats)
449 tickLambda var (SaStats tlam dlam tc dc tlet dlet)
450 = case (tick_demanded var (0,0)) of { (IBOX(tot), IBOX(demanded)) ->
451 ((), SaStats (tlam _ADD_ tot) (dlam _ADD_ demanded) tc dc tlet dlet) }
453 tickCases vars (SaStats tlam dlam tc dc tlet dlet)
454 = case (foldr tick_demanded (0,0) vars) of { (IBOX(tot), IBOX(demanded)) ->
455 ((), SaStats tlam dlam (tc _ADD_ tot) (dc _ADD_ demanded) tlet dlet) }
457 tickLet var (SaStats tlam dlam tc dc tlet dlet)
458 = case (tick_demanded var (0,0)) of { (IBOX(tot),IBOX(demanded)) ->
459 ((), SaStats tlam dlam tc dc (tlet _ADD_ tot) (dlet _ADD_ demanded)) }
461 tick_demanded var (tot, demanded)
463 if (willBeDemanded (getIdDemandInfo var))
467 #else {-OMIT_STRANAL_STATS-}
471 thenSa expr cont = cont expr
473 thenSa_ expr cont = cont
477 tickLambda var = panic "OMIT_STRANAL_STATS: tickLambda"
478 tickCases vars = panic "OMIT_STRANAL_STATS: tickCases"
479 tickLet var = panic "OMIT_STRANAL_STATS: tickLet"
481 #endif {-OMIT_STRANAL_STATS-}
483 mapSa :: (a -> SaM b) -> [a] -> SaM [b]
485 mapSa f [] = returnSa []
487 = f x `thenSa` \ r ->
488 mapSa f xs `thenSa` \ rs ->