on 5229ca1 help sign in
Idris-dev/src/IRTS/CodegenC.hs
904 lines 44 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"]
120-- clang optimises sibling calls in O1, but gcc doesn't
121-- on the other hand, O1 compiles significantly faster in clang without
122-- any noticeable performance hit.
123gccDbg TRACE = ["-O1", "-foptimize-sibling-calls"]
124gccDbg _ = ["-O1", "-foptimize-sibling-calls"]
126cname :: Name -> String
127cname n = "_idris_" ++ concatMap cchar (showCG n)
128 where cchar x | isAlpha x || isDigit x = [x]
129 | otherwise = "_" ++ show (fromEnum x) ++ "_"
131indent :: Int -> String
132indent n = replicate (n*4) ' '
134creg RVal = "RVAL"
135creg (L i) = "LOC(" ++ show i ++ ")"
136creg (T i) = "TOP(" ++ show i ++ ")"
137creg Tmp = "REG1"
139toDecl :: Name -> String
140toDecl f = "void " ++ cname f ++ "(VM*, VAL*);\n"
142toC :: Name -> [BC] -> String
143toC f code
144 = -- "/* " ++ show code ++ "*/\n\n" ++
145 "void " ++ cname f ++ "(VM* vm, VAL* oldbase) {\n" ++
146 indent 1 ++ "INITFRAME;\n" ++
147 concatMap (bcc 1) code ++ "}\n\n"
149showCStr :: String -> String
150showCStr s = '"' : foldr ((++) . showChar) "\"" s
151 where
152 showChar :: Char -> String
153 showChar '"' = "\\\""
154 showChar '\\' = "\\\\"
155 showChar c
156 -- Note: we need the double quotes around the codes because otherwise
157 -- "\n3" would get encoded as "\x0a3", which is incorrect.
158 -- Instead, we opt for "\x0a""3" and let the C compiler deal with it.
159 | ord c < 0x20 = showUTF8 (ord c)
160 | ord c < 0x7f = [c] -- 0x7f = \DEL
161 | otherwise = showHexes (utf8bytes (ord c))
163 showUTF8 c = "\"\"\\x" ++ pad (showHex c "") ++ "\"\""
164 showHexes = foldr ((++) . showUTF8) ""
166 utf8bytes :: Int -> [Int]
167 utf8bytes x
168 | x <= 0x7f = [x]
169 | x <= 0x7ff = let (y : ys) = split [] 2 x in (y .|. 0xc0) : map (.|. 0x80) ys
170 | x <= 0xffff = let (y : ys) = split [] 3 x in (y .|. 0xe0) : map (.|. 0x80) ys
171 | x <= 0x10ffff = let (y : ys) = split [] 4 x in (y .|. 0xf0) : map (.|. 0x80) ys
172 | otherwise = error $ "Invalid Unicode code point U+" ++ showHex x ""
173 where
174 split acc 1 x = x : acc
175 split acc i x = split (x .&. 0x3f : acc) (i - 1) (shiftR x 6)
177 pad :: String -> String
178 pad s = case length s of
179 1 -> "0" ++ s
180 2 -> s
181 _ -> error $ "Can't happen: String of invalid length " ++ show s
183bcc :: Int -> BC -> String
184bcc i (ASSIGN l r) = indent i ++ creg l ++ " = " ++ creg r ++ ";\n"
185bcc i (ASSIGNCONST l c)
186 = indent i ++ creg l ++ " = " ++ mkConst c ++ ";\n"
187 where
188 mkConst (I i) = "MKINT(" ++ show i ++ ")"
189 mkConst (BI i) = let maxInt = 2^30
190 in if i >= -maxInt && i < maxInt
191 then "MKINT(" ++ show i ++ ")"
192 else "MKBIGC(vm,\"" ++ show i ++ "\")"
193 mkConst (Fl f) = "MKFLOAT(vm, " ++ (map toUpper $ show f) ++ ")"
194 mkConst (Ch c) = "MKINT(" ++ show (fromEnum c) ++ ")"
195 mkConst (Str s) = "MKSTR(vm, " ++ showCStr s ++ ")"
196 mkConst (B8 x) = "idris_b8const(vm, " ++ show x ++ "U)"
197 mkConst (B16 x) = "idris_b16const(vm, " ++ show x ++ "U)"
198 mkConst (B32 x) = "idris_b32const(vm, " ++ show x ++ "UL)"
199 mkConst (B64 x) = "idris_b64const(vm, " ++ show x ++ "ULL)"
200 -- if it's a type constant, we won't use it, but equally it shouldn't
201 -- report an error. These might creep into generated for various reasons
202 -- (especially if erasure is disabled).
203 mkConst c | isTypeConst c = "MKINT(42424242)"
204 mkConst c = error $ "mkConst of (" ++ show c ++ ") not implemented"
206bcc i (UPDATE l r) = indent i ++ creg l ++ " = " ++ creg r ++ ";\n"
207bcc i (MKCON l loc tag []) | tag < 256
208 = indent i ++ creg l ++ " = NULL_CON(" ++ show tag ++ ");\n"
209bcc i (MKCON l loc tag args)
210 = indent i ++ alloc loc tag ++
211 indent i ++ setArgs 0 args ++ "\n" ++
212 indent i ++ creg l ++ " = " ++ creg Tmp ++ ";\n"
213 where setArgs i [] = ""
214 setArgs i (x : xs) = "SETARG(" ++ creg Tmp ++ ", " ++ show i ++ ", " ++ creg x ++
215 "); " ++ setArgs (i + 1) xs
216 alloc Nothing tag
217 = "allocCon(" ++ creg Tmp ++ ", vm, " ++ show tag ++ ", " ++
218 show (length args) ++ ", 0);\n"
219 alloc (Just old) tag
220 = "updateCon(" ++ creg Tmp ++ ", " ++ creg old ++ ", " ++ show tag ++ ", " ++
221 show (length args) ++ ");\n"
223bcc i (PROJECT l loc a) = indent i ++ "PROJECT(vm, " ++ creg l ++ ", " ++ show loc ++
224 ", " ++ show a ++ ");\n"
225bcc i (PROJECTINTO r t idx)
226 = indent i ++ creg r ++ " = GETARG(" ++ creg t ++ ", " ++ show idx ++ ");\n"
227bcc i (CASE True r [(_, alt)] Nothing)
228 = indent i ++ showCode i alt
229 where
230 showCode :: Int -> [BC] -> String
231 showCode i bc = "{\n" ++ concatMap (bcc (i + 1)) bc ++
232 indent i ++ "}\n"
233bcc i (CASE True r code def)
234 | length code < 6 && length code > 1 = showCase i def code
235 where
236 showCode :: Int -> [BC] -> String
237 showCode i bc = "{\n" ++ concatMap (bcc (i + 1)) bc ++
238 indent i ++ "}\n"
240 showCase :: Int -> Maybe [BC] -> [(Int, [BC])] -> String
241 showCase i Nothing [(t, c)] = indent i ++ showCode i c
242 showCase i (Just def) [] = indent i ++ showCode i def
243 showCase i def ((t, c) : cs)
244 = indent i ++ "if (CTAG(" ++ creg r ++ ") == " ++ show t ++ ") " ++ showCode i c
245 ++ indent i ++ "else\n" ++ showCase i def cs
247bcc i (CASE safe r code def)
248 = indent i ++ "switch(" ++ ctag safe ++ "(" ++ creg r ++ ")) {\n" ++
249 concatMap (showCase i) code ++
250 showDef i def ++
251 indent i ++ "}\n"
252 where
253 ctag True = "CTAG"
254 ctag False = "TAG"
256 showCase i (t, bc) = indent i ++ "case " ++ show t ++ ":\n"
257 ++ concatMap (bcc (i+1)) bc ++ indent (i + 1) ++ "break;\n"
258 showDef i Nothing = ""
259 showDef i (Just c) = indent i ++ "default:\n"
260 ++ concatMap (bcc (i+1)) c ++ indent (i + 1) ++ "break;\n"
261bcc i (CONSTCASE r code def)
262 | intConsts code
263-- = indent i ++ "switch(GETINT(" ++ creg r ++ ")) {\n" ++
264-- concatMap (showCase i) code ++
265-- showDef i def ++
266-- indent i ++ "}\n"
267 = concatMap (iCase (creg r)) code ++
268 indent i ++ "{\n" ++ showDefS i def ++ indent i ++ "}\n"
269 | strConsts code
270 = concatMap (strCase ("GETSTR(" ++ creg r ++ ")")) code ++
271 indent i ++ "{\n" ++ showDefS i def ++ indent i ++ "}\n"
272 | bigintConsts code
273 = concatMap (biCase (creg r)) code ++
274 indent i ++ "{\n" ++ showDefS i def ++ indent i ++ "}\n"
275 | otherwise = error $ "Can't happen: Can't compile const case " ++ show code
276 where
277 intConsts ((I _, _ ) : _) = True
278 intConsts ((Ch _, _ ) : _) = True
279 intConsts ((B8 _, _ ) : _) = True
280 intConsts ((B16 _, _ ) : _) = True
281 intConsts ((B32 _, _ ) : _) = True
282 intConsts ((B64 _, _ ) : _) = True
283 intConsts _ = False
285 bigintConsts ((BI _, _ ) : _) = True
286 bigintConsts _ = False
288 strConsts ((Str _, _ ) : _) = True
289 strConsts _ = False
291 strCase sv (s, bc) =
292 indent i ++ "if (strcmp(" ++ sv ++ ", " ++ show s ++ ") == 0) {\n" ++
293 concatMap (bcc (i+1)) bc ++ indent i ++ "} else\n"
294 biCase bv (BI b, bc) =
295 indent i ++ "if (bigEqConst(" ++ bv ++ ", " ++ show b ++ ")) {\n"
296 ++ concatMap (bcc (i+1)) bc ++ indent i ++ "} else\n"
297 iCase v (I b, bc) =
298 indent i ++ "if (GETINT(" ++ v ++ ") == " ++ show b ++ ") {\n"
299 ++ concatMap (bcc (i+1)) bc ++ indent i ++ "} else\n"
300 iCase v (Ch b, bc) =
301 indent i ++ "if (GETINT(" ++ v ++ ") == " ++ show (fromEnum b) ++ ") {\n"
302 ++ concatMap (bcc (i+1)) bc ++ indent i ++ "} else\n"
303 iCase v (B8 w, bc) =
304 indent i ++ "if (GETBITS8(" ++ v ++ ") == " ++ show (fromEnum w) ++ ") {\n"
305 ++ concatMap (bcc (i+1)) bc ++ indent i ++ "} else\n"
306 iCase v (B16 w, bc) =
307 indent i ++ "if (GETBITS16(" ++ v ++ ") == " ++ show (fromEnum w) ++ ") {\n"
308 ++ concatMap (bcc (i+1)) bc ++ indent i ++ "} else\n"
309 iCase v (B32 w, bc) =
310 indent i ++ "if (GETBITS32(" ++ v ++ ") == " ++ show (fromEnum w) ++ ") {\n"
311 ++ concatMap (bcc (i+1)) bc ++ indent i ++ "} else\n"
312 iCase v (B64 w, bc) =
313 indent i ++ "if (GETBITS64(" ++ v ++ ") == " ++ show (fromEnum w) ++ ") {\n"
314 ++ concatMap (bcc (i+1)) bc ++ indent i ++ "} else\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 ('#':name)) [])
331 = indent i ++
332 c_irts (toFType rty) (creg l ++ " = ") name ++ ";\n"
333bcc i (FOREIGNCALL l rty (FStr fn@('&':name)) [])
334 = indent i ++
335 c_irts (toFType rty) (creg l ++ " = ") fn ++ ";\n"
336bcc i (FOREIGNCALL l rty (FStr fn) (x:xs)) | fn == "%wrapper"
337 = indent i ++
338 c_irts (toFType rty) (creg l ++ " = ")
339 ("_idris_get_wrapper(" ++ creg (snd x) ++ ")") ++ ";\n"
340bcc i (FOREIGNCALL l rty (FStr fn) (x:xs)) | fn == "%dynamic"
341 = indent i ++ c_irts (toFType rty) (creg l ++ " = ")
342 ("(*(" ++ cFnSig "" rty xs ++ ") GETPTR(" ++ creg (snd x) ++ "))" ++
343 "(" ++ showSep "," (map fcall xs) ++ ")") ++ ";\n"
344bcc i (FOREIGNCALL l rty (FStr fn) args)
345 = indent i ++
346 c_irts (toFType rty) (creg l ++ " = ")
347 (fn ++ "(" ++ showSep "," (map fcall args) ++ ")") ++ ";\n"
348bcc i (FOREIGNCALL l rty _ args) = error "Foreign Function calls cannot be partially applied, without being inlined."
349bcc i (NULL r) = indent i ++ creg r ++ " = NULL;\n" -- clear, so it'll be GCed
350bcc i (ERROR str) = indent i ++ "fprintf(stderr, " ++ show str ++ "); fprintf(stderr, \"\\n\"); exit(-1);\n"
351-- bcc i c = error (show c) -- indent i ++ "// not done yet\n"
353fcall (t, arg) = irts_c (toFType t) (creg arg)
354-- Deconstruct the Foreign type in the defunctionalised expression and build
355-- a foreign type description for c_irts and irts_c
356toAType (FCon i)
357 | i == sUN "C_IntChar" = ATInt ITChar
358 | i == sUN "C_IntNative" = ATInt ITNative
359 | i == sUN "C_IntBits8" = ATInt (ITFixed IT8)
360 | i == sUN "C_IntBits16" = ATInt (ITFixed IT16)
361 | i == sUN "C_IntBits32" = ATInt (ITFixed IT32)
362 | i == sUN "C_IntBits64" = ATInt (ITFixed IT64)
363toAType t = error (show t ++ " not defined in toAType")
365toFType (FCon c)
366 | c == sUN "C_Str" = FString
367 | c == sUN "C_Float" = FArith ATFloat
368 | c == sUN "C_Ptr" = FPtr
369 | c == sUN "C_MPtr" = FManagedPtr
370 | c == sUN "C_CData" = FCData
371 | c == sUN "C_Unit" = FUnit
372toFType (FApp c [_,ity])
373 | c == sUN "C_IntT" = FArith (toAType ity)
374 | c == sUN "C_FnT" = toFunType ity
375toFType (FApp c [_])
376 | c == sUN "C_Any" = FAny
377toFType t = FAny
379toFunType (FApp c [_,ity])
380 | c == sUN "C_FnBase" = FFunction
381 | c == sUN "C_FnIO" = FFunctionIO
382toFunType (FApp c [_,_,_,ity])
383 | c == sUN "C_Fn" = toFunType ity
384toFunType _ = FAny
386c_irts (FArith (ATInt ITNative)) l x = l ++ "MKINT((i_int)(" ++ x ++ "))"
387c_irts (FArith (ATInt ITChar)) l x = c_irts (FArith (ATInt ITNative)) l x
388c_irts (FArith (ATInt (ITFixed ity))) l x
389 = l ++ "idris_b" ++ show (nativeTyWidth ity) ++ "const(vm, " ++ x ++ ")"
390c_irts FString l x = l ++ "MKSTR(vm, " ++ x ++ ")"
391c_irts FUnit l x = x
392c_irts FPtr l x = l ++ "MKPTR(vm, " ++ x ++ ")"
393c_irts FManagedPtr l x = l ++ "MKMPTR(vm, " ++ x ++ ")"
394c_irts (FArith ATFloat) l x = l ++ "MKFLOAT(vm, " ++ x ++ ")"
395c_irts FCData l x = l ++ "MKCDATA(vm, " ++ x ++ ")"
396c_irts FAny l x = l ++ x
397c_irts FFunction l x = error "Return of function from foreign call is not supported"
398c_irts FFunctionIO l x = error "Return of function from foreign call is not supported"
400irts_c (FArith (ATInt ITNative)) x = "GETINT(" ++ x ++ ")"
401irts_c (FArith (ATInt ITChar)) x = irts_c (FArith (ATInt ITNative)) x
402irts_c (FArith (ATInt (ITFixed ity))) x
403 = "GETBITS" ++ show (nativeTyWidth ity) ++ "(" ++ x ++ ")"
404irts_c FString x = "GETSTR(" ++ x ++ ")"
405irts_c FUnit x = x
406irts_c FPtr x = "GETPTR(" ++ x ++ ")"
407irts_c FManagedPtr x = "GETMPTR(" ++ x ++ ")"
408irts_c (FArith ATFloat) x = "GETFLOAT(" ++ x ++ ")"
409irts_c FCData x = "GETCDATA(" ++ x ++ ")"
410irts_c FAny x = x
411irts_c FFunctionIO x = wrapped x
412irts_c FFunction x = wrapped x
414cFnSig name rty [] = ctype rty ++ " (*" ++ name ++ ")(void) "
415cFnSig name rty args = ctype rty ++ " (*" ++ name ++ ")("
416 ++ showSep "," (map (ctype . fst) args) ++ ") "
418wrapped x = "_idris_get_wrapper(" ++ x ++ ")"
420bitOp v op ty args = v ++ "idris_b" ++ show (nativeTyWidth ty) ++ op ++ "(vm, " ++ intercalate ", " (map creg args) ++ ")"
422bitCoerce v op input output arg
423 = v ++ "idris_b" ++ show (nativeTyWidth input) ++ op ++ show (nativeTyWidth output) ++ "(vm, " ++ creg arg ++ ")"
425signedTy :: NativeTy -> String
426signedTy t = "int" ++ show (nativeTyWidth t) ++ "_t"
428doOp v (LPlus (ATInt ITNative)) [l, r] = v ++ "ADD(" ++ creg l ++ ", " ++ creg r ++ ")"
429doOp v (LMinus (ATInt ITNative)) [l, r] = v ++ "INTOP(-," ++ creg l ++ ", " ++ creg r ++ ")"
430doOp v (LTimes (ATInt ITNative)) [l, r] = v ++ "MULT(" ++ creg l ++ ", " ++ creg r ++ ")"
431doOp v (LUDiv ITNative) [l, r] = v ++ "UINTOP(/," ++ creg l ++ ", " ++ creg r ++ ")"
432doOp v (LSDiv (ATInt ITNative)) [l, r] = v ++ "INTOP(/," ++ creg l ++ ", " ++ creg r ++ ")"
433doOp v (LURem ITNative) [l, r] = v ++ "UINTOP(%," ++ creg l ++ ", " ++ creg r ++ ")"
434doOp v (LSRem (ATInt ITNative)) [l, r] = v ++ "INTOP(%," ++ creg l ++ ", " ++ creg r ++ ")"
435doOp v (LAnd ITNative) [l, r] = v ++ "INTOP(&," ++ creg l ++ ", " ++ creg r ++ ")"
436doOp v (LOr ITNative) [l, r] = v ++ "INTOP(|," ++ creg l ++ ", " ++ creg r ++ ")"
437doOp v (LXOr ITNative) [l, r] = v ++ "INTOP(^," ++ creg l ++ ", " ++ creg r ++ ")"
438doOp v (LSHL ITNative) [l, r] = v ++ "INTOP(<<," ++ creg l ++ ", " ++ creg r ++ ")"
439doOp v (LLSHR ITNative) [l, r] = v ++ "UINTOP(>>," ++ creg l ++ ", " ++ creg r ++ ")"
440doOp v (LASHR ITNative) [l, r] = v ++ "INTOP(>>," ++ creg l ++ ", " ++ creg r ++ ")"
441doOp v (LCompl ITNative) [x] = v ++ "INTOP(~," ++ creg x ++ ")"
442doOp v (LEq (ATInt ITNative)) [l, r] = v ++ "INTOP(==," ++ creg l ++ ", " ++ creg r ++ ")"
443doOp v (LSLt (ATInt ITNative)) [l, r] = v ++ "INTOP(<," ++ creg l ++ ", " ++ creg r ++ ")"
444doOp v (LSLe (ATInt ITNative)) [l, r] = v ++ "INTOP(<=," ++ creg l ++ ", " ++ creg r ++ ")"
445doOp v (LSGt (ATInt ITNative)) [l, r] = v ++ "INTOP(>," ++ creg l ++ ", " ++ creg r ++ ")"
446doOp v (LSGe (ATInt ITNative)) [l, r] = v ++ "INTOP(>=," ++ creg l ++ ", " ++ creg r ++ ")"
447doOp v (LLt ITNative) [l, r] = v ++ "UINTOP(<," ++ creg l ++ ", " ++ creg r ++ ")"
448doOp v (LLe ITNative) [l, r] = v ++ "UINTOP(<=," ++ creg l ++ ", " ++ creg r ++ ")"
449doOp v (LGt ITNative) [l, r] = v ++ "UINTOP(>," ++ creg l ++ ", " ++ creg r ++ ")"
450doOp v (LGe ITNative) [l, r] = v ++ "UINTOP(>=," ++ creg l ++ ", " ++ creg r ++ ")"
452doOp v (LPlus (ATInt ITChar)) [l, r] = doOp v (LPlus (ATInt ITNative)) [l, r]
453doOp v (LMinus (ATInt ITChar)) [l, r] = doOp v (LMinus (ATInt ITNative)) [l, r]
454doOp v (LTimes (ATInt ITChar)) [l, r] = doOp v (LTimes (ATInt ITNative)) [l, r]
455doOp v (LUDiv ITChar) [l, r] = doOp v (LUDiv ITNative) [l, r]
456doOp v (LSDiv (ATInt ITChar)) [l, r] = doOp v (LSDiv (ATInt ITNative)) [l, r]
457doOp v (LURem ITChar) [l, r] = doOp v (LURem ITNative) [l, r]
458doOp v (LSRem (ATInt ITChar)) [l, r] = doOp v (LSRem (ATInt ITNative)) [l, r]
459doOp v (LAnd ITChar) [l, r] = doOp v (LAnd ITNative) [l, r]
460doOp v (LOr ITChar) [l, r] = doOp v (LOr ITNative) [l, r]
461doOp v (LXOr ITChar) [l, r] = doOp v (LXOr ITNative) [l, r]
462doOp v (LSHL ITChar) [l, r] = doOp v (LSHL ITNative) [l, r]
463doOp v (LLSHR ITChar) [l, r] = doOp v (LLSHR ITNative) [l, r]
464doOp v (LASHR ITChar) [l, r] = doOp v (LASHR ITNative) [l, r]
465doOp v (LCompl ITChar) [x] = doOp v (LCompl ITNative) [x]
466doOp v (LEq (ATInt ITChar)) [l, r] = doOp v (LEq (ATInt ITNative)) [l, r]
467doOp v (LSLt (ATInt ITChar)) [l, r] = doOp v (LSLt (ATInt ITNative)) [l, r]
468doOp v (LSLe (ATInt ITChar)) [l, r] = doOp v (LSLe (ATInt ITNative)) [l, r]
469doOp v (LSGt (ATInt ITChar)) [l, r] = doOp v (LSGt (ATInt ITNative)) [l, r]
470doOp v (LSGe (ATInt ITChar)) [l, r] = doOp v (LSGe (ATInt ITNative)) [l, r]
471doOp v (LLt ITChar) [l, r] = doOp v (LLt ITNative) [l, r]
472doOp v (LLe ITChar) [l, r] = doOp v (LLe ITNative) [l, r]
473doOp v (LGt ITChar) [l, r] = doOp v (LGt ITNative) [l, r]
474doOp v (LGe ITChar) [l, r] = doOp v (LGe ITNative) [l, r]
476doOp v (LPlus ATFloat) [l, r] = v ++ "FLOATOP(+," ++ creg l ++ ", " ++ creg r ++ ")"
477doOp v (LMinus ATFloat) [l, r] = v ++ "FLOATOP(-," ++ creg l ++ ", " ++ creg r ++ ")"
478doOp v (LTimes ATFloat) [l, r] = v ++ "FLOATOP(*," ++ creg l ++ ", " ++ creg r ++ ")"
479doOp v (LSDiv ATFloat) [l, r] = v ++ "FLOATOP(/," ++ creg l ++ ", " ++ creg r ++ ")"
480doOp v (LEq ATFloat) [l, r] = v ++ "FLOATBOP(==," ++ creg l ++ ", " ++ creg r ++ ")"
481doOp v (LSLt ATFloat) [l, r] = v ++ "FLOATBOP(<," ++ creg l ++ ", " ++ creg r ++ ")"
482doOp v (LSLe ATFloat) [l, r] = v ++ "FLOATBOP(<=," ++ creg l ++ ", " ++ creg r ++ ")"
483doOp v (LSGt ATFloat) [l, r] = v ++ "FLOATBOP(>," ++ creg l ++ ", " ++ creg r ++ ")"
484doOp v (LSGe ATFloat) [l, r] = v ++ "FLOATBOP(>=," ++ creg l ++ ", " ++ creg r ++ ")"
486doOp v (LIntFloat ITBig) [x] = v ++ "idris_castBigFloat(vm, " ++ creg x ++ ")"
487doOp v (LFloatInt ITBig) [x] = v ++ "idris_castFloatBig(vm, " ++ creg x ++ ")"
488doOp v (LPlus (ATInt ITBig)) [l, r] = v ++ "idris_bigPlus(vm, " ++ creg l ++ ", " ++ creg r ++ ")"
489doOp v (LMinus (ATInt ITBig)) [l, r] = v ++ "idris_bigMinus(vm, " ++ creg l ++ ", " ++ creg r ++ ")"
490doOp v (LTimes (ATInt ITBig)) [l, r] = v ++ "idris_bigTimes(vm, " ++ creg l ++ ", " ++ creg r ++ ")"
491doOp v (LSDiv (ATInt ITBig)) [l, r] = v ++ "idris_bigDivide(vm, " ++ creg l ++ ", " ++ creg r ++ ")"
492doOp v (LSRem (ATInt ITBig)) [l, r] = v ++ "idris_bigMod(vm, " ++ creg l ++ ", " ++ creg r ++ ")"
493doOp v (LAnd ITBig) [l, r] = v ++ "idris_bigAnd(vm, " ++ creg l ++ ", " ++ creg r ++ ")"
494doOp v (LOr ITBig) [l, r] = v ++ "idris_bigOr(vm, " ++ creg l ++ ", " ++ creg r ++ ")"
495doOp v (LSHL ITBig) [l, r] = v ++ "idris_bigShiftLeft(vm, " ++ creg l ++ ", " ++ creg r ++ ")"
496doOp v (LLSHR ITBig) [l, r] = v ++ "idris_bigLShiftRight(vm, " ++ creg l ++ ", " ++ creg r ++ ")"
497doOp v (LASHR ITBig) [l, r] = v ++ "idris_bigAShiftRight(vm, " ++ creg l ++ ", " ++ creg r ++ ")"
498doOp v (LEq (ATInt ITBig)) [l, r] = v ++ "idris_bigEq(vm, " ++ creg l ++ ", " ++ creg r ++ ")"
499doOp v (LSLt (ATInt ITBig)) [l, r] = v ++ "idris_bigLt(vm, " ++ creg l ++ ", " ++ creg r ++ ")"
500doOp v (LSLe (ATInt ITBig)) [l, r] = v ++ "idris_bigLe(vm, " ++ creg l ++ ", " ++ creg r ++ ")"
501doOp v (LSGt (ATInt ITBig)) [l, r] = v ++ "idris_bigGt(vm, " ++ creg l ++ ", " ++ creg r ++ ")"
502doOp v (LSGe (ATInt ITBig)) [l, r] = v ++ "idris_bigGe(vm, " ++ creg l ++ ", " ++ creg r ++ ")"
504doOp v (LIntFloat ITNative) [x] = v ++ "idris_castIntFloat(" ++ creg x ++ ")"
505doOp v (LFloatInt ITNative) [x] = v ++ "idris_castFloatInt(" ++ creg x ++ ")"
506doOp v (LSExt ITNative ITBig) [x] = v ++ "idris_castIntBig(vm, " ++ creg x ++ ")"
507doOp v (LTrunc ITBig ITNative) [x] = v ++ "idris_castBigInt(vm, " ++ creg x ++ ")"
508doOp v (LStrInt ITBig) [x] = v ++ "idris_castStrBig(vm, " ++ creg x ++ ")"
509doOp v (LIntStr ITBig) [x] = v ++ "idris_castBigStr(vm, " ++ creg x ++ ")"
510doOp v (LIntStr ITNative) [x] = v ++ "idris_castIntStr(vm, " ++ creg x ++ ")"
511doOp v (LStrInt ITNative) [x] = v ++ "idris_castStrInt(vm, " ++ creg x ++ ")"
512doOp v (LIntStr (ITFixed _)) [x] = v ++ "idris_castBitsStr(vm, " ++ creg x ++ ")"
513doOp v LFloatStr [x] = v ++ "idris_castFloatStr(vm, " ++ creg x ++ ")"
514doOp v LStrFloat [x] = v ++ "idris_castStrFloat(vm, " ++ creg x ++ ")"
516doOp v (LSLt (ATInt (ITFixed ty))) [x, y] = bitOp v "SLt" ty [x, y]
517doOp v (LSLe (ATInt (ITFixed ty))) [x, y] = bitOp v "SLte" ty [x, y]
518doOp v (LEq (ATInt (ITFixed ty))) [x, y] = bitOp v "Eq" ty [x, y]
519doOp v (LSGe (ATInt (ITFixed ty))) [x, y] = bitOp v "SGte" ty [x, y]
520doOp v (LSGt (ATInt (ITFixed ty))) [x, y] = bitOp v "SGt" ty [x, y]
521doOp v (LLt (ITFixed ty)) [x, y] = bitOp v "Lt" ty [x, y]
522doOp v (LLe (ITFixed ty)) [x, y] = bitOp v "Lte" ty [x, y]
523doOp v (LGe (ITFixed ty)) [x, y] = bitOp v "Gte" ty [x, y]
524doOp v (LGt (ITFixed ty)) [x, y] = bitOp v "Gt" ty [x, y]
526doOp v (LSHL (ITFixed ty)) [x, y] = bitOp v "Shl" ty [x, y]
527doOp v (LLSHR (ITFixed ty)) [x, y] = bitOp v "LShr" ty [x, y]
528doOp v (LASHR (ITFixed ty)) [x, y] = bitOp v "AShr" ty [x, y]
529doOp v (LAnd (ITFixed ty)) [x, y] = bitOp v "And" ty [x, y]
530doOp v (LOr (ITFixed ty)) [x, y] = bitOp v "Or" ty [x, y]
531doOp v (LXOr (ITFixed ty)) [x, y] = bitOp v "Xor" ty [x, y]
532doOp v (LCompl (ITFixed ty)) [x] = bitOp v "Compl" ty [x]
534doOp v (LPlus (ATInt (ITFixed ty))) [x, y] = bitOp v "Plus" ty [x, y]
535doOp v (LMinus (ATInt (ITFixed ty))) [x, y] = bitOp v "Minus" ty [x, y]
536doOp v (LTimes (ATInt (ITFixed ty))) [x, y] = bitOp v "Times" ty [x, y]
537doOp v (LUDiv (ITFixed ty)) [x, y] = bitOp v "UDiv" ty [x, y]
538doOp v (LSDiv (ATInt (ITFixed ty))) [x, y] = bitOp v "SDiv" ty [x, y]
539doOp v (LURem (ITFixed ty)) [x, y] = bitOp v "URem" ty [x, y]
540doOp v (LSRem (ATInt (ITFixed ty))) [x, y] = bitOp v "SRem" ty [x, y]
542doOp v (LSExt (ITFixed from) ITBig) [x]
543 = v ++ "MKBIGSI(vm, (" ++ signedTy from ++ ") GETBITS" ++ show (nativeTyWidth from) ++ "(" ++ creg x ++ "))"
544doOp v (LSExt ITNative (ITFixed to)) [x]
545 = v ++ "idris_b" ++ show (nativeTyWidth to) ++ "const(vm, GETINT(" ++ creg x ++ "))"
546doOp v (LSExt ITChar (ITFixed to)) [x]
547 = doOp v (LSExt ITNative (ITFixed to)) [x]
548doOp v (LSExt (ITFixed from) ITNative) [x]
549 = v ++ "MKINT((i_int)((" ++ signedTy from ++ ") GETBITS" ++ show (nativeTyWidth from) ++ "(" ++ creg x ++ ")))"
550doOp v (LSExt (ITFixed from) ITChar) [x]
551 = doOp v (LSExt (ITFixed from) ITNative) [x]
552doOp v (LSExt (ITFixed from) (ITFixed to)) [x]
553 | nativeTyWidth from < nativeTyWidth to = bitCoerce v "S" from to x
554doOp v (LZExt ITNative (ITFixed to)) [x]
555 = v ++ "idris_b" ++ show (nativeTyWidth to) ++ "const(vm, (uintptr_t)GETINT(" ++ creg x ++ "))"
556doOp v (LZExt ITChar (ITFixed to)) [x]
557 = doOp v (LZExt ITNative (ITFixed to)) [x]
558doOp v (LZExt (ITFixed from) ITNative) [x]
559 = v ++ "MKINT((i_int)GETBITS" ++ show (nativeTyWidth from) ++ "(" ++ creg x ++ "))"
560doOp v (LZExt (ITFixed from) ITChar) [x]
561 = doOp v (LZExt (ITFixed from) ITNative) [x]
562doOp v (LZExt (ITFixed from) ITBig) [x]
563 = v ++ "MKBIGUI(vm, GETBITS" ++ show (nativeTyWidth from) ++ "(" ++ creg x ++ "))"
564doOp v (LZExt ITNative ITBig) [x]
565 = v ++ "MKBIGUI(vm, (uintptr_t)GETINT(" ++ creg x ++ "))"
566doOp v (LZExt (ITFixed from) (ITFixed to)) [x]
567 | nativeTyWidth from < nativeTyWidth to = bitCoerce v "Z" from to x
568doOp v (LTrunc ITNative (ITFixed to)) [x]
569 = v ++ "idris_b" ++ show (nativeTyWidth to) ++ "const(vm, GETINT(" ++ creg x ++ "))"
570doOp v (LTrunc ITChar (ITFixed to)) [x]
571 = doOp v (LTrunc ITNative (ITFixed to)) [x]
572doOp v (LTrunc (ITFixed from) ITNative) [x]
573 = v ++ "MKINT((i_int)GETBITS" ++ show (nativeTyWidth from) ++ "(" ++ creg x ++ "))"
574doOp v (LTrunc (ITFixed from) ITChar) [x]
575 = doOp v (LTrunc (ITFixed from) ITNative) [x]
576doOp v (LTrunc ITBig (ITFixed IT64)) [x]
577 = v ++ "idris_b64const(vm, ISINT(" ++ creg x ++ ") ? GETINT(" ++ creg x ++ ") : idris_truncBigB64(GETMPZ(" ++ creg x ++ ")))"
578doOp v (LTrunc ITBig (ITFixed to)) [x]
579 = v ++ "idris_b" ++ show (nativeTyWidth to) ++ "const(vm, ISINT(" ++ creg x ++ ") ? GETINT(" ++ creg x ++ ") : mpz_get_ui(GETMPZ(" ++ creg x ++ ")))"
580doOp v (LTrunc (ITFixed from) (ITFixed to)) [x]
581 | nativeTyWidth from > nativeTyWidth to = bitCoerce v "T" from to x
583doOp v LFExp [x] = v ++ flUnOp "exp" (creg x)
584doOp v LFLog [x] = v ++ flUnOp "log" (creg x)
585doOp v LFSin [x] = v ++ flUnOp "sin" (creg x)
586doOp v LFCos [x] = v ++ flUnOp "cos" (creg x)
587doOp v LFTan [x] = v ++ flUnOp "tan" (creg x)
588doOp v LFASin [x] = v ++ flUnOp "asin" (creg x)
589doOp v LFACos [x] = v ++ flUnOp "acos" (creg x)
590doOp v LFATan [x] = v ++ flUnOp "atan" (creg x)
591doOp v LFSqrt [x] = v ++ flUnOp "sqrt" (creg x)
592doOp v LFFloor [x] = v ++ flUnOp "floor" (creg x)
593doOp v LFCeil [x] = v ++ flUnOp "ceil" (creg x)
594doOp v LFNegate [x] = v ++ "MKFLOAT(vm, -GETFLOAT(" ++ (creg x) ++ "))"
595doOp v LFATan2 [y, x] = v ++ "MKFLOAT(vm, atan2(GETFLOAT(" ++ creg y ++ "), GETFLOAT(" ++ creg x ++ ")))"
597-- String functions which don't need to know we're UTF8
598doOp v LStrConcat [l,r] = v ++ "idris_concat(vm, " ++ creg l ++ ", " ++ creg r ++ ")"
599doOp v LStrLt [l,r] = v ++ "idris_strlt(vm, " ++ creg l ++ ", " ++ creg r ++ ")"
600doOp v LStrEq [l,r] = v ++ "idris_streq(vm, " ++ creg l ++ ", " ++ creg r ++ ")"
602doOp v LReadStr [_] = v ++ "idris_readStr(vm, stdin)"
603doOp v LWriteStr [_,s]
604 = v ++ "MKINT((i_int)(idris_writeStr(stdout"
605 ++ ",GETSTR("
606 ++ creg s ++ "))))"
609-- String functions which need to know we're UTF8
610doOp v LStrHead [x] = v ++ "idris_strHead(vm, " ++ creg x ++ ")"
611doOp v LStrTail [x] = v ++ "idris_strTail(vm, " ++ creg x ++ ")"
612doOp v LStrCons [x, y] = v ++ "idris_strCons(vm, " ++ creg x ++ "," ++ creg y ++ ")"
613doOp v LStrIndex [x, y] = v ++ "idris_strIndex(vm, " ++ creg x ++ "," ++ creg y ++ ")"
614doOp v LStrRev [x] = v ++ "idris_strRev(vm, " ++ creg x ++ ")"
615doOp v LStrLen [x] = v ++ "idris_strlen(vm, " ++ creg x ++ ")"
616doOp v LStrSubstr [x,y,z] = v ++ "idris_substr(vm, " ++ creg x ++ "," ++ creg y ++ "," ++ creg z ++ ")"
618doOp v LFork [x] = v ++ "MKPTR(vm, vmThread(vm, " ++ cname (sMN 0 "EVAL") ++ ", " ++ creg x ++ "))"
619doOp v LPar [x] = v ++ creg x -- "MKPTR(vm, vmThread(vm, " ++ cname (MN 0 "EVAL") ++ ", " ++ creg x ++ "))"
620doOp v (LChInt ITNative) args = v ++ creg (last args)
621doOp v (LChInt ITChar) args = doOp v (LChInt ITNative) args
622doOp v (LIntCh ITNative) args = v ++ creg (last args)
623doOp v (LIntCh ITChar) args = doOp v (LIntCh ITNative) args
625doOp v LSystemInfo [x] = v ++ "idris_systemInfo(vm, " ++ creg x ++ ")"
626doOp v LCrash [x] = "idris_crash(GETSTR(" ++ creg x ++ "))"
627doOp v LNoOp args = v ++ creg (last args)
629-- Pointer primitives (declared as %extern in Builtins.idr)
630doOp v (LExternal rf) [_,x]
631 | rf == sUN "prim__readFile"
632 = v ++ "idris_readStr(vm, GETPTR(" ++ creg x ++ "))"
633doOp v (LExternal rf) [_,len,x]
634 | rf == sUN "prim__readChars"
635 = v ++ "idris_readChars(vm, GETINT(" ++ creg len ++
636 "), GETPTR(" ++ creg x ++ "))"
637doOp v (LExternal wf) [_,x,s]
638 | wf == sUN "prim__writeFile"
639 = v ++ "MKINT((i_int)(idris_writeStr(GETPTR(" ++ creg x
640 ++ "),GETSTR("
641 ++ creg s ++ "))))"
642doOp v (LExternal si) [] | si == sUN "prim__stdin" = v ++ "MKPTR(vm, stdin)"
643doOp v (LExternal so) [] | so == sUN "prim__stdout" = v ++ "MKPTR(vm, stdout)"
644doOp v (LExternal se) [] | se == sUN "prim__stderr" = v ++ "MKPTR(vm, stderr)"
646doOp v (LExternal vm) [_] | vm == sUN "prim__vm" = v ++ "MKPTR(vm, vm)"
647doOp v (LExternal nul) [] | nul == sUN "prim__null" = v ++ "MKPTR(vm, NULL)"
648doOp v (LExternal eqp) [x, y] | eqp == sUN "prim__eqPtr"
649 = v ++ "MKINT((i_int)(GETPTR(" ++ creg x ++ ") == GETPTR(" ++ creg y ++ ")))"
650doOp v (LExternal eqp) [x, y] | eqp == sUN "prim__eqManagedPtr"
651 = v ++ "MKINT((i_int)(GETMPTR(" ++ creg x ++ ") == GETMPTR(" ++ creg y ++ ")))"
652doOp v (LExternal rp) [p, i] | rp == sUN "prim__registerPtr"
653 = v ++ "MKMPTR(vm, GETPTR(" ++ creg p ++ "), GETINT(" ++ creg i ++ "))"
654doOp v (LExternal pk) [_, p, o] | pk == sUN "prim__peek8"
655 = v ++ "idris_peekB8(vm," ++ creg p ++ "," ++ creg o ++")"
656doOp v (LExternal pk) [_, p, o, x] | pk == sUN "prim__poke8"
657 = v ++ "idris_pokeB8(" ++ creg p ++ "," ++ creg o ++ "," ++ creg x ++ ")"
658doOp v (LExternal pk) [_, p, o] | pk == sUN "prim__peek16"
659 = v ++ "idris_peekB16(vm," ++ creg p ++ "," ++ creg o ++")"
660doOp v (LExternal pk) [_, p, o, x] | pk == sUN "prim__poke16"
661 = v ++ "idris_pokeB16(" ++ creg p ++ "," ++ creg o ++ "," ++ creg x ++ ")"
662doOp v (LExternal pk) [_, p, o] | pk == sUN "prim__peek32"
663 = v ++ "idris_peekB32(vm," ++ creg p ++ "," ++ creg o ++")"
664doOp v (LExternal pk) [_, p, o, x] | pk == sUN "prim__poke32"
665 = v ++ "idris_pokeB32(" ++ creg p ++ "," ++ creg o ++ "," ++ creg x ++ ")"
666doOp v (LExternal pk) [_, p, o] | pk == sUN "prim__peek64"
667 = v ++ "idris_peekB64(vm," ++ creg p ++ "," ++ creg o ++")"
668doOp v (LExternal pk) [_, p, o, x] | pk == sUN "prim__poke64"
669 = v ++ "idris_pokeB64(" ++ creg p ++ "," ++ creg o ++ "," ++ creg x ++ ")"
670doOp v (LExternal pk) [_, p, o] | pk == sUN "prim__peekPtr"
671 = v ++ "idris_peekPtr(vm," ++ creg p ++ "," ++ creg o ++")"
672doOp v (LExternal pk) [_, p, o, x] | pk == sUN "prim__pokePtr"
673 = v ++ "idris_pokePtr(" ++ creg p ++ "," ++ creg o ++ "," ++ creg x ++ ")"
674doOp v (LExternal pk) [_, p, o, x] | pk == sUN "prim__pokeDouble"
675 = v ++ "idris_pokeDouble(" ++ creg p ++ "," ++ creg o ++ "," ++ creg x ++ ")"
676doOp v (LExternal pk) [_, p, o] | pk == sUN "prim__peekDouble"
677 = v ++ "idris_peekDouble(vm," ++ creg p ++ "," ++ creg o ++")"
678doOp v (LExternal pk) [_, p, o, x] | pk == sUN "prim__pokeSingle"
679 = v ++ "idris_pokeSingle(" ++ creg p ++ "," ++ creg o ++ "," ++ creg x ++ ")"
680doOp v (LExternal pk) [_, p, o] | pk == sUN "prim__peekSingle"
681 = v ++ "idris_peekSingle(vm," ++ creg p ++ "," ++ creg o ++")"
682doOp v (LExternal pk) [] | pk == sUN "prim__sizeofPtr"
683 = v ++ "MKINT(sizeof(void*))"
684doOp v (LExternal mpt) [p] | mpt == sUN "prim__asPtr"
685 = v ++ "MKPTR(vm, GETMPTR("++ creg p ++"))"
686doOp v (LExternal offs) [p, n] | offs == sUN "prim__ptrOffset"
687 = v ++ "MKPTR(vm, (void *)((char *)GETPTR(" ++ creg p ++ ") + GETINT(" ++ creg n ++ ")))"
688doOp _ op args = error $ "doOp not implemented (" ++ show (op, args) ++ ")"
691flUnOp :: String -> String -> String
692flUnOp name val = "MKFLOAT(vm, " ++ name ++ "(GETFLOAT(" ++ val ++ ")))"
694-------------------- Interface file generation
696-- First, the wrappers in the C file
698ifaceC :: Export -> String
699ifaceC (ExportData n) = "typedef VAL " ++ cdesc n ++ ";\n"
700ifaceC (ExportFun n cn ret args)
701 = ctype ret ++ " " ++ cdesc cn ++
702 "(VM* vm" ++ showArgs (zip argNames args) ++ ") {\n"
703 ++ mkBody n (zip argNames args) ret ++ "}\n\n"
704 where showArgs [] = ""
705 showArgs ((n, t) : ts) = ", " ++ ctype t ++ " " ++ n ++
706 showArgs ts
708 argNames = zipWith (++) (repeat "arg") (map show [0..])
710mkBody n as_in t
711 = indent 1 ++ "INITFRAME;\n" ++
712 indent 1 ++ "RESERVE(" ++ show (max (length as) 3) ++ ");\n" ++
713 push 0 as ++ call n ++ retval t
714 where
715 as = case t of
716 FIO t -> as_in ++ [("NULL", FUnknown)] -- add world token
717 _ -> as_in
718 push i [] = ""
719 push i ((n, t) : ts) = indent 1 ++ c_irts (toFType t)
720 ("TOP(" ++ show i ++ ") = ") n
721 ++ ";\n" ++ push (i + 1) ts
723 call _ = indent 1 ++ "STOREOLD;\n" ++
724 indent 1 ++ "BASETOP(0);\n" ++
725 indent 1 ++ "ADDTOP(" ++ show (length as) ++ ");\n" ++
726 indent 1 ++ "CALL(" ++ cname n ++ ");\n"
728 retval (FIO t) = retval t
729 retval t = indent 1 ++ "return " ++ irts_c (toFType t) "RVAL" ++ ";\n"
731ctype (FCon c)
732 | c == sUN "C_Str" = "char*"
733 | c == sUN "C_Float" = "float"
734 | c == sUN "C_Ptr" = "void*"
735 | c == sUN "C_MPtr" = "void*"
736 | c == sUN "C_Unit" = "void"
737ctype (FApp c [_,ity])
738 | c == sUN "C_IntT" = carith ity
739ctype (FApp c [_])
740 | c == sUN "C_Any" = "VAL"
741ctype (FStr s) = s
742ctype FUnknown = "void*"
743ctype (FIO t) = ctype t
744ctype t = error "Can't happen: Not a valid interface type " ++ show t
746carith (FCon i)
747 | i == sUN "C_IntChar" = "char"
748 | i == sUN "C_IntNative" = "int"
749 | i == sUN "C_IntBits8" = "uint8_t"
750 | i == sUN "C_IntBits16" = "uint16_t"
751 | i == sUN "C_IntBits32" = "uint32_t"
752 | i == sUN "C_IntBits64" = "uint64_t"
753carith t = error $ "Can't happen: Not an exportable arithmetic type " ++ show t
755cdesc (FStr s) = s
756cdesc s = error "Can't happen: Not a valid C name"
758-- Then, the header files
760codegenH :: [ExportIFace] -> IO ()
761codegenH es = mapM_ writeIFace es
763writeIFace :: ExportIFace -> IO ()
764writeIFace (Export ffic hdr exps)
765 | ffic == sNS (sUN "FFI_C") ["FFI_C"]
766 = do let hfile = "#ifndef " ++ hdr_guard hdr ++ "\n" ++
767 "#define " ++ hdr_guard hdr ++ "\n\n" ++
768 "#include <idris_rts.h>\n\n" ++
769 concatMap hdr_export exps ++ "\n" ++
770 "#endif\n\n"
771 writeFile hdr hfile
772 | otherwise = return ()
774hdr_guard x = "__" ++ map hchar x
775 where hchar x | isAlphaNum x = toUpper x
776 hchar _ = '_'
778hdr_export :: Export -> String
779hdr_export (ExportData n) = "typedef VAL " ++ cdesc n ++ ";\n"
780hdr_export (ExportFun n cn ret args)
781 = ctype ret ++ " " ++ cdesc cn ++
782 "(VM* vm" ++ showArgs (zip argNames args) ++ ");\n"
783 where showArgs [] = ""
784 showArgs ((n, t) : ts) = ", " ++ ctype t ++ " " ++ n ++
785 showArgs ts
787 argNames = zipWith (++) (repeat "arg") (map show [0..])
789------------------ Callback wrapper generation ----------------
790-- Generate callback wrappers and a function to select the
791-- correct wrapper function to pass.
792-- TODO: This is limited to functions that are specified in
793-- the foreign call. Otherwise we would have to generate wrappers for all
794-- functions with correct arity or do flow analysis
795-- to find all possible inputs to the foreign call.
796genWrappers :: [(Name, [BC])] -> String
797genWrappers bcs = let
798 tags = nubBy (\x y -> snd x == snd y) $ concatMap (getCallback . snd) bcs
799 in
800 case tags of
801 [] -> ""
802 t -> concatMap genWrapper t ++ genDispatcher t
804genDispatcher :: [(FDesc, Int)] -> String
805genDispatcher tags = "void* _idris_get_wrapper(VAL con)\n" ++
806 "{\n" ++
807 indent 1 ++ "switch(TAG(con)) {\n" ++
808 concatMap makeSwitch tags ++
809 indent 1 ++ "}\n" ++
810 indent 1 ++ "fprintf(stderr, \"No wrapper for callback\");\n" ++
811 indent 1 ++ "exit(-1);\n" ++
812 "}\n\n"
813 where
814 makeSwitch (_, tag) =
815 indent 1 ++ "case " ++ show tag ++ ":\n" ++
816 indent 2 ++ "return (void*) &" ++ wrapperName tag ++ ";\n"
818genWrapper :: (FDesc, Int) -> String
819genWrapper (desc, tag) | (toFType desc) == FFunctionIO =
820 error "Cannot create C callbacks for IO functions, wrap them with unsafePerformIO.\n"
821genWrapper (desc, tag) = ret ++ " " ++ wrapperName tag ++ "(" ++
822 renderArgs argList ++")\n" ++
823 "{\n" ++
824 (if ret /= "void" then indent 1 ++ ret ++ " ret;\n" else "") ++
825 indent 1 ++ "VM* vm = get_vm();\n" ++
826 indent 1 ++ "if (vm == NULL) {\n" ++
827 indent 2 ++ "vm = idris_vm();\n" ++
828 indent 1 ++ "}\n" ++
829 indent 1 ++ "INITFRAME;\n" ++
830 indent 1 ++ "RESERVE(" ++ show (len + 1) ++ ");\n" ++
831 indent 1 ++ "allocCon(REG1, vm, " ++ show tag ++ ",0 , 0);\n" ++
832 indent 1 ++ "TOP(0) = REG1;\n" ++
833 applyArgs argList ++
834 if ret /= "void"
835 then indent 1 ++ "ret = " ++ irts_c (toFType ft) "RVAL" ++ ";\n"
836 ++ indent 1 ++ "return ret;\n}\n\n"
837 else "}\n\n"
838 where
839 (ret, ft) = rty desc
840 argList = zip (args desc) [0..]
841 len = length argList
843 applyArgs (x:y:xs) = push 1 [x] ++
844 indent 1 ++ "STOREOLD;\n" ++
845 indent 1 ++ "BASETOP(0);\n" ++
846 indent 1 ++ "ADDTOP(2);\n" ++
847 indent 1 ++ "CALL(_idris__123_APPLY_95_0_125_);\n" ++
848 indent 1 ++ "TOP(0)=REG1;\n" ++
849 applyArgs (y:xs)
850 applyArgs x = push 1 x ++
851 indent 1 ++ "STOREOLD;\n" ++
852 indent 1 ++ "BASETOP(0);\n" ++
853 indent 1 ++ "ADDTOP(" ++ show (length x + 1) ++ ");\n" ++
854 indent 1 ++ "CALL(_idris__123_APPLY_95_0_125_);\n"
855 renderArgs [] = "void"
856 renderArgs [((s, _), n)] = s ++ " a" ++ (show n)
857 renderArgs (((s, _), n):xs) = s ++ " a" ++ (show n) ++ ", " ++
858 renderArgs xs
859 rty (FApp c [_,ty])
860 | c == sUN "C_FnBase" = (ctype ty, ty)
861 | c == sUN "C_FnIO" = (ctype ty, ty)
862 | c == sUN "C_FnT" = rty ty
863 rty (FApp c [_,_,ty,fn])
864 | c == sUN "C_Fn" = rty fn
865 rty x = ("", x)
866 args (FApp c [_,ty])
867 | c == sUN "C_FnBase" = []
868 | c == sUN "C_FnIO" = []
869 | c == sUN "C_FnT" = args ty
870 args (FApp c [_,_,ty,fn])
871 | toFType ty == FUnit = []
872 | c == sUN "C_Fn" = (ctype ty, ty) : args fn
873 args _ = []
874 push i [] = ""
875 push i (((c, t), n) : ts) = indent 1 ++ c_irts (toFType t)
876 ("TOP(" ++ show i ++ ") = ") ("a" ++ show n)
877 ++ ";\n" ++ push (i + 1) ts
879wrapperName :: Int -> String
880wrapperName tag = "_idris_wrapper_" ++ show tag
882getCallback :: [BC] -> [(FDesc, Int)]
883getCallback bc = getCallback' (reverse bc)
884 where
885 getCallback' (x:xs) = case hasCallback x of
886 [] -> getCallback' xs
887 cbs -> case findCons cbs xs of
888 [] -> error "Idris function couldn't be wrapped."
889 x -> x
890 getCallback' [] = []
891 findCons (c:cs) xs = findCon c xs ++ findCons cs xs
892 findCons [] _ = []
893 findCon c ((MKCON l loc tag args):xs) | snd c == l = [(fst c, tag)]
894 findCon c (_:xs) = findCon c xs
895 findCon c [] = []
897hasCallback :: BC -> [(FDesc, Reg)]
898hasCallback (FOREIGNCALL l rty (FStr fn) args) = filter isFn args
899 where
900 isFn (desc,_) = case toFType desc of
901 FFunction -> True
902 FFunctionIO -> True
903 _ -> False
904hasCallback _ = []