Warning police
[ghc-hetmet.git] / compiler / nativeGen / GraphOps.hs
index 419cd38..308cae0 100644 (file)
@@ -1,13 +1,6 @@
-
 -- | Basic operations on graphs.
 --
-
-{-# OPTIONS_GHC -w #-}
--- The above warning supression flag is a temporary kludge.
--- While working on this module you are encouraged to remove it and fix
--- any warnings in the module. See
---     http://hackage.haskell.org/trac/ghc/wiki/WorkingConventions#Warnings
--- for details
+{-# OPTIONS -fno-warn-missing-signatures #-}
 
 module GraphOps (
        addNode,        delNode,        getNode,        lookupNode,     modNode,
@@ -17,8 +10,10 @@ module GraphOps (
        addCoalesce,    delCoalesce,    
        addExclusion,   
        addPreference,
+       coalesceGraph,
+       coalesceNodes,
        setColor,
-       verify,
+       validateGraph,
        slurpNodeConflictCount
 )
 where
@@ -33,7 +28,6 @@ import UniqFM
 import Data.List       hiding (union)
 import Data.Maybe
 
-
 -- | Lookup a node from the graph.
 lookupNode 
        :: Uniquable k
@@ -91,11 +85,11 @@ delNode k graph
  = let Just node       = lookupNode graph k
 
        -- delete conflict edges from other nodes to this one.
-       graph1          = foldl' (\g k1 -> delConflict k1 k g) graph 
+       graph1          = foldl' (\g k1 -> let Just g' = delConflict k1 k g in g') graph
                        $ uniqSetToList (nodeConflicts node)
        
        -- delete coalesce edge from other nodes to this one.
-       graph2          = foldl' (\g k1 -> delCoalesce k1 k g) graph1 
+       graph2          = foldl' (\g k1 -> let Just g' = delCoalesce k1 k g in g') graph1
                        $ uniqSetToList (nodeCoalesce node)
        
        -- delete the node
@@ -104,19 +98,24 @@ delNode k graph
   in   graph3
                
 
--- | Modify a node in the graph
+-- | Modify a node in the graph.
+--     returns Nothing if the node isn't present.
+--
 modNode :: Uniquable k
        => (Node k cls color -> Node k cls color) 
-       -> k -> Graph k cls color -> Graph k cls color
+       -> k -> Graph k cls color -> Maybe (Graph k cls color)
 
 modNode f k graph
- = case getNode graph k of
-       Node{} -> graphMapModify
+ = case lookupNode graph k of
+       Just Node{}
+        -> Just
+        $  graphMapModify
                 (\fm   -> let  Just node       = lookupUFM fm k
                                node'           = f node
                           in   addToUFM fm k node') 
                graph
 
+       Nothing -> Nothing
 
 -- | Get the size of the graph, O(n)
 size   :: Uniquable k 
@@ -157,10 +156,11 @@ addConflict (u1, c1) (u2, c2)
 
  
 -- | Delete a conflict edge. k1 -> k2
+--     returns Nothing if the node isn't in the graph
 delConflict 
        :: Uniquable k
        => k -> k
-       -> Graph k cls color -> Graph k cls color
+       -> Graph k cls color -> Maybe (Graph k cls color)
        
 delConflict k1 k2
        = modNode
@@ -187,13 +187,13 @@ addConflicts conflicts getClass
 
        | otherwise
        = graphMapModify
-       $ (\fm -> foldr (\u -> addConflictSet1 u getClass conflicts) fm
+       $ (\fm -> foldl' (\g u  -> addConflictSet1 u getClass conflicts g) fm
                $ uniqSetToList conflicts)
 
 
 addConflictSet1 u getClass set 
- = let set'    = delOneFromUniqSet set u
-   in  adjustWithDefaultUFM 
+ = case delOneFromUniqSet set u of
+    set' -> adjustWithDefaultUFM
                (\node -> node                  { nodeConflicts = unionUniqSets set' (nodeConflicts node) } )
                (newNode u (getClass u))        { nodeConflicts = set' }
                u
@@ -237,7 +237,7 @@ addCoalesce (u1, c1) (u2, c2)
 delCoalesce
        :: Uniquable k
        => k -> k 
-       -> Graph k cls color    -> Graph k cls color
+       -> Graph k cls color    -> Maybe (Graph k cls color)
 
 delCoalesce k1 k2
        = modNode (\node -> node { nodeCoalesce = delOneFromUniqSet (nodeCoalesce node) k2 })
@@ -260,15 +260,142 @@ addPreference (u, c) color
                (newNode u c)  { nodePreference = [color] }
                u
 
+
+-- | Do agressive coalescing on this graph.
+--     returns the new graph and the list of pairs of nodes that got coaleced together.
+--     for each pair, the resulting node will have the least key and be second in the pair.
+--
+coalesceGraph
+       :: (Uniquable k, Ord k, Eq cls, Outputable k)
+       => Triv k cls color
+       -> Graph k cls color
+       -> (Graph k cls color, [(k, k)])
+
+coalesceGraph triv graph
+ = let
+       -- find all the nodes that have coalescence edges
+       cNodes  = filter (\node -> not $ isEmptyUniqSet (nodeCoalesce node))
+               $ eltsUFM $ graphMap graph
+
+       -- build a list of pairs of keys for node's we'll try and coalesce
+       --      every pair of nodes will appear twice in this list
+       --      ie [(k1, k2), (k2, k1) ... ]
+       --      This is ok, GrapOps.coalesceNodes handles this and it's convenient for
+       --      build a list of what nodes get coalesced together for later on.
+       --
+       cList   = [ (nodeId node1, k2)
+                       | node1 <- cNodes
+                       , k2    <- uniqSetToList $ nodeCoalesce node1 ]
+
+       -- do the coalescing, returning the new graph and a list of pairs of keys
+       --      that got coalesced together.
+       (graph', mPairs)
+               = mapAccumL (coalesceNodes False triv) graph cList
+
+   in  (graph', catMaybes mPairs)
+
+
+-- | Coalesce this pair of nodes unconditionally / agressively.
+--     The resulting node is the one with the least key.
+--
+--     returns: Just    the pair of keys if the nodes were coalesced
+--                      the second element of the pair being the least one
+--
+--              Nothing if either of the nodes weren't in the graph
+
+coalesceNodes
+       :: (Uniquable k, Ord k, Eq cls, Outputable k)
+       => Bool                 -- ^ If True, coalesce nodes even if this might make the graph
+                               --      less colorable (aggressive coalescing)
+       -> Triv  k cls color
+       -> Graph k cls color
+       -> (k, k)               -- ^ keys of the nodes to be coalesced
+       -> (Graph k cls color, Maybe (k, k))
+
+coalesceNodes aggressive triv graph (k1, k2)
+       | (kMin, kMax)  <- if k1 < k2
+                               then (k1, k2)
+                               else (k2, k1)
+
+       -- the nodes being coalesced must be in the graph
+       , Just nMin             <- lookupNode graph kMin
+       , Just nMax             <- lookupNode graph kMax
+
+       -- can't coalesce conflicting modes
+       , not $ elementOfUniqSet kMin (nodeConflicts nMax)
+       , not $ elementOfUniqSet kMax (nodeConflicts nMin)
+
+       = coalesceNodes_merge aggressive triv graph kMin kMax nMin nMax
+
+       -- don't do the coalescing after all
+       | otherwise
+       = (graph, Nothing)
+
+coalesceNodes_merge aggressive triv graph kMin kMax nMin nMax
+
+       -- sanity checks
+       | nodeClass nMin /= nodeClass nMax
+       = error "GraphOps.coalesceNodes: can't coalesce nodes of different classes."
+
+       | not (isNothing (nodeColor nMin) && isNothing (nodeColor nMax))
+       = error "GraphOps.coalesceNodes: can't coalesce colored nodes."
+
+       ---
+       | otherwise
+       = let
+               -- the new node gets all the edges from its two components
+               node    =
+                Node   { nodeId                = kMin
+                       , nodeClass             = nodeClass nMin
+                       , nodeColor             = Nothing
+
+                       -- nodes don't conflict with themselves..
+                       , nodeConflicts
+                               = (unionUniqSets (nodeConflicts nMin) (nodeConflicts nMax))
+                                       `delOneFromUniqSet` kMin
+                                       `delOneFromUniqSet` kMax
+
+                       , nodeExclusions        = unionUniqSets (nodeExclusions nMin) (nodeExclusions nMax)
+                       , nodePreference        = nodePreference nMin ++ nodePreference nMax
+
+                       -- nodes don't coalesce with themselves..
+                       , nodeCoalesce
+                               = (unionUniqSets (nodeCoalesce nMin) (nodeCoalesce nMax))
+                                       `delOneFromUniqSet` kMin
+                                       `delOneFromUniqSet` kMax
+                       }
+
+         in    coalesceNodes_check aggressive triv graph kMin kMax node
+
+coalesceNodes_check aggressive triv graph kMin kMax node
+
+       -- Unless we're coalescing aggressively, if the result node is not trivially
+       --      colorable then don't do the coalescing.
+       | not aggressive
+       , not $ triv (nodeClass node) (nodeConflicts node) (nodeExclusions node)
+       = (graph, Nothing)
+
+       | otherwise
+       = let -- delete the old nodes from the graph and add the new one
+               graph'  = addNode kMin node
+                       $ delNode kMin
+                       $ delNode kMax
+                       $ graph
+
+         in    (graph', Just (kMax, kMin))
+
                
--- | Verify the internal structure of a graph
+-- | validate the internal structure of a graph
 --     all its edges should point to valid nodes
+--     if they don't then throw an error
 --
-verify         :: Uniquable k 
-       => Graph k cls color
-       -> Bool
+validateGraph
+       :: (Uniquable k, Outputable k)
+       => SDoc
+       -> Graph k cls color
+       -> Graph k cls color
 
-verify graph
+validateGraph doc graph
  = let edges   = unionUniqSets
                        (unionManyUniqSets
                                (map nodeConflicts $ eltsUFM $ graphMap graph))
@@ -280,8 +407,12 @@ verify graph
        badEdges = minusUniqSet edges nodes
        
   in   if isEmptyUniqSet badEdges 
-        then   True
-        else   False
+        then   graph
+        else   pprPanic "GraphOps.validateGraph"
+               ( text  "-- bad edges"
+               $$ vcat (map ppr $ uniqSetToList badEdges)
+               $$ text "----------------------------"
+               $$ doc)
 
 
 -- | Slurp out a map of how many nodes had a certain number of conflict neighbours
@@ -293,7 +424,7 @@ slurpNodeConflictCount
 
 slurpNodeConflictCount graph
        = addListToUFM_C
-               (\(c1, n1) (c2, n2) -> (c1, n1 + n2))
+               (\(c1, n1) (_, n2) -> (c1, n1 + n2))
                emptyUFM
        $ map   (\node
                  -> let count  = sizeUniqSet $ nodeConflicts node
@@ -315,6 +446,7 @@ setColor u color
                u 
        
 
+{-# INLINE     adjustWithDefaultUFM #-}
 adjustWithDefaultUFM 
        :: Uniquable k 
        => (a -> a) -> a -> k 
@@ -322,11 +454,11 @@ adjustWithDefaultUFM
 
 adjustWithDefaultUFM f def k map
        = addToUFM_C 
-               (\old new -> f old)
+               (\old _ -> f old)
                map
                k def
                
-
+{-# INLINE adjustUFM #-}
 adjustUFM 
        :: Uniquable k
        => (a -> a)
@@ -336,5 +468,4 @@ adjustUFM f k map
  = case lookupUFM map k of
        Nothing -> map
        Just a  -> addToUFM map k (f a)
-