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