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.Applicative
29import Control.Monad.State
31import qualified Data.IntMap as IM
32import qualified Data.IntSet as IS
33import qualified Data.Map as M
34import qualified Data.Set as S
37import System.Directory
38import System.Environment
39import System.FilePath ((</>), addTrailingPathSeparator)
43compile :: Codegen -> FilePath -> Term -> Idris ()
46 let tmnames = namesUsed (STerm tm)
47 usedIn <- mapM (allNames []) tmnames
48 let used = sUN "prim__subBigInt" : sUN "prim__addBigInt" : concat usedIn
49 defsIn <- mkDecls tm used
52 -- TODO: traverse all names correctly
54 -- TODO: DEBUG-ONLY, remove
55 ctx <- tt_ctxt <$> getIState
56 let depMap = buildDepMap ctx used
57 let printItem (cond, deps) = show (S.toList cond) ++ " -> " ++ show (S.toList deps)
58 iLOG $ "USAGE ANALYSIS:\n" ++ unlines (map printItem . M.toList $ depMap)
60 let fmtDepMap = unlines . map (\(n,is) -> show n ++ " -> " ++ show (IS.toList is)) . M.toList
61 let minUse = minimalUsage depMap
62 iLOG $ "MINIMAL USAGE:\n" ++ fmtDepMap minUse
64 let unusedMap = usedToUnused ctx minUse
65 iLOG $ "UNUSED:\n" ++ fmtDepMap unusedMap
69 objs <- getObjectFiles codegen
70 libs <- getLibs codegen
71 flags <- getFlags codegen
72 hdrs <- getHdrs codegen
73 impdirs <- allImportDirs
74 let defs = defsIn ++ [(sMN 0 "runMain", maindef)]
75 -- iputStrLn $ showSep "\n" (map show defs)
76 let (nexttag, tagged) = addTags 65536 (liftAll defs)
77 let ctxtIn = addAlist tagged emptyContext
78 iLOG "Defunctionalising"
79 let defuns_in = defunctionalise nexttag ctxtIn
80 logLvl 5 $ show defuns_in
82 let defuns = inline defuns_in
83 logLvl 5 $ show defuns
84 iLOG "Resolving variables for CG"
85 -- iputStrLn $ showSep "\n" (map show (toAlist defuns))
86 let checked = checkDefs defuns (toAlist defuns)
88 dumpCases <- getDumpCases
89 dumpDefun <- getDumpDefun
92 Just f -> runIO $ writeFile f (showCaseTrees defs)
95 Just f -> runIO $ writeFile f (dumpDefuns defuns)
96 triple <- Idris.AbsSyntax.targetTriple
97 cpu <- Idris.AbsSyntax.targetCPU
99 iLOG "Building output"
102 OK c -> do let cginfo = CodegenInfo f outty triple cpu optimise
103 hdrs impdirs objs libs flags
104 NONE c (toAlist defuns)
106 runIO $ case codegen of
107 ViaC -> codegenC cginfo
108 ViaJava -> codegenJava cginfo
109 ViaJavaScript -> codegenJavaScript cginfo
110 ViaNode -> codegenNode cginfo
111 ViaLLVM -> codegenLLVM cginfo
112 Bytecode -> dumpBC c f
114 where checkMVs = do i <- getIState
115 case map fst (idris_metavars i) \\ primDefs of
117 ms -> ifail $ "There are undefined metavariables: " ++ show ms
118 inDir d h = do let f = d </> h
119 ex <- doesFileExist f
120 if ex then return f else return h
122irMain :: TT Name -> Idris LDecl
123irMain tm = do i <- ir tm
124 return $ LFun [] (sMN 0 "runMain") [] (LForce i)
126mkDecls :: Term -> [Name] -> Idris [(Name, LDecl)]
129 let ds = filter (\ (n, d) -> n `elem` used || isCon d) $ ctxtAlist (tt_ctxt i)
131 decls <- mapM build ds
134showCaseTrees :: [(Name, LDecl)] -> String
135showCaseTrees ds = showSep "\n\n" (map showCT ds)
137 showCT (n, LFun _ f args lexp)
138 = show n ++ " " ++ showSep " " (map show args) ++ " =\n\t "
140 showCT (n, LConstructor c t a) = "data " ++ show n ++ " " ++ show a
142isCon (TyDecl _ _) = True
146 ir :: a -> Idris LExp
148build :: (Name, Def) -> Idris (Name, LDecl)
151 case lookup n (idris_scprims i) of
153 let args = map (\x -> sMN x "op") [0..] in
154 return (n, (LFun [] n (take ar args)
155 (LOp op (map (LV . Glob) (take ar args)))))
156 _ -> do def <- mkLDecl n d
157 logLvl 3 $ "Compiled " ++ show n ++ " =\n\t" ++ show def
160getPrim :: IState -> Name -> [LExp] -> Maybe LExp
161getPrim i n args = case lookup n (idris_scprims i) of
163 if (ar == length args)
164 then return (LOp op args)
168declArgs args inl n (LLam xs x) = declArgs (args ++ xs) inl n x
169declArgs args inl n x = LFun (if inl then [Inline] else []) n args x
171mkLDecl n (Function tm _) = do e <- ir tm
172 return (declArgs [] True n e)
173mkLDecl n (CaseOp ci _ _ _ pats cd)
174 = let (args, sc) = cases_runtime cd in
175 do e <- ir (args, sc)
176 return (declArgs [] (case_inlinable ci) n e)
177mkLDecl n (TyDecl (DCon t a) _) = return $ LConstructor n t a
178mkLDecl n (TyDecl (TCon t a) _) = return $ LConstructor n (-1) a
179mkLDecl n _ = return $ (declArgs [] True n LNothing) -- postulate, never run
181instance ToIR (TT Name) where
182 ir tm = ir' [] tm where
184 | (P _ (UN m) _, args) <- unApply tm,
185 m == txt "mkForeignPrim"
187 | (P _ (UN u) _, [_, arg]) <- unApply tm,
188 u == txt "unsafePerformPrimIO"
190 -- TMP HACK - until we get inlining.
191 | (P _ (UN r) _, [_, _, _, _, _, arg]) <- unApply tm,
194 -- Laziness, the old way
195 | (P _ (UN l) _, [_, arg]) <- unApply tm,
197 = do arg' <- ir' env arg
198 error "lazy has crept in somehow"
199-- return $ LLazyExp arg'
200 | (P _ (UN l) _, [_, arg]) <- unApply tm,
202 = do arg' <- ir' env arg
204 -- Laziness, the new way
205 | (P _ (UN l) _, [arg]) <- unApply tm,
207 = do arg' <- ir' env arg
208 return $ LLazyExp arg'
209 | (P _ (UN l) _, [_, _, arg]) <- unApply tm,
211 = do arg' <- ir' env arg
213 | (P _ (UN a) _, [_, _, arg]) <- unApply tm,
214 a == txt "assert_smaller"
216 | (P _ (UN a) _, [_, arg]) <- unApply tm,
217 a == txt "assert_total"
219 | (P _ (UN p) _, [_, arg]) <- unApply tm,
221 = do arg' <- ir' env arg
222 return $ LOp LPar [LLazyExp arg']
223 | (P _ (UN pf) _, [arg]) <- unApply tm,
224 pf == txt "prim_fork"
225 = do arg' <- ir' env arg
226 return $ LOp LFork [LLazyExp arg']
227 | (P _ (UN m) _, [_,size,t]) <- unApply tm,
229 = do size' <- ir' env size
231 return t' -- TODO $ malloc_ size' t'
232 | (P _ (UN tm) _, [_,t]) <- unApply tm,
233 tm == txt "trace_malloc"
236 -- This case is here until we get more general inlining. It's just
237 -- a really common case, and the laziness hurts...
238 | (P _ (NS (UN be) [b,p]) _, [_,x,(App (P _ (UN d) _) t),
239 (App (P _ (UN d') _) e)]) <- unApply tm,
240 be == txt "boolElim" && d == txt "Delay" && d' == txt "Delay"
244 return (LCase x' [LConCase 0 (sNS (sUN "False") ["Bool","Prelude"]) [] e',
245 LConCase 1 (sNS (sUN "True") ["Bool","Prelude"]) [] t'])
246 | (P (DCon t a) n _, args) <- unApply tm
247 = irCon env t a n args
248 | (P (TCon t a) n _, args) <- unApply tm
250 | (P _ n _, args) <- unApply tm
252 args' <- mapM (ir' env) args
253 case getPrim i n args' of
257 = case lookupCtxtExact n
258 (idris_optimisation i) of
259 Just oi -> collapsible oi
262 = case lookupCtxtExact n
263 (idris_callgraph i) of
264 Just (CGInfo _ _ _ _ unusedpos) ->
269 else return (LApp False (LV (Glob n))
270 (mkUnused unused 0 args'))
271 | (f, args) <- unApply tm
273 args' <- mapM (ir' env) args
274 return (LApp False f' args')
275 where mkUnused u i [] = []
276 mkUnused u i (x : xs) | i `elem` u = LNothing : mkUnused u (i + 1) xs
277 | otherwise = x : mkUnused u (i + 1) xs
278-- ir' env (P _ (NS (UN "Z") ["Nat", "Prelude"]) _)
279-- = return $ LConst (BI 0)
280 ir' env (P _ n _) = return $ LV (Glob n)
281 ir' env (V i) | i >= 0 && i < length env = return $ LV (Glob (env!!i))
282 | otherwise = ifail $ "IR fail " ++ show i ++ " " ++ show tm
283 ir' env (Bind n (Lam _) sc)
284 = do let n' = uniqueName n env
285 sc' <- ir' (n' : env) sc
286 return $ LLam [n'] sc'
287 ir' env (Bind n (Let _ v) sc)
288 = do sc' <- ir' (n : env) sc
290 return $ LLet n v' sc'
291 ir' env (Bind _ _ _) = return $ LNothing
292 ir' env (Proj t i) | i == -1
294 return $ LOp (LMinus (ATInt ITBig))
296 ir' env (Proj t i) = do t' <- ir' env t
298 ir' env (Constant c) = return $ LConst c
299 ir' env (TType _) = return $ LNothing
300 ir' env Erased = return $ LNothing
301 ir' env Impossible = return $ LNothing
302-- ir' env _ = return $ LError "Impossible"
304 irCon env t arity n args
305 | length args == arity = buildApp env (LV (Glob n)) args
306 | otherwise = let extra = satArgs (arity - length args) in
307 do sc' <- irCon env t arity n
308 (args ++ map (\n -> P Bound n undefined) extra)
309 return $ LLam extra sc'
311 satArgs n = map (\i -> sMN i "sat") [1..n]
313 buildApp env e [] = return e
314 buildApp env e xs = do xs' <- mapM (ir' env) xs
315 return $ LApp False e xs'
317 doForeign :: [Name] -> [TT Name] -> Idris LExp
318 doForeign env (_ : fgn : args)
319 | (_, (Constant (Str fgnName) : fgnArgTys : ret : [])) <- unApply fgn
320 = let maybeTys = getFTypes fgnArgTys
323 Nothing -> ifail $ "Foreign type specification is not a constant list: " ++ show (fgn:args)
325 args' <- mapM (ir' env) (init args)
326 -- wrap it in a prim__IO
327 -- return $ con_ 0 @@ impossible @@
328 return $ -- LLazyExp $
329 LForeign LANG_C rty fgnName (zip tys args')
330 | otherwise = ifail "Badly formed foreign function call"
332getFTypes :: TT Name -> Maybe [FType]
333getFTypes tm = case unApply tm of
336 fmap (mkIty' ty :) (getFTypes xs)
339mkIty' (P _ (UN ty) _) = mkIty (str ty)
340mkIty' (App (P _ (UN fi) _) (P _ (UN intTy) _))
341 | fi == txt "FIntT" = mkIntIty (str intTy)
342mkIty' (App (App (P _ (UN ff) _) _) (App (P _ (UN fa) _) (App (P _ (UN io) _) _)))
343 | ff == txt "FFunction" && fa == txt "FAny" &&
346mkIty' (App (App (P _ (UN ff) _) _) _)
347 | ff == txt "FFunction" = FFunction
350-- would be better if these FInt types were evaluated at compile time
351-- TODO: add %eval directive for such things
353mkIty "FFloat" = FArith ATFloat
354mkIty "FInt" = mkIntIty "ITNative"
355mkIty "FChar" = mkIntIty "ITChar"
356mkIty "FByte" = mkIntIty "IT8"
357mkIty "FShort" = mkIntIty "IT16"
358mkIty "FLong" = mkIntIty "IT64"
359mkIty "FBits8" = mkIntIty "IT8"
360mkIty "FBits16" = mkIntIty "IT16"
361mkIty "FBits32" = mkIntIty "IT32"
362mkIty "FBits64" = mkIntIty "IT64"
363mkIty "FString" = FString
365mkIty "FManagedPtr" = FManagedPtr
367mkIty "FFunction" = FFunction
368mkIty "FFunctionIO" = FFunctionIO
369mkIty "FBits8x16" = FArith (ATInt (ITVec IT8 16))
370mkIty "FBits16x8" = FArith (ATInt (ITVec IT16 8))
371mkIty "FBits32x4" = FArith (ATInt (ITVec IT32 4))
372mkIty "FBits64x2" = FArith (ATInt (ITVec IT64 2))
373mkIty x = error $ "Unknown type " ++ x
375mkIntIty "ITNative" = FArith (ATInt ITNative)
376mkIntIty "ITChar" = FArith (ATInt ITChar)
377mkIntIty "IT8" = FArith (ATInt (ITFixed IT8))
378mkIntIty "IT16" = FArith (ATInt (ITFixed IT16))
379mkIntIty "IT32" = FArith (ATInt (ITFixed IT32))
380mkIntIty "IT64" = FArith (ATInt (ITFixed IT64))
382zname = sNS (sUN "Z") ["Nat","Prelude"]
383sname = sNS (sUN "S") ["Nat","Prelude"]
385instance ToIR ([Name], SC) where
386 ir (args, tree) = do logLvl 3 $ "Compiling " ++ show args ++ "\n" ++ show tree
388 return $ LLam args tree'
390instance ToIR SC where
394 ir' (UnmatchedCase str) = return $ LError str
395 ir' (ProjCase tm alt) = do tm' <- ir tm
396 alt' <- mkIRAlt tm' alt
397 return $ LCase tm' [alt']
398 ir' (Case n alts) = do alts' <- mapM (mkIRAlt (LV (Glob n))) alts
399 return $ LCase (LV (Glob n)) alts'
400 ir' ImpossibleCase = return LNothing
402 -- special cases for Z and S
403 -- Needs rethink: projections make this fail
404-- mkIRAlt n (ConCase z _ [] rhs) | z == zname
405-- = mkIRAlt n (ConstCase (BI 0) rhs)
406-- mkIRAlt n (ConCase s _ [arg] rhs) | s == sname
409-- return $ LDefaultCase
410-- (LLet arg (LOp LBMinus [n', LConst (BI 1)])
412 mkIRAlt _ (ConCase n t args rhs)
414 return $ LConCase (-1) n args rhs'
415 mkIRAlt _ (ConstCase x rhs)
418 return $ LConstCase x rhs'
421 return $ LDefaultCase rhs'
422 mkIRAlt tm (SucCase n rhs)
424 return $ LDefaultCase (LLet n (LOp (LMinus (ATInt ITBig))
426 LConst (BI 1)]) rhs')
427-- return $ LSucCase n rhs'
428 mkIRAlt _ (ConstCase c rhs)
429 = ifail $ "Can't match on (" ++ show c ++ ")"
430 mkIRAlt _ (DefaultCase rhs)
432 return $ LDefaultCase rhs'
434 matchable (I _) = True
435 matchable (BI _) = True
436 matchable (Ch _) = True
437 matchable (Str _) = True
440 matchableTy (AType (ATInt ITNative)) = True
441 matchableTy (AType (ATInt ITBig)) = True
442 matchableTy (AType (ATInt ITChar)) = True
443 matchableTy StrType = True
445 matchableTy (AType (ATInt (ITFixed IT8))) = True
446 matchableTy (AType (ATInt (ITFixed IT16))) = True
447 matchableTy (AType (ATInt (ITFixed IT32))) = True
448 matchableTy (AType (ATInt (ITFixed IT64))) = True
450 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