diff --git a/Makefile.am b/Makefile.am
index ef9b62c..ce59134 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -85,6 +85,7 @@ tock_SOURCES_hs += backends/TLP.hs
tock_SOURCES_hs += checks/ArrayUsageCheck.hs
tock_SOURCES_hs += checks/Omega.hs
tock_SOURCES_hs += checks/RainUsageCheck.hs
+tock_SOURCES_hs += checks/UsageCheckAlgorithms.hs
tock_SOURCES_hs += checks/UsageCheckUtils.hs
tock_SOURCES_hs += common/AST.hs
tock_SOURCES_hs += common/CompState.hs
diff --git a/checks/ArrayUsageCheck.hs b/checks/ArrayUsageCheck.hs
index e0283c1..e8a9528 100644
--- a/checks/ArrayUsageCheck.hs
+++ b/checks/ArrayUsageCheck.hs
@@ -35,6 +35,7 @@ import Omega
import Pass
import ShowCode
import Types
+import UsageCheckAlgorithms
import UsageCheckUtils
import Utils
diff --git a/checks/RainUsageCheck.hs b/checks/RainUsageCheck.hs
index fe8e47b..d906d07 100644
--- a/checks/RainUsageCheck.hs
+++ b/checks/RainUsageCheck.hs
@@ -20,7 +20,7 @@ with this program. If not, see .
-- the control-flow graph stuff, hence the use of functions that match the dictionary
-- of functions in FlowGraph. This is also why we don't drill down into processes;
-- the control-flow graph means that we only need to concentrate on each node that isn't nested.
-module RainUsageCheck (checkInitVar, findReachDef) where
+module RainUsageCheck (checkInitVar) where
import Control.Monad.Identity
import Data.Graph.Inductive
@@ -36,7 +36,6 @@ import FlowGraph
import Metadata
import ShowCode
import UsageCheckUtils
-import Utils
{-
Near the beginning, this piece of code was too clever for itself and applied processVarW using "everything".
@@ -221,55 +220,3 @@ checkInitVar graph startNode
do readVars <- showCodeExSet v
writtenVars <- showCodeExSet vs
dieP (getMeta n) $ "Variable read from is not written to before-hand, sets are read: " ++ show readVars ++ " and written: " ++ show writtenVars
-
--- | Returns either an error, or map *from* the node with a read, *to* the node whose definitions might be available at that point
-
--- I considered having the return type be Map Var (Map Node x)) rather than Map (Var,Node) x, but the time for lookup
--- will be identical (log N + log V in the former case, log (V*N) in the latter), and having a pair seemed simpler.
--- TODO correct that comment!
-findReachDef :: forall m. Monad m => FlowGraph m (Maybe Decl, Vars) -> Node -> Either String (Map.Map Node (Map.Map Var (Set.Set Node)))
-findReachDef graph startNode
- = do r <- flowAlgorithm graphFuncs (nodes graph) startNode
- -- These lines remove the maps where the variable is not read in that particular node:
- let r' = Map.mapWithKey (\n -> Map.filterWithKey (readInNode' n)) r
- return $ Map.filter (not . Map.null) r'
- where
- graphFuncs :: GraphFuncs Node EdgeLabel (Map.Map Var (Set.Set Node))
- graphFuncs = GF
- {
- nodeFunc = processNode
- ,prevNodes = lpre graph
- ,nextNodes = lsuc graph
- ,initVal = Map.empty
- ,defVal = Map.empty
- }
-
- readInNode' :: Node -> Var -> a -> Bool
- readInNode' n v _ = readInNode v (lab graph n)
-
- readInNode :: Var -> Maybe (FNode m (Maybe Decl, Vars)) -> Bool
- readInNode v (Just (Node (_,(_,Vars read _ _),_))) = Set.member v read
-
- writeNode :: FNode m (Maybe Decl, Vars) -> Set.Set Var
- writeNode (Node (_,(_,Vars _ written _),_)) = written
-
- -- | A confusiing function used by processNode. It takes a node and node label, and uses
- -- these to form a multi-map modifier function that replaces all node-sources for variables
- -- written to by the given with node with a singleton set containing the given node.
- -- That is, nodeLabelToMapInsert N (Node (_,Vars _ written _ _)) is a function that replaces
- -- the sets for each v (v in written) with a singleton set {N}.
- nodeLabelToMapInsert :: Node -> FNode m (Maybe Decl, Vars) -> Map.Map Var (Set.Set Node) -> Map.Map Var (Set.Set Node)
- nodeLabelToMapInsert n = foldFuncs . (map (\v -> Map.insert v (Set.singleton n) )) . Set.toList . writeNode
-
- processNode :: (Node, EdgeLabel) -> Map.Map Var (Set.Set Node) -> Maybe (Map.Map Var (Set.Set Node)) -> Map.Map Var (Set.Set Node)
- processNode (n,_) inputVal mm = mergeMultiMaps modifiedInput prevAgg
- where
- prevAgg :: Map.Map Var (Set.Set Node)
- prevAgg = fromMaybe Map.empty mm
-
- modifiedInput :: Map.Map Var (Set.Set Node)
- modifiedInput = (maybe id (nodeLabelToMapInsert n) $ lab graph n) inputVal
-
- -- | Merges two "multi-maps" (maps to sets) using union
- mergeMultiMaps :: (Ord k, Ord a) => Map.Map k (Set.Set a) -> Map.Map k (Set.Set a) -> Map.Map k (Set.Set a)
- mergeMultiMaps = Map.unionWith (Set.union)
diff --git a/checks/RainUsageCheckTest.hs b/checks/RainUsageCheckTest.hs
index 065f118..d2bba03 100644
--- a/checks/RainUsageCheckTest.hs
+++ b/checks/RainUsageCheckTest.hs
@@ -31,6 +31,7 @@ import FlowGraph
import Metadata
import RainUsageCheck
import TestUtils hiding (Var)
+import UsageCheckAlgorithms
import UsageCheckUtils
import Utils
diff --git a/checks/UsageCheckAlgorithms.hs b/checks/UsageCheckAlgorithms.hs
new file mode 100644
index 0000000..c5f4498
--- /dev/null
+++ b/checks/UsageCheckAlgorithms.hs
@@ -0,0 +1,142 @@
+{-
+Tock: a compiler for parallel languages
+Copyright (C) 2007 University of Kent
+
+This program is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation, either version 2 of the License, or (at your
+option) any later version.
+
+This program is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License along
+with this program. If not, see .
+-}
+
+module UsageCheckAlgorithms (checkPar, findReachDef, joinCheckParFunctions) where
+
+import Data.Graph.Inductive
+import qualified Data.Map as Map
+import Data.Maybe
+import qualified Data.Set as Set
+
+import FlowAlgorithms
+import FlowGraph
+import Metadata
+import UsageCheckUtils
+import Utils
+
+joinCheckParFunctions :: Monad m => ((Meta, ParItems a) -> m b) -> ((Meta, ParItems a) -> m c) -> ((Meta, ParItems a) -> m (b,c))
+joinCheckParFunctions f g x = seqPair (f x, g x)
+
+-- | Given a function to check a list of graph labels and a flow graph,
+-- returns a list of monadic actions (slightly
+-- more flexible than a monadic action giving a list) that will check
+-- all PAR items in the flow graph
+checkPar :: forall m a b. Monad m => ((Meta, ParItems a) -> m b) -> FlowGraph m a -> [m b]
+checkPar f g = map f allParItems
+ where
+ allStartParEdges :: Map.Map Int [(Node,Node)]
+ allStartParEdges = foldl (\mp (s,e,n) -> Map.insertWith (++) n [(s,e)] mp) Map.empty $ mapMaybe tagStartParEdge $ labEdges g
+
+ tagStartParEdge :: (Node,Node,EdgeLabel) -> Maybe (Node,Node,Int)
+ tagStartParEdge (s,e,EStartPar n) = Just (s,e,n)
+ tagStartParEdge _ = Nothing
+
+ allParItems :: [(Meta, ParItems a)]
+ allParItems = map makeEntry $ map findNodes $ Map.toList allStartParEdges
+ where
+ findNodes :: (Int,[(Node,Node)]) -> (Node,[ParItems a])
+ findNodes (n,ses) = (undefined, [SeqItems (followUntilEdge e (EEndPar n)) | (_,e) <- ses])
+
+ makeEntry :: (Node,[ParItems a]) -> (Meta, ParItems a)
+ makeEntry (_,xs) = (emptyMeta {- TODO fix this again -} , ParItems xs)
+
+ -- | We need to follow all edges out of a particular node until we reach
+ -- an edge that matches the given edge. So what we effectively need
+ -- is a depth-first or breadth-first search (DFS or BFS), that terminates
+ -- on a given edge, not on a given node. Therefore the DFS/BFS algorithms
+ -- that come with the inductive graph package are not very suitable as
+ -- they return node lists or edge lists, but we need a node list terminated
+ -- on a particular edge.
+ --
+ -- So, we shall attempt our own algorithm! The algorithm for DFS given in
+ -- the library is effectively:
+ --
+ -- dfs :: Graph gr => [Node] -> gr a b -> [Node]
+ -- dfs [] _ = []
+ -- dfs _ g | isEmpty g = []
+ -- dfs (v:vs) g = case match v g of
+ -- (Just c,g') -> node' c:dfs (suc' c++vs) g'
+ -- (Nothing,g') -> dfs vs g'
+ -- where node' :: Context a b -> Node and suc' :: Context a b -> [Node]
+ --
+ -- We want to stop the DFS branch either when we find no nodes following the current
+ -- one (already effectively taken care of in the algorithm above; suc' will return
+ -- the empty list) or when the edge we are meant to take matches the given edge.
+ followUntilEdge :: Node -> EdgeLabel -> [a]
+ followUntilEdge startNode endEdge = customDFS [startNode] g
+ where
+ customDFS :: [Node] -> FlowGraph m a -> [a]
+ customDFS [] _ = []
+ customDFS _ g | isEmpty g = []
+ customDFS (v:vs) g = case match v g of
+ (Just c, g') -> labelItem c : customDFS (customSucc c ++ vs) g'
+ (Nothing, g') -> customDFS vs g'
+
+ labelItem :: Context (FNode m a) EdgeLabel -> a
+ labelItem c = let (Node (_,x,_)) = lab' c in x
+
+ customSucc :: Context (FNode m a) EdgeLabel -> [Node]
+ customSucc c = [n | (n,e) <- lsuc' c, e /= endEdge]
+
+-- | Returns either an error, or map *from* the node with a read, *to* the node whose definitions might be available at that point
+findReachDef :: forall m. Monad m => FlowGraph m (Maybe Decl, Vars) -> Node -> Either String (Map.Map Node (Map.Map Var (Set.Set Node)))
+findReachDef graph startNode
+ = do r <- flowAlgorithm graphFuncs (nodes graph) startNode
+ -- These lines remove the maps where the variable is not read in that particular node:
+ let r' = Map.mapWithKey (\n -> Map.filterWithKey (readInNode' n)) r
+ return $ Map.filter (not . Map.null) r'
+ where
+ graphFuncs :: GraphFuncs Node EdgeLabel (Map.Map Var (Set.Set Node))
+ graphFuncs = GF
+ {
+ nodeFunc = processNode
+ ,prevNodes = lpre graph
+ ,nextNodes = lsuc graph
+ ,initVal = Map.empty
+ ,defVal = Map.empty
+ }
+
+ readInNode' :: Node -> Var -> a -> Bool
+ readInNode' n v _ = readInNode v (lab graph n)
+
+ readInNode :: Var -> Maybe (FNode m (Maybe Decl, Vars)) -> Bool
+ readInNode v (Just (Node (_,(_,Vars read _ _),_))) = Set.member v read
+
+ writeNode :: FNode m (Maybe Decl, Vars) -> Set.Set Var
+ writeNode (Node (_,(_,Vars _ written _),_)) = written
+
+ -- | A confusiing function used by processNode. It takes a node and node label, and uses
+ -- these to form a multi-map modifier function that replaces all node-sources for variables
+ -- written to by the given with node with a singleton set containing the given node.
+ -- That is, nodeLabelToMapInsert N (Node (_,Vars _ written _ _)) is a function that replaces
+ -- the sets for each v (v in written) with a singleton set {N}.
+ nodeLabelToMapInsert :: Node -> FNode m (Maybe Decl, Vars) -> Map.Map Var (Set.Set Node) -> Map.Map Var (Set.Set Node)
+ nodeLabelToMapInsert n = foldFuncs . (map (\v -> Map.insert v (Set.singleton n) )) . Set.toList . writeNode
+
+ processNode :: (Node, EdgeLabel) -> Map.Map Var (Set.Set Node) -> Maybe (Map.Map Var (Set.Set Node)) -> Map.Map Var (Set.Set Node)
+ processNode (n,_) inputVal mm = mergeMultiMaps modifiedInput prevAgg
+ where
+ prevAgg :: Map.Map Var (Set.Set Node)
+ prevAgg = fromMaybe Map.empty mm
+
+ modifiedInput :: Map.Map Var (Set.Set Node)
+ modifiedInput = (maybe id (nodeLabelToMapInsert n) $ lab graph n) inputVal
+
+ -- | Merges two "multi-maps" (maps to sets) using union
+ mergeMultiMaps :: (Ord k, Ord a) => Map.Map k (Set.Set a) -> Map.Map k (Set.Set a) -> Map.Map k (Set.Set a)
+ mergeMultiMaps = Map.unionWith (Set.union)
diff --git a/checks/UsageCheckUtils.hs b/checks/UsageCheckUtils.hs
index 5792781..189d181 100644
--- a/checks/UsageCheckUtils.hs
+++ b/checks/UsageCheckUtils.hs
@@ -16,20 +16,16 @@ You should have received a copy of the GNU General Public License along
with this program. If not, see .
-}
-module UsageCheckUtils (checkPar, customVarCompare, Decl(..), emptyVars, getVarProc, joinCheckParFunctions, labelFunctions, ParItems(..), transformParItems, Var(..), Vars(..), vars) where
+module UsageCheckUtils (customVarCompare, Decl(..), emptyVars, getVarProc, labelFunctions, ParItems(..), transformParItems, Var(..), Vars(..), vars) where
import Data.Generics hiding (GT)
-import Data.Graph.Inductive
-import qualified Data.Map as Map
import Data.Maybe
import qualified Data.Set as Set
import qualified AST as A
import Errors
import FlowGraph
-import Metadata
import ShowCode
-import Utils
newtype Var = Var A.Variable deriving (Show)
@@ -98,72 +94,6 @@ foldUnionVars = foldl unionVars emptyVars
mapUnionVars :: (a -> Vars) -> [a] -> Vars
mapUnionVars f = foldUnionVars . (map f)
-
-joinCheckParFunctions :: Monad m => ((Meta, ParItems a) -> m b) -> ((Meta, ParItems a) -> m c) -> ((Meta, ParItems a) -> m (b,c))
-joinCheckParFunctions f g x = seqPair (f x, g x)
-
--- | Given a function to check a list of graph labels and a flow graph,
--- returns a list of monadic actions (slightly
--- more flexible than a monadic action giving a list) that will check
--- all PAR items in the flow graph
-checkPar :: forall m a b. Monad m => ((Meta, ParItems a) -> m b) -> FlowGraph m a -> [m b]
-checkPar f g = map f allParItems
- where
- allStartParEdges :: Map.Map Int [(Node,Node)]
- allStartParEdges = foldl (\mp (s,e,n) -> Map.insertWith (++) n [(s,e)] mp) Map.empty $ mapMaybe tagStartParEdge $ labEdges g
-
- tagStartParEdge :: (Node,Node,EdgeLabel) -> Maybe (Node,Node,Int)
- tagStartParEdge (s,e,EStartPar n) = Just (s,e,n)
- tagStartParEdge _ = Nothing
-
- allParItems :: [(Meta, ParItems a)]
- allParItems = map makeEntry $ map findNodes $ Map.toList allStartParEdges
- where
- findNodes :: (Int,[(Node,Node)]) -> (Node,[ParItems a])
- findNodes (n,ses) = (undefined, [SeqItems (followUntilEdge e (EEndPar n)) | (_,e) <- ses])
-
- makeEntry :: (Node,[ParItems a]) -> (Meta, ParItems a)
- makeEntry (_,xs) = (emptyMeta {- TODO fix this again -} , ParItems xs)
-
- -- | We need to follow all edges out of a particular node until we reach
- -- an edge that matches the given edge. So what we effectively need
- -- is a depth-first or breadth-first search (DFS or BFS), that terminates
- -- on a given edge, not on a given node. Therefore the DFS/BFS algorithms
- -- that come with the inductive graph package are not very suitable as
- -- they return node lists or edge lists, but we need a node list terminated
- -- on a particular edge.
- --
- -- So, we shall attempt our own algorithm! The algorithm for DFS given in
- -- the library is effectively:
- --
- -- dfs :: Graph gr => [Node] -> gr a b -> [Node]
- -- dfs [] _ = []
- -- dfs _ g | isEmpty g = []
- -- dfs (v:vs) g = case match v g of
- -- (Just c,g') -> node' c:dfs (suc' c++vs) g'
- -- (Nothing,g') -> dfs vs g'
- -- where node' :: Context a b -> Node and suc' :: Context a b -> [Node]
- --
- -- We want to stop the DFS branch either when we find no nodes following the current
- -- one (already effectively taken care of in the algorithm above; suc' will return
- -- the empty list) or when the edge we are meant to take matches the given edge.
- followUntilEdge :: Node -> EdgeLabel -> [a]
- followUntilEdge startNode endEdge = customDFS [startNode] g
- where
- customDFS :: [Node] -> FlowGraph m a -> [a]
- customDFS [] _ = []
- customDFS _ g | isEmpty g = []
- customDFS (v:vs) g = case match v g of
- (Just c, g') -> labelItem c : customDFS (customSucc c ++ vs) g'
- (Nothing, g') -> customDFS vs g'
-
- labelItem :: Context (FNode m a) EdgeLabel -> a
- labelItem c = let (Node (_,x,_)) = lab' c in x
-
- customSucc :: Context (FNode m a) EdgeLabel -> [Node]
- customSucc c = [n | (n,e) <- lsuc' c, e /= endEdge]
-
-
--Gets the (written,read) variables of a piece of an occam program:
--For subscripted variables used as Lvalues , e.g. a[b] it should return a[b] as written-to and b as read