on 8935fed help sign in
Idris-dev/src/IRTS/CodegenC.hs
675 lines 31 kB history raw
1module IRTS.CodegenC (codegenC) where
3import Idris.AbsSyntax
4import IRTS.Bytecode
5import IRTS.Lang
6import IRTS.Simplified
7import IRTS.Defunctionalise
8import IRTS.System
9import IRTS.CodegenCommon
10import Idris.Core.TT
11import Util.System
13import Numeric
14import Data.Char
15import Data.Bits
16import Data.List (intercalate)
17import System.Process
18import System.Exit
19import System.IO
20import System.Directory
21import System.FilePath ((</>), (<.>))
22import Control.Monad
24import Debug.Trace
26codegenC :: CodeGenerator
27codegenC ci = do codegenC' (simpleDecls ci)
28 (outputFile ci)
29 (outputType ci)
30 (includes ci)
31 (compileObjs ci)
32 (map mkLib (compileLibs ci) ++
33 map incdir (importDirs ci))
34 (compilerFlags ci)
35 (exportDecls ci)
36 (interfaces ci)
37 (debugLevel ci)
38 when (interfaces ci) $
39 codegenH (exportDecls ci)
41 where mkLib l = "-l" ++ l
42 incdir i = "-I" ++ i
44codegenC' :: [(Name, SDecl)] ->
45 String -> -- output file name
46 OutputType -> -- generate executable if True, only .o if False
47 [FilePath] -> -- include files
48 [String] -> -- extra object files
49 [String] -> -- extra compiler flags (libraries)
50 [String] -> -- extra compiler flags (anything)
51 [ExportIFace] ->
52 Bool -> -- interfaces too (so make a .o instead)
53 DbgLevel ->
54 IO ()
55codegenC' defs out exec incs objs libs flags exports iface dbg
56 = do -- print defs
57 let bc = map toBC defs
58 let h = concatMap toDecl (map fst bc)
59 let cc = concatMap (uncurry toC) bc
60 let hi = concatMap ifaceC (concatMap getExp exports)
61 d <- getDataDir
62 mprog <- readFile (d </> "rts" </> "idris_main" <.> "c")
63 let cout = headers incs ++ debug dbg ++ h ++ cc ++
64 (if (exec == Executable) then mprog else hi)
65 case exec of
66 MavenProject -> putStrLn ("FAILURE: output type not supported")
67 Raw -> writeFile out cout
68 _ -> do
69 (tmpn, tmph) <- tempfile
70 hPutStr tmph cout
71 hFlush tmph
72 hClose tmph
73 comp <- getCC
74 libFlags <- getLibFlags
75 incFlags <- getIncFlags
76 let args = [gccDbg dbg] ++
77 gccFlags iface ++
78 -- # Any flags defined here which alter the RTS API must also be added to config.mk
79 ["-DHAS_PTHREAD", "-DIDRIS_ENABLE_STATS", "-msse2",
80 "-I."] ++ objs ++ ["-x", "c"] ++
81 (if (exec == Executable) then [] else ["-c"]) ++
82 [tmpn] ++
83 (if not iface then concatMap words libFlags else []) ++
84 concatMap words incFlags ++
85 (if not iface then concatMap words libs else []) ++
86 concatMap words flags ++
87 ["-o", out]
88-- putStrLn (show args)
89 exit <- rawSystem comp args
90 when (exit /= ExitSuccess) $
91 putStrLn ("FAILURE: " ++ show comp ++ " " ++ show args)
92 where
93 getExp (Export _ _ exp) = exp
95headers xs =
96 concatMap
97 (\h -> "#include <" ++ h ++ ">\n")
98 (xs ++ ["idris_rts.h", "idris_bitstring.h", "idris_stdfgn.h"])
100debug TRACE = "#define IDRIS_TRACE\n\n"
101debug _ = ""
103-- We're using signed integers now. Make sure we get consistent semantics
104-- out of them from gcc. See e.g. http://thiemonagel.de/2010/01/signed-integer-overflow/
105gccFlags i = if i then ["-fwrapv"]
106 else ["-fwrapv", "-fno-strict-overflow"]
108gccDbg DEBUG = "-g"
109gccDbg TRACE = "-O2"
110gccDbg _ = "-O2"
112cname :: Name -> String
113cname n = "_idris_" ++ concatMap cchar (showCG n)
114 where cchar x | isAlpha x || isDigit x = [x]
115 | otherwise = "_" ++ show (fromEnum x) ++ "_"
117indent :: Int -> String
118indent n = replicate (n*4) ' '
120creg RVal = "RVAL"
121creg (L i) = "LOC(" ++ show i ++ ")"
122creg (T i) = "TOP(" ++ show i ++ ")"
123creg Tmp = "REG1"
125toDecl :: Name -> String
126toDecl f = "void " ++ cname f ++ "(VM*, VAL*);\n"
128toC :: Name -> [BC] -> String
129toC f code
130 = -- "/* " ++ show code ++ "*/\n\n" ++
131 "void " ++ cname f ++ "(VM* vm, VAL* oldbase) {\n" ++
132 indent 1 ++ "INITFRAME;\n" ++
133 concatMap (bcc 1) code ++ "}\n\n"
135showCStr :: String -> String
136showCStr s = '"' : foldr ((++) . showChar) "\"" s
137 where
138 showChar :: Char -> String
139 showChar '"' = "\\\""
140 showChar '\\' = "\\\\"
141 showChar c
142 -- Note: we need the double quotes around the codes because otherwise
143 -- "\n3" would get encoded as "\x0a3", which is incorrect.
144 -- Instead, we opt for "\x0a""3" and let the C compiler deal with it.
145 | ord c < 0x10 = "\"\"\\x0" ++ showHex (ord c) "\"\""
146 | ord c < 0x20 = "\"\"\\x" ++ showHex (ord c) "\"\""
147 | ord c < 0x7f = [c] -- 0x7f = \DEL
148 | otherwise = showHexes (utf8bytes (ord c))
150 utf8bytes :: Int -> [Int]
151 utf8bytes x = let (h : bytes) = split [] x in
152 headHex h (length bytes) : map toHex bytes
153 where
154 split acc 0 = acc
155 split acc x = let xbits = x .&. 0x3f
156 xrest = shiftR x 6 in
157 split (xbits : acc) xrest
159 headHex h 1 = h + 0xc0
160 headHex h 2 = h + 0xe0
161 headHex h 3 = h + 0xf0
162 headHex h n = error "Can't happen: Invalid UTF8 character"
164 toHex i = i + 0x80
166 showHexes = foldr ((++) . showUTF8) ""
167 showUTF8 c = "\"\"\\x" ++ showHex c "\"\""
169bcc :: Int -> BC -> String
170bcc i (ASSIGN l r) = indent i ++ creg l ++ " = " ++ creg r ++ ";\n"
171bcc i (ASSIGNCONST l c)
172 = indent i ++ creg l ++ " = " ++ mkConst c ++ ";\n"
173 where
174 mkConst (I i) = "MKINT(" ++ show i ++ ")"
175 mkConst (BI i) | i < (2^30) = "MKINT(" ++ show i ++ ")"
176 | otherwise = "MKBIGC(vm,\"" ++ show i ++ "\")"
177 mkConst (Fl f) = "MKFLOAT(vm, " ++ show f ++ ")"
178 mkConst (Ch c) = "MKINT(" ++ show (fromEnum c) ++ ")"
179 mkConst (Str s) = "MKSTR(vm, " ++ showCStr s ++ ")"
180 mkConst (B8 x) = "idris_b8const(vm, " ++ show x ++ "U)"
181 mkConst (B16 x) = "idris_b16const(vm, " ++ show x ++ "U)"
182 mkConst (B32 x) = "idris_b32const(vm, " ++ show x ++ "UL)"
183 mkConst (B64 x) = "idris_b64const(vm, " ++ show x ++ "ULL)"
184 -- if it's a type constant, we won't use it, but equally it shouldn't
185 -- report an error. These might creep into generated for various reasons
186 -- (especially if erasure is disabled).
187 mkConst c | isTypeConst c = "MKINT(42424242)"
188 mkConst c = error $ "mkConst of (" ++ show c ++ ") not implemented"
190bcc i (UPDATE l r) = indent i ++ creg l ++ " = " ++ creg r ++ ";\n"
191bcc i (MKCON l loc tag []) | tag < 256
192 = indent i ++ creg l ++ " = NULL_CON(" ++ show tag ++ ");\n"
193bcc i (MKCON l loc tag args)
194 = indent i ++ alloc loc tag ++
195 indent i ++ setArgs 0 args ++ "\n" ++
196 indent i ++ creg l ++ " = " ++ creg Tmp ++ ";\n"
198-- "MKCON(vm, " ++ creg l ++ ", " ++ show tag ++ ", " ++
199-- show (length args) ++ concatMap showArg args ++ ");\n"
200 where showArg r = ", " ++ creg r
201 setArgs i [] = ""
202 setArgs i (x : xs) = "SETARG(" ++ creg Tmp ++ ", " ++ show i ++ ", " ++ creg x ++
203 "); " ++ setArgs (i + 1) xs
204 alloc Nothing tag
205 = "allocCon(" ++ creg Tmp ++ ", vm, " ++ show tag ++ ", " ++
206 show (length args) ++ ", 0);\n"
207 alloc (Just old) tag
208 = "updateCon(" ++ creg Tmp ++ ", " ++ creg old ++ ", " ++ show tag ++ ", " ++
209 show (length args) ++ ");\n"
211bcc i (PROJECT l loc a) = indent i ++ "PROJECT(vm, " ++ creg l ++ ", " ++ show loc ++
212 ", " ++ show a ++ ");\n"
213bcc i (PROJECTINTO r t idx)
214 = indent i ++ creg r ++ " = GETARG(" ++ creg t ++ ", " ++ show idx ++ ");\n"
215bcc i (CASE True r code def)
216 | length code < 4 = showCase i def code
217 where
218 showCode :: Int -> [BC] -> String
219 showCode i bc = "{\n" ++ concatMap (bcc (i + 1)) bc ++
220 indent i ++ "}\n"
222 showCase :: Int -> Maybe [BC] -> [(Int, [BC])] -> String
223 showCase i Nothing [(t, c)] = showCode i c
224 showCase i (Just def) [] = showCode i def
225 showCase i def ((t, c) : cs)
226 = indent i ++ "if (CTAG(" ++ creg r ++ ") == " ++ show t ++ ") " ++ showCode i c
227 ++ indent i ++ "else " ++ showCase i def cs
229bcc i (CASE safe r code def)
230 = indent i ++ "switch(" ++ ctag safe ++ "(" ++ creg r ++ ")) {\n" ++
231 concatMap (showCase i) code ++
232 showDef i def ++
233 indent i ++ "}\n"
234 where
235 ctag True = "CTAG"
236 ctag False = "TAG"
238 showCase i (t, bc) = indent i ++ "case " ++ show t ++ ":\n"
239 ++ concatMap (bcc (i+1)) bc ++ indent (i + 1) ++ "break;\n"
240 showDef i Nothing = ""
241 showDef i (Just c) = indent i ++ "default:\n"
242 ++ concatMap (bcc (i+1)) c ++ indent (i + 1) ++ "break;\n"
243bcc i (CONSTCASE r code def)
244 | intConsts code
245-- = indent i ++ "switch(GETINT(" ++ creg r ++ ")) {\n" ++
246-- concatMap (showCase i) code ++
247-- showDef i def ++
248-- indent i ++ "}\n"
249 = concatMap (iCase (creg r)) code ++
250 indent i ++ "{\n" ++ showDefS i def ++ indent i ++ "}\n"
251 | strConsts code
252 = concatMap (strCase ("GETSTR(" ++ creg r ++ ")")) code ++
253 indent i ++ "{\n" ++ showDefS i def ++ indent i ++ "}\n"
254 | bigintConsts code
255 = concatMap (biCase (creg r)) code ++
256 indent i ++ "{\n" ++ showDefS i def ++ indent i ++ "}\n"
257 | otherwise = error $ "Can't happen: Can't compile const case " ++ show code
258 where
259 intConsts ((I _, _ ) : _) = True
260 intConsts ((Ch _, _ ) : _) = True
261 intConsts _ = False
263 bigintConsts ((BI _, _ ) : _) = True
264 bigintConsts _ = False
266 strConsts ((Str _, _ ) : _) = True
267 strConsts _ = False
269 strCase sv (s, bc) =
270 indent i ++ "if (strcmp(" ++ sv ++ ", " ++ show s ++ ") == 0) {\n" ++
271 concatMap (bcc (i+1)) bc ++ indent i ++ "} else\n"
272 biCase bv (BI b, bc) =
273 indent i ++ "if (bigEqConst(" ++ bv ++ ", " ++ show b ++ ")) {\n"
274 ++ concatMap (bcc (i+1)) bc ++ indent i ++ "} else\n"
275 iCase v (I b, bc) =
276 indent i ++ "if (GETINT(" ++ v ++ ") == " ++ show b ++ ") {\n"
277 ++ concatMap (bcc (i+1)) bc ++ indent i ++ "} else\n"
278 iCase v (Ch b, bc) =
279 indent i ++ "if (GETINT(" ++ v ++ ") == " ++ show (fromEnum b) ++ ") {\n"
280 ++ concatMap (bcc (i+1)) bc ++ indent i ++ "} else\n"
282 showCase i (t, bc) = indent i ++ "case " ++ show t ++ ":\n"
283 ++ concatMap (bcc (i+1)) bc ++
284 indent (i + 1) ++ "break;\n"
285 showDef i Nothing = ""
286 showDef i (Just c) = indent i ++ "default:\n"
287 ++ concatMap (bcc (i+1)) c ++
288 indent (i + 1) ++ "break;\n"
289 showDefS i Nothing = ""
290 showDefS i (Just c) = concatMap (bcc (i+1)) c
292bcc i (CALL n) = indent i ++ "CALL(" ++ cname n ++ ");\n"
293bcc i (TAILCALL n) = indent i ++ "TAILCALL(" ++ cname n ++ ");\n"
294bcc i (SLIDE n) = indent i ++ "SLIDE(vm, " ++ show n ++ ");\n"
295bcc i REBASE = indent i ++ "REBASE;\n"
296bcc i (RESERVE 0) = ""
297bcc i (RESERVE n) = indent i ++ "RESERVE(" ++ show n ++ ");\n"
298bcc i (ADDTOP 0) = ""
299bcc i (ADDTOP n) = indent i ++ "ADDTOP(" ++ show n ++ ");\n"
300bcc i (TOPBASE n) = indent i ++ "TOPBASE(" ++ show n ++ ");\n"
301bcc i (BASETOP n) = indent i ++ "BASETOP(" ++ show n ++ ");\n"
302bcc i STOREOLD = indent i ++ "STOREOLD;\n"
303bcc i (OP l fn args) = indent i ++ doOp (creg l ++ " = ") fn args ++ ";\n"
304bcc i (FOREIGNCALL l rty (FStr fn) args)
305 = indent i ++
306 c_irts (toFType rty) (creg l ++ " = ")
307 (fn ++ "(" ++ showSep "," (map fcall args) ++ ")") ++ ";\n"
308 where fcall (t, arg) = irts_c (toFType t) (creg arg)
309bcc i (NULL r) = indent i ++ creg r ++ " = NULL;\n" -- clear, so it'll be GCed
310bcc i (ERROR str) = indent i ++ "fprintf(stderr, " ++ show str ++ "); fprintf(stderr, \"\\n\"); exit(-1); exit(-1);"
311-- bcc i c = error (show c) -- indent i ++ "// not done yet\n"
313-- Deconstruct the Foreign type in the defunctionalised expression and build
314-- a foreign type description for c_irts and irts_c
315toAType (FCon i)
316 | i == sUN "C_IntChar" = ATInt ITChar
317 | i == sUN "C_IntNative" = ATInt ITNative
318 | i == sUN "C_IntBits8" = ATInt (ITFixed IT8)
319 | i == sUN "C_IntBits16" = ATInt (ITFixed IT16)
320 | i == sUN "C_IntBits32" = ATInt (ITFixed IT32)
321 | i == sUN "C_IntBits64" = ATInt (ITFixed IT64)
322toAType t = error (show t ++ " not defined in toAType")
324toFType (FCon c)
325 | c == sUN "C_Str" = FString
326 | c == sUN "C_Float" = FArith ATFloat
327 | c == sUN "C_Ptr" = FPtr
328 | c == sUN "C_MPtr" = FManagedPtr
329 | c == sUN "C_Unit" = FUnit
330toFType (FApp c [_,ity])
331 | c == sUN "C_IntT" = FArith (toAType ity)
332toFType (FApp c [_])
333 | c == sUN "C_Any" = FAny
334toFType t = FAny
336c_irts (FArith (ATInt ITNative)) l x = l ++ "MKINT((i_int)(" ++ x ++ "))"
337c_irts (FArith (ATInt ITChar)) l x = c_irts (FArith (ATInt ITNative)) l x
338c_irts (FArith (ATInt (ITFixed ity))) l x
339 = l ++ "idris_b" ++ show (nativeTyWidth ity) ++ "const(vm, " ++ x ++ ")"
340c_irts FString l x = l ++ "MKSTR(vm, " ++ x ++ ")"
341c_irts FUnit l x = x
342c_irts FPtr l x = l ++ "MKPTR(vm, " ++ x ++ ")"
343c_irts FManagedPtr l x = l ++ "MKMPTR(vm, " ++ x ++ ")"
344c_irts (FArith ATFloat) l x = l ++ "MKFLOAT(vm, " ++ x ++ ")"
345c_irts FAny l x = l ++ x
347irts_c (FArith (ATInt ITNative)) x = "GETINT(" ++ x ++ ")"
348irts_c (FArith (ATInt ITChar)) x = irts_c (FArith (ATInt ITNative)) x
349irts_c (FArith (ATInt (ITFixed ity))) x
350 = "(" ++ x ++ "->info.bits" ++ show (nativeTyWidth ity) ++ ")"
351irts_c FString x = "GETSTR(" ++ x ++ ")"
352irts_c FUnit x = x
353irts_c FPtr x = "GETPTR(" ++ x ++ ")"
354irts_c FManagedPtr x = "GETMPTR(" ++ x ++ ")"
355irts_c (FArith ATFloat) x = "GETFLOAT(" ++ x ++ ")"
356irts_c FAny x = x
358bitOp v op ty args = v ++ "idris_b" ++ show (nativeTyWidth ty) ++ op ++ "(vm, " ++ intercalate ", " (map creg args) ++ ")"
360bitCoerce v op input output arg
361 = v ++ "idris_b" ++ show (nativeTyWidth input) ++ op ++ show (nativeTyWidth output) ++ "(vm, " ++ creg arg ++ ")"
363signedTy :: NativeTy -> String
364signedTy t = "int" ++ show (nativeTyWidth t) ++ "_t"
366doOp v (LPlus (ATInt ITNative)) [l, r] = v ++ "ADD(" ++ creg l ++ ", " ++ creg r ++ ")"
367doOp v (LMinus (ATInt ITNative)) [l, r] = v ++ "INTOP(-," ++ creg l ++ ", " ++ creg r ++ ")"
368doOp v (LTimes (ATInt ITNative)) [l, r] = v ++ "MULT(" ++ creg l ++ ", " ++ creg r ++ ")"
369doOp v (LUDiv ITNative) [l, r] = v ++ "UINTOP(/," ++ creg l ++ ", " ++ creg r ++ ")"
370doOp v (LSDiv (ATInt ITNative)) [l, r] = v ++ "INTOP(/," ++ creg l ++ ", " ++ creg r ++ ")"
371doOp v (LURem ITNative) [l, r] = v ++ "UINTOP(%," ++ creg l ++ ", " ++ creg r ++ ")"
372doOp v (LSRem (ATInt ITNative)) [l, r] = v ++ "INTOP(%," ++ creg l ++ ", " ++ creg r ++ ")"
373doOp v (LAnd ITNative) [l, r] = v ++ "INTOP(&," ++ creg l ++ ", " ++ creg r ++ ")"
374doOp v (LOr ITNative) [l, r] = v ++ "INTOP(|," ++ creg l ++ ", " ++ creg r ++ ")"
375doOp v (LXOr ITNative) [l, r] = v ++ "INTOP(^," ++ creg l ++ ", " ++ creg r ++ ")"
376doOp v (LSHL ITNative) [l, r] = v ++ "INTOP(<<," ++ creg l ++ ", " ++ creg r ++ ")"
377doOp v (LLSHR ITNative) [l, r] = v ++ "UINTOP(>>," ++ creg l ++ ", " ++ creg r ++ ")"
378doOp v (LASHR ITNative) [l, r] = v ++ "INTOP(>>," ++ creg l ++ ", " ++ creg r ++ ")"
379doOp v (LCompl ITNative) [x] = v ++ "INTOP(~," ++ creg x ++ ")"
380doOp v (LEq (ATInt ITNative)) [l, r] = v ++ "INTOP(==," ++ creg l ++ ", " ++ creg r ++ ")"
381doOp v (LSLt (ATInt ITNative)) [l, r] = v ++ "INTOP(<," ++ creg l ++ ", " ++ creg r ++ ")"
382doOp v (LSLe (ATInt ITNative)) [l, r] = v ++ "INTOP(<=," ++ creg l ++ ", " ++ creg r ++ ")"
383doOp v (LSGt (ATInt ITNative)) [l, r] = v ++ "INTOP(>," ++ creg l ++ ", " ++ creg r ++ ")"
384doOp v (LSGe (ATInt ITNative)) [l, r] = v ++ "INTOP(>=," ++ creg l ++ ", " ++ creg r ++ ")"
385doOp v (LLt ITNative) [l, r] = v ++ "UINTOP(<," ++ creg l ++ ", " ++ creg r ++ ")"
386doOp v (LLe ITNative) [l, r] = v ++ "UINTOP(<=," ++ creg l ++ ", " ++ creg r ++ ")"
387doOp v (LGt ITNative) [l, r] = v ++ "UINTOP(>," ++ creg l ++ ", " ++ creg r ++ ")"
388doOp v (LGe ITNative) [l, r] = v ++ "UINTOP(>=," ++ creg l ++ ", " ++ creg r ++ ")"
390doOp v (LPlus (ATInt ITChar)) [l, r] = doOp v (LPlus (ATInt ITNative)) [l, r]
391doOp v (LMinus (ATInt ITChar)) [l, r] = doOp v (LMinus (ATInt ITNative)) [l, r]
392doOp v (LTimes (ATInt ITChar)) [l, r] = doOp v (LTimes (ATInt ITNative)) [l, r]
393doOp v (LUDiv ITChar) [l, r] = doOp v (LUDiv ITNative) [l, r]
394doOp v (LSDiv (ATInt ITChar)) [l, r] = doOp v (LSDiv (ATInt ITNative)) [l, r]
395doOp v (LURem ITChar) [l, r] = doOp v (LURem ITNative) [l, r]
396doOp v (LSRem (ATInt ITChar)) [l, r] = doOp v (LSRem (ATInt ITNative)) [l, r]
397doOp v (LAnd ITChar) [l, r] = doOp v (LAnd ITNative) [l, r]
398doOp v (LOr ITChar) [l, r] = doOp v (LOr ITNative) [l, r]
399doOp v (LXOr ITChar) [l, r] = doOp v (LXOr ITNative) [l, r]
400doOp v (LSHL ITChar) [l, r] = doOp v (LSHL ITNative) [l, r]
401doOp v (LLSHR ITChar) [l, r] = doOp v (LLSHR ITNative) [l, r]
402doOp v (LASHR ITChar) [l, r] = doOp v (LASHR ITNative) [l, r]
403doOp v (LCompl ITChar) [x] = doOp v (LCompl ITNative) [x]
404doOp v (LEq (ATInt ITChar)) [l, r] = doOp v (LEq (ATInt ITNative)) [l, r]
405doOp v (LSLt (ATInt ITChar)) [l, r] = doOp v (LSLt (ATInt ITNative)) [l, r]
406doOp v (LSLe (ATInt ITChar)) [l, r] = doOp v (LSLe (ATInt ITNative)) [l, r]
407doOp v (LSGt (ATInt ITChar)) [l, r] = doOp v (LSGt (ATInt ITNative)) [l, r]
408doOp v (LSGe (ATInt ITChar)) [l, r] = doOp v (LSGe (ATInt ITNative)) [l, r]
409doOp v (LLt ITChar) [l, r] = doOp v (LLt ITNative) [l, r]
410doOp v (LLe ITChar) [l, r] = doOp v (LLe ITNative) [l, r]
411doOp v (LGt ITChar) [l, r] = doOp v (LGt ITNative) [l, r]
412doOp v (LGe ITChar) [l, r] = doOp v (LGe ITNative) [l, r]
414doOp v (LPlus ATFloat) [l, r] = v ++ "FLOATOP(+," ++ creg l ++ ", " ++ creg r ++ ")"
415doOp v (LMinus ATFloat) [l, r] = v ++ "FLOATOP(-," ++ creg l ++ ", " ++ creg r ++ ")"
416doOp v (LTimes ATFloat) [l, r] = v ++ "FLOATOP(*," ++ creg l ++ ", " ++ creg r ++ ")"
417doOp v (LSDiv ATFloat) [l, r] = v ++ "FLOATOP(/," ++ creg l ++ ", " ++ creg r ++ ")"
418doOp v (LEq ATFloat) [l, r] = v ++ "FLOATBOP(==," ++ creg l ++ ", " ++ creg r ++ ")"
419doOp v (LSLt ATFloat) [l, r] = v ++ "FLOATBOP(<," ++ creg l ++ ", " ++ creg r ++ ")"
420doOp v (LSLe ATFloat) [l, r] = v ++ "FLOATBOP(<=," ++ creg l ++ ", " ++ creg r ++ ")"
421doOp v (LSGt ATFloat) [l, r] = v ++ "FLOATBOP(>," ++ creg l ++ ", " ++ creg r ++ ")"
422doOp v (LSGe ATFloat) [l, r] = v ++ "FLOATBOP(>=," ++ creg l ++ ", " ++ creg r ++ ")"
424doOp v (LIntFloat ITBig) [x] = v ++ "idris_castBigFloat(vm, " ++ creg x ++ ")"
425doOp v (LFloatInt ITBig) [x] = v ++ "idris_castFloatBig(vm, " ++ creg x ++ ")"
426doOp v (LPlus (ATInt ITBig)) [l, r] = v ++ "idris_bigPlus(vm, " ++ creg l ++ ", " ++ creg r ++ ")"
427doOp v (LMinus (ATInt ITBig)) [l, r] = v ++ "idris_bigMinus(vm, " ++ creg l ++ ", " ++ creg r ++ ")"
428doOp v (LTimes (ATInt ITBig)) [l, r] = v ++ "idris_bigTimes(vm, " ++ creg l ++ ", " ++ creg r ++ ")"
429doOp v (LSDiv (ATInt ITBig)) [l, r] = v ++ "idris_bigDivide(vm, " ++ creg l ++ ", " ++ creg r ++ ")"
430doOp v (LSRem (ATInt ITBig)) [l, r] = v ++ "idris_bigMod(vm, " ++ creg l ++ ", " ++ creg r ++ ")"
431doOp v (LEq (ATInt ITBig)) [l, r] = v ++ "idris_bigEq(vm, " ++ creg l ++ ", " ++ creg r ++ ")"
432doOp v (LSLt (ATInt ITBig)) [l, r] = v ++ "idris_bigLt(vm, " ++ creg l ++ ", " ++ creg r ++ ")"
433doOp v (LSLe (ATInt ITBig)) [l, r] = v ++ "idris_bigLe(vm, " ++ creg l ++ ", " ++ creg r ++ ")"
434doOp v (LSGt (ATInt ITBig)) [l, r] = v ++ "idris_bigGt(vm, " ++ creg l ++ ", " ++ creg r ++ ")"
435doOp v (LSGe (ATInt ITBig)) [l, r] = v ++ "idris_bigGe(vm, " ++ creg l ++ ", " ++ creg r ++ ")"
437doOp v (LIntFloat ITNative) [x] = v ++ "idris_castIntFloat(" ++ creg x ++ ")"
438doOp v (LFloatInt ITNative) [x] = v ++ "idris_castFloatInt(" ++ creg x ++ ")"
439doOp v (LSExt ITNative ITBig) [x] = v ++ "idris_castIntBig(vm, " ++ creg x ++ ")"
440doOp v (LTrunc ITBig ITNative) [x] = v ++ "idris_castBigInt(vm, " ++ creg x ++ ")"
441doOp v (LStrInt ITBig) [x] = v ++ "idris_castStrBig(vm, " ++ creg x ++ ")"
442doOp v (LIntStr ITBig) [x] = v ++ "idris_castBigStr(vm, " ++ creg x ++ ")"
443doOp v (LIntStr ITNative) [x] = v ++ "idris_castIntStr(vm, " ++ creg x ++ ")"
444doOp v (LStrInt ITNative) [x] = v ++ "idris_castStrInt(vm, " ++ creg x ++ ")"
445doOp v (LIntStr (ITFixed _)) [x] = v ++ "idris_castBitsStr(vm, " ++ creg x ++ ")"
446doOp v LFloatStr [x] = v ++ "idris_castFloatStr(vm, " ++ creg x ++ ")"
447doOp v LStrFloat [x] = v ++ "idris_castStrFloat(vm, " ++ creg x ++ ")"
449doOp v (LSLt (ATInt (ITFixed ty))) [x, y] = bitOp v "SLt" ty [x, y]
450doOp v (LSLe (ATInt (ITFixed ty))) [x, y] = bitOp v "SLte" ty [x, y]
451doOp v (LEq (ATInt (ITFixed ty))) [x, y] = bitOp v "Eq" ty [x, y]
452doOp v (LSGe (ATInt (ITFixed ty))) [x, y] = bitOp v "SGte" ty [x, y]
453doOp v (LSGt (ATInt (ITFixed ty))) [x, y] = bitOp v "SGt" ty [x, y]
454doOp v (LLt (ITFixed ty)) [x, y] = bitOp v "Lt" ty [x, y]
455doOp v (LLe (ITFixed ty)) [x, y] = bitOp v "Lte" ty [x, y]
456doOp v (LGe (ITFixed ty)) [x, y] = bitOp v "Gte" ty [x, y]
457doOp v (LGt (ITFixed ty)) [x, y] = bitOp v "Gt" ty [x, y]
459doOp v (LSHL (ITFixed ty)) [x, y] = bitOp v "Shl" ty [x, y]
460doOp v (LLSHR (ITFixed ty)) [x, y] = bitOp v "LShr" ty [x, y]
461doOp v (LASHR (ITFixed ty)) [x, y] = bitOp v "AShr" ty [x, y]
462doOp v (LAnd (ITFixed ty)) [x, y] = bitOp v "And" ty [x, y]
463doOp v (LOr (ITFixed ty)) [x, y] = bitOp v "Or" ty [x, y]
464doOp v (LXOr (ITFixed ty)) [x, y] = bitOp v "Xor" ty [x, y]
465doOp v (LCompl (ITFixed ty)) [x] = bitOp v "Compl" ty [x]
467doOp v (LPlus (ATInt (ITFixed ty))) [x, y] = bitOp v "Plus" ty [x, y]
468doOp v (LMinus (ATInt (ITFixed ty))) [x, y] = bitOp v "Minus" ty [x, y]
469doOp v (LTimes (ATInt (ITFixed ty))) [x, y] = bitOp v "Times" ty [x, y]
470doOp v (LUDiv (ITFixed ty)) [x, y] = bitOp v "UDiv" ty [x, y]
471doOp v (LSDiv (ATInt (ITFixed ty))) [x, y] = bitOp v "SDiv" ty [x, y]
472doOp v (LURem (ITFixed ty)) [x, y] = bitOp v "URem" ty [x, y]
473doOp v (LSRem (ATInt (ITFixed ty))) [x, y] = bitOp v "SRem" ty [x, y]
475doOp v (LSExt (ITFixed from) ITBig) [x]
476 = v ++ "MKBIGSI(vm, (" ++ signedTy from ++ ")" ++ creg x ++ "->info.bits" ++ show (nativeTyWidth from) ++ ")"
477doOp v (LSExt ITNative (ITFixed to)) [x]
478 = v ++ "idris_b" ++ show (nativeTyWidth to) ++ "const(vm, GETINT(" ++ creg x ++ "))"
479doOp v (LSExt ITChar (ITFixed to)) [x]
480 = doOp v (LSExt ITNative (ITFixed to)) [x]
481doOp v (LSExt (ITFixed from) ITNative) [x]
482 = v ++ "MKINT((i_int)((" ++ signedTy from ++ ")" ++ creg x ++ "->info.bits" ++ show (nativeTyWidth from) ++ "))"
483doOp v (LSExt (ITFixed from) ITChar) [x]
484 = doOp v (LSExt (ITFixed from) ITNative) [x]
485doOp v (LSExt (ITFixed from) (ITFixed to)) [x]
486 | nativeTyWidth from < nativeTyWidth to = bitCoerce v "S" from to x
487doOp v (LZExt ITNative (ITFixed to)) [x]
488 = v ++ "idris_b" ++ show (nativeTyWidth to) ++ "const(vm, (uintptr_t)GETINT(" ++ creg x ++ "))"
489doOp v (LZExt ITChar (ITFixed to)) [x]
490 = doOp v (LZExt ITNative (ITFixed to)) [x]
491doOp v (LZExt (ITFixed from) ITNative) [x]
492 = v ++ "MKINT((i_int)" ++ creg x ++ "->info.bits" ++ show (nativeTyWidth from) ++ ")"
493doOp v (LZExt (ITFixed from) ITChar) [x]
494 = doOp v (LZExt (ITFixed from) ITNative) [x]
495doOp v (LZExt (ITFixed from) ITBig) [x]
496 = v ++ "MKBIGUI(vm, " ++ creg x ++ "->info.bits" ++ show (nativeTyWidth from) ++ ")"
497doOp v (LZExt ITNative ITBig) [x]
498 = v ++ "MKBIGUI(vm, (uintptr_t)GETINT(" ++ creg x ++ "))"
499doOp v (LZExt (ITFixed from) (ITFixed to)) [x]
500 | nativeTyWidth from < nativeTyWidth to = bitCoerce v "Z" from to x
501doOp v (LTrunc ITNative (ITFixed to)) [x]
502 = v ++ "idris_b" ++ show (nativeTyWidth to) ++ "const(vm, GETINT(" ++ creg x ++ "))"
503doOp v (LTrunc ITChar (ITFixed to)) [x]
504 = doOp v (LTrunc ITNative (ITFixed to)) [x]
505doOp v (LTrunc (ITFixed from) ITNative) [x]
506 = v ++ "MKINT((i_int)" ++ creg x ++ "->info.bits" ++ show (nativeTyWidth from) ++ ")"
507doOp v (LTrunc (ITFixed from) ITChar) [x]
508 = doOp v (LTrunc (ITFixed from) ITNative) [x]
509doOp v (LTrunc ITBig (ITFixed to)) [x]
510 = v ++ "idris_b" ++ show (nativeTyWidth to) ++ "const(vm, ISINT(" ++ creg x ++ ") ? GETINT(" ++ creg x ++ ") : mpz_get_ui(GETMPZ(" ++ creg x ++ ")))"
511doOp v (LTrunc (ITFixed from) (ITFixed to)) [x]
512 | nativeTyWidth from > nativeTyWidth to = bitCoerce v "T" from to x
514doOp v LFExp [x] = v ++ flUnOp "exp" (creg x)
515doOp v LFLog [x] = v ++ flUnOp "log" (creg x)
516doOp v LFSin [x] = v ++ flUnOp "sin" (creg x)
517doOp v LFCos [x] = v ++ flUnOp "cos" (creg x)
518doOp v LFTan [x] = v ++ flUnOp "tan" (creg x)
519doOp v LFASin [x] = v ++ flUnOp "asin" (creg x)
520doOp v LFACos [x] = v ++ flUnOp "acos" (creg x)
521doOp v LFATan [x] = v ++ flUnOp "atan" (creg x)
522doOp v LFSqrt [x] = v ++ flUnOp "sqrt" (creg x)
523doOp v LFFloor [x] = v ++ flUnOp "floor" (creg x)
524doOp v LFCeil [x] = v ++ flUnOp "ceil" (creg x)
525doOp v LFNegate [x] = v ++ "MKFLOAT(vm, -GETFLOAT(" ++ (creg x) ++ "))"
527-- String functions which don't need to know we're UTF8
528doOp v LStrConcat [l,r] = v ++ "idris_concat(vm, " ++ creg l ++ ", " ++ creg r ++ ")"
529doOp v LStrLt [l,r] = v ++ "idris_strlt(vm, " ++ creg l ++ ", " ++ creg r ++ ")"
530doOp v LStrEq [l,r] = v ++ "idris_streq(vm, " ++ creg l ++ ", " ++ creg r ++ ")"
532doOp v LReadStr [_] = v ++ "idris_readStr(vm, stdin)"
533doOp v LWriteStr [_,s]
534 = v ++ "MKINT((i_int)(idris_writeStr(stdout"
535 ++ ",GETSTR("
536 ++ creg s ++ "))))"
539-- String functions which need to know we're UTF8
540doOp v LStrHead [x] = v ++ "idris_strHead(vm, " ++ creg x ++ ")"
541doOp v LStrTail [x] = v ++ "idris_strTail(vm, " ++ creg x ++ ")"
542doOp v LStrCons [x, y] = v ++ "idris_strCons(vm, " ++ creg x ++ "," ++ creg y ++ ")"
543doOp v LStrIndex [x, y] = v ++ "idris_strIndex(vm, " ++ creg x ++ "," ++ creg y ++ ")"
544doOp v LStrRev [x] = v ++ "idris_strRev(vm, " ++ creg x ++ ")"
545doOp v LStrLen [x] = v ++ "idris_strlen(vm, " ++ creg x ++ ")"
547doOp v LFork [x] = v ++ "MKPTR(vm, vmThread(vm, " ++ cname (sMN 0 "EVAL") ++ ", " ++ creg x ++ "))"
548doOp v LPar [x] = v ++ creg x -- "MKPTR(vm, vmThread(vm, " ++ cname (MN 0 "EVAL") ++ ", " ++ creg x ++ "))"
549doOp v (LChInt ITNative) args = v ++ creg (last args)
550doOp v (LChInt ITChar) args = doOp v (LChInt ITNative) args
551doOp v (LIntCh ITNative) args = v ++ creg (last args)
552doOp v (LIntCh ITChar) args = doOp v (LIntCh ITNative) args
554doOp v LSystemInfo [x] = v ++ "idris_systemInfo(vm, " ++ creg x ++ ")"
555doOp v LNoOp args = v ++ creg (last args)
557-- Pointer primitives (declared as %extern in Builtins.idr)
558doOp v (LExternal rf) [_,x]
559 | rf == sUN "prim__readFile"
560 = v ++ "idris_readStr(vm, GETPTR(" ++ creg x ++ "))"
561doOp v (LExternal wf) [_,x,s]
562 | wf == sUN "prim__writeFile"
563 = v ++ "MKINT((i_int)(idris_writeStr(GETPTR(" ++ creg x
564 ++ "),GETSTR("
565 ++ creg s ++ "))))"
566doOp v (LExternal vm) [] | vm == sUN "prim__vm" = v ++ "MKPTR(vm, vm)"
567doOp v (LExternal si) [] | si == sUN "prim__stdin" = v ++ "MKPTR(vm, stdin)"
568doOp v (LExternal so) [] | so == sUN "prim__stdout" = v ++ "MKPTR(vm, stdout)"
569doOp v (LExternal se) [] | se == sUN "prim__stderr" = v ++ "MKPTR(vm, stderr)"
571doOp v (LExternal nul) [] | nul == sUN "prim__null" = v ++ "MKPTR(vm, NULL)"
572doOp v (LExternal rp) [p, i] | rp == sUN "prim__registerPtr"
573 = v ++ "MKMPTR(vm, GETPTR(" ++ creg p ++ "), GETINT(" ++ creg i ++ "))"
575doOp _ op args = error $ "doOp not implemented (" ++ show (op, args) ++ ")"
577flUnOp :: String -> String -> String
578flUnOp name val = "MKFLOAT(vm, " ++ name ++ "(GETFLOAT(" ++ val ++ ")))"
580-------------------- Interface file generation
582-- First, the wrappers in the C file
584ifaceC :: Export -> String
585ifaceC (ExportData n) = "typedef VAL " ++ cdesc n ++ ";\n"
586ifaceC (ExportFun n cn ret args)
587 = ctype ret ++ " " ++ cdesc cn ++
588 "(VM* vm" ++ showArgs (zip argNames args) ++ ") {\n"
589 ++ mkBody n (zip argNames args) ret ++ "}\n\n"
590 where showArgs [] = ""
591 showArgs ((n, t) : ts) = ", " ++ ctype t ++ " " ++ n ++
592 showArgs ts
594 argNames = zipWith (++) (repeat "arg") (map show [0..])
596mkBody n as t = indent 1 ++ "INITFRAME;\n" ++
597 indent 1 ++ "RESERVE(" ++ show (max (length as) 3) ++ ");\n" ++
598 push 0 as ++ call n ++ retval t
599 where push i [] = ""
600 push i ((n, t) : ts) = indent 1 ++ c_irts (toFType t)
601 ("TOP(" ++ show i ++ ") = ") n
602 ++ ";\n" ++ push (i + 1) ts
604 call _ = indent 1 ++ "STOREOLD;\n" ++
605 indent 1 ++ "BASETOP(0);\n" ++
606 indent 1 ++ "ADDTOP(" ++ show (length as) ++ ");\n" ++
607 indent 1 ++ "CALL(" ++ cname n ++ ");\n"
609 retval (FIO t)
610 = indent 1 ++ "TOP(0) = NULL;\n" ++
611 indent 1 ++ "TOP(1) = NULL;\n" ++
612 indent 1 ++ "TOP(2) = RVAL;\n" ++
613 indent 1 ++ "STOREOLD;\n" ++
614 indent 1 ++ "BASETOP(0);\n" ++
615 indent 1 ++ "ADDTOP(3);\n" ++
616 indent 1 ++ "CALL(" ++ cname (sUN "call__IO") ++ ");\n" ++
617 retval t
618 retval t = indent 1 ++ "return " ++ irts_c (toFType t) "RVAL" ++ ";\n"
620ctype (FCon c)
621 | c == sUN "C_Str" = "char*"
622 | c == sUN "C_Float" = "float"
623 | c == sUN "C_Ptr" = "void*"
624 | c == sUN "C_MPtr" = "void*"
625 | c == sUN "C_Unit" = "void"
626ctype (FApp c [_,ity])
627 | c == sUN "C_IntT" = carith ity
628ctype (FApp c [_])
629 | c == sUN "C_Any" = "VAL"
630ctype (FStr s) = s
631ctype FUnknown = "void*"
632ctype (FIO t) = ctype t
633ctype t = error "Can't happen: Not a valid interface type " ++ show t
635carith (FCon i)
636 | i == sUN "C_IntChar" = "char"
637 | i == sUN "C_IntNative" = "int"
638carith t = error "Can't happen: Not an exportable arithmetic type"
640cdesc (FStr s) = s
641cdesc s = error "Can't happen: Not a valid C name"
643-- Then, the header files
645codegenH :: [ExportIFace] -> IO ()
646codegenH es = mapM_ writeIFace es
648writeIFace :: ExportIFace -> IO ()
649writeIFace (Export ffic hdr exps)
650 | ffic == sUN "FFI_C"
651 = do let hfile = "#ifndef " ++ hdr_guard hdr ++ "\n" ++
652 "#define " ++ hdr_guard hdr ++ "\n\n" ++
653 "#include <idris_rts.h>\n\n" ++
654 concatMap hdr_export exps ++ "\n" ++
655 "#endif\n\n"
656 writeFile hdr hfile
657 | otherwise = return ()
659hdr_guard x = "__" ++ map hchar x
660 where hchar x | isAlphaNum x = toUpper x
661 hchar _ = '_'
663hdr_export :: Export -> String
664hdr_export (ExportData n) = "typedef VAL " ++ cdesc n ++ ";\n"
665hdr_export (ExportFun n cn ret args)
666 = ctype ret ++ " " ++ cdesc cn ++
667 "(VM* vm" ++ showArgs (zip argNames args) ++ ");\n"
668 where showArgs [] = ""
669 showArgs ((n, t) : ts) = ", " ++ ctype t ++ " " ++ n ++
670 showArgs ts
672 argNames = zipWith (++) (repeat "arg") (map show [0..])