@@ -18,15 +18,25 @@ import Util.LLVMStubs
1818import IRTS.Inliner
1919
2020import Idris.AbsSyntax
21−import Idris.UnusedArgs
21+import Idris.AbsSyntaxTree
22+import Idris.Erasure
2223import Idris.Error
2324
25+import Debug.Trace
26+
2427import Idris.Core.TT
2528import Idris.Core.Evaluate
2629import Idris.Core.CaseTree
2730
31+import Control.Applicative
2832import Control.Monad.State
33+import Data.Maybe
2934import Data.List
35+import Data.Ord
36+import Data.IntSet (IntSet)
37+import qualified Data.IntSet as IS
38+import qualified Data.Map as M
39+import qualified Data.Set as S
3040import System.Process
3141import System.IO
3242import System.Directory
@@ -37,18 +47,16 @@ import Paths_idris
3747
3848compile :: Codegen -> FilePath -> Term -> Idris ()
3949compile codegen f tm
40− = do checkMVs
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)
50+ = do checkMVs -- check for undefined metavariables
51+ reachableNames <- performUsageAnalysis
4652 maindef <- irMain tm
53+ iLOG $ "MAIN: " ++ show maindef
4754 objs <- getObjectFiles codegen
4855 libs <- getLibs codegen
4956 flags <- getFlags codegen
5057 hdrs <- getHdrs codegen
5158 impdirs <- allImportDirs
59+ defsIn <- mkDecls tm reachableNames
5260 let defs = defsIn ++ [(sMN 0 "runMain", maindef)]
5361 -- iputStrLn $ showSep "\n" (map show defs)
5462 let (nexttag, tagged) = addTags 65536 (liftAll defs)
@@ -98,31 +106,48 @@ compile codegen f tm
98106 if ex then return f else return h
99107
100108irMain :: TT Name -> Idris LDecl
101−irMain tm = do i <- ir tm
102− return $ LFun [] (sMN 0 "runMain") [] (LForce i)
109+irMain tm = do
110+ i <- irTerm M.empty [] tm
111+ return $ LFun [] (sMN 0 "runMain") [] (LForce i)
103112
104113mkDecls :: Term -> [Name] -> Idris [(Name, LDecl)]
105114mkDecls t used
106115 = do i <- getIState
107− let ds = filter (\ (n, d) -> n `elem` used || isCon d) $ ctxtAlist (tt_ctxt i)
108− mapM traceUnused used
116+ let ds = filter (\(n, d) -> n `elem` used || isCon d) $ ctxtAlist (tt_ctxt i)
109117 decls <- mapM build ds
110118 return decls
111119
112120showCaseTrees :: [(Name, LDecl)] -> String
113−showCaseTrees ds = showSep "\n\n" (map showCT ds)
121+showCaseTrees = showSep "\n\n" . map showCT . sortBy (comparing defnRank)
114122 where
115123 showCT (n, LFun _ f args lexp)
116− = show n ++ " " ++ showSep " " (map show args) ++ " =\n\t "
124+ = show n ++ " " ++ showSep " " (map show args) ++ " =\n\t"
117125 ++ show lexp
118126 showCT (n, LConstructor c t a) = "data " ++ show n ++ " " ++ show a
119127
128+ defnRank :: (Name, LDecl) -> String
129+ defnRank (n, LFun _ _ _ _) = "1" ++ nameRank n
130+ defnRank (n, LConstructor _ _ _) = "2" ++ nameRank n
131+
132+ nameRank :: Name -> String
133+ nameRank (UN s) = "1" ++ show s
134+ nameRank (MN i s) = "2" ++ show s ++ show i
135+ nameRank (NS n ns) = "3" ++ concatMap show (reverse ns) ++ nameRank n
136+ nameRank (SN sn) = "4" ++ snRank sn
137+ nameRank n = "5" ++ show n
138+
139+ snRank :: SpecialName -> String
140+ snRank (WhereN i n n') = "1" ++ nameRank n' ++ nameRank n ++ show i
141+ snRank (InstanceN n args) = "2" ++ nameRank n ++ concatMap show args
142+ snRank (ParentN n s) = "3" ++ nameRank n ++ show s
143+ snRank (MethodN n) = "4" ++ nameRank n
144+ snRank (CaseN n) = "5" ++ nameRank n
145+ snRank (ElimN n) = "6" ++ nameRank n
146+ snRank (InstanceCtorN n) = "7" ++ nameRank n
147+
120148isCon (TyDecl _ _) = True
121149isCon _ = False
122150
123−class ToIR a where
124− ir :: a -> Idris LExp
125−
126151build :: (Name, Def) -> Idris (Name, LDecl)
127152build (n, d)
128153 = do i <- getIState
@@ -135,295 +160,396 @@ build (n, d)
135160 logLvl 3 $ "Compiled " ++ show n ++ " =\n\t" ++ show def
136161 return (n, def)
137162
138−getPrim :: IState -> Name -> [LExp] -> Maybe LExp
139−getPrim i n args = case lookup n (idris_scprims i) of
140− Just (ar, op) ->
141− if (ar == length args)
142− then return (LOp op args)
143− else Nothing
144− _ -> Nothing
145−
146163declArgs args inl n (LLam xs x) = declArgs (args ++ xs) inl n x
147164declArgs args inl n x = LFun (if inl then [Inline] else []) n args x
148165
149−mkLDecl n (Function tm _) = do e <- ir tm
150− return (declArgs [] True n e)
166+mkLDecl n (Function tm _)
167+ = declArgs [] True n <$> irTerm M.empty [] tm
168+
151169mkLDecl n (CaseOp ci _ _ _ pats cd)
152− = let (args, sc) = cases_runtime cd in
153− do e <- ir (args, sc)
154− return (declArgs [] (case_inlinable ci) n e)
155−mkLDecl n (TyDecl (DCon t a) _) = return $ LConstructor n t a
170+ = declArgs [] (case_inlinable ci) n <$> irTree args sc
171+ where
172+ (args, sc) = cases_runtime cd
173+
174+mkLDecl n (TyDecl (DCon tag arity) _) =
175+ LConstructor n tag . erasedArity . lookup n <$> getIState
176+ where
177+ lookup n = lookupCtxtExact n . idris_callgraph
178+ erasedArity = maybe 0 (length . usedpos)
179+
156180mkLDecl n (TyDecl (TCon t a) _) = return $ LConstructor n (-1) a
157181mkLDecl n _ = return $ (declArgs [] True n LNothing) -- postulate, never run
158182
159−instance ToIR (TT Name) where
160− ir tm = ir' [] tm where
161− ir' env tm@(App f a)
162− | (P _ (UN m) _, args) <- unApply tm,
163− m == txt "mkForeignPrim"
164− = doForeign env args
165− | (P _ (UN u) _, [_, arg]) <- unApply tm,
166− u == txt "unsafePerformPrimIO"
167− = ir' env arg
168− -- TMP HACK - until we get inlining.
169− | (P _ (UN r) _, [_, _, _, _, _, arg]) <- unApply tm,
170− r == txt "replace"
171− = ir' env arg
172− -- Laziness, the old way
173− | (P _ (UN l) _, [_, arg]) <- unApply tm,
174− l == txt "lazy"
175− = do arg' <- ir' env arg
176− error "lazy has crept in somehow"
177−-- return $ LLazyExp arg'
178− | (P _ (UN l) _, [_, arg]) <- unApply tm,
179− l == txt "force"
180− = do arg' <- ir' env arg
181− return $ LForce arg'
182− -- Laziness, the new way
183− | (P _ (UN l) _, [arg]) <- unApply tm,
184− l == txt "Delay"
185− = do arg' <- ir' env arg
186− return $ LLazyExp arg'
187− | (P _ (UN l) _, [_, _, arg]) <- unApply tm,
188− l == txt "Force"
189− = do arg' <- ir' env arg
190− return $ LForce arg'
191− | (P _ (UN a) _, [_, _, arg]) <- unApply tm,
192− a == txt "assert_smaller"
193− = ir' env arg
194− | (P _ (UN a) _, [_, arg]) <- unApply tm,
195− a == txt "assert_total"
196− = ir' env arg
197− | (P _ (UN p) _, [_, arg]) <- unApply tm,
198− p == txt "par"
199− = do arg' <- ir' env arg
200− return $ LOp LPar [LLazyExp arg']
201− | (P _ (UN pf) _, [arg]) <- unApply tm,
202− pf == txt "prim_fork"
203− = do arg' <- ir' env arg
204− return $ LOp LFork [LLazyExp arg']
205− | (P _ (UN m) _, [_,size,t]) <- unApply tm,
206− m == txt "malloc"
207− = do size' <- ir' env size
208− t' <- ir' env t
209− return t' -- TODO $ malloc_ size' t'
210− | (P _ (UN tm) _, [_,t]) <- unApply tm,
211− tm == txt "trace_malloc"
212− = do t' <- ir' env t
213− return t' -- TODO
214− -- This case is here until we get more general inlining. It's just
215− -- a really common case, and the laziness hurts...
216− | (P _ (NS (UN be) [b,p]) _, [_,x,(App (P _ (UN d) _) t),
217− (App (P _ (UN d') _) e)]) <- unApply tm,
218− be == txt "boolElim" && d == txt "Delay" && d' == txt "Delay"
219− = do x' <- ir' env x
220− t' <- ir' env t
221− e' <- ir' env e
222− return (LCase x' [LConCase 0 (sNS (sUN "False") ["Bool","Prelude"]) [] e',
223− LConCase 1 (sNS (sUN "True") ["Bool","Prelude"]) [] t'])
224− | (P (DCon t a) n _, args) <- unApply tm
225− = irCon env t a n args
226− | (P (TCon t a) n _, args) <- unApply tm
227− = return LNothing
228− | (P _ n _, args) <- unApply tm
229− = do i <- getIState
230− args' <- mapM (ir' env) args
231− case getPrim i n args' of
232− Just tm -> return tm
233− _ -> do
234− let collapse
235− = case lookupCtxtExact n
236− (idris_optimisation i) of
237− Just oi -> collapsible oi
238− _ -> False
239− let unused
240− = case lookupCtxtExact n
241− (idris_callgraph i) of
242− Just (CGInfo _ _ _ _ unusedpos) ->
243− unusedpos
244− _ -> []
245− if collapse
246− then return LNothing
247− else return (LApp False (LV (Glob n))
248− (mkUnused unused 0 args'))
249− | (f, args) <- unApply tm
250− = do f' <- ir' env f
251− args' <- mapM (ir' env) args
252− return (LApp False f' args')
253− where mkUnused u i [] = []
254− mkUnused u i (x : xs) | i `elem` u = LNothing : mkUnused u (i + 1) xs
255− | otherwise = x : mkUnused u (i + 1) xs
256−-- ir' env (P _ (NS (UN "Z") ["Nat", "Prelude"]) _)
257−-- = return $ LConst (BI 0)
258− ir' env (P _ n _) = return $ LV (Glob n)
259− ir' env (V i) | i >= 0 && i < length env = return $ LV (Glob (env!!i))
260− | otherwise = ifail $ "IR fail " ++ show i ++ " " ++ show tm
261− ir' env (Bind n (Lam _) sc)
262− = do let n' = uniqueName n env
263− sc' <- ir' (n' : env) sc
264− return $ LLam [n'] sc'
265− ir' env (Bind n (Let _ v) sc)
266− = do sc' <- ir' (n : env) sc
267− v' <- ir' env v
268− return $ LLet n v' sc'
269− ir' env (Bind _ _ _) = return $ LNothing
270− ir' env (Proj t i) | i == -1
271− = do t' <- ir' env t
272− return $ LOp (LMinus (ATInt ITBig))
273− [t', LConst (BI 1)]
274− ir' env (Proj t i) = do t' <- ir' env t
275− return $ LProj t' i
276− ir' env (Constant c) = return $ LConst c
277− ir' env (TType _) = return $ LNothing
278− ir' env Erased = return $ LNothing
279− ir' env Impossible = return $ LNothing
280−-- ir' env _ = return $ LError "Impossible"
281−
282− irCon env t arity n args
283− | length args == arity = buildApp env (LV (Glob n)) args
284− | otherwise = let extra = satArgs (arity - length args) in
285− do sc' <- irCon env t arity n
286− (args ++ map (\n -> P Bound n undefined) extra)
287− return $ LLam extra sc'
288−
289− satArgs n = map (\i -> sMN i "sat") [1..n]
290−
291− buildApp env e [] = return e
292− buildApp env e xs = do xs' <- mapM (ir' env) xs
293− return $ LApp False e xs'
294−
295− doForeign :: [Name] -> [TT Name] -> Idris LExp
296− doForeign env (_ : fgn : args)
297− | (_, (Constant (Str fgnName) : fgnArgTys : ret : [])) <- unApply fgn
298− = let maybeTys = getFTypes fgnArgTys
299− rty = mkIty' ret in
300− case maybeTys of
301− Nothing -> ifail $ "Foreign type specification is not a constant list: " ++ show (fgn:args)
302− Just tys -> do
303− args' <- mapM (ir' env) (init args)
304− -- wrap it in a prim__IO
305− -- return $ con_ 0 @@ impossible @@
306− return $ -- LLazyExp $
307− LForeign LANG_C rty fgnName (zip tys args')
308− | otherwise = ifail "Badly formed foreign function call"
309−
310−getFTypes :: TT Name -> Maybe [FType]
311−getFTypes tm = case unApply tm of
312− (nil, []) -> Just []
313− (cons, [ty, xs]) ->
314− fmap (mkIty' ty :) (getFTypes xs)
315− _ -> Nothing
316−
317−mkIty' (P _ (UN ty) _) = mkIty (str ty)
318−mkIty' (App (P _ (UN fi) _) (P _ (UN intTy) _))
319− | fi == txt "FIntT" = mkIntIty (str intTy)
320−mkIty' (App (App (P _ (UN ff) _) _) (App (P _ (UN fa) _) (App (P _ (UN io) _) _)))
321− | ff == txt "FFunction" && fa == txt "FAny" &&
322− io == txt "IO"
183+data VarInfo = VI
184+ { viMethod :: Maybe Name
185+ }
186+ deriving Show
187+
188+type Vars = M.Map Name VarInfo
189+
190+irTerm :: Vars -> [Name] -> Term -> Idris LExp
191+irTerm vs env tm@(App f a) = case unApply tm of
192+ (P _ (UN m) _, args)
193+ | m == txt "mkForeignPrim"
194+ -> doForeign vs env args
195+
196+ (P _ (UN u) _, [_, arg])
197+ | u == txt "unsafePerformPrimIO"
198+ -> irTerm vs env arg
199+
200+ -- TMP HACK - until we get inlining.
201+ (P _ (UN r) _, [_, _, _, _, _, arg])
202+ | r == txt "replace"
203+ -> irTerm vs env arg
204+
205+ -- Laziness, the old way
206+ (P _ (UN l) _, [_, arg])
207+ | l == txt "lazy"
208+ -> error "lazy has crept in somehow"
209+
210+ (P _ (UN l) _, [_, arg])
211+ | l == txt "force"
212+ -> LForce <$> irTerm vs env arg
213+
214+ -- Laziness, the new way
215+ (P _ (UN l) _, [_, _, arg])
216+ | l == txt "Delay"
217+ -> LLazyExp <$> irTerm vs env arg
218+
219+ (P _ (UN l) _, [_, _, arg])
220+ | l == txt "Force"
221+ -> LForce <$> irTerm vs env arg
222+
223+ (P _ (UN a) _, [_, _, arg])
224+ | a == txt "assert_smaller"
225+ -> irTerm vs env arg
226+
227+ (P _ (UN a) _, [_, arg])
228+ | a == txt "assert_total"
229+ -> irTerm vs env arg
230+
231+ (P _ (UN p) _, [_, arg])
232+ | p == txt "par"
233+ -> do arg' <- irTerm vs env arg
234+ return $ LOp LPar [LLazyExp arg']
235+
236+ (P _ (UN pf) _, [arg])
237+ | pf == txt "prim_fork"
238+ -> do arg' <- irTerm vs env arg
239+ return $ LOp LFork [LLazyExp arg']
240+
241+ (P _ (UN m) _, [_,size,t])
242+ | m == txt "malloc"
243+ -> irTerm vs env t
244+
245+ (P _ (UN tm) _, [_,t])
246+ | tm == txt "trace_malloc"
247+ -> irTerm vs env t -- TODO
248+
249+ -- This case is here until we get more general inlining. It's just
250+ -- a really common case, and the laziness hurts...
251+ (P _ (NS (UN be) [b,p]) _, [_,x,(App (P _ (UN d) _) t),
252+ (App (P _ (UN d') _) e)])
253+ | be == txt "boolElim"
254+ , d == txt "Delay"
255+ , d' == txt "Delay"
256+ -> do
257+ x' <- irTerm vs env x
258+ t' <- irTerm vs env t
259+ e' <- irTerm vs env e
260+ return (LCase x' [LConCase 0 (sNS (sUN "False") ["Bool","Prelude"]) [] e'
261+ ,LConCase 1 (sNS (sUN "True" ) ["Bool","Prelude"]) [] t'
262+ ])
263+
264+ (P (DCon t arity) n _, args) -> do
265+ ist <- getIState
266+ let detag = maybe False detaggable . lookupCtxtExact n $ idris_optimisation ist
267+ used = maybe [] (map fst . usedpos) . lookupCtxtExact n $ idris_callgraph ist
268+ args' = [a | (i,a) <- zip [0..] args, i `elem` used]
269+
270+ when (length args > arity) $
271+ ifail ("oversaturated data ctor: " ++ show tm)
272+
273+ if length args' == 1 && detag -- detaggable
274+ then irTerm vs env (head args') -- newtype
275+ else irCon vs env (length used) n args'
276+
277+ (P (TCon t a) n _, args) -> return LNothing
278+
279+ (P _ n _, args) -> do
280+ ist <- getIState
281+ case lookup n (idris_scprims ist) of
282+ -- if it's a primitive that is already saturated,
283+ -- compile to the corresponding op here already to save work
284+ Just (arity, op) | length args == arity
285+ -> LOp op <$> mapM (irTerm vs env) args
286+
287+ -- otherwise, just apply the name
288+ _ -> applyName n ist args
289+
290+ -- turn de bruijn vars into regular named references and try again
291+ (V i, args) -> irTerm vs env $ mkApp (P Bound (env !! i) Erased) args
292+
293+ (f, args)
294+ -> LApp False
295+ <$> irTerm vs env f
296+ <*> mapM (irTerm vs env) args
297+
298+ where
299+ applyName :: Name -> IState -> [Term] -> Idris LExp
300+ applyName n ist args =
301+ LApp False (LV $ Glob n) <$> mapM (irTerm vs env . erase) (zip [0..] args)
302+ where
303+ erase (i, x)
304+ | i >= arity || i `elem` used = x
305+ | otherwise = Erased
306+
307+ arity = case fst4 <$> lookupCtxtExact n (definitions . tt_ctxt $ ist) of
308+ Just (CaseOp ci ty tys def tot cdefs) -> length tys
309+ Just (TyDecl (DCon tag ar) _) -> ar
310+ Just (TyDecl Ref ty) -> length $ getArgTys ty
311+ Just (Operator ty ar op) -> ar
312+ Just def -> error $ "unknown arity: " ++ show (n, def)
313+ Nothing -> 0 -- no definition, probably local name => can't erase anything
314+
315+ -- name for purposes of usage info lookup
316+ uName
317+ | Just n' <- viMethod =<< M.lookup n vs = n'
318+ | otherwise = n
319+
320+ used = maybe [] (map fst . usedpos) $ lookupCtxtExact uName (idris_callgraph ist)
321+ fst4 (x,_,_,_) = x
322+
323+irTerm vs env (P _ n _) = return $ LV (Glob n)
324+irTerm vs env (V i)
325+ | i >= 0 && i < length env = return $ LV (Glob (env!!i))
326+ | otherwise = ifail $ "bad de bruijn index: " ++ show i
327+
328+irTerm vs env (Bind n (Lam _) sc) = LLam [n'] <$> irTerm vs (n':env) sc
329+ where
330+ n' = uniqueName n env
331+
332+irTerm vs env (Bind n (Let _ v) sc)
333+ = LLet n <$> irTerm vs env v <*> irTerm vs (n : env) sc
334+
335+irTerm vs env (Bind _ _ _) = return $ LNothing
336+
337+irTerm vs env (Proj t (-1)) = do
338+ t' <- irTerm vs env t
339+ return $ LOp (LMinus (ATInt ITBig))
340+ [t', LConst (BI 1)]
341+
342+irTerm vs env (Proj t i) = LProj <$> irTerm vs env t <*> pure i
343+irTerm vs env (Constant c) = return $ LConst c
344+irTerm vs env (TType _) = return $ LNothing
345+irTerm vs env Erased = return $ LNothing
346+irTerm vs env Impossible = return $ LNothing
347+
348+irCon :: Vars -> [Name] -> Int -> Name -> [Term] -> Idris LExp
349+irCon vs env arity n args
350+ | length args > arity
351+ = error $ "oversaturated data constructor: " ++ show (n, args)
352+
353+ -- saturated
354+ | length args == arity
355+ = buildApp (LV (Glob n)) args
356+
357+ -- undersaturated, wrap in lambdas
358+ | otherwise
359+ = let extraNs = [sMN i "sat" | i <- [length args .. arity-1]]
360+ extraTs = [P Bound n undefined | n <- extraNs]
361+ in LLam extraNs <$> irCon vs env arity n (args ++ extraTs)
362+ where
363+ buildApp e [] = return e
364+ buildApp e xs = LApp False e <$> mapM (irTerm vs env) xs
365+
366+doForeign :: Vars -> [Name] -> [TT Name] -> Idris LExp
367+doForeign vs env (_ : fgn : args)
368+ | (_, (Constant (Str fgnName) : fgnArgTys : ret : [])) <- unApply fgn
369+ = case getFTypes fgnArgTys of
370+ Nothing -> ifail $ "Foreign type specification is not a constant list: " ++ show (fgn:args)
371+ Just tys -> do
372+ args' <- mapM (irTerm vs env) (init args)
373+ return $ LForeign LANG_C (mkIty' ret) fgnName (zip tys args')
374+
375+ | otherwise = ifail "Badly formed foreign function call"
376+ where
377+ getFTypes :: TT Name -> Maybe [FType]
378+ getFTypes tm = case unApply tm of
379+ -- nil : {a : Type} -> List a
380+ (nil, [_]) -> Just []
381+ -- cons : {a : Type} -> a -> List a -> List a
382+ (cons, [_, ty, xs]) -> (mkIty' ty :) <$> getFTypes xs
383+ _ -> Nothing
384+
385+ mkIty' (P _ (UN ty) _) = mkIty (str ty)
386+ mkIty' (App (P _ (UN fi) _) (P _ (UN intTy) _))
387+ | fi == txt "FIntT"
388+ = mkIntIty (str intTy)
389+
390+ mkIty' (App (App (P _ (UN ff) _) _) (App (P _ (UN fa) _) (App (P _ (UN io) _) _)))
391+ | ff == txt "FFunction"
392+ , fa == txt "FAny"
393+ , io == txt "IO"
323394 = FFunctionIO
324−mkIty' (App (App (P _ (UN ff) _) _) _)
325− | ff == txt "FFunction" = FFunction
326−mkIty' _ = FAny
327−
328−-- would be better if these FInt types were evaluated at compile time
329−-- TODO: add %eval directive for such things
330−
331−mkIty "FFloat" = FArith ATFloat
332−mkIty "FInt" = mkIntIty "ITNative"
333−mkIty "FChar" = mkIntIty "ITChar"
334−mkIty "FByte" = mkIntIty "IT8"
335−mkIty "FShort" = mkIntIty "IT16"
336−mkIty "FLong" = mkIntIty "IT64"
337−mkIty "FBits8" = mkIntIty "IT8"
338−mkIty "FBits16" = mkIntIty "IT16"
339−mkIty "FBits32" = mkIntIty "IT32"
340−mkIty "FBits64" = mkIntIty "IT64"
341−mkIty "FString" = FString
342−mkIty "FPtr" = FPtr
343−mkIty "FManagedPtr" = FManagedPtr
344−mkIty "FUnit" = FUnit
345−mkIty "FFunction" = FFunction
346−mkIty "FFunctionIO" = FFunctionIO
347−mkIty "FBits8x16" = FArith (ATInt (ITVec IT8 16))
348−mkIty "FBits16x8" = FArith (ATInt (ITVec IT16 8))
349−mkIty "FBits32x4" = FArith (ATInt (ITVec IT32 4))
350−mkIty "FBits64x2" = FArith (ATInt (ITVec IT64 2))
351−mkIty x = error $ "Unknown type " ++ x
352−
353−mkIntIty "ITNative" = FArith (ATInt ITNative)
354−mkIntIty "ITChar" = FArith (ATInt ITChar)
355−mkIntIty "IT8" = FArith (ATInt (ITFixed IT8))
356−mkIntIty "IT16" = FArith (ATInt (ITFixed IT16))
357−mkIntIty "IT32" = FArith (ATInt (ITFixed IT32))
358−mkIntIty "IT64" = FArith (ATInt (ITFixed IT64))
359−
360−zname = sNS (sUN "Z") ["Nat","Prelude"]
361−sname = sNS (sUN "S") ["Nat","Prelude"]
362−
363−instance ToIR ([Name], SC) where
364− ir (args, tree) = do logLvl 3 $ "Compiling " ++ show args ++ "\n" ++ show tree
365− tree' <- ir tree
366− return $ LLam args tree'
367−
368−instance ToIR SC where
369− ir t = ir' t where
370−
371− ir' (STerm t) = ir t
372− ir' (UnmatchedCase str) = return $ LError str
373− ir' (ProjCase tm alts) = do tm' <- ir tm
374− alts' <- mapM (mkIRAlt tm') alts
375− return $ LCase tm' alts'
376− ir' (Case n alts) = do alts' <- mapM (mkIRAlt (LV (Glob n))) alts
377− return $ LCase (LV (Glob n)) alts'
378− ir' ImpossibleCase = return LNothing
379−
380− -- special cases for Z and S
381− -- Needs rethink: projections make this fail
382−-- mkIRAlt n (ConCase z _ [] rhs) | z == zname
383−-- = mkIRAlt n (ConstCase (BI 0) rhs)
384−-- mkIRAlt n (ConCase s _ [arg] rhs) | s == sname
385−-- = do n' <- ir n
386−-- rhs' <- ir rhs
387−-- return $ LDefaultCase
388−-- (LLet arg (LOp LBMinus [n', LConst (BI 1)])
389−-- rhs')
390− mkIRAlt _ (ConCase n t args rhs)
391− = do rhs' <- ir rhs
392− return $ LConCase (-1) n args rhs'
393− mkIRAlt _ (ConstCase x rhs)
394− | matchable x
395− = do rhs' <- ir rhs
396− return $ LConstCase x rhs'
397− | matchableTy x
398− = do rhs' <- ir rhs
399− return $ LDefaultCase rhs'
400− mkIRAlt tm (SucCase n rhs)
401− = do rhs' <- ir rhs
402− return $ LDefaultCase (LLet n (LOp (LMinus (ATInt ITBig))
403− [tm,
404− LConst (BI 1)]) rhs')
405−-- return $ LSucCase n rhs'
406− mkIRAlt _ (ConstCase c rhs)
407− = ifail $ "Can't match on (" ++ show c ++ ")"
408− mkIRAlt _ (DefaultCase rhs)
409− = do rhs' <- ir rhs
410− return $ LDefaultCase rhs'
411−
412− matchable (I _) = True
413− matchable (BI _) = True
414− matchable (Ch _) = True
415− matchable (Str _) = True
416− matchable _ = False
417−
418− matchableTy (AType (ATInt ITNative)) = True
419− matchableTy (AType (ATInt ITBig)) = True
420− matchableTy (AType (ATInt ITChar)) = True
421− matchableTy StrType = True
422−
423− matchableTy (AType (ATInt (ITFixed IT8))) = True
424− matchableTy (AType (ATInt (ITFixed IT16))) = True
425− matchableTy (AType (ATInt (ITFixed IT32))) = True
426− matchableTy (AType (ATInt (ITFixed IT64))) = True
427−
428− matchableTy _ = False
429395
396+ mkIty' (App (App (P _ (UN ff) _) _) _)
397+ | ff == txt "FFunction"
398+ = FFunction
399+
400+ mkIty' _ = FAny
401+
402+ -- would be better if these FInt types were evaluated at compile time
403+ -- TODO: add %eval directive for such things
404+
405+ mkIty "FFloat" = FArith ATFloat
406+ mkIty "FInt" = mkIntIty "ITNative"
407+ mkIty "FChar" = mkIntIty "ITChar"
408+ mkIty "FByte" = mkIntIty "IT8"
409+ mkIty "FShort" = mkIntIty "IT16"
410+ mkIty "FLong" = mkIntIty "IT64"
411+ mkIty "FBits8" = mkIntIty "IT8"
412+ mkIty "FBits16" = mkIntIty "IT16"
413+ mkIty "FBits32" = mkIntIty "IT32"
414+ mkIty "FBits64" = mkIntIty "IT64"
415+ mkIty "FString" = FString
416+ mkIty "FPtr" = FPtr
417+ mkIty "FManagedPtr" = FManagedPtr
418+ mkIty "FUnit" = FUnit
419+ mkIty "FFunction" = FFunction
420+ mkIty "FFunctionIO" = FFunctionIO
421+ mkIty "FBits8x16" = FArith (ATInt (ITVec IT8 16))
422+ mkIty "FBits16x8" = FArith (ATInt (ITVec IT16 8))
423+ mkIty "FBits32x4" = FArith (ATInt (ITVec IT32 4))
424+ mkIty "FBits64x2" = FArith (ATInt (ITVec IT64 2))
425+ mkIty x = error $ "Unknown type " ++ x
426+
427+ mkIntIty "ITNative" = FArith (ATInt ITNative)
428+ mkIntIty "ITChar" = FArith (ATInt ITChar)
429+ mkIntIty "IT8" = FArith (ATInt (ITFixed IT8))
430+ mkIntIty "IT16" = FArith (ATInt (ITFixed IT16))
431+ mkIntIty "IT32" = FArith (ATInt (ITFixed IT32))
432+ mkIntIty "IT64" = FArith (ATInt (ITFixed IT64))
433+
434+irTree :: [Name] -> SC -> Idris LExp
435+irTree args tree = do
436+ logLvl 3 $ "Compiling " ++ show args ++ "\n" ++ show tree
437+ LLam args <$> irSC M.empty tree
438+
439+irSC :: Vars -> SC -> Idris LExp
440+irSC vs (STerm t) = irTerm vs [] t
441+irSC vs (UnmatchedCase str) = return $ LError str
442+irSC vs (ProjCase tm alts) = do
443+ tm' <- irTerm vs [] tm
444+ alts' <- mapM (irAlt vs tm') alts
445+ return $ LCase tm' alts'
446+
447+-- Transform matching on Delay to applications of Force.
448+irSC vs (Case n [ConCase (UN delay) i [_, _, n'] sc])
449+ | delay == txt "Delay"
450+ = irSC vs $ mkForce n n' sc
451+
452+-- There are two transformations in this case:
453+--
454+-- 1. Newtype-case elimination:
455+-- case {e0} of
456+-- wrap({e1}) -> P({e1}) ==> P({e0})
457+--
458+-- This is important because newtyped constructors are compiled away entirely
459+-- and we need to do that everywhere.
460+--
461+-- 2. Unused-case elimination (only valid for singleton branches):
462+-- case {e0} of ==> P
463+-- C(x,y) -> P[... x,y not used ...]
464+--
465+-- This is important for runtime because sometimes we case on irrelevant data:
466+--
467+-- In the example above, {e0} will most probably have been erased
468+-- so this vain projection would make the resulting program segfault
469+-- because the code generator still emits a PROJECT(...) G-machine instruction.
470+--
471+-- Hence, we check whether the variables are used at all
472+-- and erase the casesplit if they are not.
473+irSC vs (Case n [alt]) = do
474+ replacement <- case alt of
475+ ConCase cn a ns sc -> do
476+ detag <- maybe False detaggable . lookupCtxtExact cn . idris_optimisation <$> getIState
477+ used <- maybe [] (map fst . usedpos) . lookupCtxtExact cn . idris_callgraph <$> getIState
478+ if detag && length used == 1
479+ then return . Just $ substSC (ns !! head used) n sc
480+ else return Nothing
481+ _ -> return Nothing
482+
483+ case replacement of
484+ Just sc -> irSC vs sc
485+ _ -> do
486+ alt' <- irAlt vs (LV (Glob n)) alt
487+ return $ case namesBoundIn alt' `usedIn` subexpr alt' of
488+ [] -> subexpr alt' -- strip the unused top-most case
489+ _ -> LCase (LV (Glob n)) [alt']
490+ where
491+ namesBoundIn :: LAlt -> [Name]
492+ namesBoundIn (LConCase cn i ns sc) = ns
493+ namesBoundIn (LConstCase c sc) = []
494+ namesBoundIn (LDefaultCase sc) = []
495+
496+ subexpr :: LAlt -> LExp
497+ subexpr (LConCase _ _ _ e) = e
498+ subexpr (LConstCase _ e) = e
499+ subexpr (LDefaultCase e) = e
500+
501+irSC vs (Case n alts) = LCase (LV (Glob n)) <$> mapM (irAlt vs (LV (Glob n))) alts
502+irSC vs ImpossibleCase = return LNothing
503+
504+irAlt :: Vars -> LExp -> CaseAlt -> Idris LAlt
505+
506+-- this leaves out all unused arguments of the constructor
507+irAlt vs _ (ConCase n t args sc) = do
508+ used <- getUsed . lookup n <$> getIState
509+ let usedArgs = [a | (i,a) <- zip [0..] args, i `elem` used]
510+ LConCase (-1) n usedArgs <$> irSC (methodVars `M.union` vs) sc
511+ where
512+ lookup n = lookupCtxtExact n . idris_callgraph
513+ getUsed = maybe [] (map fst . usedpos)
514+
515+ methodVars = case n of
516+ SN (InstanceCtorN className)
517+ -> M.fromList [(v, VI
518+ { viMethod = Just $ mkFieldName n i
519+ }) | (v,i) <- zip args [0..]]
520+ _
521+ -> M.empty -- not an instance constructor
522+
523+irAlt vs _ (ConstCase x rhs)
524+ | matchable x = LConstCase x <$> irSC vs rhs
525+ | matchableTy x = LDefaultCase <$> irSC vs rhs
526+ where
527+ matchable (I _) = True
528+ matchable (BI _) = True
529+ matchable (Ch _) = True
530+ matchable (Str _) = True
531+ matchable _ = False
532+
533+ matchableTy (AType (ATInt ITNative)) = True
534+ matchableTy (AType (ATInt ITBig)) = True
535+ matchableTy (AType (ATInt ITChar)) = True
536+ matchableTy StrType = True
537+
538+ matchableTy (AType (ATInt (ITFixed IT8))) = True
539+ matchableTy (AType (ATInt (ITFixed IT16))) = True
540+ matchableTy (AType (ATInt (ITFixed IT32))) = True
541+ matchableTy (AType (ATInt (ITFixed IT64))) = True
542+
543+ matchableTy _ = False
544+
545+irAlt vs tm (SucCase n rhs) = do
546+ rhs' <- irSC vs rhs
547+ return $ LDefaultCase (LLet n (LOp (LMinus (ATInt ITBig))
548+ [tm,
549+ LConst (BI 1)]) rhs')
550+
551+irAlt vs _ (ConstCase c rhs)
552+ = ifail $ "Can't match on (" ++ show c ++ ")"
553+
554+irAlt vs _ (DefaultCase rhs)
555+ = LDefaultCase <$> irSC vs rhs