module RegAlloc.Graph.Spill (
regSpill,
SpillStats(..),
accSpillSL
) where
import GhcPrelude
import RegAlloc.Liveness
import Instruction
import Reg
import Cmm hiding (RegSet)
import BlockId
import Hoopl.Collections
import MonadUtils
import State
import Unique
import UniqFM
import UniqSet
import UniqSupply
import Outputable
import Platform
import Data.List
import Data.Maybe
import Data.IntSet (IntSet)
import qualified Data.IntSet as IntSet
regSpill
:: Instruction instr
=> Platform
-> [LiveCmmDecl statics instr]
-> UniqSet Int
-> UniqSet VirtualReg
-> UniqSM
([LiveCmmDecl statics instr]
, UniqSet Int
, SpillStats )
regSpill platform code slotsFree regs
| sizeUniqSet slotsFree < sizeUniqSet regs
= pprPanic "regSpill: out of spill slots!"
( text " regs to spill = " <> ppr (sizeUniqSet regs)
$$ text " slots left = " <> ppr (sizeUniqSet slotsFree))
| otherwise
= do
let slots = take (sizeUniqSet regs) $ nonDetEltsUniqSet slotsFree
let regSlotMap = listToUFM
$ zip (nonDetEltsUniqSet regs) slots
us <- getUniqueSupplyM
let (code', state') =
runState (mapM (regSpill_top platform regSlotMap) code)
(initSpillS us)
return ( code'
, minusUniqSet slotsFree (mkUniqSet slots)
, makeSpillStats state')
regSpill_top
:: Instruction instr
=> Platform
-> RegMap Int
-> LiveCmmDecl statics instr
-> SpillM (LiveCmmDecl statics instr)
regSpill_top platform regSlotMap cmm
= case cmm of
CmmData{}
-> return cmm
CmmProc info label live sccs
| LiveInfo static firstId mLiveVRegsOnEntry liveSlotsOnEntry <- info
-> do
let liveVRegsOnEntry = fromMaybe mapEmpty mLiveVRegsOnEntry
let liveSlotsOnEntry' :: BlockMap IntSet
liveSlotsOnEntry'
= mapFoldlWithKey patchLiveSlot
liveSlotsOnEntry liveVRegsOnEntry
let info'
= LiveInfo static firstId
(Just liveVRegsOnEntry)
liveSlotsOnEntry'
sccs' <- mapM (mapSCCM (regSpill_block platform regSlotMap)) sccs
return $ CmmProc info' label live sccs'
where
patchLiveSlot
:: BlockMap IntSet -> BlockId -> RegSet -> BlockMap IntSet
patchLiveSlot slotMap blockId regsLive
= let
curSlotsLive = fromMaybe IntSet.empty
$ mapLookup blockId slotMap
moreSlotsLive = IntSet.fromList
$ catMaybes
$ map (lookupUFM regSlotMap)
$ nonDetEltsUniqSet regsLive
slotMap'
= mapInsert blockId (IntSet.union curSlotsLive moreSlotsLive)
slotMap
in slotMap'
regSpill_block
:: Instruction instr
=> Platform
-> UniqFM Int
-> LiveBasicBlock instr
-> SpillM (LiveBasicBlock instr)
regSpill_block platform regSlotMap (BasicBlock i instrs)
= do instrss' <- mapM (regSpill_instr platform regSlotMap) instrs
return $ BasicBlock i (concat instrss')
regSpill_instr
:: Instruction instr
=> Platform
-> UniqFM Int
-> LiveInstr instr
-> SpillM [LiveInstr instr]
regSpill_instr _ _ li@(LiveInstr _ Nothing)
= do return [li]
regSpill_instr platform regSlotMap
(LiveInstr instr (Just _))
= do
let RU rlRead rlWritten = regUsageOfInstr platform instr
let rsRead_ = nub rlRead
let rsWritten_ = nub rlWritten
let rsRead = rsRead_ \\ rsWritten_
let rsWritten = rsWritten_ \\ rsRead_
let rsModify = intersect rsRead_ rsWritten_
let rsSpillRead = filter (\r -> elemUFM r regSlotMap) rsRead
let rsSpillWritten = filter (\r -> elemUFM r regSlotMap) rsWritten
let rsSpillModify = filter (\r -> elemUFM r regSlotMap) rsModify
(instr1, prepost1) <- mapAccumLM (spillRead regSlotMap) instr rsSpillRead
(instr2, prepost2) <- mapAccumLM (spillWrite regSlotMap) instr1 rsSpillWritten
(instr3, prepost3) <- mapAccumLM (spillModify regSlotMap) instr2 rsSpillModify
let (mPrefixes, mPostfixes) = unzip (prepost1 ++ prepost2 ++ prepost3)
let prefixes = concat mPrefixes
let postfixes = concat mPostfixes
let instrs' = prefixes
++ [LiveInstr instr3 Nothing]
++ postfixes
return $ instrs'
spillRead
:: Instruction instr
=> UniqFM Int
-> instr
-> Reg
-> SpillM (instr, ([LiveInstr instr'], [LiveInstr instr']))
spillRead regSlotMap instr reg
| Just slot <- lookupUFM regSlotMap reg
= do (instr', nReg) <- patchInstr reg instr
modify $ \s -> s
{ stateSpillSL = addToUFM_C accSpillSL (stateSpillSL s) reg (reg, 0, 1) }
return ( instr'
, ( [LiveInstr (RELOAD slot nReg) Nothing]
, []) )
| otherwise = panic "RegSpill.spillRead: no slot defined for spilled reg"
spillWrite
:: Instruction instr
=> UniqFM Int
-> instr
-> Reg
-> SpillM (instr, ([LiveInstr instr'], [LiveInstr instr']))
spillWrite regSlotMap instr reg
| Just slot <- lookupUFM regSlotMap reg
= do (instr', nReg) <- patchInstr reg instr
modify $ \s -> s
{ stateSpillSL = addToUFM_C accSpillSL (stateSpillSL s) reg (reg, 1, 0) }
return ( instr'
, ( []
, [LiveInstr (SPILL nReg slot) Nothing]))
| otherwise = panic "RegSpill.spillWrite: no slot defined for spilled reg"
spillModify
:: Instruction instr
=> UniqFM Int
-> instr
-> Reg
-> SpillM (instr, ([LiveInstr instr'], [LiveInstr instr']))
spillModify regSlotMap instr reg
| Just slot <- lookupUFM regSlotMap reg
= do (instr', nReg) <- patchInstr reg instr
modify $ \s -> s
{ stateSpillSL = addToUFM_C accSpillSL (stateSpillSL s) reg (reg, 1, 1) }
return ( instr'
, ( [LiveInstr (RELOAD slot nReg) Nothing]
, [LiveInstr (SPILL nReg slot) Nothing]))
| otherwise = panic "RegSpill.spillModify: no slot defined for spilled reg"
patchInstr
:: Instruction instr
=> Reg -> instr -> SpillM (instr, Reg)
patchInstr reg instr
= do nUnique <- newUnique
let nReg
= case reg of
RegVirtual vr
-> RegVirtual (renameVirtualReg nUnique vr)
RegReal{}
-> panic "RegAlloc.Graph.Spill.patchIntr: not patching real reg"
let instr' = patchReg1 reg nReg instr
return (instr', nReg)
patchReg1
:: Instruction instr
=> Reg -> Reg -> instr -> instr
patchReg1 old new instr
= let patchF r
| r == old = new
| otherwise = r
in patchRegsOfInstr instr patchF
type SpillM a
= State SpillS a
data SpillS
= SpillS
{
stateUS :: UniqSupply
, stateSpillSL :: UniqFM (Reg, Int, Int) }
initSpillS :: UniqSupply -> SpillS
initSpillS uniqueSupply
= SpillS
{ stateUS = uniqueSupply
, stateSpillSL = emptyUFM }
newUnique :: SpillM Unique
newUnique
= do us <- gets stateUS
case takeUniqFromSupply us of
(uniq, us')
-> do modify $ \s -> s { stateUS = us' }
return uniq
accSpillSL :: (Reg, Int, Int) -> (Reg, Int, Int) -> (Reg, Int, Int)
accSpillSL (r1, s1, l1) (_, s2, l2)
= (r1, s1 + s2, l1 + l2)
data SpillStats
= SpillStats
{ spillStoreLoad :: UniqFM (Reg, Int, Int) }
makeSpillStats :: SpillS -> SpillStats
makeSpillStats s
= SpillStats
{ spillStoreLoad = stateSpillSL s }
instance Outputable SpillStats where
ppr stats
= pprUFM (spillStoreLoad stats)
(vcat . map (\(r, s, l) -> ppr r <+> int s <+> int l))