PageRenderTime 30ms CodeModel.GetById 0ms RepoModel.GetById 0ms app.codeStats 0ms

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

https://bitbucket.org/carter/ghc
Haskell | 285 lines | 147 code | 56 blank | 82 comment | 2 complexity | 4fdce07e5c43d9e3ac47a4b4045e9ce9 MD5 | raw file
  1. {-# OPTIONS -fno-warn-tabs #-}
  2. -- The above warning supression flag is a temporary kludge.
  3. -- While working on this module you are encouraged to remove it and
  4. -- detab the module (please do the detabbing in a separate patch). See
  5. -- http://hackage.haskell.org/trac/ghc/wiki/Commentary/CodingStyle#TabsvsSpaces
  6. -- for details
  7. module RegAlloc.Graph.SpillCost (
  8. SpillCostRecord,
  9. plusSpillCostRecord,
  10. pprSpillCostRecord,
  11. SpillCostInfo,
  12. zeroSpillCostInfo,
  13. plusSpillCostInfo,
  14. slurpSpillCostInfo,
  15. chooseSpill,
  16. lifeMapFromSpillCostInfo
  17. )
  18. where
  19. import RegAlloc.Liveness
  20. import Instruction
  21. import RegClass
  22. import Reg
  23. import GraphBase
  24. import BlockId
  25. import OldCmm
  26. import UniqFM
  27. import UniqSet
  28. import Digraph (flattenSCCs)
  29. import Outputable
  30. import Platform
  31. import State
  32. import Data.List (nub, minimumBy)
  33. import Data.Maybe
  34. type SpillCostRecord
  35. = ( VirtualReg -- register name
  36. , Int -- number of writes to this reg
  37. , Int -- number of reads from this reg
  38. , Int) -- number of instrs this reg was live on entry to
  39. type SpillCostInfo
  40. = UniqFM SpillCostRecord
  41. zeroSpillCostInfo :: SpillCostInfo
  42. zeroSpillCostInfo = emptyUFM
  43. -- | Add two spillCostInfos
  44. plusSpillCostInfo :: SpillCostInfo -> SpillCostInfo -> SpillCostInfo
  45. plusSpillCostInfo sc1 sc2
  46. = plusUFM_C plusSpillCostRecord sc1 sc2
  47. plusSpillCostRecord :: SpillCostRecord -> SpillCostRecord -> SpillCostRecord
  48. plusSpillCostRecord (r1, a1, b1, c1) (r2, a2, b2, c2)
  49. | r1 == r2 = (r1, a1 + a2, b1 + b2, c1 + c2)
  50. | otherwise = error "RegSpillCost.plusRegInt: regs don't match"
  51. -- | Slurp out information used for determining spill costs
  52. -- for each vreg, the number of times it was written to, read from,
  53. -- and the number of instructions it was live on entry to (lifetime)
  54. --
  55. slurpSpillCostInfo :: (Outputable instr, Instruction instr)
  56. => Platform
  57. -> LiveCmmDecl statics instr
  58. -> SpillCostInfo
  59. slurpSpillCostInfo platform cmm
  60. = execState (countCmm cmm) zeroSpillCostInfo
  61. where
  62. countCmm CmmData{} = return ()
  63. countCmm (CmmProc info _ sccs)
  64. = mapM_ (countBlock info)
  65. $ flattenSCCs sccs
  66. -- lookup the regs that are live on entry to this block in
  67. -- the info table from the CmmProc
  68. countBlock info (BasicBlock blockId instrs)
  69. | LiveInfo _ _ (Just blockLive) _ <- info
  70. , Just rsLiveEntry <- mapLookup blockId blockLive
  71. , rsLiveEntry_virt <- takeVirtuals rsLiveEntry
  72. = countLIs rsLiveEntry_virt instrs
  73. | otherwise
  74. = error "RegAlloc.SpillCost.slurpSpillCostInfo: bad block"
  75. countLIs _ []
  76. = return ()
  77. -- skip over comment and delta pseudo instrs
  78. countLIs rsLive (LiveInstr instr Nothing : lis)
  79. | isMetaInstr instr
  80. = countLIs rsLive lis
  81. | otherwise
  82. = pprPanic "RegSpillCost.slurpSpillCostInfo"
  83. (text "no liveness information on instruction " <> ppr instr)
  84. countLIs rsLiveEntry (LiveInstr instr (Just live) : lis)
  85. = do
  86. -- increment the lifetime counts for regs live on entry to this instr
  87. mapM_ incLifetime $ uniqSetToList rsLiveEntry
  88. -- increment counts for what regs were read/written from
  89. let (RU read written) = regUsageOfInstr platform instr
  90. mapM_ incUses $ catMaybes $ map takeVirtualReg $ nub read
  91. mapM_ incDefs $ catMaybes $ map takeVirtualReg $ nub written
  92. -- compute liveness for entry to next instruction.
  93. let liveDieRead_virt = takeVirtuals (liveDieRead live)
  94. let liveDieWrite_virt = takeVirtuals (liveDieWrite live)
  95. let liveBorn_virt = takeVirtuals (liveBorn live)
  96. let rsLiveAcross
  97. = rsLiveEntry `minusUniqSet` liveDieRead_virt
  98. let rsLiveNext
  99. = (rsLiveAcross `unionUniqSets` liveBorn_virt)
  100. `minusUniqSet` liveDieWrite_virt
  101. countLIs rsLiveNext lis
  102. incDefs reg = modify $ \s -> addToUFM_C plusSpillCostRecord s reg (reg, 1, 0, 0)
  103. incUses reg = modify $ \s -> addToUFM_C plusSpillCostRecord s reg (reg, 0, 1, 0)
  104. incLifetime reg = modify $ \s -> addToUFM_C plusSpillCostRecord s reg (reg, 0, 0, 1)
  105. takeVirtuals :: UniqSet Reg -> UniqSet VirtualReg
  106. takeVirtuals set = mapUniqSet get_virtual
  107. $ filterUniqSet isVirtualReg set
  108. where
  109. get_virtual (RegVirtual vr) = vr
  110. get_virtual _ = panic "getVirt"
  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. $ eltsUFM $ graphMap graph
  120. in nodeId node
  121. -- | Chaitins spill cost function is:
  122. --
  123. -- cost = sum loadCost * freq (u) + sum storeCost * freq (d)
  124. -- u <- uses (v) d <- defs (v)
  125. --
  126. -- There are no loops in our code at the momemnt, so we can set the freq's to 1
  127. -- We divide this by the degree if t
  128. --
  129. --
  130. -- If we don't have live range splitting then Chaitins function performs badly if we have
  131. -- 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. --
  144. -- defs uses degree cost
  145. -- v1: 1 3 3 1.5
  146. -- v2: 1 2 3 1.0
  147. -- v3: 1 1 3 0.666
  148. --
  149. -- v3 has the lowest cost, but if we only have 2 hardregs and we insert spill code for v3
  150. -- then this isn't going to improve the colorability of the graph.
  151. --
  152. -- When compiling SHA1, which as very long basic blocks and some vregs with very long live ranges
  153. -- the allocator seems to try and spill from the inside out and eventually run out of stack slots.
  154. --
  155. -- Without live range splitting, its's better to spill from the outside in so set the cost of very
  156. -- long live ranges to zero
  157. --
  158. {-
  159. spillCost_chaitin
  160. :: SpillCostInfo
  161. -> Graph Reg RegClass Reg
  162. -> Reg
  163. -> Float
  164. spillCost_chaitin info graph reg
  165. -- Spilling a live range that only lives for 1 instruction isn't going to help
  166. -- us at all - and we definately want to avoid trying to re-spill previously
  167. -- inserted spill code.
  168. | lifetime <= 1 = 1/0
  169. -- It's unlikely that we'll find a reg for a live range this long
  170. -- better to spill it straight up and not risk trying to keep it around
  171. -- and have to go through the build/color cycle again.
  172. | lifetime > allocatableRegsInClass (regClass reg) * 10
  173. = 0
  174. -- otherwise revert to chaitin's regular cost function.
  175. | otherwise = fromIntegral (uses + defs) / fromIntegral (nodeDegree graph reg)
  176. where (_, defs, uses, lifetime)
  177. = fromMaybe (reg, 0, 0, 0) $ lookupUFM info reg
  178. -}
  179. -- Just spill the longest live range.
  180. spillCost_length
  181. :: SpillCostInfo
  182. -> Graph VirtualReg RegClass RealReg
  183. -> VirtualReg
  184. -> Float
  185. spillCost_length info _ reg
  186. | lifetime <= 1 = 1/0
  187. | otherwise = 1 / fromIntegral lifetime
  188. where (_, _, _, lifetime)
  189. = fromMaybe (reg, 0, 0, 0)
  190. $ lookupUFM info reg
  191. lifeMapFromSpillCostInfo :: SpillCostInfo -> UniqFM (VirtualReg, Int)
  192. lifeMapFromSpillCostInfo info
  193. = listToUFM
  194. $ map (\(r, _, _, life) -> (r, (r, life)))
  195. $ eltsUFM info
  196. -- | Work out the degree (number of neighbors) of this node which have the same class.
  197. nodeDegree
  198. :: (VirtualReg -> RegClass)
  199. -> Graph VirtualReg RegClass RealReg
  200. -> VirtualReg
  201. -> Int
  202. nodeDegree classOfVirtualReg graph reg
  203. | Just node <- lookupUFM (graphMap graph) reg
  204. , virtConflicts <- length
  205. $ filter (\r -> classOfVirtualReg r == classOfVirtualReg reg)
  206. $ uniqSetToList
  207. $ nodeConflicts node
  208. = virtConflicts + sizeUniqSet (nodeExclusions node)
  209. | otherwise
  210. = 0
  211. -- | Show a spill cost record, including the degree from the graph and final calulated spill cos
  212. pprSpillCostRecord
  213. :: (VirtualReg -> RegClass)
  214. -> (Reg -> SDoc)
  215. -> Graph VirtualReg RegClass RealReg
  216. -> SpillCostRecord
  217. -> SDoc
  218. pprSpillCostRecord regClass pprReg graph (reg, uses, defs, life)
  219. = hsep
  220. [ pprReg (RegVirtual reg)
  221. , ppr uses
  222. , ppr defs
  223. , ppr life
  224. , ppr $ nodeDegree regClass graph reg
  225. , text $ show $ (fromIntegral (uses + defs)
  226. / fromIntegral (nodeDegree regClass graph reg) :: Float) ]