on master help sign in
Merge remote-tracking branch 'upstream/master' into pretty-warnings
commiteb4c235ec0f8439382e02ba01acb34ed19703231 authorJason Felice <jason.m.felice@gmail.com> dateTue 12 Dec 2017, 13:51 (9 years ago) parent7a2acb1de1d865
9 files changed+246−85
libs/contrib/Data/List/Group.idr+24 libs/prelude/IO.idr+3−2 src/IRTS/CodegenC.hs+20−23 src/IRTS/Compiler.hs+14−7 src/IRTS/Lang.hs+2−2 src/IRTS/LangOpts.hs+108−49 src/Idris/Core/CaseTree.hs+52−1 stack-nightly.yaml+17 stack.yaml+6−1
libs/contrib/Data/List/Group.idrnew file+24
@@ -0,0 +1,24 @@
1+module Data.List.Group
2+
3+||| The groupBy function returns a list of lists such that the concatenation
4+||| of the list is equal to the argument, and each sublist contains only
5+||| elements that are equal according to the user-supplied predicate.
6+|||
7+||| ```idris example
8+||| groupBy (==) [1, 1, 2, 3, 3]
9+||| ```
10+|||
11+groupBy : (a -> a -> Bool) -> List a -> List (List a)
12+groupBy _ [] = []
13+groupBy p list@(x :: xs) =
14+ let (ys, zs) = span (p x) xs in
15+ (x :: ys) :: groupBy p (assert_smaller list zs)
16+
17+||| The group function is a special case of groupBy.
18+|||
19+||| ```idris example
20+||| group [1, 1, 2, 3, 3]
21+||| ```
22+|||
23+group : Eq a => List a -> List (List a)
24+group = groupBy (==)
libs/prelude/IO.idr+3−2
@@ -101,9 +101,10 @@ unsafePerformPrimIO : PrimIO a -> a
101101prim_io_pure : a -> PrimIO a
102102prim_io_pure x = Prim__IO x
103103
104+-- %inline
104105io_bind : IO' l a -> (a -> IO' l b) -> IO' l b
105−io_bind (MkIO fn) k
106− = MkIO (\w => prim_io_bind (fn w)
106+io_bind (MkIO fn)
107+ = \k => MkIO (\w => prim_io_bind (fn w)
107108 (\ b => case k b of
108109 MkIO fkb => fkb w))
109110
src/IRTS/CodegenC.hs+20−23
@@ -221,7 +221,7 @@ bcc i (PROJECT l loc a) = indent i ++ "PROJECT(vm, " ++ creg l ++ ", " ++ show l
221221bcc i (PROJECTINTO r t idx)
222222 = indent i ++ creg r ++ " = GETARG(" ++ creg t ++ ", " ++ show idx ++ ");\n"
223223bcc i (CASE True r code def)
224− | length code < 4 = showCase i def code
224+ | length code < 4 && length code > 0 = showCase i def code
225225 where
226226 showCode :: Int -> [BC] -> String
227227 showCode i bc = "{\n" ++ concatMap (bcc (i + 1)) bc ++
@@ -697,29 +697,26 @@ ifaceC (ExportFun n cn ret args)
697697
698698 argNames = zipWith (++) (repeat "arg") (map show [0..])
699699
700−mkBody n as t = indent 1 ++ "INITFRAME;\n" ++
701− indent 1 ++ "RESERVE(" ++ show (max (length as) 3) ++ ");\n" ++
702− push 0 as ++ call n ++ retval t
703− where push i [] = ""
704− push i ((n, t) : ts) = indent 1 ++ c_irts (toFType t)
705− ("TOP(" ++ show i ++ ") = ") n
706− ++ ";\n" ++ push (i + 1) ts
707−
708− call _ = indent 1 ++ "STOREOLD;\n" ++
709− indent 1 ++ "BASETOP(0);\n" ++
710− indent 1 ++ "ADDTOP(" ++ show (length as) ++ ");\n" ++
711− indent 1 ++ "CALL(" ++ cname n ++ ");\n"
712−
713− retval (FIO t)
714− = indent 1 ++ "TOP(0) = NULL;\n" ++
715− indent 1 ++ "TOP(1) = NULL;\n" ++
716− indent 1 ++ "TOP(2) = RVAL;\n" ++
717− indent 1 ++ "STOREOLD;\n" ++
700+mkBody n as_in t
701+ = indent 1 ++ "INITFRAME;\n" ++
702+ indent 1 ++ "RESERVE(" ++ show (max (length as) 3) ++ ");\n" ++
703+ push 0 as ++ call n ++ retval t
704+ where
705+ as = case t of
706+ FIO t -> as_in ++ [("NULL", FUnknown)] -- add world token
707+ _ -> as_in
708+ push i [] = ""
709+ push i ((n, t) : ts) = indent 1 ++ c_irts (toFType t)
710+ ("TOP(" ++ show i ++ ") = ") n
711+ ++ ";\n" ++ push (i + 1) ts
712+
713+ call _ = indent 1 ++ "STOREOLD;\n" ++
718714 indent 1 ++ "BASETOP(0);\n" ++
719− indent 1 ++ "ADDTOP(3);\n" ++
720− indent 1 ++ "CALL(" ++ cname (sUN "call__IO") ++ ");\n" ++
721− retval t
722− retval t = indent 1 ++ "return " ++ irts_c (toFType t) "RVAL" ++ ";\n"
715+ indent 1 ++ "ADDTOP(" ++ show (length as) ++ ");\n" ++
716+ indent 1 ++ "CALL(" ++ cname n ++ ");\n"
717+
718+ retval (FIO t) = retval t
719+ retval t = indent 1 ++ "return " ++ irts_c (toFType t) "RVAL" ++ ";\n"
723720
724721ctype (FCon c)
725722 | c == sUN "C_Str" = "char*"
src/IRTS/Compiler.hs+14−7
@@ -81,7 +81,14 @@ compile codegen f mtm = do
8181 let defsUniq = map (allocUnique (addAlist defsInlined emptyContext))
8282 defsInlined
8383
84− let (nexttag, tagged) = addTags 65536 (liftAll defsUniq)
84+ logCodeGen 1 "Inlining"
85+
86+ dumpCases <- getDumpCases
87+ case dumpCases of
88+ Nothing -> return ()
89+ Just f -> runIO $ writeFile f (showCaseTrees defsUniq)
90+
91+ let (nexttag, tagged) = addTags 65536 (liftAll defsInlined)
8592 let ctxtIn = addAlist tagged emptyContext
8693
8794 logCodeGen 1 "Defunctionalising"
@@ -96,11 +103,7 @@ compile codegen f mtm = do
96103
97104 let checked = simplifyDefs defuns (toAlist defuns)
98105 outty <- outputTy
99− dumpCases <- getDumpCases
100106 dumpDefun <- getDumpDefun
101− case dumpCases of
102− Nothing -> return ()
103− Just f -> runIO $ writeFile f (showCaseTrees defs)
104107 case dumpDefun of
105108 Nothing -> return ()
106109 Just f -> runIO $ writeFile f (dumpDefuns defuns)
@@ -168,9 +171,13 @@ getDeclarations used
168171showCaseTrees :: [(Name, LDecl)] -> String
169172showCaseTrees = showSep "\n\n" . map showCT . sortBy (comparing defnRank)
170173 where
171− showCT (n, LFun _ f args lexp)
172− = show n ++ " " ++ showSep " " (map show args) ++ " =\n\t"
174+ showCT (n, LFun opts f args lexp)
175+ = showOpts ++
176+ show n ++ " " ++ showSep " " (map show args) ++ " =\n\t"
173177 ++ show lexp
178+ where
179+ showOpts | Inline `elem` opts = "%inline "
180+ | otherwise = ""
174181 showCT (n, LConstructor c t a) = "data " ++ show n ++ " " ++ show a
175182
176183 defnRank :: (Name, LDecl) -> String
src/IRTS/Lang.hs+2−2
@@ -346,8 +346,8 @@ instance Show LExp where
346346 ++ " in " ++ show' (env ++ [show n]) ind e
347347
348348 show' env ind (LLam args e)
349− = "\\ " ++ showSep "," (map show args)
350− ++ " => " ++ show' (env ++ (map show args)) ind e
349+ = "(\\ " ++ showSep "," (map show args)
350+ ++ " => " ++ show' (env ++ (map show args)) ind e ++ ") "
351351
352352 show' env ind (LProj t i) = show t ++ "!" ++ show i
353353
src/IRTS/LangOpts.hs+108−49
@@ -7,12 +7,16 @@ Maintainer : The Idris Community.
77-}
88{-# LANGUAGE DeriveFunctor, PatternGuards #-}
99
10−module IRTS.LangOpts where
10+module IRTS.LangOpts(inlineAll) where
1111
12+import Idris.Core.CaseTree
1213import Idris.Core.TT
1314import IRTS.Lang
1415
1516import Control.Monad.State hiding (lift)
17+import Data.List
18+
19+import Debug.Trace
1620
1721inlineAll :: [(Name, LDecl)] -> [(Name, LDecl)]
1822inlineAll lds = let defs = addAlist lds emptyContext in
@@ -31,53 +35,108 @@ nextN = do i <- get
3135doInline :: LDefs -> LDecl -> LDecl
3236doInline defs d@(LConstructor _ _ _) = d
3337doInline defs (LFun opts topn args exp)
34− = let res = evalState (inlineWith [topn] (map (\n -> (n, LV n)) args) exp) 0 in
35− LFun opts topn args res
38+ = let res = evalState (eval [] initEnv [topn] defs exp)
39+ (length args) in
40+-- = let res = evalState (inlineWith [topn] (map (\n -> (n, LV n)) args) exp) 0 in
41+ case res of
42+ LLam args' body -> LFun opts topn (map snd initNames ++ args') body
43+ _ -> LFun opts topn (map snd initNames) res
3644 where
37− inlineWith :: [Name] -> [(Name, LExp)] -> LExp -> State Int LExp
38− inlineWith done env var@(LV n)
39− = case lookup n env of
40− Just t -> return t
41− Nothing -> return var
42− inlineWith done env (LLazyApp n es) = LLazyApp n <$> (mapM (inlineWith done env) es)
43− inlineWith done env (LForce e) = LForce <$> inlineWith done env e
44− inlineWith done env (LLazyExp e) = LLazyExp <$> inlineWith done env e
45− -- Extend the environment for Let and Lam so that bound names aren't
46− -- expanded with any top level argument definitions they shadow
47− inlineWith done env (LLet n val sc)
48− = do n' <- nextN
49− LLet n' <$> inlineWith done env val <*>
50− inlineWith done ((n, LV n') : env) sc
51− inlineWith done env (LLam args sc)
52− = do ns' <- mapM (\n -> do n' <- nextN
53− return (n, n')) args
54− LLam (map snd ns') <$>
55− inlineWith done (map (\ (n,n') -> (n, LV n')) ns' ++ env) sc
56− inlineWith done env (LProj exp i) = LProj <$> inlineWith done env exp <*> return i
57− inlineWith done env (LCon loc i n es)
58− = LCon loc i n <$> mapM (inlineWith done env) es
59− inlineWith done env (LCase ty e alts)
60− = LCase ty <$> inlineWith done env e <*> mapM (inlineWithAlt done env) alts
61− inlineWith done env (LOp f es) = LOp f <$> mapM (inlineWith done env) es
62− -- the interesting case!
63− inlineWith done env (LApp t (LV n) es)
64− | n `notElem` done,
65− [LFun opts _ args body] <- lookupCtxt n defs,
66− Inline `elem` opts,
67− length es == length args
68− = do es' <- mapM (inlineWith done env) es
69− inlineWith (n : done) (zip args es' ++ env) body
70− inlineWith done env (LApp t f es)
71− = LApp t <$> inlineWith done env f <*> mapM (inlineWith done env) es
72− inlineWith done env (LForeign t s args)
73− = LForeign t s <$> mapM (\(t, e) -> do e' <- inlineWith done env e
74− return (t, e')) args
75− inlineWith done env t = return t
45+ initNames = zipWith (\n i -> (n, newn n i)) args [0..]
46+ initEnv = map (\(n, n') -> (n, LV n')) initNames
47+ newn (UN n) i = MN i n
48+ newn _ i = sMN i "arg"
49+
50+unload :: [LExp] -> LExp -> LExp
51+unload [] e = e
52+unload stk (LApp tc e args) = LApp tc e (args ++ stk)
53+unload stk e = LApp False e stk
54+
55+takeStk :: [(Name, LExp)] -> [Name] -> [LExp] ->
56+ ([(Name, LExp)], [Name], [LExp])
57+takeStk env (a : args) (v : stk) = takeStk ((a, v) : env) args stk
58+takeStk env args stk = (env, args, stk)
59+
60+eval :: [LExp] -> [(Name, LExp)] -> [Name] -> LDefs -> LExp -> State Int LExp
61+eval stk env rec defs (LLazyApp n es)
62+ = unload stk <$> LLazyApp n <$> (mapM (eval [] env rec defs) es)
63+eval stk env rec defs (LForce e)
64+ = unload stk <$> LForce <$> eval [] env rec defs e
65+eval stk env rec defs (LLazyExp e)
66+ = unload stk <$> LLazyExp <$> eval [] env rec defs e
67+-- Special case for io_bind, because it needs to keep executing the first
68+-- action, and is worth inlining to avoid the thunk
69+eval [] env rec defs (LApp t (LV n) [_, _, _, act, (LLam [arg] k)])
70+ | n == sUN "io_bind"
71+ = do w <- nextN
72+ let env' = (w, LV w) : env
73+ act' <- eval [] env' rec defs (LApp False act [LV w])
74+ argn <- nextN
75+ k' <- eval [] ((arg, LV argn) : env') rec defs (LApp False k [LV w])
76+ return $ LLam [w] (LLet argn act' k')
77+eval (world : stk) env rec defs (LApp t (LV n) [_, _, _, act, (LLam [arg] k)])
78+ | n == sUN "io_bind"
79+ = do act' <- eval [] env rec defs (LApp False act [world])
80+ argn <- nextN
81+ k' <- eval stk ((arg, LV argn) : env) rec defs (LApp False k [world])
82+ return $ LLet argn act' k'
83+
84+eval stk env rec defs (LApp t f es)
85+ = do es' <- mapM (eval [] env rec defs) es
86+ eval (es' ++ stk) env rec defs f
87+eval stk env rec defs (LLet n val sc)
88+ = do n' <- nextN
89+ LLet n' <$> eval [] env rec defs val
90+ <*> eval stk ((n, LV n') : env) rec defs sc
91+eval stk env rec defs (LProj exp i)
92+ = unload stk <$> (LProj <$> eval [] env rec defs exp <*> return i)
93+eval stk env rec defs (LCon loc i n es)
94+ = unload stk <$> (LCon loc i n <$> mapM (eval [] env rec defs) es)
95+eval stk env rec defs (LCase ty e alts)
96+ = LCase ty <$> eval [] env rec defs e
97+ <*> mapM (evalAlt stk env rec defs) alts
98+eval stk env rec defs (LOp f es)
99+ = unload stk <$> LOp f <$> mapM (eval [] env rec defs) es
100+eval stk env rec defs (LForeign t s args)
101+ = unload stk <$>
102+ LForeign t s <$> mapM (\(t, e) -> do e' <- eval [] env rec defs e
103+ return (t, e')) args
104+-- save the interesting cases for the end:
105+-- lambdas, and names to reduce
106+eval stk env rec defs (LLam args sc)
107+ | (env', args', stk') <- takeStk env args stk
108+ = case args' of
109+ [] -> eval stk' env' rec defs sc
110+ as -> do ns' <- mapM (\n -> do n' <- nextN
111+ return (n, n')) args'
112+ LLam (map snd ns') <$>
113+ eval [] (map (\ (n, n') -> (n, LV n')) ns' ++ env')
114+ rec defs sc
115+eval stk env rec defs var@(LV n)
116+ = case lookup n env of
117+ Just t
118+ | t /= LV n && n `notElem` rec ->
119+ eval stk env (n : rec) defs t
120+ | otherwise -> return (unload stk t)
121+ Nothing
122+ | n `notElem` rec,
123+ Just (LFun opts _ args body) <- lookupCtxtExact n defs,
124+ Inline `elem` opts ->
125+ apply stk env (n : rec) defs var args body
126+ | otherwise -> return (unload stk var)
127+eval stk env rec defs t = return (unload stk t)
128+
129+evalAlt stk env rec defs (LConCase i n es rhs)
130+ = do ns' <- mapM (\n -> do n' <- nextN
131+ return (n, n')) es
132+ LConCase i n (map snd ns') <$>
133+ eval stk (map (\ (n, n') -> (n, LV n')) ns' ++ env) rec defs rhs
134+evalAlt stk env rec defs (LConstCase c e)
135+ = LConstCase c <$> eval stk env rec defs e
136+evalAlt stk env rec defs (LDefaultCase e)
137+ = LDefaultCase <$> eval stk env rec defs e
76138
77− inlineWithAlt done env (LConCase i n es rhs)
78− = do ns' <- mapM (\n -> do n' <- nextN
79− return (n, n')) es
80− LConCase i n (map snd ns') <$>
81− inlineWith done (map (\ (n,n') -> (n, LV n')) ns' ++ env) rhs
82− inlineWithAlt done env (LConstCase c e) = LConstCase c <$> inlineWith done env e
83− inlineWithAlt done env (LDefaultCase e) = LDefaultCase <$> inlineWith done env e
139+apply :: [LExp] -> [(Name, LExp)] -> [Name] -> LDefs -> LExp ->
140+ [Name] -> LExp -> State Int LExp
141+apply stk env rec defs var args body
142+ = eval stk env rec defs (LLam args body)
src/Idris/Core/CaseTree.hs+52−1
@@ -279,7 +279,8 @@ simpleCase tc defcase reflect phase fc inacc argtys cs erInfo
279279 (tree, st) = runCaseBuilder erInfo
280280 (match ns' ps' defcase)
281281 ([], numargs, [])
282− t = CaseDef ns (prune proj (depatt ns' tree)) (fstT st) in
282+ sc = removeUnreachable (prune proj (depatt ns' tree))
283+ t = CaseDef ns sc (fstT st) in
283284 if proj then return (stripLambdas t)
284285 else return t
285286 Error err -> Error (At fc err)
@@ -765,6 +766,56 @@ prune proj (Case up n alts) = case alts' of
765766
766767prune _ t = t
767768
769+-- Remove any branches we can't reach because of variables we've already
770+-- tested
771+removeUnreachable :: SC -> SC
772+removeUnreachable sc = ru [] sc
773+ where
774+ -- keep a mapping from variable names, to the constructor tag we've
775+ -- already checked it as in this branch
776+ ru :: [(Name, Int)] -> SC -> SC
777+ ru checked (Case t n alts)
778+ = let alts' = map (ruAlt checked n) (dropImpossible (lookup n checked) alts) in
779+ Case t n alts'
780+ ru checked t = t
781+
782+ dropImpossible Nothing alts = alts
783+ dropImpossible (Just t) [] = []
784+ dropImpossible (Just t) (ConCase con tag args sc : rest)
785+ | t == tag = [ConCase con tag args sc] -- must be this case
786+ | otherwise = dropImpossible (Just t) rest -- can't be this case
787+ dropImpossible (Just t) (c : rest)
788+ = c : dropImpossible (Just t) rest
789+
790+ ruAlt :: [(Name, Int)] -> Name -> CaseAlt -> CaseAlt
791+ ruAlt checked var (ConCase con tag args sc)
792+ = let checked' = dropChecked args (updateChecked var tag checked)
793+ sc' = ru checked' sc in
794+ ConCase con tag args sc'
795+ ruAlt checked var (FnCase n args sc)
796+ = let checked' = dropChecked [var] checked
797+ sc' = ru checked' sc in
798+ FnCase n args sc'
799+ ruAlt checked var (ConstCase c sc)
800+ = let checked' = dropChecked [var] checked
801+ sc' = ru checked' sc in
802+ ConstCase c sc'
803+ ruAlt checked var (SucCase n sc)
804+ = let checked' = dropChecked [var] checked
805+ sc' = ru checked' sc in
806+ SucCase n sc'
807+ ruAlt checked var (DefaultCase sc)
808+ = let checked' = dropChecked [var] checked
809+ sc' = ru checked' sc in
810+ DefaultCase sc'
811+
812+ updateChecked :: Name -> Int -> [(Name, Int)] -> [(Name, Int)]
813+ updateChecked n i checked
814+ = (n, i) : filter (\x -> fst x /= n) checked
815+
816+ dropChecked :: [Name] -> [(Name, Int)] -> [(Name, Int)]
817+ dropChecked ns checked = filter (\x -> fst x `notElem` ns) checked
818+
768819stripLambdas :: CaseDef -> CaseDef
769820stripLambdas (CaseDef ns (STerm (Bind x (Lam _ _) sc)) tm)
770821 = stripLambdas (CaseDef (ns ++ [x]) (STerm (instantiate (P Bound x Erased) sc)) tm)
stack-nightly.yamlnew file+17
@@ -0,0 +1,17 @@
1+#recheck extra-deps next on resolver or cabal file change
2+resolver: nightly-2017-11-25
3+
4+packages:
5+ - location: .
6+
7+flags:
8+ idris:
9+ FFI: true
10+ GMP: true
11+
12+ghc-options:
13+ idris: -fwarn-unused-imports -fwarn-unused-binds
14+
15+nix:
16+ enable: false
17+ shell-file: stack-shell.nix
stack.yaml+6−1
@@ -1,9 +1,14 @@
11#recheck extra-deps next on resolver or cabal file change
2−resolver: nightly-2017-11-25
2+resolver: lts-9.17
33
44packages:
55 - location: .
66
7+extra-deps:
8+ - binary-0.8.5.1
9+ - cheapskate-0.1.1
10+ - megaparsec-6.2.0
11+
712flags:
813 idris:
914 FFI: true