on e105606 help sign in
Idris-dev/src/IRTS/CodegenC.hs
884 lines 43 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, nubBy)
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 wrappers = genWrappers bc
59 let h = concatMap toDecl (map fst bc)
60 let cc = concatMap (uncurry toC) bc
61 let hi = concatMap ifaceC (concatMap getExp exports)
62 d <- getDataDir
63 mprog <- readFile (d </> "rts" </> "idris_main" <.> "c")
64 let cout = headers incs ++ debug dbg ++ h ++ wrappers ++ cc ++
65 (if (exec == Executable) then mprog else hi)
66 case exec of
67 Raw -> writeSource out cout
68 _ -> do
69 (tmpn, tmph) <- tempfile ".c"
70 hPutStr tmph cout
71 hFlush tmph
72 hClose tmph
73 comp <- getCC
74 libFlags <- getLibFlags
75 incFlags <- getIncFlags
76 envFlags <- getEnvFlags
77 let stackFlag = if isWindows then ["-Wl,--stack,16777216"] else []
78 let args = [gccDbg dbg] ++
79 gccFlags iface ++
80 -- # Any flags defined here which alter the RTS API must also be added to config.mk
81 ["-DHAS_PTHREAD", "-DIDRIS_ENABLE_STATS",
82 "-I."] ++ objs ++ envFlags ++
83 (if (exec == Executable) then [] else ["-c"]) ++
84 [tmpn] ++
85 (if not iface then libFlags else []) ++
86 incFlags ++
87 (if not iface then libs else []) ++
88 flags ++ stackFlag ++
89 ["-o", out]
90-- putStrLn (show args)
91 exit <- rawSystem comp args
92 when (exit /= ExitSuccess) $
93 putStrLn ("FAILURE: " ++ show comp ++ " " ++ show args)
94 where
95 getExp (Export _ _ exp) = exp
97headers xs =
98 concatMap
99 (\h -> "#include \"" ++ h ++ "\"\n")
100 (xs ++ ["idris_rts.h", "idris_bitstring.h", "idris_stdfgn.h"])
102debug TRACE = "#define IDRIS_TRACE\n\n"
103debug _ = ""
105-- We're using signed integers now. Make sure we get consistent semantics
106-- out of them from gcc. See e.g. http://thiemonagel.de/2010/01/signed-integer-overflow/
107gccFlags i = if i then ["-fwrapv"]
108 else ["-fwrapv", "-fno-strict-overflow"]
110gccDbg DEBUG = "-g"
111gccDbg TRACE = "-O2"
112gccDbg _ = "-O2"
114cname :: Name -> String
115cname n = "_idris_" ++ concatMap cchar (showCG n)
116 where cchar x | isAlpha x || isDigit x = [x]
117 | otherwise = "_" ++ show (fromEnum x) ++ "_"
119indent :: Int -> String
120indent n = replicate (n*4) ' '
122creg RVal = "RVAL"
123creg (L i) = "LOC(" ++ show i ++ ")"
124creg (T i) = "TOP(" ++ show i ++ ")"
125creg Tmp = "REG1"
127toDecl :: Name -> String
128toDecl f = "void " ++ cname f ++ "(VM*, VAL*);\n"
130toC :: Name -> [BC] -> String
131toC f code
132 = -- "/* " ++ show code ++ "*/\n\n" ++
133 "void " ++ cname f ++ "(VM* vm, VAL* oldbase) {\n" ++
134 indent 1 ++ "INITFRAME;\n" ++
135 concatMap (bcc 1) code ++ "}\n\n"
137showCStr :: String -> String
138showCStr s = '"' : foldr ((++) . showChar) "\"" s
139 where
140 showChar :: Char -> String
141 showChar '"' = "\\\""
142 showChar '\\' = "\\\\"
143 showChar c
144 -- Note: we need the double quotes around the codes because otherwise
145 -- "\n3" would get encoded as "\x0a3", which is incorrect.
146 -- Instead, we opt for "\x0a""3" and let the C compiler deal with it.
147 | ord c < 0x10 = "\"\"\\x0" ++ showHex (ord c) "\"\""
148 | ord c < 0x20 = "\"\"\\x" ++ showHex (ord c) "\"\""
149 | ord c < 0x7f = [c] -- 0x7f = \DEL
150 | otherwise = showHexes (utf8bytes (ord c))
152 utf8bytes :: Int -> [Int]
153 utf8bytes x = let (h : bytes) = split [] x in
154 headHex h (length bytes) : map toHex bytes
155 where
156 split acc 0 = acc
157 split acc x = let xbits = x .&. 0x3f
158 xrest = shiftR x 6 in
159 split (xbits : acc) xrest
161 headHex h 1 = h + 0xc0
162 headHex h 2 = h + 0xe0
163 headHex h 3 = h + 0xf0
164 headHex h n = error "Can't happen: Invalid UTF8 character"
166 toHex i = i + 0x80
168 showHexes = foldr ((++) . showUTF8) ""
169 showUTF8 c = "\"\"\\x" ++ showHex c "\"\""
171bcc :: Int -> BC -> String
172bcc i (ASSIGN l r) = indent i ++ creg l ++ " = " ++ creg r ++ ";\n"
173bcc i (ASSIGNCONST l c)
174 = indent i ++ creg l ++ " = " ++ mkConst c ++ ";\n"
175 where
176 mkConst (I i) = "MKINT(" ++ show i ++ ")"
177 mkConst (BI i) | i < (2^30) = "MKINT(" ++ show i ++ ")"
178 | otherwise = "MKBIGC(vm,\"" ++ show i ++ "\")"
179 mkConst (Fl f) = "MKFLOAT(vm, " ++ show f ++ ")"
180 mkConst (Ch c) = "MKINT(" ++ show (fromEnum c) ++ ")"
181 mkConst (Str s) = "MKSTR(vm, " ++ showCStr s ++ ")"
182 mkConst (B8 x) = "idris_b8const(vm, " ++ show x ++ "U)"
183 mkConst (B16 x) = "idris_b16const(vm, " ++ show x ++ "U)"
184 mkConst (B32 x) = "idris_b32const(vm, " ++ show x ++ "UL)"
185 mkConst (B64 x) = "idris_b64const(vm, " ++ show x ++ "ULL)"
186 -- if it's a type constant, we won't use it, but equally it shouldn't
187 -- report an error. These might creep into generated for various reasons
188 -- (especially if erasure is disabled).
189 mkConst c | isTypeConst c = "MKINT(42424242)"
190 mkConst c = error $ "mkConst of (" ++ show c ++ ") not implemented"
192bcc i (UPDATE l r) = indent i ++ creg l ++ " = " ++ creg r ++ ";\n"
193bcc i (MKCON l loc tag []) | tag < 256
194 = indent i ++ creg l ++ " = NULL_CON(" ++ show tag ++ ");\n"
195bcc i (MKCON l loc tag args)
196 = indent i ++ alloc loc tag ++
197 indent i ++ setArgs 0 args ++ "\n" ++
198 indent i ++ creg l ++ " = " ++ creg Tmp ++ ";\n"
200-- "MKCON(vm, " ++ creg l ++ ", " ++ show tag ++ ", " ++
201-- show (length args) ++ concatMap showArg args ++ ");\n"
202 where showArg r = ", " ++ creg r
203 setArgs i [] = ""
204 setArgs i (x : xs) = "SETARG(" ++ creg Tmp ++ ", " ++ show i ++ ", " ++ creg x ++
205 "); " ++ setArgs (i + 1) xs
206 alloc Nothing tag
207 = "allocCon(" ++ creg Tmp ++ ", vm, " ++ show tag ++ ", " ++
208 show (length args) ++ ", 0);\n"
209 alloc (Just old) tag
210 = "updateCon(" ++ creg Tmp ++ ", " ++ creg old ++ ", " ++ show tag ++ ", " ++
211 show (length args) ++ ");\n"
213bcc i (PROJECT l loc a) = indent i ++ "PROJECT(vm, " ++ creg l ++ ", " ++ show loc ++
214 ", " ++ show a ++ ");\n"
215bcc i (PROJECTINTO r t idx)
216 = indent i ++ creg r ++ " = GETARG(" ++ creg t ++ ", " ++ show idx ++ ");\n"
217bcc i (CASE True r code def)
218 | length code < 4 = showCase i def code
219 where
220 showCode :: Int -> [BC] -> String
221 showCode i bc = "{\n" ++ concatMap (bcc (i + 1)) bc ++
222 indent i ++ "}\n"
224 showCase :: Int -> Maybe [BC] -> [(Int, [BC])] -> String
225 showCase i Nothing [(t, c)] = indent i ++ showCode i c
226 showCase i (Just def) [] = indent i ++ showCode i def
227 showCase i def ((t, c) : cs)
228 = indent i ++ "if (CTAG(" ++ creg r ++ ") == " ++ show t ++ ") " ++ showCode i c
229 ++ indent i ++ "else\n" ++ showCase i def cs
231bcc i (CASE safe r code def)
232 = indent i ++ "switch(" ++ ctag safe ++ "(" ++ creg r ++ ")) {\n" ++
233 concatMap (showCase i) code ++
234 showDef i def ++
235 indent i ++ "}\n"
236 where
237 ctag True = "CTAG"
238 ctag False = "TAG"
240 showCase i (t, bc) = indent i ++ "case " ++ show t ++ ":\n"
241 ++ concatMap (bcc (i+1)) bc ++ indent (i + 1) ++ "break;\n"
242 showDef i Nothing = ""
243 showDef i (Just c) = indent i ++ "default:\n"
244 ++ concatMap (bcc (i+1)) c ++ indent (i + 1) ++ "break;\n"
245bcc i (CONSTCASE r code def)
246 | intConsts code
247-- = indent i ++ "switch(GETINT(" ++ creg r ++ ")) {\n" ++
248-- concatMap (showCase i) code ++
249-- showDef i def ++
250-- indent i ++ "}\n"
251 = concatMap (iCase (creg r)) code ++
252 indent i ++ "{\n" ++ showDefS i def ++ indent i ++ "}\n"
253 | strConsts code
254 = concatMap (strCase ("GETSTR(" ++ creg r ++ ")")) code ++
255 indent i ++ "{\n" ++ showDefS i def ++ indent i ++ "}\n"
256 | bigintConsts code
257 = concatMap (biCase (creg r)) code ++
258 indent i ++ "{\n" ++ showDefS i def ++ indent i ++ "}\n"
259 | otherwise = error $ "Can't happen: Can't compile const case " ++ show code
260 where
261 intConsts ((I _, _ ) : _) = True
262 intConsts ((Ch _, _ ) : _) = True
263 intConsts ((B8 _, _ ) : _) = True
264 intConsts ((B16 _, _ ) : _) = True
265 intConsts ((B32 _, _ ) : _) = True
266 intConsts ((B64 _, _ ) : _) = True
267 intConsts _ = False
269 bigintConsts ((BI _, _ ) : _) = True
270 bigintConsts _ = False
272 strConsts ((Str _, _ ) : _) = True
273 strConsts _ = False
275 strCase sv (s, bc) =
276 indent i ++ "if (strcmp(" ++ sv ++ ", " ++ show s ++ ") == 0) {\n" ++
277 concatMap (bcc (i+1)) bc ++ indent i ++ "} else\n"
278 biCase bv (BI b, bc) =
279 indent i ++ "if (bigEqConst(" ++ bv ++ ", " ++ show b ++ ")) {\n"
280 ++ concatMap (bcc (i+1)) bc ++ indent i ++ "} else\n"
281 iCase v (I b, bc) =
282 indent i ++ "if (GETINT(" ++ v ++ ") == " ++ show b ++ ") {\n"
283 ++ concatMap (bcc (i+1)) bc ++ indent i ++ "} else\n"
284 iCase v (Ch b, bc) =
285 indent i ++ "if (GETINT(" ++ v ++ ") == " ++ show (fromEnum b) ++ ") {\n"
286 ++ concatMap (bcc (i+1)) bc ++ indent i ++ "} else\n"
287 iCase v (B8 w, bc) =
288 indent i ++ "if (GETBITS8(" ++ v ++ ") == " ++ show (fromEnum w) ++ ") {\n"
289 ++ concatMap (bcc (i+1)) bc ++ indent i ++ "} else\n"
290 iCase v (B16 w, bc) =
291 indent i ++ "if (GETBITS16(" ++ v ++ ") == " ++ show (fromEnum w) ++ ") {\n"
292 ++ concatMap (bcc (i+1)) bc ++ indent i ++ "} else\n"
293 iCase v (B32 w, bc) =
294 indent i ++ "if (GETBITS32(" ++ v ++ ") == " ++ show (fromEnum w) ++ ") {\n"
295 ++ concatMap (bcc (i+1)) bc ++ indent i ++ "} else\n"
296 iCase v (B64 w, bc) =
297 indent i ++ "if (GETBITS64(" ++ v ++ ") == " ++ show (fromEnum w) ++ ") {\n"
298 ++ concatMap (bcc (i+1)) bc ++ indent i ++ "} else\n"
299 showCase i (t, bc) = indent i ++ "case " ++ show t ++ ":\n"
300 ++ concatMap (bcc (i+1)) bc ++
301 indent (i + 1) ++ "break;\n"
302 showDef i Nothing = ""
303 showDef i (Just c) = indent i ++ "default:\n"
304 ++ concatMap (bcc (i+1)) c ++
305 indent (i + 1) ++ "break;\n"
306 showDefS i Nothing = ""
307 showDefS i (Just c) = concatMap (bcc (i+1)) c
309bcc i (CALL n) = indent i ++ "CALL(" ++ cname n ++ ");\n"
310bcc i (TAILCALL n) = indent i ++ "TAILCALL(" ++ cname n ++ ");\n"
311bcc i (SLIDE n) = indent i ++ "SLIDE(vm, " ++ show n ++ ");\n"
312bcc i REBASE = indent i ++ "REBASE;\n"
313bcc i (RESERVE 0) = ""
314bcc i (RESERVE n) = indent i ++ "RESERVE(" ++ show n ++ ");\n"
315bcc i (ADDTOP 0) = ""
316bcc i (ADDTOP n) = indent i ++ "ADDTOP(" ++ show n ++ ");\n"
317bcc i (TOPBASE n) = indent i ++ "TOPBASE(" ++ show n ++ ");\n"
318bcc i (BASETOP n) = indent i ++ "BASETOP(" ++ show n ++ ");\n"
319bcc i STOREOLD = indent i ++ "STOREOLD;\n"
320bcc i (OP l fn args) = indent i ++ doOp (creg l ++ " = ") fn args ++ ";\n"
321bcc i (FOREIGNCALL l rty (FStr fn@('&':name)) [])
322 = indent i ++
323 c_irts (toFType rty) (creg l ++ " = ") fn ++ ";\n"
324bcc i (FOREIGNCALL l rty (FStr fn) (x:xs)) | fn == "%wrapper"
325 = indent i ++
326 c_irts (toFType rty) (creg l ++ " = ")
327 ("_idris_get_wrapper(" ++ creg (snd x) ++ ")") ++ ";\n"
328bcc i (FOREIGNCALL l rty (FStr fn) (x:xs)) | fn == "%dynamic"
329 = indent i ++ c_irts (toFType rty) (creg l ++ " = ")
330 ("(*(" ++ cFnSig "" rty xs ++ ") GETPTR(" ++ creg (snd x) ++ "))" ++
331 "(" ++ showSep "," (map fcall xs) ++ ")") ++ ";\n"
332bcc i (FOREIGNCALL l rty (FStr fn) args)
333 = indent i ++
334 c_irts (toFType rty) (creg l ++ " = ")
335 (fn ++ "(" ++ showSep "," (map fcall args) ++ ")") ++ ";\n"
336bcc i (NULL r) = indent i ++ creg r ++ " = NULL;\n" -- clear, so it'll be GCed
337bcc i (ERROR str) = indent i ++ "fprintf(stderr, " ++ show str ++ "); fprintf(stderr, \"\\n\"); exit(-1);\n"
338-- bcc i c = error (show c) -- indent i ++ "// not done yet\n"
340fcall (t, arg) = irts_c (toFType t) (creg arg)
341-- Deconstruct the Foreign type in the defunctionalised expression and build
342-- a foreign type description for c_irts and irts_c
343toAType (FCon i)
344 | i == sUN "C_IntChar" = ATInt ITChar
345 | i == sUN "C_IntNative" = ATInt ITNative
346 | i == sUN "C_IntBits8" = ATInt (ITFixed IT8)
347 | i == sUN "C_IntBits16" = ATInt (ITFixed IT16)
348 | i == sUN "C_IntBits32" = ATInt (ITFixed IT32)
349 | i == sUN "C_IntBits64" = ATInt (ITFixed IT64)
350toAType t = error (show t ++ " not defined in toAType")
352toFType (FCon c)
353 | c == sUN "C_Str" = FString
354 | c == sUN "C_Float" = FArith ATFloat
355 | c == sUN "C_Ptr" = FPtr
356 | c == sUN "C_MPtr" = FManagedPtr
357 | c == sUN "C_CData" = FCData
358 | c == sUN "C_Unit" = FUnit
359toFType (FApp c [_,ity])
360 | c == sUN "C_IntT" = FArith (toAType ity)
361 | c == sUN "C_FnT" = toFunType ity
362toFType (FApp c [_])
363 | c == sUN "C_Any" = FAny
364toFType t = FAny
366toFunType (FApp c [_,ity])
367 | c == sUN "C_FnBase" = FFunction
368 | c == sUN "C_FnIO" = FFunctionIO
369toFunType (FApp c [_,_,_,ity])
370 | c == sUN "C_Fn" = toFunType ity
371toFunType _ = FAny
373c_irts (FArith (ATInt ITNative)) l x = l ++ "MKINT((i_int)(" ++ x ++ "))"
374c_irts (FArith (ATInt ITChar)) l x = c_irts (FArith (ATInt ITNative)) l x
375c_irts (FArith (ATInt (ITFixed ity))) l x
376 = l ++ "idris_b" ++ show (nativeTyWidth ity) ++ "const(vm, " ++ x ++ ")"
377c_irts FString l x = l ++ "MKSTR(vm, " ++ x ++ ")"
378c_irts FUnit l x = x
379c_irts FPtr l x = l ++ "MKPTR(vm, " ++ x ++ ")"
380c_irts FManagedPtr l x = l ++ "MKMPTR(vm, " ++ x ++ ")"
381c_irts (FArith ATFloat) l x = l ++ "MKFLOAT(vm, " ++ x ++ ")"
382c_irts FCData l x = l ++ "MKCDATA(vm, " ++ x ++ ")"
383c_irts FAny l x = l ++ x
384c_irts FFunction l x = error "Return of function from foreign call is not supported"
385c_irts FFunctionIO l x = error "Return of function from foreign call is not supported"
387irts_c (FArith (ATInt ITNative)) x = "GETINT(" ++ x ++ ")"
388irts_c (FArith (ATInt ITChar)) x = irts_c (FArith (ATInt ITNative)) x
389irts_c (FArith (ATInt (ITFixed ity))) x
390 = "(" ++ x ++ "->info.bits" ++ show (nativeTyWidth ity) ++ ")"
391irts_c FString x = "GETSTR(" ++ x ++ ")"
392irts_c FUnit x = x
393irts_c FPtr x = "GETPTR(" ++ x ++ ")"
394irts_c FManagedPtr x = "GETMPTR(" ++ x ++ ")"
395irts_c (FArith ATFloat) x = "GETFLOAT(" ++ x ++ ")"
396irts_c FCData x = "GETCDATA(" ++ x ++ ")"
397irts_c FAny x = x
398irts_c FFunctionIO x = wrapped x
399irts_c FFunction x = wrapped x
401cFnSig name rty [] = ctype rty ++ " (*" ++ name ++ ")(void) "
402cFnSig name rty args = ctype rty ++ " (*" ++ name ++ ")("
403 ++ showSep "," (map (ctype . fst) args) ++ ") "
405wrapped x = "_idris_get_wrapper(" ++ x ++ ")"
407bitOp v op ty args = v ++ "idris_b" ++ show (nativeTyWidth ty) ++ op ++ "(vm, " ++ intercalate ", " (map creg args) ++ ")"
409bitCoerce v op input output arg
410 = v ++ "idris_b" ++ show (nativeTyWidth input) ++ op ++ show (nativeTyWidth output) ++ "(vm, " ++ creg arg ++ ")"
412signedTy :: NativeTy -> String
413signedTy t = "int" ++ show (nativeTyWidth t) ++ "_t"
415doOp v (LPlus (ATInt ITNative)) [l, r] = v ++ "ADD(" ++ creg l ++ ", " ++ creg r ++ ")"
416doOp v (LMinus (ATInt ITNative)) [l, r] = v ++ "INTOP(-," ++ creg l ++ ", " ++ creg r ++ ")"
417doOp v (LTimes (ATInt ITNative)) [l, r] = v ++ "MULT(" ++ creg l ++ ", " ++ creg r ++ ")"
418doOp v (LUDiv ITNative) [l, r] = v ++ "UINTOP(/," ++ creg l ++ ", " ++ creg r ++ ")"
419doOp v (LSDiv (ATInt ITNative)) [l, r] = v ++ "INTOP(/," ++ creg l ++ ", " ++ creg r ++ ")"
420doOp v (LURem ITNative) [l, r] = v ++ "UINTOP(%," ++ creg l ++ ", " ++ creg r ++ ")"
421doOp v (LSRem (ATInt ITNative)) [l, r] = v ++ "INTOP(%," ++ creg l ++ ", " ++ creg r ++ ")"
422doOp v (LAnd ITNative) [l, r] = v ++ "INTOP(&," ++ creg l ++ ", " ++ creg r ++ ")"
423doOp v (LOr ITNative) [l, r] = v ++ "INTOP(|," ++ creg l ++ ", " ++ creg r ++ ")"
424doOp v (LXOr ITNative) [l, r] = v ++ "INTOP(^," ++ creg l ++ ", " ++ creg r ++ ")"
425doOp v (LSHL ITNative) [l, r] = v ++ "INTOP(<<," ++ creg l ++ ", " ++ creg r ++ ")"
426doOp v (LLSHR ITNative) [l, r] = v ++ "UINTOP(>>," ++ creg l ++ ", " ++ creg r ++ ")"
427doOp v (LASHR ITNative) [l, r] = v ++ "INTOP(>>," ++ creg l ++ ", " ++ creg r ++ ")"
428doOp v (LCompl ITNative) [x] = v ++ "INTOP(~," ++ creg x ++ ")"
429doOp v (LEq (ATInt ITNative)) [l, r] = v ++ "INTOP(==," ++ creg l ++ ", " ++ creg r ++ ")"
430doOp v (LSLt (ATInt ITNative)) [l, r] = v ++ "INTOP(<," ++ creg l ++ ", " ++ creg r ++ ")"
431doOp v (LSLe (ATInt ITNative)) [l, r] = v ++ "INTOP(<=," ++ creg l ++ ", " ++ creg r ++ ")"
432doOp v (LSGt (ATInt ITNative)) [l, r] = v ++ "INTOP(>," ++ creg l ++ ", " ++ creg r ++ ")"
433doOp v (LSGe (ATInt ITNative)) [l, r] = v ++ "INTOP(>=," ++ creg l ++ ", " ++ creg r ++ ")"
434doOp v (LLt ITNative) [l, r] = v ++ "UINTOP(<," ++ creg l ++ ", " ++ creg r ++ ")"
435doOp v (LLe ITNative) [l, r] = v ++ "UINTOP(<=," ++ creg l ++ ", " ++ creg r ++ ")"
436doOp v (LGt ITNative) [l, r] = v ++ "UINTOP(>," ++ creg l ++ ", " ++ creg r ++ ")"
437doOp v (LGe ITNative) [l, r] = v ++ "UINTOP(>=," ++ creg l ++ ", " ++ creg r ++ ")"
439doOp v (LPlus (ATInt ITChar)) [l, r] = doOp v (LPlus (ATInt ITNative)) [l, r]
440doOp v (LMinus (ATInt ITChar)) [l, r] = doOp v (LMinus (ATInt ITNative)) [l, r]
441doOp v (LTimes (ATInt ITChar)) [l, r] = doOp v (LTimes (ATInt ITNative)) [l, r]
442doOp v (LUDiv ITChar) [l, r] = doOp v (LUDiv ITNative) [l, r]
443doOp v (LSDiv (ATInt ITChar)) [l, r] = doOp v (LSDiv (ATInt ITNative)) [l, r]
444doOp v (LURem ITChar) [l, r] = doOp v (LURem ITNative) [l, r]
445doOp v (LSRem (ATInt ITChar)) [l, r] = doOp v (LSRem (ATInt ITNative)) [l, r]
446doOp v (LAnd ITChar) [l, r] = doOp v (LAnd ITNative) [l, r]
447doOp v (LOr ITChar) [l, r] = doOp v (LOr ITNative) [l, r]
448doOp v (LXOr ITChar) [l, r] = doOp v (LXOr ITNative) [l, r]
449doOp v (LSHL ITChar) [l, r] = doOp v (LSHL ITNative) [l, r]
450doOp v (LLSHR ITChar) [l, r] = doOp v (LLSHR ITNative) [l, r]
451doOp v (LASHR ITChar) [l, r] = doOp v (LASHR ITNative) [l, r]
452doOp v (LCompl ITChar) [x] = doOp v (LCompl ITNative) [x]
453doOp v (LEq (ATInt ITChar)) [l, r] = doOp v (LEq (ATInt ITNative)) [l, r]
454doOp v (LSLt (ATInt ITChar)) [l, r] = doOp v (LSLt (ATInt ITNative)) [l, r]
455doOp v (LSLe (ATInt ITChar)) [l, r] = doOp v (LSLe (ATInt ITNative)) [l, r]
456doOp v (LSGt (ATInt ITChar)) [l, r] = doOp v (LSGt (ATInt ITNative)) [l, r]
457doOp v (LSGe (ATInt ITChar)) [l, r] = doOp v (LSGe (ATInt ITNative)) [l, r]
458doOp v (LLt ITChar) [l, r] = doOp v (LLt ITNative) [l, r]
459doOp v (LLe ITChar) [l, r] = doOp v (LLe ITNative) [l, r]
460doOp v (LGt ITChar) [l, r] = doOp v (LGt ITNative) [l, r]
461doOp v (LGe ITChar) [l, r] = doOp v (LGe ITNative) [l, r]
463doOp v (LPlus ATFloat) [l, r] = v ++ "FLOATOP(+," ++ creg l ++ ", " ++ creg r ++ ")"
464doOp v (LMinus ATFloat) [l, r] = v ++ "FLOATOP(-," ++ creg l ++ ", " ++ creg r ++ ")"
465doOp v (LTimes ATFloat) [l, r] = v ++ "FLOATOP(*," ++ creg l ++ ", " ++ creg r ++ ")"
466doOp v (LSDiv ATFloat) [l, r] = v ++ "FLOATOP(/," ++ creg l ++ ", " ++ creg r ++ ")"
467doOp v (LEq ATFloat) [l, r] = v ++ "FLOATBOP(==," ++ creg l ++ ", " ++ creg r ++ ")"
468doOp v (LSLt ATFloat) [l, r] = v ++ "FLOATBOP(<," ++ creg l ++ ", " ++ creg r ++ ")"
469doOp v (LSLe ATFloat) [l, r] = v ++ "FLOATBOP(<=," ++ creg l ++ ", " ++ creg r ++ ")"
470doOp v (LSGt ATFloat) [l, r] = v ++ "FLOATBOP(>," ++ creg l ++ ", " ++ creg r ++ ")"
471doOp v (LSGe ATFloat) [l, r] = v ++ "FLOATBOP(>=," ++ creg l ++ ", " ++ creg r ++ ")"
473doOp v (LIntFloat ITBig) [x] = v ++ "idris_castBigFloat(vm, " ++ creg x ++ ")"
474doOp v (LFloatInt ITBig) [x] = v ++ "idris_castFloatBig(vm, " ++ creg x ++ ")"
475doOp v (LPlus (ATInt ITBig)) [l, r] = v ++ "idris_bigPlus(vm, " ++ creg l ++ ", " ++ creg r ++ ")"
476doOp v (LMinus (ATInt ITBig)) [l, r] = v ++ "idris_bigMinus(vm, " ++ creg l ++ ", " ++ creg r ++ ")"
477doOp v (LTimes (ATInt ITBig)) [l, r] = v ++ "idris_bigTimes(vm, " ++ creg l ++ ", " ++ creg r ++ ")"
478doOp v (LSDiv (ATInt ITBig)) [l, r] = v ++ "idris_bigDivide(vm, " ++ creg l ++ ", " ++ creg r ++ ")"
479doOp v (LSRem (ATInt ITBig)) [l, r] = v ++ "idris_bigMod(vm, " ++ creg l ++ ", " ++ creg r ++ ")"
480doOp v (LAnd ITBig) [l, r] = v ++ "idris_bigAnd(vm, " ++ creg l ++ ", " ++ creg r ++ ")"
481doOp v (LOr ITBig) [l, r] = v ++ "idris_bigOr(vm, " ++ creg l ++ ", " ++ creg r ++ ")"
482doOp v (LSHL ITBig) [l, r] = v ++ "idris_bigShiftLeft(vm, " ++ creg l ++ ", " ++ creg r ++ ")"
483doOp v (LLSHR ITBig) [l, r] = v ++ "idris_bigLShiftRight(vm, " ++ creg l ++ ", " ++ creg r ++ ")"
484doOp v (LASHR ITBig) [l, r] = v ++ "idris_bigAShiftRight(vm, " ++ creg l ++ ", " ++ creg r ++ ")"
485doOp v (LEq (ATInt ITBig)) [l, r] = v ++ "idris_bigEq(vm, " ++ creg l ++ ", " ++ creg r ++ ")"
486doOp v (LSLt (ATInt ITBig)) [l, r] = v ++ "idris_bigLt(vm, " ++ creg l ++ ", " ++ creg r ++ ")"
487doOp v (LSLe (ATInt ITBig)) [l, r] = v ++ "idris_bigLe(vm, " ++ creg l ++ ", " ++ creg r ++ ")"
488doOp v (LSGt (ATInt ITBig)) [l, r] = v ++ "idris_bigGt(vm, " ++ creg l ++ ", " ++ creg r ++ ")"
489doOp v (LSGe (ATInt ITBig)) [l, r] = v ++ "idris_bigGe(vm, " ++ creg l ++ ", " ++ creg r ++ ")"
491doOp v (LIntFloat ITNative) [x] = v ++ "idris_castIntFloat(" ++ creg x ++ ")"
492doOp v (LFloatInt ITNative) [x] = v ++ "idris_castFloatInt(" ++ creg x ++ ")"
493doOp v (LSExt ITNative ITBig) [x] = v ++ "idris_castIntBig(vm, " ++ creg x ++ ")"
494doOp v (LTrunc ITBig ITNative) [x] = v ++ "idris_castBigInt(vm, " ++ creg x ++ ")"
495doOp v (LStrInt ITBig) [x] = v ++ "idris_castStrBig(vm, " ++ creg x ++ ")"
496doOp v (LIntStr ITBig) [x] = v ++ "idris_castBigStr(vm, " ++ creg x ++ ")"
497doOp v (LIntStr ITNative) [x] = v ++ "idris_castIntStr(vm, " ++ creg x ++ ")"
498doOp v (LStrInt ITNative) [x] = v ++ "idris_castStrInt(vm, " ++ creg x ++ ")"
499doOp v (LIntStr (ITFixed _)) [x] = v ++ "idris_castBitsStr(vm, " ++ creg x ++ ")"
500doOp v LFloatStr [x] = v ++ "idris_castFloatStr(vm, " ++ creg x ++ ")"
501doOp v LStrFloat [x] = v ++ "idris_castStrFloat(vm, " ++ creg x ++ ")"
503doOp v (LSLt (ATInt (ITFixed ty))) [x, y] = bitOp v "SLt" ty [x, y]
504doOp v (LSLe (ATInt (ITFixed ty))) [x, y] = bitOp v "SLte" ty [x, y]
505doOp v (LEq (ATInt (ITFixed ty))) [x, y] = bitOp v "Eq" ty [x, y]
506doOp v (LSGe (ATInt (ITFixed ty))) [x, y] = bitOp v "SGte" ty [x, y]
507doOp v (LSGt (ATInt (ITFixed ty))) [x, y] = bitOp v "SGt" ty [x, y]
508doOp v (LLt (ITFixed ty)) [x, y] = bitOp v "Lt" ty [x, y]
509doOp v (LLe (ITFixed ty)) [x, y] = bitOp v "Lte" ty [x, y]
510doOp v (LGe (ITFixed ty)) [x, y] = bitOp v "Gte" ty [x, y]
511doOp v (LGt (ITFixed ty)) [x, y] = bitOp v "Gt" ty [x, y]
513doOp v (LSHL (ITFixed ty)) [x, y] = bitOp v "Shl" ty [x, y]
514doOp v (LLSHR (ITFixed ty)) [x, y] = bitOp v "LShr" ty [x, y]
515doOp v (LASHR (ITFixed ty)) [x, y] = bitOp v "AShr" ty [x, y]
516doOp v (LAnd (ITFixed ty)) [x, y] = bitOp v "And" ty [x, y]
517doOp v (LOr (ITFixed ty)) [x, y] = bitOp v "Or" ty [x, y]
518doOp v (LXOr (ITFixed ty)) [x, y] = bitOp v "Xor" ty [x, y]
519doOp v (LCompl (ITFixed ty)) [x] = bitOp v "Compl" ty [x]
521doOp v (LPlus (ATInt (ITFixed ty))) [x, y] = bitOp v "Plus" ty [x, y]
522doOp v (LMinus (ATInt (ITFixed ty))) [x, y] = bitOp v "Minus" ty [x, y]
523doOp v (LTimes (ATInt (ITFixed ty))) [x, y] = bitOp v "Times" ty [x, y]
524doOp v (LUDiv (ITFixed ty)) [x, y] = bitOp v "UDiv" ty [x, y]
525doOp v (LSDiv (ATInt (ITFixed ty))) [x, y] = bitOp v "SDiv" ty [x, y]
526doOp v (LURem (ITFixed ty)) [x, y] = bitOp v "URem" ty [x, y]
527doOp v (LSRem (ATInt (ITFixed ty))) [x, y] = bitOp v "SRem" ty [x, y]
529doOp v (LSExt (ITFixed from) ITBig) [x]
530 = v ++ "MKBIGSI(vm, (" ++ signedTy from ++ ")" ++ creg x ++ "->info.bits" ++ show (nativeTyWidth from) ++ ")"
531doOp v (LSExt ITNative (ITFixed to)) [x]
532 = v ++ "idris_b" ++ show (nativeTyWidth to) ++ "const(vm, GETINT(" ++ creg x ++ "))"
533doOp v (LSExt ITChar (ITFixed to)) [x]
534 = doOp v (LSExt ITNative (ITFixed to)) [x]
535doOp v (LSExt (ITFixed from) ITNative) [x]
536 = v ++ "MKINT((i_int)((" ++ signedTy from ++ ")" ++ creg x ++ "->info.bits" ++ show (nativeTyWidth from) ++ "))"
537doOp v (LSExt (ITFixed from) ITChar) [x]
538 = doOp v (LSExt (ITFixed from) ITNative) [x]
539doOp v (LSExt (ITFixed from) (ITFixed to)) [x]
540 | nativeTyWidth from < nativeTyWidth to = bitCoerce v "S" from to x
541doOp v (LZExt ITNative (ITFixed to)) [x]
542 = v ++ "idris_b" ++ show (nativeTyWidth to) ++ "const(vm, (uintptr_t)GETINT(" ++ creg x ++ "))"
543doOp v (LZExt ITChar (ITFixed to)) [x]
544 = doOp v (LZExt ITNative (ITFixed to)) [x]
545doOp v (LZExt (ITFixed from) ITNative) [x]
546 = v ++ "MKINT((i_int)" ++ creg x ++ "->info.bits" ++ show (nativeTyWidth from) ++ ")"
547doOp v (LZExt (ITFixed from) ITChar) [x]
548 = doOp v (LZExt (ITFixed from) ITNative) [x]
549doOp v (LZExt (ITFixed from) ITBig) [x]
550 = v ++ "MKBIGUI(vm, " ++ creg x ++ "->info.bits" ++ show (nativeTyWidth from) ++ ")"
551doOp v (LZExt ITNative ITBig) [x]
552 = v ++ "MKBIGUI(vm, (uintptr_t)GETINT(" ++ creg x ++ "))"
553doOp v (LZExt (ITFixed from) (ITFixed to)) [x]
554 | nativeTyWidth from < nativeTyWidth to = bitCoerce v "Z" from to x
555doOp v (LTrunc ITNative (ITFixed to)) [x]
556 = v ++ "idris_b" ++ show (nativeTyWidth to) ++ "const(vm, GETINT(" ++ creg x ++ "))"
557doOp v (LTrunc ITChar (ITFixed to)) [x]
558 = doOp v (LTrunc ITNative (ITFixed to)) [x]
559doOp v (LTrunc (ITFixed from) ITNative) [x]
560 = v ++ "MKINT((i_int)" ++ creg x ++ "->info.bits" ++ show (nativeTyWidth from) ++ ")"
561doOp v (LTrunc (ITFixed from) ITChar) [x]
562 = doOp v (LTrunc (ITFixed from) ITNative) [x]
563doOp v (LTrunc ITBig (ITFixed IT64)) [x]
564 = v ++ "idris_b64const(vm, ISINT(" ++ creg x ++ ") ? GETINT(" ++ creg x ++ ") : idris_truncBigB64(GETMPZ(" ++ creg x ++ ")))"
565doOp v (LTrunc ITBig (ITFixed to)) [x]
566 = v ++ "idris_b" ++ show (nativeTyWidth to) ++ "const(vm, ISINT(" ++ creg x ++ ") ? GETINT(" ++ creg x ++ ") : mpz_get_ui(GETMPZ(" ++ creg x ++ ")))"
567doOp v (LTrunc (ITFixed from) (ITFixed to)) [x]
568 | nativeTyWidth from > nativeTyWidth to = bitCoerce v "T" from to x
570doOp v LFExp [x] = v ++ flUnOp "exp" (creg x)
571doOp v LFLog [x] = v ++ flUnOp "log" (creg x)
572doOp v LFSin [x] = v ++ flUnOp "sin" (creg x)
573doOp v LFCos [x] = v ++ flUnOp "cos" (creg x)
574doOp v LFTan [x] = v ++ flUnOp "tan" (creg x)
575doOp v LFASin [x] = v ++ flUnOp "asin" (creg x)
576doOp v LFACos [x] = v ++ flUnOp "acos" (creg x)
577doOp v LFATan [x] = v ++ flUnOp "atan" (creg x)
578doOp v LFSqrt [x] = v ++ flUnOp "sqrt" (creg x)
579doOp v LFFloor [x] = v ++ flUnOp "floor" (creg x)
580doOp v LFCeil [x] = v ++ flUnOp "ceil" (creg x)
581doOp v LFNegate [x] = v ++ "MKFLOAT(vm, -GETFLOAT(" ++ (creg x) ++ "))"
583-- String functions which don't need to know we're UTF8
584doOp v LStrConcat [l,r] = v ++ "idris_concat(vm, " ++ creg l ++ ", " ++ creg r ++ ")"
585doOp v LStrLt [l,r] = v ++ "idris_strlt(vm, " ++ creg l ++ ", " ++ creg r ++ ")"
586doOp v LStrEq [l,r] = v ++ "idris_streq(vm, " ++ creg l ++ ", " ++ creg r ++ ")"
588doOp v LReadStr [_] = v ++ "idris_readStr(vm, stdin)"
589doOp v LWriteStr [_,s]
590 = v ++ "MKINT((i_int)(idris_writeStr(stdout"
591 ++ ",GETSTR("
592 ++ creg s ++ "))))"
595-- String functions which need to know we're UTF8
596doOp v LStrHead [x] = v ++ "idris_strHead(vm, " ++ creg x ++ ")"
597doOp v LStrTail [x] = v ++ "idris_strTail(vm, " ++ creg x ++ ")"
598doOp v LStrCons [x, y] = v ++ "idris_strCons(vm, " ++ creg x ++ "," ++ creg y ++ ")"
599doOp v LStrIndex [x, y] = v ++ "idris_strIndex(vm, " ++ creg x ++ "," ++ creg y ++ ")"
600doOp v LStrRev [x] = v ++ "idris_strRev(vm, " ++ creg x ++ ")"
601doOp v LStrLen [x] = v ++ "idris_strlen(vm, " ++ creg x ++ ")"
602doOp v LStrSubstr [x,y,z] = v ++ "idris_substr(vm, " ++ creg x ++ "," ++ creg y ++ "," ++ creg z ++ ")"
604doOp v LFork [x] = v ++ "MKPTR(vm, vmThread(vm, " ++ cname (sMN 0 "EVAL") ++ ", " ++ creg x ++ "))"
605doOp v LPar [x] = v ++ creg x -- "MKPTR(vm, vmThread(vm, " ++ cname (MN 0 "EVAL") ++ ", " ++ creg x ++ "))"
606doOp v (LChInt ITNative) args = v ++ creg (last args)
607doOp v (LChInt ITChar) args = doOp v (LChInt ITNative) args
608doOp v (LIntCh ITNative) args = v ++ creg (last args)
609doOp v (LIntCh ITChar) args = doOp v (LIntCh ITNative) args
611doOp v LSystemInfo [x] = v ++ "idris_systemInfo(vm, " ++ creg x ++ ")"
612doOp v LNoOp args = v ++ creg (last args)
614-- Pointer primitives (declared as %extern in Builtins.idr)
615doOp v (LExternal rf) [_,x]
616 | rf == sUN "prim__readFile"
617 = v ++ "idris_readStr(vm, GETPTR(" ++ creg x ++ "))"
618doOp v (LExternal wf) [_,x,s]
619 | wf == sUN "prim__writeFile"
620 = v ++ "MKINT((i_int)(idris_writeStr(GETPTR(" ++ creg x
621 ++ "),GETSTR("
622 ++ creg s ++ "))))"
623doOp v (LExternal vm) [] | vm == sUN "prim__vm" = v ++ "MKPTR(vm, vm)"
624doOp v (LExternal si) [] | si == sUN "prim__stdin" = v ++ "MKPTR(vm, stdin)"
625doOp v (LExternal so) [] | so == sUN "prim__stdout" = v ++ "MKPTR(vm, stdout)"
626doOp v (LExternal se) [] | se == sUN "prim__stderr" = v ++ "MKPTR(vm, stderr)"
628doOp v (LExternal nul) [] | nul == sUN "prim__null" = v ++ "MKPTR(vm, NULL)"
629doOp v (LExternal eqp) [x, y] | eqp == sUN "prim__eqPtr"
630 = v ++ "MKINT((i_int)(GETPTR(" ++ creg x ++ ") == GETPTR(" ++ creg y ++ ")))"
631doOp v (LExternal eqp) [x, y] | eqp == sUN "prim__eqManagedPtr"
632 = v ++ "MKINT((i_int)(GETMPTR(" ++ creg x ++ ") == GETMPTR(" ++ creg y ++ ")))"
633doOp v (LExternal rp) [p, i] | rp == sUN "prim__registerPtr"
634 = v ++ "MKMPTR(vm, GETPTR(" ++ creg p ++ "), GETINT(" ++ creg i ++ "))"
635doOp v (LExternal pk) [_, p, o] | pk == sUN "prim__peek8"
636 = v ++ "idris_peekB8(vm," ++ creg p ++ "," ++ creg o ++")"
637doOp v (LExternal pk) [_, p, o, x] | pk == sUN "prim__poke8"
638 = v ++ "idris_pokeB8(" ++ creg p ++ "," ++ creg o ++ "," ++ creg x ++ ")"
639doOp v (LExternal pk) [_, p, o] | pk == sUN "prim__peek16"
640 = v ++ "idris_peekB16(vm," ++ creg p ++ "," ++ creg o ++")"
641doOp v (LExternal pk) [_, p, o, x] | pk == sUN "prim__poke16"
642 = v ++ "idris_pokeB16(" ++ creg p ++ "," ++ creg o ++ "," ++ creg x ++ ")"
643doOp v (LExternal pk) [_, p, o] | pk == sUN "prim__peek32"
644 = v ++ "idris_peekB32(vm," ++ creg p ++ "," ++ creg o ++")"
645doOp v (LExternal pk) [_, p, o, x] | pk == sUN "prim__poke32"
646 = v ++ "idris_pokeB32(" ++ creg p ++ "," ++ creg o ++ "," ++ creg x ++ ")"
647doOp v (LExternal pk) [_, p, o] | pk == sUN "prim__peek64"
648 = v ++ "idris_peekB64(vm," ++ creg p ++ "," ++ creg o ++")"
649doOp v (LExternal pk) [_, p, o, x] | pk == sUN "prim__poke64"
650 = v ++ "idris_pokeB64(" ++ creg p ++ "," ++ creg o ++ "," ++ creg x ++ ")"
651doOp v (LExternal pk) [_, p, o] | pk == sUN "prim__peekPtr"
652 = v ++ "idris_peekPtr(vm," ++ creg p ++ "," ++ creg o ++")"
653doOp v (LExternal pk) [_, p, o, x] | pk == sUN "prim__pokePtr"
654 = v ++ "idris_pokePtr(" ++ creg p ++ "," ++ creg o ++ "," ++ creg x ++ ")"
655doOp v (LExternal pk) [_, p, o, x] | pk == sUN "prim__pokeDouble"
656 = v ++ "idris_pokeDouble(" ++ creg p ++ "," ++ creg o ++ "," ++ creg x ++ ")"
657doOp v (LExternal pk) [_, p, o] | pk == sUN "prim__peekDouble"
658 = v ++ "idris_peekDouble(vm," ++ creg p ++ "," ++ creg o ++")"
659doOp v (LExternal pk) [_, p, o, x] | pk == sUN "prim__pokeSingle"
660 = v ++ "idris_pokeSingle(" ++ creg p ++ "," ++ creg o ++ "," ++ creg x ++ ")"
661doOp v (LExternal pk) [_, p, o] | pk == sUN "prim__peekSingle"
662 = v ++ "idris_peekSingle(vm," ++ creg p ++ "," ++ creg o ++")"
663doOp v (LExternal pk) [] | pk == sUN "prim__sizeofPtr"
664 = v ++ "MKINT(sizeof(void*))"
665doOp v (LExternal mpt) [p] | mpt == sUN "prim__asPtr"
666 = v ++ "MKPTR(vm, GETMPTR("++ creg p ++"))"
667doOp v (LExternal offs) [p, n] | offs == sUN "prim__ptrOffset"
668 = v ++ "MKPTR(vm, GETPTR(" ++ creg p ++ ") + GETINT(" ++ creg n ++ "))"
669doOp _ op args = error $ "doOp not implemented (" ++ show (op, args) ++ ")"
672flUnOp :: String -> String -> String
673flUnOp name val = "MKFLOAT(vm, " ++ name ++ "(GETFLOAT(" ++ val ++ ")))"
675-------------------- Interface file generation
677-- First, the wrappers in the C file
679ifaceC :: Export -> String
680ifaceC (ExportData n) = "typedef VAL " ++ cdesc n ++ ";\n"
681ifaceC (ExportFun n cn ret args)
682 = ctype ret ++ " " ++ cdesc cn ++
683 "(VM* vm" ++ showArgs (zip argNames args) ++ ") {\n"
684 ++ mkBody n (zip argNames args) ret ++ "}\n\n"
685 where showArgs [] = ""
686 showArgs ((n, t) : ts) = ", " ++ ctype t ++ " " ++ n ++
687 showArgs ts
689 argNames = zipWith (++) (repeat "arg") (map show [0..])
691mkBody n as t = indent 1 ++ "INITFRAME;\n" ++
692 indent 1 ++ "RESERVE(" ++ show (max (length as) 3) ++ ");\n" ++
693 push 0 as ++ call n ++ retval t
694 where push i [] = ""
695 push i ((n, t) : ts) = indent 1 ++ c_irts (toFType t)
696 ("TOP(" ++ show i ++ ") = ") n
697 ++ ";\n" ++ push (i + 1) ts
699 call _ = indent 1 ++ "STOREOLD;\n" ++
700 indent 1 ++ "BASETOP(0);\n" ++
701 indent 1 ++ "ADDTOP(" ++ show (length as) ++ ");\n" ++
702 indent 1 ++ "CALL(" ++ cname n ++ ");\n"
704 retval (FIO t)
705 = indent 1 ++ "TOP(0) = NULL;\n" ++
706 indent 1 ++ "TOP(1) = NULL;\n" ++
707 indent 1 ++ "TOP(2) = RVAL;\n" ++
708 indent 1 ++ "STOREOLD;\n" ++
709 indent 1 ++ "BASETOP(0);\n" ++
710 indent 1 ++ "ADDTOP(3);\n" ++
711 indent 1 ++ "CALL(" ++ cname (sUN "call__IO") ++ ");\n" ++
712 retval t
713 retval t = indent 1 ++ "return " ++ irts_c (toFType t) "RVAL" ++ ";\n"
715ctype (FCon c)
716 | c == sUN "C_Str" = "char*"
717 | c == sUN "C_Float" = "float"
718 | c == sUN "C_Ptr" = "void*"
719 | c == sUN "C_MPtr" = "void*"
720 | c == sUN "C_Unit" = "void"
721ctype (FApp c [_,ity])
722 | c == sUN "C_IntT" = carith ity
723ctype (FApp c [_])
724 | c == sUN "C_Any" = "VAL"
725ctype (FStr s) = s
726ctype FUnknown = "void*"
727ctype (FIO t) = ctype t
728ctype t = error "Can't happen: Not a valid interface type " ++ show t
730carith (FCon i)
731 | i == sUN "C_IntChar" = "char"
732 | i == sUN "C_IntNative" = "int"
733carith t = error "Can't happen: Not an exportable arithmetic type"
735cdesc (FStr s) = s
736cdesc s = error "Can't happen: Not a valid C name"
738-- Then, the header files
740codegenH :: [ExportIFace] -> IO ()
741codegenH es = mapM_ writeIFace es
743writeIFace :: ExportIFace -> IO ()
744writeIFace (Export ffic hdr exps)
745 | ffic == sNS (sUN "FFI_C") ["FFI_C"]
746 = do let hfile = "#ifndef " ++ hdr_guard hdr ++ "\n" ++
747 "#define " ++ hdr_guard hdr ++ "\n\n" ++
748 "#include <idris_rts.h>\n\n" ++
749 concatMap hdr_export exps ++ "\n" ++
750 "#endif\n\n"
751 writeFile hdr hfile
752 | otherwise = return ()
754hdr_guard x = "__" ++ map hchar x
755 where hchar x | isAlphaNum x = toUpper x
756 hchar _ = '_'
758hdr_export :: Export -> String
759hdr_export (ExportData n) = "typedef VAL " ++ cdesc n ++ ";\n"
760hdr_export (ExportFun n cn ret args)
761 = ctype ret ++ " " ++ cdesc cn ++
762 "(VM* vm" ++ showArgs (zip argNames args) ++ ");\n"
763 where showArgs [] = ""
764 showArgs ((n, t) : ts) = ", " ++ ctype t ++ " " ++ n ++
765 showArgs ts
767 argNames = zipWith (++) (repeat "arg") (map show [0..])
769------------------ Callback wrapper generation ----------------
770-- Generate callback wrappers and a function to select the
771-- correct wrapper function to pass.
772-- TODO: This is limited to functions that are specified in
773-- the foreign call. Otherwise we would have to generate wrappers for all
774-- functions with correct arity or do flow analysis
775-- to find all possible inputs to the foreign call.
776genWrappers :: [(Name, [BC])] -> String
777genWrappers bcs = let
778 tags = nubBy (\x y -> snd x == snd y) $ concatMap (getCallback . snd) bcs
779 in
780 case tags of
781 [] -> ""
782 t -> concatMap genWrapper t ++ genDispatcher t
784genDispatcher :: [(FDesc, Int)] -> String
785genDispatcher tags = "void* _idris_get_wrapper(VAL con)\n" ++
786 "{\n" ++
787 indent 1 ++ "switch(TAG(con)) {\n" ++
788 concatMap makeSwitch tags ++
789 indent 1 ++ "}\n" ++
790 indent 1 ++ "fprintf(stderr, \"No wrapper for callback\");\n" ++
791 indent 1 ++ "exit(-1);\n" ++
792 "}\n\n"
793 where
794 makeSwitch (_, tag) =
795 indent 1 ++ "case " ++ show tag ++ ":\n" ++
796 indent 2 ++ "return (void*) &" ++ wrapperName tag ++ ";\n"
798genWrapper :: (FDesc, Int) -> String
799genWrapper (desc, tag) | (toFType desc) == FFunctionIO =
800 error $ "Cannot create C callbacks for IO functions, wrap them with unsafePerformIO.\n"
801genWrapper (desc, tag) = ret ++ " " ++ wrapperName tag ++ "(" ++
802 renderArgs argList ++")\n" ++
803 "{\n" ++
804 (if ret /= "void" then indent 1 ++ ret ++ " ret;\n" else "") ++
805 indent 1 ++ "VM* vm = get_vm();\n" ++
806 indent 1 ++ "if (vm == NULL) {\n" ++
807 indent 2 ++ "vm = idris_vm();\n" ++
808 indent 1 ++ "}\n" ++
809 indent 1 ++ "INITFRAME;\n" ++
810 indent 1 ++ "RESERVE(" ++ show (len + 1) ++ ");\n" ++
811 indent 1 ++ "allocCon(REG1, vm, " ++ show tag ++ ",0 , 0);\n" ++
812 indent 1 ++ "TOP(0) = REG1;\n" ++
813 applyArgs argList ++
814 if ret /= "void"
815 then indent 1 ++ "ret = " ++ irts_c (toFType ft) "RVAL" ++ ";\n"
816 ++ indent 1 ++ "return ret;\n}\n\n"
817 else "}\n\n"
818 where
819 (ret, ft) = rty desc
820 argList = zip (args desc) [0..]
821 len = length argList
823 applyArgs (x:y:xs) = push 1 [x] ++
824 indent 1 ++ "STOREOLD;\n" ++
825 indent 1 ++ "BASETOP(0);\n" ++
826 indent 1 ++ "ADDTOP(2);\n" ++
827 indent 1 ++ "CALL(_idris__123_APPLY0_125_);\n" ++
828 indent 1 ++ "TOP(0)=REG1;\n" ++
829 applyArgs (y:xs)
830 applyArgs x = push 1 x ++
831 indent 1 ++ "STOREOLD;\n" ++
832 indent 1 ++ "BASETOP(0);\n" ++
833 indent 1 ++ "ADDTOP(" ++ show (length x + 1) ++ ");\n" ++
834 indent 1 ++ "CALL(_idris__123_APPLY0_125_);\n"
835 renderArgs [] = "void"
836 renderArgs [((s, _), n)] = s ++ " a" ++ (show n)
837 renderArgs (((s, _), n):xs) = s ++ " a" ++ (show n) ++ ", " ++
838 renderArgs xs
839 rty (FApp c [_,ty])
840 | c == sUN "C_FnBase" = (ctype ty, ty)
841 | c == sUN "C_FnIO" = (ctype ty, ty)
842 | c == sUN "C_FnT" = rty ty
843 rty (FApp c [_,_,ty,fn])
844 | c == sUN "C_Fn" = rty fn
845 rty x = ("", x)
846 args (FApp c [_,ty])
847 | c == sUN "C_FnBase" = []
848 | c == sUN "C_FnIO" = []
849 | c == sUN "C_FnT" = args ty
850 args (FApp c [_,_,ty,fn])
851 | toFType ty == FUnit = []
852 | c == sUN "C_Fn" = (ctype ty, ty) : args fn
853 args _ = []
854 push i [] = ""
855 push i (((c, t), n) : ts) = indent 1 ++ c_irts (toFType t)
856 ("TOP(" ++ show i ++ ") = ") ("a" ++ show n)
857 ++ ";\n" ++ push (i + 1) ts
859wrapperName :: Int -> String
860wrapperName tag = "_idris_wrapper_" ++ show tag
862getCallback :: [BC] -> [(FDesc, Int)]
863getCallback bc = getCallback' (reverse bc)
864 where
865 getCallback' (x:xs) = case hasCallback x of
866 [] -> getCallback' xs
867 cbs -> case findCons cbs xs of
868 [] -> error "Idris function couldn't be wrapped."
869 x -> x
870 getCallback' [] = []
871 findCons (c:cs) xs = findCon c xs ++ findCons cs xs
872 findCons [] _ = []
873 findCon c ((MKCON l loc tag args):xs) | snd c == l = [(fst c, tag)]
874 findCon c (_:xs) = findCon c xs
875 findCon c [] = []
877hasCallback :: BC -> [(FDesc, Reg)]
878hasCallback (FOREIGNCALL l rty (FStr fn) args) = filter isFn args
879 where
880 isFn (desc,_) = case toFType desc of
881 FFunction -> True
882 FFunctionIO -> True
883 _ -> False
884hasCallback _ = []