{-# LANGUAGE Strict #-}
module Futhark.Analysis.UsageTable
( UsageTable
, empty
, contains
, without
, lookup
, keys
, used
, expand
, isConsumed
, isInResult
, isUsedDirectly
, allConsumed
, usages
, usage
, consumedUsage
, inResultUsage
, Usages
, leftScope
)
where
import Control.Arrow (first)
import Data.Bits
import qualified Data.Foldable as Foldable
import Data.List (foldl')
import qualified Data.Map.Strict as M
import qualified Data.Set as S
import Prelude hiding (lookup)
import Futhark.Transform.Substitute
import Futhark.Representation.AST
newtype UsageTable = UsageTable (M.Map VName Usages)
deriving (Eq, Show)
instance Semigroup UsageTable where
UsageTable table1 <> UsageTable table2 =
UsageTable $ M.unionWith (<>) table1 table2
instance Monoid UsageTable where
mempty = empty
instance Substitute UsageTable where
substituteNames subst (UsageTable table)
| not $ M.null $ subst `M.intersection` table =
UsageTable $ M.fromList $
map (first $ substituteNames subst) $ M.toList table
| otherwise = UsageTable table
empty :: UsageTable
empty = UsageTable M.empty
contains :: UsageTable -> [VName] -> Bool
contains (UsageTable table) = Foldable.any (`M.member` table)
without :: UsageTable -> [VName] -> UsageTable
without (UsageTable table) = UsageTable . Foldable.foldl (flip M.delete) table
lookup :: VName -> UsageTable -> Maybe Usages
lookup name (UsageTable table) = M.lookup name table
lookupPred :: (Usages -> Bool) -> VName -> UsageTable -> Bool
lookupPred f name = maybe False f . lookup name
used :: VName -> UsageTable -> Bool
used = lookupPred $ const True
expand :: (VName -> Names) -> UsageTable -> UsageTable
expand look (UsageTable m) = UsageTable $ foldl' grow m $ M.toList m
where grow m' (k, v) = foldl' (grow'' $ v `withoutU` presentU) m' $ look k
grow'' v m'' k = M.insertWith (<>) k v m''
keys :: UsageTable -> [VName]
keys (UsageTable table) = M.keys table
is :: Usages -> VName -> UsageTable -> Bool
is = lookupPred . matches
isConsumed :: VName -> UsageTable -> Bool
isConsumed = is consumedU
isInResult :: VName -> UsageTable -> Bool
isInResult = is inResultU
isUsedDirectly :: VName -> UsageTable -> Bool
isUsedDirectly = is presentU
allConsumed :: UsageTable -> Names
allConsumed (UsageTable m) =
S.fromList . map fst . filter (matches consumedU . snd) $ M.toList m
usages :: Names -> UsageTable
usages names = UsageTable $ M.fromList [ (name, presentU) | name <- S.toList names ]
usage :: VName -> Usages -> UsageTable
usage name uses = UsageTable $ M.singleton name uses
consumedUsage :: VName -> UsageTable
consumedUsage name = UsageTable $ M.singleton name consumedU
inResultUsage :: VName -> UsageTable
inResultUsage name = UsageTable $ M.singleton name inResultU
newtype Usages = Usages Int
deriving (Eq, Ord, Show)
instance Semigroup Usages where
Usages x <> Usages y = Usages $ x .|. y
instance Monoid Usages where
mempty = Usages 0
consumedU, inResultU, presentU :: Usages
consumedU = Usages 1
inResultU = Usages 2
presentU = Usages 4
matches :: Usages -> Usages -> Bool
matches (Usages x) (Usages y) = x == (x .&. y)
withoutU :: Usages -> Usages -> Usages
withoutU (Usages x) (Usages y) = Usages $ x .&. complement y
leftScope :: UsageTable -> UsageTable
leftScope (UsageTable table) = UsageTable $ M.map (`withoutU` inResultU) table