apple-0.1.0.0: src/C/CF.hs
module C.CF ( cfC ) where
import C
import CF
import CF.AL
-- seems to pretty clearly be faster
import Control.Monad.State.Strict (State, evalState, gets, modify, state)
import Data.Bifunctor (first)
import Data.Functor (($>))
import qualified Data.IntMap as IM
import qualified Data.IntSet as IS
import Data.List (uncons)
import qualified Data.Map as M
import Data.Tuple.Extra (second3, snd3, thd3, third3)
type N=Int
-- map of labels by node
type FreshM = State (N, M.Map Label N, M.Map Label [N])
runFreshM :: FreshM a -> a
runFreshM = flip evalState (0, mempty, mempty)
cfC :: [CS ()] -> ([N], [CS ControlAnn], IM.IntMap (ControlAnn, Liveness))
cfC cs = let cfs = mkControlFlow cs in (inspectOrder cfs, cfs, initLiveness cfs)
mkControlFlow :: [CS ()] -> [CS ControlAnn]
mkControlFlow instrs = runFreshM (brs instrs *> addCF instrs)
getFresh :: FreshM N
getFresh = state (\(i,m0,m1) -> (i,(i+1,m0,m1)))
fm :: Label -> FreshM N
fm l = do {i <- getFresh; br i l $> i}
ll :: Label -> FreshM N
ll l = gets (M.findWithDefault (error "Internal error in control-flow graph: node label not in map.") l . snd3)
lC :: Label -> FreshM [N]
lC l = gets (M.findWithDefault (error "Internal error in CF graph: node label not in map.") l . thd3)
br :: N -> Label -> FreshM ()
br i l = modify (second3 (M.insert l i))
b3 :: N -> Label -> FreshM ()
b3 i l = modify (third3 (M.alter (\k -> Just$case k of {Nothing -> [i]; Just is -> i:is}) l))
mC :: ([N] -> [N]) -> ControlAnn -> ControlAnn
mC f (ControlAnn l ds udϵ) = ControlAnn l (f ds) udϵ
unsnoc :: [a] -> ([a], a)
unsnoc [x] = ([], x)
unsnoc (x:xs) = first (x:) $ unsnoc xs
unsnoc _ = error "Internal error: unsnoc called on empty list."
emptyL :: Liveness
emptyL = Liveness IS.empty IS.empty IS.empty IS.empty
initLiveness :: [CS ControlAnn] -> IM.IntMap (ControlAnn, Liveness)
initLiveness = IM.fromList . go where
go [] = []
go (For ann _ _ _ _ ss:cs) = (node ann, (ann, emptyL)):go ss++go cs
go (For1 ann _ _ _ _ ss:cs) = (node ann, (ann, emptyL)):go ss++go cs
go (While ann _ _ _ ss:cs) = (node ann, (ann, emptyL)):go ss++go cs
go (If ann _ ss ss':cs) = (node ann, (ann, emptyL)):go ss++go ss'++go cs
go (Ifn't ann _ ss:cs) = (node ann, (ann, emptyL)):go ss++go cs
go (Def ann _ ss:cs) = (node ann, (ann, emptyL)):go ss++go cs
go (c:cs) = let x=lann c in (node x, (x, emptyL)):go cs
inspectOrder :: [CS ControlAnn] -> [N]
inspectOrder (For ann _ _ _ _ ss:cs) = node ann:inspectOrder ss++inspectOrder cs
inspectOrder (For1 ann _ _ _ _ ss:cs) = node ann:inspectOrder ss++inspectOrder cs
inspectOrder (While ann _ _ _ ss:cs) = node ann:inspectOrder ss++inspectOrder cs
inspectOrder (If ann _ ss ss':cs) = node ann:inspectOrder ss++inspectOrder ss'++inspectOrder cs
inspectOrder (Ifn't ann _ ss:cs) = node ann:inspectOrder ss++inspectOrder cs
inspectOrder (Def ann _ ss:cs) = node ann:inspectOrder ss++inspectOrder cs
inspectOrder (c:cs) = node (lann c):inspectOrder cs
inspectOrder [] = []
tieBranch :: ([N] -> [N]) -> [CS ()] -> FreshM ([N] -> [N], [CS ControlAnn])
tieBranch f ss = do
preSs <- addCF ss
pure $ case uncons preSs of
Just (i1, _) ->
let hi=node (lann i1)
(ss',l) = unsnoc preSs
l' = fmap (mC f) l
ss'' = ss'++[l']
in ((hi:), ss'')
Nothing -> (id, preSs)
tieBody :: N -> ([N] -> [N]) -> [CS ()] -> FreshM ([N] -> [N], [CS ControlAnn])
tieBody h f ss = do
preSs <- addCF ss
case uncons preSs of
Just (i1, _) ->
let hi=node (lann i1)
(ss',l) = unsnoc preSs
l'=fmap (mC ((h:).f)) l
ss''=ss'++[l']
in pure ((hi:), ss'')
Nothing -> pure (id, [])
-- | Pair 'CS with a unique node name and a list of all possible
-- destinations.
addCF :: [CS ()] -> FreshM [CS ControlAnn]
addCF [] = pure []
addCF ((Def _ l ss):stmts) = do
i <- ll l
nextStmts <- addCF stmts
preSs <- addCF ss
case uncons preSs of
Nothing -> undefined
Just (h, _) ->
let hi=node (lann h)
(ss',lϵ) = unsnoc preSs
in do
l_is <- lC l
let l'= fmap (mC (const l_is)) lϵ
ss''=ss'++[l']
pure (Def (ControlAnn i [hi] (UD IS.empty IS.empty IS.empty IS.empty)) l ss'':nextStmts)
addCF (G _ l r:stmts) = do
i <- ll r
nextStmts <- addCF stmts
l_i <- ll l
pure (G (ControlAnn i [l_i] (UD IS.empty IS.empty IS.empty IS.empty)) l r:nextStmts)
addCF ((For _ t el c eu ss):stmts) = do
i <- getFresh
(f, stmts') <- next stmts
(h, ss') <- tieBody i f ss
pure $ For (ControlAnn i (f (h [])) udϵ) t el c eu ss':stmts'
where
udϵ = UD (uE el<>uE eu) IS.empty IS.empty IS.empty
addCF ((For1 _ t el c eu ss):stmts) = do
i <- getFresh
(f, stmts') <- next stmts
(h, ss') <- tieBody i f ss
pure $ For1 (ControlAnn i (f (h [])) udϵ) t el c eu ss':stmts'
where
udϵ = UD (uE el<>uE eu) IS.empty IS.empty IS.empty
addCF ((While _ t c ed ss):stmts) = do
i <- getFresh
(f, stmts') <- next stmts
(h, ss') <- tieBody i f ss
pure $ While (ControlAnn i (f (h [])) udϵ) t c ed ss':stmts'
where
udϵ = UD (uE ed) IS.empty IS.empty IS.empty
addCF (If _ p b0 b1:stmts) = do
i <- getFresh
(f, stmts') <- next stmts
(h0, b0') <- tieBranch f b0
(h1, b1') <- tieBranch f b1
pure $ If (ControlAnn i (f (h0 (h1 []))) udϵ) p b0' b1':stmts'
where
udϵ = UD (uB p) IS.empty IS.empty IS.empty
addCF (Ifn't _ p b:stmts) = do
i <- getFresh
(f, stmts') <- next stmts
(h, b') <- tieBranch f b
pure $ Ifn't (ControlAnn i (f (h [])) udϵ) p b':stmts'
where
udϵ = UD (uB p) IS.empty IS.empty IS.empty
addCF (stmt:stmts) = do
i <- getFresh
(f, stmts') <- next stmts
pure ((stmt $> ControlAnn i (f []) (UD (uses stmt) IS.empty (defs stmt) IS.empty)):stmts')
uE :: CE -> IS.IntSet
uE ConstI{} = IS.empty
uE LA{} = IS.empty
uE (EAt a) = uA a
uE Tmp{} = IS.empty
uE (Bin _ e0 e1) = uE e0<>uE e1
uE (CFloor e0) = uF e0
uE (DP _ e) = uE e
uF :: CFE -> IS.IntSet
uF ConstF{} = IS.empty
uF FTmp{} = IS.empty
uF (FAt a) = uA a
uF (FUn _ e) = uF e
uF (FBin _ e0 e1) = uF e0<>uF e1
uF (IE e) = uE e
m'insert (Just l) a = sinsert l a
m'insert Nothing a = a
uA (ARnk _ (Just l)) = singleton l
uA (ARnk _ Nothing) = IS.empty
uA (ADim _ d l) = m'insert l $ uE d
uA (TupM _ (Just l)) = singleton l
uA (TupM _ Nothing) = IS.empty
uA (AElem _ r ei l _) = m'insert l (uE r<>uE ei)
uA (Raw _ e l _) = m'insert l (uE e)
uA (At _ ss ixs l _) = m'insert l (foldMap uE ss<>foldMap uE ixs)
uses :: CS a -> IS.IntSet
uses (Ma _ _ _ r n _) = uE r<>uE n
uses (MaΠ _ _ _ n) = uE n
uses (MX _ _ e) = uF e
uses (Wr _ a e) = uA a <> uE e
uses (RA _ l) = singleton l
uses (Cmov _ e0 _ e1) = uB e0<>uE e1
uses (Fcmov _ e0 _ e1) = uB e0<>uF e1
uses (WrF _ a e) = uA a <> uF e
uses (Cset _ e _) = uB e
uses (MT _ _ e) = uE e
uses (MB _ _ e) = uB e
uses (WrP _ a e) = uA a<>uB e
uses Rnd{} = IS.empty
uses FRnd{} = IS.empty
uses (PlProd _ _ es) = foldMap uE es
uses (SZ _ _ _ e (Just l)) = sinsert l (uE e)
uses (SZ _ _ _ e Nothing) = uE e
uses (Pop _ e) = uE e
uses (Sa _ _ e) = uE e
uses (CpyD _ d s n) = uA d<>uA s<>uE n
uses (CpyE _ d s n _) = uA d<>uA s<>uE n
uB :: PE -> IS.IntSet
uB (PAt a) = uA a
uB BConst{} = IS.empty
uB (IRel _ e0 e1) = uE e0<>uE e1
uB (FRel _ e0 e1) = uF e0<>uF e1
uB (Boo _ e0 e1) = uB e0<>uB e1
uB (IUn _ e) = uE e
uB Is{} = IS.empty
uB (BU _ e) = uB e
defs :: CS a -> IS.IntSet
defs (Ma _ a _ _ _ _) = singleton a
defs (MaΠ _ a _ _) = singleton a
defs _ = IS.empty
next :: [CS ()] -> FreshM ([N] -> [N], [CS ControlAnn])
next stmts = do
nextStmts <- addCF stmts
case nextStmts of
[] -> pure (id, [])
(stmt:_) -> pure ((node (lann stmt) :), nextStmts)
-- | Construct map assigning labels to their node name.
brs :: [CS ()] -> FreshM ()
brs [] = pure ()
brs (G _ l retL:stmts) = do {i <- fm retL; b3 i l; brs stmts}
brs (Def _ f b:stmts) = fm f *> brs b *> brs stmts
brs (For _ _ _ _ _ ss:stmts) = brs ss *> brs stmts
brs (For1 _ _ _ _ _ ss:stmts) = brs ss *> brs stmts
brs (While _ _ _ _ ss:stmts) = brs ss *> brs stmts
brs (If _ _ ss ss':stmts) = brs ss *> brs ss' *> brs stmts
brs (Ifn't _ _ ss:stmts) = brs ss *> brs stmts
brs (_:asms) = brs asms