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

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

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