PageRenderTime 44ms CodeModel.GetById 13ms RepoModel.GetById 1ms app.codeStats 0ms

/compiler/nativeGen/RegAlloc/Graph/SpillCost.hs

http://github.com/ghc/ghc
Haskell | 291 lines | 144 code | 54 blank | 93 comment | 2 complexity | c767d4cf589b8089145d8e7ddd903528 MD5 | raw file
Possible License(s): MIT, BSD-3-Clause, GPL-3.0
  1. module RegAlloc.Graph.SpillCost (
  2. SpillCostRecord,
  3. plusSpillCostRecord,
  4. pprSpillCostRecord,
  5. SpillCostInfo,
  6. zeroSpillCostInfo,
  7. plusSpillCostInfo,
  8. slurpSpillCostInfo,
  9. chooseSpill,
  10. lifeMapFromSpillCostInfo
  11. ) where
  12. import RegAlloc.Liveness
  13. import Instruction
  14. import RegClass
  15. import Reg
  16. import GraphBase
  17. import BlockId
  18. import Cmm
  19. import UniqFM
  20. import UniqSet
  21. import Digraph (flattenSCCs)
  22. import Outputable
  23. import Platform
  24. import State
  25. import Data.List (nub, minimumBy)
  26. import Data.Maybe
  27. -- | Records the expected cost to spill some regster.
  28. type SpillCostRecord
  29. = ( VirtualReg -- register name
  30. , Int -- number of writes to this reg
  31. , Int -- number of reads from this reg
  32. , Int) -- number of instrs this reg was live on entry to
  33. -- | Map of `SpillCostRecord`
  34. type SpillCostInfo
  35. = UniqFM SpillCostRecord
  36. -- | An empty map of spill costs.
  37. zeroSpillCostInfo :: SpillCostInfo
  38. zeroSpillCostInfo = emptyUFM
  39. -- | Add two spill cost infos.
  40. plusSpillCostInfo :: SpillCostInfo -> SpillCostInfo -> SpillCostInfo
  41. plusSpillCostInfo sc1 sc2
  42. = plusUFM_C plusSpillCostRecord sc1 sc2
  43. -- | Add two spill cost records.
  44. plusSpillCostRecord :: SpillCostRecord -> SpillCostRecord -> SpillCostRecord
  45. plusSpillCostRecord (r1, a1, b1, c1) (r2, a2, b2, c2)
  46. | r1 == r2 = (r1, a1 + a2, b1 + b2, c1 + c2)
  47. | otherwise = error "RegSpillCost.plusRegInt: regs don't match"
  48. -- | Slurp out information used for determining spill costs.
  49. --
  50. -- For each vreg, the number of times it was written to, read from,
  51. -- and the number of instructions it was live on entry to (lifetime)
  52. --
  53. slurpSpillCostInfo :: (Outputable instr, Instruction instr)
  54. => Platform
  55. -> LiveCmmDecl statics instr
  56. -> SpillCostInfo
  57. slurpSpillCostInfo platform cmm
  58. = execState (countCmm cmm) zeroSpillCostInfo
  59. where
  60. countCmm CmmData{} = return ()
  61. countCmm (CmmProc info _ _ sccs)
  62. = mapM_ (countBlock info)
  63. $ flattenSCCs sccs
  64. -- Lookup the regs that are live on entry to this block in
  65. -- the info table from the CmmProc.
  66. countBlock info (BasicBlock blockId instrs)
  67. | LiveInfo _ _ (Just blockLive) _ <- info
  68. , Just rsLiveEntry <- mapLookup blockId blockLive
  69. , rsLiveEntry_virt <- takeVirtuals rsLiveEntry
  70. = countLIs rsLiveEntry_virt instrs
  71. | otherwise
  72. = error "RegAlloc.SpillCost.slurpSpillCostInfo: bad block"
  73. countLIs _ []
  74. = return ()
  75. -- Skip over comment and delta pseudo instrs.
  76. countLIs rsLive (LiveInstr instr Nothing : lis)
  77. | isMetaInstr instr
  78. = countLIs rsLive lis
  79. | otherwise
  80. = pprPanic "RegSpillCost.slurpSpillCostInfo"
  81. $ text "no liveness information on instruction " <> ppr instr
  82. countLIs rsLiveEntry (LiveInstr instr (Just live) : lis)
  83. = do
  84. -- Increment the lifetime counts for regs live on entry to this instr.
  85. mapM_ incLifetime $ nonDetEltsUFM rsLiveEntry
  86. -- This is non-deterministic but we do not
  87. -- currently support deterministic code-generation.
  88. -- See Note [Unique Determinism and code generation]
  89. -- Increment counts for what regs were read/written from.
  90. let (RU read written) = regUsageOfInstr platform instr
  91. mapM_ incUses $ catMaybes $ map takeVirtualReg $ nub read
  92. mapM_ incDefs $ catMaybes $ map takeVirtualReg $ nub written
  93. -- Compute liveness for entry to next instruction.
  94. let liveDieRead_virt = takeVirtuals (liveDieRead live)
  95. let liveDieWrite_virt = takeVirtuals (liveDieWrite live)
  96. let liveBorn_virt = takeVirtuals (liveBorn live)
  97. let rsLiveAcross
  98. = rsLiveEntry `minusUniqSet` liveDieRead_virt
  99. let rsLiveNext
  100. = (rsLiveAcross `unionUniqSets` liveBorn_virt)
  101. `minusUniqSet` liveDieWrite_virt
  102. countLIs rsLiveNext lis
  103. incDefs reg = modify $ \s -> addToUFM_C plusSpillCostRecord s reg (reg, 1, 0, 0)
  104. incUses reg = modify $ \s -> addToUFM_C plusSpillCostRecord s reg (reg, 0, 1, 0)
  105. incLifetime reg = modify $ \s -> addToUFM_C plusSpillCostRecord s reg (reg, 0, 0, 1)
  106. -- | Take all the virtual registers from this set.
  107. takeVirtuals :: UniqSet Reg -> UniqSet VirtualReg
  108. takeVirtuals set = mkUniqSet
  109. [ vr | RegVirtual vr <- nonDetEltsUFM set ]
  110. -- See Note [Unique Determinism and code generation]
  111. -- | Choose a node to spill from this graph
  112. chooseSpill
  113. :: SpillCostInfo
  114. -> Graph VirtualReg RegClass RealReg
  115. -> VirtualReg
  116. chooseSpill info graph
  117. = let cost = spillCost_length info graph
  118. node = minimumBy (\n1 n2 -> compare (cost $ nodeId n1) (cost $ nodeId n2))
  119. $ nonDetEltsUFM $ graphMap graph
  120. -- See Note [Unique Determinism and code generation]
  121. in nodeId node
  122. -------------------------------------------------------------------------------
  123. -- | Chaitins spill cost function is:
  124. --
  125. -- cost = sum loadCost * freq (u) + sum storeCost * freq (d)
  126. -- u <- uses (v) d <- defs (v)
  127. --
  128. -- There are no loops in our code at the momemnt, so we can set the freq's to 1.
  129. --
  130. -- If we don't have live range splitting then Chaitins function performs badly
  131. -- if we have lots of nested live ranges and very few registers.
  132. --
  133. -- v1 v2 v3
  134. -- def v1 .
  135. -- use v1 .
  136. -- def v2 . .
  137. -- def v3 . . .
  138. -- use v1 . . .
  139. -- use v3 . . .
  140. -- use v2 . .
  141. -- use v1 .
  142. --
  143. -- defs uses degree cost
  144. -- v1: 1 3 3 1.5
  145. -- v2: 1 2 3 1.0
  146. -- v3: 1 1 3 0.666
  147. --
  148. -- v3 has the lowest cost, but if we only have 2 hardregs and we insert
  149. -- spill code for v3 then this isn't going to improve the colorability of
  150. -- the graph.
  151. --
  152. -- When compiling SHA1, which as very long basic blocks and some vregs
  153. -- with very long live ranges the allocator seems to try and spill from
  154. -- the inside out and eventually run out of stack slots.
  155. --
  156. -- Without live range splitting, its's better to spill from the outside
  157. -- in so set the cost of very long live ranges to zero
  158. --
  159. {-
  160. spillCost_chaitin
  161. :: SpillCostInfo
  162. -> Graph Reg RegClass Reg
  163. -> Reg
  164. -> Float
  165. spillCost_chaitin info graph reg
  166. -- Spilling a live range that only lives for 1 instruction
  167. -- isn't going to help us at all - and we definitely want to avoid
  168. -- trying to re-spill previously inserted spill code.
  169. | lifetime <= 1 = 1/0
  170. -- It's unlikely that we'll find a reg for a live range this long
  171. -- better to spill it straight up and not risk trying to keep it around
  172. -- and have to go through the build/color cycle again.
  173. | lifetime > allocatableRegsInClass (regClass reg) * 10
  174. = 0
  175. -- Otherwise revert to chaitin's regular cost function.
  176. | otherwise = fromIntegral (uses + defs)
  177. / fromIntegral (nodeDegree graph reg)
  178. where (_, defs, uses, lifetime)
  179. = fromMaybe (reg, 0, 0, 0) $ lookupUFM info reg
  180. -}
  181. -- Just spill the longest live range.
  182. spillCost_length
  183. :: SpillCostInfo
  184. -> Graph VirtualReg RegClass RealReg
  185. -> VirtualReg
  186. -> Float
  187. spillCost_length info _ reg
  188. | lifetime <= 1 = 1/0
  189. | otherwise = 1 / fromIntegral lifetime
  190. where (_, _, _, lifetime)
  191. = fromMaybe (reg, 0, 0, 0)
  192. $ lookupUFM info reg
  193. -- | Extract a map of register lifetimes from a `SpillCostInfo`.
  194. lifeMapFromSpillCostInfo :: SpillCostInfo -> UniqFM (VirtualReg, Int)
  195. lifeMapFromSpillCostInfo info
  196. = listToUFM
  197. $ map (\(r, _, _, life) -> (r, (r, life)))
  198. $ nonDetEltsUFM info
  199. -- See Note [Unique Determinism and code generation]
  200. -- | Determine the degree (number of neighbors) of this node which
  201. -- have the same class.
  202. nodeDegree
  203. :: (VirtualReg -> RegClass)
  204. -> Graph VirtualReg RegClass RealReg
  205. -> VirtualReg
  206. -> Int
  207. nodeDegree classOfVirtualReg graph reg
  208. | Just node <- lookupUFM (graphMap graph) reg
  209. , virtConflicts
  210. <- length
  211. $ filter (\r -> classOfVirtualReg r == classOfVirtualReg reg)
  212. $ nonDetEltsUFM
  213. -- See Note [Unique Determinism and code generation]
  214. $ nodeConflicts node
  215. = virtConflicts + sizeUniqSet (nodeExclusions node)
  216. | otherwise
  217. = 0
  218. -- | Show a spill cost record, including the degree from the graph
  219. -- and final calulated spill cost.
  220. pprSpillCostRecord
  221. :: (VirtualReg -> RegClass)
  222. -> (Reg -> SDoc)
  223. -> Graph VirtualReg RegClass RealReg
  224. -> SpillCostRecord
  225. -> SDoc
  226. pprSpillCostRecord regClass pprReg graph (reg, uses, defs, life)
  227. = hsep
  228. [ pprReg (RegVirtual reg)
  229. , ppr uses
  230. , ppr defs
  231. , ppr life
  232. , ppr $ nodeDegree regClass graph reg
  233. , text $ show $ (fromIntegral (uses + defs)
  234. / fromIntegral (nodeDegree regClass graph reg) :: Float) ]