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 Data.IntSet (IntSet)
32import qualified Data.IntMap as IM
33import qualified Data.IntSet as IS
34import qualified Data.Map as M
35import qualified Data.Set as S
38import System.Directory
39import System.Environment
40import System.FilePath ((</>), addTrailingPathSeparator)
44compile :: Codegen -> FilePath -> Term -> Idris ()
47 let tmnames = namesUsed (STerm tm)
48 usedIn <- mapM (allNames []) tmnames
49 let used = sUN "prim__subBigInt" : sUN "prim__addBigInt" : concat usedIn
51 -- TODO: DEBUG-ONLY, remove
52 ctx <- tt_ctxt <$> getIState
53 let depMap = buildDepMap ctx used
54 let printItem (cond, deps) = show (S.toList cond) ++ " -> " ++ show (S.toList deps)
55 iLOG $ "USAGE ANALYSIS:\n" ++ unlines (map printItem . M.toList $ depMap)
57 let fmtDepMap = unlines . map (\(n,is) -> show n ++ " -> " ++ show (IS.toList is)) . M.toList
58 let (reachableNames, minUse) = minimalUsage depMap
59 iLOG $ "REACHABLE NAMES: " ++ show (S.toList reachableNames)
60 iLOG $ "MINIMAL USAGE:\n" ++ fmtDepMap minUse
62 mapM_ (uncurry storeUsage) (M.toList minUse)
66 iLOG $ "MAIN: " ++ show maindef
67 iLOG $ "USED: " ++ show used
68 objs <- getObjectFiles codegen
69 libs <- getLibs codegen
70 flags <- getFlags codegen
71 hdrs <- getHdrs codegen
72 impdirs <- allImportDirs
73 defsIn <- mkDecls tm used
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
122storeUsage :: Name -> IntSet -> Idris ()
123storeUsage n args = do
124 cg <- idris_callgraph <$> getIState
125 case lookupCtxt n cg of
126 [x] -> addToCG n x{ usedpos = IS.toList args }
129irMain :: TT Name -> Idris LDecl
130irMain tm = do i <- ir tm
131 return $ LFun [] (sMN 0 "runMain") [] (LForce i)
133mkDecls :: Term -> [Name] -> Idris [(Name, LDecl)]
136 let ds = filter (\ (n, d) -> n `elem` used || isCon d) $ ctxtAlist (tt_ctxt i)
137 decls <- mapM build ds
140showCaseTrees :: [(Name, LDecl)] -> String
141showCaseTrees ds = showSep "\n\n" (map showCT ds)
143 showCT (n, LFun _ f args lexp)
144 = show n ++ " " ++ showSep " " (map show args) ++ " =\n\t "
146 showCT (n, LConstructor c t a) = "data " ++ show n ++ " " ++ show a
148isCon (TyDecl _ _) = True
152 ir :: a -> Idris LExp
154build :: (Name, Def) -> Idris (Name, LDecl)
157 case lookup n (idris_scprims i) of
159 let args = map (\x -> sMN x "op") [0..] in
160 return (n, (LFun [] n (take ar args)
161 (LOp op (map (LV . Glob) (take ar args)))))
162 _ -> do def <- mkLDecl n d
163 logLvl 3 $ "Compiled " ++ show n ++ " =\n\t" ++ show def
166getPrim :: IState -> Name -> [LExp] -> Maybe LExp
167getPrim i n args = case lookup n (idris_scprims i) of
169 if (ar == length args)
170 then return (LOp op args)
174declArgs args inl n (LLam xs x) = declArgs (args ++ xs) inl n x
175declArgs args inl n x = LFun (if inl then [Inline] else []) n args x
177mkLDecl n (Function tm _) = do e <- ir tm
178 return (declArgs [] True n e)
179mkLDecl n (CaseOp ci _ _ _ pats cd)
180 = let (args, sc) = cases_runtime cd in
181 do e <- ir (args, sc)
182 return (declArgs [] (case_inlinable ci) n e)
183mkLDecl n (TyDecl (DCon t a) _) = return $ LConstructor n t a
184mkLDecl n (TyDecl (TCon t a) _) = return $ LConstructor n (-1) a
185mkLDecl n _ = return $ (declArgs [] True n LNothing) -- postulate, never run
187instance ToIR (TT Name) where
188 ir tm = ir' [] tm where
190 | (P _ (UN m) _, args) <- unApply tm,
191 m == txt "mkForeignPrim"
193 | (P _ (UN u) _, [_, arg]) <- unApply tm,
194 u == txt "unsafePerformPrimIO"
196 -- TMP HACK - until we get inlining.
197 | (P _ (UN r) _, [_, _, _, _, _, arg]) <- unApply tm,
200 -- Laziness, the old way
201 | (P _ (UN l) _, [_, arg]) <- unApply tm,
203 = do arg' <- ir' env arg
204 error "lazy has crept in somehow"
205-- return $ LLazyExp arg'
206 | (P _ (UN l) _, [_, arg]) <- unApply tm,
208 = do arg' <- ir' env arg
210 -- Laziness, the new way
211 | (P _ (UN l) _, [arg]) <- unApply tm,
213 = do arg' <- ir' env arg
214 return $ LLazyExp arg'
215 | (P _ (UN l) _, [_, _, arg]) <- unApply tm,
217 = do arg' <- ir' env arg
219 | (P _ (UN a) _, [_, _, arg]) <- unApply tm,
220 a == txt "assert_smaller"
222 | (P _ (UN a) _, [_, arg]) <- unApply tm,
223 a == txt "assert_total"
225 | (P _ (UN p) _, [_, arg]) <- unApply tm,
227 = do arg' <- ir' env arg
228 return $ LOp LPar [LLazyExp arg']
229 | (P _ (UN pf) _, [arg]) <- unApply tm,
230 pf == txt "prim_fork"
231 = do arg' <- ir' env arg
232 return $ LOp LFork [LLazyExp arg']
233 | (P _ (UN m) _, [_,size,t]) <- unApply tm,
235 = do size' <- ir' env size
237 return t' -- TODO $ malloc_ size' t'
238 | (P _ (UN tm) _, [_,t]) <- unApply tm,
239 tm == txt "trace_malloc"
242 -- This case is here until we get more general inlining. It's just
243 -- a really common case, and the laziness hurts...
244 | (P _ (NS (UN be) [b,p]) _, [_,x,(App (P _ (UN d) _) t),
245 (App (P _ (UN d') _) e)]) <- unApply tm,
246 be == txt "boolElim" && d == txt "Delay" && d' == txt "Delay"
250 return (LCase x' [LConCase 0 (sNS (sUN "False") ["Bool","Prelude"]) [] e',
251 LConCase 1 (sNS (sUN "True") ["Bool","Prelude"]) [] t'])
252 | (P (DCon t a) n _, args) <- unApply tm
253 = irCon env t a n args
254 | (P (TCon t a) n _, args) <- unApply tm
256 | (P _ n _, args) <- unApply tm
258 args' <- mapM (ir' env) args
259 case getPrim i n args' of
263 = case lookupCtxtExact n
264 (idris_optimisation i) of
265 Just oi -> collapsible oi
268 = case lookupCtxtExact n
269 (idris_callgraph i) of
270 Just (CGInfo _ _ _ _ usedpos) ->
272 _ -> [] -- TODO: is this correct?
275 else return (LApp False (LV (Glob n))
276 (mkUsed used 0 args'))
277 | (f, args) <- unApply tm
279 args' <- mapM (ir' env) args
280 return (LApp False f' args')
281 where mkUsed u i [] = []
282 mkUsed u i (x : xs) | i `elem` u = x : mkUsed u (i + 1) xs
283 | otherwise = LNothing : mkUsed u (i + 1) xs
284-- ir' env (P _ (NS (UN "Z") ["Nat", "Prelude"]) _)
285-- = return $ LConst (BI 0)
286 ir' env (P _ n _) = return $ LV (Glob n)
287 ir' env (V i) | i >= 0 && i < length env = return $ LV (Glob (env!!i))
288 | otherwise = ifail $ "IR fail " ++ show i ++ " " ++ show tm
289 ir' env (Bind n (Lam _) sc)
290 = do let n' = uniqueName n env
291 sc' <- ir' (n' : env) sc
292 return $ LLam [n'] sc'
293 ir' env (Bind n (Let _ v) sc)
294 = do sc' <- ir' (n : env) sc
296 return $ LLet n v' sc'
297 ir' env (Bind _ _ _) = return $ LNothing
298 ir' env (Proj t i) | i == -1
300 return $ LOp (LMinus (ATInt ITBig))
302 ir' env (Proj t i) = do t' <- ir' env t
304 ir' env (Constant c) = return $ LConst c
305 ir' env (TType _) = return $ LNothing
306 ir' env Erased = return $ LNothing
307 ir' env Impossible = return $ LNothing
308-- ir' env _ = return $ LError "Impossible"
310 irCon env t arity n args
311 | length args == arity = buildApp env (LV (Glob n)) args
312 | otherwise = let extra = satArgs (arity - length args) in
313 do sc' <- irCon env t arity n
314 (args ++ map (\n -> P Bound n undefined) extra)
315 return $ LLam extra sc'
317 satArgs n = map (\i -> sMN i "sat") [1..n]
319 buildApp env e [] = return e
320 buildApp env e xs = do xs' <- mapM (ir' env) xs
321 return $ LApp False e xs'
323 doForeign :: [Name] -> [TT Name] -> Idris LExp
324 doForeign env (_ : fgn : args)
325 | (_, (Constant (Str fgnName) : fgnArgTys : ret : [])) <- unApply fgn
326 = let maybeTys = getFTypes fgnArgTys
329 Nothing -> ifail $ "Foreign type specification is not a constant list: " ++ show (fgn:args)
331 args' <- mapM (ir' env) (init args)
332 -- wrap it in a prim__IO
333 -- return $ con_ 0 @@ impossible @@
334 return $ -- LLazyExp $
335 LForeign LANG_C rty fgnName (zip tys args')
336 | otherwise = ifail "Badly formed foreign function call"
338getFTypes :: TT Name -> Maybe [FType]
339getFTypes tm = case unApply tm of
342 fmap (mkIty' ty :) (getFTypes xs)
345mkIty' (P _ (UN ty) _) = mkIty (str ty)
346mkIty' (App (P _ (UN fi) _) (P _ (UN intTy) _))
347 | fi == txt "FIntT" = mkIntIty (str intTy)
348mkIty' (App (App (P _ (UN ff) _) _) (App (P _ (UN fa) _) (App (P _ (UN io) _) _)))
349 | ff == txt "FFunction" && fa == txt "FAny" &&
352mkIty' (App (App (P _ (UN ff) _) _) _)
353 | ff == txt "FFunction" = FFunction
356-- would be better if these FInt types were evaluated at compile time
357-- TODO: add %eval directive for such things
359mkIty "FFloat" = FArith ATFloat
360mkIty "FInt" = mkIntIty "ITNative"
361mkIty "FChar" = mkIntIty "ITChar"
362mkIty "FByte" = mkIntIty "IT8"
363mkIty "FShort" = mkIntIty "IT16"
364mkIty "FLong" = mkIntIty "IT64"
365mkIty "FBits8" = mkIntIty "IT8"
366mkIty "FBits16" = mkIntIty "IT16"
367mkIty "FBits32" = mkIntIty "IT32"
368mkIty "FBits64" = mkIntIty "IT64"
369mkIty "FString" = FString
371mkIty "FManagedPtr" = FManagedPtr
373mkIty "FFunction" = FFunction
374mkIty "FFunctionIO" = FFunctionIO
375mkIty "FBits8x16" = FArith (ATInt (ITVec IT8 16))
376mkIty "FBits16x8" = FArith (ATInt (ITVec IT16 8))
377mkIty "FBits32x4" = FArith (ATInt (ITVec IT32 4))
378mkIty "FBits64x2" = FArith (ATInt (ITVec IT64 2))
379mkIty x = error $ "Unknown type " ++ x
381mkIntIty "ITNative" = FArith (ATInt ITNative)
382mkIntIty "ITChar" = FArith (ATInt ITChar)
383mkIntIty "IT8" = FArith (ATInt (ITFixed IT8))
384mkIntIty "IT16" = FArith (ATInt (ITFixed IT16))
385mkIntIty "IT32" = FArith (ATInt (ITFixed IT32))
386mkIntIty "IT64" = FArith (ATInt (ITFixed IT64))
388zname = sNS (sUN "Z") ["Nat","Prelude"]
389sname = sNS (sUN "S") ["Nat","Prelude"]
391instance ToIR ([Name], SC) where
392 ir (args, tree) = do logLvl 3 $ "Compiling " ++ show args ++ "\n" ++ show tree
394 return $ LLam args tree'
396instance ToIR SC where
400 ir' (UnmatchedCase str) = return $ LError str
401 ir' (ProjCase tm alt) = do tm' <- ir tm
402 alt' <- mkIRAlt tm' alt
403 return $ LCase tm' [alt']
404 ir' (Case n alts) = do alts' <- mapM (mkIRAlt (LV (Glob n))) alts
405 return $ LCase (LV (Glob n)) alts'
406 ir' ImpossibleCase = return LNothing
408 -- special cases for Z and S
409 -- Needs rethink: projections make this fail
410-- mkIRAlt n (ConCase z _ [] rhs) | z == zname
411-- = mkIRAlt n (ConstCase (BI 0) rhs)
412-- mkIRAlt n (ConCase s _ [arg] rhs) | s == sname
415-- return $ LDefaultCase
416-- (LLet arg (LOp LBMinus [n', LConst (BI 1)])
418 mkIRAlt _ (ConCase n t args rhs)
420 return $ LConCase (-1) n args rhs'
421 mkIRAlt _ (ConstCase x rhs)
424 return $ LConstCase x rhs'
427 return $ LDefaultCase rhs'
428 mkIRAlt tm (SucCase n rhs)
430 return $ LDefaultCase (LLet n (LOp (LMinus (ATInt ITBig))
432 LConst (BI 1)]) rhs')
433-- return $ LSucCase n rhs'
434 mkIRAlt _ (ConstCase c rhs)
435 = ifail $ "Can't match on (" ++ show c ++ ")"
436 mkIRAlt _ (DefaultCase rhs)
438 return $ LDefaultCase rhs'
440 matchable (I _) = True
441 matchable (BI _) = True
442 matchable (Ch _) = True
443 matchable (Str _) = True
446 matchableTy (AType (ATInt ITNative)) = True
447 matchableTy (AType (ATInt ITBig)) = True
448 matchableTy (AType (ATInt ITChar)) = True
449 matchableTy StrType = True
451 matchableTy (AType (ATInt (ITFixed IT8))) = True
452 matchableTy (AType (ATInt (ITFixed IT16))) = True
453 matchableTy (AType (ATInt (ITFixed IT32))) = True
454 matchableTy (AType (ATInt (ITFixed IT64))) = True
456 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