on aa7262e help sign in
Idris-dev/src/IRTS/CodegenC.hs
285 lines 13 kB history raw
1module IRTS.CodegenC (codegenC) where
3import Idris.AbsSyntax
4import IRTS.Bytecode
5import IRTS.Lang
6import IRTS.Simplified
7import IRTS.CodegenCommon
8import Core.TT
9import Paths_idris
10import Util.System
12import Data.Char
13import System.Process
14import System.Exit
15import System.IO
16import System.Directory
17import System.FilePath ((</>), (<.>))
18import Control.Monad
20codegenC :: [(Name, SDecl)] ->
21 String -> -- output file name
22 OutputType -> -- generate executable if True, only .o if False
23 [FilePath] -> -- include files
24 String -> -- extra object files
25 String -> -- extra compiler flags
26 DbgLevel ->
27 IO ()
28codegenC defs out exec incs objs libs dbg
29 = do -- print defs
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 == Executable) then mprog else "")
37 case exec of
38 Raw -> writeFile out cout
39 _ -> do
40 (tmpn, tmph) <- tempfile
41 hPutStr tmph cout
42 hFlush tmph
43 hClose tmph
44 let useclang = False
45 comp <- getCC
46 let gcc = comp ++ " " ++
47 gccDbg dbg ++
48 " -I. " ++ objs ++ " -x c " ++
49 (if (exec == Executable) then "" else " -c ") ++
50 " " ++ tmpn ++
51 " `idris --link` `idris --include` " ++ libs ++
52 " -o " ++ out
53-- putStrLn gcc
54 exit <- system gcc
55 when (exit /= ExitSuccess) $
56 putStrLn ("FAILURE: " ++ gcc)
58headers [] = "#include <idris_rts.h>\n#include <idris_stdfgn.h>\n" ++
59 "#include <gmp.h>\n#include <assert.h>\n"
60headers (x : xs) = "#include <" ++ x ++ ">\n" ++ headers xs
62debug TRACE = "#define IDRIS_TRACE\n\n"
63debug _ = ""
65gccDbg DEBUG = "-g"
66gccDbg TRACE = "-O2"
67gccDbg _ = "-O2"
69cname :: Name -> String
70cname n = "_idris_" ++ concatMap cchar (show n)
71 where cchar x | isAlpha x || isDigit x = [x]
72 | otherwise = "_" ++ show (fromEnum x) ++ "_"
74indent i = take (i * 4) (repeat ' ')
76creg RVal = "RVAL"
77creg (L i) = "LOC(" ++ show i ++ ")"
78creg (T i) = "TOP(" ++ show i ++ ")"
79creg Tmp = "REG1"
81toDecl :: Name -> String
82toDecl f = "void " ++ cname f ++ "(VM*, VAL*);\n"
84toC :: Name -> [BC] -> String
85toC f code
86 = -- "/* " ++ show code ++ "*/\n\n" ++
87 "void " ++ cname f ++ "(VM* vm, VAL* oldbase) {\n" ++
88 indent 1 ++ "INITFRAME;\n" ++
89 concatMap (bcc 1) code ++ "}\n\n"
91bcc :: Int -> BC -> String
92bcc i (ASSIGN l r) = indent i ++ creg l ++ " = " ++ creg r ++ ";\n"
93bcc i (ASSIGNCONST l c)
94 = indent i ++ creg l ++ " = " ++ mkConst c ++ ";\n"
95 where
96 mkConst (I i) = "MKINT(" ++ show i ++ ")"
97 mkConst (BI i) | i < (2^30) = "MKINT(" ++ show i ++ ")"
98 | otherwise = "MKBIGC(vm,\"" ++ show i ++ "\")"
99 mkConst (Fl f) = "MKFLOAT(vm, " ++ show f ++ ")"
100 mkConst (Ch c) = "MKINT(" ++ show (fromEnum c) ++ ")"
101 mkConst (Str s) = "MKSTR(vm, " ++ show s ++ ")"
102 mkConst _ = "MKINT(42424242)"
103bcc i (MKCON l tag args)
104 = indent i ++ creg Tmp ++ " = allocCon(vm, " ++ show (length args) ++
105 ", 0); " ++ "SETTAG(" ++ creg Tmp ++ ", " ++ show tag ++ ");\n" ++
106 indent i ++ setArgs 0 args ++ "\n" ++
107 indent i ++ creg l ++ " = " ++ creg Tmp ++ ";\n"
109-- "MKCON(vm, " ++ creg l ++ ", " ++ show tag ++ ", " ++
110-- show (length args) ++ concatMap showArg args ++ ");\n"
111 where showArg r = ", " ++ creg r
112 setArgs i [] = ""
113 setArgs i (x : xs) = "SETARG(" ++ creg Tmp ++ ", " ++ show i ++ ", " ++ creg x ++
114 "); " ++ setArgs (i + 1) xs
116bcc i (PROJECT l loc a) = indent i ++ "PROJECT(vm, " ++ creg l ++ ", " ++ show loc ++
117 ", " ++ show a ++ ");\n"
118bcc i (PROJECTINTO r t idx)
119 = indent i ++ creg r ++ " = GETARG(" ++ creg t ++ ", " ++ show idx ++ ");\n"
120bcc i (CASE r code def)
121 = indent i ++ "switch(TAG(" ++ creg r ++ ")) {\n" ++
122 concatMap (showCase i) code ++
123 showDef i def ++
124 indent i ++ "}\n"
125 where
126 showCase i (t, bc) = indent i ++ "case " ++ show t ++ ":\n"
127 ++ concatMap (bcc (i+1)) bc ++ indent (i + 1) ++ "break;\n"
128 showDef i Nothing = ""
129 showDef i (Just c) = indent i ++ "default:\n"
130 ++ concatMap (bcc (i+1)) c ++ indent (i + 1) ++ "break;\n"
131bcc i (CONSTCASE r code def)
132 | intConsts code
133 = indent i ++ "switch(GETINT(" ++ creg r ++ ")) {\n" ++
134 concatMap (showCase i) code ++
135 showDef i def ++
136 indent i ++ "}\n"
137 | strConsts code
138 = concatMap (strCase ("GETSTR(" ++ creg r ++ ")")) code ++
139 indent i ++ "{\n" ++ showDefS i def ++ indent i ++ "}\n"
140 | bigintConsts code
141 = concatMap (biCase (creg r)) code ++
142 indent i ++ "{\n" ++ showDefS i def ++ indent i ++ "}\n"
143 | otherwise = error $ "Can't happen: Can't compile const case " ++ show code
144 where
145 intConsts ((I _, _ ) : _) = True
146 intConsts ((Ch _, _ ) : _) = True
147 intConsts _ = False
149 bigintConsts ((BI _, _ ) : _) = True
150 bigintConsts _ = False
152 strConsts ((Str _, _ ) : _) = True
153 strConsts _ = False
155 strCase sv (s, bc) =
156 indent i ++ "if (strcmp(" ++ sv ++ ", " ++ show s ++ ") == 0) {\n" ++
157 concatMap (bcc (i+1)) bc ++ indent i ++ "} else\n"
158 biCase bv (BI b, bc) =
159 indent i ++ "if (bigEqConst(" ++ bv ++ ", " ++ show b ++ ")) {\n"
160 ++ concatMap (bcc (i+1)) bc ++ indent i ++ "} else\n"
162 showCase i (t, bc) = indent i ++ "case " ++ show t ++ ":\n"
163 ++ concatMap (bcc (i+1)) bc ++
164 indent (i + 1) ++ "break;\n"
165 showDef i Nothing = ""
166 showDef i (Just c) = indent i ++ "default:\n"
167 ++ concatMap (bcc (i+1)) c ++
168 indent (i + 1) ++ "break;\n"
169 showDefS i Nothing = ""
170 showDefS i (Just c) = concatMap (bcc (i+1)) c
172bcc i (CALL n) = indent i ++ "CALL(" ++ cname n ++ ");\n"
173bcc i (TAILCALL n) = indent i ++ "TAILCALL(" ++ cname n ++ ");\n"
174bcc i (SLIDE n) = indent i ++ "SLIDE(vm, " ++ show n ++ ");\n"
175bcc i REBASE = indent i ++ "REBASE;\n"
176bcc i (RESERVE n) = indent i ++ "RESERVE(" ++ show n ++ ");\n"
177bcc i (ADDTOP n) = indent i ++ "ADDTOP(" ++ show n ++ ");\n"
178bcc i (TOPBASE n) = indent i ++ "TOPBASE(" ++ show n ++ ");\n"
179bcc i (BASETOP n) = indent i ++ "BASETOP(" ++ show n ++ ");\n"
180bcc i STOREOLD = indent i ++ "STOREOLD;\n"
181bcc i (OP l fn args) = indent i ++ doOp (creg l ++ " = ") fn args ++ ";\n"
182bcc i (FOREIGNCALL l LANG_C rty fn args)
183 = indent i ++
184 c_irts rty (creg l ++ " = ")
185 (fn ++ "(" ++ showSep "," (map fcall args) ++ ")") ++ ";\n"
186 where fcall (t, arg) = irts_c t (creg arg)
187bcc i (NULL r) = indent i ++ creg r ++ " = NULL;\n" -- clear, so it'll be GCed
188bcc i (ERROR str) = indent i ++ "fprintf(stderr, " ++ show str ++ "); assert(0); exit(-1);"
189-- bcc i _ = indent i ++ "// not done yet\n"
191c_irts FInt l x = l ++ "MKINT((i_int)(" ++ x ++ "))"
192c_irts FChar l x = l ++ "MKINT((i_int)(" ++ x ++ "))"
193c_irts FString l x = l ++ "MKSTR(vm, " ++ x ++ ")"
194c_irts FUnit l x = x
195c_irts FPtr l x = l ++ "MKPTR(vm, " ++ x ++ ")"
196c_irts FDouble l x = l ++ "MKFLOAT(vm, " ++ x ++ ")"
197c_irts FAny l x = l ++ x
199irts_c FInt x = "GETINT(" ++ x ++ ")"
200irts_c FChar x = "GETINT(" ++ x ++ ")"
201irts_c FString x = "GETSTR(" ++ x ++ ")"
202irts_c FUnit x = x
203irts_c FPtr x = "GETPTR(" ++ x ++ ")"
204irts_c FDouble x = "GETFLOAT(" ++ x ++ ")"
205irts_c FAny x = x
207doOp v LPlus [l, r] = v ++ "ADD(" ++ creg l ++ ", " ++ creg r ++ ")"
208doOp v LMinus [l, r] = v ++ "INTOP(-," ++ creg l ++ ", " ++ creg r ++ ")"
209doOp v LTimes [l, r] = v ++ "MULT(" ++ creg l ++ ", " ++ creg r ++ ")"
210doOp v LDiv [l, r] = v ++ "INTOP(/," ++ creg l ++ ", " ++ creg r ++ ")"
211doOp v LMod [l, r] = v ++ "INTOP(%," ++ creg l ++ ", " ++ creg r ++ ")"
212doOp v LEq [l, r] = v ++ "INTOP(==," ++ creg l ++ ", " ++ creg r ++ ")"
213doOp v LLt [l, r] = v ++ "INTOP(<," ++ creg l ++ ", " ++ creg r ++ ")"
214doOp v LLe [l, r] = v ++ "INTOP(<=," ++ creg l ++ ", " ++ creg r ++ ")"
215doOp v LGt [l, r] = v ++ "INTOP(>," ++ creg l ++ ", " ++ creg r ++ ")"
216doOp v LGe [l, r] = v ++ "INTOP(>=," ++ creg l ++ ", " ++ creg r ++ ")"
218doOp v LFPlus [l, r] = v ++ "FLOATOP(+," ++ creg l ++ ", " ++ creg r ++ ")"
219doOp v LFMinus [l, r] = v ++ "FLOATOP(-," ++ creg l ++ ", " ++ creg r ++ ")"
220doOp v LFTimes [l, r] = v ++ "FLOATOP(*," ++ creg l ++ ", " ++ creg r ++ ")"
221doOp v LFDiv [l, r] = v ++ "FLOATOP(/," ++ creg l ++ ", " ++ creg r ++ ")"
222doOp v LFEq [l, r] = v ++ "FLOATBOP(==," ++ creg l ++ ", " ++ creg r ++ ")"
223doOp v LFLt [l, r] = v ++ "FLOATBOP(<," ++ creg l ++ ", " ++ creg r ++ ")"
224doOp v LFLe [l, r] = v ++ "FLOATBOP(<=," ++ creg l ++ ", " ++ creg r ++ ")"
225doOp v LFGt [l, r] = v ++ "FLOATBOP(>," ++ creg l ++ ", " ++ creg r ++ ")"
226doOp v LFGe [l, r] = v ++ "FLOATBOP(>=," ++ creg l ++ ", " ++ creg r ++ ")"
228doOp v LBPlus [l, r] = v ++ "idris_bigPlus(vm, " ++ creg l ++ ", " ++ creg r ++ ")"
229doOp v LBMinus [l, r] = v ++ "idris_bigMinus(vm, " ++ creg l ++ ", " ++ creg r ++ ")"
230doOp v LBTimes [l, r] = v ++ "idris_bigTimes(vm, " ++ creg l ++ ", " ++ creg r ++ ")"
231doOp v LBDiv [l, r] = v ++ "idris_bigDivide(vm, " ++ creg l ++ ", " ++ creg r ++ ")"
232doOp v LBMod [l, r] = v ++ "idris_bigMod(vm, " ++ creg l ++ ", " ++ creg r ++ ")"
233doOp v LBEq [l, r] = v ++ "idris_bigEq(vm, " ++ creg l ++ ", " ++ creg r ++ ")"
234doOp v LBLt [l, r] = v ++ "idris_bigLt(vm, " ++ creg l ++ ", " ++ creg r ++ ")"
235doOp v LBLe [l, r] = v ++ "idris_bigLe(vm, " ++ creg l ++ ", " ++ creg r ++ ")"
236doOp v LBGt [l, r] = v ++ "idris_bigGt(vm, " ++ creg l ++ ", " ++ creg r ++ ")"
237doOp v LBGe [l, r] = v ++ "idris_bigGe(vm, " ++ creg l ++ ", " ++ creg r ++ ")"
239doOp v LStrConcat [l,r] = v ++ "idris_concat(vm, " ++ creg l ++ ", " ++ creg r ++ ")"
240doOp v LStrLt [l,r] = v ++ "idris_strlt(vm, " ++ creg l ++ ", " ++ creg r ++ ")"
241doOp v LStrEq [l,r] = v ++ "idris_streq(vm, " ++ creg l ++ ", " ++ creg r ++ ")"
242doOp v LStrLen [x] = v ++ "idris_strlen(vm, " ++ creg x ++ ")"
244doOp v LIntFloat [x] = v ++ "idris_castIntFloat(" ++ creg x ++ ")"
245doOp v LFloatInt [x] = v ++ "idris_castFloatInt(" ++ creg x ++ ")"
246doOp v LIntStr [x] = v ++ "idris_castIntStr(vm, " ++ creg x ++ ")"
247doOp v LStrInt [x] = v ++ "idris_castStrInt(vm, " ++ creg x ++ ")"
248doOp v LIntBig [x] = v ++ "idris_castIntBig(vm, " ++ creg x ++ ")"
249doOp v LBigInt [x] = v ++ "idris_castBigInt(vm, " ++ creg x ++ ")"
250doOp v LStrBig [x] = v ++ "idris_castStrBig(vm, " ++ creg x ++ ")"
251doOp v LBigStr [x] = v ++ "idris_castBigStr(vm, " ++ creg x ++ ")"
252doOp v LFloatStr [x] = v ++ "idris_castFloatStr(vm, " ++ creg x ++ ")"
253doOp v LStrFloat [x] = v ++ "idris_castStrFloat(vm, " ++ creg x ++ ")"
255doOp v LReadStr [x] = v ++ "idris_readStr(vm, GETPTR(" ++ creg x ++ "))"
256doOp _ LPrintNum [x] = "printf(\"%ld\\n\", GETINT(" ++ creg x ++ "))"
257doOp _ LPrintStr [x] = "fputs(GETSTR(" ++ creg x ++ "), stdout)"
259doOp v LFExp [x] = v ++ "MKFLOAT(exp(GETFLOAT(" ++ creg x ++ ")))"
260doOp v LFLog [x] = v ++ "MKFLOAT(log(GETFLOAT(" ++ creg x ++ ")))"
261doOp v LFSin [x] = v ++ "MKFLOAT(sin(GETFLOAT(" ++ creg x ++ ")))"
262doOp v LFCos [x] = v ++ "MKFLOAT(cos(GETFLOAT(" ++ creg x ++ ")))"
263doOp v LFTan [x] = v ++ "MKFLOAT(tan(GETFLOAT(" ++ creg x ++ ")))"
264doOp v LFASin [x] = v ++ "MKFLOAT(asin(GETFLOAT(" ++ creg x ++ ")))"
265doOp v LFACos [x] = v ++ "MKFLOAT(acos(GETFLOAT(" ++ creg x ++ ")))"
266doOp v LFATan [x] = v ++ "MKFLOAT(atan(GETFLOAT(" ++ creg x ++ ")))"
267doOp v LFSqrt [x] = v ++ "MKFLOAT(floor(GETFLOAT(" ++ creg x ++ ")))"
268doOp v LFFloor [x] = v ++ "MKFLOAT(ceil(GETFLOAT(" ++ creg x ++ ")))"
269doOp v LFCeil [x] = v ++ "MKFLOAT(sqrt(GETFLOAT(" ++ creg x ++ ")))"
271doOp v LStrHead [x] = v ++ "idris_strHead(vm, " ++ creg x ++ ")"
272doOp v LStrTail [x] = v ++ "idris_strTail(vm, " ++ creg x ++ ")"
273doOp v LStrCons [x, y] = v ++ "idris_strCons(vm, " ++ creg x ++ "," ++ creg y ++ ")"
274doOp v LStrIndex [x, y] = v ++ "idris_strIndex(vm, " ++ creg x ++ "," ++ creg y ++ ")"
275doOp v LStrRev [x] = v ++ "idris_strRev(vm, " ++ creg x ++ ")"
277doOp v LStdIn [] = v ++ "MKPTR(vm, stdin)"
278doOp v LStdOut [] = v ++ "MKPTR(vm, stdout)"
279doOp v LStdErr [] = v ++ "MKPTR(vm, stderr)"
281doOp v LFork [x] = v ++ "MKPTR(vm, vmThread(vm, " ++ cname (MN 0 "EVAL") ++ ", " ++ creg x ++ "))"
282doOp v LPar [x] = v ++ creg x -- "MKPTR(vm, vmThread(vm, " ++ cname (MN 0 "EVAL") ++ ", " ++ creg x ++ "))"
283doOp v LVMPtr [] = v ++ "MKPTR(vm, vm)"
284doOp v LNoOp args = v ++ creg (last args)
285doOp _ _ _ = "FAIL"