alpha-0.9.9: src/Specialize.hs
{-# LANGUAGE RankNTypes, ParallelListComp, TupleSections #-}
module Specialize(specialize) where
import Data.Monoid
import Control.Arrow
import Context.Types
import Control.Monad.Trans.Reader
import Data.Array
import Data.List
import Data.Maybe
import Data.Word
import Data.Ord
import qualified Data.ByteString as B
import qualified Data.Map as M
import qualified Data.Relation as R
import qualified Data.Set as S
import ID
import My.Control.Monad
import My.Control.Monad.State
import My.Control.Monad.TimeLine
import My.Data.Either
import My.Data.Tree
import PCode
import Specialize.Architecture
import Specialize.Architecture
import Specialize.Types
import System.IO.Unsafe
import My.Prelude
retCode = ret
where ret = [0xc3]
exit = [0x31,0xdb
,0x31,0xc0, 0xff,0xc0
,0xcd,0x80]
sums = scanl (+) 0
specialize arch assoc (Code args code retVar) = foo
where
foo = (sum sizes,B.concat $< sequence codes)
-- foo = (length retCode, return (B.pack retCode))
(estimates,sizes,codes) = unzip3 [v | Right (_,v) <- elems instructions]
(past,future) = archInitials arch args retVar
(bounds,instr,nexts,prevs) = navigate code
positions = listArray bounds [(e,s) | e <- sums estimates, s <- sums sizes]
codeTree = spanningTree 0 nexts
runInstr i (p,f) past = runTimeLine (runReaderT (compile $ instr i) ((infos!i) getPos)) (p,f)
where compile = archCompileInstr arch
getPos j = (e'-e,d'-d,past j)
where (e,d) = positions!i ; (e',d') = positions!j
treeArray next seed = ret
where assocs = (0,seed):concatMap f (nodeList codeTree)
ret = array bounds assocs
f (Node i subs) = [(j,next j (ret!i) (instr j)) | Node j _ <- subs]
instructions = execState (specializeTree past codeTree) initialArray
where
specializeTree p (Node i subs) = gets ((!i) >>> fromLeft) >>= \f -> do
past <- gets (!)
let newVal@(p',_,vals) = runInstr i (p,f) (either (const Nothing) (Just . fst) . past)
modify (// [(i,Right (p,vals))])
mapM_ (specializeTree p') subs
initialArray = fmap Left init
where init = array bounds (concatMap f $ branches codeTree)
f br = (n,fut):[(i,snd3 $ runInstr j (undefined,init!j) (const Nothing)) | (i,j) <- zip br (tail br)]
where n = last br ; fut = if null (nexts n) then future else emptyFuture
infos = constA bounds (Info assoc) `applyA` bindingsA `applyA` activesA `applyA` clobbersA
where parent i v = fmap fst $ M.lookup v (bindingsA!i)
bindingsA = treeArray next M.empty
where next _ bnd (Bind bv (Just id)) = foldl (\m (k,v) -> M.insert k v m) bnd
[(s,(id,n)) | (s,n,_) <- flattenBind (archDefaultSize arch) bv]
next _ bnd _ = bnd
activesA = saturate fun prevs nexts init start
where init = accumArray const S.empty bounds []
start = concat [prevs i | i <- indices init, isRet (instr i)]
fun i a = addActives (instr i) $ S.unions (map (a!) (nexts i))
where addActives (Op _ v vs) s = (s S.\\ clobbers i v)
<> S.unions [clobbers i s' | SymVal Value s <- vs
, s' <- s:maybeToList (parent i s)]
<> maybe S.empty (clobbers i) (parent i v)
addActives (Branch (SymVal Value id) _) s = s <> clobbers i id
addActives (Bind bv v) s = maybe id S.insert v $ s S.\\ S.fromList (bindSyms bv)
addActives _ s = s
clobbers i v = fromMaybe (S.singleton v) $ R.lookupRan v (clobbersA!i)
clobbersA = treeArray next (foldl (next undefined) R.empty [Bind bv Nothing | bv <- retVar:args])
where next i r (Bind bv v) = insertManyR r' assocs
where r' = restrict r (S.fromList (bindSyms bv))
assocs = [ass | bv <- bindNodes bv
, s <- bindSyms bv
, ass <- [(bindSym bv,s),(s,bindSym bv)]]
++[ass | v <- maybeToList v
, ref <- S.toList $ references i v
, s <- maybe [v] S.toList (R.lookupRan ref r')
, ass <- [(s,ref),(ref,s)]]
next _ r _ = r
lookupRefs v r = fromMaybe (S.singleton (ID (-1))) $ R.lookupRan v r
references i v = lookupRefs v (referencesA!i)
referencesA = treeArray next R.empty
where next i r (Op _ v vs) = insertManyR r' (map (v,) $ S.toList refs)
where r' = S.delete v (R.dom r) R.<| r
refs = S.fromList [s | SymVal Address s <- vs]
<> S.unions [lookupRefs v r | SymVal Value s <- vs]
next _ r (Bind bv _) = restrict r (S.fromList (bindSyms bv))
next _ r _ = r
restrict r s = (R.dom r S.\\ s) R.<| r R.|> (R.ran r S.\\ s)
constA bs v = accumArray const v bs []
zipWithA f a b = array (bounds a) [(i,f x y) | (i,x) <- assocs a | y <- elems b]
applyA = zipWithA ($)
insertManyR = foldl (\r (a,b) -> R.insert a b r)
saturate fun nexts prevs init start = f init (array (bounds init) [(i,length $ prevs i) | i <- indices init]) start
where f a d [] = a
f a d (i:t) | newElt == a!i = f a d t
| otherwise = f (a//[(i,newElt)]) d'' (foldr (insertBy (comparing (d''!))) (filter (/=i) t) (nexts i))
where newElt = fun i a
d' = d // [(i,length $ (prevs`asTypeOf`nexts) i)]
d'' = d' // [(n,(d'!n)-1) | n <- nexts i]