1{-# LANGUAGE PatternGuards, TypeSynonymInstances, CPP #-}
3module IRTS.Compiler where
6import IRTS.Defunctionalise
8import IRTS.CodegenCommon
10import IRTS.CodegenJava
12import IRTS.CodegenJavaScript
14import IRTS.CodegenLLVM
25import Idris.Core.Evaluate
26import Idris.Core.CaseTree
28import Control.Monad.State
30import qualified Data.IntMap as IM
31import qualified Data.IntSet as IS
32import qualified Data.Map as M
33import qualified Data.Set as S
36import System.Directory
37import System.Environment
38import System.FilePath ((</>), addTrailingPathSeparator)
42compile :: Codegen -> FilePath -> Term -> Idris ()
45 let tmnames = namesUsed (STerm tm)
46 usedIn <- mapM (allNames []) tmnames
47 let used = sUN "prim__subBigInt" : sUN "prim__addBigInt" : concat usedIn
48 defsIn <- mkDecls tm used
51 -- TODO: traverse all names correctly
53 -- TODO: DEBUG-ONLY, remove
56 let depMap = buildDepMap (tt_ctxt ist) used
57 let printCond (ctors, cond) = "if " ++ show (S.toList cond) ++ " -ctors- " ++ show (S.toList ctors)
58 let printDep (i, conds) = unlines . map (" "++) $ (show i : map printCond (S.toList conds))
59 let printItem (fn, deps) = unlines (show fn : map printDep (IM.toList deps))
60 iLOG $ "USAGE ANALYSIS:\n" ++ unlines (map printItem . M.toList $ depMap)
62 let minUse = minimalUsage depMap
63 iLOG $ "MINIMAL USAGE:\n" ++ unlines (map (\(n,is) -> show n ++ " -> " ++ show (IS.toList is)) $ M.toList minUse)
68 objs <- getObjectFiles codegen
69 libs <- getLibs codegen
70 flags <- getFlags codegen
71 hdrs <- getHdrs codegen
72 impdirs <- allImportDirs
73 let defs = defsIn ++ [(sMN 0 "runMain", maindef)]
74 -- iputStrLn $ showSep "\n" (map show defs)
75 let (nexttag, tagged) = addTags 65536 (liftAll defs)
76 let ctxtIn = addAlist tagged emptyContext
77 iLOG "Defunctionalising"
78 let defuns_in = defunctionalise nexttag ctxtIn
79 logLvl 5 $ show defuns_in
81 let defuns = inline defuns_in
82 logLvl 5 $ show defuns
83 iLOG "Resolving variables for CG"
84 -- iputStrLn $ showSep "\n" (map show (toAlist defuns))
85 let checked = checkDefs defuns (toAlist defuns)
87 dumpCases <- getDumpCases
88 dumpDefun <- getDumpDefun
91 Just f -> runIO $ writeFile f (showCaseTrees defs)
94 Just f -> runIO $ writeFile f (dumpDefuns defuns)
95 triple <- Idris.AbsSyntax.targetTriple
96 cpu <- Idris.AbsSyntax.targetCPU
98 iLOG "Building output"
101 OK c -> do let cginfo = CodegenInfo f outty triple cpu optimise
102 hdrs impdirs objs libs flags
103 NONE c (toAlist defuns)
105 runIO $ case codegen of
106 ViaC -> codegenC cginfo
107 ViaJava -> codegenJava cginfo
108 ViaJavaScript -> codegenJavaScript cginfo
109 ViaNode -> codegenNode cginfo
110 ViaLLVM -> codegenLLVM cginfo
111 Bytecode -> dumpBC c f
113 where checkMVs = do i <- getIState
114 case map fst (idris_metavars i) \\ primDefs of
116 ms -> ifail $ "There are undefined metavariables: " ++ show ms
117 inDir d h = do let f = d </> h
118 ex <- doesFileExist f
119 if ex then return f else return h
121irMain :: TT Name -> Idris LDecl
122irMain tm = do i <- ir tm
123 return $ LFun [] (sMN 0 "runMain") [] (LForce i)
125mkDecls :: Term -> [Name] -> Idris [(Name, LDecl)]
128 let ds = filter (\ (n, d) -> n `elem` used || isCon d) $ ctxtAlist (tt_ctxt i)
130 decls <- mapM build ds
133showCaseTrees :: [(Name, LDecl)] -> String
134showCaseTrees ds = showSep "\n\n" (map showCT ds)
136 showCT (n, LFun _ f args lexp)
137 = show n ++ " " ++ showSep " " (map show args) ++ " =\n\t "
139 showCT (n, LConstructor c t a) = "data " ++ show n ++ " " ++ show a
141isCon (TyDecl _ _) = True
145 ir :: a -> Idris LExp
147build :: (Name, Def) -> Idris (Name, LDecl)
150 case lookup n (idris_scprims i) of
152 let args = map (\x -> sMN x "op") [0..] in
153 return (n, (LFun [] n (take ar args)
154 (LOp op (map (LV . Glob) (take ar args)))))
155 _ -> do def <- mkLDecl n d
156 logLvl 3 $ "Compiled " ++ show n ++ " =\n\t" ++ show def
159getPrim :: IState -> Name -> [LExp] -> Maybe LExp
160getPrim i n args = case lookup n (idris_scprims i) of
162 if (ar == length args)
163 then return (LOp op args)
167declArgs args inl n (LLam xs x) = declArgs (args ++ xs) inl n x
168declArgs args inl n x = LFun (if inl then [Inline] else []) n args x
170mkLDecl n (Function tm _) = do e <- ir tm
171 return (declArgs [] True n e)
172mkLDecl n (CaseOp ci _ _ _ pats cd)
173 = let (args, sc) = cases_runtime cd in
174 do e <- ir (args, sc)
175 return (declArgs [] (case_inlinable ci) n e)
176mkLDecl n (TyDecl (DCon t a) _) = return $ LConstructor n t a
177mkLDecl n (TyDecl (TCon t a) _) = return $ LConstructor n (-1) a
178mkLDecl n _ = return $ (declArgs [] True n LNothing) -- postulate, never run
180instance ToIR (TT Name) where
181 ir tm = ir' [] tm where
183 | (P _ (UN m) _, args) <- unApply tm,
184 m == txt "mkForeignPrim"
186 | (P _ (UN u) _, [_, arg]) <- unApply tm,
187 u == txt "unsafePerformPrimIO"
189 -- TMP HACK - until we get inlining.
190 | (P _ (UN r) _, [_, _, _, _, _, arg]) <- unApply tm,
193 -- Laziness, the old way
194 | (P _ (UN l) _, [_, arg]) <- unApply tm,
196 = do arg' <- ir' env arg
197 error "lazy has crept in somehow"
198-- return $ LLazyExp arg'
199 | (P _ (UN l) _, [_, arg]) <- unApply tm,
201 = do arg' <- ir' env arg
203 -- Laziness, the new way
204 | (P _ (UN l) _, [arg]) <- unApply tm,
206 = do arg' <- ir' env arg
207 return $ LLazyExp arg'
208 | (P _ (UN l) _, [_, _, arg]) <- unApply tm,
210 = do arg' <- ir' env arg
212 | (P _ (UN a) _, [_, _, arg]) <- unApply tm,
213 a == txt "assert_smaller"
215 | (P _ (UN a) _, [_, arg]) <- unApply tm,
216 a == txt "assert_total"
218 | (P _ (UN p) _, [_, arg]) <- unApply tm,
220 = do arg' <- ir' env arg
221 return $ LOp LPar [LLazyExp arg']
222 | (P _ (UN pf) _, [arg]) <- unApply tm,
223 pf == txt "prim_fork"
224 = do arg' <- ir' env arg
225 return $ LOp LFork [LLazyExp arg']
226 | (P _ (UN m) _, [_,size,t]) <- unApply tm,
228 = do size' <- ir' env size
230 return t' -- TODO $ malloc_ size' t'
231 | (P _ (UN tm) _, [_,t]) <- unApply tm,
232 tm == txt "trace_malloc"
235 -- This case is here until we get more general inlining. It's just
236 -- a really common case, and the laziness hurts...
237 | (P _ (NS (UN be) [b,p]) _, [_,x,(App (P _ (UN d) _) t),
238 (App (P _ (UN d') _) e)]) <- unApply tm,
239 be == txt "boolElim" && d == txt "Delay" && d' == txt "Delay"
243 return (LCase x' [LConCase 0 (sNS (sUN "False") ["Bool","Prelude"]) [] e',
244 LConCase 1 (sNS (sUN "True") ["Bool","Prelude"]) [] t'])
245 | (P (DCon t a) n _, args) <- unApply tm
246 = irCon env t a n args
247 | (P (TCon t a) n _, args) <- unApply tm
249 | (P _ n _, args) <- unApply tm
251 args' <- mapM (ir' env) args
252 case getPrim i n args' of
256 = case lookupCtxtExact n
257 (idris_optimisation i) of
258 Just oi -> collapsible oi
261 = case lookupCtxtExact n
262 (idris_callgraph i) of
263 Just (CGInfo _ _ _ _ unusedpos) ->
268 else return (LApp False (LV (Glob n))
269 (mkUnused unused 0 args'))
270 | (f, args) <- unApply tm
272 args' <- mapM (ir' env) args
273 return (LApp False f' args')
274 where mkUnused u i [] = []
275 mkUnused u i (x : xs) | i `elem` u = LNothing : mkUnused u (i + 1) xs
276 | otherwise = x : mkUnused u (i + 1) xs
277-- ir' env (P _ (NS (UN "Z") ["Nat", "Prelude"]) _)
278-- = return $ LConst (BI 0)
279 ir' env (P _ n _) = return $ LV (Glob n)
280 ir' env (V i) | i >= 0 && i < length env = return $ LV (Glob (env!!i))
281 | otherwise = ifail $ "IR fail " ++ show i ++ " " ++ show tm
282 ir' env (Bind n (Lam _) sc)
283 = do let n' = uniqueName n env
284 sc' <- ir' (n' : env) sc
285 return $ LLam [n'] sc'
286 ir' env (Bind n (Let _ v) sc)
287 = do sc' <- ir' (n : env) sc
289 return $ LLet n v' sc'
290 ir' env (Bind _ _ _) = return $ LNothing
291 ir' env (Proj t i) | i == -1
293 return $ LOp (LMinus (ATInt ITBig))
295 ir' env (Proj t i) = do t' <- ir' env t
297 ir' env (Constant c) = return $ LConst c
298 ir' env (TType _) = return $ LNothing
299 ir' env Erased = return $ LNothing
300 ir' env Impossible = return $ LNothing
301-- ir' env _ = return $ LError "Impossible"
303 irCon env t arity n args
304 | length args == arity = buildApp env (LV (Glob n)) args
305 | otherwise = let extra = satArgs (arity - length args) in
306 do sc' <- irCon env t arity n
307 (args ++ map (\n -> P Bound n undefined) extra)
308 return $ LLam extra sc'
310 satArgs n = map (\i -> sMN i "sat") [1..n]
312 buildApp env e [] = return e
313 buildApp env e xs = do xs' <- mapM (ir' env) xs
314 return $ LApp False e xs'
316 doForeign :: [Name] -> [TT Name] -> Idris LExp
317 doForeign env (_ : fgn : args)
318 | (_, (Constant (Str fgnName) : fgnArgTys : ret : [])) <- unApply fgn
319 = let maybeTys = getFTypes fgnArgTys
322 Nothing -> ifail $ "Foreign type specification is not a constant list: " ++ show (fgn:args)
324 args' <- mapM (ir' env) (init args)
325 -- wrap it in a prim__IO
326 -- return $ con_ 0 @@ impossible @@
327 return $ -- LLazyExp $
328 LForeign LANG_C rty fgnName (zip tys args')
329 | otherwise = ifail "Badly formed foreign function call"
331getFTypes :: TT Name -> Maybe [FType]
332getFTypes tm = case unApply tm of
335 fmap (mkIty' ty :) (getFTypes xs)
338mkIty' (P _ (UN ty) _) = mkIty (str ty)
339mkIty' (App (P _ (UN fi) _) (P _ (UN intTy) _))
340 | fi == txt "FIntT" = mkIntIty (str intTy)
341mkIty' (App (App (P _ (UN ff) _) _) (App (P _ (UN fa) _) (App (P _ (UN io) _) _)))
342 | ff == txt "FFunction" && fa == txt "FAny" &&
345mkIty' (App (App (P _ (UN ff) _) _) _)
346 | ff == txt "FFunction" = FFunction
349-- would be better if these FInt types were evaluated at compile time
350-- TODO: add %eval directive for such things
352mkIty "FFloat" = FArith ATFloat
353mkIty "FInt" = mkIntIty "ITNative"
354mkIty "FChar" = mkIntIty "ITChar"
355mkIty "FByte" = mkIntIty "IT8"
356mkIty "FShort" = mkIntIty "IT16"
357mkIty "FLong" = mkIntIty "IT64"
358mkIty "FBits8" = mkIntIty "IT8"
359mkIty "FBits16" = mkIntIty "IT16"
360mkIty "FBits32" = mkIntIty "IT32"
361mkIty "FBits64" = mkIntIty "IT64"
362mkIty "FString" = FString
364mkIty "FManagedPtr" = FManagedPtr
366mkIty "FFunction" = FFunction
367mkIty "FFunctionIO" = FFunctionIO
368mkIty "FBits8x16" = FArith (ATInt (ITVec IT8 16))
369mkIty "FBits16x8" = FArith (ATInt (ITVec IT16 8))
370mkIty "FBits32x4" = FArith (ATInt (ITVec IT32 4))
371mkIty "FBits64x2" = FArith (ATInt (ITVec IT64 2))
372mkIty x = error $ "Unknown type " ++ x
374mkIntIty "ITNative" = FArith (ATInt ITNative)
375mkIntIty "ITChar" = FArith (ATInt ITChar)
376mkIntIty "IT8" = FArith (ATInt (ITFixed IT8))
377mkIntIty "IT16" = FArith (ATInt (ITFixed IT16))
378mkIntIty "IT32" = FArith (ATInt (ITFixed IT32))
379mkIntIty "IT64" = FArith (ATInt (ITFixed IT64))
381zname = sNS (sUN "Z") ["Nat","Prelude"]
382sname = sNS (sUN "S") ["Nat","Prelude"]
384instance ToIR ([Name], SC) where
385 ir (args, tree) = do logLvl 3 $ "Compiling " ++ show args ++ "\n" ++ show tree
387 return $ LLam args tree'
389instance ToIR SC where
393 ir' (UnmatchedCase str) = return $ LError str
394 ir' (ProjCase tm alt) = do tm' <- ir tm
395 alt' <- mkIRAlt tm' alt
396 return $ LCase tm' [alt']
397 ir' (Case n alts) = do alts' <- mapM (mkIRAlt (LV (Glob n))) alts
398 return $ LCase (LV (Glob n)) alts'
399 ir' ImpossibleCase = return LNothing
401 -- special cases for Z and S
402 -- Needs rethink: projections make this fail
403-- mkIRAlt n (ConCase z _ [] rhs) | z == zname
404-- = mkIRAlt n (ConstCase (BI 0) rhs)
405-- mkIRAlt n (ConCase s _ [arg] rhs) | s == sname
408-- return $ LDefaultCase
409-- (LLet arg (LOp LBMinus [n', LConst (BI 1)])
411 mkIRAlt _ (ConCase n t args rhs)
413 return $ LConCase (-1) n args rhs'
414 mkIRAlt _ (ConstCase x rhs)
417 return $ LConstCase x rhs'
420 return $ LDefaultCase rhs'
421 mkIRAlt tm (SucCase n rhs)
423 return $ LDefaultCase (LLet n (LOp (LMinus (ATInt ITBig))
425 LConst (BI 1)]) rhs')
426-- return $ LSucCase n rhs'
427 mkIRAlt _ (ConstCase c rhs)
428 = ifail $ "Can't match on (" ++ show c ++ ")"
429 mkIRAlt _ (DefaultCase rhs)
431 return $ LDefaultCase rhs'
433 matchable (I _) = True
434 matchable (BI _) = True
435 matchable (Ch _) = True
436 matchable (Str _) = True
439 matchableTy (AType (ATInt ITNative)) = True
440 matchableTy (AType (ATInt ITBig)) = True
441 matchableTy (AType (ATInt ITChar)) = True
442 matchableTy StrType = True
444 matchableTy (AType (ATInt (ITFixed IT8))) = True
445 matchableTy (AType (ATInt (ITFixed IT16))) = True
446 matchableTy (AType (ATInt (ITFixed IT32))) = True
447 matchableTy (AType (ATInt (ITFixed IT64))) = True
449 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