module GHC.CmmToAsm.Reg.Liveness (
RegSet,
RegMap, emptyRegMap,
BlockMap, mapEmpty,
LiveCmmDecl,
InstrSR (..),
LiveInstr (..),
Liveness (..),
LiveInfo (..),
LiveBasicBlock,
mapBlockTop, mapBlockTopM, mapSCCM,
mapGenBlockTop, mapGenBlockTopM,
mapLiveCmmDecl, pprLiveCmmDecl,
stripLive,
stripLiveBlock,
slurpConflicts,
slurpReloadCoalesce,
eraseDeltasLive,
patchEraseLive,
patchRegsLiveInstr,
reverseBlocksInTops,
regLiveness,
cmmTopLiveness
) where
import GHC.Prelude
import GHC.Platform.Reg
import GHC.CmmToAsm.Instr
import GHC.CmmToAsm.CFG
import GHC.CmmToAsm.Config
import GHC.CmmToAsm.Types
import GHC.CmmToAsm.Utils
import GHC.Cmm.BlockId
import GHC.Cmm.Dataflow.Collections
import GHC.Cmm.Dataflow.Label
import GHC.Cmm hiding (RegSet, emptyRegSet)
import GHC.Data.Graph.Directed
import GHC.Utils.Monad
import GHC.Utils.Outputable
import GHC.Utils.Panic
import GHC.Platform
import GHC.Types.Unique.Set
import GHC.Types.Unique.FM
import GHC.Types.Unique.Supply
import GHC.Data.Bag
import GHC.Utils.Monad.State
import Data.List (mapAccumL, groupBy, partition)
import Data.Maybe
import Data.IntSet (IntSet)
type RegSet = UniqSet Reg
type RegMap a = UniqFM Reg a
emptyRegMap :: RegMap a
emptyRegMap = emptyUFM
emptyRegSet :: RegSet
emptyRegSet = emptyUniqSet
type BlockMap a = LabelMap a
type SlotMap a = UniqFM Slot a
type Slot = Int
type LiveCmmDecl statics instr
= GenCmmDecl
statics
LiveInfo
[SCC (LiveBasicBlock instr)]
data InstrSR instr
= Instr instr
| SPILL Reg Int
| RELOAD Int Reg
deriving (Functor)
instance Instruction instr => Instruction (InstrSR instr) where
regUsageOfInstr platform i
= case i of
Instr instr -> regUsageOfInstr platform instr
SPILL reg _ -> RU [reg] []
RELOAD _ reg -> RU [] [reg]
patchRegsOfInstr i f
= case i of
Instr instr -> Instr (patchRegsOfInstr instr f)
SPILL reg slot -> SPILL (f reg) slot
RELOAD slot reg -> RELOAD slot (f reg)
isJumpishInstr i
= case i of
Instr instr -> isJumpishInstr instr
_ -> False
jumpDestsOfInstr i
= case i of
Instr instr -> jumpDestsOfInstr instr
_ -> []
patchJumpInstr i f
= case i of
Instr instr -> Instr (patchJumpInstr instr f)
_ -> i
mkSpillInstr = error "mkSpillInstr[InstrSR]: Not making SPILL meta-instr"
mkLoadInstr = error "mkLoadInstr[InstrSR]: Not making LOAD meta-instr"
takeDeltaInstr i
= case i of
Instr instr -> takeDeltaInstr instr
_ -> Nothing
isMetaInstr i
= case i of
Instr instr -> isMetaInstr instr
_ -> False
mkRegRegMoveInstr platform r1 r2
= Instr (mkRegRegMoveInstr platform r1 r2)
takeRegRegMoveInstr i
= case i of
Instr instr -> takeRegRegMoveInstr instr
_ -> Nothing
mkJumpInstr target = map Instr (mkJumpInstr target)
mkStackAllocInstr platform amount =
Instr <$> mkStackAllocInstr platform amount
mkStackDeallocInstr platform amount =
Instr <$> mkStackDeallocInstr platform amount
pprInstr platform i = ppr (fmap (pprInstr platform) i)
data LiveInstr instr
= LiveInstr (InstrSR instr) (Maybe Liveness)
deriving (Functor)
data Liveness
= Liveness
{ liveBorn :: RegSet
, liveDieRead :: RegSet
, liveDieWrite :: RegSet }
data LiveInfo
= LiveInfo
(LabelMap RawCmmStatics)
[BlockId]
(BlockMap RegSet)
(BlockMap IntSet)
type LiveBasicBlock instr
= GenBasicBlock (LiveInstr instr)
instance Outputable instr
=> Outputable (InstrSR instr) where
ppr (Instr realInstr)
= ppr realInstr
ppr (SPILL reg slot)
= hcat [
text "\tSPILL",
char ' ',
ppr reg,
comma,
text "SLOT" <> parens (int slot)]
ppr (RELOAD slot reg)
= hcat [
text "\tRELOAD",
char ' ',
text "SLOT" <> parens (int slot),
comma,
ppr reg]
instance Outputable instr
=> Outputable (LiveInstr instr) where
ppr (LiveInstr instr Nothing)
= ppr instr
ppr (LiveInstr instr (Just live))
= ppr instr
$$ (nest 8
$ vcat
[ pprRegs (text "# born: ") (liveBorn live)
, pprRegs (text "# r_dying: ") (liveDieRead live)
, pprRegs (text "# w_dying: ") (liveDieWrite live) ]
$+$ space)
where pprRegs :: SDoc -> RegSet -> SDoc
pprRegs name regs
| isEmptyUniqSet regs = empty
| otherwise = name <>
(pprUFM (getUniqSet regs) (hcat . punctuate space . map ppr))
instance OutputableP env instr => OutputableP env (LiveInstr instr) where
pdoc env i = ppr (fmap (pdoc env) i)
instance OutputableP Platform LiveInfo where
pdoc env (LiveInfo mb_static entryIds liveVRegsOnEntry liveSlotsOnEntry)
= (pdoc env mb_static)
$$ text "# entryIds = " <> ppr entryIds
$$ text "# liveVRegsOnEntry = " <> ppr liveVRegsOnEntry
$$ text "# liveSlotsOnEntry = " <> text (show liveSlotsOnEntry)
mapBlockTop
:: (LiveBasicBlock instr -> LiveBasicBlock instr)
-> LiveCmmDecl statics instr -> LiveCmmDecl statics instr
mapBlockTop f cmm
= evalState (mapBlockTopM (\x -> return $ f x) cmm) ()
mapBlockTopM
:: Monad m
=> (LiveBasicBlock instr -> m (LiveBasicBlock instr))
-> LiveCmmDecl statics instr -> m (LiveCmmDecl statics instr)
mapBlockTopM _ cmm@(CmmData{})
= return cmm
mapBlockTopM f (CmmProc header label live sccs)
= do sccs' <- mapM (mapSCCM f) sccs
return $ CmmProc header label live sccs'
mapSCCM :: Monad m => (a -> m b) -> SCC a -> m (SCC b)
mapSCCM f (AcyclicSCC x)
= do x' <- f x
return $ AcyclicSCC x'
mapSCCM f (CyclicSCC xs)
= do xs' <- mapM f xs
return $ CyclicSCC xs'
mapGenBlockTop
:: (GenBasicBlock i -> GenBasicBlock i)
-> (GenCmmDecl d h (ListGraph i) -> GenCmmDecl d h (ListGraph i))
mapGenBlockTop f cmm
= evalState (mapGenBlockTopM (\x -> return $ f x) cmm) ()
mapGenBlockTopM
:: Monad m
=> (GenBasicBlock i -> m (GenBasicBlock i))
-> (GenCmmDecl d h (ListGraph i) -> m (GenCmmDecl d h (ListGraph i)))
mapGenBlockTopM _ cmm@(CmmData{})
= return cmm
mapGenBlockTopM f (CmmProc header label live (ListGraph blocks))
= do blocks' <- mapM f blocks
return $ CmmProc header label live (ListGraph blocks')
slurpConflicts
:: Instruction instr
=> LiveCmmDecl statics instr
-> (Bag (UniqSet Reg), Bag (Reg, Reg))
slurpConflicts live
= slurpCmm (emptyBag, emptyBag) live
where slurpCmm rs CmmData{} = rs
slurpCmm rs (CmmProc info _ _ sccs)
= foldl' (slurpSCC info) rs sccs
slurpSCC info rs (AcyclicSCC b)
= slurpBlock info rs b
slurpSCC info rs (CyclicSCC bs)
= foldl' (slurpBlock info) rs bs
slurpBlock info rs (BasicBlock blockId instrs)
| LiveInfo _ _ blockLive _ <- info
, Just rsLiveEntry <- mapLookup blockId blockLive
, (conflicts, moves) <- slurpLIs rsLiveEntry rs instrs
= (consBag rsLiveEntry conflicts, moves)
| otherwise
= panic "Liveness.slurpConflicts: bad block"
slurpLIs rsLive (conflicts, moves) []
= (consBag rsLive conflicts, moves)
slurpLIs rsLive rs (LiveInstr _ Nothing : lis)
= slurpLIs rsLive rs lis
slurpLIs rsLiveEntry (conflicts, moves) (LiveInstr instr (Just live) : lis)
= let
rsLiveAcross = rsLiveEntry `minusUniqSet` (liveDieRead live)
rsLiveNext = (rsLiveAcross `unionUniqSets` (liveBorn live))
`minusUniqSet` (liveDieWrite live)
rsOrphans = intersectUniqSets
(liveBorn live)
(unionUniqSets (liveDieWrite live) (liveDieRead live))
rsConflicts = unionUniqSets rsLiveNext rsOrphans
in case takeRegRegMoveInstr instr of
Just rr -> slurpLIs rsLiveNext
( consBag rsConflicts conflicts
, consBag rr moves) lis
Nothing -> slurpLIs rsLiveNext
( consBag rsConflicts conflicts
, moves) lis
slurpReloadCoalesce
:: forall statics instr. Instruction instr
=> LiveCmmDecl statics instr
-> Bag (Reg, Reg)
slurpReloadCoalesce live
= slurpCmm emptyBag live
where
slurpCmm :: Bag (Reg, Reg)
-> GenCmmDecl t t1 [SCC (LiveBasicBlock instr)]
-> Bag (Reg, Reg)
slurpCmm cs CmmData{} = cs
slurpCmm cs (CmmProc _ _ _ sccs)
= slurpComp cs (flattenSCCs sccs)
slurpComp :: Bag (Reg, Reg)
-> [LiveBasicBlock instr]
-> Bag (Reg, Reg)
slurpComp cs blocks
= let (moveBags, _) = runState (slurpCompM blocks) emptyUFM
in unionManyBags (cs : moveBags)
slurpCompM :: [LiveBasicBlock instr]
-> State (UniqFM BlockId [UniqFM Slot Reg]) [Bag (Reg, Reg)]
slurpCompM blocks
= do
mapM_ (slurpBlock False) blocks
mapM (slurpBlock True) blocks
slurpBlock :: Bool -> LiveBasicBlock instr
-> State (UniqFM BlockId [UniqFM Slot Reg]) (Bag (Reg, Reg))
slurpBlock propagate (BasicBlock blockId instrs)
= do
slotMap <- if propagate
then getSlotMap blockId
else return emptyUFM
(_, mMoves) <- mapAccumLM slurpLI slotMap instrs
return $ listToBag $ catMaybes mMoves
slurpLI :: SlotMap Reg
-> LiveInstr instr
-> State (UniqFM BlockId [SlotMap Reg])
( SlotMap Reg
, Maybe (Reg, Reg))
slurpLI slotMap li
| LiveInstr (SPILL reg slot) _ <- li
, slotMap' <- addToUFM slotMap slot reg
= return (slotMap', Nothing)
| LiveInstr (RELOAD slot reg) _ <- li
= case lookupUFM slotMap slot of
Just reg2
| reg /= reg2 -> return (slotMap, Just (reg, reg2))
| otherwise -> return (slotMap, Nothing)
Nothing -> return (slotMap, Nothing)
| LiveInstr (Instr instr) _ <- li
, targets <- jumpDestsOfInstr instr
, not $ null targets
= do mapM_ (accSlotMap slotMap) targets
return (slotMap, Nothing)
| otherwise
= return (slotMap, Nothing)
accSlotMap slotMap blockId
= modify (\s -> addToUFM_C (++) s blockId [slotMap])
getSlotMap blockId
= do map <- get
let slotMaps = fromMaybe [] (lookupUFM map blockId)
return $ foldr mergeSlotMaps emptyUFM slotMaps
mergeSlotMaps :: SlotMap Reg -> SlotMap Reg -> SlotMap Reg
mergeSlotMaps map1 map2
= listToUFM_Directly
$ [ (k, r1)
| (k, r1) <- nonDetUFMToList map1
, case lookupUFM_Directly map2 k of
Nothing -> False
Just r2 -> r1 == r2 ]
stripLive
:: (OutputableP Platform statics, Instruction instr)
=> NCGConfig
-> LiveCmmDecl statics instr
-> NatCmmDecl statics instr
stripLive config live
= stripCmm live
where stripCmm :: (OutputableP Platform statics, Instruction instr)
=> LiveCmmDecl statics instr -> NatCmmDecl statics instr
stripCmm (CmmData sec ds) = CmmData sec ds
stripCmm (CmmProc (LiveInfo info (first_id:_) _ _) label live sccs)
= let final_blocks = flattenSCCs sccs
((first':_), rest')
= partition ((== first_id) . blockId) final_blocks
in CmmProc info label live
(ListGraph $ map (stripLiveBlock config) $ first' : rest')
stripCmm proc
= pprPanic "RegAlloc.Liveness.stripLive: no first_id on proc" (pprLiveCmmDecl (ncgPlatform config) proc)
pprLiveCmmDecl :: (OutputableP Platform statics, Instruction instr) => Platform -> LiveCmmDecl statics instr -> SDoc
pprLiveCmmDecl platform d = pdoc platform (mapLiveCmmDecl (pprInstr platform) d)
mapLiveCmmDecl
:: (instr -> b)
-> LiveCmmDecl statics instr
-> LiveCmmDecl statics b
mapLiveCmmDecl f proc = fmap (fmap (fmap (fmap (fmap f)))) proc
stripLiveBlock
:: Instruction instr
=> NCGConfig
-> LiveBasicBlock instr
-> NatBasicBlock instr
stripLiveBlock config (BasicBlock i lis)
= BasicBlock i instrs'
where (instrs', _)
= runState (spillNat [] lis) 0
spillNat acc []
= return (reverse acc)
spillNat acc (LiveInstr (SPILL reg slot) _ : instrs)
= do delta <- get
spillNat (mkSpillInstr config reg delta slot : acc) instrs
spillNat acc (LiveInstr (RELOAD slot reg) _ : instrs)
= do delta <- get
spillNat (mkLoadInstr config reg delta slot : acc) instrs
spillNat acc (LiveInstr (Instr instr) _ : instrs)
| Just i <- takeDeltaInstr instr
= do put i
spillNat acc instrs
spillNat acc (LiveInstr (Instr instr) _ : instrs)
= spillNat (instr : acc) instrs
eraseDeltasLive
:: Instruction instr
=> LiveCmmDecl statics instr
-> LiveCmmDecl statics instr
eraseDeltasLive cmm
= mapBlockTop eraseBlock cmm
where
eraseBlock (BasicBlock id lis)
= BasicBlock id
$ filter (\(LiveInstr i _) -> not $ isJust $ takeDeltaInstr i)
$ lis
patchEraseLive
:: Instruction instr
=> (Reg -> Reg)
-> LiveCmmDecl statics instr -> LiveCmmDecl statics instr
patchEraseLive patchF cmm
= patchCmm cmm
where
patchCmm cmm@CmmData{} = cmm
patchCmm (CmmProc info label live sccs)
| LiveInfo static id blockMap mLiveSlots <- info
= let
patchRegSet set = mkUniqSet $ map patchF $ nonDetEltsUFM set
blockMap' = mapMap (patchRegSet . getUniqSet) blockMap
info' = LiveInfo static id blockMap' mLiveSlots
in CmmProc info' label live $ map patchSCC sccs
patchSCC (AcyclicSCC b) = AcyclicSCC (patchBlock b)
patchSCC (CyclicSCC bs) = CyclicSCC (map patchBlock bs)
patchBlock (BasicBlock id lis)
= BasicBlock id $ patchInstrs lis
patchInstrs [] = []
patchInstrs (li : lis)
| LiveInstr i (Just live) <- li'
, Just (r1, r2) <- takeRegRegMoveInstr i
, eatMe r1 r2 live
= patchInstrs lis
| otherwise
= li' : patchInstrs lis
where li' = patchRegsLiveInstr patchF li
eatMe r1 r2 live
| r1 == r2 = True
| elementOfUniqSet r2 (liveBorn live)
, elementOfUniqSet r2 (liveDieRead live) || elementOfUniqSet r2 (liveDieWrite live)
= True
| otherwise = False
patchRegsLiveInstr
:: Instruction instr
=> (Reg -> Reg)
-> LiveInstr instr -> LiveInstr instr
patchRegsLiveInstr patchF li
= case li of
LiveInstr instr Nothing
-> LiveInstr (patchRegsOfInstr instr patchF) Nothing
LiveInstr instr (Just live)
-> LiveInstr
(patchRegsOfInstr instr patchF)
(Just live
{
liveBorn = mapUniqSet patchF $ liveBorn live
, liveDieRead = mapUniqSet patchF $ liveDieRead live
, liveDieWrite = mapUniqSet patchF $ liveDieWrite live })
cmmTopLiveness
:: Instruction instr
=> Maybe CFG
-> Platform
-> NatCmmDecl statics instr
-> UniqSM (LiveCmmDecl statics instr)
cmmTopLiveness cfg platform cmm
= regLiveness platform $ natCmmTopToLive cfg cmm
natCmmTopToLive
:: Instruction instr
=> Maybe CFG -> NatCmmDecl statics instr
-> LiveCmmDecl statics instr
natCmmTopToLive _ (CmmData i d)
= CmmData i d
natCmmTopToLive _ (CmmProc info lbl live (ListGraph []))
= CmmProc (LiveInfo info [] mapEmpty mapEmpty) lbl live []
natCmmTopToLive mCfg proc@(CmmProc info lbl live (ListGraph blocks@(first : _)))
= CmmProc (LiveInfo info' (first_id : entry_ids) mapEmpty mapEmpty)
lbl live sccsLive
where
first_id = blockId first
all_entry_ids = entryBlocks proc
sccs = sccBlocks blocks all_entry_ids mCfg
sccsLive = map (fmap (\(BasicBlock l instrs) ->
BasicBlock l (map (\i -> LiveInstr (Instr i) Nothing) instrs)))
$ sccs
entry_ids = filter (reachable_node) .
filter (/= first_id) $ all_entry_ids
info' = mapFilterWithKey (\node _ -> reachable_node node) info
reachable_node
| Just cfg <- mCfg
= hasNode cfg
| otherwise
= const True
sccBlocks
:: forall instr . Instruction instr
=> [NatBasicBlock instr]
-> [BlockId]
-> Maybe CFG
-> [SCC (NatBasicBlock instr)]
sccBlocks blocks entries mcfg = map (fmap node_payload) sccs
where
nodes :: [ Node BlockId (NatBasicBlock instr) ]
nodes = [ DigraphNode block id (getOutEdges instrs)
| block@(BasicBlock id instrs) <- blocks ]
g1 = graphFromEdgedVerticesUniq nodes
reachable :: LabelSet
reachable
| Just cfg <- mcfg
= setFromList $ getCfgNodes cfg
| otherwise
= setFromList $ [ node_key node | node <- reachablesG g1 roots ]
g2 = graphFromEdgedVerticesUniq [ node | node <- nodes
, node_key node
`setMember` reachable ]
sccs = stronglyConnCompG g2
getOutEdges :: Instruction instr => [instr] -> [BlockId]
getOutEdges instrs = concatMap jumpDestsOfInstr instrs
roots = [DigraphNode (panic "sccBlocks") b (panic "sccBlocks")
| b <- entries ]
regLiveness
:: Instruction instr
=> Platform
-> LiveCmmDecl statics instr
-> UniqSM (LiveCmmDecl statics instr)
regLiveness _ (CmmData i d)
= return $ CmmData i d
regLiveness _ (CmmProc info lbl live [])
| LiveInfo static mFirst _ _ <- info
= return $ CmmProc
(LiveInfo static mFirst mapEmpty mapEmpty)
lbl live []
regLiveness platform (CmmProc info lbl live sccs)
| LiveInfo static mFirst _ liveSlotsOnEntry <- info
= let (ann_sccs, block_live) = computeLiveness platform sccs
in return $ CmmProc (LiveInfo static mFirst block_live liveSlotsOnEntry)
lbl live ann_sccs
checkIsReverseDependent
:: Instruction instr
=> [SCC (LiveBasicBlock instr)]
-> Maybe BlockId
checkIsReverseDependent sccs'
= go emptyUniqSet sccs'
where go _ []
= Nothing
go blocksSeen (AcyclicSCC block : sccs)
= let dests = slurpJumpDestsOfBlock block
blocksSeen' = unionUniqSets blocksSeen $ mkUniqSet [blockId block]
badDests = dests `minusUniqSet` blocksSeen'
in case nonDetEltsUniqSet badDests of
[] -> go blocksSeen' sccs
bad : _ -> Just bad
go blocksSeen (CyclicSCC blocks : sccs)
= let dests = unionManyUniqSets $ map slurpJumpDestsOfBlock blocks
blocksSeen' = unionUniqSets blocksSeen $ mkUniqSet $ map blockId blocks
badDests = dests `minusUniqSet` blocksSeen'
in case nonDetEltsUniqSet badDests of
[] -> go blocksSeen' sccs
bad : _ -> Just bad
slurpJumpDestsOfBlock (BasicBlock _ instrs)
= unionManyUniqSets
$ map (mkUniqSet . jumpDestsOfInstr)
[ i | LiveInstr i _ <- instrs]
reverseBlocksInTops :: LiveCmmDecl statics instr -> LiveCmmDecl statics instr
reverseBlocksInTops top
= case top of
CmmData{} -> top
CmmProc info lbl live sccs -> CmmProc info lbl live (reverse sccs)
computeLiveness
:: Instruction instr
=> Platform
-> [SCC (LiveBasicBlock instr)]
-> ([SCC (LiveBasicBlock instr)],
BlockMap RegSet)
computeLiveness platform sccs
= case checkIsReverseDependent sccs of
Nothing -> livenessSCCs platform mapEmpty [] sccs
Just bad -> let sccs' = fmap (fmap (fmap (fmap (pprInstr platform)))) sccs
in pprPanic "RegAlloc.Liveness.computeLiveness"
(vcat [ text "SCCs aren't in reverse dependent order"
, text "bad blockId" <+> ppr bad
, ppr sccs'])
livenessSCCs
:: Instruction instr
=> Platform
-> BlockMap RegSet
-> [SCC (LiveBasicBlock instr)]
-> [SCC (LiveBasicBlock instr)]
-> ( [SCC (LiveBasicBlock instr)]
, BlockMap RegSet)
livenessSCCs _ blockmap done []
= (done, blockmap)
livenessSCCs platform blockmap done (AcyclicSCC block : sccs)
= let (blockmap', block') = livenessBlock platform blockmap block
in livenessSCCs platform blockmap' (AcyclicSCC block' : done) sccs
livenessSCCs platform blockmap done
(CyclicSCC blocks : sccs) =
livenessSCCs platform blockmap' (CyclicSCC blocks':done) sccs
where (blockmap', blocks')
= iterateUntilUnchanged linearLiveness equalBlockMaps
blockmap blocks
iterateUntilUnchanged
:: (a -> b -> (a,c)) -> (a -> a -> Bool)
-> a -> b
-> (a,c)
iterateUntilUnchanged f eq a b
= head $
concatMap tail $
groupBy (\(a1, _) (a2, _) -> eq a1 a2) $
iterate (\(a, _) -> f a b) $
(a, panic "RegLiveness.livenessSCCs")
linearLiveness
:: Instruction instr
=> BlockMap RegSet -> [LiveBasicBlock instr]
-> (BlockMap RegSet, [LiveBasicBlock instr])
linearLiveness = mapAccumL (livenessBlock platform)
equalBlockMaps a b
= a' == b'
where a' = map f $ mapToList a
b' = map f $ mapToList b
f (key,elt) = (key, nonDetEltsUniqSet elt)
livenessBlock
:: Instruction instr
=> Platform
-> BlockMap RegSet
-> LiveBasicBlock instr
-> (BlockMap RegSet, LiveBasicBlock instr)
livenessBlock platform blockmap (BasicBlock block_id instrs)
= let
(regsLiveOnEntry, instrs1)
= livenessBack platform emptyUniqSet blockmap [] (reverse instrs)
blockmap' = mapInsert block_id regsLiveOnEntry blockmap
instrs2 = livenessForward platform regsLiveOnEntry instrs1
output = BasicBlock block_id instrs2
in ( blockmap', output)
livenessForward
:: Instruction instr
=> Platform
-> RegSet
-> [LiveInstr instr] -> [LiveInstr instr]
livenessForward _ _ [] = []
livenessForward platform rsLiveEntry (li@(LiveInstr instr mLive) : lis)
| Just live <- mLive
= let
RU _ written = regUsageOfInstr platform instr
rsBorn = mkUniqSet
$ filter (\r -> not $ elementOfUniqSet r rsLiveEntry) written
rsLiveNext = (rsLiveEntry `unionUniqSets` rsBorn)
`minusUniqSet` (liveDieRead live)
`minusUniqSet` (liveDieWrite live)
in LiveInstr instr (Just live { liveBorn = rsBorn })
: livenessForward platform rsLiveNext lis
| otherwise
= li : livenessForward platform rsLiveEntry lis
livenessBack
:: Instruction instr
=> Platform
-> RegSet
-> BlockMap RegSet
-> [LiveInstr instr]
-> [LiveInstr instr]
-> (RegSet, [LiveInstr instr])
livenessBack _ liveregs _ done [] = (liveregs, done)
livenessBack platform liveregs blockmap acc (instr : instrs)
= let (liveregs', instr') = liveness1 platform liveregs blockmap instr
in livenessBack platform liveregs' blockmap (instr' : acc) instrs
liveness1
:: Instruction instr
=> Platform
-> RegSet
-> BlockMap RegSet
-> LiveInstr instr
-> (RegSet, LiveInstr instr)
liveness1 _ liveregs _ (LiveInstr instr _)
| isMetaInstr instr
= (liveregs, LiveInstr instr Nothing)
liveness1 platform liveregs blockmap (LiveInstr instr _)
| not_a_branch
= (liveregs1, LiveInstr instr
(Just $ Liveness
{ liveBorn = emptyUniqSet
, liveDieRead = mkUniqSet r_dying
, liveDieWrite = mkUniqSet w_dying }))
| otherwise
= (liveregs_br, LiveInstr instr
(Just $ Liveness
{ liveBorn = emptyUniqSet
, liveDieRead = mkUniqSet r_dying_br
, liveDieWrite = mkUniqSet w_dying }))
where
!(RU read written) = regUsageOfInstr platform instr
liveregs1 = (liveregs `delListFromUniqSet` written)
`addListToUniqSet` read
r_dying = [ reg | reg <- read, reg `notElem` written,
not (elementOfUniqSet reg liveregs) ]
w_dying = [ reg | reg <- written,
not (elementOfUniqSet reg liveregs) ]
targets = jumpDestsOfInstr instr
not_a_branch = null targets
targetLiveRegs target
= case mapLookup target blockmap of
Just ra -> ra
Nothing -> emptyRegSet
live_from_branch = unionManyUniqSets (map targetLiveRegs targets)
liveregs_br = liveregs1 `unionUniqSets` live_from_branch
live_branch_only = live_from_branch `minusUniqSet` liveregs
r_dying_br = nonDetEltsUniqSet (mkUniqSet r_dying `unionUniqSets`
live_branch_only)