PageRenderTime 42ms CodeModel.GetById 11ms RepoModel.GetById 0ms app.codeStats 0ms

/compiler/nativeGen/RegAlloc/Graph/Main.hs

https://bitbucket.org/carter/ghc
Haskell | 420 lines | 273 code | 80 blank | 67 comment | 14 complexity | ecd6e0d6c9d68c138227f700a264f114 MD5 | raw file
  1. -- | Graph coloring register allocator.
  2. --
  3. -- TODO: The colors in graphviz graphs for x86_64 and ppc could be nicer.
  4. --
  5. module RegAlloc.Graph.Main (
  6. regAlloc
  7. )
  8. where
  9. import qualified GraphColor as Color
  10. import RegAlloc.Liveness
  11. import RegAlloc.Graph.Spill
  12. import RegAlloc.Graph.SpillClean
  13. import RegAlloc.Graph.SpillCost
  14. import RegAlloc.Graph.Stats
  15. import RegAlloc.Graph.TrivColorable
  16. import Instruction
  17. import TargetReg
  18. import RegClass
  19. import Reg
  20. import UniqSupply
  21. import UniqSet
  22. import UniqFM
  23. import Bag
  24. import Outputable
  25. import Platform
  26. import DynFlags
  27. import Data.List
  28. import Data.Maybe
  29. import Control.Monad
  30. -- | The maximum number of build\/spill cycles we'll allow.
  31. -- We should only need 3 or 4 cycles tops.
  32. -- If we run for any longer than this we're probably in an infinite loop,
  33. -- It's probably better just to bail out and report a bug at this stage.
  34. maxSpinCount :: Int
  35. maxSpinCount = 10
  36. -- | The top level of the graph coloring register allocator.
  37. regAlloc
  38. :: (Outputable statics, Outputable instr, Instruction instr)
  39. => DynFlags
  40. -> UniqFM (UniqSet RealReg) -- ^ the registers we can use for allocation
  41. -> UniqSet Int -- ^ the set of available spill slots.
  42. -> [LiveCmmDecl statics instr] -- ^ code annotated with liveness information.
  43. -> UniqSM ( [NatCmmDecl statics instr], [RegAllocStats statics instr] )
  44. -- ^ code with registers allocated and stats for each stage of
  45. -- allocation
  46. regAlloc dflags regsFree slotsFree code
  47. = do
  48. -- TODO: the regClass function is currently hard coded to the default target
  49. -- architecture. Would prefer to determine this from dflags.
  50. -- There are other uses of targetRegClass later in this module.
  51. let platform = targetPlatform dflags
  52. triv = trivColorable platform
  53. (targetVirtualRegSqueeze platform)
  54. (targetRealRegSqueeze platform)
  55. (code_final, debug_codeGraphs, _)
  56. <- regAlloc_spin dflags 0
  57. triv
  58. regsFree slotsFree [] code
  59. return ( code_final
  60. , reverse debug_codeGraphs )
  61. regAlloc_spin :: (Instruction instr,
  62. Outputable instr,
  63. Outputable statics)
  64. => DynFlags
  65. -> Int
  66. -> Color.Triv VirtualReg RegClass RealReg
  67. -> UniqFM (UniqSet RealReg)
  68. -> UniqSet Int
  69. -> [RegAllocStats statics instr]
  70. -> [LiveCmmDecl statics instr]
  71. -> UniqSM ([NatCmmDecl statics instr],
  72. [RegAllocStats statics instr],
  73. Color.Graph VirtualReg RegClass RealReg)
  74. regAlloc_spin dflags spinCount triv regsFree slotsFree debug_codeGraphs code
  75. = do
  76. let platform = targetPlatform dflags
  77. -- if any of these dump flags are turned on we want to hang on to
  78. -- intermediate structures in the allocator - otherwise tell the
  79. -- allocator to ditch them early so we don't end up creating space leaks.
  80. let dump = or
  81. [ dopt Opt_D_dump_asm_regalloc_stages dflags
  82. , dopt Opt_D_dump_asm_stats dflags
  83. , dopt Opt_D_dump_asm_conflicts dflags ]
  84. -- check that we're not running off down the garden path.
  85. when (spinCount > maxSpinCount)
  86. $ pprPanic "regAlloc_spin: max build/spill cycle count exceeded."
  87. ( text "It looks like the register allocator is stuck in an infinite loop."
  88. $$ text "max cycles = " <> int maxSpinCount
  89. $$ text "regsFree = " <> (hcat $ punctuate space $ map ppr
  90. $ uniqSetToList $ unionManyUniqSets $ eltsUFM regsFree)
  91. $$ text "slotsFree = " <> ppr (sizeUniqSet slotsFree))
  92. -- build a conflict graph from the code.
  93. (graph :: Color.Graph VirtualReg RegClass RealReg)
  94. <- {-# SCC "BuildGraph" #-} buildGraph code
  95. -- VERY IMPORTANT:
  96. -- We really do want the graph to be fully evaluated _before_ we start coloring.
  97. -- If we don't do this now then when the call to Color.colorGraph forces bits of it,
  98. -- the heap will be filled with half evaluated pieces of graph and zillions of apply thunks.
  99. --
  100. seqGraph graph `seq` return ()
  101. -- build a map of the cost of spilling each instruction
  102. -- this will only actually be computed if we have to spill something.
  103. let spillCosts = foldl' plusSpillCostInfo zeroSpillCostInfo
  104. $ map (slurpSpillCostInfo platform) code
  105. -- the function to choose regs to leave uncolored
  106. let spill = chooseSpill spillCosts
  107. -- record startup state
  108. let stat1 =
  109. if spinCount == 0
  110. then Just $ RegAllocStatsStart
  111. { raLiveCmm = code
  112. , raGraph = graph
  113. , raSpillCosts = spillCosts }
  114. else Nothing
  115. -- try and color the graph
  116. let (graph_colored, rsSpill, rmCoalesce)
  117. = {-# SCC "ColorGraph" #-}
  118. Color.colorGraph
  119. (dopt Opt_RegsIterative dflags)
  120. spinCount
  121. regsFree triv spill graph
  122. -- rewrite regs in the code that have been coalesced
  123. let patchF reg
  124. | RegVirtual vr <- reg
  125. = case lookupUFM rmCoalesce vr of
  126. Just vr' -> patchF (RegVirtual vr')
  127. Nothing -> reg
  128. | otherwise
  129. = reg
  130. let code_coalesced
  131. = map (patchEraseLive patchF) code
  132. -- see if we've found a coloring
  133. if isEmptyUniqSet rsSpill
  134. then do
  135. -- if -fasm-lint is turned on then validate the graph
  136. let graph_colored_lint =
  137. if dopt Opt_DoAsmLinting dflags
  138. then Color.validateGraph (text "")
  139. True -- require all nodes to be colored
  140. graph_colored
  141. else graph_colored
  142. -- patch the registers using the info in the graph
  143. let code_patched = map (patchRegsFromGraph platform graph_colored_lint) code_coalesced
  144. -- clean out unneeded SPILL/RELOADs
  145. let code_spillclean = map (cleanSpills platform) code_patched
  146. -- strip off liveness information,
  147. -- and rewrite SPILL/RELOAD pseudos into real instructions along the way
  148. let code_final = map (stripLive dflags) code_spillclean
  149. -- record what happened in this stage for debugging
  150. let stat =
  151. RegAllocStatsColored
  152. { raCode = code
  153. , raGraph = graph
  154. , raGraphColored = graph_colored_lint
  155. , raCoalesced = rmCoalesce
  156. , raCodeCoalesced = code_coalesced
  157. , raPatched = code_patched
  158. , raSpillClean = code_spillclean
  159. , raFinal = code_final
  160. , raSRMs = foldl' addSRM (0, 0, 0) $ map countSRMs code_spillclean }
  161. let statList =
  162. if dump then [stat] ++ maybeToList stat1 ++ debug_codeGraphs
  163. else []
  164. -- space leak avoidance
  165. seqList statList `seq` return ()
  166. return ( code_final
  167. , statList
  168. , graph_colored_lint)
  169. -- we couldn't find a coloring, time to spill something
  170. else do
  171. -- if -fasm-lint is turned on then validate the graph
  172. let graph_colored_lint =
  173. if dopt Opt_DoAsmLinting dflags
  174. then Color.validateGraph (text "")
  175. False -- don't require nodes to be colored
  176. graph_colored
  177. else graph_colored
  178. -- spill the uncolored regs
  179. (code_spilled, slotsFree', spillStats)
  180. <- regSpill platform code_coalesced slotsFree rsSpill
  181. -- recalculate liveness
  182. -- NOTE: we have to reverse the SCCs here to get them back into the reverse-dependency
  183. -- order required by computeLiveness. If they're not in the correct order
  184. -- that function will panic.
  185. code_relive <- mapM (regLiveness platform . reverseBlocksInTops) code_spilled
  186. -- record what happened in this stage for debugging
  187. let stat =
  188. RegAllocStatsSpill
  189. { raCode = code
  190. , raGraph = graph_colored_lint
  191. , raCoalesced = rmCoalesce
  192. , raSpillStats = spillStats
  193. , raSpillCosts = spillCosts
  194. , raSpilled = code_spilled }
  195. let statList =
  196. if dump
  197. then [stat] ++ maybeToList stat1 ++ debug_codeGraphs
  198. else []
  199. -- space leak avoidance
  200. seqList statList `seq` return ()
  201. regAlloc_spin dflags (spinCount + 1) triv regsFree slotsFree'
  202. statList
  203. code_relive
  204. -- | Build a graph from the liveness and coalesce information in this code.
  205. buildGraph
  206. :: Instruction instr
  207. => [LiveCmmDecl statics instr]
  208. -> UniqSM (Color.Graph VirtualReg RegClass RealReg)
  209. buildGraph code
  210. = do
  211. -- Slurp out the conflicts and reg->reg moves from this code
  212. let (conflictList, moveList) =
  213. unzip $ map slurpConflicts code
  214. -- Slurp out the spill/reload coalesces
  215. let moveList2 = map slurpReloadCoalesce code
  216. -- Add the reg-reg conflicts to the graph
  217. let conflictBag = unionManyBags conflictList
  218. let graph_conflict = foldrBag graphAddConflictSet Color.initGraph conflictBag
  219. -- Add the coalescences edges to the graph.
  220. let moveBag = unionBags (unionManyBags moveList2) (unionManyBags moveList)
  221. let graph_coalesce = foldrBag graphAddCoalesce graph_conflict moveBag
  222. return graph_coalesce
  223. -- | Add some conflict edges to the graph.
  224. -- Conflicts between virtual and real regs are recorded as exclusions.
  225. graphAddConflictSet
  226. :: UniqSet Reg
  227. -> Color.Graph VirtualReg RegClass RealReg
  228. -> Color.Graph VirtualReg RegClass RealReg
  229. graphAddConflictSet set graph
  230. = let virtuals = mkUniqSet
  231. [ vr | RegVirtual vr <- uniqSetToList set ]
  232. graph1 = Color.addConflicts virtuals classOfVirtualReg graph
  233. graph2 = foldr (\(r1, r2) -> Color.addExclusion r1 classOfVirtualReg r2)
  234. graph1
  235. [ (vr, rr)
  236. | RegVirtual vr <- uniqSetToList set
  237. , RegReal rr <- uniqSetToList set]
  238. in graph2
  239. -- | Add some coalesence edges to the graph
  240. -- Coalesences between virtual and real regs are recorded as preferences.
  241. graphAddCoalesce
  242. :: (Reg, Reg)
  243. -> Color.Graph VirtualReg RegClass RealReg
  244. -> Color.Graph VirtualReg RegClass RealReg
  245. graphAddCoalesce (r1, r2) graph
  246. | RegReal rr <- r1
  247. , RegVirtual vr <- r2
  248. = Color.addPreference (vr, classOfVirtualReg vr) rr graph
  249. | RegReal rr <- r2
  250. , RegVirtual vr <- r1
  251. = Color.addPreference (vr, classOfVirtualReg vr) rr graph
  252. | RegVirtual vr1 <- r1
  253. , RegVirtual vr2 <- r2
  254. = Color.addCoalesce
  255. (vr1, classOfVirtualReg vr1)
  256. (vr2, classOfVirtualReg vr2)
  257. graph
  258. -- We can't coalesce two real regs, but there could well be existing
  259. -- hreg,hreg moves in the input code. We'll just ignore these
  260. -- for coalescing purposes.
  261. | RegReal _ <- r1
  262. , RegReal _ <- r2
  263. = graph
  264. graphAddCoalesce _ _
  265. = panic "graphAddCoalesce: bogus"
  266. -- | Patch registers in code using the reg -> reg mapping in this graph.
  267. patchRegsFromGraph
  268. :: (Outputable statics, Outputable instr, Instruction instr)
  269. => Platform -> Color.Graph VirtualReg RegClass RealReg
  270. -> LiveCmmDecl statics instr -> LiveCmmDecl statics instr
  271. patchRegsFromGraph platform graph code
  272. = let
  273. -- a function to lookup the hardreg for a virtual reg from the graph.
  274. patchF reg
  275. -- leave real regs alone.
  276. | RegReal{} <- reg
  277. = reg
  278. -- this virtual has a regular node in the graph.
  279. | RegVirtual vr <- reg
  280. , Just node <- Color.lookupNode graph vr
  281. = case Color.nodeColor node of
  282. Just color -> RegReal color
  283. Nothing -> RegVirtual vr
  284. -- no node in the graph for this virtual, bad news.
  285. | otherwise
  286. = pprPanic "patchRegsFromGraph: register mapping failed."
  287. ( text "There is no node in the graph for register " <> ppr reg
  288. $$ ppr code
  289. $$ Color.dotGraph
  290. (\_ -> text "white")
  291. (trivColorable platform
  292. (targetVirtualRegSqueeze platform)
  293. (targetRealRegSqueeze platform))
  294. graph)
  295. in patchEraseLive patchF code
  296. -----
  297. -- for when laziness just isn't what you wanted...
  298. --
  299. seqGraph :: Color.Graph VirtualReg RegClass RealReg -> ()
  300. seqGraph graph = seqNodes (eltsUFM (Color.graphMap graph))
  301. seqNodes :: [Color.Node VirtualReg RegClass RealReg] -> ()
  302. seqNodes ns
  303. = case ns of
  304. [] -> ()
  305. (n : ns) -> seqNode n `seq` seqNodes ns
  306. seqNode :: Color.Node VirtualReg RegClass RealReg -> ()
  307. seqNode node
  308. = seqVirtualReg (Color.nodeId node)
  309. `seq` seqRegClass (Color.nodeClass node)
  310. `seq` seqMaybeRealReg (Color.nodeColor node)
  311. `seq` (seqVirtualRegList (uniqSetToList (Color.nodeConflicts node)))
  312. `seq` (seqRealRegList (uniqSetToList (Color.nodeExclusions node)))
  313. `seq` (seqRealRegList (Color.nodePreference node))
  314. `seq` (seqVirtualRegList (uniqSetToList (Color.nodeCoalesce node)))
  315. seqVirtualReg :: VirtualReg -> ()
  316. seqVirtualReg reg = reg `seq` ()
  317. seqRealReg :: RealReg -> ()
  318. seqRealReg reg = reg `seq` ()
  319. seqRegClass :: RegClass -> ()
  320. seqRegClass c = c `seq` ()
  321. seqMaybeRealReg :: Maybe RealReg -> ()
  322. seqMaybeRealReg mr
  323. = case mr of
  324. Nothing -> ()
  325. Just r -> seqRealReg r
  326. seqVirtualRegList :: [VirtualReg] -> ()
  327. seqVirtualRegList rs
  328. = case rs of
  329. [] -> ()
  330. (r : rs) -> seqVirtualReg r `seq` seqVirtualRegList rs
  331. seqRealRegList :: [RealReg] -> ()
  332. seqRealRegList rs
  333. = case rs of
  334. [] -> ()
  335. (r : rs) -> seqRealReg r `seq` seqRealRegList rs
  336. seqList :: [a] -> ()
  337. seqList ls
  338. = case ls of
  339. [] -> ()
  340. (r : rs) -> r `seq` seqList rs