module RegAlloc.Linear.JoinToTargets (
joinToTargets
)
where
import RegAlloc.Linear.State
import RegAlloc.Linear.Base
import RegAlloc.Linear.FreeRegs
import RegAlloc.Liveness
import Instruction
import Reg
import BlockId
import OldCmm hiding (RegSet)
import Digraph
import Outputable
import Platform
import Unique
import UniqFM
import UniqSet
joinToTargets
:: (FR freeRegs, Instruction instr)
=> Platform
-> BlockMap RegSet
-> BlockId
-> instr
-> RegM freeRegs ([NatBasicBlock instr]
, instr)
joinToTargets platform block_live id instr
| not $ isJumpishInstr instr
= return ([], instr)
| otherwise
= joinToTargets' platform block_live [] id instr (jumpDestsOfInstr instr)
joinToTargets'
:: (FR freeRegs, Instruction instr)
=> Platform
-> BlockMap RegSet
-> [NatBasicBlock instr]
-> BlockId
-> instr
-> [BlockId]
-> RegM freeRegs ( [NatBasicBlock instr]
, instr)
joinToTargets' _ _ new_blocks _ instr []
= return (new_blocks, instr)
joinToTargets' platform block_live new_blocks block_id instr (dest:dests)
= do
block_assig <- getBlockAssigR
assig <- getAssigR
let Just live_set = mapLookup dest block_live
let still_live uniq _ = uniq `elemUniqSet_Directly` live_set
let adjusted_assig = filterUFM_Directly still_live assig
let to_free =
[ r | (reg, loc) <- ufmToList assig
, not (elemUniqSet_Directly reg live_set)
, r <- regsOfLoc loc ]
case mapLookup dest block_assig of
Nothing
-> joinToTargets_first
platform block_live new_blocks block_id instr dest dests
block_assig adjusted_assig to_free
Just (_, dest_assig)
-> joinToTargets_again
platform block_live new_blocks block_id instr dest dests
adjusted_assig dest_assig
joinToTargets_first :: (FR freeRegs, Instruction instr)
=> Platform
-> BlockMap RegSet
-> [NatBasicBlock instr]
-> BlockId
-> instr
-> BlockId
-> [BlockId]
-> BlockAssignment freeRegs
-> RegMap Loc
-> [RealReg]
-> RegM freeRegs ([NatBasicBlock instr], instr)
joinToTargets_first platform block_live new_blocks block_id instr dest dests
block_assig src_assig
to_free
= do
freeregs <- getFreeRegsR
let freeregs' = foldr frReleaseReg freeregs to_free
setBlockAssigR (mapInsert dest (freeregs', src_assig) block_assig)
joinToTargets' platform block_live new_blocks block_id instr dests
joinToTargets_again :: (Instruction instr, FR freeRegs)
=> Platform
-> BlockMap RegSet
-> [NatBasicBlock instr]
-> BlockId
-> instr
-> BlockId
-> [BlockId]
-> UniqFM Loc
-> UniqFM Loc
-> RegM freeRegs ([NatBasicBlock instr], instr)
joinToTargets_again
platform block_live new_blocks block_id instr dest dests
src_assig dest_assig
| ufmToList dest_assig == ufmToList src_assig
= joinToTargets' platform block_live new_blocks block_id instr dests
| otherwise
= do
let graph = makeRegMovementGraph src_assig dest_assig
let sccs = stronglyConnCompFromEdgedVerticesR graph
delta <- getDeltaR
fixUpInstrs_ <- mapM (handleComponent platform delta instr) sccs
let fixUpInstrs = concat fixUpInstrs_
fixup_block_id <- getUniqueR
let block = BasicBlock (mkBlockId fixup_block_id)
$ fixUpInstrs ++ mkJumpInstr dest
case fixUpInstrs of
[] -> joinToTargets' platform block_live new_blocks block_id instr dests
_ -> let instr' = patchJumpInstr instr
(\bid -> if bid == dest
then mkBlockId fixup_block_id
else bid)
in joinToTargets' platform block_live (block : new_blocks) block_id instr' dests
makeRegMovementGraph :: RegMap Loc -> RegMap Loc -> [(Unique, Loc, [Loc])]
makeRegMovementGraph adjusted_assig dest_assig
= let
mkNodes src vreg
= expandNode vreg src
$ lookupWithDefaultUFM_Directly
dest_assig
(panic "RegAllocLinear.makeRegMovementGraph")
vreg
in [ node | (vreg, src) <- ufmToList adjusted_assig
, node <- mkNodes src vreg ]
expandNode
:: a
-> Loc
-> Loc
-> [(a, Loc, [Loc])]
expandNode vreg loc@(InReg src) (InBoth dst mem)
| src == dst = [(vreg, loc, [InMem mem])]
| otherwise = [(vreg, loc, [InReg dst, InMem mem])]
expandNode vreg loc@(InMem src) (InBoth dst mem)
| src == mem = [(vreg, loc, [InReg dst])]
| otherwise = [(vreg, loc, [InReg dst, InMem mem])]
expandNode _ (InBoth _ src) (InMem dst)
| src == dst = []
expandNode _ (InBoth src _) (InReg dst)
| src == dst = []
expandNode vreg (InBoth src _) dst
= expandNode vreg (InReg src) dst
expandNode vreg src dst
| src == dst = []
| otherwise = [(vreg, src, [dst])]
handleComponent
:: Instruction instr
=> Platform -> Int -> instr -> SCC (Unique, Loc, [Loc]) -> RegM freeRegs [instr]
handleComponent platform delta _ (AcyclicSCC (vreg, src, dsts))
= mapM (makeMove platform delta vreg src) dsts
handleComponent platform delta instr
(CyclicSCC ( (vreg, InReg sreg, (InReg dreg: _)) : rest))
= do
(instrSpill, slot)
<- spillR platform (RegReal sreg) vreg
instrLoad <- loadR platform (RegReal dreg) slot
remainingFixUps <- mapM (handleComponent platform delta instr)
(stronglyConnCompFromEdgedVerticesR rest)
return ([instrSpill] ++ concat remainingFixUps ++ [instrLoad])
handleComponent _ _ _ (CyclicSCC _)
= panic "Register Allocator: handleComponent cyclic"
makeMove
:: Instruction instr
=> Platform
-> Int
-> Unique
-> Loc
-> Loc
-> RegM freeRegs instr
makeMove platform _ vreg (InReg src) (InReg dst)
= do recordSpill (SpillJoinRR vreg)
return $ mkRegRegMoveInstr platform (RegReal src) (RegReal dst)
makeMove platform delta vreg (InMem src) (InReg dst)
= do recordSpill (SpillJoinRM vreg)
return $ mkLoadInstr platform (RegReal dst) delta src
makeMove platform delta vreg (InReg src) (InMem dst)
= do recordSpill (SpillJoinRM vreg)
return $ mkSpillInstr platform (RegReal src) delta dst
makeMove _ _ vreg src dst
= panic $ "makeMove " ++ show vreg ++ " (" ++ show src ++ ") ("
++ show dst ++ ")"
++ " we don't handle mem->mem moves."