Generalized assignment rewriting pass.
[ghc-hetmet.git] / compiler / cmm / CmmSpillReload.hs
1 {-# LANGUAGE GADTs, NoMonoLocalBinds, FlexibleContexts, ViewPatterns #-}
2 -- Norman likes local bindings
3 -- If this module lives on I'd like to get rid of this flag in due course
4
5 {-# OPTIONS_GHC -fno-warn-warnings-deprecations #-}
6 {-# OPTIONS_GHC -fno-warn-incomplete-patterns #-}
7 #if __GLASGOW_HASKELL__ >= 701
8 -- GHC 7.0.1 improved incomplete pattern warnings with GADTs
9 {-# OPTIONS_GHC -fwarn-incomplete-patterns #-}
10 #endif
11
12 module CmmSpillReload
13   ( DualLive(..)
14   , dualLiveLattice, dualLiveTransfers, dualLiveness
15   --, insertSpillsAndReloads  --- XXX todo check live-in at entry against formals
16   , dualLivenessWithInsertion
17
18   , rewriteAssignments
19   , removeDeadAssignmentsAndReloads
20   )
21 where
22
23 import BlockId
24 import Cmm
25 import CmmExpr
26 import CmmLive
27 import OptimizationFuel
28
29 import Control.Monad
30 import Outputable hiding (empty)
31 import qualified Outputable as PP
32 import UniqSet
33 import UniqFM
34 import Unique
35
36 import Compiler.Hoopl hiding (Unique)
37 import Data.Maybe
38 import Prelude hiding (succ, zip)
39
40 {- Note [Overview of spill/reload]
41 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
42 The point of this module is to insert spills and reloads to
43 establish the invariant that at a call (or at any proc point with
44 an established protocol) all live variables not expected in
45 registers are sitting on the stack.  We use a backward analysis to
46 insert spills and reloads.  It should be followed by a
47 forward transformation to sink reloads as deeply as possible, so as
48 to reduce register pressure.
49
50 A variable can be expected to be live in a register, live on the
51 stack, or both.  This analysis ensures that spills and reloads are
52 inserted as needed to make sure that every live variable needed
53 after a call is available on the stack.  Spills are pushed back to
54 their reaching definitions, but reloads are dropped wherever needed
55 and will have to be sunk by a later forward transformation.
56 -}
57
58 data DualLive = DualLive { on_stack :: RegSet, in_regs :: RegSet }
59
60 dualUnion :: DualLive -> DualLive -> DualLive
61 dualUnion (DualLive s r) (DualLive s' r') =
62     DualLive (s `unionUniqSets` s') (r `unionUniqSets` r') 
63
64 dualUnionList :: [DualLive] -> DualLive
65 dualUnionList ls = DualLive ss rs
66     where ss = unionManyUniqSets $ map on_stack ls
67           rs = unionManyUniqSets $ map in_regs  ls
68
69 changeStack, changeRegs :: (RegSet -> RegSet) -> DualLive -> DualLive
70 changeStack f live = live { on_stack = f (on_stack live) }
71 changeRegs  f live = live { in_regs  = f (in_regs  live) }
72
73
74 dualLiveLattice :: DataflowLattice DualLive
75 dualLiveLattice = DataflowLattice "variables live in registers and on stack" empty add
76     where empty = DualLive emptyRegSet emptyRegSet
77           add _ (OldFact old) (NewFact new) = (changeIf $ change1 || change2, DualLive stack regs)
78             where (change1, stack) = add1 (on_stack old) (on_stack new)
79                   (change2, regs)  = add1 (in_regs old)  (in_regs new)
80           add1 old new = if sizeUniqSet join > sizeUniqSet old then (True, join) else (False, old)
81             where join = unionUniqSets old new
82
83 dualLivenessWithInsertion :: BlockSet -> CmmGraph -> FuelUniqSM CmmGraph
84 dualLivenessWithInsertion procPoints g =
85   liftM fst $ dataflowPassBwd g [] $ analRewBwd dualLiveLattice
86                                                 (dualLiveTransfers (g_entry g) procPoints)
87                                                 (insertSpillAndReloadRewrites g procPoints)
88
89 dualLiveness :: BlockSet -> CmmGraph -> FuelUniqSM (BlockEnv DualLive)
90 dualLiveness procPoints g =
91   liftM snd $ dataflowPassBwd g [] $ analBwd dualLiveLattice $ dualLiveTransfers (g_entry g) procPoints
92
93 dualLiveTransfers :: BlockId -> BlockSet -> (BwdTransfer CmmNode DualLive)
94 dualLiveTransfers entry procPoints = mkBTransfer3 first middle last
95     where first :: CmmNode C O -> DualLive -> DualLive
96           first (CmmEntry id) live = check live id $  -- live at procPoint => spill
97             if id /= entry && setMember id procPoints
98                then DualLive { on_stack = on_stack live `plusRegSet` in_regs live
99                              , in_regs  = emptyRegSet }
100                else live
101             where check live id x = if id == entry then noLiveOnEntry id (in_regs live) x else x
102
103           middle :: CmmNode O O -> DualLive -> DualLive
104           middle m = changeStack updSlots
105                    . changeRegs  updRegs
106             where -- Reuse middle of liveness analysis from CmmLive
107                   updRegs = case getBTransfer3 xferLive of (_, middle, _) -> middle m
108
109                   updSlots live = foldSlotsUsed reload (foldSlotsDefd spill live m) m
110                   spill  live s@(RegSlot r, _, _) = check s $ deleteFromRegSet live r
111                   spill  live _ = live
112                   reload live s@(RegSlot r, _, _) = check s $ extendRegSet live r
113                   reload live _ = live
114                   check (RegSlot (LocalReg _ ty), o, w) x
115                      | o == w && w == widthInBytes (typeWidth ty) = x
116                   check _ _ = panic "middleDualLiveness unsupported: slices"
117           last :: CmmNode O C -> FactBase DualLive -> DualLive
118           last l fb = case l of
119             CmmBranch id                   -> lkp id
120             l@(CmmCall {cml_cont=Nothing}) -> changeRegs (gen l . kill l) empty
121             l@(CmmCall {cml_cont=Just k})  -> call l k
122             l@(CmmForeignCall {succ=k})    -> call l k
123             l@(CmmCondBranch _ t f)        -> changeRegs (gen l . kill l) $ dualUnion (lkp t) (lkp f)
124             l@(CmmSwitch _ tbl)            -> changeRegs (gen l . kill l) $ dualUnionList $ map lkp (catMaybes tbl)
125             where empty = fact_bot dualLiveLattice
126                   lkp id = empty `fromMaybe` lookupFact id fb
127                   call l k = DualLive (on_stack (lkp k)) (gen l emptyRegSet)
128
129 gen  :: UserOfLocalRegs    a => a -> RegSet -> RegSet
130 gen  a live = foldRegsUsed extendRegSet     live a
131 kill :: DefinerOfLocalRegs a => a -> RegSet -> RegSet
132 kill a live = foldRegsDefd deleteFromRegSet live a
133
134 insertSpillAndReloadRewrites :: CmmGraph -> BlockSet -> CmmBwdRewrite DualLive
135 insertSpillAndReloadRewrites graph procPoints = deepBwdRw3 first middle nothing
136   -- Beware: deepBwdRw with one polymorphic function seems more reasonable here,
137   -- but GHC miscompiles it, see bug #4044.
138     where first :: CmmNode C O -> Fact O DualLive -> CmmReplGraph C O
139           first e@(CmmEntry id) live = return $
140             if id /= (g_entry graph) && setMember id procPoints then
141               case map reload (uniqSetToList spill_regs) of
142                 [] -> Nothing
143                 is -> Just $ mkFirst e <*> mkMiddles is
144             else Nothing
145               where
146                 -- If we are splitting procedures, we need the LastForeignCall
147                 -- to spill its results to the stack because they will only
148                 -- be used by a separate procedure (so they can't stay in LocalRegs).
149                 splitting = True
150                 spill_regs = if splitting then in_regs live
151                              else in_regs live `minusRegSet` defs
152                 defs = case mapLookup id firstDefs of
153                            Just defs -> defs
154                            Nothing   -> emptyRegSet
155                 -- A LastForeignCall may contain some definitions, which take place
156                 -- on return from the function call. Therefore, we build a map (firstDefs)
157                 -- from BlockId to the set of variables defined on return to the BlockId.
158                 firstDefs = mapFold addLive emptyBlockMap (toBlockMap graph)
159                 addLive :: CmmBlock -> BlockEnv RegSet -> BlockEnv RegSet
160                 addLive b env = case lastNode b of
161                                   CmmForeignCall {succ=k, res=defs} -> add k (mkRegSet defs) env
162                                   _                                 -> env
163                 add bid defs env = mapInsert bid defs'' env
164                   where defs'' = case mapLookup bid env of
165                                    Just defs' -> timesRegSet defs defs'
166                                    Nothing    -> defs
167
168           middle :: CmmNode O O -> Fact O DualLive -> CmmReplGraph O O
169           middle (CmmAssign (CmmLocal reg) (CmmLoad (CmmStackSlot (RegSlot reg') _) _)) _ | reg == reg' = return Nothing
170           middle m@(CmmAssign (CmmLocal reg) _) live = return $
171               if reg `elemRegSet` on_stack live then -- must spill
172                    my_trace "Spilling" (f4sep [text "spill" <+> ppr reg,
173                                                text "after"{-, ppr m-}]) $
174                    Just $ mkMiddles $ [m, spill reg]
175               else Nothing
176           middle _ _ = return Nothing
177
178           nothing _ _ = return Nothing
179
180 regSlot :: LocalReg -> CmmExpr
181 regSlot r = CmmStackSlot (RegSlot r) (widthInBytes $ typeWidth $ localRegType r)
182
183 spill, reload :: LocalReg -> CmmNode O O
184 spill  r = CmmStore  (regSlot r) (CmmReg $ CmmLocal r)
185 reload r = CmmAssign (CmmLocal r) (CmmLoad (regSlot r) $ localRegType r)
186
187 removeDeadAssignmentsAndReloads :: BlockSet -> CmmGraph -> FuelUniqSM CmmGraph
188 removeDeadAssignmentsAndReloads procPoints g =
189    liftM fst $ dataflowPassBwd g [] $ analRewBwd dualLiveLattice
190                                                  (dualLiveTransfers (g_entry g) procPoints)
191                                                  rewrites
192    where rewrites = deepBwdRw3 nothing middle nothing
193          -- Beware: deepBwdRw with one polymorphic function seems more reasonable here,
194          -- but GHC panics while compiling, see bug #4045.
195          middle :: CmmNode O O -> Fact O DualLive -> CmmReplGraph O O
196          middle (CmmAssign (CmmLocal reg') _) live | not (reg' `elemRegSet` in_regs live) = return $ Just emptyGraph
197          -- XXX maybe this should be somewhere else...
198          middle (CmmStore lhs (CmmLoad rhs _)) _ | lhs == rhs = return $ Just emptyGraph
199          middle _ _ = return Nothing
200
201          nothing _ _ = return Nothing
202
203 ----------------------------------------------------------------
204 --- Usage information
205
206 -- We decorate all register assignments with usage information,
207 -- that is, the maximum number of times the register is referenced
208 -- while it is live along all outgoing control paths.  There are a few
209 -- subtleties here:
210 --
211 --  - If a register goes dead, and then becomes live again, the usages
212 --    of the disjoint live range don't count towards the original range.
213 --
214 --          a = 1; // used once
215 --          b = a;
216 --          a = 2; // used once
217 --          c = a;
218 --
219 --  - A register may be used multiple times, but these all reside in
220 --    different control paths, such that any given execution only uses
221 --    it once. In that case, the usage count may still be 1.
222 --
223 --          a = 1; // used once
224 --          if (b) {
225 --              c = a + 3;
226 --          } else {
227 --              c = a + 1;
228 --          }
229 --
230 --    This policy corresponds to an inlining strategy that does not
231 --    duplicate computation but may increase binary size.
232 --
233 --  - If we naively implement a usage count, we have a counting to
234 --    infinity problem across joins.  Furthermore, knowing that
235 --    something is used 2 or more times in one runtime execution isn't
236 --    particularly useful for optimizations (inlining may be beneficial,
237 --    but there's no way of knowing that without register pressure
238 --    information.)
239 --
240 --          while (...) {
241 --              // first iteration, b used once
242 --              // second iteration, b used twice
243 --              // third iteration ...
244 --              a = b;
245 --          }
246 --          // b used zero times
247 --
248 --    There is an orthogonal question, which is that for every runtime
249 --    execution, the register may be used only once, but if we inline it
250 --    in every conditional path, the binary size might increase a lot.
251 --    But tracking this information would be tricky, because it violates
252 --    the finite lattice restriction Hoopl requires for termination;
253 --    we'd thus need to supply an alternate proof, which is probably
254 --    something we should defer until we actually have an optimization
255 --    that would take advantage of this.  (This might also interact
256 --    strangely with liveness information.)
257 --
258 --          a = ...;
259 --          // a is used one time, but in X different paths
260 --          case (b) of
261 --              1 -> ... a ...
262 --              2 -> ... a ...
263 --              3 -> ... a ...
264 --              ...
265 --
266 --  This analysis is very similar to liveness analysis; we just keep a
267 --  little extra info. (Maybe we should move it to CmmLive, and subsume
268 --  the old liveness analysis.)
269
270 data RegUsage = SingleUse | ManyUse
271     deriving (Ord, Eq, Show)
272 -- Absence in map = ZeroUse
273
274 {-
275 -- minBound is bottom, maxBound is top, least-upper-bound is max
276 -- ToDo: Put this in Hoopl.  Note that this isn't as useful as I
277 -- originally hoped, because you usually want to leave out the bottom
278 -- element when you have things like this put in maps.  Maybe f is
279 -- useful on its own as a combining function.
280 boundedOrdLattice :: (Bounded a, Ord a) => String -> DataflowLattice a
281 boundedOrdLattice n = DataflowLattice n minBound f
282     where f _ (OldFact x) (NewFact y)
283             | x >= y    = (NoChange,   x)
284             | otherwise = (SomeChange, y)
285 -}
286
287 -- Custom node type we'll rewrite to.  CmmAssign nodes to local
288 -- registers are replaced with AssignLocal nodes.
289 data WithRegUsage n e x where
290     Plain       :: n e x -> WithRegUsage n e x
291     AssignLocal :: LocalReg -> CmmExpr -> RegUsage -> WithRegUsage n O O
292
293 instance UserOfLocalRegs (n e x) => UserOfLocalRegs (WithRegUsage n e x) where
294     foldRegsUsed f z (Plain n) = foldRegsUsed f z n
295     foldRegsUsed f z (AssignLocal _ e _) = foldRegsUsed f z e
296
297 instance DefinerOfLocalRegs (n e x) => DefinerOfLocalRegs (WithRegUsage n e x) where
298     foldRegsDefd f z (Plain n) = foldRegsDefd f z n
299     foldRegsDefd f z (AssignLocal r _ _) = foldRegsDefd f z r
300
301 instance NonLocal n => NonLocal (WithRegUsage n) where
302     entryLabel (Plain n) = entryLabel n
303     successors (Plain n) = successors n
304
305 liftRegUsage :: Graph n e x -> Graph (WithRegUsage n) e x
306 liftRegUsage = mapGraph Plain
307
308 eraseRegUsage :: Graph (WithRegUsage CmmNode) e x -> Graph CmmNode e x
309 eraseRegUsage = mapGraph f
310     where f :: WithRegUsage CmmNode e x -> CmmNode e x
311           f (AssignLocal l e _) = CmmAssign (CmmLocal l) e
312           f (Plain n) = n
313
314 type UsageMap = UniqFM RegUsage
315
316 usageLattice :: DataflowLattice UsageMap
317 usageLattice = DataflowLattice "usage counts for registers" emptyUFM (joinUFM f)
318     where f _ (OldFact x) (NewFact y)
319             | x >= y    = (NoChange,   x)
320             | otherwise = (SomeChange, y)
321
322 -- We reuse the names 'gen' and 'kill', although we're doing something
323 -- slightly different from the Dragon Book
324 usageTransfer :: BwdTransfer (WithRegUsage CmmNode) UsageMap
325 usageTransfer = mkBTransfer3 first middle last
326     where first _ f = f
327           middle :: WithRegUsage CmmNode O O -> UsageMap -> UsageMap
328           middle n f = gen_kill n f
329           last :: WithRegUsage CmmNode O C -> FactBase UsageMap -> UsageMap
330           -- Checking for CmmCall/CmmForeignCall is unnecessary, because
331           -- spills/reloads have already occurred by the time we do this
332           -- analysis.
333           -- XXX Deprecated warning is puzzling: what label are we
334           -- supposed to use?
335           -- ToDo: With a bit more cleverness here, we can avoid
336           -- disappointment and heartbreak associated with the inability
337           -- to inline into CmmCall and CmmForeignCall by
338           -- over-estimating the usage to be ManyUse.
339           last n f = gen_kill n (joinOutFacts usageLattice n f)
340           gen_kill a = gen a . kill a
341           gen  a f = foldRegsUsed increaseUsage f a
342           kill a f = foldRegsDefd delFromUFM f a
343           increaseUsage f r = addToUFM_C combine f r SingleUse
344             where combine _ _ = ManyUse
345
346 usageRewrite :: BwdRewrite FuelUniqSM (WithRegUsage CmmNode) UsageMap
347 usageRewrite = mkBRewrite3 first middle last
348     where first  _ _ = return Nothing
349           middle :: Monad m => WithRegUsage CmmNode O O -> UsageMap -> m (Maybe (Graph (WithRegUsage CmmNode) O O))
350           middle (Plain (CmmAssign (CmmLocal l) e)) f
351                      = return . Just
352                      $ case lookupUFM f l of
353                             Nothing    -> emptyGraph
354                             Just usage -> mkMiddle (AssignLocal l e usage)
355           middle _ _ = return Nothing
356           last   _ _ = return Nothing
357
358 type CmmGraphWithRegUsage = GenCmmGraph (WithRegUsage CmmNode)
359 annotateUsage :: CmmGraph -> FuelUniqSM (CmmGraphWithRegUsage)
360 annotateUsage vanilla_g =
361     let g = modifyGraph liftRegUsage vanilla_g
362     in liftM fst $ dataflowPassBwd g [(g_entry g, fact_bot usageLattice)] $
363                                    analRewBwd usageLattice usageTransfer usageRewrite
364
365 ----------------------------------------------------------------
366 --- Assignment tracking
367
368 -- The idea is to maintain a map of local registers do expressions,
369 -- such that the value of that register is the same as the value of that
370 -- expression at any given time.  We can then do several things,
371 -- as described by Assignment.
372
373 -- Assignment describes the various optimizations that are valid
374 -- at a given point in the program.
375 data Assignment =
376 -- This assignment can always be inlined.  It is cheap or single-use.
377                   AlwaysInline CmmExpr
378 -- This assignment should be sunk down to its first use.  (This will
379 -- increase code size if the register is used in multiple control flow
380 -- paths, but won't increase execution time, and the reduction of
381 -- register pressure is worth it.)
382                 | AlwaysSink CmmExpr
383 -- We cannot safely optimize occurrences of this local register. (This
384 -- corresponds to top in the lattice structure.)
385                 | NeverOptimize
386
387 -- Extract the expression that is being assigned to
388 xassign :: Assignment -> Maybe CmmExpr
389 xassign (AlwaysInline e) = Just e
390 xassign (AlwaysSink e)   = Just e
391 xassign NeverOptimize    = Nothing
392
393 -- Extracts the expression, but only if they're the same constructor
394 xassign2 :: (Assignment, Assignment) -> Maybe (CmmExpr, CmmExpr)
395 xassign2 (AlwaysInline e, AlwaysInline e') = Just (e, e')
396 xassign2 (AlwaysSink e, AlwaysSink e')     = Just (e, e')
397 xassign2 _ = Nothing
398
399 -- Note: We'd like to make decisions about "not optimizing" as soon as
400 -- possible, because this will make running the transfer function more
401 -- efficient.
402 type AssignmentMap = UniqFM Assignment
403
404 assignmentLattice :: DataflowLattice AssignmentMap
405 assignmentLattice = DataflowLattice "assignments for registers" emptyUFM (joinUFM add)
406     where add _ (OldFact old) (NewFact new)
407             = case (old, new) of
408                 (NeverOptimize, _) -> (NoChange,   NeverOptimize)
409                 (_, NeverOptimize) -> (SomeChange, NeverOptimize)
410                 (xassign2 -> Just (e, e'))
411                     | e == e'   -> (NoChange, old)
412                     | otherwise -> (SomeChange, NeverOptimize)
413                 _ -> (SomeChange, NeverOptimize)
414
415 -- Deletes sinks from assignment map, because /this/ is the place
416 -- where it will be sunk to.
417 deleteSinks :: UserOfLocalRegs n => n -> AssignmentMap -> AssignmentMap
418 deleteSinks n m = foldRegsUsed (adjustUFM f) m n
419   where f (AlwaysSink _) = NeverOptimize
420         f old = old
421
422 -- Invalidates any expressions that use a register.
423 invalidateUsersOf :: CmmReg -> AssignmentMap -> AssignmentMap
424 invalidateUsersOf reg = mapUFM (invalidateUsers' reg)
425   where invalidateUsers' reg (xassign -> Just e) | reg `regUsedIn` e = NeverOptimize
426         invalidateUsers' _ old = old
427
428 middleAssignment :: WithRegUsage CmmNode O O -> AssignmentMap -> AssignmentMap
429
430 -- Algorithm for annotated assignments:
431 --  1. Delete any sinking assignments that were used by this instruction
432 --  2. Add the assignment to our list of valid local assignments with
433 --     the correct optimization policy.
434 --  3. Look for all assignments that reference that register and
435 --     invalidate them.
436 middleAssignment n@(AssignLocal r e usage) assign
437     = invalidateUsersOf (CmmLocal r) . add . deleteSinks n $ assign
438       where add m = addToUFM m r
439                   $ case usage of
440                         SingleUse -> AlwaysInline e
441                         ManyUse   -> decide e
442             decide CmmLit{}       = AlwaysInline e
443             decide CmmReg{}       = AlwaysInline e
444             decide CmmLoad{}      = AlwaysSink e
445             decide CmmStackSlot{} = AlwaysSink e
446             decide CmmMachOp{}    = AlwaysSink e
447             decide CmmRegOff{}    = AlwaysSink e
448
449 -- Algorithm for unannotated assignments of global registers:
450 -- 1. Delete any sinking assignments that were used by this instruction
451 -- 2. Look for all assignments that reference this register and
452 --    invalidate them.
453 middleAssignment (Plain n@(CmmAssign reg@(CmmGlobal _) _)) assign
454     = invalidateUsersOf reg . deleteSinks n $ assign
455
456 -- Algorithm for unannotated assignments of *local* registers: do
457 -- nothing (it's a reload, so no state should have changed)
458 middleAssignment (Plain (CmmAssign (CmmLocal _) _)) assign = assign
459
460 -- Algorithm for stores:
461 --  1. Delete any sinking assignments that were used by this instruction
462 --  2. Look for all assignments that load from memory locations that
463 --     were clobbered by this store and invalidate them.
464 middleAssignment (Plain n@(CmmStore lhs rhs)) assign
465     = mapUFM_Directly p . deleteSinks n $ assign
466       -- ToDo: There's a missed opportunity here: even if a memory
467       -- access we're attempting to sink gets clobbered at some
468       -- location, it's still /better/ to sink it to right before the
469       -- point where it gets clobbered.  How might we do this?
470       -- Unfortunately, it's too late to change the assignment...
471       where p r (xassign -> Just x) | (lhs, rhs) `clobbers` (r, x) = NeverOptimize
472             p _ old = old
473
474 -- Assumption: Unsafe foreign calls don't clobber memory
475 middleAssignment (Plain n@(CmmUnsafeForeignCall{})) assign
476     = foldRegsDefd (\m r -> addToUFM m r NeverOptimize) (deleteSinks n assign) n
477
478 middleAssignment (Plain (CmmComment {})) assign
479     = assign
480
481 -- Assumptions:
482 --  * Stack slots do not overlap with any other memory locations
483 --  * Non stack-slot stores always conflict with each other.  (This is
484 --    not always the case; we could probably do something special for Hp)
485 --  * Stack slots for different areas do not overlap
486 --  * Stack slots within the same area and different offsets may
487 --    overlap; we need to do a size check (see 'overlaps').
488 clobbers :: (CmmExpr, CmmExpr) -> (Unique, CmmExpr) -> Bool
489 clobbers (ss@CmmStackSlot{}, CmmReg (CmmLocal r)) (u, CmmLoad (ss'@CmmStackSlot{}) _)
490     | getUnique r == u, ss == ss' = False -- No-op on the stack slot (XXX: Do we need this special case?)
491 clobbers (CmmStackSlot (CallArea a) o, rhs) (_, expr) = f expr
492     where f (CmmLoad (CmmStackSlot (CallArea a') o') t)
493             = (a, o, widthInBytes (cmmExprWidth rhs)) `overlaps` (a', o', widthInBytes (typeWidth t))
494           f (CmmLoad e _)    = containsStackSlot e
495           f (CmmMachOp _ es) = or (map f es)
496           f _                = False
497           -- Maybe there's an invariant broken if this actually ever
498           -- returns True
499           containsStackSlot (CmmLoad{})      = True -- load of a load, all bets off
500           containsStackSlot (CmmMachOp _ es) = or (map containsStackSlot es)
501           containsStackSlot (CmmStackSlot{}) = True
502           containsStackSlot _ = False
503 clobbers _ (_, e) = f e
504     where f (CmmLoad (CmmStackSlot _ _) _) = False
505           f (CmmLoad{}) = True -- conservative
506           f (CmmMachOp _ es) = or (map f es)
507           f _ = False
508
509 -- Check for memory overlapping.
510 -- Diagram:
511 --      4      8     12
512 --      s -w-  o
513 --      [ I32  ]
514 --      [    F64     ]
515 --      s'   -w'-    o'
516 type CallSubArea = (AreaId, Int, Int) -- area, offset, width
517 overlaps :: CallSubArea -> CallSubArea -> Bool
518 overlaps (a, _, _) (a', _, _) | a /= a' = False
519 overlaps (_, o, w) (_, o', w') =
520     let s  = o  - w
521         s' = o' - w'
522     in (s' < o) && (s < o) -- Not LTE, because [ I32  ][ I32  ] is OK
523
524 lastAssignment :: WithRegUsage CmmNode O C -> AssignmentMap -> [(Label, AssignmentMap)]
525 -- Variables are dead across calls, so invalidating all mappings is justified
526 lastAssignment (Plain (CmmCall _ (Just k) _ _ _)) assign = [(k, mapUFM (const NeverOptimize) assign)]
527 lastAssignment (Plain (CmmForeignCall {succ=k}))  assign = [(k, mapUFM (const NeverOptimize) assign)]
528 lastAssignment l assign = map (\id -> (id, assign)) $ successors l
529
530 assignmentTransfer :: FwdTransfer (WithRegUsage CmmNode) AssignmentMap
531 assignmentTransfer = mkFTransfer3 (flip const) middleAssignment ((mkFactBase assignmentLattice .) . lastAssignment)
532
533 assignmentRewrite :: FwdRewrite FuelUniqSM (WithRegUsage CmmNode) AssignmentMap
534 assignmentRewrite = mkFRewrite3 first middle last
535     where
536         first _ _ = return Nothing
537         middle (Plain m) assign = return $ rewrite assign (precompute assign m) mkMiddle m
538         middle _ _ = return Nothing
539         last (Plain l) assign = return $ rewrite assign (precompute assign l) mkLast l
540         -- Tuple is (inline?, reloads)
541         precompute assign n = foldRegsUsed f (False, []) n -- duplicates are harmless
542             where f (i, l) r = case lookupUFM assign r of
543                                 Just (AlwaysSink e)   -> (i, (Plain (CmmAssign (CmmLocal r) e)):l)
544                                 Just (AlwaysInline _) -> (True, l)
545                                 Just NeverOptimize    -> (i, l)
546                                 -- This case can show up when we have
547                                 -- limited optimization fuel.
548                                 Nothing -> (i, l)
549         rewrite _ (False, []) _ _ = Nothing
550         -- Note [CmmCall Inline Hack]
551         -- ToDo: Conservative hack: don't do any inlining on CmmCalls, since
552         -- the code produced here tends to be unproblematic and I need
553         -- to write lint passes to ensure that we don't put anything in
554         -- the arguments that could be construed as a global register by
555         -- some later translation pass.  (For example, slots will turn
556         -- into dereferences of Sp).  This is the same hack in spirit as
557         -- was in cmm/CmmOpt.hs.  Fix this up to only bug out if certain
558         -- CmmExprs are involved.
559         -- ToDo: We miss an opportunity here, where all possible
560         -- inlinings should instead be sunk.
561         rewrite _ (True, []) _ n | not (inlinable n) = Nothing -- see [CmmCall Inline Hack]
562         rewrite assign (i, xs) mk n = Just $ mkMiddles xs <*> mk (Plain (inline i assign n))
563
564         inline :: Bool -> AssignmentMap -> CmmNode e x -> CmmNode e x
565         inline False _ n = n
566         inline True  _ n | not (inlinable n) = n -- see [CmmCall Inline Hack]
567         inline True assign n = mapExpDeep inlineExp n
568             where inlineExp old@(CmmReg (CmmLocal r))
569                     = case lookupUFM assign r of
570                         Just (AlwaysInline x) -> x
571                         _ -> old
572                   inlineExp old@(CmmRegOff (CmmLocal r) i)
573                     = case lookupUFM assign r of
574                         Just (AlwaysInline x) -> CmmMachOp (MO_Add rep) [x, CmmLit (CmmInt (fromIntegral i) rep)]
575                             where rep = typeWidth (localRegType r)
576                         _ -> old
577                   inlineExp old = old
578
579         inlinable :: CmmNode e x -> Bool
580         inlinable (CmmCall{}) = False
581         inlinable (CmmForeignCall{}) = False
582         inlinable _ = True
583
584 rewriteAssignments :: CmmGraph -> FuelUniqSM CmmGraph
585 rewriteAssignments g = do
586   g'  <- annotateUsage g
587   g'' <- liftM fst $ dataflowPassFwd g' [(g_entry g, fact_bot assignmentLattice)] $
588                                      analRewFwd assignmentLattice assignmentTransfer assignmentRewrite
589   return (modifyGraph eraseRegUsage g'')
590
591 ---------------------
592 -- prettyprinting
593
594 ppr_regs :: String -> RegSet -> SDoc
595 ppr_regs s regs = text s <+> commafy (map ppr $ uniqSetToList regs)
596   where commafy xs = hsep $ punctuate comma xs
597
598 instance Outputable DualLive where
599   ppr (DualLive {in_regs = regs, on_stack = stack}) =
600       if isEmptyUniqSet regs && isEmptyUniqSet stack then
601           text "<nothing-live>"
602       else
603           nest 2 $ fsep [if isEmptyUniqSet regs then PP.empty
604                          else (ppr_regs "live in regs =" regs),
605                          if isEmptyUniqSet stack then PP.empty
606                          else (ppr_regs "live on stack =" stack)]
607
608 -- ToDo: Outputable instance for UsageMap and AssignmentMap
609
610 my_trace :: String -> SDoc -> a -> a
611 my_trace = if False then pprTrace else \_ _ a -> a
612
613 f4sep :: [SDoc] -> SDoc
614 f4sep [] = fsep []
615 f4sep (d:ds) = fsep (d : map (nest 4) ds)