on 79351ee help sign in
Idris-dev/src/IRTS/CodegenC.hs
897 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 stackFlag = if isWindows then ["-Wl,--stack,16777216"] else []
83 let args = gccDbg dbg ++
84 gccFlags iface ++
85 -- # Any flags defined here which alter the RTS API must also be added to config.mk
86 ["-DHAS_PTHREAD", "-DIDRIS_ENABLE_STATS",
87 "-I."] ++ objs ++ envFlags ++
88 (if (exec == Executable) then [] else ["-c"]) ++
89 [tmpn] ++
90 (if not iface then libFlags else []) ++
91 incFlags ++
92 (if not iface then libs else []) ++
93 flags ++ stackFlag ++
94 ["-o", out]
95-- putStrLn (show args)
96 exit <- rawSystem comp args
97 when (exit /= ExitSuccess) $
98 putStrLn ("FAILURE: " ++ show comp ++ " " ++ show args)
99 where
100 getExp (Export _ _ exp) = exp
102headers xs =
103 concatMap
104 (\h -> "#include \"" ++ h ++ "\"\n")
105 (xs ++ ["idris_rts.h", "idris_bitstring.h", "idris_stdfgn.h"])
107debug TRACE = "#define IDRIS_TRACE\n\n"
108debug _ = ""
110-- We're using signed integers now. Make sure we get consistent semantics
111-- out of them from gcc. See e.g. http://thiemonagel.de/2010/01/signed-integer-overflow/
112gccFlags i = if i then ["-fwrapv"]
113 else ["-fwrapv", "-fno-strict-overflow"]
115gccDbg DEBUG = ["-g"]
116-- clang optimises sibling calls in O1, but gcc doesn't
117-- on the other hand, O1 compiles significantly faster in clang without
118-- any noticeable performance hit.
119gccDbg TRACE = ["-O1", "-foptimize-sibling-calls"]
120gccDbg _ = ["-O1", "-foptimize-sibling-calls"]
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;\n" ++
143 concatMap (bcc 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 :: Int -> BC -> String
180bcc i (ASSIGN l r) = indent i ++ creg l ++ " = " ++ creg r ++ ";\n"
181bcc 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 i (UPDATE l r) = indent i ++ creg l ++ " = " ++ creg r ++ ";\n"
203bcc i (MKCON l loc tag []) | tag < 256
204 = indent i ++ creg l ++ " = NULL_CON(" ++ show tag ++ ");\n"
205bcc 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 i (PROJECT l loc a) = indent i ++ "PROJECT(vm, " ++ creg l ++ ", " ++ show loc ++
220 ", " ++ show a ++ ");\n"
221bcc i (PROJECTINTO r t idx)
222 = indent i ++ creg r ++ " = GETARG(" ++ creg t ++ ", " ++ show idx ++ ");\n"
223bcc i (CASE True r code def)
224 | length code < 4 = showCase i def code
225 where
226 showCode :: Int -> [BC] -> String
227 showCode i bc = "{\n" ++ concatMap (bcc (i + 1)) bc ++
228 indent i ++ "}\n"
230 showCase :: Int -> Maybe [BC] -> [(Int, [BC])] -> String
231 showCase i Nothing [(t, c)] = indent i ++ showCode i c
232 showCase i (Just def) [] = indent i ++ showCode i def
233 showCase i def ((t, c) : cs)
234 = indent i ++ "if (CTAG(" ++ creg r ++ ") == " ++ show t ++ ") " ++ showCode i c
235 ++ indent i ++ "else\n" ++ showCase i def cs
237bcc i (CASE safe r code def)
238 = indent i ++ "switch(" ++ ctag safe ++ "(" ++ creg r ++ ")) {\n" ++
239 concatMap (showCase i) code ++
240 showDef i def ++
241 indent i ++ "}\n"
242 where
243 ctag True = "CTAG"
244 ctag False = "TAG"
246 showCase i (t, bc) = indent i ++ "case " ++ show t ++ ":\n"
247 ++ concatMap (bcc (i+1)) bc ++ indent (i + 1) ++ "break;\n"
248 showDef i Nothing = ""
249 showDef i (Just c) = indent i ++ "default:\n"
250 ++ concatMap (bcc (i+1)) c ++ indent (i + 1) ++ "break;\n"
251bcc i (CONSTCASE r code def)
252 | intConsts code
253-- = indent i ++ "switch(GETINT(" ++ creg r ++ ")) {\n" ++
254-- concatMap (showCase i) code ++
255-- showDef i def ++
256-- indent i ++ "}\n"
257 = concatMap (iCase (creg r)) code ++
258 indent i ++ "{\n" ++ showDefS i def ++ indent i ++ "}\n"
259 | strConsts code
260 = concatMap (strCase ("GETSTR(" ++ creg r ++ ")")) code ++
261 indent i ++ "{\n" ++ showDefS i def ++ indent i ++ "}\n"
262 | bigintConsts code
263 = concatMap (biCase (creg r)) code ++
264 indent i ++ "{\n" ++ showDefS i def ++ indent i ++ "}\n"
265 | otherwise = error $ "Can't happen: Can't compile const case " ++ show code
266 where
267 intConsts ((I _, _ ) : _) = True
268 intConsts ((Ch _, _ ) : _) = True
269 intConsts ((B8 _, _ ) : _) = True
270 intConsts ((B16 _, _ ) : _) = True
271 intConsts ((B32 _, _ ) : _) = True
272 intConsts ((B64 _, _ ) : _) = True
273 intConsts _ = False
275 bigintConsts ((BI _, _ ) : _) = True
276 bigintConsts _ = False
278 strConsts ((Str _, _ ) : _) = True
279 strConsts _ = False
281 strCase sv (s, bc) =
282 indent i ++ "if (strcmp(" ++ sv ++ ", " ++ show s ++ ") == 0) {\n" ++
283 concatMap (bcc (i+1)) bc ++ indent i ++ "} else\n"
284 biCase bv (BI b, bc) =
285 indent i ++ "if (bigEqConst(" ++ bv ++ ", " ++ show b ++ ")) {\n"
286 ++ concatMap (bcc (i+1)) bc ++ indent i ++ "} else\n"
287 iCase v (I b, bc) =
288 indent i ++ "if (GETINT(" ++ v ++ ") == " ++ show b ++ ") {\n"
289 ++ concatMap (bcc (i+1)) bc ++ indent i ++ "} else\n"
290 iCase v (Ch b, bc) =
291 indent i ++ "if (GETINT(" ++ v ++ ") == " ++ show (fromEnum b) ++ ") {\n"
292 ++ concatMap (bcc (i+1)) bc ++ indent i ++ "} else\n"
293 iCase v (B8 w, bc) =
294 indent i ++ "if (GETBITS8(" ++ v ++ ") == " ++ show (fromEnum w) ++ ") {\n"
295 ++ concatMap (bcc (i+1)) bc ++ indent i ++ "} else\n"
296 iCase v (B16 w, bc) =
297 indent i ++ "if (GETBITS16(" ++ v ++ ") == " ++ show (fromEnum w) ++ ") {\n"
298 ++ concatMap (bcc (i+1)) bc ++ indent i ++ "} else\n"
299 iCase v (B32 w, bc) =
300 indent i ++ "if (GETBITS32(" ++ v ++ ") == " ++ show (fromEnum w) ++ ") {\n"
301 ++ concatMap (bcc (i+1)) bc ++ indent i ++ "} else\n"
302 iCase v (B64 w, bc) =
303 indent i ++ "if (GETBITS64(" ++ v ++ ") == " ++ show (fromEnum w) ++ ") {\n"
304 ++ concatMap (bcc (i+1)) bc ++ indent i ++ "} else\n"
305 showDefS i Nothing = ""
306 showDefS i (Just c) = concatMap (bcc (i+1)) c
308bcc i (CALL n) = indent i ++ "CALL(" ++ cname n ++ ");\n"
309bcc i (TAILCALL n) = indent i ++ "TAILCALL(" ++ cname n ++ ");\n"
310bcc i (SLIDE n) = indent i ++ "SLIDE(vm, " ++ show n ++ ");\n"
311bcc i REBASE = indent i ++ "REBASE;\n"
312bcc i (RESERVE 0) = ""
313bcc i (RESERVE n) = indent i ++ "RESERVE(" ++ show n ++ ");\n"
314bcc i (ADDTOP 0) = ""
315bcc i (ADDTOP n) = indent i ++ "ADDTOP(" ++ show n ++ ");\n"
316bcc i (TOPBASE n) = indent i ++ "TOPBASE(" ++ show n ++ ");\n"
317bcc i (BASETOP n) = indent i ++ "BASETOP(" ++ show n ++ ");\n"
318bcc i STOREOLD = indent i ++ "STOREOLD;\n"
319bcc i (OP l fn args) = indent i ++ doOp (creg l ++ " = ") fn args ++ ";\n"
320bcc i (FOREIGNCALL l rty (FStr ('#':name)) [])
321 = indent i ++
322 c_irts (toFType rty) (creg l ++ " = ") name ++ ";\n"
323bcc i (FOREIGNCALL l rty (FStr fn@('&':name)) [])
324 = indent i ++
325 c_irts (toFType rty) (creg l ++ " = ") fn ++ ";\n"
326bcc i (FOREIGNCALL l rty (FStr fn) (x:xs)) | fn == "%wrapper"
327 = indent i ++
328 c_irts (toFType rty) (creg l ++ " = ")
329 ("_idris_get_wrapper(" ++ creg (snd x) ++ ")") ++ ";\n"
330bcc i (FOREIGNCALL l rty (FStr fn) (x:xs)) | fn == "%dynamic"
331 = indent i ++ c_irts (toFType rty) (creg l ++ " = ")
332 ("(*(" ++ cFnSig "" rty xs ++ ") GETPTR(" ++ creg (snd x) ++ "))" ++
333 "(" ++ showSep "," (map fcall xs) ++ ")") ++ ";\n"
334bcc i (FOREIGNCALL l rty (FStr fn) args)
335 = indent i ++
336 c_irts (toFType rty) (creg l ++ " = ")
337 (fn ++ "(" ++ showSep "," (map fcall args) ++ ")") ++ ";\n"
338bcc i (FOREIGNCALL l rty _ args) = error "Foreign Function calls cannot be partially applied, without being inlined."
339bcc i (NULL r) = indent i ++ creg r ++ " = NULL;\n" -- clear, so it'll be GCed
340bcc i (ERROR str) = indent i ++ "fprintf(stderr, " ++ show str ++ "); fprintf(stderr, \"\\n\"); exit(-1);\n"
341-- bcc i c = error (show c) -- indent i ++ "// not done yet\n"
343fcall (t, arg) = irts_c (toFType t) (creg arg)
344-- Deconstruct the Foreign type in the defunctionalised expression and build
345-- a foreign type description for c_irts and irts_c
346toAType (FCon i)
347 | i == sUN "C_IntChar" = ATInt ITChar
348 | i == sUN "C_IntNative" = ATInt ITNative
349 | i == sUN "C_IntBits8" = ATInt (ITFixed IT8)
350 | i == sUN "C_IntBits16" = ATInt (ITFixed IT16)
351 | i == sUN "C_IntBits32" = ATInt (ITFixed IT32)
352 | i == sUN "C_IntBits64" = ATInt (ITFixed IT64)
353toAType t = error (show t ++ " not defined in toAType")
355toFType (FCon c)
356 | c == sUN "C_Str" = FString
357 | c == sUN "C_Float" = FArith ATFloat
358 | c == sUN "C_Ptr" = FPtr
359 | c == sUN "C_MPtr" = FManagedPtr
360 | c == sUN "C_CData" = FCData
361 | c == sUN "C_Unit" = FUnit
362toFType (FApp c [_,ity])
363 | c == sUN "C_IntT" = FArith (toAType ity)
364 | c == sUN "C_FnT" = toFunType ity
365toFType (FApp c [_])
366 | c == sUN "C_Any" = FAny
367toFType t = FAny
369toFunType (FApp c [_,ity])
370 | c == sUN "C_FnBase" = FFunction
371 | c == sUN "C_FnIO" = FFunctionIO
372toFunType (FApp c [_,_,_,ity])
373 | c == sUN "C_Fn" = toFunType ity
374toFunType _ = FAny
376c_irts (FArith (ATInt ITNative)) l x = l ++ "MKINT((i_int)(" ++ x ++ "))"
377c_irts (FArith (ATInt ITChar)) l x = c_irts (FArith (ATInt ITNative)) l x
378c_irts (FArith (ATInt (ITFixed ity))) l x
379 = l ++ "idris_b" ++ show (nativeTyWidth ity) ++ "const(vm, " ++ x ++ ")"
380c_irts FString l x = l ++ "MKSTR(vm, " ++ x ++ ")"
381c_irts FUnit l x = x
382c_irts FPtr l x = l ++ "MKPTR(vm, " ++ x ++ ")"
383c_irts FManagedPtr l x = l ++ "MKMPTR(vm, " ++ x ++ ")"
384c_irts (FArith ATFloat) l x = l ++ "MKFLOAT(vm, " ++ x ++ ")"
385c_irts FCData l x = l ++ "MKCDATA(vm, " ++ x ++ ")"
386c_irts FAny l x = l ++ x
387c_irts FFunction l x = error "Return of function from foreign call is not supported"
388c_irts FFunctionIO l x = error "Return of function from foreign call is not supported"
390irts_c (FArith (ATInt ITNative)) x = "GETINT(" ++ x ++ ")"
391irts_c (FArith (ATInt ITChar)) x = irts_c (FArith (ATInt ITNative)) x
392irts_c (FArith (ATInt (ITFixed ity))) x
393 = "(" ++ x ++ "->info.bits" ++ show (nativeTyWidth ity) ++ ")"
394irts_c FString x = "GETSTR(" ++ x ++ ")"
395irts_c FUnit x = x
396irts_c FPtr x = "GETPTR(" ++ x ++ ")"
397irts_c FManagedPtr x = "GETMPTR(" ++ x ++ ")"
398irts_c (FArith ATFloat) x = "GETFLOAT(" ++ x ++ ")"
399irts_c FCData x = "GETCDATA(" ++ x ++ ")"
400irts_c FAny x = x
401irts_c FFunctionIO x = wrapped x
402irts_c FFunction x = wrapped x
404cFnSig name rty [] = ctype rty ++ " (*" ++ name ++ ")(void) "
405cFnSig name rty args = ctype rty ++ " (*" ++ name ++ ")("
406 ++ showSep "," (map (ctype . fst) args) ++ ") "
408wrapped x = "_idris_get_wrapper(" ++ x ++ ")"
410bitOp v op ty args = v ++ "idris_b" ++ show (nativeTyWidth ty) ++ op ++ "(vm, " ++ intercalate ", " (map creg args) ++ ")"
412bitCoerce v op input output arg
413 = v ++ "idris_b" ++ show (nativeTyWidth input) ++ op ++ show (nativeTyWidth output) ++ "(vm, " ++ creg arg ++ ")"
415signedTy :: NativeTy -> String
416signedTy t = "int" ++ show (nativeTyWidth t) ++ "_t"
418doOp v (LPlus (ATInt ITNative)) [l, r] = v ++ "ADD(" ++ creg l ++ ", " ++ creg r ++ ")"
419doOp v (LMinus (ATInt ITNative)) [l, r] = v ++ "INTOP(-," ++ creg l ++ ", " ++ creg r ++ ")"
420doOp v (LTimes (ATInt ITNative)) [l, r] = v ++ "MULT(" ++ creg l ++ ", " ++ creg r ++ ")"
421doOp v (LUDiv ITNative) [l, r] = v ++ "UINTOP(/," ++ creg l ++ ", " ++ creg r ++ ")"
422doOp v (LSDiv (ATInt ITNative)) [l, r] = v ++ "INTOP(/," ++ creg l ++ ", " ++ creg r ++ ")"
423doOp v (LURem ITNative) [l, r] = v ++ "UINTOP(%," ++ creg l ++ ", " ++ creg r ++ ")"
424doOp v (LSRem (ATInt ITNative)) [l, r] = v ++ "INTOP(%," ++ creg l ++ ", " ++ creg r ++ ")"
425doOp v (LAnd ITNative) [l, r] = v ++ "INTOP(&," ++ creg l ++ ", " ++ creg r ++ ")"
426doOp v (LOr ITNative) [l, r] = v ++ "INTOP(|," ++ creg l ++ ", " ++ creg r ++ ")"
427doOp v (LXOr ITNative) [l, r] = v ++ "INTOP(^," ++ creg l ++ ", " ++ creg r ++ ")"
428doOp v (LSHL ITNative) [l, r] = v ++ "INTOP(<<," ++ creg l ++ ", " ++ creg r ++ ")"
429doOp v (LLSHR ITNative) [l, r] = v ++ "UINTOP(>>," ++ creg l ++ ", " ++ creg r ++ ")"
430doOp v (LASHR ITNative) [l, r] = v ++ "INTOP(>>," ++ creg l ++ ", " ++ creg r ++ ")"
431doOp v (LCompl ITNative) [x] = v ++ "INTOP(~," ++ creg x ++ ")"
432doOp v (LEq (ATInt ITNative)) [l, r] = v ++ "INTOP(==," ++ creg l ++ ", " ++ creg r ++ ")"
433doOp v (LSLt (ATInt ITNative)) [l, r] = v ++ "INTOP(<," ++ creg l ++ ", " ++ creg r ++ ")"
434doOp v (LSLe (ATInt ITNative)) [l, r] = v ++ "INTOP(<=," ++ creg l ++ ", " ++ creg r ++ ")"
435doOp v (LSGt (ATInt ITNative)) [l, r] = v ++ "INTOP(>," ++ creg l ++ ", " ++ creg r ++ ")"
436doOp v (LSGe (ATInt ITNative)) [l, r] = v ++ "INTOP(>=," ++ creg l ++ ", " ++ creg r ++ ")"
437doOp v (LLt ITNative) [l, r] = v ++ "UINTOP(<," ++ creg l ++ ", " ++ creg r ++ ")"
438doOp v (LLe ITNative) [l, r] = v ++ "UINTOP(<=," ++ creg l ++ ", " ++ creg r ++ ")"
439doOp v (LGt ITNative) [l, r] = v ++ "UINTOP(>," ++ creg l ++ ", " ++ creg r ++ ")"
440doOp v (LGe ITNative) [l, r] = v ++ "UINTOP(>=," ++ creg l ++ ", " ++ creg r ++ ")"
442doOp v (LPlus (ATInt ITChar)) [l, r] = doOp v (LPlus (ATInt ITNative)) [l, r]
443doOp v (LMinus (ATInt ITChar)) [l, r] = doOp v (LMinus (ATInt ITNative)) [l, r]
444doOp v (LTimes (ATInt ITChar)) [l, r] = doOp v (LTimes (ATInt ITNative)) [l, r]
445doOp v (LUDiv ITChar) [l, r] = doOp v (LUDiv ITNative) [l, r]
446doOp v (LSDiv (ATInt ITChar)) [l, r] = doOp v (LSDiv (ATInt ITNative)) [l, r]
447doOp v (LURem ITChar) [l, r] = doOp v (LURem ITNative) [l, r]
448doOp v (LSRem (ATInt ITChar)) [l, r] = doOp v (LSRem (ATInt ITNative)) [l, r]
449doOp v (LAnd ITChar) [l, r] = doOp v (LAnd ITNative) [l, r]
450doOp v (LOr ITChar) [l, r] = doOp v (LOr ITNative) [l, r]
451doOp v (LXOr ITChar) [l, r] = doOp v (LXOr ITNative) [l, r]
452doOp v (LSHL ITChar) [l, r] = doOp v (LSHL ITNative) [l, r]
453doOp v (LLSHR ITChar) [l, r] = doOp v (LLSHR ITNative) [l, r]
454doOp v (LASHR ITChar) [l, r] = doOp v (LASHR ITNative) [l, r]
455doOp v (LCompl ITChar) [x] = doOp v (LCompl ITNative) [x]
456doOp v (LEq (ATInt ITChar)) [l, r] = doOp v (LEq (ATInt ITNative)) [l, r]
457doOp v (LSLt (ATInt ITChar)) [l, r] = doOp v (LSLt (ATInt ITNative)) [l, r]
458doOp v (LSLe (ATInt ITChar)) [l, r] = doOp v (LSLe (ATInt ITNative)) [l, r]
459doOp v (LSGt (ATInt ITChar)) [l, r] = doOp v (LSGt (ATInt ITNative)) [l, r]
460doOp v (LSGe (ATInt ITChar)) [l, r] = doOp v (LSGe (ATInt ITNative)) [l, r]
461doOp v (LLt ITChar) [l, r] = doOp v (LLt ITNative) [l, r]
462doOp v (LLe ITChar) [l, r] = doOp v (LLe ITNative) [l, r]
463doOp v (LGt ITChar) [l, r] = doOp v (LGt ITNative) [l, r]
464doOp v (LGe ITChar) [l, r] = doOp v (LGe ITNative) [l, r]
466doOp v (LPlus ATFloat) [l, r] = v ++ "FLOATOP(+," ++ creg l ++ ", " ++ creg r ++ ")"
467doOp v (LMinus ATFloat) [l, r] = v ++ "FLOATOP(-," ++ creg l ++ ", " ++ creg r ++ ")"
468doOp v (LTimes ATFloat) [l, r] = v ++ "FLOATOP(*," ++ creg l ++ ", " ++ creg r ++ ")"
469doOp v (LSDiv ATFloat) [l, r] = v ++ "FLOATOP(/," ++ creg l ++ ", " ++ creg r ++ ")"
470doOp v (LEq ATFloat) [l, r] = v ++ "FLOATBOP(==," ++ creg l ++ ", " ++ creg r ++ ")"
471doOp v (LSLt ATFloat) [l, r] = v ++ "FLOATBOP(<," ++ creg l ++ ", " ++ creg r ++ ")"
472doOp v (LSLe ATFloat) [l, r] = v ++ "FLOATBOP(<=," ++ creg l ++ ", " ++ creg r ++ ")"
473doOp v (LSGt ATFloat) [l, r] = v ++ "FLOATBOP(>," ++ creg l ++ ", " ++ creg r ++ ")"
474doOp v (LSGe ATFloat) [l, r] = v ++ "FLOATBOP(>=," ++ creg l ++ ", " ++ creg r ++ ")"
476doOp v (LIntFloat ITBig) [x] = v ++ "idris_castBigFloat(vm, " ++ creg x ++ ")"
477doOp v (LFloatInt ITBig) [x] = v ++ "idris_castFloatBig(vm, " ++ creg x ++ ")"
478doOp v (LPlus (ATInt ITBig)) [l, r] = v ++ "idris_bigPlus(vm, " ++ creg l ++ ", " ++ creg r ++ ")"
479doOp v (LMinus (ATInt ITBig)) [l, r] = v ++ "idris_bigMinus(vm, " ++ creg l ++ ", " ++ creg r ++ ")"
480doOp v (LTimes (ATInt ITBig)) [l, r] = v ++ "idris_bigTimes(vm, " ++ creg l ++ ", " ++ creg r ++ ")"
481doOp v (LSDiv (ATInt ITBig)) [l, r] = v ++ "idris_bigDivide(vm, " ++ creg l ++ ", " ++ creg r ++ ")"
482doOp v (LSRem (ATInt ITBig)) [l, r] = v ++ "idris_bigMod(vm, " ++ creg l ++ ", " ++ creg r ++ ")"
483doOp v (LAnd ITBig) [l, r] = v ++ "idris_bigAnd(vm, " ++ creg l ++ ", " ++ creg r ++ ")"
484doOp v (LOr ITBig) [l, r] = v ++ "idris_bigOr(vm, " ++ creg l ++ ", " ++ creg r ++ ")"
485doOp v (LSHL ITBig) [l, r] = v ++ "idris_bigShiftLeft(vm, " ++ creg l ++ ", " ++ creg r ++ ")"
486doOp v (LLSHR ITBig) [l, r] = v ++ "idris_bigLShiftRight(vm, " ++ creg l ++ ", " ++ creg r ++ ")"
487doOp v (LASHR ITBig) [l, r] = v ++ "idris_bigAShiftRight(vm, " ++ creg l ++ ", " ++ creg r ++ ")"
488doOp v (LEq (ATInt ITBig)) [l, r] = v ++ "idris_bigEq(vm, " ++ creg l ++ ", " ++ creg r ++ ")"
489doOp v (LSLt (ATInt ITBig)) [l, r] = v ++ "idris_bigLt(vm, " ++ creg l ++ ", " ++ creg r ++ ")"
490doOp v (LSLe (ATInt ITBig)) [l, r] = v ++ "idris_bigLe(vm, " ++ creg l ++ ", " ++ creg r ++ ")"
491doOp v (LSGt (ATInt ITBig)) [l, r] = v ++ "idris_bigGt(vm, " ++ creg l ++ ", " ++ creg r ++ ")"
492doOp v (LSGe (ATInt ITBig)) [l, r] = v ++ "idris_bigGe(vm, " ++ creg l ++ ", " ++ creg r ++ ")"
494doOp v (LIntFloat ITNative) [x] = v ++ "idris_castIntFloat(" ++ creg x ++ ")"
495doOp v (LFloatInt ITNative) [x] = v ++ "idris_castFloatInt(" ++ creg x ++ ")"
496doOp v (LSExt ITNative ITBig) [x] = v ++ "idris_castIntBig(vm, " ++ creg x ++ ")"
497doOp v (LTrunc ITBig ITNative) [x] = v ++ "idris_castBigInt(vm, " ++ creg x ++ ")"
498doOp v (LStrInt ITBig) [x] = v ++ "idris_castStrBig(vm, " ++ creg x ++ ")"
499doOp v (LIntStr ITBig) [x] = v ++ "idris_castBigStr(vm, " ++ creg x ++ ")"
500doOp v (LIntStr ITNative) [x] = v ++ "idris_castIntStr(vm, " ++ creg x ++ ")"
501doOp v (LStrInt ITNative) [x] = v ++ "idris_castStrInt(vm, " ++ creg x ++ ")"
502doOp v (LIntStr (ITFixed _)) [x] = v ++ "idris_castBitsStr(vm, " ++ creg x ++ ")"
503doOp v LFloatStr [x] = v ++ "idris_castFloatStr(vm, " ++ creg x ++ ")"
504doOp v LStrFloat [x] = v ++ "idris_castStrFloat(vm, " ++ creg x ++ ")"
506doOp v (LSLt (ATInt (ITFixed ty))) [x, y] = bitOp v "SLt" ty [x, y]
507doOp v (LSLe (ATInt (ITFixed ty))) [x, y] = bitOp v "SLte" ty [x, y]
508doOp v (LEq (ATInt (ITFixed ty))) [x, y] = bitOp v "Eq" ty [x, y]
509doOp v (LSGe (ATInt (ITFixed ty))) [x, y] = bitOp v "SGte" ty [x, y]
510doOp v (LSGt (ATInt (ITFixed ty))) [x, y] = bitOp v "SGt" ty [x, y]
511doOp v (LLt (ITFixed ty)) [x, y] = bitOp v "Lt" ty [x, y]
512doOp v (LLe (ITFixed ty)) [x, y] = bitOp v "Lte" ty [x, y]
513doOp v (LGe (ITFixed ty)) [x, y] = bitOp v "Gte" ty [x, y]
514doOp v (LGt (ITFixed ty)) [x, y] = bitOp v "Gt" ty [x, y]
516doOp v (LSHL (ITFixed ty)) [x, y] = bitOp v "Shl" ty [x, y]
517doOp v (LLSHR (ITFixed ty)) [x, y] = bitOp v "LShr" ty [x, y]
518doOp v (LASHR (ITFixed ty)) [x, y] = bitOp v "AShr" ty [x, y]
519doOp v (LAnd (ITFixed ty)) [x, y] = bitOp v "And" ty [x, y]
520doOp v (LOr (ITFixed ty)) [x, y] = bitOp v "Or" ty [x, y]
521doOp v (LXOr (ITFixed ty)) [x, y] = bitOp v "Xor" ty [x, y]
522doOp v (LCompl (ITFixed ty)) [x] = bitOp v "Compl" ty [x]
524doOp v (LPlus (ATInt (ITFixed ty))) [x, y] = bitOp v "Plus" ty [x, y]
525doOp v (LMinus (ATInt (ITFixed ty))) [x, y] = bitOp v "Minus" ty [x, y]
526doOp v (LTimes (ATInt (ITFixed ty))) [x, y] = bitOp v "Times" ty [x, y]
527doOp v (LUDiv (ITFixed ty)) [x, y] = bitOp v "UDiv" ty [x, y]
528doOp v (LSDiv (ATInt (ITFixed ty))) [x, y] = bitOp v "SDiv" ty [x, y]
529doOp v (LURem (ITFixed ty)) [x, y] = bitOp v "URem" ty [x, y]
530doOp v (LSRem (ATInt (ITFixed ty))) [x, y] = bitOp v "SRem" ty [x, y]
532doOp v (LSExt (ITFixed from) ITBig) [x]
533 = v ++ "MKBIGSI(vm, (" ++ signedTy from ++ ")" ++ creg x ++ "->info.bits" ++ show (nativeTyWidth from) ++ ")"
534doOp v (LSExt ITNative (ITFixed to)) [x]
535 = v ++ "idris_b" ++ show (nativeTyWidth to) ++ "const(vm, GETINT(" ++ creg x ++ "))"
536doOp v (LSExt ITChar (ITFixed to)) [x]
537 = doOp v (LSExt ITNative (ITFixed to)) [x]
538doOp v (LSExt (ITFixed from) ITNative) [x]
539 = v ++ "MKINT((i_int)((" ++ signedTy from ++ ")" ++ creg x ++ "->info.bits" ++ show (nativeTyWidth from) ++ "))"
540doOp v (LSExt (ITFixed from) ITChar) [x]
541 = doOp v (LSExt (ITFixed from) ITNative) [x]
542doOp v (LSExt (ITFixed from) (ITFixed to)) [x]
543 | nativeTyWidth from < nativeTyWidth to = bitCoerce v "S" from to x
544doOp v (LZExt ITNative (ITFixed to)) [x]
545 = v ++ "idris_b" ++ show (nativeTyWidth to) ++ "const(vm, (uintptr_t)GETINT(" ++ creg x ++ "))"
546doOp v (LZExt ITChar (ITFixed to)) [x]
547 = doOp v (LZExt ITNative (ITFixed to)) [x]
548doOp v (LZExt (ITFixed from) ITNative) [x]
549 = v ++ "MKINT((i_int)" ++ creg x ++ "->info.bits" ++ show (nativeTyWidth from) ++ ")"
550doOp v (LZExt (ITFixed from) ITChar) [x]
551 = doOp v (LZExt (ITFixed from) ITNative) [x]
552doOp v (LZExt (ITFixed from) ITBig) [x]
553 = v ++ "MKBIGUI(vm, " ++ creg x ++ "->info.bits" ++ show (nativeTyWidth from) ++ ")"
554doOp v (LZExt ITNative ITBig) [x]
555 = v ++ "MKBIGUI(vm, (uintptr_t)GETINT(" ++ creg x ++ "))"
556doOp v (LZExt (ITFixed from) (ITFixed to)) [x]
557 | nativeTyWidth from < nativeTyWidth to = bitCoerce v "Z" from to x
558doOp v (LTrunc ITNative (ITFixed to)) [x]
559 = v ++ "idris_b" ++ show (nativeTyWidth to) ++ "const(vm, GETINT(" ++ creg x ++ "))"
560doOp v (LTrunc ITChar (ITFixed to)) [x]
561 = doOp v (LTrunc ITNative (ITFixed to)) [x]
562doOp v (LTrunc (ITFixed from) ITNative) [x]
563 = v ++ "MKINT((i_int)" ++ creg x ++ "->info.bits" ++ show (nativeTyWidth from) ++ ")"
564doOp v (LTrunc (ITFixed from) ITChar) [x]
565 = doOp v (LTrunc (ITFixed from) ITNative) [x]
566doOp v (LTrunc ITBig (ITFixed IT64)) [x]
567 = v ++ "idris_b64const(vm, ISINT(" ++ creg x ++ ") ? GETINT(" ++ creg x ++ ") : idris_truncBigB64(GETMPZ(" ++ creg x ++ ")))"
568doOp v (LTrunc ITBig (ITFixed to)) [x]
569 = v ++ "idris_b" ++ show (nativeTyWidth to) ++ "const(vm, ISINT(" ++ creg x ++ ") ? GETINT(" ++ creg x ++ ") : mpz_get_ui(GETMPZ(" ++ creg x ++ ")))"
570doOp v (LTrunc (ITFixed from) (ITFixed to)) [x]
571 | nativeTyWidth from > nativeTyWidth to = bitCoerce v "T" from to x
573doOp v LFExp [x] = v ++ flUnOp "exp" (creg x)
574doOp v LFLog [x] = v ++ flUnOp "log" (creg x)
575doOp v LFSin [x] = v ++ flUnOp "sin" (creg x)
576doOp v LFCos [x] = v ++ flUnOp "cos" (creg x)
577doOp v LFTan [x] = v ++ flUnOp "tan" (creg x)
578doOp v LFASin [x] = v ++ flUnOp "asin" (creg x)
579doOp v LFACos [x] = v ++ flUnOp "acos" (creg x)
580doOp v LFATan [x] = v ++ flUnOp "atan" (creg x)
581doOp v LFSqrt [x] = v ++ flUnOp "sqrt" (creg x)
582doOp v LFFloor [x] = v ++ flUnOp "floor" (creg x)
583doOp v LFCeil [x] = v ++ flUnOp "ceil" (creg x)
584doOp v LFNegate [x] = v ++ "MKFLOAT(vm, -GETFLOAT(" ++ (creg x) ++ "))"
585doOp v LFATan2 [y, x] = v ++ "MKFLOAT(vm, atan2(GETFLOAT(" ++ creg y ++ "), GETFLOAT(" ++ creg x ++ ")))"
587-- String functions which don't need to know we're UTF8
588doOp v LStrConcat [l,r] = v ++ "idris_concat(vm, " ++ creg l ++ ", " ++ creg r ++ ")"
589doOp v LStrLt [l,r] = v ++ "idris_strlt(vm, " ++ creg l ++ ", " ++ creg r ++ ")"
590doOp v LStrEq [l,r] = v ++ "idris_streq(vm, " ++ creg l ++ ", " ++ creg r ++ ")"
592doOp v LReadStr [_] = v ++ "idris_readStr(vm, stdin)"
593doOp v LWriteStr [_,s]
594 = v ++ "MKINT((i_int)(idris_writeStr(stdout"
595 ++ ",GETSTR("
596 ++ creg s ++ "))))"
599-- String functions which need to know we're UTF8
600doOp v LStrHead [x] = v ++ "idris_strHead(vm, " ++ creg x ++ ")"
601doOp v LStrTail [x] = v ++ "idris_strTail(vm, " ++ creg x ++ ")"
602doOp v LStrCons [x, y] = v ++ "idris_strCons(vm, " ++ creg x ++ "," ++ creg y ++ ")"
603doOp v LStrIndex [x, y] = v ++ "idris_strIndex(vm, " ++ creg x ++ "," ++ creg y ++ ")"
604doOp v LStrRev [x] = v ++ "idris_strRev(vm, " ++ creg x ++ ")"
605doOp v LStrLen [x] = v ++ "idris_strlen(vm, " ++ creg x ++ ")"
606doOp v LStrSubstr [x,y,z] = v ++ "idris_substr(vm, " ++ creg x ++ "," ++ creg y ++ "," ++ creg z ++ ")"
608doOp v LFork [x] = v ++ "MKPTR(vm, vmThread(vm, " ++ cname (sMN 0 "EVAL") ++ ", " ++ creg x ++ "))"
609doOp v LPar [x] = v ++ creg x -- "MKPTR(vm, vmThread(vm, " ++ cname (MN 0 "EVAL") ++ ", " ++ creg x ++ "))"
610doOp v (LChInt ITNative) args = v ++ creg (last args)
611doOp v (LChInt ITChar) args = doOp v (LChInt ITNative) args
612doOp v (LIntCh ITNative) args = v ++ creg (last args)
613doOp v (LIntCh ITChar) args = doOp v (LIntCh ITNative) args
615doOp v LSystemInfo [x] = v ++ "idris_systemInfo(vm, " ++ creg x ++ ")"
616doOp v LCrash [x] = "idris_crash(GETSTR(" ++ creg x ++ "))"
617doOp v LNoOp args = v ++ creg (last args)
619-- Pointer primitives (declared as %extern in Builtins.idr)
620doOp v (LExternal rf) [_,x]
621 | rf == sUN "prim__readFile"
622 = v ++ "idris_readStr(vm, GETPTR(" ++ creg x ++ "))"
623doOp v (LExternal rf) [_,len,x]
624 | rf == sUN "prim__readChars"
625 = v ++ "idris_readChars(vm, GETINT(" ++ creg len ++
626 "), GETPTR(" ++ creg x ++ "))"
627doOp v (LExternal wf) [_,x,s]
628 | wf == sUN "prim__writeFile"
629 = v ++ "MKINT((i_int)(idris_writeStr(GETPTR(" ++ creg x
630 ++ "),GETSTR("
631 ++ creg s ++ "))))"
632doOp v (LExternal si) [] | si == sUN "prim__stdin" = v ++ "MKPTR(vm, stdin)"
633doOp v (LExternal so) [] | so == sUN "prim__stdout" = v ++ "MKPTR(vm, stdout)"
634doOp v (LExternal se) [] | se == sUN "prim__stderr" = v ++ "MKPTR(vm, stderr)"
636doOp v (LExternal vm) [_] | vm == sUN "prim__vm" = v ++ "MKPTR(vm, vm)"
637doOp v (LExternal nul) [] | nul == sUN "prim__null" = v ++ "MKPTR(vm, NULL)"
638doOp v (LExternal eqp) [x, y] | eqp == sUN "prim__eqPtr"
639 = v ++ "MKINT((i_int)(GETPTR(" ++ creg x ++ ") == GETPTR(" ++ creg y ++ ")))"
640doOp v (LExternal eqp) [x, y] | eqp == sUN "prim__eqManagedPtr"
641 = v ++ "MKINT((i_int)(GETMPTR(" ++ creg x ++ ") == GETMPTR(" ++ creg y ++ ")))"
642doOp v (LExternal rp) [p, i] | rp == sUN "prim__registerPtr"
643 = v ++ "MKMPTR(vm, GETPTR(" ++ creg p ++ "), GETINT(" ++ creg i ++ "))"
644doOp v (LExternal pk) [_, p, o] | pk == sUN "prim__peek8"
645 = v ++ "idris_peekB8(vm," ++ creg p ++ "," ++ creg o ++")"
646doOp v (LExternal pk) [_, p, o, x] | pk == sUN "prim__poke8"
647 = v ++ "idris_pokeB8(" ++ creg p ++ "," ++ creg o ++ "," ++ creg x ++ ")"
648doOp v (LExternal pk) [_, p, o] | pk == sUN "prim__peek16"
649 = v ++ "idris_peekB16(vm," ++ creg p ++ "," ++ creg o ++")"
650doOp v (LExternal pk) [_, p, o, x] | pk == sUN "prim__poke16"
651 = v ++ "idris_pokeB16(" ++ creg p ++ "," ++ creg o ++ "," ++ creg x ++ ")"
652doOp v (LExternal pk) [_, p, o] | pk == sUN "prim__peek32"
653 = v ++ "idris_peekB32(vm," ++ creg p ++ "," ++ creg o ++")"
654doOp v (LExternal pk) [_, p, o, x] | pk == sUN "prim__poke32"
655 = v ++ "idris_pokeB32(" ++ creg p ++ "," ++ creg o ++ "," ++ creg x ++ ")"
656doOp v (LExternal pk) [_, p, o] | pk == sUN "prim__peek64"
657 = v ++ "idris_peekB64(vm," ++ creg p ++ "," ++ creg o ++")"
658doOp v (LExternal pk) [_, p, o, x] | pk == sUN "prim__poke64"
659 = v ++ "idris_pokeB64(" ++ creg p ++ "," ++ creg o ++ "," ++ creg x ++ ")"
660doOp v (LExternal pk) [_, p, o] | pk == sUN "prim__peekPtr"
661 = v ++ "idris_peekPtr(vm," ++ creg p ++ "," ++ creg o ++")"
662doOp v (LExternal pk) [_, p, o, x] | pk == sUN "prim__pokePtr"
663 = v ++ "idris_pokePtr(" ++ creg p ++ "," ++ creg o ++ "," ++ creg x ++ ")"
664doOp v (LExternal pk) [_, p, o, x] | pk == sUN "prim__pokeDouble"
665 = v ++ "idris_pokeDouble(" ++ creg p ++ "," ++ creg o ++ "," ++ creg x ++ ")"
666doOp v (LExternal pk) [_, p, o] | pk == sUN "prim__peekDouble"
667 = v ++ "idris_peekDouble(vm," ++ creg p ++ "," ++ creg o ++")"
668doOp v (LExternal pk) [_, p, o, x] | pk == sUN "prim__pokeSingle"
669 = v ++ "idris_pokeSingle(" ++ creg p ++ "," ++ creg o ++ "," ++ creg x ++ ")"
670doOp v (LExternal pk) [_, p, o] | pk == sUN "prim__peekSingle"
671 = v ++ "idris_peekSingle(vm," ++ creg p ++ "," ++ creg o ++")"
672doOp v (LExternal pk) [] | pk == sUN "prim__sizeofPtr"
673 = v ++ "MKINT(sizeof(void*))"
674doOp v (LExternal mpt) [p] | mpt == sUN "prim__asPtr"
675 = v ++ "MKPTR(vm, GETMPTR("++ creg p ++"))"
676doOp v (LExternal offs) [p, n] | offs == sUN "prim__ptrOffset"
677 = v ++ "MKPTR(vm, (void *)((char *)GETPTR(" ++ creg p ++ ") + GETINT(" ++ creg n ++ ")))"
678doOp _ op args = error $ "doOp not implemented (" ++ show (op, args) ++ ")"
681flUnOp :: String -> String -> String
682flUnOp name val = "MKFLOAT(vm, " ++ name ++ "(GETFLOAT(" ++ val ++ ")))"
684-------------------- Interface file generation
686-- First, the wrappers in the C file
688ifaceC :: Export -> String
689ifaceC (ExportData n) = "typedef VAL " ++ cdesc n ++ ";\n"
690ifaceC (ExportFun n cn ret args)
691 = ctype ret ++ " " ++ cdesc cn ++
692 "(VM* vm" ++ showArgs (zip argNames args) ++ ") {\n"
693 ++ mkBody n (zip argNames args) ret ++ "}\n\n"
694 where showArgs [] = ""
695 showArgs ((n, t) : ts) = ", " ++ ctype t ++ " " ++ n ++
696 showArgs ts
698 argNames = zipWith (++) (repeat "arg") (map show [0..])
700mkBody n as t = indent 1 ++ "INITFRAME;\n" ++
701 indent 1 ++ "RESERVE(" ++ show (max (length as) 3) ++ ");\n" ++
702 push 0 as ++ call n ++ retval t
703 where push i [] = ""
704 push i ((n, t) : ts) = indent 1 ++ c_irts (toFType t)
705 ("TOP(" ++ show i ++ ") = ") n
706 ++ ";\n" ++ push (i + 1) ts
708 call _ = indent 1 ++ "STOREOLD;\n" ++
709 indent 1 ++ "BASETOP(0);\n" ++
710 indent 1 ++ "ADDTOP(" ++ show (length as) ++ ");\n" ++
711 indent 1 ++ "CALL(" ++ cname n ++ ");\n"
713 retval (FIO t)
714 = indent 1 ++ "TOP(0) = NULL;\n" ++
715 indent 1 ++ "TOP(1) = NULL;\n" ++
716 indent 1 ++ "TOP(2) = RVAL;\n" ++
717 indent 1 ++ "STOREOLD;\n" ++
718 indent 1 ++ "BASETOP(0);\n" ++
719 indent 1 ++ "ADDTOP(3);\n" ++
720 indent 1 ++ "CALL(" ++ cname (sUN "call__IO") ++ ");\n" ++
721 retval t
722 retval t = indent 1 ++ "return " ++ irts_c (toFType t) "RVAL" ++ ";\n"
724ctype (FCon c)
725 | c == sUN "C_Str" = "char*"
726 | c == sUN "C_Float" = "float"
727 | c == sUN "C_Ptr" = "void*"
728 | c == sUN "C_MPtr" = "void*"
729 | c == sUN "C_Unit" = "void"
730ctype (FApp c [_,ity])
731 | c == sUN "C_IntT" = carith ity
732ctype (FApp c [_])
733 | c == sUN "C_Any" = "VAL"
734ctype (FStr s) = s
735ctype FUnknown = "void*"
736ctype (FIO t) = ctype t
737ctype t = error "Can't happen: Not a valid interface type " ++ show t
739carith (FCon i)
740 | i == sUN "C_IntChar" = "char"
741 | i == sUN "C_IntNative" = "int"
742 | i == sUN "C_IntBits8" = "uint8_t"
743 | i == sUN "C_IntBits16" = "uint16_t"
744 | i == sUN "C_IntBits32" = "uint32_t"
745 | i == sUN "C_IntBits64" = "uint64_t"
746carith t = error $ "Can't happen: Not an exportable arithmetic type " ++ show t
748cdesc (FStr s) = s
749cdesc s = error "Can't happen: Not a valid C name"
751-- Then, the header files
753codegenH :: [ExportIFace] -> IO ()
754codegenH es = mapM_ writeIFace es
756writeIFace :: ExportIFace -> IO ()
757writeIFace (Export ffic hdr exps)
758 | ffic == sNS (sUN "FFI_C") ["FFI_C"]
759 = do let hfile = "#ifndef " ++ hdr_guard hdr ++ "\n" ++
760 "#define " ++ hdr_guard hdr ++ "\n\n" ++
761 "#include <idris_rts.h>\n\n" ++
762 concatMap hdr_export exps ++ "\n" ++
763 "#endif\n\n"
764 writeFile hdr hfile
765 | otherwise = return ()
767hdr_guard x = "__" ++ map hchar x
768 where hchar x | isAlphaNum x = toUpper x
769 hchar _ = '_'
771hdr_export :: Export -> String
772hdr_export (ExportData n) = "typedef VAL " ++ cdesc n ++ ";\n"
773hdr_export (ExportFun n cn ret args)
774 = ctype ret ++ " " ++ cdesc cn ++
775 "(VM* vm" ++ showArgs (zip argNames args) ++ ");\n"
776 where showArgs [] = ""
777 showArgs ((n, t) : ts) = ", " ++ ctype t ++ " " ++ n ++
778 showArgs ts
780 argNames = zipWith (++) (repeat "arg") (map show [0..])
782------------------ Callback wrapper generation ----------------
783-- Generate callback wrappers and a function to select the
784-- correct wrapper function to pass.
785-- TODO: This is limited to functions that are specified in
786-- the foreign call. Otherwise we would have to generate wrappers for all
787-- functions with correct arity or do flow analysis
788-- to find all possible inputs to the foreign call.
789genWrappers :: [(Name, [BC])] -> String
790genWrappers bcs = let
791 tags = nubBy (\x y -> snd x == snd y) $ concatMap (getCallback . snd) bcs
792 in
793 case tags of
794 [] -> ""
795 t -> concatMap genWrapper t ++ genDispatcher t
797genDispatcher :: [(FDesc, Int)] -> String
798genDispatcher tags = "void* _idris_get_wrapper(VAL con)\n" ++
799 "{\n" ++
800 indent 1 ++ "switch(TAG(con)) {\n" ++
801 concatMap makeSwitch tags ++
802 indent 1 ++ "}\n" ++
803 indent 1 ++ "fprintf(stderr, \"No wrapper for callback\");\n" ++
804 indent 1 ++ "exit(-1);\n" ++
805 "}\n\n"
806 where
807 makeSwitch (_, tag) =
808 indent 1 ++ "case " ++ show tag ++ ":\n" ++
809 indent 2 ++ "return (void*) &" ++ wrapperName tag ++ ";\n"
811genWrapper :: (FDesc, Int) -> String
812genWrapper (desc, tag) | (toFType desc) == FFunctionIO =
813 error "Cannot create C callbacks for IO functions, wrap them with unsafePerformIO.\n"
814genWrapper (desc, tag) = ret ++ " " ++ wrapperName tag ++ "(" ++
815 renderArgs argList ++")\n" ++
816 "{\n" ++
817 (if ret /= "void" then indent 1 ++ ret ++ " ret;\n" else "") ++
818 indent 1 ++ "VM* vm = get_vm();\n" ++
819 indent 1 ++ "if (vm == NULL) {\n" ++
820 indent 2 ++ "vm = idris_vm();\n" ++
821 indent 1 ++ "}\n" ++
822 indent 1 ++ "INITFRAME;\n" ++
823 indent 1 ++ "RESERVE(" ++ show (len + 1) ++ ");\n" ++
824 indent 1 ++ "allocCon(REG1, vm, " ++ show tag ++ ",0 , 0);\n" ++
825 indent 1 ++ "TOP(0) = REG1;\n" ++
826 applyArgs argList ++
827 if ret /= "void"
828 then indent 1 ++ "ret = " ++ irts_c (toFType ft) "RVAL" ++ ";\n"
829 ++ indent 1 ++ "return ret;\n}\n\n"
830 else "}\n\n"
831 where
832 (ret, ft) = rty desc
833 argList = zip (args desc) [0..]
834 len = length argList
836 applyArgs (x:y:xs) = push 1 [x] ++
837 indent 1 ++ "STOREOLD;\n" ++
838 indent 1 ++ "BASETOP(0);\n" ++
839 indent 1 ++ "ADDTOP(2);\n" ++
840 indent 1 ++ "CALL(_idris__123_APPLY_95_0_125_);\n" ++
841 indent 1 ++ "TOP(0)=REG1;\n" ++
842 applyArgs (y:xs)
843 applyArgs x = push 1 x ++
844 indent 1 ++ "STOREOLD;\n" ++
845 indent 1 ++ "BASETOP(0);\n" ++
846 indent 1 ++ "ADDTOP(" ++ show (length x + 1) ++ ");\n" ++
847 indent 1 ++ "CALL(_idris__123_APPLY_95_0_125_);\n"
848 renderArgs [] = "void"
849 renderArgs [((s, _), n)] = s ++ " a" ++ (show n)
850 renderArgs (((s, _), n):xs) = s ++ " a" ++ (show n) ++ ", " ++
851 renderArgs xs
852 rty (FApp c [_,ty])
853 | c == sUN "C_FnBase" = (ctype ty, ty)
854 | c == sUN "C_FnIO" = (ctype ty, ty)
855 | c == sUN "C_FnT" = rty ty
856 rty (FApp c [_,_,ty,fn])
857 | c == sUN "C_Fn" = rty fn
858 rty x = ("", x)
859 args (FApp c [_,ty])
860 | c == sUN "C_FnBase" = []
861 | c == sUN "C_FnIO" = []
862 | c == sUN "C_FnT" = args ty
863 args (FApp c [_,_,ty,fn])
864 | toFType ty == FUnit = []
865 | c == sUN "C_Fn" = (ctype ty, ty) : args fn
866 args _ = []
867 push i [] = ""
868 push i (((c, t), n) : ts) = indent 1 ++ c_irts (toFType t)
869 ("TOP(" ++ show i ++ ") = ") ("a" ++ show n)
870 ++ ";\n" ++ push (i + 1) ts
872wrapperName :: Int -> String
873wrapperName tag = "_idris_wrapper_" ++ show tag
875getCallback :: [BC] -> [(FDesc, Int)]
876getCallback bc = getCallback' (reverse bc)
877 where
878 getCallback' (x:xs) = case hasCallback x of
879 [] -> getCallback' xs
880 cbs -> case findCons cbs xs of
881 [] -> error "Idris function couldn't be wrapped."
882 x -> x
883 getCallback' [] = []
884 findCons (c:cs) xs = findCon c xs ++ findCons cs xs
885 findCons [] _ = []
886 findCon c ((MKCON l loc tag args):xs) | snd c == l = [(fst c, tag)]
887 findCon c (_:xs) = findCon c xs
888 findCon c [] = []
890hasCallback :: BC -> [(FDesc, Reg)]
891hasCallback (FOREIGNCALL l rty (FStr fn) args) = filter isFn args
892 where
893 isFn (desc,_) = case toFType desc of
894 FFunction -> True
895 FFunctionIO -> True
896 _ -> False
897hasCallback _ = []