2 % (c) The AQUA Project, Glasgow University, 1994-1998
\r
4 \section[CoreUnfold]{Core-syntax unfoldings}
\r
6 Unfoldings (which can travel across module boundaries) are in Core
\r
7 syntax (namely @CoreExpr@s).
\r
9 The type @Unfolding@ sits ``above'' simply-Core-expressions
\r
10 unfoldings, capturing ``higher-level'' things we know about a binding,
\r
11 usually things that the simplifier found out (e.g., ``it's a
\r
12 literal''). In the corner of a @CoreUnfolding@ unfolding, you will
\r
13 find, unsurprisingly, a Core expression.
\r
17 Unfolding(..), UnfoldingGuidance, -- types
\r
19 noUnfolding, mkUnfolding, getUnfoldingTemplate,
\r
20 isEvaldUnfolding, hasUnfolding,
\r
22 couldBeSmallEnoughToInline,
\r
23 certainlySmallEnoughToInline,
\r
26 calcUnfoldingGuidance,
\r
28 callSiteInline, blackListed
\r
31 #include "HsVersions.h"
\r
33 import CmdLineOpts ( opt_UF_CreationThreshold,
\r
34 opt_UF_UseThreshold,
\r
35 opt_UF_ScrutConDiscount,
\r
36 opt_UF_FunAppDiscount,
\r
37 opt_UF_PrimArgDiscount,
\r
38 opt_UF_KeenessFactor,
\r
39 opt_UF_CheapOp, opt_UF_DearOp, opt_UF_NoRepLit,
\r
40 opt_UnfoldCasms, opt_PprStyle_Debug,
\r
41 opt_D_dump_inlinings
\r
44 import PprCore ( pprCoreExpr )
\r
45 import OccurAnal ( occurAnalyseGlobalExpr )
\r
46 import BinderInfo ( )
\r
47 import CoreUtils ( coreExprType, exprIsTrivial, mkFormSummary, whnfOrBottom,
\r
49 import Id ( Id, idType, idUnique, isId,
\r
50 getIdSpecialisation, getInlinePragma, getIdUnfolding
\r
53 import Const ( Con(..), isLitLitLit, isWHNFCon )
\r
54 import PrimOp ( PrimOp(..), primOpIsDupable )
\r
55 import IdInfo ( ArityInfo(..), InlinePragInfo(..), OccInfo(..) )
\r
56 import TyCon ( tyConFamilySize )
\r
57 import Type ( splitAlgTyConApp_maybe, splitFunTy_maybe )
\r
58 import Const ( isNoRepLit )
\r
59 import Unique ( Unique, buildIdKey, augmentIdKey, runSTRepIdKey )
\r
60 import Maybes ( maybeToBool )
\r
62 import Util ( isIn, lengthExceeds )
\r
66 %************************************************************************
\r
68 \subsection{@Unfolding@ and @UnfoldingGuidance@ types}
\r
70 %************************************************************************
\r
76 | OtherCon [Con] -- It ain't one of these
\r
77 -- (OtherCon xs) also indicates that something has been evaluated
\r
78 -- and hence there's no point in re-evaluating it.
\r
79 -- OtherCon [] is used even for non-data-type values
\r
80 -- to indicated evaluated-ness. Notably:
\r
81 -- data C = C !(Int -> Int)
\r
82 -- case x of { C f -> ... }
\r
83 -- Here, f gets an OtherCon [] unfolding.
\r
85 | CoreUnfolding -- An unfolding with redundant cached information
\r
86 FormSummary -- Tells whether the template is a WHNF or bottom
\r
87 UnfoldingGuidance -- Tells about the *size* of the template.
\r
88 CoreExpr -- Template; binder-info is correct
\r
92 noUnfolding = NoUnfolding
\r
96 -- strictness mangling (depends on there being no CSE)
\r
97 ufg = calcUnfoldingGuidance opt_UF_CreationThreshold expr
\r
98 occ = occurAnalyseGlobalExpr expr
\r
100 CoreUnfolding (mkFormSummary expr) ufg occ
\r
102 getUnfoldingTemplate :: Unfolding -> CoreExpr
\r
103 getUnfoldingTemplate (CoreUnfolding _ _ expr) = expr
\r
104 getUnfoldingTemplate other = panic "getUnfoldingTemplate"
\r
106 isEvaldUnfolding :: Unfolding -> Bool
\r
107 isEvaldUnfolding (OtherCon _) = True
\r
108 isEvaldUnfolding (CoreUnfolding ValueForm _ expr) = True
\r
109 isEvaldUnfolding other = False
\r
111 hasUnfolding :: Unfolding -> Bool
\r
112 hasUnfolding NoUnfolding = False
\r
113 hasUnfolding other = True
\r
115 data UnfoldingGuidance
\r
117 | UnfoldAlways -- There is no "original" definition,
\r
118 -- so you'd better unfold. Or: something
\r
119 -- so cheap to unfold (e.g., 1#) that
\r
120 -- you should do it absolutely always.
\r
122 | UnfoldIfGoodArgs Int -- and "n" value args
\r
124 [Int] -- Discount if the argument is evaluated.
\r
125 -- (i.e., a simplification will definitely
\r
126 -- be possible). One elt of the list per *value* arg.
\r
128 Int -- The "size" of the unfolding; to be elaborated
\r
131 Int -- Scrutinee discount: the discount to substract if the thing is in
\r
132 -- a context (case (thing args) of ...),
\r
133 -- (where there are the right number of arguments.)
\r
137 instance Outputable UnfoldingGuidance where
\r
138 ppr UnfoldAlways = ptext SLIT("ALWAYS")
\r
139 ppr UnfoldNever = ptext SLIT("NEVER")
\r
140 ppr (UnfoldIfGoodArgs v cs size discount)
\r
141 = hsep [ptext SLIT("IF_ARGS"), int v,
\r
142 if null cs -- always print *something*
\r
144 else hcat (map (text . show) cs),
\r
150 %************************************************************************
\r
152 \subsection[calcUnfoldingGuidance]{Calculate ``unfolding guidance'' for an expression}
\r
154 %************************************************************************
\r
157 calcUnfoldingGuidance
\r
158 :: Int -- bomb out if size gets bigger than this
\r
159 -> CoreExpr -- expression to look at
\r
160 -> UnfoldingGuidance
\r
161 calcUnfoldingGuidance bOMB_OUT_SIZE expr
\r
162 | exprIsTrivial expr -- Often trivial expressions are never bound
\r
163 -- to an expression, but it can happen. For
\r
164 -- example, the Id for a nullary constructor has
\r
165 -- a trivial expression as its unfolding, and
\r
166 -- we want to make sure that we always unfold it.
\r
170 = case collectBinders expr of { (binders, body) ->
\r
172 val_binders = filter isId binders
\r
174 case (sizeExpr bOMB_OUT_SIZE val_binders body) of
\r
176 TooBig -> UnfoldNever
\r
178 SizeIs size cased_args scrut_discount
\r
179 -> UnfoldIfGoodArgs
\r
180 (length val_binders)
\r
181 (map discount_for val_binders)
\r
183 (I# scrut_discount)
\r
186 | num_cases == 0 = 0
\r
187 | is_fun_ty = num_cases * opt_UF_FunAppDiscount
\r
188 | is_data_ty = num_cases * tyConFamilySize tycon * opt_UF_ScrutConDiscount
\r
189 | otherwise = num_cases * opt_UF_PrimArgDiscount
\r
191 num_cases = foldlBag (\n b' -> if b==b' then n+1 else n) 0 cased_args
\r
192 -- Count occurrences of b in cased_args
\r
194 is_fun_ty = maybeToBool (splitFunTy_maybe arg_ty)
\r
195 (is_data_ty, tycon) = case (splitAlgTyConApp_maybe (idType b)) of
\r
196 Nothing -> (False, panic "discount")
\r
197 Just (tc,_,_) -> (True, tc)
\r
202 sizeExpr :: Int -- Bomb out if it gets bigger than this
\r
203 -> [Id] -- Arguments; we're interested in which of these
\r
208 sizeExpr (I# bOMB_OUT_SIZE) args expr
\r
211 size_up (Type t) = sizeZero -- Types cost nothing
\r
212 size_up (Var v) = sizeOne
\r
214 size_up (Note InlineMe _) = sizeTwo -- The idea is that this is one more
\r
215 -- than the size of the "call" (i.e. 1)
\r
216 -- We want to reply "no" to noSizeIncrease
\r
217 -- for a bare reference (i.e. applied to no args)
\r
218 -- to an INLINE thing
\r
220 size_up (Note _ body) = size_up body -- Notes cost nothing
\r
222 size_up (App fun (Type t)) = size_up fun
\r
223 size_up (App fun arg) = size_up_app fun `addSize` size_up arg
\r
225 size_up (Con con args) = foldr (addSize . size_up)
\r
226 (size_up_con con args)
\r
229 size_up (Lam b e) | isId b = size_up e `addSizeN` 1
\r
230 | otherwise = size_up e
\r
232 size_up (Let (NonRec binder rhs) body)
\r
233 = nukeScrutDiscount (size_up rhs) `addSize`
\r
234 size_up body `addSizeN`
\r
235 1 -- For the allocation
\r
237 size_up (Let (Rec pairs) body)
\r
238 = nukeScrutDiscount rhs_size `addSize`
\r
239 size_up body `addSizeN`
\r
240 length pairs -- For the allocation
\r
242 rhs_size = foldr (addSize . size_up . snd) sizeZero pairs
\r
244 size_up (Case scrut _ alts)
\r
245 = nukeScrutDiscount (size_up scrut) `addSize`
\r
246 arg_discount scrut `addSize`
\r
247 foldr (addSize . size_up_alt) sizeZero alts `addSizeN`
\r
248 case (splitAlgTyConApp_maybe (coreExprType scrut)) of
\r
250 Just (tc,_,_) -> tyConFamilySize tc
\r
253 -- A function application with at least one value argument
\r
254 -- so if the function is an argument give it an arg-discount
\r
255 size_up_app (App fun arg) = size_up_app fun `addSize` size_up arg
\r
256 size_up_app fun = arg_discount fun `addSize` size_up fun
\r
259 size_up_alt (con, bndrs, rhs) = size_up rhs
\r
260 -- Don't charge for args, so that wrappers look cheap
\r
263 size_up_con (Literal lit) args | isNoRepLit lit = sizeN opt_UF_NoRepLit
\r
264 | otherwise = sizeOne
\r
266 size_up_con (DataCon dc) args = conSizeN (valArgCount args)
\r
268 size_up_con (PrimOp op) args = foldr addSize (sizeN op_cost) (map arg_discount args)
\r
269 -- Give an arg-discount if a primop is applies to
\r
270 -- one of the function's arguments
\r
272 op_cost | primOpIsDupable op = opt_UF_CheapOp
\r
273 | otherwise = opt_UF_DearOp
\r
276 -- We want to record if we're case'ing, or applying, an argument
\r
277 arg_discount (Var v) | v `is_elem` args = scrutArg v
\r
278 arg_discount other = sizeZero
\r
280 is_elem :: Id -> [Id] -> Bool
\r
281 is_elem = isIn "size_up_scrut"
\r
284 -- These addSize things have to be here because
\r
285 -- I don't want to give them bOMB_OUT_SIZE as an argument
\r
287 addSizeN TooBig _ = TooBig
\r
288 addSizeN (SizeIs n xs d) (I# m)
\r
289 | n_tot -# d <# bOMB_OUT_SIZE = SizeIs n_tot xs d
\r
290 | otherwise = TooBig
\r
294 addSize TooBig _ = TooBig
\r
295 addSize _ TooBig = TooBig
\r
296 addSize (SizeIs n1 xs d1) (SizeIs n2 ys d2)
\r
297 | (n_tot -# d_tot) <# bOMB_OUT_SIZE = SizeIs n_tot xys d_tot
\r
298 | otherwise = TooBig
\r
302 xys = xs `unionBags` ys
\r
305 Code for manipulating sizes
\r
309 data ExprSize = TooBig
\r
310 | SizeIs Int# -- Size found
\r
311 (Bag Id) -- Arguments cased herein
\r
312 Int# -- Size to subtract if result is scrutinised
\r
313 -- by a case expression
\r
315 sizeZero = SizeIs 0# emptyBag 0#
\r
316 sizeOne = SizeIs 1# emptyBag 0#
\r
317 sizeTwo = SizeIs 2# emptyBag 0#
\r
318 sizeN (I# n) = SizeIs n emptyBag 0#
\r
319 conSizeN (I# n) = SizeIs 1# emptyBag (n +# 1#)
\r
320 -- Treat constructors as size 1, that unfoldAlways responsds 'False'
\r
321 -- when asked about 'x' when x is bound to (C 3#).
\r
322 -- This avoids gratuitous 'ticks' when x itself appears as an
\r
323 -- atomic constructor argument.
\r
325 scrutArg v = SizeIs 0# (unitBag v) 0#
\r
327 nukeScrutDiscount (SizeIs n vs d) = SizeIs n vs 0#
\r
328 nukeScrutDiscount TooBig = TooBig
\r
332 %************************************************************************
\r
334 \subsection[considerUnfolding]{Given all the info, do (not) do the unfolding}
\r
336 %************************************************************************
\r
338 We have very limited information about an unfolding expression: (1)~so
\r
339 many type arguments and so many value arguments expected---for our
\r
340 purposes here, we assume we've got those. (2)~A ``size'' or ``cost,''
\r
341 a single integer. (3)~An ``argument info'' vector. For this, what we
\r
342 have at the moment is a Boolean per argument position that says, ``I
\r
343 will look with great favour on an explicit constructor in this
\r
344 position.'' (4)~The ``discount'' to subtract if the expression
\r
345 is being scrutinised.
\r
347 Assuming we have enough type- and value arguments (if not, we give up
\r
348 immediately), then we see if the ``discounted size'' is below some
\r
349 (semi-arbitrary) threshold. It works like this: for every argument
\r
350 position where we're looking for a constructor AND WE HAVE ONE in our
\r
351 hands, we get a (again, semi-arbitrary) discount [proportion to the
\r
352 number of constructors in the type being scrutinized].
\r
354 If we're in the context of a scrutinee ( \tr{(case <expr > of A .. -> ...;.. )})
\r
355 and the expression in question will evaluate to a constructor, we use
\r
356 the computed discount size *for the result only* rather than
\r
357 computing the argument discounts. Since we know the result of
\r
358 the expression is going to be taken apart, discounting its size
\r
359 is more accurate (see @sizeExpr@ above for how this discount size
\r
362 We use this one to avoid exporting inlinings that we ``couldn't possibly
\r
363 use'' on the other side. Can be overridden w/ flaggery.
\r
364 Just the same as smallEnoughToInline, except that it has no actual arguments.
\r
367 couldBeSmallEnoughToInline :: UnfoldingGuidance -> Bool
\r
368 couldBeSmallEnoughToInline UnfoldNever = False
\r
369 couldBeSmallEnoughToInline other = True
\r
371 certainlySmallEnoughToInline :: UnfoldingGuidance -> Bool
\r
372 certainlySmallEnoughToInline UnfoldNever = False
\r
373 certainlySmallEnoughToInline UnfoldAlways = True
\r
374 certainlySmallEnoughToInline (UnfoldIfGoodArgs _ _ size _) = size <= opt_UF_UseThreshold
\r
377 @okToUnfoldInHifile@ is used when emitting unfolding info into an interface
\r
378 file to determine whether an unfolding candidate really should be unfolded.
\r
379 The predicate is needed to prevent @_casm_@s (+ lit-lits) from being emitted
\r
380 into interface files.
\r
382 The reason for inlining expressions containing _casm_s into interface files
\r
383 is that these fragments of C are likely to mention functions/#defines that
\r
384 will be out-of-scope when inlined into another module. This is not an
\r
385 unfixable problem for the user (just need to -#include the approp. header
\r
386 file), but turning it off seems to the simplest thing to do.
\r
389 okToUnfoldInHiFile :: CoreExpr -> Bool
\r
390 okToUnfoldInHiFile e = opt_UnfoldCasms || go e
\r
392 -- Race over an expression looking for CCalls..
\r
394 go (Con (Literal lit) _) = not (isLitLitLit lit)
\r
395 go (Con (PrimOp op) args) = okToUnfoldPrimOp op && all go args
\r
396 go (Con con args) = True -- con args are always atomic
\r
397 go (App fun arg) = go fun && go arg
\r
398 go (Lam _ body) = go body
\r
399 go (Let binds body) = and (map go (body :rhssOfBind binds))
\r
400 go (Case scrut bndr alts) = and (map go (scrut:rhssOfAlts alts))
\r
401 go (Note _ body) = go body
\r
404 -- ok to unfold a PrimOp as long as it's not a _casm_
\r
405 okToUnfoldPrimOp (CCallOp _ is_casm _ _) = not is_casm
\r
406 okToUnfoldPrimOp _ = True
\r
410 %************************************************************************
\r
412 \subsection{callSiteInline}
\r
414 %************************************************************************
\r
416 This is the key function. It decides whether to inline a variable at a call site
\r
418 callSiteInline is used at call sites, so it is a bit more generous.
\r
419 It's a very important function that embodies lots of heuristics.
\r
420 A non-WHNF can be inlined if it doesn't occur inside a lambda,
\r
421 and occurs exactly once or
\r
422 occurs once in each branch of a case and is small
\r
424 If the thing is in WHNF, there's no danger of duplicating work,
\r
425 so we can inline if it occurs once, or is small
\r
428 callSiteInline :: Bool -- True <=> the Id is black listed
\r
429 -> Bool -- 'inline' note at call site
\r
431 -> [CoreExpr] -- Arguments
\r
432 -> Bool -- True <=> continuation is interesting
\r
433 -> Maybe CoreExpr -- Unfolding, if any
\r
436 callSiteInline black_listed inline_call id args interesting_cont
\r
437 = case getIdUnfolding id of {
\r
438 NoUnfolding -> Nothing ;
\r
439 OtherCon _ -> Nothing ;
\r
440 CoreUnfolding form guidance unf_template ->
\r
443 result | yes_or_no = Just unf_template
\r
444 | otherwise = Nothing
\r
446 inline_prag = getInlinePragma id
\r
447 arg_infos = map interestingArg val_args
\r
448 val_args = filter isValArg args
\r
449 whnf = whnfOrBottom form
\r
452 case inline_prag of
\r
453 IAmDead -> pprTrace "callSiteInline: dead" (ppr id) False
\r
454 IMustNotBeINLINEd -> False
\r
455 IAmALoopBreaker -> False
\r
456 IMustBeINLINEd -> True -- Overrides absolutely everything, including the black list
\r
457 ICanSafelyBeINLINEd in_lam one_br -> consider in_lam one_br
\r
458 NoInlinePragInfo -> consider InsideLam False
\r
460 consider in_lam one_branch
\r
461 | black_listed = False
\r
462 | inline_call = True
\r
463 | one_branch -- Be very keen to inline something if this is its unique occurrence; that
\r
464 -- gives a good chance of eliminating the original binding for the thing.
\r
465 -- The only time we hold back is when substituting inside a lambda;
\r
466 -- then if the context is totally uninteresting (not applied, not scrutinised)
\r
467 -- there is no point in substituting because it might just increase allocation.
\r
469 NotInsideLam -> True
\r
470 InsideLam -> whnf && (not (null args) || interesting_cont)
\r
472 | otherwise -- Occurs (textually) more than once, so look at its size
\r
474 UnfoldAlways -> True
\r
475 UnfoldNever -> False
\r
476 UnfoldIfGoodArgs n_vals_wanted arg_discounts size res_discount
\r
477 | enough_args && size <= (n_vals_wanted + 1)
\r
478 -- No size increase
\r
479 -- Size of call is n_vals_wanted (+1 for the function)
\r
481 NotInsideLam -> True
\r
484 | not (or arg_infos || really_interesting_cont)
\r
485 -- If it occurs more than once, there must be something interesting
\r
486 -- about some argument, or the result, to make it worth inlining
\r
491 NotInsideLam -> small_enough
\r
492 InsideLam -> whnf && small_enough
\r
495 n_args = length arg_infos
\r
496 enough_args = n_args >= n_vals_wanted
\r
497 really_interesting_cont | n_args < n_vals_wanted = False -- Too few args
\r
498 | n_args == n_vals_wanted = interesting_cont
\r
499 | otherwise = True -- Extra args
\r
500 -- This rather elaborate defn for really_interesting_cont is important
\r
501 -- Consider an I# = INLINE (\x -> I# {x})
\r
502 -- The unfolding guidance deems it to have size 2, and no arguments.
\r
503 -- So in an application (I# y) we must take the extra arg 'y' as
\r
504 -- evidene of an interesting context!
\r
506 small_enough = (size - discount) <= opt_UF_UseThreshold
\r
507 discount = computeDiscount n_vals_wanted arg_discounts res_discount
\r
508 arg_infos really_interesting_cont
\r
513 if opt_D_dump_inlinings then
\r
514 pprTrace "Considering inlining"
\r
515 (ppr id <+> vcat [text "black listed" <+> ppr black_listed,
\r
516 text "inline prag:" <+> ppr inline_prag,
\r
517 text "arg infos" <+> ppr arg_infos,
\r
518 text "interesting continuation" <+> ppr interesting_cont,
\r
519 text "whnf" <+> ppr whnf,
\r
520 text "guidance" <+> ppr guidance,
\r
521 text "ANSWER =" <+> if yes_or_no then text "YES" else text "NO",
\r
523 text "Unfolding =" <+> pprCoreExpr unf_template
\r
531 -- An argument is interesting if it has *some* structure
\r
532 -- We are here trying to avoid unfolding a function that
\r
533 -- is applied only to variables that have no unfolding
\r
534 -- (i.e. they are probably lambda bound): f x y z
\r
535 -- There is little point in inlining f here.
\r
536 interestingArg (Type _) = False
\r
537 interestingArg (App fn (Type _)) = interestingArg fn
\r
538 interestingArg (Var v) = hasUnfolding (getIdUnfolding v)
\r
539 interestingArg other = True
\r
542 computeDiscount :: Int -> [Int] -> Int -> [Bool] -> Bool -> Int
\r
543 computeDiscount n_vals_wanted arg_discounts res_discount arg_infos result_used
\r
544 -- We multiple the raw discounts (args_discount and result_discount)
\r
545 -- ty opt_UnfoldingKeenessFactor because the former have to do with
\r
546 -- *size* whereas the discounts imply that there's some extra
\r
547 -- *efficiency* to be gained (e.g. beta reductions, case reductions)
\r
550 -- we also discount 1 for each argument passed, because these will
\r
551 -- reduce with the lambdas in the function (we count 1 for a lambda
\r
553 = length (take n_vals_wanted arg_infos) +
\r
554 -- Discount of 1 for each arg supplied, because the
\r
555 -- result replaces the call
\r
556 round (opt_UF_KeenessFactor *
\r
557 fromInt (arg_discount + result_discount))
\r
559 arg_discount = sum (zipWith mk_arg_discount arg_discounts arg_infos)
\r
561 mk_arg_discount discount is_evald | is_evald = discount
\r
564 -- Don't give a result discount unless there are enough args
\r
565 result_discount | result_used = res_discount -- Over-applied, or case scrut
\r
570 %************************************************************************
\r
572 \subsection{Black-listing}
\r
574 %************************************************************************
\r
576 Inlining is controlled by the "Inline phase" number, which is set
\r
577 by the per-simplification-pass '-finline-phase' flag.
\r
579 For optimisation we use phase 1,2 and nothing (i.e. no -finline-phase flag)
\r
580 in that order. The meanings of these are determined by the @blackListed@ function
\r
584 blackListed :: IdSet -- Used in transformation rules
\r
585 -> Maybe Int -- Inline phase
\r
586 -> Id -> Bool -- True <=> blacklisted
\r
588 -- The blackListed function sees whether a variable should *not* be
\r
589 -- inlined because of the inline phase we are in. This is the sole
\r
590 -- place that the inline phase number is looked at.
\r
592 -- Phase 0: used for 'no inlinings please'
\r
593 blackListed rule_vars (Just 0)
\r
596 -- Phase 1: don't inline any rule-y things or things with specialisations
\r
597 blackListed rule_vars (Just 1)
\r
598 = \v -> let v_uniq = idUnique v
\r
599 in v `elemVarSet` rule_vars
\r
600 || not (isEmptyCoreRules (getIdSpecialisation v))
\r
601 || v_uniq == runSTRepIdKey
\r
603 -- Phase 2: allow build/augment to inline, and specialisations
\r
604 blackListed rule_vars (Just 2)
\r
605 = \v -> let v_uniq = idUnique v
\r
606 in (v `elemVarSet` rule_vars && not (v_uniq == buildIdKey ||
\r
607 v_uniq == augmentIdKey))
\r
608 || v_uniq == runSTRepIdKey
\r
610 -- Otherwise just go for it
\r
611 blackListed rule_vars phase
\r
616 SLPJ 95/04: Why @runST@ must be inlined very late:
\r
620 (a, s') = newArray# 100 [] s
\r
621 (_, s'') = fill_in_array_or_something a x s'
\r
623 freezeArray# a s'' )
\r
625 If we inline @runST@, we'll get:
\r
628 (a, s') = newArray# 100 [] realWorld#{-NB-}
\r
629 (_, s'') = fill_in_array_or_something a x s'
\r
633 And now the @newArray#@ binding can be floated to become a CAF, which
\r
634 is totally and utterly wrong:
\r
637 (a, s') = newArray# 100 [] realWorld#{-NB-} -- YIKES!!!
\r
640 let (_, s'') = fill_in_array_or_something a x s' in
\r
643 All calls to @f@ will share a {\em single} array!
\r
645 Yet we do want to inline runST sometime, so we can avoid
\r
646 needless code. Solution: black list it until the last moment.
\r