alpha-0.9.9.5: src/PCode/Instruction.hs
{-# LANGUAGE ViewPatterns, ParallelListComp #-}
module PCode.Instruction where
import Control.Monad.State
import Data.List
import Data.Maybe
import Data.Array
import My.Data.Tree
import qualified Data.Set as S
import PCode.Builtin
import PCode.Value
import ID
type Addr = Int
data BindVar = BindVar {
bindSym :: ID,
bindSize :: (Int,Int),
bindPad :: Int,
bindSubs :: [(BindVar,Int)]
}
data Instruction = Op Builtin ID [Value]
| Branch Value [Addr]
| Bind BindVar (Maybe ID)
| Noop
data Code = Code [BindVar] [Instruction] BindVar
deriving Show
isNoop Noop = True
isNoop _ = False
isBranch (Branch _ _) = True
isBranch _ = False
bindSyms bv = bindSym bv : concatMap bindSyms (map fst $ bindSubs bv)
bindNodes bv = bv:map fst (bindSubs bv)
symBind s = BindVar s (0,1) 0 []
instrVals (Op _ _ vs) = vs
instrVals (Bind _ v) = map (SymVal Value) $ maybeToList v
instrVals (Branch v _) = [v]
instrVals _ = []
instrVars (Op _ v _) = [v]
instrVars (Bind v _) = bindSyms v
instrVars _ = []
flattenBind def = flatten
where sizeOf (bindSize -> (s,sr)) = s+sr*def
flatten bv@(BindVar s _ p subs) = (s,0,sizeOf bv):concat [
[(s,n+n0,sz) | (s,n,sz) <- flatten bv]
| (bv,_) <- subs
| n0 <- scanl (+) p [n*sizeOf bv | (bv,n) <- subs]]
set v val = Op BSet v [val]
call v f args = Op BCall v (f:args)
ret = Branch NullVal []
isRet (Branch NullVal []) = True
isRet _ = False
concatCode c1 [] = c1
concatCode c1 c2 = map (f g1) c1 ++ map (f g2) c2
where f g (Branch v as) = Branch v (g as)
f _ i = i
g1 as = if null as then [l] else as
g2 as = map (l+) as
l = length c1
navigate code = (bs,instr,nexts,prevs)
where bs@(bMin,bMax) = (0,length code-1)
instr n = listArray bs code!n
nexts (instr -> Branch _ l) = l
nexts n = [n+1]
prevs n = accumArray (flip (:)) [] bs [(n,i) | i <- [bMin..bMax], n <- nexts i] ! n
spanArray bs tree = array bs (assocs Nothing tree)
where assocs p (Node a subs) = (a,(p,map rootLabel subs)):concatMap (assocs (Just a)) subs
codeRefs (Code args code ret) = refs code (bindSyms ret++concatMap bindSyms args)
where refs code local = traverse (S.fromList local) (spanningTree 0 nexts)
where (_,instr,nexts,_) = navigate code
traverse local (Node i subs) = valRefs (instrVals (instr i)) ++ concatMap (traverse newLocal) subs
where valRefs vals = [v | SymVal t v <- vals, t==SymID || not (S.member v local)]
newLocal = S.union local (S.fromList (instrVars (instr i)))
instance Show Instruction where
show (Op BCall d (f:args)) = show d ++ " = " ++ show f ++ "(" ++ intercalate "," (map show args) ++ ")"
show (Op BSet v [val]) = show v ++ " = " ++ show val
show (Op o d vs) = show d ++ " = " ++ intercalate (" "++opStr++" ") (map show vs)
where opStr = fromMaybe (error $ "unknown builtin "++show o) $ lookup o bNames
show (Branch _ []) = "return"
show (Branch _ [off]) = "goto " ++ show off
show (Branch v off) = "case " ++ show v ++ " " ++ show off
show (Bind vars x) = "bind "++show vars++" "++show x
show Noop = "noop"
instance Show BindVar where
show (BindVar v (n,nr) pad subs) = case (pad,subs) of
(0,[]) -> head varStr
_ -> "["++intercalate " " (varStr++padStr++subsStr)++"]"
where varStr = [show v++":"++if sizeStr=="" then "0" else sizeStr]
sizeStr = intercalate "+" (size++regSize)
size = if n==0 then [] else [show n]
regSize = if nr==0 then [] else [show nr++"r"]
padStr = if pad==0 then [] else [show pad]
subsStr = map show subs