packages feed

apple-0.2.0.0: src/IR/Hoist.hs

{-# LANGUAGE TupleSections #-}

module IR.Hoist ( loop, hoist, pall ) where

import           CF
import           Control.Composition        (thread)
import           Control.Monad.State.Strict (gets, modify, runState)
import qualified Data.Array                 as A
import           Data.Bifunctor             (bimap, first, second)
import           Data.Functor               (($>))
import           Data.Graph                 (Tree (Node))
import           Data.Graph.Dom             (Graph, Node, domTree)
import qualified Data.IntMap                as IM
import qualified Data.IntSet                as IS
import qualified Data.Map.Strict            as M
import           Data.Maybe                 (catMaybes, fromJust, fromMaybe)
import           Data.Tuple.Extra           (first3, snd3)
import           IR
import           IR.CF
import           LR

type N=Int

mapFA :: (FTemp -> FTemp) -> AE -> AE
mapFA f (AP t (Just e) l) = AP t (Just$mapFE f e) l
mapFA _ a                 = a

mapFE :: (FTemp -> FTemp) -> Exp -> Exp
mapFE f (IRFloor x)      = IRFloor (mapFF f x)
mapFE f (EAt a)          = EAt (mapFA f a)
mapFE f (BAt a)          = BAt (mapFA f a)
mapFE _ e@ConstI{}       = e
mapFE _ e@Reg{}          = e
mapFE _ e@Is{}           = e
mapFE f (FRel rel x0 x1) = FRel rel (mapFF f x0) (mapFF f x1)
mapFE f (IB op e0 e1)    = IB op (mapFE f e0) (mapFE f e1)
mapFE f (IU op e)        = IU op (mapFE f e)
mapFE f (BU op e)        = BU op (mapFE f e)
mapFE f (IRel rel e0 e1) = IRel rel (mapFE f e0) (mapFE f e1)
mapFE _ e@LA{}           = e

mapFF :: (FTemp -> FTemp) -> FExp -> FExp
mapFF _ x@ConstF{}    = x
mapFF f (FAt a)       = FAt (mapFA f a)
mapFF f (FB op e0 e1) = FB op (mapFF f e0) (mapFF f e1)
mapFF f (FU op e)     = FU op (mapFF f e)
mapFF f (FReg r)      = FReg (f r)
mapFF f (FConv e)     = FConv (mapFE f e)

mapF :: (FTemp -> FTemp) -> Stmt -> Stmt
mapF f (MX t e)       = MX (f t) (mapFF f e)
mapF _ s@L{}          = s
mapF _ s@C{}          = s
mapF _ s@R{}          = s
mapF _ s@IRnd{}       = s
mapF f (FRnd t)       = FRnd (f t)
mapF _ s@J{}          = s
mapF _ s@Free{}       = s
mapF _ s@RA{}         = s
mapF f (MT t e)       = MT t (mapFE f e)
mapF f (Wr a e)       = Wr (mapFA f a) (mapFE f e)
mapF f (WrF a x)      = WrF (mapFA f a) (mapFF f x)
mapF f (WrB a e)      = WrB (mapFA f a) (mapFE f e)
mapF f (Fcmov e t x)  = Fcmov (mapFE f e) (f t) (mapFF f x)
mapF f (MJ e l)       = MJ (mapFE f e) l
mapF f (Ma l t e)     = Ma l t (mapFE f e)
mapF f (Sa t e)       = Sa t (mapFE f e)
mapF f (Pop e)        = Pop (mapFE f e)
mapF f (Cpy a0 a1 e)  = Cpy (mapFA f a0) (mapFA f a1) (mapFE f e)
mapF f (Cpy1 a0 a1 e) = Cpy1 (mapFA f a0) (mapFA f a1) (mapFE f e)
mapF f (Cmov p t e)   = Cmov (mapFE f p) t (mapFE f e)
mapF f (Cset t p)     = Cset t (mapFE f p)

type Loop = (N, IS.IntSet)

-- TODO: array?
lm :: [(Stmt, NLiveness)] -> IM.IntMap NLiveness
lm = IM.fromList.fmap (\(_,n) -> (nx n, n))

hl :: (Loop, A.Array Int (Stmt, ControlAnn), IM.IntMap NLiveness) -> [(N, N, (FTemp, Double))]
hl ((n,ns), info, linfo) = go ss
  where
    lH=liveness (gN n linfo)
    fliveInH=fins lH
    go ((MX x (ConstF i), a):ssϵ) | fToInt x `IS.notMember` fliveInH && notFDef x (node a) = (n, node a, (x,i)):go ssϵ
    go (_:ssϵ)                      = go ssϵ
    go []                           = []
    otherDefFs nL = defsFNode.ud.snd.(info A.!)<$>IS.toList(IS.delete nL ns)
    notFDef r nL = not $ any (fToInt r `IS.member`) (otherDefFs nL)
    ss = (info A.!)<$>IS.toList ns
    gN = IM.findWithDefault (error "internal error: node not in map.")

pall :: [Stmt] -> [Stmt]
pall ss =
    let ss' = fmap (second node) cf
        (s, ss'') = go ss'
    in {-# SCC "applySubst" #-} applySubst s ss''
  where
    go ((_,n):ssϵ) | n `IS.member` dels = go ssϵ
    go ((s,n):ssϵ) | Just cs <- IM.lookup n is = let (css, (_, subst)) = {-# SCC "consolidate" #-} consolidate cs in bimap (subst<>) ((css++[s])++) (go ssϵ)
    go ((s,_):ssϵ) = second (s:)$go ssϵ
    go [] = (M.empty, [])
    (cf, is, dels) = indels ss
    applySubst s = fmap (mapF (\t -> fromMaybe t (M.lookup t s)))
    consolidate = first catMaybes . flip runState (M.empty, M.empty) . traverse (\(t,x) -> do
        seen <- gets fst
        case M.lookup x seen of
            Nothing -> modify (first (M.insert x t)) $> Just (MX t (ConstF x))
            Just r  -> modify (second (M.insert t r)) $> Nothing)

indels :: [Stmt] -> ([(Stmt, ControlAnn)], IM.IntMap [(FTemp, Double)], IS.IntSet)
indels ss = (c, is IM.empty, ds)
  where
    (c,h) = hs ss
    ds = IS.fromList (snd3<$>h)
    go n s = IM.alter (\d -> case d of {Nothing -> Just [s]; Just ssϵ -> Just$s:ssϵ}) n
    is = thread ((\(n,_,s) -> go n s)<$>h)

hs :: [Stmt] -> ([(Stmt, ControlAnn)], [(N, N, (FTemp, Double))])
hs ss = let (ls, cf, dm) = loop ss
            mm = lm (reconstructFlat cf)
     in (cf, concatMap (\l -> hl (l,dm,mm)) (ols ls))

loop :: [Stmt] -> ([Loop], [(Stmt, ControlAnn)], A.Array Int (Stmt, ControlAnn))
loop = first3 (fmap mkL).(\(w,x,y,z) -> (et w (fmap fst z) [] x,y,z)).hoist
  where
    mkL (n, ns) = (n, IS.fromList ns)

hoist :: [Stmt] -> (Graph, Tree N, [(Stmt, ControlAnn)], A.Array Int (Stmt, ControlAnn))
hoist ss = (\ssϵ -> (\(x,y,z,_) -> (x,y,fst ssϵ,z))$mkG ssϵ) (mkControlFlow ss)

{-# SCC ols #-}
ols :: [Loop] -> [Loop]
ols ls = filter (\(_,ns) -> not $ any (\(_,ns') -> ns `IS.isSubsetOf` ns') ls) ls

et :: Graph -> A.Array Int Stmt -> [N] -> Tree N -> [(N, [N])]
et g ss seen t = expandLoop t <$> tLoops g ss seen t

{-# SCC expandLoop #-}
expandLoop :: Tree N -> (N,N) -> (N,[N])
-- wir müssen wissen, wir werden wissen
expandLoop t se = fromJust (go [] se t)
  where
    go seen (s,e) (Node n _) | e == n = Just (s, dropWhile (/=s) (reverse seen))
    go _ _ (Node _ [])       = Nothing
    go seen seϵ (Node n ns)  = mh (go (n:seen) seϵ <$> ns) where mh xs=case catMaybes xs of {[] -> Nothing; (nϵ:_) -> Just nϵ}

tLoops :: Graph -> A.Array Int Stmt -> [N] -> Tree N -> [(N, N)]
tLoops g ss seen (Node n cs) =
    let bes=filter (hasEdge g n) seen
    in (if isMJ n then (fmap (,n) bes++) else id) $ concatMap (tLoops g ss (n:seen)) cs
  where
    isMJ nϵ = p (ss A.! nϵ)
    p MJ{}=True; p _=False

hasEdge :: Graph -> Node -> Node -> Bool
hasEdge g n0 n1 = case IM.lookup n0 g of {Nothing -> False; Just ns -> n1 `IS.member` ns}

mkG :: ([(Stmt, ControlAnn)], Int) -> (Graph, Tree N, A.Array Int (Stmt, ControlAnn), IM.IntMap (Stmt, ControlAnn))
mkG (ns,m) = (domG, domTree (node (snd (head ns)), domG), sa, IM.fromList ((\(s, ann) -> (node ann, (s, ann)))<$>ns))
  where
    domG = IM.fromList [ (node ann, IS.fromList (conn ann)) | (_, ann) <- ns ]
    sa = A.listArray (0,m-1) ns