mirror of
https://github.com/edwinb/Idris2-boot.git
synced 2024-11-28 05:32:03 +03:00
Add some more IRs for back ends to use
ANF, in which everything is applied to variables only, and VMCode, in which everything is reduced to a list of assignments. I don't plan to add a defunctionalisation step. I've tested with with a quick hack C backend, though I don't intend to commit that (not here at least) because even though it basically works, it's Very Slow.
This commit is contained in:
parent
409357c302
commit
4a913752ba
@ -1,6 +1,7 @@
|
|||||||
package idris2
|
package idris2
|
||||||
|
|
||||||
modules =
|
modules =
|
||||||
|
Compiler.ANF,
|
||||||
Compiler.Common,
|
Compiler.Common,
|
||||||
Compiler.CompileExpr,
|
Compiler.CompileExpr,
|
||||||
Compiler.Inline,
|
Compiler.Inline,
|
||||||
@ -9,6 +10,7 @@ modules =
|
|||||||
-- Compiler.Scheme.Chicken,
|
-- Compiler.Scheme.Chicken,
|
||||||
Compiler.Scheme.Racket,
|
Compiler.Scheme.Racket,
|
||||||
Compiler.Scheme.Common,
|
Compiler.Scheme.Common,
|
||||||
|
Compiler.VMCode,
|
||||||
|
|
||||||
Control.Delayed,
|
Control.Delayed,
|
||||||
|
|
||||||
|
262
src/Compiler/ANF.idr
Normal file
262
src/Compiler/ANF.idr
Normal file
@ -0,0 +1,262 @@
|
|||||||
|
module Compiler.ANF
|
||||||
|
|
||||||
|
import Compiler.LambdaLift
|
||||||
|
|
||||||
|
import Core.CompileExpr
|
||||||
|
import Core.Context
|
||||||
|
import Core.Core
|
||||||
|
import Core.TT
|
||||||
|
|
||||||
|
import Data.Vect
|
||||||
|
|
||||||
|
%default covering
|
||||||
|
|
||||||
|
-- Convert the lambda lifted form to ANF, with variable names made explicit.
|
||||||
|
-- i.e. turn intermediate expressions into let bindings. Every argument is
|
||||||
|
-- a variable as a result.
|
||||||
|
|
||||||
|
mutual
|
||||||
|
public export
|
||||||
|
data AVar : Type where
|
||||||
|
ALocal : Int -> AVar
|
||||||
|
ANull : AVar
|
||||||
|
|
||||||
|
public export
|
||||||
|
data ANF : Type where
|
||||||
|
AV : FC -> AVar -> ANF
|
||||||
|
AAppName : FC -> Name -> List AVar -> ANF
|
||||||
|
AUnderApp : FC -> Name -> (missing : Nat) -> (args : List AVar) -> ANF
|
||||||
|
AApp : FC -> (closure : AVar) -> (arg : AVar) -> ANF
|
||||||
|
ALet : FC -> (var : Int) -> ANF -> ANF -> ANF
|
||||||
|
ACon : FC -> Name -> (tag : Int) -> List AVar -> ANF
|
||||||
|
AOp : FC -> PrimFn arity -> Vect arity AVar -> ANF
|
||||||
|
AExtPrim : FC -> Name -> List AVar -> ANF
|
||||||
|
AConCase : FC -> AVar -> List AConAlt -> Maybe ANF -> ANF
|
||||||
|
AConstCase : FC -> AVar -> List AConstAlt -> Maybe ANF -> ANF
|
||||||
|
APrimVal : FC -> Constant -> ANF
|
||||||
|
AErased : FC -> ANF
|
||||||
|
ACrash : FC -> String -> ANF
|
||||||
|
|
||||||
|
public export
|
||||||
|
data AConAlt : Type where
|
||||||
|
MkAConAlt : Name -> (tag : Int) -> (args : List Int) ->
|
||||||
|
ANF -> AConAlt
|
||||||
|
|
||||||
|
public export
|
||||||
|
data AConstAlt : Type where
|
||||||
|
MkAConstAlt : Constant -> ANF -> AConstAlt
|
||||||
|
|
||||||
|
public export
|
||||||
|
data ANFDef : Type where
|
||||||
|
MkAFun : (args : List Int) -> ANF -> ANFDef
|
||||||
|
MkACon : (tag : Int) -> (arity : Nat) -> ANFDef
|
||||||
|
MkAForeign : (ccs : List String) -> (fargs : List CFType) ->
|
||||||
|
CFType -> ANFDef
|
||||||
|
MkAError : ANF -> ANFDef
|
||||||
|
|
||||||
|
mutual
|
||||||
|
export
|
||||||
|
Show AVar where
|
||||||
|
show (ALocal i) = "v" ++ show i
|
||||||
|
show ANull = "[__]"
|
||||||
|
|
||||||
|
export
|
||||||
|
Show ANF where
|
||||||
|
show (AV _ v) = show v
|
||||||
|
show (AAppName fc n args)
|
||||||
|
= show n ++ "(" ++ showSep ", " (map show args) ++ ")"
|
||||||
|
show (AUnderApp fc n m args)
|
||||||
|
= "<" ++ show n ++ " underapp " ++ show m ++ ">(" ++
|
||||||
|
showSep ", " (map show args) ++ ")"
|
||||||
|
show (AApp fc c arg)
|
||||||
|
= show c ++ " @ (" ++ show arg ++ ")"
|
||||||
|
show (ALet fc x val sc)
|
||||||
|
= "%let v" ++ show x ++ " = " ++ show val ++ " in " ++ show sc
|
||||||
|
show (ACon fc n t args)
|
||||||
|
= "%con " ++ show n ++ "(" ++ showSep ", " (map show args) ++ ")"
|
||||||
|
show (AOp fc op args)
|
||||||
|
= "%op " ++ show op ++ "(" ++ showSep ", " (toList (map show args)) ++ ")"
|
||||||
|
show (AExtPrim fc p args)
|
||||||
|
= "%extprim " ++ show p ++ "(" ++ showSep ", " (map show args) ++ ")"
|
||||||
|
show (AConCase fc sc alts def)
|
||||||
|
= "%case " ++ show sc ++ " of { "
|
||||||
|
++ showSep "| " (map show alts) ++ " " ++ show def
|
||||||
|
show (AConstCase fc sc alts def)
|
||||||
|
= "%case " ++ show sc ++ " of { "
|
||||||
|
++ showSep "| " (map show alts) ++ " " ++ show def
|
||||||
|
show (APrimVal _ x) = show x
|
||||||
|
show (AErased _) = "___"
|
||||||
|
show (ACrash _ x) = "%CRASH(" ++ show x ++ ")"
|
||||||
|
|
||||||
|
export
|
||||||
|
Show AConAlt where
|
||||||
|
show (MkAConAlt n t args sc)
|
||||||
|
= "%conalt " ++ show n ++
|
||||||
|
"(" ++ showSep ", " (map showArg args) ++ ") => " ++ show sc
|
||||||
|
where
|
||||||
|
showArg : Int -> String
|
||||||
|
showArg i = "v" ++ show i
|
||||||
|
|
||||||
|
export
|
||||||
|
Show AConstAlt where
|
||||||
|
show (MkAConstAlt c sc)
|
||||||
|
= "%constalt(" ++ show c ++ ") => " ++ show sc
|
||||||
|
|
||||||
|
export
|
||||||
|
Show ANFDef where
|
||||||
|
show (MkAFun args exp) = show args ++ ": " ++ show exp
|
||||||
|
show (MkACon tag arity)
|
||||||
|
= "Constructor tag " ++ show tag ++ " arity " ++ show arity
|
||||||
|
show (MkAForeign ccs args ret)
|
||||||
|
= "Foreign call " ++ show ccs ++ " " ++
|
||||||
|
show args ++ " -> " ++ show ret
|
||||||
|
show (MkAError exp) = "Error: " ++ show exp
|
||||||
|
|
||||||
|
data AVars : List Name -> Type where
|
||||||
|
Nil : AVars []
|
||||||
|
(::) : Int -> AVars xs -> AVars (x :: xs)
|
||||||
|
|
||||||
|
data Next : Type where
|
||||||
|
|
||||||
|
nextVar : {auto v : Ref Next Int} ->
|
||||||
|
Core Int
|
||||||
|
nextVar
|
||||||
|
= do i <- get Next
|
||||||
|
put Next (i + 1)
|
||||||
|
pure i
|
||||||
|
|
||||||
|
lookup : IsVar x idx vs -> AVars vs -> Int
|
||||||
|
lookup First (x :: xs) = x
|
||||||
|
lookup (Later p) (x :: xs) = lookup p xs
|
||||||
|
|
||||||
|
bindArgs : {auto v : Ref Next Int} ->
|
||||||
|
List ANF -> Core (List (AVar, Maybe ANF))
|
||||||
|
bindArgs [] = pure []
|
||||||
|
bindArgs (AV fc var :: xs)
|
||||||
|
= do xs' <- bindArgs xs
|
||||||
|
pure $ (var, Nothing) :: xs'
|
||||||
|
bindArgs (AErased fc :: xs)
|
||||||
|
= do xs' <- bindArgs xs
|
||||||
|
pure $ (ANull, Nothing) :: xs'
|
||||||
|
bindArgs (x :: xs)
|
||||||
|
= do i <- nextVar
|
||||||
|
xs' <- bindArgs xs
|
||||||
|
pure $ (ALocal i, Just x) :: xs'
|
||||||
|
|
||||||
|
letBind : {auto v : Ref Next Int} ->
|
||||||
|
FC -> List ANF -> (List AVar -> ANF) -> Core ANF
|
||||||
|
letBind fc args f
|
||||||
|
= do bargs <- bindArgs args
|
||||||
|
pure $ doBind [] bargs
|
||||||
|
where
|
||||||
|
doBind : List AVar -> List (AVar, Maybe ANF) -> ANF
|
||||||
|
doBind vs [] = f (reverse vs)
|
||||||
|
doBind vs ((ALocal i, Just t) :: xs)
|
||||||
|
= ALet fc i t (doBind (ALocal i :: vs) xs)
|
||||||
|
doBind vs ((var, _) :: xs) = doBind (var :: vs) xs
|
||||||
|
|
||||||
|
toVect : (n : Nat) -> List a -> Maybe (Vect n a)
|
||||||
|
toVect Z [] = Just []
|
||||||
|
toVect (S k) (x :: xs)
|
||||||
|
= do xs' <- toVect k xs
|
||||||
|
pure (x :: xs')
|
||||||
|
toVect _ _ = Nothing
|
||||||
|
|
||||||
|
mlet : {auto v : Ref Next Int} ->
|
||||||
|
FC -> ANF -> (AVar -> ANF) -> Core ANF
|
||||||
|
mlet fc (AV _ var) sc = pure $ sc var
|
||||||
|
mlet fc val sc
|
||||||
|
= do i <- nextVar
|
||||||
|
pure $ ALet fc i val (sc (ALocal i))
|
||||||
|
|
||||||
|
mutual
|
||||||
|
anfArgs : {auto v : Ref Next Int} ->
|
||||||
|
FC -> AVars vars ->
|
||||||
|
List (Lifted vars) -> (List AVar -> ANF) -> Core ANF
|
||||||
|
anfArgs fc vs args f
|
||||||
|
= do args' <- traverse (anf vs) args
|
||||||
|
letBind fc args' f
|
||||||
|
|
||||||
|
anf : {auto v : Ref Next Int} ->
|
||||||
|
AVars vars -> Lifted vars -> Core ANF
|
||||||
|
anf vs (LLocal fc p) = pure $ AV fc (ALocal (lookup p vs))
|
||||||
|
anf vs (LAppName fc n args)
|
||||||
|
= anfArgs fc vs args (AAppName fc n)
|
||||||
|
anf vs (LUnderApp fc n m args)
|
||||||
|
= anfArgs fc vs args (AUnderApp fc n m)
|
||||||
|
anf vs (LApp fc f a)
|
||||||
|
= anfArgs fc vs [f, a]
|
||||||
|
(\args => case args of
|
||||||
|
[fvar, avar] => AApp fc fvar avar
|
||||||
|
_ => ACrash fc "Can't happen (AApp)")
|
||||||
|
anf vs (LLet fc x val sc)
|
||||||
|
= do i <- nextVar
|
||||||
|
let vs' = i :: vs
|
||||||
|
pure $ ALet fc i !(anf vs val) !(anf vs' sc)
|
||||||
|
anf vs (LCon fc n t args)
|
||||||
|
= anfArgs fc vs args (ACon fc n t)
|
||||||
|
anf vs (LOp {arity} fc op args)
|
||||||
|
= do args' <- traverse (anf vs) (toList args)
|
||||||
|
letBind fc args'
|
||||||
|
(\args => case toVect arity args of
|
||||||
|
Nothing => ACrash fc "Can't happen (AOp)"
|
||||||
|
Just argsv => AOp fc op argsv)
|
||||||
|
anf vs (LExtPrim fc p args)
|
||||||
|
= anfArgs fc vs args (AExtPrim fc p)
|
||||||
|
anf vs (LConCase fc scr alts def)
|
||||||
|
= do scr' <- anf vs scr
|
||||||
|
alts' <- traverse (anfConAlt vs) alts
|
||||||
|
def' <- traverseOpt (anf vs) def
|
||||||
|
mlet fc scr' (\x => AConCase fc x alts' def')
|
||||||
|
anf vs (LConstCase fc scr alts def)
|
||||||
|
= do scr' <- anf vs scr
|
||||||
|
alts' <- traverse (anfConstAlt vs) alts
|
||||||
|
def' <- traverseOpt (anf vs) def
|
||||||
|
mlet fc scr' (\x => AConstCase fc x alts' def')
|
||||||
|
anf vs (LPrimVal fc c) = pure $ APrimVal fc c
|
||||||
|
anf vs (LErased fc) = pure $ AErased fc
|
||||||
|
anf vs (LCrash fc err) = pure $ ACrash fc err
|
||||||
|
|
||||||
|
anfConAlt : {auto v : Ref Next Int} ->
|
||||||
|
AVars vars -> LiftedConAlt vars -> Core AConAlt
|
||||||
|
anfConAlt vs (MkLConAlt n t args sc)
|
||||||
|
= do (is, vs') <- bindArgs args vs
|
||||||
|
pure $ MkAConAlt n t is !(anf vs' sc)
|
||||||
|
where
|
||||||
|
bindArgs : {auto v : Ref Next Int} ->
|
||||||
|
(args : List Name) -> AVars vars' ->
|
||||||
|
Core (List Int, AVars (args ++ vars'))
|
||||||
|
bindArgs [] vs = pure ([], vs)
|
||||||
|
bindArgs (n :: ns) vs
|
||||||
|
= do i <- nextVar
|
||||||
|
(is, vs') <- bindArgs ns vs
|
||||||
|
pure (i :: is, i :: vs')
|
||||||
|
|
||||||
|
anfConstAlt : {auto v : Ref Next Int} ->
|
||||||
|
AVars vars -> LiftedConstAlt vars -> Core AConstAlt
|
||||||
|
anfConstAlt vs (MkLConstAlt c sc)
|
||||||
|
= pure $ MkAConstAlt c !(anf vs sc)
|
||||||
|
|
||||||
|
export
|
||||||
|
toANF : LiftedDef -> Core ANFDef
|
||||||
|
toANF (MkLFun args scope sc)
|
||||||
|
= do v <- newRef Next (the Int 0)
|
||||||
|
(iargs, vsNil) <- bindArgs args []
|
||||||
|
let vs : AVars args = rewrite sym (appendNilRightNeutral args) in
|
||||||
|
vsNil
|
||||||
|
(iargs', vs) <- bindArgs scope vs
|
||||||
|
pure $ MkAFun (iargs ++ reverse iargs') !(anf vs sc)
|
||||||
|
where
|
||||||
|
bindArgs : {auto v : Ref Next Int} ->
|
||||||
|
(args : List Name) -> AVars vars' ->
|
||||||
|
Core (List Int, AVars (args ++ vars'))
|
||||||
|
bindArgs [] vs = pure ([], vs)
|
||||||
|
bindArgs (n :: ns) vs
|
||||||
|
= do i <- nextVar
|
||||||
|
(is, vs') <- bindArgs ns vs
|
||||||
|
pure (i :: is, i :: vs')
|
||||||
|
toANF (MkLCon t a ns) = pure $ MkACon t a
|
||||||
|
toANF (MkLForeign ccs fargs t) = pure $ MkAForeign ccs fargs t
|
||||||
|
toANF (MkLError err)
|
||||||
|
= do v <- newRef Next (the Int 0)
|
||||||
|
pure $ MkAError !(anf [] err)
|
@ -1,8 +1,10 @@
|
|||||||
module Compiler.Common
|
module Compiler.Common
|
||||||
|
|
||||||
|
import Compiler.ANF
|
||||||
import Compiler.CompileExpr
|
import Compiler.CompileExpr
|
||||||
import Compiler.Inline
|
import Compiler.Inline
|
||||||
import Compiler.LambdaLift
|
import Compiler.LambdaLift
|
||||||
|
import Compiler.VMCode
|
||||||
|
|
||||||
import Core.Context
|
import Core.Context
|
||||||
import Core.Directory
|
import Core.Directory
|
||||||
@ -27,6 +29,24 @@ record Codegen where
|
|||||||
||| Execute an Idris 2 expression directly.
|
||| Execute an Idris 2 expression directly.
|
||||||
executeExpr : Ref Ctxt Defs -> (execDir : String) -> ClosedTerm -> Core ()
|
executeExpr : Ref Ctxt Defs -> (execDir : String) -> ClosedTerm -> Core ()
|
||||||
|
|
||||||
|
public export
|
||||||
|
record CompileData where
|
||||||
|
constructor MkCompileData
|
||||||
|
allNames : List Name -- names which need to be compiled
|
||||||
|
nameTags : NameTags -- a mapping from type names to constructor tags
|
||||||
|
mainExpr : CExp [] -- main expression to execute. This also appears in
|
||||||
|
-- the definitions below as MN "__mainExpression" 0
|
||||||
|
lambdaLifted : List (Name, LiftedDef)
|
||||||
|
-- ^ lambda lifted definitions, if required. Only the top level names
|
||||||
|
-- will be in the context, and (for the moment...) I don't expect to
|
||||||
|
-- need to look anything up, so it's just an alist.
|
||||||
|
anf : List (Name, ANFDef)
|
||||||
|
-- ^ lambda lifted and converted to ANF (all arguments to functions
|
||||||
|
-- and constructors transformed to either variables or Null if erased)
|
||||||
|
vmcode : List (Name, VMDef)
|
||||||
|
-- ^ A much simplified virtual machine code, suitable for passing
|
||||||
|
-- to a more low level target such as C
|
||||||
|
|
||||||
||| compile
|
||| compile
|
||||||
||| Given a value of type Codegen, produce a standalone function
|
||| Given a value of type Codegen, produce a standalone function
|
||||||
||| that executes the `compileExpr` method of the Codegen
|
||| that executes the `compileExpr` method of the Codegen
|
||||||
@ -102,6 +122,7 @@ fastAppend xs
|
|||||||
build b (x :: xs) = do addToStringBuffer b x
|
build b (x :: xs) = do addToStringBuffer b x
|
||||||
build b xs
|
build b xs
|
||||||
|
|
||||||
|
-- Hmm, these dump functions are all very similar aren't they...
|
||||||
dumpCases : Defs -> String -> List Name ->
|
dumpCases : Defs -> String -> List Name ->
|
||||||
Core ()
|
Core ()
|
||||||
dumpCases defs fn cns
|
dumpCases defs fn cns
|
||||||
@ -137,16 +158,33 @@ dumpLifted fn lns
|
|||||||
dumpDef : (Name, LiftedDef) -> String
|
dumpDef : (Name, LiftedDef) -> String
|
||||||
dumpDef (n, d) = fullShow n ++ " = " ++ show d ++ "\n"
|
dumpDef (n, d) = fullShow n ++ " = " ++ show d ++ "\n"
|
||||||
|
|
||||||
public export
|
dumpANF : String -> List (Name, ANFDef) -> Core ()
|
||||||
record CompileData where
|
dumpANF fn lns
|
||||||
constructor MkCompileData
|
= do let cstrs = map dumpDef lns
|
||||||
allNames : List Name -- names which need to be compiled
|
Right () <- coreLift $ writeFile fn (fastAppend cstrs)
|
||||||
nameTags : NameTags -- a mapping from type names to constructor tags
|
| Left err => throw (FileErr fn err)
|
||||||
mainExpr : CExp [] -- main expression to execute
|
pure ()
|
||||||
lambdaLifted : List (Name, LiftedDef)
|
where
|
||||||
-- ^ lambda lifted definitions, if required. Only the top level names
|
fullShow : Name -> String
|
||||||
-- will be in the context, and (for the moment...) I don't expect to
|
fullShow (DN _ n) = show n
|
||||||
-- need to look anything up, so it's just an alist.
|
fullShow n = show n
|
||||||
|
|
||||||
|
dumpDef : (Name, ANFDef) -> String
|
||||||
|
dumpDef (n, d) = fullShow n ++ " = " ++ show d ++ "\n"
|
||||||
|
|
||||||
|
dumpVMCode : String -> List (Name, VMDef) -> Core ()
|
||||||
|
dumpVMCode fn lns
|
||||||
|
= do let cstrs = map dumpDef lns
|
||||||
|
Right () <- coreLift $ writeFile fn (fastAppend cstrs)
|
||||||
|
| Left err => throw (FileErr fn err)
|
||||||
|
pure ()
|
||||||
|
where
|
||||||
|
fullShow : Name -> String
|
||||||
|
fullShow (DN _ n) = show n
|
||||||
|
fullShow n = show n
|
||||||
|
|
||||||
|
dumpDef : (Name, VMDef) -> String
|
||||||
|
dumpDef (n, d) = fullShow n ++ " = " ++ show d ++ "\n"
|
||||||
|
|
||||||
-- Find all the names which need compiling, from a given expression, and compile
|
-- Find all the names which need compiling, from a given expression, and compile
|
||||||
-- them to CExp form (and update that in the Defs).
|
-- them to CExp form (and update that in the Defs).
|
||||||
@ -183,9 +221,17 @@ getCompileData tm
|
|||||||
logTime "Fix arity" $ traverse_ fixArityDef cns
|
logTime "Fix arity" $ traverse_ fixArityDef cns
|
||||||
logTime "Forget names" $ traverse_ mkForgetDef cns
|
logTime "Forget names" $ traverse_ mkForgetDef cns
|
||||||
|
|
||||||
lifted <- logTime "Lambda lift" $ traverse lambdaLift cns
|
|
||||||
|
|
||||||
compiledtm <- fixArityExp !(compileExp tycontags tm)
|
compiledtm <- fixArityExp !(compileExp tycontags tm)
|
||||||
|
let mainname = MN "__mainExpression" 0
|
||||||
|
(liftedtm, ldefs) <- liftBody mainname compiledtm
|
||||||
|
|
||||||
|
lifted_in <- logTime "Lambda lift" $ traverse lambdaLift cns
|
||||||
|
|
||||||
|
let lifted = (mainname, MkLFun [] [] liftedtm) ::
|
||||||
|
ldefs ++ concat lifted_in
|
||||||
|
|
||||||
|
anf <- logTime "Get ANF" $ traverse (\ (n, d) => pure (n, !(toANF d))) lifted
|
||||||
|
vmcode <- logTime "Get VM Code" $ pure (allDefs anf)
|
||||||
|
|
||||||
defs <- get Ctxt
|
defs <- get Ctxt
|
||||||
maybe (pure ())
|
maybe (pure ())
|
||||||
@ -194,9 +240,18 @@ getCompileData tm
|
|||||||
(dumpcases sopts)
|
(dumpcases sopts)
|
||||||
maybe (pure ())
|
maybe (pure ())
|
||||||
(\f => do coreLift $ putStrLn $ "Dumping lambda lifted defs to " ++ f
|
(\f => do coreLift $ putStrLn $ "Dumping lambda lifted defs to " ++ f
|
||||||
dumpLifted f (concat lifted))
|
dumpLifted f lifted)
|
||||||
(dumplifted sopts)
|
(dumplifted sopts)
|
||||||
pure (MkCompileData cns tycontags compiledtm (concat lifted))
|
maybe (pure ())
|
||||||
|
(\f => do coreLift $ putStrLn $ "Dumping ANF defs to " ++ f
|
||||||
|
dumpANF f anf)
|
||||||
|
(dumpanf sopts)
|
||||||
|
maybe (pure ())
|
||||||
|
(\f => do coreLift $ putStrLn $ "Dumping VM defs to " ++ f
|
||||||
|
dumpVMCode f vmcode)
|
||||||
|
(dumpvmcode sopts)
|
||||||
|
pure (MkCompileData cns tycontags compiledtm
|
||||||
|
lifted anf vmcode)
|
||||||
where
|
where
|
||||||
primTags : Int -> NameTags -> List Constant -> NameTags
|
primTags : Int -> NameTags -> List Constant -> NameTags
|
||||||
primTags t tags [] = tags
|
primTags t tags [] = tags
|
||||||
|
@ -59,7 +59,7 @@ etaExpand i Z exp args = mkApp exp (map (mkLocal (getFC exp)) (reverse args))
|
|||||||
mkApp (CExtPrim fc p args) args' = CExtPrim fc p (args ++ args')
|
mkApp (CExtPrim fc p args) args' = CExtPrim fc p (args ++ args')
|
||||||
mkApp tm args = CApp (getFC tm) tm args
|
mkApp tm args = CApp (getFC tm) tm args
|
||||||
etaExpand i (S k) exp args
|
etaExpand i (S k) exp args
|
||||||
= CLam (getFC exp) (MN "x" i)
|
= CLam (getFC exp) (MN "eta" i)
|
||||||
(etaExpand (i + 1) k (weaken exp)
|
(etaExpand (i + 1) k (weaken exp)
|
||||||
(MkVar First :: map weakenVar args))
|
(MkVar First :: map weakenVar args))
|
||||||
|
|
||||||
|
@ -54,7 +54,10 @@ data LiftedDef : Type where
|
|||||||
-- We take the outer scope and the function arguments separately so that
|
-- We take the outer scope and the function arguments separately so that
|
||||||
-- we don't have to reshuffle de Bruijn indices, which is expensive.
|
-- we don't have to reshuffle de Bruijn indices, which is expensive.
|
||||||
-- This should be compiled as a function which takes 'args' first,
|
-- This should be compiled as a function which takes 'args' first,
|
||||||
-- then 'scope'.
|
-- then 'reverse scope'.
|
||||||
|
-- (Sorry for the awkward API - it's to do with how the indices are
|
||||||
|
-- arranged for the variables, and it oculd be expensive to reshuffle them!
|
||||||
|
-- See Compiler.ANF for an example of how they get resolved to names)
|
||||||
MkLFun : (args : List Name) -> -- function arguments
|
MkLFun : (args : List Name) -> -- function arguments
|
||||||
(scope : List Name) -> -- outer scope
|
(scope : List Name) -> -- outer scope
|
||||||
Lifted (scope ++ args) -> LiftedDef
|
Lifted (scope ++ args) -> LiftedDef
|
||||||
@ -107,7 +110,8 @@ mutual
|
|||||||
|
|
||||||
export
|
export
|
||||||
Show LiftedDef where
|
Show LiftedDef where
|
||||||
show (MkLFun args scope exp) = show args ++ show scope ++ ": " ++ show exp
|
show (MkLFun args scope exp)
|
||||||
|
= show args ++ show (reverse scope) ++ ": " ++ show exp
|
||||||
show (MkLCon tag arity pos)
|
show (MkLCon tag arity pos)
|
||||||
= "Constructor tag " ++ show tag ++ " arity " ++ show arity ++
|
= "Constructor tag " ++ show tag ++ " arity " ++ show arity ++
|
||||||
maybe "" (\n => " (newtype by " ++ show n ++ ")") pos
|
maybe "" (\n => " (newtype by " ++ show n ++ ")") pos
|
||||||
@ -136,6 +140,7 @@ genName
|
|||||||
mkName : Name -> Int -> Name
|
mkName : Name -> Int -> Name
|
||||||
mkName (NS ns b) i = NS ns (mkName b i)
|
mkName (NS ns b) i = NS ns (mkName b i)
|
||||||
mkName (UN n) i = MN n i
|
mkName (UN n) i = MN n i
|
||||||
|
mkName (DN _ n) i = mkName n i
|
||||||
mkName n i = MN (show n) i
|
mkName n i = MN (show n) i
|
||||||
|
|
||||||
unload : FC -> Lifted vars -> List (Lifted vars) -> Core (Lifted vars)
|
unload : FC -> Lifted vars -> List (Lifted vars) -> Core (Lifted vars)
|
||||||
@ -188,7 +193,7 @@ mutual
|
|||||||
traverseArgs (a :: as) = pure $ !(liftExp a) :: !(traverseArgs as)
|
traverseArgs (a :: as) = pure $ !(liftExp a) :: !(traverseArgs as)
|
||||||
liftExp (CExtPrim fc p args) = pure $ LExtPrim fc p !(traverse liftExp args)
|
liftExp (CExtPrim fc p args) = pure $ LExtPrim fc p !(traverse liftExp args)
|
||||||
liftExp (CForce fc tm) = liftExp (CApp fc tm [CErased fc])
|
liftExp (CForce fc tm) = liftExp (CApp fc tm [CErased fc])
|
||||||
liftExp (CDelay fc tm) = liftExp (CLam fc (MN "x" 0) (weaken tm))
|
liftExp (CDelay fc tm) = liftExp (CLam fc (MN "act" 0) (weaken tm))
|
||||||
liftExp (CConCase fc sc alts def)
|
liftExp (CConCase fc sc alts def)
|
||||||
= pure $ LConCase fc !(liftExp sc) !(traverse liftConAlt alts)
|
= pure $ LConCase fc !(liftExp sc) !(traverse liftConAlt alts)
|
||||||
!(traverseOpt liftExp def)
|
!(traverseOpt liftExp def)
|
||||||
@ -205,6 +210,7 @@ mutual
|
|||||||
liftExp (CErased fc) = pure $ LErased fc
|
liftExp (CErased fc) = pure $ LErased fc
|
||||||
liftExp (CCrash fc str) = pure $ LCrash fc str
|
liftExp (CCrash fc str) = pure $ LCrash fc str
|
||||||
|
|
||||||
|
export
|
||||||
liftBody : Name -> CExp vars -> Core (Lifted vars, List (Name, LiftedDef))
|
liftBody : Name -> CExp vars -> Core (Lifted vars, List (Name, LiftedDef))
|
||||||
liftBody n tm
|
liftBody n tm
|
||||||
= do l <- newRef Lifts (MkLDefs n [] 0)
|
= do l <- newRef Lifts (MkLDefs n [] 0)
|
||||||
|
196
src/Compiler/VMCode.idr
Normal file
196
src/Compiler/VMCode.idr
Normal file
@ -0,0 +1,196 @@
|
|||||||
|
module Compiler.VMCode
|
||||||
|
|
||||||
|
import Compiler.ANF
|
||||||
|
|
||||||
|
import Core.CompileExpr
|
||||||
|
import Core.Context
|
||||||
|
import Core.Core
|
||||||
|
import Core.TT
|
||||||
|
|
||||||
|
import Data.Vect
|
||||||
|
|
||||||
|
import Debug.Trace
|
||||||
|
|
||||||
|
%default covering
|
||||||
|
|
||||||
|
public export
|
||||||
|
data Reg : Type where
|
||||||
|
RVal : Reg
|
||||||
|
Loc : Int -> Reg
|
||||||
|
Discard : Reg
|
||||||
|
|
||||||
|
-- VM instructions - first Reg is where the result goes, unless stated
|
||||||
|
-- otherwise.
|
||||||
|
|
||||||
|
-- As long as you have a representation of closures, and an 'apply' function
|
||||||
|
-- which adds an argument and evaluates if it's fully applied, then you can
|
||||||
|
-- translate this directly to a target language program.
|
||||||
|
public export
|
||||||
|
data VMInst : Type where
|
||||||
|
DECLARE : Reg -> VMInst
|
||||||
|
START : VMInst -- start of the main body of the function
|
||||||
|
ASSIGN : Reg -> Reg -> VMInst
|
||||||
|
MKCON : Reg -> (tag : Int) -> (args : List Reg) -> VMInst
|
||||||
|
MKCLOSURE : Reg -> Name -> (missing : Nat) -> (args : List Reg) -> VMInst
|
||||||
|
MKCONSTANT : Reg -> Constant -> VMInst
|
||||||
|
|
||||||
|
APPLY : Reg -> (f : Reg) -> (a : Reg) -> VMInst
|
||||||
|
CALL : Reg -> (tailpos : Bool) -> Name -> (args : List Reg) -> VMInst
|
||||||
|
OP : Reg -> PrimFn arity -> Vect arity Reg -> VMInst
|
||||||
|
EXTPRIM : Reg -> Name -> List Reg -> VMInst
|
||||||
|
|
||||||
|
CASE : Reg -> -- scrutinee
|
||||||
|
(alts : List (Int, List VMInst)) -> -- based on constructor tag
|
||||||
|
(def : Maybe (List VMInst)) ->
|
||||||
|
VMInst
|
||||||
|
CONSTCASE : Reg -> -- scrutinee
|
||||||
|
(alts : List (Constant, List VMInst)) ->
|
||||||
|
(def : Maybe (List VMInst)) ->
|
||||||
|
VMInst
|
||||||
|
PROJECT : Reg -> (value : Reg) -> (pos : Int) -> VMInst
|
||||||
|
NULL : Reg -> VMInst
|
||||||
|
|
||||||
|
ERROR : String -> VMInst
|
||||||
|
|
||||||
|
public export
|
||||||
|
data VMDef : Type where
|
||||||
|
MkVMFun : (args : List Int) -> List VMInst -> VMDef
|
||||||
|
MkVMError : List VMInst -> VMDef
|
||||||
|
|
||||||
|
export
|
||||||
|
Show Reg where
|
||||||
|
show RVal = "RVAL"
|
||||||
|
show (Loc i) = "v" ++ show i
|
||||||
|
show Discard = "DISCARD"
|
||||||
|
|
||||||
|
export
|
||||||
|
Show VMInst where
|
||||||
|
show (DECLARE r) = "DECLARE " ++ show r
|
||||||
|
show START = "START"
|
||||||
|
show (ASSIGN r v) = show r ++ " := " ++ show v
|
||||||
|
show (MKCON r t args)
|
||||||
|
= show r ++ " := MKCON " ++ show t ++ " (" ++
|
||||||
|
showSep ", " (map show args) ++ ")"
|
||||||
|
show (MKCLOSURE r n m args)
|
||||||
|
= show r ++ " := MKCLOSURE " ++ show n ++ " " ++ show m ++ " (" ++
|
||||||
|
showSep ", " (map show args) ++ ")"
|
||||||
|
show (MKCONSTANT r c) = show r ++ " := MKCONSTANT " ++ show c
|
||||||
|
show (APPLY r f a) = show r ++ " := " ++ show f ++ " @ " ++ show a
|
||||||
|
show (CALL r t n args)
|
||||||
|
= show r ++ " := " ++ (if t then "TAILCALL " else "CALL ") ++
|
||||||
|
show n ++ "(" ++ showSep ", " (map show args) ++ ")"
|
||||||
|
show (OP r op args)
|
||||||
|
= show r ++ " := " ++ "OP " ++
|
||||||
|
show op ++ "(" ++ showSep ", " (map show (toList args)) ++ ")"
|
||||||
|
show (EXTPRIM r n args)
|
||||||
|
= show r ++ " := " ++ "EXTPRIM " ++
|
||||||
|
show n ++ "(" ++ showSep ", " (map show args) ++ ")"
|
||||||
|
|
||||||
|
show (CASE scr alts def)
|
||||||
|
= "CASE " ++ show scr ++ " " ++ show alts ++ " {default: " ++ show def ++ "}"
|
||||||
|
show (CONSTCASE scr alts def)
|
||||||
|
= "CASE " ++ show scr ++ " " ++ show alts ++ " {default: " ++ show def ++ "}"
|
||||||
|
|
||||||
|
show (PROJECT r val pos)
|
||||||
|
= show r ++ " := PROJECT(" ++ show val ++ ", " ++ show pos ++ ")"
|
||||||
|
show (NULL r) = show r ++ " := NULL"
|
||||||
|
show (ERROR str) = "ERROR " ++ show str
|
||||||
|
|
||||||
|
export
|
||||||
|
Show VMDef where
|
||||||
|
show (MkVMFun args body) = show args ++ ": " ++ show body
|
||||||
|
show (MkVMError err) = "Error: " ++ show err
|
||||||
|
|
||||||
|
toReg : AVar -> Reg
|
||||||
|
toReg (ALocal i) = Loc i
|
||||||
|
toReg ANull = Discard
|
||||||
|
|
||||||
|
toVM : (tailpos : Bool) -> (target : Reg) -> ANF -> List VMInst
|
||||||
|
toVM t Discard _ = []
|
||||||
|
toVM t res (AV fc (ALocal i))
|
||||||
|
= [ASSIGN res (Loc i)]
|
||||||
|
toVM t res (AAppName fc n args)
|
||||||
|
= [CALL res t n (map toReg args)]
|
||||||
|
toVM t res (AUnderApp fc n m args)
|
||||||
|
= [MKCLOSURE res n m (map toReg args)]
|
||||||
|
toVM t res (AApp fc f a)
|
||||||
|
= [APPLY res (toReg f) (toReg a)]
|
||||||
|
toVM t res (ALet fc var val body)
|
||||||
|
= toVM False (Loc var) val ++ toVM t res body
|
||||||
|
toVM t res (ACon fc n tag args)
|
||||||
|
= [MKCON res tag (map toReg args)]
|
||||||
|
toVM t res (AOp fc op args)
|
||||||
|
= [OP res op (map toReg args)]
|
||||||
|
toVM t res (AExtPrim fc p args)
|
||||||
|
= [EXTPRIM res p (map toReg args)]
|
||||||
|
toVM t res (AConCase fc (ALocal scr) alts def)
|
||||||
|
= [CASE (Loc scr) (map toVMConAlt alts) (map (toVM t res) def)]
|
||||||
|
where
|
||||||
|
projectArgs : Int -> List Int -> List VMInst
|
||||||
|
projectArgs i [] = []
|
||||||
|
projectArgs i (arg :: args)
|
||||||
|
= PROJECT (Loc arg) (Loc scr) i :: projectArgs (i + 1) args
|
||||||
|
|
||||||
|
toVMConAlt : AConAlt -> (Int, List VMInst)
|
||||||
|
toVMConAlt (MkAConAlt n tag args code)
|
||||||
|
= (tag, projectArgs 0 args ++ toVM t res code)
|
||||||
|
toVM t res (AConstCase fc (ALocal scr) alts def)
|
||||||
|
= [CONSTCASE (Loc scr) (map toVMConstAlt alts) (map (toVM t res) def)]
|
||||||
|
where
|
||||||
|
toVMConstAlt : AConstAlt -> (Constant, List VMInst)
|
||||||
|
toVMConstAlt (MkAConstAlt c code)
|
||||||
|
= (c, toVM t res code)
|
||||||
|
toVM t res (APrimVal fc c)
|
||||||
|
= [MKCONSTANT res c]
|
||||||
|
toVM t res (AErased fc)
|
||||||
|
= [NULL res]
|
||||||
|
toVM t res (ACrash fc err)
|
||||||
|
= [ERROR err]
|
||||||
|
toVM t res _
|
||||||
|
= [NULL res]
|
||||||
|
|
||||||
|
findVars : VMInst -> List Int
|
||||||
|
findVars (ASSIGN (Loc r) _) = [r]
|
||||||
|
findVars (MKCON (Loc r) _ _) = [r]
|
||||||
|
findVars (MKCLOSURE (Loc r) _ _ _) = [r]
|
||||||
|
findVars (MKCONSTANT (Loc r) _) = [r]
|
||||||
|
findVars (APPLY (Loc r) _ _) = [r]
|
||||||
|
findVars (CALL (Loc r) _ _ _) = [r]
|
||||||
|
findVars (OP (Loc r) _ _) = [r]
|
||||||
|
findVars (EXTPRIM (Loc r) _ _) = [r]
|
||||||
|
findVars (CASE _ alts d)
|
||||||
|
= concatMap findVarAlt alts ++ fromMaybe [] (map (concatMap findVars) d)
|
||||||
|
where
|
||||||
|
findVarAlt : (Int, List VMInst) -> List Int
|
||||||
|
findVarAlt (t, code) = concatMap findVars code
|
||||||
|
findVars (CONSTCASE _ alts d)
|
||||||
|
= concatMap findConstVarAlt alts ++ fromMaybe [] (map (concatMap findVars) d)
|
||||||
|
where
|
||||||
|
findConstVarAlt : (Constant, List VMInst) -> List Int
|
||||||
|
findConstVarAlt (t, code) = concatMap findVars code
|
||||||
|
findVars (PROJECT (Loc r) _ _) = [r]
|
||||||
|
findVars _ = []
|
||||||
|
|
||||||
|
declareVars : List Int -> List VMInst -> List VMInst
|
||||||
|
declareVars got code
|
||||||
|
= let vs = concatMap findVars code in
|
||||||
|
declareAll got vs
|
||||||
|
where
|
||||||
|
declareAll : List Int -> List Int -> List VMInst
|
||||||
|
declareAll got [] = START :: code
|
||||||
|
declareAll got (i :: is)
|
||||||
|
= if i `elem` got
|
||||||
|
then declareAll got is
|
||||||
|
else DECLARE (Loc i) :: declareAll (i :: got) is
|
||||||
|
|
||||||
|
export
|
||||||
|
toVMDef : ANFDef -> Maybe VMDef
|
||||||
|
toVMDef (MkAFun args body)
|
||||||
|
= Just $ MkVMFun args (declareVars args (toVM True RVal body))
|
||||||
|
toVMDef (MkAError body)
|
||||||
|
= Just $ MkVMError (declareVars [] (toVM True RVal body))
|
||||||
|
toVMDef _ = Nothing
|
||||||
|
|
||||||
|
export
|
||||||
|
allDefs : List (Name, ANFDef) -> List (Name, VMDef)
|
||||||
|
allDefs = mapMaybe (\ (n, d) => do d' <- toVMDef d; pure (n, d'))
|
@ -45,7 +45,10 @@ Eq CG where
|
|||||||
|
|
||||||
export
|
export
|
||||||
availableCGs : List (String, CG)
|
availableCGs : List (String, CG)
|
||||||
availableCGs = [("chez", Chez), ("chicken", Chicken), ("racket", Racket)]
|
availableCGs
|
||||||
|
= [ ("chez", Chez),
|
||||||
|
-- ("chicken", Chicken),
|
||||||
|
("racket", Racket)]
|
||||||
|
|
||||||
export
|
export
|
||||||
getCG : String -> Maybe CG
|
getCG : String -> Maybe CG
|
||||||
@ -101,6 +104,8 @@ record Session where
|
|||||||
debugElabCheck : Bool -- do conversion check to verify results of elaborator
|
debugElabCheck : Bool -- do conversion check to verify results of elaborator
|
||||||
dumpcases : Maybe String -- file to output compiled case trees
|
dumpcases : Maybe String -- file to output compiled case trees
|
||||||
dumplifted : Maybe String -- file to output lambda lifted definitions
|
dumplifted : Maybe String -- file to output lambda lifted definitions
|
||||||
|
dumpanf : Maybe String -- file to output ANF definitions
|
||||||
|
dumpvmcode : Maybe String -- file to output VM code definitions
|
||||||
|
|
||||||
public export
|
public export
|
||||||
record PPrinter where
|
record PPrinter where
|
||||||
@ -146,7 +151,7 @@ defaultPPrint = MkPPOpts False True False
|
|||||||
|
|
||||||
defaultSession : Session
|
defaultSession : Session
|
||||||
defaultSession = MkSessionOpts False False False Chez 0 False False
|
defaultSession = MkSessionOpts False False False Chez 0 False False
|
||||||
Nothing Nothing
|
Nothing Nothing Nothing Nothing
|
||||||
|
|
||||||
defaultElab : ElabDirectives
|
defaultElab : ElabDirectives
|
||||||
defaultElab = MkElabDirectives True True PartialOK 3 True
|
defaultElab = MkElabDirectives True True PartialOK 3 True
|
||||||
|
@ -73,6 +73,10 @@ data CLOpt
|
|||||||
DumpCases String |
|
DumpCases String |
|
||||||
||| Dump lambda lifted defs before compiling
|
||| Dump lambda lifted defs before compiling
|
||||||
DumpLifted String |
|
DumpLifted String |
|
||||||
|
||| Dump ANF defs before compiling
|
||||||
|
DumpANF String |
|
||||||
|
||| Dump VM code defs before compiling
|
||||||
|
DumpVMCode String |
|
||||||
||| Run a REPL command then exit immediately
|
||| Run a REPL command then exit immediately
|
||||||
RunREPL String |
|
RunREPL String |
|
||||||
FindIPKG |
|
FindIPKG |
|
||||||
@ -150,7 +154,11 @@ options = [MkOpt ["--check", "-c"] [] [CheckOnly]
|
|||||||
MkOpt ["--dumpcases"] ["output file"] (\f => [DumpCases f])
|
MkOpt ["--dumpcases"] ["output file"] (\f => [DumpCases f])
|
||||||
Nothing, -- dump case trees to the given file
|
Nothing, -- dump case trees to the given file
|
||||||
MkOpt ["--dumplifted"] ["output file"] (\f => [DumpLifted f])
|
MkOpt ["--dumplifted"] ["output file"] (\f => [DumpLifted f])
|
||||||
Nothing, -- dump case trees to the given file
|
Nothing, -- dump lambda lifted trees to the given file
|
||||||
|
MkOpt ["--dumpanf"] ["output file"] (\f => [DumpANF f])
|
||||||
|
Nothing, -- dump ANF to the given file
|
||||||
|
MkOpt ["--dumpvmcode"] ["output file"] (\f => [DumpVMCode f])
|
||||||
|
Nothing, -- dump VM Code to the given file
|
||||||
MkOpt ["--debug-elab-check"] [] [DebugElabCheck]
|
MkOpt ["--debug-elab-check"] [] [DebugElabCheck]
|
||||||
Nothing -- do more elaborator checks (currently conversion in LinearCheck)
|
Nothing -- do more elaborator checks (currently conversion in LinearCheck)
|
||||||
]
|
]
|
||||||
|
@ -92,6 +92,12 @@ preOptions (DumpCases f :: opts)
|
|||||||
preOptions (DumpLifted f :: opts)
|
preOptions (DumpLifted f :: opts)
|
||||||
= do setSession (record { dumplifted = Just f } !getSession)
|
= do setSession (record { dumplifted = Just f } !getSession)
|
||||||
preOptions opts
|
preOptions opts
|
||||||
|
preOptions (DumpANF f :: opts)
|
||||||
|
= do setSession (record { dumpanf = Just f } !getSession)
|
||||||
|
preOptions opts
|
||||||
|
preOptions (DumpVMCode f :: opts)
|
||||||
|
= do setSession (record { dumpvmcode = Just f } !getSession)
|
||||||
|
preOptions opts
|
||||||
preOptions (_ :: opts) = preOptions opts
|
preOptions (_ :: opts) = preOptions opts
|
||||||
|
|
||||||
-- Options to be processed after type checking. Returns whether execution
|
-- Options to be processed after type checking. Returns whether execution
|
||||||
|
Loading…
Reference in New Issue
Block a user