This commit is contained in:
+56
-15
@@ -22,6 +22,7 @@ import Data.HashMap.Strict (HashMap)
|
|||||||
import qualified Data.HashMap.Strict as H
|
import qualified Data.HashMap.Strict as H
|
||||||
import Data.HashSet.Lens (hashMap)
|
import Data.HashSet.Lens (hashMap)
|
||||||
import Data.List (List)
|
import Data.List (List)
|
||||||
|
import GHC.Exts (IsList(fromList))
|
||||||
|
|
||||||
|
|
||||||
type Stackify = Writer Stk.Program
|
type Stackify = Writer Stk.Program
|
||||||
@@ -29,26 +30,30 @@ type Stackify = Writer Stk.Program
|
|||||||
runStackify :: Eff (Stackify : es) a -> Eff es (a, Stk.Program)
|
runStackify :: Eff (Stackify : es) a -> Eff es (a, Stk.Program)
|
||||||
runStackify = runWriter
|
runStackify = runWriter
|
||||||
|
|
||||||
|
live :: Free a => Env -> a -> List Name
|
||||||
|
live g e = free' e & filter \x -> x `H.member` g.bound && x /= g.returnLabel
|
||||||
|
|
||||||
stackify
|
stackify
|
||||||
:: (GenSym :> es, Stackify :> es)
|
:: (GenSym :> es, Stackify :> es)
|
||||||
=> Env -> Exp -> Eff es (Seq Stk.Instr)
|
=> Env -> Exp -> Eff es (Seq Stk.Instr)
|
||||||
|
|
||||||
stackify g (ExpLetRec [(f, kap@(AbsKappa' xs m))] e) = do
|
stackify g (ExpLetRec [(f, kap@(AbsKappa' xs m))] e) = do
|
||||||
let vs = (f, Stk.ValLabel f) : (bindReg <$> xs)
|
let vs = (f, Stk.ValLabel f) : (bindReg <$> xs)
|
||||||
let live = free' kap & filter (`H.member` g.bound)
|
let ls = live g kap
|
||||||
m' <- stackify (g & #bound .~ H.fromList (vs ++ (bindReg <$> live))) m
|
m' <- stackify (g & #bound .~ H.fromList (vs ++ (bindReg <$> ls))) m
|
||||||
tell [Stk.MkBlock f xs $
|
tell [Stk.MkBlock f xs $
|
||||||
[Stk.Pop x | x <- live] <> toList m']
|
[Stk.Pop x | x <- ls] <> toList m']
|
||||||
stackify (g & #bound . at f ?~ Stk.ValLabel f) e
|
let g' = g & #bound . at f ?~ Stk.ValLabel f
|
||||||
|
& #liveness . at f ?~ ls
|
||||||
|
stackify g' e
|
||||||
|
|
||||||
stackify g (ExpLetRec [(f, AbsLambda' xs k m)] e) = do
|
stackify g (ExpLetRec [(f, AbsLambda' xs k m)] e) = do
|
||||||
let vs = (k:xs) <&> \x -> (x, Stk.ValReg x)
|
let vs = (k:xs) <&> \x -> (x, Stk.ValReg x)
|
||||||
lam_body <- gensym' "lambda-body"
|
lam_body <- gensym' "lambda-body"
|
||||||
m' <- stackify (g & #bound .~ H.fromList vs
|
m' <- stackify (g & #bound .~ H.fromList vs
|
||||||
& #bound . at f ?~ Stk.ValLabel lam_body) m
|
& #bound . at f ?~ Stk.ValLabel lam_body
|
||||||
tell [Stk.MkBlock lam_body xs . toList $
|
& #returnLabel .~ k) m
|
||||||
-- this is probably evil and wrong.
|
tell [Stk.MkBlock lam_body xs . toList $ m']
|
||||||
[Stk.PopCont k] <> m']
|
|
||||||
stackify (g & #bound . at f ?~ Stk.ValLabel lam_body) e
|
stackify (g & #bound . at f ?~ Stk.ValLabel lam_body) e
|
||||||
|
|
||||||
stackify g (ExpIf c t f) = do
|
stackify g (ExpIf c t f) = do
|
||||||
@@ -57,13 +62,24 @@ stackify g (ExpIf c t f) = do
|
|||||||
pure [ Stk.If (stackifyVal g c) (toList t') (toList f') ]
|
pure [ Stk.If (stackifyVal g c) (toList t') (toList f') ]
|
||||||
|
|
||||||
stackify g (ExpApply f xs ktail) = do
|
stackify g (ExpApply f xs ktail) = do
|
||||||
pure [ Stk.PushCont (var g ktail)
|
pure $
|
||||||
, Stk.Call (stackifyVal g f) (stackifyVal g <$> xs)
|
[ Stk.PushCont (Stk.ValLabel k) ]
|
||||||
]
|
<> fromList [ Stk.Push (Stk.ValReg l) | l <- ls ]
|
||||||
|
<> [ Stk.Call (stackifyVal g f) (stackifyVal g <$> xs) ]
|
||||||
|
where
|
||||||
|
k = case var g ktail of
|
||||||
|
Stk.ValLabel x -> x
|
||||||
|
x -> error [i|expected a label, got #{x} (i guess)|]
|
||||||
|
ls = fold $ g ^. #liveness . at k
|
||||||
|
|
||||||
stackify g (ExpContinue k xs) = pure
|
-- this probably won't work for call/cc, for cps-converted code it'll
|
||||||
[ Stk.Call (var g k) (stackifyVal g <$> xs)
|
-- be fine i think. notice how, instead of calling `var g k`, we just
|
||||||
]
|
-- assume it's the return continuation on top of the stack.
|
||||||
|
stackify g (ExpContinue k xs) = do
|
||||||
|
ktail <- gensym' $ k ^. _Wrapped'
|
||||||
|
pure [ Stk.PopCont ktail
|
||||||
|
, Stk.Call (Stk.ValReg ktail) (stackifyVal g <$> xs)
|
||||||
|
]
|
||||||
|
|
||||||
stackify g (ExpPrim p (MkKappa [x] e)) = do
|
stackify g (ExpPrim p (MkKappa [x] e)) = do
|
||||||
e' <- stackify (g & #bound . at x ?~ Stk.ValReg x) e
|
e' <- stackify (g & #bound . at x ?~ Stk.ValReg x) e
|
||||||
@@ -90,11 +106,16 @@ bindReg x = (x, Stk.ValReg x)
|
|||||||
|
|
||||||
data Env = MkEnv
|
data Env = MkEnv
|
||||||
{ bound :: HashMap Name Stk.Val
|
{ bound :: HashMap Name Stk.Val
|
||||||
|
, returnLabel :: Name
|
||||||
|
-- | for each locally-bound continuation @k@, @liveness@ has an
|
||||||
|
-- entry @(k,ls)@ where @ls@ is the sequence of registers @k@
|
||||||
|
-- expects to find saved on the stack.
|
||||||
|
, liveness :: HashMap Name (List Name)
|
||||||
}
|
}
|
||||||
deriving (Show, Generic)
|
deriving (Show, Generic)
|
||||||
|
|
||||||
emptyEnv :: Env
|
emptyEnv :: Env
|
||||||
emptyEnv = MkEnv mempty
|
emptyEnv = MkEnv mempty "halt" mempty
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -105,3 +126,23 @@ stackifyExp lbl e = do
|
|||||||
|
|
||||||
stackifyProgram :: GenSym :> es => Program -> Eff es Stk.Program
|
stackifyProgram :: GenSym :> es => Program -> Eff es Stk.Program
|
||||||
stackifyProgram (MkProgram e) = stackifyExp "main" e
|
stackifyProgram (MkProgram e) = stackifyExp "main" e
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
fac :: Program
|
||||||
|
fac = [cps|
|
||||||
|
(letrec ((fac (λ (n ktail)
|
||||||
|
(prim (zero? n)
|
||||||
|
(κ (x0)
|
||||||
|
(if x0
|
||||||
|
(continue ktail 1)
|
||||||
|
(prim (- n 1)
|
||||||
|
(κ (x1)
|
||||||
|
(letrec ((fac-k0
|
||||||
|
(κ (x2)
|
||||||
|
(prim (* n x2)
|
||||||
|
(κ (x3)
|
||||||
|
(continue ktail x3))))))
|
||||||
|
(fac x1 fac-k0))))))))))
|
||||||
|
(fac 6 halt))
|
||||||
|
|]
|
||||||
|
|||||||
@@ -231,6 +231,7 @@ instance CPS Val where toCPS = Gyehoek.Sexp.fromSexp
|
|||||||
instance CPS Kappa where toCPS = Gyehoek.Sexp.fromSexp
|
instance CPS Kappa where toCPS = Gyehoek.Sexp.fromSexp
|
||||||
instance CPS Lambda where toCPS = Gyehoek.Sexp.fromSexp
|
instance CPS Lambda where toCPS = Gyehoek.Sexp.fromSexp
|
||||||
instance CPS Abs where toCPS = Gyehoek.Sexp.fromSexp
|
instance CPS Abs where toCPS = Gyehoek.Sexp.fromSexp
|
||||||
|
instance CPS Program where toCPS = Gyehoek.Sexp.fromSexp
|
||||||
|
|
||||||
cps :: QuasiQuoter
|
cps :: QuasiQuoter
|
||||||
cps = Gyehoek.Sexp.makeSx' [| toCPS |]
|
cps = Gyehoek.Sexp.makeSx' [| toCPS |]
|
||||||
|
|||||||
@@ -63,7 +63,7 @@ condition = testCase "if" do
|
|||||||
[cps|(if #f (continue halt 123) (continue halt 456))|]
|
[cps|(if #f (continue halt 123) (continue halt 456))|]
|
||||||
|
|
||||||
procedure = testGroup "procedure"
|
procedure = testGroup "procedure"
|
||||||
[ expectFail $ testCase "factorial" do
|
[ testCase "factorial" do
|
||||||
evalsTo [ObjImm (ImmInt 720)]
|
evalsTo [ObjImm (ImmInt 720)]
|
||||||
[cps|(letrec ((fac (λ (n ktail)
|
[cps|(letrec ((fac (λ (n ktail)
|
||||||
(prim (zero? n)
|
(prim (zero? n)
|
||||||
|
|||||||
Reference in New Issue
Block a user