PageRenderTime 56ms CodeModel.GetById 23ms RepoModel.GetById 0ms app.codeStats 0ms

/ghc-7.0.4/compiler/utils/GraphOps.hs

http://picorec.googlecode.com/
Haskell | 634 lines | 389 code | 136 blank | 109 comment | 5 complexity | fff5139964e92ad28b2216102b42d0cc MD5 | raw file
Possible License(s): BSD-3-Clause, BSD-2-Clause
  1. {-# OPTIONS -fno-warn-missing-signatures #-}
  2. -- | Basic operations on graphs.
  3. --
  4. module GraphOps (
  5. addNode, delNode, getNode, lookupNode, modNode,
  6. size,
  7. union,
  8. addConflict, delConflict, addConflicts,
  9. addCoalesce, delCoalesce,
  10. addExclusion, addExclusions,
  11. addPreference,
  12. coalesceNodes, coalesceGraph,
  13. freezeNode, freezeOneInGraph, freezeAllInGraph,
  14. scanGraph,
  15. setColor,
  16. validateGraph,
  17. slurpNodeConflictCount
  18. )
  19. where
  20. import GraphBase
  21. import Outputable
  22. import Unique
  23. import UniqSet
  24. import UniqFM
  25. import Data.List hiding (union)
  26. import Data.Maybe
  27. -- | Lookup a node from the graph.
  28. lookupNode
  29. :: Uniquable k
  30. => Graph k cls color
  31. -> k -> Maybe (Node k cls color)
  32. lookupNode graph k
  33. = lookupUFM (graphMap graph) k
  34. -- | Get a node from the graph, throwing an error if it's not there
  35. getNode
  36. :: Uniquable k
  37. => Graph k cls color
  38. -> k -> Node k cls color
  39. getNode graph k
  40. = case lookupUFM (graphMap graph) k of
  41. Just node -> node
  42. Nothing -> panic "ColorOps.getNode: not found"
  43. -- | Add a node to the graph, linking up its edges
  44. addNode :: Uniquable k
  45. => k -> Node k cls color
  46. -> Graph k cls color -> Graph k cls color
  47. addNode k node graph
  48. = let
  49. -- add back conflict edges from other nodes to this one
  50. map_conflict
  51. = foldUniqSet
  52. (adjustUFM (\n -> n { nodeConflicts = addOneToUniqSet (nodeConflicts n) k}))
  53. (graphMap graph)
  54. (nodeConflicts node)
  55. -- add back coalesce edges from other nodes to this one
  56. map_coalesce
  57. = foldUniqSet
  58. (adjustUFM (\n -> n { nodeCoalesce = addOneToUniqSet (nodeCoalesce n) k}))
  59. map_conflict
  60. (nodeCoalesce node)
  61. in graph
  62. { graphMap = addToUFM map_coalesce k node}
  63. -- | Delete a node and all its edges from the graph.
  64. delNode :: (Uniquable k, Outputable k)
  65. => k -> Graph k cls color -> Maybe (Graph k cls color)
  66. delNode k graph
  67. | Just node <- lookupNode graph k
  68. = let -- delete conflict edges from other nodes to this one.
  69. graph1 = foldl' (\g k1 -> let Just g' = delConflict k1 k g in g') graph
  70. $ uniqSetToList (nodeConflicts node)
  71. -- delete coalesce edge from other nodes to this one.
  72. graph2 = foldl' (\g k1 -> let Just g' = delCoalesce k1 k g in g') graph1
  73. $ uniqSetToList (nodeCoalesce node)
  74. -- delete the node
  75. graph3 = graphMapModify (\fm -> delFromUFM fm k) graph2
  76. in Just graph3
  77. | otherwise
  78. = Nothing
  79. -- | Modify a node in the graph.
  80. -- returns Nothing if the node isn't present.
  81. --
  82. modNode :: Uniquable k
  83. => (Node k cls color -> Node k cls color)
  84. -> k -> Graph k cls color -> Maybe (Graph k cls color)
  85. modNode f k graph
  86. = case lookupNode graph k of
  87. Just Node{}
  88. -> Just
  89. $ graphMapModify
  90. (\fm -> let Just node = lookupUFM fm k
  91. node' = f node
  92. in addToUFM fm k node')
  93. graph
  94. Nothing -> Nothing
  95. -- | Get the size of the graph, O(n)
  96. size :: Uniquable k
  97. => Graph k cls color -> Int
  98. size graph
  99. = sizeUFM $ graphMap graph
  100. -- | Union two graphs together.
  101. union :: Uniquable k
  102. => Graph k cls color -> Graph k cls color -> Graph k cls color
  103. union graph1 graph2
  104. = Graph
  105. { graphMap = plusUFM (graphMap graph1) (graphMap graph2) }
  106. -- | Add a conflict between nodes to the graph, creating the nodes required.
  107. -- Conflicts are virtual regs which need to be colored differently.
  108. addConflict
  109. :: Uniquable k
  110. => (k, cls) -> (k, cls)
  111. -> Graph k cls color -> Graph k cls color
  112. addConflict (u1, c1) (u2, c2)
  113. = let addNeighbor u c u'
  114. = adjustWithDefaultUFM
  115. (\node -> node { nodeConflicts = addOneToUniqSet (nodeConflicts node) u' })
  116. (newNode u c) { nodeConflicts = unitUniqSet u' }
  117. u
  118. in graphMapModify
  119. ( addNeighbor u1 c1 u2
  120. . addNeighbor u2 c2 u1)
  121. -- | Delete a conflict edge. k1 -> k2
  122. -- returns Nothing if the node isn't in the graph
  123. delConflict
  124. :: Uniquable k
  125. => k -> k
  126. -> Graph k cls color -> Maybe (Graph k cls color)
  127. delConflict k1 k2
  128. = modNode
  129. (\node -> node { nodeConflicts = delOneFromUniqSet (nodeConflicts node) k2 })
  130. k1
  131. -- | Add some conflicts to the graph, creating nodes if required.
  132. -- All the nodes in the set are taken to conflict with each other.
  133. addConflicts
  134. :: Uniquable k
  135. => UniqSet k -> (k -> cls)
  136. -> Graph k cls color -> Graph k cls color
  137. addConflicts conflicts getClass
  138. -- just a single node, but no conflicts, create the node anyway.
  139. | (u : []) <- uniqSetToList conflicts
  140. = graphMapModify
  141. $ adjustWithDefaultUFM
  142. id
  143. (newNode u (getClass u))
  144. u
  145. | otherwise
  146. = graphMapModify
  147. $ (\fm -> foldl' (\g u -> addConflictSet1 u getClass conflicts g) fm
  148. $ uniqSetToList conflicts)
  149. addConflictSet1 u getClass set
  150. = case delOneFromUniqSet set u of
  151. set' -> adjustWithDefaultUFM
  152. (\node -> node { nodeConflicts = unionUniqSets set' (nodeConflicts node) } )
  153. (newNode u (getClass u)) { nodeConflicts = set' }
  154. u
  155. -- | Add an exclusion to the graph, creating nodes if required.
  156. -- These are extra colors that the node cannot use.
  157. addExclusion
  158. :: (Uniquable k, Uniquable color)
  159. => k -> (k -> cls) -> color
  160. -> Graph k cls color -> Graph k cls color
  161. addExclusion u getClass color
  162. = graphMapModify
  163. $ adjustWithDefaultUFM
  164. (\node -> node { nodeExclusions = addOneToUniqSet (nodeExclusions node) color })
  165. (newNode u (getClass u)) { nodeExclusions = unitUniqSet color }
  166. u
  167. addExclusions
  168. :: (Uniquable k, Uniquable color)
  169. => k -> (k -> cls) -> [color]
  170. -> Graph k cls color -> Graph k cls color
  171. addExclusions u getClass colors graph
  172. = foldr (addExclusion u getClass) graph colors
  173. -- | Add a coalescence edge to the graph, creating nodes if requried.
  174. -- It is considered adventageous to assign the same color to nodes in a coalesence.
  175. addCoalesce
  176. :: Uniquable k
  177. => (k, cls) -> (k, cls)
  178. -> Graph k cls color -> Graph k cls color
  179. addCoalesce (u1, c1) (u2, c2)
  180. = let addCoalesce u c u'
  181. = adjustWithDefaultUFM
  182. (\node -> node { nodeCoalesce = addOneToUniqSet (nodeCoalesce node) u' })
  183. (newNode u c) { nodeCoalesce = unitUniqSet u' }
  184. u
  185. in graphMapModify
  186. ( addCoalesce u1 c1 u2
  187. . addCoalesce u2 c2 u1)
  188. -- | Delete a coalescence edge (k1 -> k2) from the graph.
  189. delCoalesce
  190. :: Uniquable k
  191. => k -> k
  192. -> Graph k cls color -> Maybe (Graph k cls color)
  193. delCoalesce k1 k2
  194. = modNode (\node -> node { nodeCoalesce = delOneFromUniqSet (nodeCoalesce node) k2 })
  195. k1
  196. -- | Add a color preference to the graph, creating nodes if required.
  197. -- The most recently added preference is the most prefered.
  198. -- The algorithm tries to assign a node it's prefered color if possible.
  199. --
  200. addPreference
  201. :: Uniquable k
  202. => (k, cls) -> color
  203. -> Graph k cls color -> Graph k cls color
  204. addPreference (u, c) color
  205. = graphMapModify
  206. $ adjustWithDefaultUFM
  207. (\node -> node { nodePreference = color : (nodePreference node) })
  208. (newNode u c) { nodePreference = [color] }
  209. u
  210. -- | Do agressive coalescing on this graph.
  211. -- returns the new graph and the list of pairs of nodes that got coaleced together.
  212. -- for each pair, the resulting node will have the least key and be second in the pair.
  213. --
  214. coalesceGraph
  215. :: (Uniquable k, Ord k, Eq cls, Outputable k)
  216. => Bool -- ^ If True, coalesce nodes even if this might make the graph
  217. -- less colorable (aggressive coalescing)
  218. -> Triv k cls color
  219. -> Graph k cls color
  220. -> ( Graph k cls color
  221. , [(k, k)]) -- pairs of nodes that were coalesced, in the order that the
  222. -- coalescing was applied.
  223. coalesceGraph aggressive triv graph
  224. = coalesceGraph' aggressive triv graph []
  225. coalesceGraph' aggressive triv graph kkPairsAcc
  226. = let
  227. -- find all the nodes that have coalescence edges
  228. cNodes = filter (\node -> not $ isEmptyUniqSet (nodeCoalesce node))
  229. $ eltsUFM $ graphMap graph
  230. -- build a list of pairs of keys for node's we'll try and coalesce
  231. -- every pair of nodes will appear twice in this list
  232. -- ie [(k1, k2), (k2, k1) ... ]
  233. -- This is ok, GrapOps.coalesceNodes handles this and it's convenient for
  234. -- build a list of what nodes get coalesced together for later on.
  235. --
  236. cList = [ (nodeId node1, k2)
  237. | node1 <- cNodes
  238. , k2 <- uniqSetToList $ nodeCoalesce node1 ]
  239. -- do the coalescing, returning the new graph and a list of pairs of keys
  240. -- that got coalesced together.
  241. (graph', mPairs)
  242. = mapAccumL (coalesceNodes aggressive triv) graph cList
  243. -- keep running until there are no more coalesces can be found
  244. in case catMaybes mPairs of
  245. [] -> (graph', reverse kkPairsAcc)
  246. pairs -> coalesceGraph' aggressive triv graph' (reverse pairs ++ kkPairsAcc)
  247. -- | Coalesce this pair of nodes unconditionally \/ agressively.
  248. -- The resulting node is the one with the least key.
  249. --
  250. -- returns: Just the pair of keys if the nodes were coalesced
  251. -- the second element of the pair being the least one
  252. --
  253. -- Nothing if either of the nodes weren't in the graph
  254. coalesceNodes
  255. :: (Uniquable k, Ord k, Eq cls, Outputable k)
  256. => Bool -- ^ If True, coalesce nodes even if this might make the graph
  257. -- less colorable (aggressive coalescing)
  258. -> Triv k cls color
  259. -> Graph k cls color
  260. -> (k, k) -- ^ keys of the nodes to be coalesced
  261. -> (Graph k cls color, Maybe (k, k))
  262. coalesceNodes aggressive triv graph (k1, k2)
  263. | (kMin, kMax) <- if k1 < k2
  264. then (k1, k2)
  265. else (k2, k1)
  266. -- the nodes being coalesced must be in the graph
  267. , Just nMin <- lookupNode graph kMin
  268. , Just nMax <- lookupNode graph kMax
  269. -- can't coalesce conflicting modes
  270. , not $ elementOfUniqSet kMin (nodeConflicts nMax)
  271. , not $ elementOfUniqSet kMax (nodeConflicts nMin)
  272. -- can't coalesce the same node
  273. , nodeId nMin /= nodeId nMax
  274. = coalesceNodes_merge aggressive triv graph kMin kMax nMin nMax
  275. -- don't do the coalescing after all
  276. | otherwise
  277. = (graph, Nothing)
  278. coalesceNodes_merge aggressive triv graph kMin kMax nMin nMax
  279. -- sanity checks
  280. | nodeClass nMin /= nodeClass nMax
  281. = error "GraphOps.coalesceNodes: can't coalesce nodes of different classes."
  282. | not (isNothing (nodeColor nMin) && isNothing (nodeColor nMax))
  283. = error "GraphOps.coalesceNodes: can't coalesce colored nodes."
  284. ---
  285. | otherwise
  286. = let
  287. -- the new node gets all the edges from its two components
  288. node =
  289. Node { nodeId = kMin
  290. , nodeClass = nodeClass nMin
  291. , nodeColor = Nothing
  292. -- nodes don't conflict with themselves..
  293. , nodeConflicts
  294. = (unionUniqSets (nodeConflicts nMin) (nodeConflicts nMax))
  295. `delOneFromUniqSet` kMin
  296. `delOneFromUniqSet` kMax
  297. , nodeExclusions = unionUniqSets (nodeExclusions nMin) (nodeExclusions nMax)
  298. , nodePreference = nodePreference nMin ++ nodePreference nMax
  299. -- nodes don't coalesce with themselves..
  300. , nodeCoalesce
  301. = (unionUniqSets (nodeCoalesce nMin) (nodeCoalesce nMax))
  302. `delOneFromUniqSet` kMin
  303. `delOneFromUniqSet` kMax
  304. }
  305. in coalesceNodes_check aggressive triv graph kMin kMax node
  306. coalesceNodes_check aggressive triv graph kMin kMax node
  307. -- Unless we're coalescing aggressively, if the result node is not trivially
  308. -- colorable then don't do the coalescing.
  309. | not aggressive
  310. , not $ triv (nodeClass node) (nodeConflicts node) (nodeExclusions node)
  311. = (graph, Nothing)
  312. | otherwise
  313. = let -- delete the old nodes from the graph and add the new one
  314. Just graph1 = delNode kMax graph
  315. Just graph2 = delNode kMin graph1
  316. graph3 = addNode kMin node graph2
  317. in (graph3, Just (kMax, kMin))
  318. -- | Freeze a node
  319. -- This is for the iterative coalescer.
  320. -- By freezing a node we give up on ever coalescing it.
  321. -- Move all its coalesce edges into the frozen set - and update
  322. -- back edges from other nodes.
  323. --
  324. freezeNode
  325. :: Uniquable k
  326. => k -- ^ key of the node to freeze
  327. -> Graph k cls color -- ^ the graph
  328. -> Graph k cls color -- ^ graph with that node frozen
  329. freezeNode k
  330. = graphMapModify
  331. $ \fm ->
  332. let -- freeze all the edges in the node to be frozen
  333. Just node = lookupUFM fm k
  334. node' = node
  335. { nodeCoalesce = emptyUniqSet }
  336. fm1 = addToUFM fm k node'
  337. -- update back edges pointing to this node
  338. freezeEdge k node
  339. = if elementOfUniqSet k (nodeCoalesce node)
  340. then node { nodeCoalesce = delOneFromUniqSet (nodeCoalesce node) k }
  341. else node -- panic "GraphOps.freezeNode: edge to freeze wasn't in the coalesce set"
  342. -- If the edge isn't actually in the coelesce set then just ignore it.
  343. fm2 = foldUniqSet (adjustUFM (freezeEdge k)) fm1
  344. $ nodeCoalesce node
  345. in fm2
  346. -- | Freeze one node in the graph
  347. -- This if for the iterative coalescer.
  348. -- Look for a move related node of low degree and freeze it.
  349. --
  350. -- We probably don't need to scan the whole graph looking for the node of absolute
  351. -- lowest degree. Just sample the first few and choose the one with the lowest
  352. -- degree out of those. Also, we don't make any distinction between conflicts of different
  353. -- classes.. this is just a heuristic, after all.
  354. --
  355. -- IDEA: freezing a node might free it up for Simplify.. would be good to check for triv
  356. -- right here, and add it to a worklist if known triv\/non-move nodes.
  357. --
  358. freezeOneInGraph
  359. :: (Uniquable k, Outputable k)
  360. => Graph k cls color
  361. -> ( Graph k cls color -- the new graph
  362. , Bool ) -- whether we found a node to freeze
  363. freezeOneInGraph graph
  364. = let compareNodeDegree n1 n2
  365. = compare (sizeUniqSet $ nodeConflicts n1) (sizeUniqSet $ nodeConflicts n2)
  366. candidates
  367. = sortBy compareNodeDegree
  368. $ take 5 -- 5 isn't special, it's just a small number.
  369. $ scanGraph (\node -> not $ isEmptyUniqSet (nodeCoalesce node)) graph
  370. in case candidates of
  371. -- there wasn't anything available to freeze
  372. [] -> (graph, False)
  373. -- we found something to freeze
  374. (n : _)
  375. -> ( freezeNode (nodeId n) graph
  376. , True)
  377. -- | Freeze all the nodes in the graph
  378. -- for debugging the iterative allocator.
  379. --
  380. freezeAllInGraph
  381. :: (Uniquable k, Outputable k)
  382. => Graph k cls color
  383. -> Graph k cls color
  384. freezeAllInGraph graph
  385. = foldr freezeNode graph
  386. $ map nodeId
  387. $ eltsUFM $ graphMap graph
  388. -- | Find all the nodes in the graph that meet some criteria
  389. --
  390. scanGraph
  391. :: Uniquable k
  392. => (Node k cls color -> Bool)
  393. -> Graph k cls color
  394. -> [Node k cls color]
  395. scanGraph match graph
  396. = filter match $ eltsUFM $ graphMap graph
  397. -- | validate the internal structure of a graph
  398. -- all its edges should point to valid nodes
  399. -- If they don't then throw an error
  400. --
  401. validateGraph
  402. :: (Uniquable k, Outputable k, Eq color)
  403. => SDoc -- ^ extra debugging info to display on error
  404. -> Bool -- ^ whether this graph is supposed to be colored.
  405. -> Graph k cls color -- ^ graph to validate
  406. -> Graph k cls color -- ^ validated graph
  407. validateGraph doc isColored graph
  408. -- Check that all edges point to valid nodes.
  409. | edges <- unionManyUniqSets
  410. ( (map nodeConflicts $ eltsUFM $ graphMap graph)
  411. ++ (map nodeCoalesce $ eltsUFM $ graphMap graph))
  412. , nodes <- mkUniqSet $ map nodeId $ eltsUFM $ graphMap graph
  413. , badEdges <- minusUniqSet edges nodes
  414. , not $ isEmptyUniqSet badEdges
  415. = pprPanic "GraphOps.validateGraph"
  416. ( text "Graph has edges that point to non-existant nodes"
  417. $$ text " bad edges: " <> vcat (map ppr $ uniqSetToList badEdges)
  418. $$ doc )
  419. -- Check that no conflicting nodes have the same color
  420. | badNodes <- filter (not . (checkNode graph))
  421. $ eltsUFM $ graphMap graph
  422. , not $ null badNodes
  423. = pprPanic "GraphOps.validateGraph"
  424. ( text "Node has same color as one of it's conflicts"
  425. $$ text " bad nodes: " <> hcat (map (ppr . nodeId) badNodes)
  426. $$ doc)
  427. -- If this is supposed to be a colored graph,
  428. -- check that all nodes have a color.
  429. | isColored
  430. , badNodes <- filter (\n -> isNothing $ nodeColor n)
  431. $ eltsUFM $ graphMap graph
  432. , not $ null badNodes
  433. = pprPanic "GraphOps.validateGraph"
  434. ( text "Supposably colored graph has uncolored nodes."
  435. $$ text " uncolored nodes: " <> hcat (map (ppr . nodeId) badNodes)
  436. $$ doc )
  437. -- graph looks ok
  438. | otherwise
  439. = graph
  440. -- | If this node is colored, check that all the nodes which
  441. -- conflict with it have different colors.
  442. checkNode
  443. :: (Uniquable k, Eq color)
  444. => Graph k cls color
  445. -> Node k cls color
  446. -> Bool -- ^ True if this node is ok
  447. checkNode graph node
  448. | Just color <- nodeColor node
  449. , Just neighbors <- sequence $ map (lookupNode graph)
  450. $ uniqSetToList $ nodeConflicts node
  451. , neighbourColors <- catMaybes $ map nodeColor neighbors
  452. , elem color neighbourColors
  453. = False
  454. | otherwise
  455. = True
  456. -- | Slurp out a map of how many nodes had a certain number of conflict neighbours
  457. slurpNodeConflictCount
  458. :: Uniquable k
  459. => Graph k cls color
  460. -> UniqFM (Int, Int) -- ^ (conflict neighbours, num nodes with that many conflicts)
  461. slurpNodeConflictCount graph
  462. = addListToUFM_C
  463. (\(c1, n1) (_, n2) -> (c1, n1 + n2))
  464. emptyUFM
  465. $ map (\node
  466. -> let count = sizeUniqSet $ nodeConflicts node
  467. in (count, (count, 1)))
  468. $ eltsUFM
  469. $ graphMap graph
  470. -- | Set the color of a certain node
  471. setColor
  472. :: Uniquable k
  473. => k -> color
  474. -> Graph k cls color -> Graph k cls color
  475. setColor u color
  476. = graphMapModify
  477. $ adjustUFM
  478. (\n -> n { nodeColor = Just color })
  479. u
  480. {-# INLINE adjustWithDefaultUFM #-}
  481. adjustWithDefaultUFM
  482. :: Uniquable k
  483. => (a -> a) -> a -> k
  484. -> UniqFM a -> UniqFM a
  485. adjustWithDefaultUFM f def k map
  486. = addToUFM_C
  487. (\old _ -> f old)
  488. map
  489. k def
  490. {-# INLINE adjustUFM #-}
  491. adjustUFM
  492. :: Uniquable k
  493. => (a -> a)
  494. -> k -> UniqFM a -> UniqFM a
  495. adjustUFM f k map
  496. = case lookupUFM map k of
  497. Nothing -> map
  498. Just a -> addToUFM map k (f a)