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