module IRTS.Bytecode where
import Idris.Core.TT
import IRTS.Defunctionalise
import IRTS.Simplified
import Data.Maybe
data Reg = RVal | L Int | T Int | Tmp
deriving (Show, Eq)
data BC =
ASSIGN Reg Reg
| ASSIGNCONST Reg Const
| UPDATE Reg Reg
| MKCON Reg (Maybe Reg) Int [Reg]
| CASE Bool
Reg [(Int, [BC])] (Maybe [BC])
| PROJECT Reg Int Int
| PROJECTINTO Reg Reg Int
| CONSTCASE Reg [(Const, [BC])] (Maybe [BC])
| CALL Name
| TAILCALL Name
| FOREIGNCALL Reg FDesc FDesc [(FDesc, Reg)]
| SLIDE Int
| REBASE
| RESERVE Int
| ADDTOP Int
| TOPBASE Int
| BASETOP Int
| STOREOLD
| OP Reg PrimFn [Reg]
| NULL Reg
| ERROR String
deriving Show
toBC :: (Name, SDecl) -> (Name, [BC])
toBC (n, SFun n' args locs exp)
= (n, reserve locs ++ bc RVal exp True)
where reserve 0 = []
reserve n = [RESERVE n, ADDTOP n]
clean True = [TOPBASE 0, REBASE]
clean False = []
bc :: Reg -> SExp -> Bool ->
[BC]
bc reg (SV (Glob n)) r = bc reg (SApp False n []) r
bc reg (SV (Loc i)) r = assign reg (L i) ++ clean r
bc reg (SApp False f vs) r =
if argCount == 0
then moveReg 0 vs ++ [STOREOLD, BASETOP 0, CALL f] ++ ret
else RESERVE argCount : moveReg 0 vs ++
[STOREOLD, BASETOP 0, ADDTOP argCount, CALL f] ++ ret
where
ret = assign reg RVal ++ clean r
argCount = length vs
bc reg (SApp True f vs) r
= RESERVE (length vs) : moveReg 0 vs
++ [SLIDE (length vs), TOPBASE (length vs), TAILCALL f]
bc reg (SForeign t fname args) r
= FOREIGNCALL reg t fname (map farg args) : clean r
where farg (ty, Loc i) = (ty, L i)
bc reg (SLet (Loc i) e sc) r = bc (L i) e False ++ bc reg sc r
bc reg (SUpdate (Loc i) sc) r = bc reg sc False ++ [ASSIGN (L i) reg]
++ clean r
bc reg (SCon atloc i _ vs) r
= MKCON reg (getAllocLoc atloc) i (map getL vs) : clean r
where getL (Loc x) = L x
getAllocLoc (Just (Loc x)) = Just (L x)
getAllocLoc _ = Nothing
bc reg (SProj (Loc l) i) r = PROJECTINTO reg (L l) i : clean r
bc reg (SConst i) r = ASSIGNCONST reg i : clean r
bc reg (SOp p vs) r = OP reg p (map getL vs) : clean r
where getL (Loc x) = L x
bc reg (SError str) r = [ERROR str]
bc reg SNothing r = NULL reg : clean r
bc reg (SCase up (Loc l) alts) r
| isConst alts = constCase reg (L l) alts r
| otherwise = conCase True reg (L l) alts r
bc reg (SChkCase (Loc l) alts) r
= conCase False reg (L l) alts r
bc reg t r = error $ "Can't compile " ++ show t
isConst [] = False
isConst (SConstCase _ _ : xs) = True
isConst (SConCase _ _ _ _ _ : xs) = False
isConst (_ : xs) = False
moveReg off [] = []
moveReg off (Loc x : xs) = assign (T off) (L x) ++ moveReg (off + 1) xs
assign r1 r2 | r1 == r2 = []
| otherwise = [ASSIGN r1 r2]
conCase safe reg l xs r = [CASE safe l (mapMaybe (caseAlt l reg r) xs)
(defaultAlt reg xs r)]
constCase reg l xs r = [CONSTCASE l (mapMaybe (constAlt l reg r) xs)
(defaultAlt reg xs r)]
caseAlt l reg r (SConCase lvar tag _ args e)
= Just (tag, PROJECT l lvar (length args) : bc reg e r)
caseAlt l reg r _ = Nothing
constAlt l reg r (SConstCase c e)
= Just (c, bc reg e r)
constAlt l reg r _ = Nothing
defaultAlt reg [] r = Nothing
defaultAlt reg (SDefaultCase e : _) r = Just (bc reg e r)
defaultAlt reg (_ : xs) r = defaultAlt reg xs r