PageRenderTime 48ms CodeModel.GetById 19ms RepoModel.GetById 0ms app.codeStats 0ms

/ghc-7.0.4/compiler/nativeGen/RegAlloc/Graph/Spill.hs

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