1{-# LANGUAGE PatternGuards, TypeSynonymInstances, CPP #-}
3module IRTS.Compiler where
6import IRTS.Defunctionalise
8import IRTS.CodegenCommon
10import IRTS.CodegenJava
12import IRTS.CodegenJavaScript
14import IRTS.CodegenLLVM
21import Idris.UnusedArgs
25import Idris.Core.Evaluate
26import Idris.Core.CaseTree
28import Control.Monad.State
32import System.Directory
33import System.Environment
34import System.FilePath ((</>), addTrailingPathSeparator)
38compile :: Codegen -> FilePath -> Term -> Idris ()
41 let tmnames = namesUsed (STerm tm)
42 usedIn <- mapM (allNames []) tmnames
43 let used = [sUN "prim__subBigInt", sUN "prim__addBigInt"] : usedIn
44 defsIn <- mkDecls tm (concat used)
45 findUnusedArgs (concat used)
47 objs <- getObjectFiles codegen
48 libs <- getLibs codegen
49 flags <- getFlags codegen
50 hdrs <- getHdrs codegen
51 impdirs <- allImportDirs
52 let defs = defsIn ++ [(sMN 0 "runMain", maindef)]
53 -- iputStrLn $ showSep "\n" (map show defs)
54 let (nexttag, tagged) = addTags 65536 (liftAll defs)
55 let ctxtIn = addAlist tagged emptyContext
56 iLOG "Defunctionalising"
57 let defuns_in = defunctionalise nexttag ctxtIn
58 logLvl 5 $ show defuns_in
60 let defuns = inline defuns_in
61 logLvl 5 $ show defuns
62 iLOG "Resolving variables for CG"
63 -- iputStrLn $ showSep "\n" (map show (toAlist defuns))
64 let checked = checkDefs defuns (toAlist defuns)
66 dumpCases <- getDumpCases
67 dumpDefun <- getDumpDefun
70 Just f -> runIO $ writeFile f (showCaseTrees defs)
73 Just f -> runIO $ writeFile f (dumpDefuns defuns)
74 triple <- targetTriple
77 iLOG "Building output"
79 OK c -> runIO $ case codegen of
81 codegenC c f outty hdrs
82 (concatMap mkObj objs)
83 (concatMap mkLib libs)
84 (concatMap mkFlag flags ++
85 concatMap incdir impdirs) NONE
87 codegenJava [] c f hdrs libs outty
89 codegenJavaScript JavaScript c f outty
91 codegenJavaScript Node c f outty
92 ViaLLVM -> codegenLLVM c triple cpu optimize f outty
93 Bytecode -> dumpBC c f
95 where checkMVs = do i <- getIState
96 case map fst (idris_metavars i) \\ primDefs of
98 ms -> ifail $ "There are undefined metavariables: " ++ show ms
99 inDir d h = do let f = d </> h
100 ex <- doesFileExist f
101 if ex then return f else return h
103 mkLib l = "-l" ++ l ++ " "
106 incdir i = "-I" ++ i ++ " "
109irMain :: TT Name -> Idris LDecl
110irMain tm = do i <- ir tm
111 return $ LFun [] (sMN 0 "runMain") [] (LForce i)
113mkDecls :: Term -> [Name] -> Idris [(Name, LDecl)]
116 let ds = filter (\ (n, d) -> n `elem` used || isCon d) $ ctxtAlist (tt_ctxt i)
117 mapM traceUnused used
118 decls <- mapM build ds
121showCaseTrees :: [(Name, LDecl)] -> String
122showCaseTrees ds = showSep "\n\n" (map showCT ds)
124 showCT (n, LFun _ f args lexp)
125 = show n ++ " " ++ showSep " " (map show args) ++ " =\n\t "
127 showCT (n, LConstructor c t a) = "data " ++ show n ++ " " ++ show a
129isCon (TyDecl _ _) = True
133 ir :: a -> Idris LExp
135build :: (Name, Def) -> Idris (Name, LDecl)
138 case lookup n (idris_scprims i) of
140 let args = map (\x -> sMN x "op") [0..] in
141 return (n, (LFun [] n (take ar args)
142 (LOp op (map (LV . Glob) (take ar args)))))
143 _ -> do def <- mkLDecl n d
144 logLvl 3 $ "Compiled " ++ show n ++ " =\n\t" ++ show def
147getPrim :: IState -> Name -> [LExp] -> Maybe LExp
148getPrim i n args = case lookup n (idris_scprims i) of
150 if (ar == length args)
151 then return (LOp op args)
155declArgs args inl n (LLam xs x) = declArgs (args ++ xs) inl n x
156declArgs args inl n x = LFun (if inl then [Inline] else []) n args x
158mkLDecl n (Function tm _) = do e <- ir tm
159 return (declArgs [] True n e)
160mkLDecl n (CaseOp ci _ _ _ pats cd)
161 = let (args, sc) = cases_runtime cd in
162 do e <- ir (args, sc)
163 return (declArgs [] (case_inlinable ci) n e)
164mkLDecl n (TyDecl (DCon t a) _) = return $ LConstructor n t a
165mkLDecl n (TyDecl (TCon t a) _) = return $ LConstructor n (-1) a
166mkLDecl n _ = return (LFun [] n [] (LError ("Impossible declaration " ++ show n)))
168instance ToIR (TT Name) where
169 ir tm = ir' [] tm where
171 | (P _ (UN m) _, args) <- unApply tm,
172 m == txt "mkForeignPrim"
174 | (P _ (UN u) _, [_, arg]) <- unApply tm,
175 u == txt "unsafePerformPrimIO"
177 -- TMP HACK - until we get inlining.
178 | (P _ (UN r) _, [_, _, _, _, _, arg]) <- unApply tm,
181 | (P _ (UN l) _, [_, arg]) <- unApply tm,
183 = do arg' <- ir' env arg
184 return $ LLazyExp arg'
185 | (P _ (UN a) _, [_, _, _, arg]) <- unApply tm,
186 a == txt "assert_smaller"
188 | (P _ (UN p) _, [_, arg]) <- unApply tm,
190 = do arg' <- ir' env arg
191 return $ LOp LPar [LLazyExp arg']
192 | (P _ (UN pf) _, [arg]) <- unApply tm,
193 pf == txt "prim_fork"
194 = do arg' <- ir' env arg
195 return $ LOp LFork [LLazyExp arg']
196 | (P _ (UN m) _, [_,size,t]) <- unApply tm,
198 = do size' <- ir' env size
200 return t' -- TODO $ malloc_ size' t'
201 | (P _ (UN tm) _, [_,t]) <- unApply tm,
202 tm == txt "trace_malloc"
205-- | (P _ (NS (UN "S") ["Nat", "Prelude"]) _, [k]) <- unApply tm
206-- = do k' <- ir' env k
207-- return (LOp LBPlus [k', LConst (BI 1)])
208 | (P (DCon t a) n _, args) <- unApply tm
209 = irCon env t a n args
210 | (P (TCon t a) n _, args) <- unApply tm
212 | (P _ n _, args) <- unApply tm
214 args' <- mapM (ir' env) args
215 case getPrim i n args' of
219 = case lookupCtxtExact n
220 (idris_optimisation i) of
221 [oi] -> collapsible oi
224 = case lookupCtxtExact n
225 (idris_callgraph i) of
226 [CGInfo _ _ _ _ unusedpos] ->
231 else return (LApp False (LV (Glob n))
232 (mkUnused unused 0 args'))
233 | (f, args) <- unApply tm
235 args' <- mapM (ir' env) args
236 return (LApp False f' args')
237 where mkUnused u i [] = []
238 mkUnused u i (x : xs) | i `elem` u = LNothing : mkUnused u (i + 1) xs
239 | otherwise = x : mkUnused u (i + 1) xs
240-- ir' env (P _ (NS (UN "Z") ["Nat", "Prelude"]) _)
241-- = return $ LConst (BI 0)
242 ir' env (P _ n _) = return $ LV (Glob n)
243 ir' env (V i) | i >= 0 && i < length env = return $ LV (Glob (env!!i))
244 | otherwise = ifail $ "IR fail " ++ show i ++ " " ++ show tm
245 ir' env (Bind n (Lam _) sc)
246 = do let n' = uniqueName n env
247 sc' <- ir' (n' : env) sc
248 return $ LLam [n'] sc'
249 ir' env (Bind n (Let _ v) sc)
250 = do sc' <- ir' (n : env) sc
252 return $ LLet n v' sc'
253 ir' env (Bind _ _ _) = return $ LNothing
254 ir' env (Proj t i) | i == -1
256 return $ LOp (LMinus (ATInt ITBig))
258 ir' env (Proj t i) = do t' <- ir' env t
260 ir' env (Constant c) = return $ LConst c
261 ir' env (TType _) = return $ LNothing
262 ir' env Erased = return $ LNothing
263 ir' env Impossible = return $ LNothing
264-- ir' env _ = return $ LError "Impossible"
266 irCon env t arity n args
267 | length args == arity = buildApp env (LV (Glob n)) args
268 | otherwise = let extra = satArgs (arity - length args) in
269 do sc' <- irCon env t arity n
270 (args ++ map (\n -> P Bound n undefined) extra)
271 return $ LLam extra sc'
273 satArgs n = map (\i -> sMN i "sat") [1..n]
275 buildApp env e [] = return e
276 buildApp env e xs = do xs' <- mapM (ir' env) xs
277 return $ LApp False e xs'
279 doForeign :: [Name] -> [TT Name] -> Idris LExp
280 doForeign env (_ : fgn : args)
281 | (_, (Constant (Str fgnName) : fgnArgTys : ret : [])) <- unApply fgn
282 = let maybeTys = getFTypes fgnArgTys
285 Nothing -> ifail $ "Foreign type specification is not a constant list: " ++ show (fgn:args)
287 args' <- mapM (ir' env) (init args)
288 -- wrap it in a prim__IO
289 -- return $ con_ 0 @@ impossible @@
290 return $ -- LLazyExp $
291 LForeign LANG_C rty fgnName (zip tys args')
292 | otherwise = ifail "Badly formed foreign function call"
294getFTypes :: TT Name -> Maybe [FType]
295getFTypes tm = case unApply tm of
298 fmap (mkIty' ty :) (getFTypes xs)
301mkIty' (P _ (UN ty) _) = mkIty (str ty)
302mkIty' (App (P _ (UN fi) _) (P _ (UN intTy) _))
303 | fi == txt "FIntT" = mkIntIty (str intTy)
304mkIty' (App (App (P _ (UN ff) _) _) (App (P _ (UN fa) _) (App (P _ (UN io) _) _)))
305 | ff == txt "FFunction" && fa == txt "FAny" &&
308mkIty' (App (App (P _ (UN ff) _) _) _)
309 | ff == txt "FFunction" = FFunction
312-- would be better if these FInt types were evaluated at compile time
313-- TODO: add %eval directive for such things
315mkIty "FFloat" = FArith ATFloat
316mkIty "FInt" = mkIntIty "ITNative"
317mkIty "FChar" = mkIntIty "ITChar"
318mkIty "FByte" = mkIntIty "IT8"
319mkIty "FShort" = mkIntIty "IT16"
320mkIty "FLong" = mkIntIty "IT64"
321mkIty "FBits8" = mkIntIty "IT8"
322mkIty "FBits16" = mkIntIty "IT16"
323mkIty "FBits32" = mkIntIty "IT32"
324mkIty "FBits64" = mkIntIty "IT64"
325mkIty "FString" = FString
328mkIty "FFunction" = FFunction
329mkIty "FFunctionIO" = FFunctionIO
330mkIty "FBits8x16" = FArith (ATInt (ITVec IT8 16))
331mkIty "FBits16x8" = FArith (ATInt (ITVec IT16 8))
332mkIty "FBits32x4" = FArith (ATInt (ITVec IT32 4))
333mkIty "FBits64x2" = FArith (ATInt (ITVec IT64 2))
334mkIty x = error $ "Unknown type " ++ x
336mkIntIty "ITNative" = FArith (ATInt ITNative)
337mkIntIty "ITChar" = FArith (ATInt ITChar)
338mkIntIty "IT8" = FArith (ATInt (ITFixed IT8))
339mkIntIty "IT16" = FArith (ATInt (ITFixed IT16))
340mkIntIty "IT32" = FArith (ATInt (ITFixed IT32))
341mkIntIty "IT64" = FArith (ATInt (ITFixed IT64))
343zname = sNS (sUN "Z") ["Nat","Prelude"]
344sname = sNS (sUN "S") ["Nat","Prelude"]
346instance ToIR ([Name], SC) where
347 ir (args, tree) = do logLvl 3 $ "Compiling " ++ show args ++ "\n" ++ show tree
349 return $ LLam args tree'
351instance ToIR SC where
355 ir' (UnmatchedCase str) = return $ LError str
356 ir' (ProjCase tm alts) = do tm' <- ir tm
357 alts' <- mapM (mkIRAlt tm') alts
358 return $ LCase tm' alts'
359 ir' (Case n alts) = do alts' <- mapM (mkIRAlt (LV (Glob n))) alts
360 return $ LCase (LV (Glob n)) alts'
361 ir' ImpossibleCase = return LNothing
363 -- special cases for Z and S
364 -- Needs rethink: projections make this fail
365-- mkIRAlt n (ConCase z _ [] rhs) | z == zname
366-- = mkIRAlt n (ConstCase (BI 0) rhs)
367-- mkIRAlt n (ConCase s _ [arg] rhs) | s == sname
370-- return $ LDefaultCase
371-- (LLet arg (LOp LBMinus [n', LConst (BI 1)])
373 mkIRAlt _ (ConCase n t args rhs)
375 return $ LConCase (-1) n args rhs'
376 mkIRAlt _ (ConstCase x rhs)
379 return $ LConstCase x rhs'
382 return $ LDefaultCase rhs'
383 mkIRAlt tm (SucCase n rhs)
385 return $ LDefaultCase (LLet n (LOp (LMinus (ATInt ITBig))
387 LConst (BI 1)]) rhs')
388-- return $ LSucCase n rhs'
389 mkIRAlt _ (ConstCase c rhs)
390 = ifail $ "Can't match on (" ++ show c ++ ")"
391 mkIRAlt _ (DefaultCase rhs)
393 return $ LDefaultCase rhs'
395 matchable (I _) = True
396 matchable (BI _) = True
397 matchable (Ch _) = True
398 matchable (Str _) = True
401 matchableTy (AType (ATInt ITNative)) = True
402 matchableTy (AType (ATInt ITBig)) = True
403 matchableTy (AType (ATInt ITChar)) = True
404 matchableTy StrType = True
406 matchableTy (AType (ATInt (ITFixed IT8))) = True
407 matchableTy (AType (ATInt (ITFixed IT16))) = True
408 matchableTy (AType (ATInt (ITFixed IT32))) = True
409 matchableTy (AType (ATInt (ITFixed IT64))) = True
411 matchableTy _ = False
keysesc to close
- j k
- move down, up
- enter
- open
- esc
- back, or up a level
- 1 2 3 4
- readme, files, commits, refs
- /
- filter
- y
- copy the clone command
- c
- compare the chosen commit with another (or shift-click both)
- ?
- show or hide this list