-- (c) The University of Glasgow 2004
--
-----------------------------------------------------------------------------
-
+{-# OPTIONS -Wall -fno-warn-name-shadowing #-}
module RegLiveness (
RegSet,
stripLive,
spillNatBlock,
slurpConflicts,
+ slurpReloadCoalesce,
lifetimeCount,
eraseDeltasLive,
patchEraseLive,
import MachInstrs
import PprMach
import RegAllocInfo
-import Cmm
+import Cmm hiding (RegSet)
import Digraph
import Outputable
type RegSet = UniqSet Reg
type RegMap a = UniqFM a
+
+emptyRegMap :: UniqFM a
emptyRegMap = emptyUFM
type BlockMap a = UniqFM a
+
+emptyBlockMap :: UniqFM a
emptyBlockMap = emptyUFM
= GenCmmTop
CmmStatic
LiveInfo
- (GenBasicBlock LiveInstr)
+ (ListGraph (GenBasicBlock LiveInstr))
-- the "instructions" here are actually more blocks,
-- single blocks are acyclic
-- multiple blocks are taken to be cyclic.
=> (LiveBasicBlock -> m LiveBasicBlock)
-> LiveCmmTop -> m LiveCmmTop
-mapBlockTopM f cmm@(CmmData{})
+mapBlockTopM _ cmm@(CmmData{})
= return cmm
-mapBlockTopM f (CmmProc header label params comps)
+mapBlockTopM f (CmmProc header label params (ListGraph comps))
= do comps' <- mapM (mapBlockCompM f) comps
- return $ CmmProc header label params comps'
+ return $ CmmProc header label params (ListGraph comps')
+mapBlockCompM :: Monad m => (a -> m a') -> (GenBasicBlock a) -> m (GenBasicBlock a')
mapBlockCompM f (BasicBlock i blocks)
= do blocks' <- mapM f blocks
return $ BasicBlock i blocks'
-- map a function across all the basic blocks in this code
mapGenBlockTop
- :: (GenBasicBlock i -> GenBasicBlock i)
- -> (GenCmmTop d h i -> GenCmmTop d h i)
+ :: (GenBasicBlock i -> GenBasicBlock i)
+ -> (GenCmmTop d h (ListGraph i) -> GenCmmTop d h (ListGraph i))
mapGenBlockTop f cmm
= evalState (mapGenBlockTopM (\x -> return $ f x) cmm) ()
-- | map a function across all the basic blocks in this code (monadic version)
mapGenBlockTopM
:: Monad m
- => (GenBasicBlock i -> m (GenBasicBlock i))
- -> (GenCmmTop d h i -> m (GenCmmTop d h i))
+ => (GenBasicBlock i -> m (GenBasicBlock i))
+ -> (GenCmmTop d h (ListGraph i) -> m (GenCmmTop d h (ListGraph i)))
-mapGenBlockTopM f cmm@(CmmData{})
+mapGenBlockTopM _ cmm@(CmmData{})
= return cmm
-mapGenBlockTopM f (CmmProc header label params blocks)
+mapGenBlockTopM f (CmmProc header label params (ListGraph blocks))
= do blocks' <- mapM f blocks
- return $ CmmProc header label params blocks'
-
+ return $ CmmProc header label params (ListGraph blocks')
-
-
--- | Slurp out the list of register conflicts from this top level thing.
-
-slurpConflicts :: LiveCmmTop -> Bag (UniqSet Reg)
+-- | Slurp out the list of register conflicts and reg-reg moves from this top level thing.
+-- Slurping of conflicts and moves is wrapped up together so we don't have
+-- to make two passes over the same code when we want to build the graph.
+--
+slurpConflicts :: LiveCmmTop -> (Bag (UniqSet Reg), Bag (Reg, Reg))
slurpConflicts live
- = slurpCmm emptyBag live
+ = slurpCmm (emptyBag, emptyBag) live
where slurpCmm rs CmmData{} = rs
- slurpCmm rs (CmmProc info _ _ blocks)
+ slurpCmm rs (CmmProc info _ _ (ListGraph blocks))
= foldl' (slurpComp info) rs blocks
- slurpComp info rs (BasicBlock i blocks)
+ slurpComp info rs (BasicBlock _ blocks)
= foldl' (slurpBlock info) rs blocks
slurpBlock info rs (BasicBlock blockId instrs)
| LiveInfo _ _ blockLive <- info
, Just rsLiveEntry <- lookupUFM blockLive blockId
- = consBag rsLiveEntry $ slurpLIs rsLiveEntry rs instrs
+ , (conflicts, moves) <- slurpLIs rsLiveEntry rs instrs
+ = (consBag rsLiveEntry conflicts, moves)
+
+ | otherwise
+ = error "RegLiveness.slurpBlock: bad block"
+
+ slurpLIs rsLive (conflicts, moves) []
+ = (consBag rsLive conflicts, moves)
- slurpLIs rsLive rs [] = consBag rsLive rs
slurpLIs rsLive rs (Instr _ Nothing : lis) = slurpLIs rsLive rs lis
- slurpLIs rsLiveEntry rs (li@(Instr _ (Just live)) : lis)
+ slurpLIs rsLiveEntry (conflicts, moves) (Instr instr (Just live) : lis)
= let
-- regs that die because they are read for the last time at the start of an instruction
-- are not live across it.
--
rsConflicts = unionUniqSets rsLiveNext rsOrphans
- in slurpLIs rsLiveNext (consBag rsConflicts rs) lis
+ in case isRegRegMove instr of
+ Just rr -> slurpLIs rsLiveNext
+ ( consBag rsConflicts conflicts
+ , consBag rr moves) lis
+
+ Nothing -> slurpLIs rsLiveNext
+ ( consBag rsConflicts conflicts
+ , moves) lis
+
+
+-- | For spill/reloads
+--
+-- SPILL v1, slot1
+-- ...
+-- RELOAD slot1, v2
+--
+-- If we can arrange that v1 and v2 are allocated to the same hreg it's more likely
+-- the spill/reload instrs can be cleaned and replaced by a nop reg-reg move.
+--
+-- TODO: This only works intra-block at the momement. It's be nice to join up the mappings
+-- across blocks also.
+--
+slurpReloadCoalesce :: LiveCmmTop -> Bag (Reg, Reg)
+slurpReloadCoalesce live
+ = slurpCmm emptyBag live
+
+ where slurpCmm cs CmmData{} = cs
+ slurpCmm cs (CmmProc _ _ _ (ListGraph blocks))
+ = foldl' slurpComp cs blocks
+
+ slurpComp cs (BasicBlock _ blocks)
+ = foldl' slurpBlock cs blocks
+
+ slurpBlock cs (BasicBlock _ instrs)
+ = let (_, mMoves) = mapAccumL slurpLI emptyUFM instrs
+ in unionBags cs (listToBag $ catMaybes mMoves)
+
+ slurpLI :: UniqFM Reg -> LiveInstr -> (UniqFM Reg, Maybe (Reg, Reg))
+ slurpLI slotMap (Instr instr _)
+
+ -- remember what reg was stored into the slot
+ | SPILL reg slot <- instr
+ , slotMap' <- addToUFM slotMap slot reg
+ = (slotMap', Nothing)
+
+ -- add an edge betwen the this reg and the last one stored into the slot
+ | RELOAD slot reg <- instr
+ = case lookupUFM slotMap slot of
+ Just reg2 -> (slotMap, Just (reg, reg2))
+ Nothing -> (slotMap, Nothing)
+
+ | otherwise
+ = (slotMap, Nothing)
-- | Strip away liveness information, yielding NatCmmTop
= stripCmm live
where stripCmm (CmmData sec ds) = CmmData sec ds
- stripCmm (CmmProc (LiveInfo info _ _) label params comps)
- = CmmProc info label params (concatMap stripComp comps)
+ stripCmm (CmmProc (LiveInfo info _ _) label params (ListGraph comps))
+ = CmmProc info label params (ListGraph $ concatMap stripComp comps)
- stripComp (BasicBlock i blocks) = map stripBlock blocks
+ stripComp (BasicBlock _ blocks) = map stripBlock blocks
stripBlock (BasicBlock i instrs) = BasicBlock i (map stripLI instrs)
stripLI (Instr instr _) = instr
-- | Make real spill instructions out of SPILL, RELOAD pseudos
spillNatBlock :: NatBasicBlock -> NatBasicBlock
-spillNatBlock (BasicBlock i instrs)
+spillNatBlock (BasicBlock i is)
= BasicBlock i instrs'
where (instrs', _)
- = runState (mapM spillNat instrs) 0
+ = runState (spillNat [] is) 0
- spillNat instr@(DELTA i)
+ spillNat acc []
+ = return (reverse acc)
+
+ spillNat acc (DELTA i : instrs)
= do put i
- return instr
+ spillNat acc instrs
- spillNat (SPILL reg slot)
+ spillNat acc (SPILL reg slot : instrs)
= do delta <- get
- return $ mkSpillInstr reg delta slot
+ spillNat (mkSpillInstr reg delta slot : acc) instrs
- spillNat (RELOAD slot reg)
+ spillNat acc (RELOAD slot reg : instrs)
= do delta <- get
- return $ mkLoadInstr reg delta slot
+ spillNat (mkLoadInstr reg delta slot : acc) instrs
- spillNat instr
- = return instr
+ spillNat acc (instr : instrs)
+ = spillNat (instr : acc) instrs
-- | Slurp out a map of how many times each register was live upon entry to an instruction.
= countCmm emptyUFM cmm
where
countCmm fm CmmData{} = fm
- countCmm fm (CmmProc info _ _ blocks)
+ countCmm fm (CmmProc info _ _ (ListGraph blocks))
= foldl' (countComp info) fm blocks
- countComp info fm (BasicBlock i blocks)
+ countComp info fm (BasicBlock _ blocks)
= foldl' (countBlock info) fm blocks
countBlock info fm (BasicBlock blockId instrs)
| LiveInfo _ _ blockLive <- info
, Just rsLiveEntry <- lookupUFM blockLive blockId
= countLIs rsLiveEntry fm instrs
+
+ | otherwise
+ = error "RegLiveness.countBlock: bad block"
- countLIs rsLive fm [] = fm
+ countLIs _ fm [] = fm
countLIs rsLive fm (Instr _ Nothing : lis) = countLIs rsLive fm lis
countLIs rsLiveEntry fm (Instr _ (Just live) : lis)
where
patchCmm cmm@CmmData{} = cmm
- patchCmm cmm@(CmmProc info label params comps)
+ patchCmm (CmmProc info label params (ListGraph comps))
| LiveInfo static id blockMap <- info
= let patchRegSet set = mkUniqSet $ map patchF $ uniqSetToList set
blockMap' = mapUFM patchRegSet blockMap
info' = LiveInfo static id blockMap'
- in CmmProc info' label params $ map patchComp comps
+ in CmmProc info' label params $ ListGraph $ map patchComp comps
patchComp (BasicBlock id blocks)
= BasicBlock id $ map patchBlock blocks
:: NatCmmTop
-> UniqSM LiveCmmTop
-regLiveness cmm@(CmmData sec d)
- = returnUs $ CmmData sec d
+regLiveness (CmmData i d)
+ = returnUs $ CmmData i d
-regLiveness cmm@(CmmProc info lbl params [])
+regLiveness (CmmProc info lbl params (ListGraph []))
= returnUs $ CmmProc
(LiveInfo info Nothing emptyUFM)
- lbl params []
+ lbl params (ListGraph [])
-regLiveness cmm@(CmmProc info lbl params blocks@(first:rest))
+regLiveness (CmmProc info lbl params (ListGraph blocks@(first : _)))
= let first_id = blockId first
sccs = sccBlocks blocks
(ann_sccs, block_live) = computeLiveness sccs
in returnUs $ CmmProc
(LiveInfo info (Just first_id) block_live)
- lbl params liveBlocks
+ lbl params (ListGraph liveBlocks)
sccBlocks :: [NatBasicBlock] -> [SCC NatBasicBlock]
-> NatBasicBlock
-> (BlockMap RegSet, LiveBasicBlock)
-livenessBlock blockmap block@(BasicBlock block_id instrs)
+livenessBlock blockmap (BasicBlock block_id instrs)
= let
(regsLiveOnEntry, instrs1)
= livenessBack emptyUniqSet blockmap [] (reverse instrs)
:: RegSet -- regs live on this instr
-> [LiveInstr] -> [LiveInstr]
-livenessForward rsLiveEntry [] = []
+livenessForward _ [] = []
livenessForward rsLiveEntry (li@(Instr instr mLive) : lis)
| Nothing <- mLive
= li : livenessForward rsLiveEntry lis
- | Just live <- mLive
- , RU read written <- regUsage instr
+ | Just live <- mLive
+ , RU _ written <- regUsage instr
= let
-- Regs that are written to but weren't live on entry to this instruction
-- are recorded as being born here.
in Instr instr (Just live { liveBorn = rsBorn })
: livenessForward rsLiveNext lis
+livenessForward _ _ = panic "RegLiveness.livenessForward: no match"
+
-- | Calculate liveness going backwards,
-- filling in when regs die, and what regs are live across each instruction
-> [Instr] -- instructions
-> (RegSet, [LiveInstr])
-livenessBack liveregs blockmap done [] = (liveregs, done)
+livenessBack liveregs _ done [] = (liveregs, done)
livenessBack liveregs blockmap acc (instr : instrs)
= let (liveregs', instr') = liveness1 liveregs blockmap instr
in livenessBack liveregs' blockmap (instr' : acc) instrs
-- don't bother tagging comments or deltas with liveness
-liveness1 liveregs blockmap (instr@COMMENT{})
+liveness1 :: RegSet -> BlockMap RegSet -> Instr -> (RegSet, LiveInstr)
+liveness1 liveregs _ (instr@COMMENT{})
= (liveregs, Instr instr Nothing)
-liveness1 liveregs blockmap (instr@DELTA{})
+liveness1 liveregs _ (instr@DELTA{})
= (liveregs, Instr instr Nothing)
liveness1 liveregs blockmap instr