on master help sign in
Added defunctionalisation to IRTS

idris --fovm now gives a full defunctionalising compiler for a supercombinator language

commit4e0fe225274d1537dab3d462404f367154bbfb01 authorEdwin Brady <eb@cs.st-andrews.ac.uk> dateTue 4 Sep 2012, 16:36 (14 years ago) parent517acc1
8 files changed+194−39
idris.cabal+1−1 iif/adder.iif+30 iif/testmap.iif+18 rts/idris_rts.h+1−1 src/IRTS/CodegenC.hs+22−28 src/IRTS/Defunctionalise.hs+106−2 src/IRTS/LParser.hs+10−1 src/IRTS/Lang.hs+6−6
idris.cabal+1−1
@@ -71,7 +71,7 @@ Executable idris
7171
7272 RTS.Bytecode, RTS.SC, RTS.PreC, RTS.CodegenC,
7373 IRTS.Lang, IRTS.LParser, IRTS.Bytecode, IRTS.Simplified,
74− IRTS.CodegenC,
74+ IRTS.CodegenC, IRTS.Defunctionalise,
7575
7676 Paths_idris
7777
iif/adder.iifnew file+30
@@ -0,0 +1,30 @@
1+data O 0
2+data S 1
3+
4+fun plus(x, y) = case x of {
5+ O => y
6+ | S(k) => S (plus(k, y))
7+ }
8+
9+fun natToInt(x) = case x of {
10+ O => 0
11+ | S(k) => let y = natToInt(k) in y + 1
12+ }
13+
14+fun adder(arity, acc) = case arity of {
15+ O => acc
16+ | S(k) => adderAux(k, acc)
17+ }
18+
19+fun adderAux(k, acc, n) = adder(k, plus(acc, n))
20+
21+fun zero() = O
22+fun one() = S(zero)
23+fun two() = S(one)
24+fun three() = S(two)
25+fun four() = S(three)
26+fun five() = S(four)
27+
28+fun main() = %WriteInt(natToInt(adder(three, two, three, four, five)))
29+
30+
iif/testmap.iifnew file+18
@@ -0,0 +1,18 @@
1+data Nil 0
2+data Cons 2
3+
4+fun twice(f, x) = f(f(x))
5+
6+fun map(f, xs) = case xs of {
7+ Nil => Nil
8+ | Cons(y, ys) => Cons(f(y), map(f, ys))
9+ }
10+
11+fun dumpList(xs) = case xs of {
12+ Nil => "END"
13+ | Cons(y, ys) => %IntString(y) ++ ", " ++ dumpList(ys)
14+ }
15+
16+fun double(x) = x + x
17+
18+fun main() = %WriteString(dumpList(map(twice(double), Cons(4, Cons(6, Nil)))))
rts/idris_rts.h+1−1
@@ -64,7 +64,7 @@ typedef void(*func)(VM*, VAL*);
6464#define GETPTR(x) (((VAL)(x))->info.ptr)
6565#define GETFLOAT(x) (((VAL)(x))->info.f)
6666
67−#define TAG(x) ((x)->info.c.tag)
67+#define TAG(x) (ISINT(x) ? (-1) : ( (x)->ty == CON ? (x)->info.c.tag : (-1)) )
6868
6969// Integers, floats and operators
7070
src/IRTS/CodegenC.hs+22−28
@@ -18,7 +18,7 @@ import Control.Monad
1818
1919data DbgLevel = NONE | DEBUG | TRACE
2020
21−codegenC :: [(Name, LDecl)] ->
21+codegenC :: [(Name, SDecl)] ->
2222 String -> -- output file name
2323 Bool -> -- generate executable if True, only .o if False
2424 [FilePath] -> -- include files
@@ -27,33 +27,27 @@ codegenC :: [(Name, LDecl)] ->
2727 IO ()
2828codegenC defs out exec incs libs dbg
2929 = do -- print defs
30− let tagged = addTags defs
31− let ctxtIn = addAlist tagged emptyContext
32− let checked = checkDefs ctxtIn tagged
33− case checked of
34− OK c -> do let bc = map toBC c
35− let h = concatMap toDecl (map fst bc)
36− let cc = concatMap (uncurry toC) bc
37− d <- getDataDir
38− mprog <- readFile (d ++ "/rts/idris_main.c")
39− let cout = headers incs ++ debug dbg ++ h ++ cc ++
40− (if exec then mprog else "")
41− (tmpn, tmph) <- tempfile
42− hPutStr tmph cout
43− hFlush tmph
44− hClose tmph
45− let gcc = "gcc -x c " ++
46− (if exec then "" else " - c ") ++
47− gccDbg dbg ++
48− " " ++ tmpn ++
49− " `idris --link` `idris --include` " ++ libs ++
50− " -lidris_rts -o " ++ out
51−-- putStrLn cout
52− exit <- system gcc
53− when (exit /= ExitSuccess) $
54− putStrLn ("FAILURE: " ++ gcc)
55−
56− Error e -> fail $ "Can't happen: Something went wrong in codegenC\n" ++ show e
30+ let bc = map toBC defs
31+ let h = concatMap toDecl (map fst bc)
32+ let cc = concatMap (uncurry toC) bc
33+ d <- getDataDir
34+ mprog <- readFile (d ++ "/rts/idris_main.c")
35+ let cout = headers incs ++ debug dbg ++ h ++ cc ++
36+ (if exec then mprog else "")
37+ (tmpn, tmph) <- tempfile
38+ hPutStr tmph cout
39+ hFlush tmph
40+ hClose tmph
41+ let gcc = "gcc -x c " ++
42+ (if exec then "" else " - c ") ++
43+ gccDbg dbg ++
44+ " " ++ tmpn ++
45+ " `idris --link` `idris --include` " ++ libs ++
46+ " -lidris_rts -o " ++ out
47+-- putStrLn cout
48+ exit <- system gcc
49+ when (exit /= ExitSuccess) $
50+ putStrLn ("FAILURE: " ++ gcc)
5751
5852headers [] = "#include <idris_rts.h>\n\n"
5953headers (x : xs) = "#include <" ++ x ++ ">\n" ++ headers xs
src/IRTS/Defunctionalise.hs+106−2
@@ -3,8 +3,22 @@ module IRTS.Defunctionalise where
33import IRTS.Lang
44import Core.TT
55
6−defunctionalise :: [(Name, LDecl)] -> [(Name, LDecl)]
7−defunctionalise defs = defs -- TODO!
6+import Debug.Trace
7+import Data.Maybe
8+
9+defunctionalise :: Int -> LDefs -> LDefs
10+defunctionalise nexttag defs
11+ = let all = toAlist defs
12+ newcons = concatMap toCons (getFn all)
13+ eval = mkEval newcons
14+ app = mkApply newcons
15+ condecls = declare nexttag newcons in
16+ addAlist (eval : app : condecls ++ (map (addApps defs) all)) emptyContext
17+
18+getFn :: [(Name, LDecl)] -> [(Name, Int)]
19+getFn xs = mapMaybe fnData xs
20+ where fnData (n, LFun _ args _) = Just (n, length args)
21+ fnData _ = Nothing
822
923-- To defunctionalise:
1024--
@@ -16,5 +30,95 @@ defunctionalise defs = defs -- TODO!
1630-- 5 Create an APPLY function which adds an argument to each underapplication (or calls
1731-- APPLY again for an exact application)
1832-- 6 Wrap overapplications in chains of APPLY
33+-- 7 Wrap unknown applications (i.e. applications of local variables) in chains of APPLY
34+-- 8 Add explicit EVAL to case, primitives, and foreign calls
35+
36+addApps :: LDefs -> (Name, LDecl) -> (Name, LDecl)
37+addApps defs o@(n, LConstructor _ _ _) = o
38+addApps defs (n, LFun _ args e) = (n, LFun n args (aa args e))
39+ where
40+ aa env (LV (Glob n)) | n `elem` env = LV (Glob n)
41+ | otherwise = aa env (LApp False n [])
42+-- aa env e@(LApp tc (MN 0 "EVAL") [a]) = e
43+ aa env (LApp tc n args)
44+ = let args' = map (aa env) args in
45+ case lookupCtxt Nothing n defs of
46+ [LConstructor _ i ar] -> LApp tc n args'
47+ [LFun _ as _] -> let arity = length as in
48+ fixApply tc n args' arity
49+ [] -> chainAPPLY (LV (Glob n)) args'
50+ aa env (LLet n v sc) = LLet n (aa env v) (aa (n : env) sc)
51+ aa env (LCon i n args) = LCon i n (map (aa env) args)
52+ aa env (LCase e alts) = LCase (eEVAL (aa env e)) (map (aaAlt env) alts)
53+ aa env (LConst c) = LConst c
54+ aa env (LForeign l t n args) = LForeign l t n (map (aaF env) args)
55+ aa env (LOp f args) = LOp f (map (eEVAL . (aa env)) args)
56+
57+ aaF env (t, e) = (t, eEVAL (aa env e))
58+
59+ aaAlt env (LConCase i n args e) = LConCase i n args (aa (args ++ env) e)
60+ aaAlt env (LConstCase c e) = LConstCase c (aa env e)
61+ aaAlt env (LDefaultCase e) = LDefaultCase (aa env e)
62+
63+ eEVAL x = LApp False (MN 0 "EVAL") [x]
64+
65+ fixApply tc n args ar
66+ | length args == ar = LApp tc n args
67+ | length args < ar = LApp tc (mkUnderCon n (ar - length args)) args
68+ | length args > ar = chainAPPLY (LApp tc n (take ar args)) (drop ar args)
69+
70+ chainAPPLY f [] = f
71+ chainAPPLY f (a : as) = chainAPPLY (LApp False (MN 0 "APPLY") [f, a]) as
72+
73+data EvalApply a = EvalCase a
74+ | ApplyCase a
75+ deriving Show
76+
77+-- For a function name, generate a list of
78+-- data constuctors, and whether to handle them in EVAL or APPLY
79+
80+toCons :: (Name, Int) -> [(Name, Int, EvalApply LAlt)]
81+toCons (n, i) = (mkFnCon n, i,
82+ EvalCase (LConCase (-1) (mkFnCon n) (take i (genArgs 0))
83+ (LApp False n (map (LV . Glob) (take i (genArgs 0))))))
84+ :
85+ mkApplyCase n 0 i
86+
87+mkApplyCase fname n ar | n == ar = []
88+mkApplyCase fname n ar
89+ = let nm = mkUnderCon fname (ar - n) in
90+ (nm, n, ApplyCase (LConCase (-1) nm (take n (genArgs 0))
91+ (LApp False (mkUnderCon fname (ar - (n + 1)))
92+ (map (LV . Glob) (take n (genArgs 0) ++
93+ [MN 0 "arg"])))))
94+ : mkApplyCase fname (n + 1) ar
95+
96+mkEval :: [(Name, Int, EvalApply LAlt)] -> (Name, LDecl)
97+mkEval xs = (MN 0 "EVAL", LFun (MN 0 "EVAL") [MN 0 "arg"]
98+ (LCase (LV (Glob (MN 0 "arg")))
99+ (mapMaybe evalCase xs ++
100+ [LDefaultCase (LV (Glob (MN 0 "arg")))])))
101+ where
102+ evalCase (n, t, EvalCase x) = Just x
103+ evalCase _ = Nothing
104+
105+mkApply :: [(Name, Int, EvalApply LAlt)] -> (Name, LDecl)
106+mkApply xs = (MN 0 "APPLY", LFun (MN 0 "APPLY") [MN 0 "fn", MN 0 "arg"]
107+ (LCase (LApp False (MN 0 "EVAL") [LV (Glob (MN 0 "fn"))])
108+ (mapMaybe applyCase xs)))
109+ where
110+ applyCase (n, t, ApplyCase x) = Just x
111+ applyCase _ = Nothing
112+
113+declare :: Int -> [(Name, Int, EvalApply LAlt)] -> [(Name, LDecl)]
114+declare t xs = dec' t xs [] where
115+ dec' t [] acc = reverse acc
116+ dec' t ((n, ar, _) : xs) acc = dec' (t + 1) xs ((n, LConstructor n t ar) : acc)
117+
118+
119+genArgs i = MN i "P_c" : genArgs (i + 1)
19120
121+mkFnCon n = MN 0 ("P_" ++ show n)
122+mkUnderCon n 0 = n
123+mkUnderCon n missing = MN missing ("U_" ++ show n)
20124
src/IRTS/LParser.hs+10−1
@@ -6,6 +6,7 @@ import IRTS.Lang
66import IRTS.Simplified
77import IRTS.Bytecode
88import IRTS.CodegenC
9+import IRTS.Defunctionalise
910import Paths_idris
1011
1112import Text.ParserCombinators.Parsec
@@ -46,7 +47,15 @@ lchar = lexeme.char
4647
4748fovm :: FilePath -> IO ()
4849fovm f = do defs <- parseFOVM f
49− codegenC defs "a.out" True ["math.h"] "" TRACE
50+ let (nexttag, tagged) = addTags 0 defs
51+ let ctxtIn = addAlist tagged emptyContext
52+ let defuns = defunctionalise nexttag ctxtIn
53+-- print defuns
54+ let checked = checkDefs defuns (toAlist defuns)
55+-- print checked
56+ case checked of
57+ OK c -> codegenC c "a.out" True ["math.h"] "" TRACE
58+ Error e -> fail $ show e
5059
5160parseFOVM :: FilePath -> IO [(Name, LDecl)]
5261parseFOVM fname = do -- putStrLn $ "Reading " ++ fname
src/IRTS/Lang.hs+6−6
@@ -41,10 +41,10 @@ data LDecl = LFun Name [Name] LExp -- name, arg names, definition
4141
4242type LDefs = Ctxt LDecl
4343
44−addTags :: [(Name, LDecl)] -> [(Name, LDecl)]
45−addTags ds = tag 0 ds
46− where tag i ((n, LConstructor n' t a) : as)
47− = (n, LConstructor n' i a) : tag (i + 1) as
48− tag i (x : as) = x : tag i as
49− tag i [] = []
44+addTags :: Int -> [(Name, LDecl)] -> (Int, [(Name, LDecl)])
45+addTags i ds = tag i ds []
46+ where tag i ((n, LConstructor n' t a) : as) acc
47+ = tag (i + 1) as ((n, LConstructor n' i a) : acc)
48+ tag i (x : as) acc = tag i as (x : acc)
49+ tag i [] acc = (i, reverse acc)
5050