/compiler/GHC/Data/Graph/Ops.hs

https://github.com/bgamari/ghc · Haskell · 699 lines · 429 code · 145 blank · 125 comment · 15 complexity · 4f23a56be53df53ab6cd52115b39ec67 MD5 · raw file

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