@@ -1,12 +1,8 @@
1module Optimize (optimize) where
1module Optimize (optimize) where
3import Control.Applicative
3import Control.Applicative
4−import Control.Arrow (second)
5import qualified Control.Monad as M
4import qualified Control.Monad as M
6import qualified Control.Monad.State as State
5import qualified Control.Monad.State as State
7−import qualified Data.Map as Map
9−import qualified Data.Maybe as Maybe
10import qualified Data.Traversable as T
6import qualified Data.Traversable as T
12import qualified AST.Expression.General as Expr
8import qualified AST.Expression.General as Expr
@@ -16,8 +12,8 @@ import qualified AST.Module as Module
16import qualified AST.Module.Name as ModuleName
12import qualified AST.Module.Name as ModuleName
17import qualified AST.Pattern as P
13import qualified AST.Pattern as P
18import qualified AST.Variable as Var
14import qualified AST.Variable as Var
19−import Elm.Utils ((|>))
15+import qualified Optimize.Environment as Env
20−import qualified Optimize.Cases as Cases
16+import qualified Optimize.Patterns as Patterns
21import qualified Reporting.Annotation as A
17import qualified Reporting.Annotation as A
22import qualified Reporting.Region as R
18import qualified Reporting.Region as R
@@ -35,7 +31,7 @@ optimize module_ =
36 State.evalState
32 State.evalState
37 (concat <$> mapM (optimizeDef (Just home)) defs)
33 (concat <$> mapM (optimizeDef (Just home)) defs)
38− (Env False 0)
34+ (Env.Env False 0)
41flattenLets :: [Can.Def] -> Can.Expr -> ([Can.Def], Can.Expr)
37flattenLets :: [Can.Def] -> Can.Expr -> ([Can.Def], Can.Expr)
@@ -48,32 +44,9 @@ flattenLets defs annExpr@(A.A _ expr) =
48 (defs, annExpr)
44 (defs, annExpr)
51−-- TRACKER TO THREAD FINDINGS THROUGH TRAVERSAL
58− { _hasTailCall :: Bool
63−setTailCall :: Bool -> Optimizer ()
65− do uid <- State.gets _uid
66− State.put (Env bool uid)
69−mapSnd :: M.Functor box => (a -> box b) -> (x, a) -> box (x, b)
74-- CONVERT DEFINITIONS
47-- CONVERT DEFINITIONS
76−optimizeDef :: Maybe ModuleName.Canonical -> Can.Def -> Optimizer [Opt.Def]
49+optimizeDef :: Maybe ModuleName.Canonical -> Can.Def -> Env.Optimizer [Opt.Def]
77optimizeDef home (Can.Definition (Can.Facts deps) pattern@(A.A _ ptrn) expression _) =
50optimizeDef home (Can.Definition (Can.Facts deps) pattern@(A.A _ ptrn) expression _) =
79 (args, rawBody) =
52 (args, rawBody) =
@@ -82,13 +55,13 @@ optimizeDef home (Can.Definition (Can.Facts deps) pattern@(A.A _ ptrn) expressio
82 case (ptrn, args) of
55 case (ptrn, args) of
83 (P.Var name, _ : _) ->
56 (P.Var name, _ : _) ->
85− do (Env htc uid) <- State.get
58+ do (Env.Env htc uid) <- State.get
86− State.put (Env False uid)
59+ State.put (Env.Env False uid)
88 (args, body) <- optimizeFunction (Just name) args rawBody
61 (args, body) <- optimizeFunction (Just name) args rawBody
90− (Env isTailCall uid') <- State.get
63+ (Env.Env isTailCall uid') <- State.get
91− State.put (Env htc uid')
64+ State.put (Env.Env htc uid')
93 let facts = Opt.Facts home deps
66 let facts = Opt.Facts home deps
@@ -103,14 +76,14 @@ optimizeDef home (Can.Definition (Can.Facts deps) pattern@(A.A _ ptrn) expressio
104 (P.Var name, []) ->
77 (P.Var name, []) ->
106− do hasTailCall <- State.gets _hasTailCall
79+ do hasTailCall <- State.gets Env._hasTailCall
107 body <- optimizeExpr Nothing rawBody
80 body <- optimizeExpr Nothing rawBody
108− setTailCall hasTailCall
81+ Env.setTailCall hasTailCall
109 return [ Opt.Def (Opt.Facts home deps) name body ]
82 return [ Opt.Def (Opt.Facts home deps) name body ]
111 (_, []) ->
84 (_, []) ->
113− do name <- freshName
86+ do name <- Env.freshName
114 optBody <- optimizeExpr Nothing rawBody
87 optBody <- optimizeExpr Nothing rawBody
115 let optDef = Opt.Def (Opt.Facts home deps) name optBody
88 let optDef = Opt.Def (Opt.Facts home deps) name optBody
116 return (optDef : patternToDefs home name pattern)
89 return (optDef : patternToDefs home name pattern)
@@ -125,7 +98,7 @@ optimizeFunction
125 :: Maybe String
98 :: Maybe String
126 -> [P.CanonicalPattern]
99 -> [P.CanonicalPattern]
127 -> Can.Expr
100 -> Can.Expr
128− -> Optimizer ([String], Opt.Expr)
101+ -> Env.Optimizer ([String], Opt.Expr)
129optimizeFunction maybeName patterns givenBody =
102optimizeFunction maybeName patterns givenBody =
130 do (argNames, body) <- M.foldM depatternArgs ([], givenBody) (reverse patterns)
103 do (argNames, body) <- M.foldM depatternArgs ([], givenBody) (reverse patterns)
131 optBody <- optimizeExpr (makeContext argNames =<< maybeName) body
104 optBody <- optimizeExpr (makeContext argNames =<< maybeName) body
@@ -140,7 +113,7 @@ makeContext argNames name =
140depatternArgs
113depatternArgs
141 :: ([String], Can.Expr)
114 :: ([String], Can.Expr)
142 -> P.CanonicalPattern
115 -> P.CanonicalPattern
143− -> Optimizer ([String], Can.Expr)
116+ -> Env.Optimizer ([String], Can.Expr)
144depatternArgs (names, rawExpr) ptrn =
117depatternArgs (names, rawExpr) ptrn =
145 do (name, expr) <- depattern ptrn rawExpr
118 do (name, expr) <- depattern ptrn rawExpr
146 return (name : names, expr)
119 return (name : names, expr)
@@ -203,7 +176,7 @@ function arity, and list of argument names. If a tail call is possible, the
203`Context` will be filled in and we check any function we run into. If we go
176`Context` will be filled in and we check any function we run into. If we go
204down a route that cannot possibly have tail calls, we remove the context.
177down a route that cannot possibly have tail calls, we remove the context.
206−optimizeExpr :: Context -> Can.Expr -> Optimizer Opt.Expr
179+optimizeExpr :: Context -> Can.Expr -> Env.Optimizer Opt.Expr
207optimizeExpr context annExpr@(A.A region expression) =
180optimizeExpr context annExpr@(A.A region expression) =
209 keepLooking =
182 keepLooking =
@@ -250,17 +223,16 @@ optimizeExpr context annExpr@(A.A region expression) =
250 case isTailCall context func (length args) of
223 case isTailCall context func (length args) of
251 Just (name, argNames) ->
224 Just (name, argNames) ->
252 do optArgs <- T.traverse justConvert args
225 do optArgs <- T.traverse justConvert args
253− setTailCall True
226+ Env.setTailCall True
254 return (Opt.TailCall name argNames optArgs)
227 return (Opt.TailCall name argNames optArgs)
256 Nothing ->
229 Nothing ->
257− do hasTailCall <- State.gets _hasTailCall
230+ do hasTailCall <- State.gets Env._hasTailCall
258 optFunc <- justConvert func
231 optFunc <- justConvert func
259 optArgs <- T.traverse justConvert args
232 optArgs <- T.traverse justConvert args
260− setTailCall hasTailCall
233+ Env.setTailCall hasTailCall
261 return (Opt.Call optFunc optArgs)
234 return (Opt.Call optFunc optArgs)
264 Expr.If branches finally ->
236 Expr.If branches finally ->
266 crawlBranch (cond,branch) =
238 crawlBranch (cond,branch) =
@@ -275,7 +247,9 @@ optimizeExpr context annExpr@(A.A region expression) =
275 Opt.Let optDefs <$> keepLooking body
247 Opt.Let optDefs <$> keepLooking body
277 Expr.Case expr branches ->
249 Expr.Case expr branches ->
278− optimizeCase context region expr branches
250+ do optExpr <- optimizeExpr Nothing expr
251+ optBranches <- T.traverse (mapSnd (optimizeExpr context)) branches
252+ Patterns.optimize region optExpr optBranches
280 Expr.Data name exprs ->
254 Expr.Data name exprs ->
281 Opt.Data name <$> T.traverse justConvert exprs
255 Opt.Data name <$> T.traverse justConvert exprs
@@ -310,6 +284,11 @@ optimizeExpr context annExpr@(A.A region expression) =
310 (\e -> Expr.Task name e tipe) <$> justConvert expr
284 (\e -> Expr.Task name e tipe) <$> justConvert expr
287+mapSnd :: M.Functor box => (a -> box b) -> (x, a) -> box (x, b)
313-- DETECT TAIL CALL
292-- DETECT TAIL CALL
315isTailCall :: Context -> Can.Expr -> Int -> Maybe (String, [String])
294isTailCall :: Context -> Can.Expr -> Int -> Maybe (String, [String])
@@ -327,13 +306,12 @@ isTailCall context (A.A _ function) arity =
331-- DEPATTERN
309-- DEPATTERN
332-- given a pattern and an expression, push the actual pattern matching into the
310-- given a pattern and an expression, push the actual pattern matching into the
333-- expression as a case-expression if necessary. The pattern compiler will work
311-- expression as a case-expression if necessary. The pattern compiler will work
334-- it out from there
312-- it out from there
336−depattern :: P.CanonicalPattern -> Can.Expr -> Optimizer (String, Can.Expr)
314+depattern :: P.CanonicalPattern -> Can.Expr -> Env.Optimizer (String, Can.Expr)
337depattern canPattern@(A.A _ pattern) expr =
315depattern canPattern@(A.A _ pattern) expr =
@@ -346,7 +324,7 @@ depattern canPattern@(A.A _ pattern) expr =
346 ann (Expr.Var (Var.local name))
324 ann (Expr.Var (Var.local name))
348 caseify =
326 caseify =
349− do name <- freshName
327+ do name <- Env.freshName
352 , caseExpr (var name) [ (canPattern, expr) ]
330 , caseExpr (var name) [ (canPattern, expr) ]
@@ -363,7 +341,7 @@ depattern canPattern@(A.A _ pattern) expr =
365 P.Anything ->
343 P.Anything ->
366− do name <- freshName
344+ do name <- Env.freshName
367 return (name, expr)
345 return (name, expr)
369 P.Alias _ _ ->
347 P.Alias _ _ ->
@@ -373,122 +351,6 @@ depattern canPattern@(A.A _ pattern) expr =
376−freshName :: Optimizer String
378− do (Env htc uid) <- State.get
379− State.put (Env htc (uid + 1))
380− return ("_p" ++ show uid)
389− -> [(P.CanonicalPattern, Can.Expr)]
390− -> Optimizer Opt.Expr
391−optimizeCase context region expr rawBranches =
393− indexify index (pattern, branch) =
398− do optBranches <- T.traverse (mapSnd (optimizeExpr context)) rawBranches
400− case last optBranches of
401− (A.A ann P.Anything, Opt.Call (Opt.Crash _ _) [arg]) ->
402− do name <- freshName
403− let newPattern = A.A ann (P.Var name)
404− let newCall = Opt.Call (Opt.Crash region (Just name)) [arg]
405− return (init optBranches ++ [(newPattern, newCall)])
410− let (patterns, indexedBranches) =
411− unzip (zipWith indexify [0..] crashBranches)
414− Cases.compile (error "need a VariantDict") patterns
416− optExpr <- optimizeExpr Nothing expr
418− return (inlinedCase optExpr decisionTree indexedBranches)
423− -> Cases.DecisionTree Cases.Jump
424− -> [(Int, Opt.Expr)]
426−inlinedCase expr decisionTree jumpTargets =
429− gatherSubstitutions decisionTree
431− (jumps, sharedBranches) =
432− unzip (map (toJumps substitutionDict) jumpTargets)
436− (inlineJumps (Map.fromList jumps) decisionTree)
437− (Maybe.catMaybes sharedBranches)
441− :: Cases.DecisionTree Cases.Jump
442− -> Map.Map Int [[(String, Cases.Path)]]
443−gatherSubstitutions decisionTree =
444− case decisionTree of
445− Cases.Decision _ edges fallback ->
447− |> maybe id (:) fallback
448− |> map gatherSubstitutions
449− |> Map.unionsWith (++)
451− Cases.Match (Cases.Jump target substitutions) ->
452− Map.singleton target [substitutions]
456− :: Map.Map Int [[(String, Cases.Path)]]
458− -> ( (Int, Opt.Jump), Maybe (Int, Opt.Branch) )
459−toJumps substitutionDict (target, branch) =
460− case substitutionDict ! target of
462− ( (target, Opt.Inline (Opt.Branch substitutions branch))
466− substitutions : _ ->
467− ( (target, Opt.Jump target)
468− , Just (target, Opt.Branch substitutions branch)
472− error "it is not possible for there to be no substitutions"
476− :: Map.Map Int Opt.Jump
477− -> Cases.DecisionTree Cases.Jump
478− -> Cases.DecisionTree Opt.Jump
479−inlineJumps jumpDict decisionTree =
482− inlineJumps jumpDict
484− case decisionTree of
485− Cases.Decision test edges fallback ->
486− Cases.Decision test (map (second go) edges) (fmap go fallback)
488− Cases.Match (Cases.Jump target _) ->
489− Cases.Match (jumpDict ! target)
492-- OPTIMIZE BINOPS
354-- OPTIMIZE BINOPS
494optimizeBinop
356optimizeBinop
@@ -497,7 +359,7 @@ optimizeBinop
497 -> Var.Canonical
359 -> Var.Canonical
498 -> Can.Expr
360 -> Can.Expr
499 -> Can.Expr
361 -> Can.Expr
500− -> Optimizer Opt.Expr
362+ -> Env.Optimizer Opt.Expr
501optimizeBinop context region op leftExpr rightExpr =
363optimizeBinop context region op leftExpr rightExpr =
503 ann = A.A region
365 ann = A.A region
@@ -513,14 +375,14 @@ optimizeBinop context region op leftExpr rightExpr =
514 else if op == forwardCompose then
376 else if op == forwardCompose then
516− do var <- freshName
378+ do var <- Env.freshName
517 let makeRoot func = ann (Expr.App func (ann (Expr.Var (Var.local var))))
379 let makeRoot func = ann (Expr.App func (ann (Expr.Var (Var.local var))))
518 let body = collect makeRoot left forwardCompose binop
380 let body = collect makeRoot left forwardCompose binop
519 optimizeExpr context (ann (Expr.Lambda (ann (P.Var var)) body))
381 optimizeExpr context (ann (Expr.Lambda (ann (P.Var var)) body))
521 else if op == backwardCompose then
383 else if op == backwardCompose then
523− do var <- freshName
385+ do var <- Env.freshName
524 let makeRoot func = ann (Expr.App func (ann (Expr.Var (Var.local var))))
386 let makeRoot func = ann (Expr.App func (ann (Expr.Var (Var.local var))))
525 let body = collect makeRoot right backwardCompose binop
387 let body = collect makeRoot right backwardCompose binop
526 optimizeExpr context (ann (Expr.Lambda (ann (P.Var var)) body))
388 optimizeExpr context (ann (Expr.Lambda (ann (P.Var var)) body))