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

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

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