814bef1401a21dfcabd5cb9423c8906dc8e6f12e
[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 -- foldUFM_Directly :: (Unique -> elt -> a -> a) -> a -> UniqFM elt -> a
425 invalidateUsersOf reg m = foldUFM_Directly f m m -- [foldUFM performance]
426     where f u (xassign -> Just e) m | reg `regUsedIn` e = addToUFM_Directly m u NeverOptimize
427           f _ _ m = m
428 {- This requires the entire spine of the map to be continually rebuilt,
429  - which causes crazy memory usage!
430 invalidateUsersOf reg = mapUFM (invalidateUsers' reg)
431   where invalidateUsers' reg (xassign -> Just e) | reg `regUsedIn` e = NeverOptimize
432         invalidateUsers' _ old = old
433 -}
434
435 -- Note [foldUFM performance]
436 -- These calls to fold UFM no longer leak memory, but they do cause
437 -- pretty killer amounts of allocation.  So they'll be something to
438 -- optimize; we need an algorithmic change to prevent us from having to
439 -- traverse the /entire/ map continually.
440
441 middleAssignment :: WithRegUsage CmmNode O O -> AssignmentMap -> AssignmentMap
442
443 -- Algorithm for annotated assignments:
444 --  1. Delete any sinking assignments that were used by this instruction
445 --  2. Add the assignment to our list of valid local assignments with
446 --     the correct optimization policy.
447 --  3. Look for all assignments that reference that register and
448 --     invalidate them.
449 middleAssignment n@(AssignLocal r e usage) assign
450     = invalidateUsersOf (CmmLocal r) . add . deleteSinks n $ assign
451       where add m = addToUFM m r
452                   $ case usage of
453                         SingleUse -> AlwaysInline e
454                         ManyUse   -> decide e
455             decide CmmLit{}       = AlwaysInline e
456             decide CmmReg{}       = AlwaysInline e
457             decide CmmLoad{}      = AlwaysSink e
458             decide CmmStackSlot{} = AlwaysSink e
459             decide CmmMachOp{}    = AlwaysSink e
460             decide CmmRegOff{}    = AlwaysSink e
461
462 -- Algorithm for unannotated assignments of global registers:
463 -- 1. Delete any sinking assignments that were used by this instruction
464 -- 2. Look for all assignments that reference this register and
465 --    invalidate them.
466 middleAssignment (Plain n@(CmmAssign reg@(CmmGlobal _) _)) assign
467     = invalidateUsersOf reg . deleteSinks n $ assign
468
469 -- Algorithm for unannotated assignments of *local* registers: do
470 -- nothing (it's a reload, so no state should have changed)
471 middleAssignment (Plain (CmmAssign (CmmLocal _) _)) assign = assign
472
473 -- Algorithm for stores:
474 --  1. Delete any sinking assignments that were used by this instruction
475 --  2. Look for all assignments that load from memory locations that
476 --     were clobbered by this store and invalidate them.
477 middleAssignment (Plain n@(CmmStore lhs rhs)) assign
478     = let m = deleteSinks n assign
479       in foldUFM_Directly f m m -- [foldUFM performance]
480       where f u (xassign -> Just x) m | (lhs, rhs) `clobbers` (u, x) = addToUFM_Directly m u NeverOptimize
481             f _ _ m = m
482 {- Also leaky
483     = mapUFM_Directly p . deleteSinks n $ assign
484       -- ToDo: There's a missed opportunity here: even if a memory
485       -- access we're attempting to sink gets clobbered at some
486       -- location, it's still /better/ to sink it to right before the
487       -- point where it gets clobbered.  How might we do this?
488       -- Unfortunately, it's too late to change the assignment...
489       where p r (xassign -> Just x) | (lhs, rhs) `clobbers` (r, x) = NeverOptimize
490             p _ old = old
491 -}
492
493 -- Assumption: Unsafe foreign calls don't clobber memory
494 middleAssignment (Plain n@(CmmUnsafeForeignCall{})) assign
495     = foldRegsDefd (\m r -> addToUFM m r NeverOptimize) (deleteSinks n assign) n
496
497 middleAssignment (Plain (CmmComment {})) assign
498     = assign
499
500 -- Assumptions:
501 --  * Stack slots do not overlap with any other memory locations
502 --  * Non stack-slot stores always conflict with each other.  (This is
503 --    not always the case; we could probably do something special for Hp)
504 --  * Stack slots for different areas do not overlap
505 --  * Stack slots within the same area and different offsets may
506 --    overlap; we need to do a size check (see 'overlaps').
507 clobbers :: (CmmExpr, CmmExpr) -> (Unique, CmmExpr) -> Bool
508 clobbers (ss@CmmStackSlot{}, CmmReg (CmmLocal r)) (u, CmmLoad (ss'@CmmStackSlot{}) _)
509     | getUnique r == u, ss == ss' = False -- No-op on the stack slot (XXX: Do we need this special case?)
510 clobbers (CmmStackSlot (CallArea a) o, rhs) (_, expr) = f expr
511     where f (CmmLoad (CmmStackSlot (CallArea a') o') t)
512             = (a, o, widthInBytes (cmmExprWidth rhs)) `overlaps` (a', o', widthInBytes (typeWidth t))
513           f (CmmLoad e _)    = containsStackSlot e
514           f (CmmMachOp _ es) = or (map f es)
515           f _                = False
516           -- Maybe there's an invariant broken if this actually ever
517           -- returns True
518           containsStackSlot (CmmLoad{})      = True -- load of a load, all bets off
519           containsStackSlot (CmmMachOp _ es) = or (map containsStackSlot es)
520           containsStackSlot (CmmStackSlot{}) = True
521           containsStackSlot _ = False
522 clobbers _ (_, e) = f e
523     where f (CmmLoad (CmmStackSlot _ _) _) = False
524           f (CmmLoad{}) = True -- conservative
525           f (CmmMachOp _ es) = or (map f es)
526           f _ = False
527
528 -- Check for memory overlapping.
529 -- Diagram:
530 --      4      8     12
531 --      s -w-  o
532 --      [ I32  ]
533 --      [    F64     ]
534 --      s'   -w'-    o'
535 type CallSubArea = (AreaId, Int, Int) -- area, offset, width
536 overlaps :: CallSubArea -> CallSubArea -> Bool
537 overlaps (a, _, _) (a', _, _) | a /= a' = False
538 overlaps (_, o, w) (_, o', w') =
539     let s  = o  - w
540         s' = o' - w'
541     in (s' < o) && (s < o) -- Not LTE, because [ I32  ][ I32  ] is OK
542
543 lastAssignment :: WithRegUsage CmmNode O C -> AssignmentMap -> [(Label, AssignmentMap)]
544 -- Variables are dead across calls, so invalidating all mappings is justified
545 lastAssignment (Plain (CmmCall _ (Just k) _ _ _)) assign = [(k, mapUFM (const NeverOptimize) assign)]
546 lastAssignment (Plain (CmmForeignCall {succ=k}))  assign = [(k, mapUFM (const NeverOptimize) assign)]
547 lastAssignment l assign = map (\id -> (id, deleteSinks l assign)) $ successors l
548
549 assignmentTransfer :: FwdTransfer (WithRegUsage CmmNode) AssignmentMap
550 assignmentTransfer = mkFTransfer3 (flip const) middleAssignment ((mkFactBase assignmentLattice .) . lastAssignment)
551
552 assignmentRewrite :: FwdRewrite FuelUniqSM (WithRegUsage CmmNode) AssignmentMap
553 assignmentRewrite = mkFRewrite3 first middle last
554     where
555         first _ _ = return Nothing
556         middle (Plain m) assign = return $ rewrite assign (precompute assign m) mkMiddle m
557         middle _ _ = return Nothing
558         last (Plain l) assign = return $ rewrite assign (precompute assign l) mkLast l
559         -- Tuple is (inline?, reloads)
560         precompute assign n = foldRegsUsed f (False, []) n -- duplicates are harmless
561             where f (i, l) r = case lookupUFM assign r of
562                                 Just (AlwaysSink e)   -> (i, (Plain (CmmAssign (CmmLocal r) e)):l)
563                                 Just (AlwaysInline _) -> (True, l)
564                                 Just NeverOptimize    -> (i, l)
565                                 -- This case can show up when we have
566                                 -- limited optimization fuel.
567                                 Nothing -> (i, l)
568         rewrite _ (False, []) _ _ = Nothing
569         -- Note [CmmCall Inline Hack]
570         -- ToDo: Conservative hack: don't do any inlining on CmmCalls, since
571         -- the code produced here tends to be unproblematic and I need
572         -- to write lint passes to ensure that we don't put anything in
573         -- the arguments that could be construed as a global register by
574         -- some later translation pass.  (For example, slots will turn
575         -- into dereferences of Sp).  This is the same hack in spirit as
576         -- was in cmm/CmmOpt.hs.  Fix this up to only bug out if certain
577         -- CmmExprs are involved.
578         -- ToDo: We miss an opportunity here, where all possible
579         -- inlinings should instead be sunk.
580         rewrite _ (True, []) _ n | not (inlinable n) = Nothing -- see [CmmCall Inline Hack]
581         rewrite assign (i, xs) mk n = Just $ mkMiddles xs <*> mk (Plain (inline i assign n))
582
583         inline :: Bool -> AssignmentMap -> CmmNode e x -> CmmNode e x
584         inline False _ n = n
585         inline True  _ n | not (inlinable n) = n -- see [CmmCall Inline Hack]
586         inline True assign n = mapExpDeep inlineExp n
587             where inlineExp old@(CmmReg (CmmLocal r))
588                     = case lookupUFM assign r of
589                         Just (AlwaysInline x) -> x
590                         _ -> old
591                   inlineExp old@(CmmRegOff (CmmLocal r) i)
592                     = case lookupUFM assign r of
593                         Just (AlwaysInline x) -> CmmMachOp (MO_Add rep) [x, CmmLit (CmmInt (fromIntegral i) rep)]
594                             where rep = typeWidth (localRegType r)
595                         _ -> old
596                   inlineExp old = old
597
598         inlinable :: CmmNode e x -> Bool
599         inlinable (CmmCall{}) = False
600         inlinable (CmmForeignCall{}) = False
601         inlinable _ = True
602
603 rewriteAssignments :: CmmGraph -> FuelUniqSM CmmGraph
604 rewriteAssignments g = do
605   g'  <- annotateUsage g
606   g'' <- liftM fst $ dataflowPassFwd g' [(g_entry g, fact_bot assignmentLattice)] $
607                                      analRewFwd assignmentLattice assignmentTransfer assignmentRewrite
608   return (modifyGraph eraseRegUsage g'')
609
610 ---------------------
611 -- prettyprinting
612
613 ppr_regs :: String -> RegSet -> SDoc
614 ppr_regs s regs = text s <+> commafy (map ppr $ uniqSetToList regs)
615   where commafy xs = hsep $ punctuate comma xs
616
617 instance Outputable DualLive where
618   ppr (DualLive {in_regs = regs, on_stack = stack}) =
619       if isEmptyUniqSet regs && isEmptyUniqSet stack then
620           text "<nothing-live>"
621       else
622           nest 2 $ fsep [if isEmptyUniqSet regs then PP.empty
623                          else (ppr_regs "live in regs =" regs),
624                          if isEmptyUniqSet stack then PP.empty
625                          else (ppr_regs "live on stack =" stack)]
626
627 -- ToDo: Outputable instance for UsageMap and AssignmentMap
628
629 my_trace :: String -> SDoc -> a -> a
630 my_trace = if False then pprTrace else \_ _ a -> a
631
632 f4sep :: [SDoc] -> SDoc
633 f4sep [] = fsep []
634 f4sep (d:ds) = fsep (d : map (nest 4) ds)