PageRenderTime 45ms CodeModel.GetById 20ms RepoModel.GetById 1ms app.codeStats 0ms

/compiler/nativeGen/RegAlloc/Graph/Spill.hs

http://github.com/ghc/ghc
Haskell | 378 lines | 227 code | 81 blank | 70 comment | 4 complexity | cc23035153f291ec307f5085bdcad480 MD5 | raw file
Possible License(s): MIT, BSD-3-Clause, GPL-3.0
  1. -- | When there aren't enough registers to hold all the vregs we have to spill
  2. -- some of those vregs to slots on the stack. This module is used modify the
  3. -- code to use those slots.
  4. module RegAlloc.Graph.Spill (
  5. regSpill,
  6. SpillStats(..),
  7. accSpillSL
  8. ) where
  9. import RegAlloc.Liveness
  10. import Instruction
  11. import Reg
  12. import Cmm hiding (RegSet)
  13. import BlockId
  14. import MonadUtils
  15. import State
  16. import Unique
  17. import UniqFM
  18. import UniqSet
  19. import UniqSupply
  20. import Outputable
  21. import Platform
  22. import Data.List
  23. import Data.Maybe
  24. import Data.IntSet (IntSet)
  25. import qualified Data.IntSet as IntSet
  26. -- | Spill all these virtual regs to stack slots.
  27. --
  28. -- TODO: See if we can split some of the live ranges instead of just globally
  29. -- spilling the virtual reg. This might make the spill cleaner's job easier.
  30. --
  31. -- TODO: On CISCy x86 and x86_64 we don't nessesarally have to add a mov instruction
  32. -- when making spills. If an instr is using a spilled virtual we may be able to
  33. -- address the spill slot directly.
  34. --
  35. regSpill
  36. :: Instruction instr
  37. => Platform
  38. -> [LiveCmmDecl statics instr] -- ^ the code
  39. -> UniqSet Int -- ^ available stack slots
  40. -> UniqSet VirtualReg -- ^ the regs to spill
  41. -> UniqSM
  42. ([LiveCmmDecl statics instr]
  43. -- code with SPILL and RELOAD meta instructions added.
  44. , UniqSet Int -- left over slots
  45. , SpillStats ) -- stats about what happened during spilling
  46. regSpill platform code slotsFree regs
  47. -- Not enough slots to spill these regs.
  48. | sizeUniqSet slotsFree < sizeUniqSet regs
  49. = pprPanic "regSpill: out of spill slots!"
  50. ( text " regs to spill = " <> ppr (sizeUniqSet regs)
  51. $$ text " slots left = " <> ppr (sizeUniqSet slotsFree))
  52. | otherwise
  53. = do
  54. -- Allocate a slot for each of the spilled regs.
  55. let slots = take (sizeUniqSet regs) $ nonDetEltsUFM slotsFree
  56. let regSlotMap = listToUFM
  57. $ zip (nonDetEltsUFM regs) slots
  58. -- This is non-deterministic but we do not
  59. -- currently support deterministic code-generation.
  60. -- See Note [Unique Determinism and code generation]
  61. -- Grab the unique supply from the monad.
  62. us <- getUniqueSupplyM
  63. -- Run the spiller on all the blocks.
  64. let (code', state') =
  65. runState (mapM (regSpill_top platform regSlotMap) code)
  66. (initSpillS us)
  67. return ( code'
  68. , minusUniqSet slotsFree (mkUniqSet slots)
  69. , makeSpillStats state')
  70. -- | Spill some registers to stack slots in a top-level thing.
  71. regSpill_top
  72. :: Instruction instr
  73. => Platform
  74. -> RegMap Int
  75. -- ^ map of vregs to slots they're being spilled to.
  76. -> LiveCmmDecl statics instr
  77. -- ^ the top level thing.
  78. -> SpillM (LiveCmmDecl statics instr)
  79. regSpill_top platform regSlotMap cmm
  80. = case cmm of
  81. CmmData{}
  82. -> return cmm
  83. CmmProc info label live sccs
  84. | LiveInfo static firstId mLiveVRegsOnEntry liveSlotsOnEntry <- info
  85. -> do
  86. -- We should only passed Cmms with the liveness maps filled in,
  87. -- but we'll create empty ones if they're not there just in case.
  88. let liveVRegsOnEntry = fromMaybe mapEmpty mLiveVRegsOnEntry
  89. -- The liveVRegsOnEntry contains the set of vregs that are live
  90. -- on entry to each basic block. If we spill one of those vregs
  91. -- we remove it from that set and add the corresponding slot
  92. -- number to the liveSlotsOnEntry set. The spill cleaner needs
  93. -- this information to erase unneeded spill and reload instructions
  94. -- after we've done a successful allocation.
  95. let liveSlotsOnEntry' :: BlockMap IntSet
  96. liveSlotsOnEntry'
  97. = mapFoldWithKey patchLiveSlot
  98. liveSlotsOnEntry liveVRegsOnEntry
  99. let info'
  100. = LiveInfo static firstId
  101. (Just liveVRegsOnEntry)
  102. liveSlotsOnEntry'
  103. -- Apply the spiller to all the basic blocks in the CmmProc.
  104. sccs' <- mapM (mapSCCM (regSpill_block platform regSlotMap)) sccs
  105. return $ CmmProc info' label live sccs'
  106. where -- Given a BlockId and the set of registers live in it,
  107. -- if registers in this block are being spilled to stack slots,
  108. -- then record the fact that these slots are now live in those blocks
  109. -- in the given slotmap.
  110. patchLiveSlot
  111. :: BlockId -> RegSet
  112. -> BlockMap IntSet -> BlockMap IntSet
  113. patchLiveSlot blockId regsLive slotMap
  114. = let
  115. -- Slots that are already recorded as being live.
  116. curSlotsLive = fromMaybe IntSet.empty
  117. $ lookupBlockMap blockId slotMap
  118. moreSlotsLive = IntSet.fromList
  119. $ catMaybes
  120. $ map (lookupUFM regSlotMap)
  121. $ nonDetEltsUFM regsLive
  122. -- See Note [Unique Determinism and code generation]
  123. slotMap'
  124. = insertBlockMap blockId (IntSet.union curSlotsLive moreSlotsLive)
  125. slotMap
  126. in slotMap'
  127. -- | Spill some registers to stack slots in a basic block.
  128. regSpill_block
  129. :: Instruction instr
  130. => Platform
  131. -> UniqFM Int -- ^ map of vregs to slots they're being spilled to.
  132. -> LiveBasicBlock instr
  133. -> SpillM (LiveBasicBlock instr)
  134. regSpill_block platform regSlotMap (BasicBlock i instrs)
  135. = do instrss' <- mapM (regSpill_instr platform regSlotMap) instrs
  136. return $ BasicBlock i (concat instrss')
  137. -- | Spill some registers to stack slots in a single instruction.
  138. -- If the instruction uses registers that need to be spilled, then it is
  139. -- prefixed (or postfixed) with the appropriate RELOAD or SPILL meta
  140. -- instructions.
  141. regSpill_instr
  142. :: Instruction instr
  143. => Platform
  144. -> UniqFM Int -- ^ map of vregs to slots they're being spilled to.
  145. -> LiveInstr instr
  146. -> SpillM [LiveInstr instr]
  147. regSpill_instr _ _ li@(LiveInstr _ Nothing)
  148. = do return [li]
  149. regSpill_instr platform regSlotMap
  150. (LiveInstr instr (Just _))
  151. = do
  152. -- work out which regs are read and written in this instr
  153. let RU rlRead rlWritten = regUsageOfInstr platform instr
  154. -- sometimes a register is listed as being read more than once,
  155. -- nub this so we don't end up inserting two lots of spill code.
  156. let rsRead_ = nub rlRead
  157. let rsWritten_ = nub rlWritten
  158. -- if a reg is modified, it appears in both lists, want to undo this..
  159. let rsRead = rsRead_ \\ rsWritten_
  160. let rsWritten = rsWritten_ \\ rsRead_
  161. let rsModify = intersect rsRead_ rsWritten_
  162. -- work out if any of the regs being used are currently being spilled.
  163. let rsSpillRead = filter (\r -> elemUFM r regSlotMap) rsRead
  164. let rsSpillWritten = filter (\r -> elemUFM r regSlotMap) rsWritten
  165. let rsSpillModify = filter (\r -> elemUFM r regSlotMap) rsModify
  166. -- rewrite the instr and work out spill code.
  167. (instr1, prepost1) <- mapAccumLM (spillRead regSlotMap) instr rsSpillRead
  168. (instr2, prepost2) <- mapAccumLM (spillWrite regSlotMap) instr1 rsSpillWritten
  169. (instr3, prepost3) <- mapAccumLM (spillModify regSlotMap) instr2 rsSpillModify
  170. let (mPrefixes, mPostfixes) = unzip (prepost1 ++ prepost2 ++ prepost3)
  171. let prefixes = concat mPrefixes
  172. let postfixes = concat mPostfixes
  173. -- final code
  174. let instrs' = prefixes
  175. ++ [LiveInstr instr3 Nothing]
  176. ++ postfixes
  177. return $ instrs'
  178. -- | Add a RELOAD met a instruction to load a value for an instruction that
  179. -- writes to a vreg that is being spilled.
  180. spillRead
  181. :: Instruction instr
  182. => UniqFM Int
  183. -> instr
  184. -> Reg
  185. -> SpillM (instr, ([LiveInstr instr'], [LiveInstr instr']))
  186. spillRead regSlotMap instr reg
  187. | Just slot <- lookupUFM regSlotMap reg
  188. = do (instr', nReg) <- patchInstr reg instr
  189. modify $ \s -> s
  190. { stateSpillSL = addToUFM_C accSpillSL (stateSpillSL s) reg (reg, 0, 1) }
  191. return ( instr'
  192. , ( [LiveInstr (RELOAD slot nReg) Nothing]
  193. , []) )
  194. | otherwise = panic "RegSpill.spillRead: no slot defined for spilled reg"
  195. -- | Add a SPILL meta instruction to store a value for an instruction that
  196. -- writes to a vreg that is being spilled.
  197. spillWrite
  198. :: Instruction instr
  199. => UniqFM Int
  200. -> instr
  201. -> Reg
  202. -> SpillM (instr, ([LiveInstr instr'], [LiveInstr instr']))
  203. spillWrite regSlotMap instr reg
  204. | Just slot <- lookupUFM regSlotMap reg
  205. = do (instr', nReg) <- patchInstr reg instr
  206. modify $ \s -> s
  207. { stateSpillSL = addToUFM_C accSpillSL (stateSpillSL s) reg (reg, 1, 0) }
  208. return ( instr'
  209. , ( []
  210. , [LiveInstr (SPILL nReg slot) Nothing]))
  211. | otherwise = panic "RegSpill.spillWrite: no slot defined for spilled reg"
  212. -- | Add both RELOAD and SPILL meta instructions for an instruction that
  213. -- both reads and writes to a vreg that is being spilled.
  214. spillModify
  215. :: Instruction instr
  216. => UniqFM Int
  217. -> instr
  218. -> Reg
  219. -> SpillM (instr, ([LiveInstr instr'], [LiveInstr instr']))
  220. spillModify regSlotMap instr reg
  221. | Just slot <- lookupUFM regSlotMap reg
  222. = do (instr', nReg) <- patchInstr reg instr
  223. modify $ \s -> s
  224. { stateSpillSL = addToUFM_C accSpillSL (stateSpillSL s) reg (reg, 1, 1) }
  225. return ( instr'
  226. , ( [LiveInstr (RELOAD slot nReg) Nothing]
  227. , [LiveInstr (SPILL nReg slot) Nothing]))
  228. | otherwise = panic "RegSpill.spillModify: no slot defined for spilled reg"
  229. -- | Rewrite uses of this virtual reg in an instr to use a different
  230. -- virtual reg.
  231. patchInstr
  232. :: Instruction instr
  233. => Reg -> instr -> SpillM (instr, Reg)
  234. patchInstr reg instr
  235. = do nUnique <- newUnique
  236. -- The register we're rewriting is suppoed to be virtual.
  237. -- If it's not then something has gone horribly wrong.
  238. let nReg
  239. = case reg of
  240. RegVirtual vr
  241. -> RegVirtual (renameVirtualReg nUnique vr)
  242. RegReal{}
  243. -> panic "RegAlloc.Graph.Spill.patchIntr: not patching real reg"
  244. let instr' = patchReg1 reg nReg instr
  245. return (instr', nReg)
  246. patchReg1
  247. :: Instruction instr
  248. => Reg -> Reg -> instr -> instr
  249. patchReg1 old new instr
  250. = let patchF r
  251. | r == old = new
  252. | otherwise = r
  253. in patchRegsOfInstr instr patchF
  254. -- Spiller monad --------------------------------------------------------------
  255. -- | State monad for the spill code generator.
  256. type SpillM a
  257. = State SpillS a
  258. -- | Spill code generator state.
  259. data SpillS
  260. = SpillS
  261. { -- | Unique supply for generating fresh vregs.
  262. stateUS :: UniqSupply
  263. -- | Spilled vreg vs the number of times it was loaded, stored.
  264. , stateSpillSL :: UniqFM (Reg, Int, Int) }
  265. -- | Create a new spiller state.
  266. initSpillS :: UniqSupply -> SpillS
  267. initSpillS uniqueSupply
  268. = SpillS
  269. { stateUS = uniqueSupply
  270. , stateSpillSL = emptyUFM }
  271. -- | Allocate a new unique in the spiller monad.
  272. newUnique :: SpillM Unique
  273. newUnique
  274. = do us <- gets stateUS
  275. case takeUniqFromSupply us of
  276. (uniq, us')
  277. -> do modify $ \s -> s { stateUS = us' }
  278. return uniq
  279. -- | Add a spill/reload count to a stats record for a register.
  280. accSpillSL :: (Reg, Int, Int) -> (Reg, Int, Int) -> (Reg, Int, Int)
  281. accSpillSL (r1, s1, l1) (_, s2, l2)
  282. = (r1, s1 + s2, l1 + l2)
  283. -- Spiller stats --------------------------------------------------------------
  284. -- | Spiller statistics.
  285. -- Tells us what registers were spilled.
  286. data SpillStats
  287. = SpillStats
  288. { spillStoreLoad :: UniqFM (Reg, Int, Int) }
  289. -- | Extract spiller statistics from the spiller state.
  290. makeSpillStats :: SpillS -> SpillStats
  291. makeSpillStats s
  292. = SpillStats
  293. { spillStoreLoad = stateSpillSL s }
  294. instance Outputable SpillStats where
  295. ppr stats
  296. = pprUFM (spillStoreLoad stats)
  297. (vcat . map (\(r, s, l) -> ppr r <+> int s <+> int l))