> module Ivor.Bytecode where
Compilation of supercombinators to bytecode
> import Ivor.SC
> import Ivor.TTCore
> type Arity = Int
> type Tag = Int
> type TmpVar = Int
> type Bytecode = [ByteOp]
> data ByteOp
> = STARTFN SCName Arity
> | DECLARE Int
> | TMP Int
> | RETURN TmpVar
> | CALL TmpVar SCName [TmpVar]
> | CON TmpVar Tag [TmpVar]
> | CLOSURE TmpVar SCName [TmpVar]
> | VAR TmpVar Int
> | GETARG TmpVar Int TmpVar
> | CLOSUREADD TmpVar TmpVar [TmpVar]
> | EVAL Int
> | EVALTMP TmpVar
> | TYPE TmpVar
> | TAILCALL SCName [TmpVar]
> | ALET Int TmpVar
> | CASE Int [Bytecode]
> deriving Show
> data FunInfo
> = FI {
> bytecode :: Bytecode,
> cname :: String,
> ctag :: String,
> farity :: Int,
> ctagid :: Int
> }
> deriving Show
> type ByteDef = [(SCName,FunInfo)]
I wonder how generally useful this is...
> mapInc :: (Int->a->b) -> [a] -> Int -> [b]
> mapInc f [] i = []
> mapInc f (x:xs) i = (f i x):(mapInc f xs (i+1))
> compileAll :: SCs -> SCs -> ByteDef
> compileAll ctxt group = mapInc scomp group ((length ctxt)(length group))
> where scomp i (n,(a,sc)) = (n,FI (adddecls a (scompile n ctxt sc))
> (mkcname n)
> (mkctag n)
> a
> i)
> mkcname (N n) = "_EVM_"++show n
> mkcname (SN n i) = "_EVMSC_"++show i++"_"++show n
> mkctag (N n) = "FTAG_EVM_"++show n
> mkctag (SN n i) = "FTAG_EVMSC_"++show i++"_"++show n
> scompile :: SCName -> SCs -> SC -> Bytecode
> scompile name scs (SLam args body) =
> (STARTFN name (length args)):(bcomp (length args) 0 body)
> where
> getarity n = case lookup n scs of
> (Just (a,d)) -> a
> Nothing -> error $ "Can't happen (scompile, name "++show n++", " ++ show (map fst scs)++ ")"
> bcomp v t (SCase scr alts) =
> (EVAL scr):
> [CASE scr (map (acomp v t) alts)]
> bcomp v t (SApp (SP n) as)
> | getarity n == length as =
> concat (mapInc (ecomp v) as (t+1))
> ++ [TAILCALL n (mktargs (length as) (t+1))]
> bcomp v t x = (ecomp v t x)++[RETURN t]
> mktargs 0 s = []
> mktargs n s = s:(mktargs (n1) (s+1))
> acomp v t x = bcomp v t x
> ecomp :: Int -> TmpVar -> SCBody -> Bytecode
> ecomp v t (SP n) | getarity n == 0 = [CALL t n []]
> | otherwise = [CLOSURE t n []]
>
>
> ecomp v t (SV i) = [VAR t i]
> ecomp v t (SCon tag n as)
> = concat (mapInc (ecomp v) as (t+1))
> ++ [CON t tag (mktargs (length as) (t+1))]
> ecomp v t (SApp f as) = fcomp v t f as
> ecomp v t (SLet val ty b) =
> (ecomp v (t+1) val) ++
> (ALET v (t+1)):
> (ecomp (v+1) (t+2) b)
> ecomp v t (SProj i b) = (ecomp v (t+1) b) ++
> [GETARG t i (t+1)]
> ecomp v t (SPi e ty) = [TYPE t]
> ecomp v t SStar = [TYPE t]
> ecomp v t (SConst c) = error "Can't compile constants yet"
> ecomp v t _ = [TYPE t]
> fcomp v t (SP n) as
> | getarity n == length as
> = concat (mapInc (ecomp v) as (t+1))
> ++ [CALL t n (mktargs (length as) (t+1))]
> | otherwise
> = concat (mapInc (ecomp v) as (t+1))
> ++ [CLOSURE t n (mktargs (length as) (t+1))]
> fcomp v t f as
> = (ecomp v (t+1) f) ++
> concat (mapInc (ecomp v) as (t+2))
> ++ [CLOSUREADD t (t+1) (mktargs (length as) (t+2))]
>
Add type declarations to the top of bytecode, for the benefit of C/C--.
> adddecls :: Int -> Bytecode -> Bytecode
> adddecls arity bc = let (tmps,vars) = fd (1,1) bc in
> ad (tmps+1) (vars+1) ++ bc
> where ad 0 n | n<=arity = []
> ad 0 n = (DECLARE (n1)):(ad 0 (n1))
> ad m n = (TMP (m1)):(ad (m1) n)
> fd (t,v) [] = (t,v)
> fd (t,v) (c:cs) = let (t',v') = fd' (t,v) c in
> fd (t',v') cs
> fd' (t,v) (RETURN rt) | rt>t = (rt,v)
> | otherwise = (t,v)
> fd' (t,v) (CALL tv _ _)
> | tv > t = (tv,v)
> | otherwise = (t,v)
> fd' (t,v) (CON tv _ _)
> | tv > t = (tv,v)
> | otherwise = (t,v)
> fd' (t,v) (CLOSURE tv _ _)
> | tv > t = (tv,v)
> | otherwise = (t,v)
> fd' (t,v) (CLOSUREADD tv _ _)
> | tv > t = (tv,v)
> | otherwise = (t,v)
> fd' (t,v) (VAR tv _)
> | tv > t = (tv,v)
> | otherwise = (t,v)
> fd' (t,v) (GETARG tv _ _)
> | tv > t = (tv,v)
> | otherwise = (t,v)
> fd' (t,v) (TYPE tv)
> | tv > t = (tv,v)
> | otherwise = (t,v)
> fd' (t,v) (ALET vv _)
> | vv > v = (t,vv)
> | otherwise = (t,v)
> fd' (t,v) (CASE _ bs) = fdcs (t,v) bs
> fd' ts _ = ts
> fdcs (t,v) [] = (t,v)
> fdcs (t,v) (c:cs) = let (t',v') = fd (t,v) c in
> fdcs (t',v') cs