PageRenderTime 112ms CodeModel.GetById 8ms RepoModel.GetById 0ms app.codeStats 0ms

/compiler/simplCore/FloatIn.lhs

https://bitbucket.org/carter/ghc
Haskell | 535 lines | 381 code | 96 blank | 58 comment | 22 complexity | 0299d6bfd77a8caed15f532eb35c7f83 MD5 | raw file
  1. %
  2. % (c) The GRASP/AQUA Project, Glasgow University, 1992-1998
  3. %
  4. %************************************************************************
  5. %* *
  6. \section[FloatIn]{Floating Inwards pass}
  7. %* *
  8. %************************************************************************
  9. The main purpose of @floatInwards@ is floating into branches of a
  10. case, so that we don't allocate things, save them on the stack, and
  11. then discover that they aren't needed in the chosen branch.
  12. \begin{code}
  13. {-# OPTIONS -fno-warn-tabs #-}
  14. -- The above warning supression flag is a temporary kludge.
  15. -- While working on this module you are encouraged to remove it and
  16. -- detab the module (please do the detabbing in a separate patch). See
  17. -- http://hackage.haskell.org/trac/ghc/wiki/Commentary/CodingStyle#TabsvsSpaces
  18. -- for details
  19. module FloatIn ( floatInwards ) where
  20. #include "HsVersions.h"
  21. import CoreSyn
  22. import MkCore
  23. import CoreUtils ( exprIsDupable, exprIsExpandable, exprOkForSideEffects )
  24. import CoreFVs ( CoreExprWithFVs, freeVars, freeVarsOf, idRuleAndUnfoldingVars )
  25. import Id ( isOneShotBndr, idType )
  26. import Var
  27. import Type ( isUnLiftedType )
  28. import VarSet
  29. import Util
  30. import UniqFM
  31. import DynFlags
  32. import Outputable
  33. \end{code}
  34. Top-level interface function, @floatInwards@. Note that we do not
  35. actually float any bindings downwards from the top-level.
  36. \begin{code}
  37. floatInwards :: DynFlags -> CoreProgram -> CoreProgram
  38. floatInwards dflags = map fi_top_bind
  39. where
  40. fi_top_bind (NonRec binder rhs)
  41. = NonRec binder (fiExpr dflags [] (freeVars rhs))
  42. fi_top_bind (Rec pairs)
  43. = Rec [ (b, fiExpr dflags [] (freeVars rhs)) | (b, rhs) <- pairs ]
  44. \end{code}
  45. %************************************************************************
  46. %* *
  47. \subsection{Mail from Andr\'e [edited]}
  48. %* *
  49. %************************************************************************
  50. {\em Will wrote: What??? I thought the idea was to float as far
  51. inwards as possible, no matter what. This is dropping all bindings
  52. every time it sees a lambda of any kind. Help! }
  53. You are assuming we DO DO full laziness AFTER floating inwards! We
  54. have to [not float inside lambdas] if we don't.
  55. If we indeed do full laziness after the floating inwards (we could
  56. check the compilation flags for that) then I agree we could be more
  57. aggressive and do float inwards past lambdas.
  58. Actually we are not doing a proper full laziness (see below), which
  59. was another reason for not floating inwards past a lambda.
  60. This can easily be fixed. The problem is that we float lets outwards,
  61. but there are a few expressions which are not let bound, like case
  62. scrutinees and case alternatives. After floating inwards the
  63. simplifier could decide to inline the let and the laziness would be
  64. lost, e.g.
  65. \begin{verbatim}
  66. let a = expensive ==> \b -> case expensive of ...
  67. in \ b -> case a of ...
  68. \end{verbatim}
  69. The fix is
  70. \begin{enumerate}
  71. \item
  72. to let bind the algebraic case scrutinees (done, I think) and
  73. the case alternatives (except the ones with an
  74. unboxed type)(not done, I think). This is best done in the
  75. SetLevels.lhs module, which tags things with their level numbers.
  76. \item
  77. do the full laziness pass (floating lets outwards).
  78. \item
  79. simplify. The simplifier inlines the (trivial) lets that were
  80. created but were not floated outwards.
  81. \end{enumerate}
  82. With the fix I think Will's suggestion that we can gain even more from
  83. strictness by floating inwards past lambdas makes sense.
  84. We still gain even without going past lambdas, as things may be
  85. strict in the (new) context of a branch (where it was floated to) or
  86. of a let rhs, e.g.
  87. \begin{verbatim}
  88. let a = something case x of
  89. in case x of alt1 -> case something of a -> a + a
  90. alt1 -> a + a ==> alt2 -> b
  91. alt2 -> b
  92. let a = something let b = case something of a -> a + a
  93. in let b = a + a ==> in (b,b)
  94. in (b,b)
  95. \end{verbatim}
  96. Also, even if a is not found to be strict in the new context and is
  97. still left as a let, if the branch is not taken (or b is not entered)
  98. the closure for a is not built.
  99. %************************************************************************
  100. %* *
  101. \subsection{Main floating-inwards code}
  102. %* *
  103. %************************************************************************
  104. \begin{code}
  105. type FreeVarSet = IdSet
  106. type BoundVarSet = IdSet
  107. data FloatInBind = FB BoundVarSet FreeVarSet FloatBind
  108. -- The FreeVarSet is the free variables of the binding. In the case
  109. -- of recursive bindings, the set doesn't include the bound
  110. -- variables.
  111. type FloatInBinds = [FloatInBind]
  112. -- In reverse dependency order (innermost binder first)
  113. fiExpr :: DynFlags
  114. -> FloatInBinds -- Binds we're trying to drop
  115. -- as far "inwards" as possible
  116. -> CoreExprWithFVs -- Input expr
  117. -> CoreExpr -- Result
  118. fiExpr _ to_drop (_, AnnLit lit) = ASSERT( null to_drop ) Lit lit
  119. fiExpr _ to_drop (_, AnnType ty) = ASSERT( null to_drop ) Type ty
  120. fiExpr _ to_drop (_, AnnVar v) = wrapFloats to_drop (Var v)
  121. fiExpr _ to_drop (_, AnnCoercion co) = wrapFloats to_drop (Coercion co)
  122. fiExpr dflags to_drop (_, AnnCast expr (fvs_co, co))
  123. = wrapFloats (drop_here ++ co_drop) $
  124. Cast (fiExpr dflags e_drop expr) co
  125. where
  126. [drop_here, e_drop, co_drop] = sepBindsByDropPoint dflags False [freeVarsOf expr, fvs_co] to_drop
  127. \end{code}
  128. Applications: we do float inside applications, mainly because we
  129. need to get at all the arguments. The next simplifier run will
  130. pull out any silly ones.
  131. \begin{code}
  132. fiExpr dflags to_drop (_,AnnApp fun arg@(arg_fvs, ann_arg))
  133. | noFloatIntoRhs ann_arg = wrapFloats drop_here $ wrapFloats arg_drop $
  134. App (fiExpr dflags fun_drop fun) (fiExpr dflags [] arg)
  135. -- It's inconvenient to test for an unlifted arg here,
  136. -- and it really doesn't matter if we float into one
  137. | otherwise = wrapFloats drop_here $
  138. App (fiExpr dflags fun_drop fun) (fiExpr dflags arg_drop arg)
  139. where
  140. [drop_here, fun_drop, arg_drop]
  141. = sepBindsByDropPoint dflags False [freeVarsOf fun, arg_fvs] to_drop
  142. \end{code}
  143. Note [Floating in past a lambda group]
  144. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  145. * We must be careful about floating inside inside a value lambda.
  146. That risks losing laziness.
  147. The float-out pass might rescue us, but then again it might not.
  148. * We must be careful about type lambdas too. At one time we did, and
  149. there is no risk of duplicating work thereby, but we do need to be
  150. careful. In particular, here is a bad case (it happened in the
  151. cichelli benchmark:
  152. let v = ...
  153. in let f = /\t -> \a -> ...
  154. ==>
  155. let f = /\t -> let v = ... in \a -> ...
  156. This is bad as now f is an updatable closure (update PAP)
  157. and has arity 0.
  158. * Hack alert! We only float in through one-shot lambdas,
  159. not (as you might guess) through lone big lambdas.
  160. Reason: we float *out* past big lambdas (see the test in the Lam
  161. case of FloatOut.floatExpr) and we don't want to float straight
  162. back in again.
  163. It *is* important to float into one-shot lambdas, however;
  164. see the remarks with noFloatIntoRhs.
  165. So we treat lambda in groups, using the following rule:
  166. Float in if (a) there is at least one Id,
  167. and (b) there are no non-one-shot Ids
  168. Otherwise drop all the bindings outside the group.
  169. This is what the 'go' function in the AnnLam case is doing.
  170. Urk! if all are tyvars, and we don't float in, we may miss an
  171. opportunity to float inside a nested case branch
  172. \begin{code}
  173. fiExpr dflags to_drop lam@(_, AnnLam _ _)
  174. | okToFloatInside bndrs -- Float in
  175. -- NB: Must line up with noFloatIntoRhs (AnnLam...); see Trac #7088
  176. = mkLams bndrs (fiExpr dflags to_drop body)
  177. | otherwise -- Dump it all here
  178. = wrapFloats to_drop (mkLams bndrs (fiExpr dflags [] body))
  179. where
  180. (bndrs, body) = collectAnnBndrs lam
  181. \end{code}
  182. We don't float lets inwards past an SCC.
  183. ToDo: keep info on current cc, and when passing
  184. one, if it is not the same, annotate all lets in binds with current
  185. cc, change current cc to the new one and float binds into expr.
  186. \begin{code}
  187. fiExpr dflags to_drop (_, AnnTick tickish expr)
  188. | tickishScoped tickish
  189. = -- Wimp out for now - we could push values in
  190. wrapFloats to_drop (Tick tickish (fiExpr dflags [] expr))
  191. | otherwise
  192. = Tick tickish (fiExpr dflags to_drop expr)
  193. \end{code}
  194. For @Lets@, the possible ``drop points'' for the \tr{to_drop}
  195. bindings are: (a)~in the body, (b1)~in the RHS of a NonRec binding,
  196. or~(b2), in each of the RHSs of the pairs of a @Rec@.
  197. Note that we do {\em weird things} with this let's binding. Consider:
  198. \begin{verbatim}
  199. let
  200. w = ...
  201. in {
  202. let v = ... w ...
  203. in ... v .. w ...
  204. }
  205. \end{verbatim}
  206. Look at the inner \tr{let}. As \tr{w} is used in both the bind and
  207. body of the inner let, we could panic and leave \tr{w}'s binding where
  208. it is. But \tr{v} is floatable further into the body of the inner let, and
  209. {\em then} \tr{w} will also be only in the body of that inner let.
  210. So: rather than drop \tr{w}'s binding here, we add it onto the list of
  211. things to drop in the outer let's body, and let nature take its
  212. course.
  213. Note [extra_fvs (1): avoid floating into RHS]
  214. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  215. Consdider let x=\y....t... in body. We do not necessarily want to float
  216. a binding for t into the RHS, because it'll immediately be floated out
  217. again. (It won't go inside the lambda else we risk losing work.)
  218. In letrec, we need to be more careful still. We don't want to transform
  219. let x# = y# +# 1#
  220. in
  221. letrec f = \z. ...x#...f...
  222. in ...
  223. into
  224. letrec f = let x# = y# +# 1# in \z. ...x#...f... in ...
  225. because now we can't float the let out again, because a letrec
  226. can't have unboxed bindings.
  227. So we make "extra_fvs" which is the rhs_fvs of such bindings, and
  228. arrange to dump bindings that bind extra_fvs before the entire let.
  229. Note [extra_fvs (2): free variables of rules]
  230. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  231. Consider
  232. let x{rule mentioning y} = rhs in body
  233. Here y is not free in rhs or body; but we still want to dump bindings
  234. that bind y outside the let. So we augment extra_fvs with the
  235. idRuleAndUnfoldingVars of x. No need for type variables, hence not using
  236. idFreeVars.
  237. \begin{code}
  238. fiExpr dflags to_drop (_,AnnLet (AnnNonRec id rhs@(rhs_fvs, ann_rhs)) body)
  239. = fiExpr dflags new_to_drop body
  240. where
  241. body_fvs = freeVarsOf body `delVarSet` id
  242. rule_fvs = idRuleAndUnfoldingVars id -- See Note [extra_fvs (2): free variables of rules]
  243. extra_fvs | noFloatIntoRhs ann_rhs
  244. || isUnLiftedType (idType id) = rule_fvs `unionVarSet` rhs_fvs
  245. | otherwise = rule_fvs
  246. -- See Note [extra_fvs (1): avoid floating into RHS]
  247. -- No point in floating in only to float straight out again
  248. -- Ditto ok-for-speculation unlifted RHSs
  249. [shared_binds, extra_binds, rhs_binds, body_binds]
  250. = sepBindsByDropPoint dflags False [extra_fvs, rhs_fvs, body_fvs] to_drop
  251. new_to_drop = body_binds ++ -- the bindings used only in the body
  252. [FB (unitVarSet id) rhs_fvs'
  253. (FloatLet (NonRec id rhs'))] ++ -- the new binding itself
  254. extra_binds ++ -- bindings from extra_fvs
  255. shared_binds -- the bindings used both in rhs and body
  256. -- Push rhs_binds into the right hand side of the binding
  257. rhs' = fiExpr dflags rhs_binds rhs
  258. rhs_fvs' = rhs_fvs `unionVarSet` floatedBindsFVs rhs_binds `unionVarSet` rule_fvs
  259. -- Don't forget the rule_fvs; the binding mentions them!
  260. fiExpr dflags to_drop (_,AnnLet (AnnRec bindings) body)
  261. = fiExpr dflags new_to_drop body
  262. where
  263. (ids, rhss) = unzip bindings
  264. rhss_fvs = map freeVarsOf rhss
  265. body_fvs = freeVarsOf body
  266. -- See Note [extra_fvs (1,2)]
  267. rule_fvs = foldr (unionVarSet . idRuleAndUnfoldingVars) emptyVarSet ids
  268. extra_fvs = rule_fvs `unionVarSet`
  269. unionVarSets [ fvs | (fvs, rhs) <- rhss
  270. , noFloatIntoRhs rhs ]
  271. (shared_binds:extra_binds:body_binds:rhss_binds)
  272. = sepBindsByDropPoint dflags False (extra_fvs:body_fvs:rhss_fvs) to_drop
  273. new_to_drop = body_binds ++ -- the bindings used only in the body
  274. [FB (mkVarSet ids) rhs_fvs'
  275. (FloatLet (Rec (fi_bind rhss_binds bindings)))] ++
  276. -- The new binding itself
  277. extra_binds ++ -- Note [extra_fvs (1,2)]
  278. shared_binds -- Used in more than one place
  279. rhs_fvs' = unionVarSets rhss_fvs `unionVarSet`
  280. unionVarSets (map floatedBindsFVs rhss_binds) `unionVarSet`
  281. rule_fvs -- Don't forget the rule variables!
  282. -- Push rhs_binds into the right hand side of the binding
  283. fi_bind :: [FloatInBinds] -- one per "drop pt" conjured w/ fvs_of_rhss
  284. -> [(Id, CoreExprWithFVs)]
  285. -> [(Id, CoreExpr)]
  286. fi_bind to_drops pairs
  287. = [ (binder, fiExpr dflags to_drop rhs)
  288. | ((binder, rhs), to_drop) <- zipEqual "fi_bind" pairs to_drops ]
  289. \end{code}
  290. For @Case@, the possible ``drop points'' for the \tr{to_drop}
  291. bindings are: (a)~inside the scrutinee, (b)~inside one of the
  292. alternatives/default [default FVs always {\em first}!].
  293. Floating case expressions inward was added to fix Trac #5658: strict bindings
  294. not floated in. In particular, this change allows array indexing operations,
  295. which have a single DEFAULT alternative without any binders, to be floated
  296. inward. SIMD primops for unpacking SIMD vectors into an unboxed tuple of unboxed
  297. scalars also need to be floated inward, but unpacks have a single non-DEFAULT
  298. alternative that binds the elements of the tuple. We now therefore also support
  299. floating in cases with a single alternative that may bind values.
  300. \begin{code}
  301. fiExpr dflags to_drop (_, AnnCase scrut case_bndr _ [(con,alt_bndrs,rhs)])
  302. | isUnLiftedType (idType case_bndr)
  303. , exprOkForSideEffects (deAnnotate scrut)
  304. = wrapFloats shared_binds $
  305. fiExpr dflags (case_float : rhs_binds) rhs
  306. where
  307. case_float = FB (mkVarSet (case_bndr : alt_bndrs)) scrut_fvs
  308. (FloatCase scrut' case_bndr con alt_bndrs)
  309. scrut' = fiExpr dflags scrut_binds scrut
  310. [shared_binds, scrut_binds, rhs_binds]
  311. = sepBindsByDropPoint dflags False [freeVarsOf scrut, rhs_fvs] to_drop
  312. rhs_fvs = freeVarsOf rhs `delVarSetList` (case_bndr : alt_bndrs)
  313. scrut_fvs = freeVarsOf scrut
  314. fiExpr dflags to_drop (_, AnnCase scrut case_bndr ty alts)
  315. = wrapFloats drop_here1 $
  316. wrapFloats drop_here2 $
  317. Case (fiExpr dflags scrut_drops scrut) case_bndr ty
  318. (zipWith fi_alt alts_drops_s alts)
  319. where
  320. -- Float into the scrut and alts-considered-together just like App
  321. [drop_here1, scrut_drops, alts_drops]
  322. = sepBindsByDropPoint dflags False [scrut_fvs, all_alts_fvs] to_drop
  323. -- Float into the alts with the is_case flag set
  324. (drop_here2 : alts_drops_s) = sepBindsByDropPoint dflags True alts_fvs alts_drops
  325. scrut_fvs = freeVarsOf scrut
  326. alts_fvs = map alt_fvs alts
  327. all_alts_fvs = unionVarSets alts_fvs
  328. alt_fvs (_con, args, rhs) = foldl delVarSet (freeVarsOf rhs) (case_bndr:args)
  329. -- Delete case_bndr and args from free vars of rhs
  330. -- to get free vars of alt
  331. fi_alt to_drop (con, args, rhs) = (con, args, fiExpr dflags to_drop rhs)
  332. okToFloatInside :: [Var] -> Bool
  333. okToFloatInside bndrs = all ok bndrs
  334. where
  335. ok b = not (isId b) || isOneShotBndr b
  336. -- Push the floats inside there are no non-one-shot value binders
  337. noFloatIntoRhs :: AnnExpr' Var (UniqFM Var) -> Bool
  338. noFloatIntoRhs (AnnLam bndr e)
  339. = not (okToFloatInside (bndr:bndrs))
  340. -- NB: Must line up with fiExpr (AnnLam...); see Trac #7088
  341. where
  342. (bndrs, _) = collectAnnBndrs e
  343. -- IMPORTANT: don't say 'True' for a RHS with a one-shot lambda at the top.
  344. -- This makes a big difference for things like
  345. -- f x# = let x = I# x#
  346. -- in let j = \() -> ...x...
  347. -- in if <condition> then normal-path else j ()
  348. -- If x is used only in the error case join point, j, we must float the
  349. -- boxing constructor into it, else we box it every time which is very bad
  350. -- news indeed.
  351. noFloatIntoRhs rhs = exprIsExpandable (deAnnotate' rhs)
  352. -- We'd just float right back out again...
  353. -- Should match the test in SimplEnv.doFloatFromRhs
  354. \end{code}
  355. %************************************************************************
  356. %* *
  357. \subsection{@sepBindsByDropPoint@}
  358. %* *
  359. %************************************************************************
  360. This is the crucial function. The idea is: We have a wad of bindings
  361. that we'd like to distribute inside a collection of {\em drop points};
  362. insides the alternatives of a \tr{case} would be one example of some
  363. drop points; the RHS and body of a non-recursive \tr{let} binding
  364. would be another (2-element) collection.
  365. So: We're given a list of sets-of-free-variables, one per drop point,
  366. and a list of floating-inwards bindings. If a binding can go into
  367. only one drop point (without suddenly making something out-of-scope),
  368. in it goes. If a binding is used inside {\em multiple} drop points,
  369. then it has to go in a you-must-drop-it-above-all-these-drop-points
  370. point.
  371. We have to maintain the order on these drop-point-related lists.
  372. \begin{code}
  373. sepBindsByDropPoint
  374. :: DynFlags
  375. -> Bool -- True <=> is case expression
  376. -> [FreeVarSet] -- One set of FVs per drop point
  377. -> FloatInBinds -- Candidate floaters
  378. -> [FloatInBinds] -- FIRST one is bindings which must not be floated
  379. -- inside any drop point; the rest correspond
  380. -- one-to-one with the input list of FV sets
  381. -- Every input floater is returned somewhere in the result;
  382. -- none are dropped, not even ones which don't seem to be
  383. -- free in *any* of the drop-point fvs. Why? Because, for example,
  384. -- a binding (let x = E in B) might have a specialised version of
  385. -- x (say x') stored inside x, but x' isn't free in E or B.
  386. type DropBox = (FreeVarSet, FloatInBinds)
  387. sepBindsByDropPoint _ _is_case drop_pts []
  388. = [] : [[] | _ <- drop_pts] -- cut to the chase scene; it happens
  389. sepBindsByDropPoint dflags is_case drop_pts floaters
  390. = go floaters (map (\fvs -> (fvs, [])) (emptyVarSet : drop_pts))
  391. where
  392. go :: FloatInBinds -> [DropBox] -> [FloatInBinds]
  393. -- The *first* one in the argument list is the drop_here set
  394. -- The FloatInBinds in the lists are in the reverse of
  395. -- the normal FloatInBinds order; that is, they are the right way round!
  396. go [] drop_boxes = map (reverse . snd) drop_boxes
  397. go (bind_w_fvs@(FB bndrs bind_fvs bind) : binds) drop_boxes@(here_box : fork_boxes)
  398. = go binds new_boxes
  399. where
  400. -- "here" means the group of bindings dropped at the top of the fork
  401. (used_here : used_in_flags) = [ fvs `intersectsVarSet` bndrs
  402. | (fvs, _) <- drop_boxes]
  403. drop_here = used_here || not can_push
  404. -- For case expressions we duplicate the binding if it is
  405. -- reasonably small, and if it is not used in all the RHSs
  406. -- This is good for situations like
  407. -- let x = I# y in
  408. -- case e of
  409. -- C -> error x
  410. -- D -> error x
  411. -- E -> ...not mentioning x...
  412. n_alts = length used_in_flags
  413. n_used_alts = count id used_in_flags -- returns number of Trues in list.
  414. can_push = n_used_alts == 1 -- Used in just one branch
  415. || (is_case && -- We are looking at case alternatives
  416. n_used_alts > 1 && -- It's used in more than one
  417. n_used_alts < n_alts && -- ...but not all
  418. floatIsDupable dflags bind) -- and we can duplicate the binding
  419. new_boxes | drop_here = (insert here_box : fork_boxes)
  420. | otherwise = (here_box : new_fork_boxes)
  421. new_fork_boxes = zipWithEqual "FloatIn.sepBinds" insert_maybe fork_boxes used_in_flags
  422. insert :: DropBox -> DropBox
  423. insert (fvs,drops) = (fvs `unionVarSet` bind_fvs, bind_w_fvs:drops)
  424. insert_maybe box True = insert box
  425. insert_maybe box False = box
  426. go _ _ = panic "sepBindsByDropPoint/go"
  427. floatedBindsFVs :: FloatInBinds -> FreeVarSet
  428. floatedBindsFVs binds = foldr (unionVarSet . fbFVs) emptyVarSet binds
  429. fbFVs :: FloatInBind -> VarSet
  430. fbFVs (FB _ fvs _) = fvs
  431. wrapFloats :: FloatInBinds -> CoreExpr -> CoreExpr
  432. -- Remember FloatInBinds is in *reverse* dependency order
  433. wrapFloats [] e = e
  434. wrapFloats (FB _ _ fl : bs) e = wrapFloats bs (wrapFloat fl e)
  435. floatIsDupable :: DynFlags -> FloatBind -> Bool
  436. floatIsDupable dflags (FloatCase scrut _ _ _) = exprIsDupable dflags scrut
  437. floatIsDupable dflags (FloatLet (Rec prs)) = all (exprIsDupable dflags . snd) prs
  438. floatIsDupable dflags (FloatLet (NonRec _ r)) = exprIsDupable dflags r
  439. \end{code}