1{-# OPTIONS_GHC -Wall #-}
2{-# LANGUAGE OverloadedStrings #-}
3module Optimize.Expression
7 , optimizePotentialTailCall
12import Prelude hiding (cycle)
13import Control.Monad (foldM)
14import qualified Data.Set as Set
16import qualified AST.Canonical as Can
17import qualified AST.Optimized as Opt
18import qualified AST.Module.Name as ModuleName
19import qualified Data.Index as Index
20import qualified Elm.Name as N
21import qualified Optimize.Case as Case
22import qualified Optimize.Names as Names
23import qualified Reporting.Annotation as A
34optimize :: Cycle -> Can.Expr -> Names.Tracker Opt.Expr
35optimize cycle (A.At region expression) =
38 pure (Opt.VarLocal name)
40 Can.VarTopLevel home name ->
41 if Set.member name cycle then
42 pure (Opt.VarCycle home name)
44 Names.registerGlobal home name
46 Can.VarKernel home name ->
47 Names.registerKernel home (Opt.VarKernel home name)
49 Can.VarForeign home name _ ->
50 Names.registerGlobal home name
52 Can.VarCtor opts home name index _ ->
53 Names.registerCtor home name index opts
55 Can.VarDebug home name _ ->
56 Names.registerDebug name home region
58 Can.VarOperator _ home name _ ->
59 Names.registerGlobal home name
62 Names.registerKernel N.utils (Opt.Chr chr)
71 pure (Opt.Float float)
74 Names.registerKernel N.list Opt.List
75 <*> traverse (optimize cycle) entries
78 do func <- Names.registerGlobal ModuleName.basics N.negate
79 arg <- optimize cycle expr
80 pure $ Opt.Call func [arg]
82 Can.Binop _ home name _ left right ->
83 do optFunc <- Names.registerGlobal home name
84 optLeft <- optimize cycle left
85 optRight <- optimize cycle right
86 return (Opt.Call optFunc [optLeft, optRight])
88 Can.Lambda args body ->
89 do (argNames, destructors) <- destructArgs args
90 obody <- optimize cycle body
91 pure $ Opt.Function argNames (foldr Opt.Destruct obody destructors)
95 <$> optimize cycle func
96 <*> traverse (optimize cycle) args
98 Can.If branches finally ->
100 optimizeBranch (condition, branch) =
102 <$> optimize cycle condition
103 <*> optimize cycle branch
106 <$> traverse optimizeBranch branches
107 <*> optimize cycle finally
110 optimizeDef cycle def =<< optimize cycle body
112 Can.LetRec defs body ->
116 <$> optimizePotentialTailCall cycle def
117 <*> optimize cycle body
120 do obody <- optimize cycle body
121 foldM (\bod def -> optimizeDef cycle def bod) obody defs
123 Can.LetDestruct pattern expr body ->
124 do (name, destructs) <- destruct pattern
125 oexpr <- optimize cycle expr
126 obody <- optimize cycle body
128 Opt.Let (Opt.Def name oexpr) (foldr Opt.Destruct obody destructs)
130 Can.Case expr branches ->
132 optimizeBranch root (Can.CaseBranch pattern branch) =
133 do destructors <- destructCase root pattern
134 obranch <- optimize cycle branch
135 pure (pattern, foldr Opt.Destruct obranch destructors)
137 do temp <- Names.generate
138 oexpr <- optimize cycle expr
141 Case.optimize temp root <$> traverse (optimizeBranch root) branches
144 do obranches <- traverse (optimizeBranch temp) branches
145 return $ Opt.Let (Opt.Def temp oexpr) (Case.optimize temp temp obranches)
147 Can.Accessor field ->
148 Names.registerField field (Opt.Accessor field)
150 Can.Access record (A.At _ field) ->
151 do optRecord <- optimize cycle record
152 Names.registerField field (Opt.Access optRecord field)
154 Can.Update _ record updates ->
155 Names.registerFieldDict updates Opt.Update
156 <*> optimize cycle record
157 <*> traverse (optimizeUpdate cycle) updates
160 Names.registerFieldDict fields Opt.Record
161 <*> traverse (optimize cycle) fields
164 Names.registerKernel N.utils Opt.Unit
166 Can.Tuple a b maybeC ->
167 Names.registerKernel N.utils Opt.Tuple
170 <*> traverse (optimize cycle) maybeC
172 Can.Shader _ src _ ->
173 pure (Opt.Shader src)
180optimizeUpdate :: Cycle -> Can.FieldUpdate -> Names.Tracker Opt.Expr
181optimizeUpdate cycle (Can.FieldUpdate _ expr) =
189optimizeDef :: Cycle -> Can.Def -> Opt.Expr -> Names.Tracker Opt.Expr
190optimizeDef cycle def body =
192 Can.Def (A.At _ name) args expr ->
193 optimizeDefHelp cycle name args expr body
195 Can.TypedDef (A.At _ name) _ typedArgs expr _ ->
196 optimizeDefHelp cycle name (map fst typedArgs) expr body
199optimizeDefHelp :: Cycle -> N.Name -> [Can.Pattern] -> Can.Expr -> Opt.Expr -> Names.Tracker Opt.Expr
200optimizeDefHelp cycle name args expr body =
201 do oexpr <- optimize cycle expr
204 pure $ Opt.Let (Opt.Def name oexpr) body
207 do (argNames, destructors) <- destructArgs args
208 let ofunc = Opt.Function argNames (foldr Opt.Destruct oexpr destructors)
209 pure $ Opt.Let (Opt.Def name ofunc) body
216destructArgs :: [Can.Pattern] -> Names.Tracker ([N.Name], [Opt.Destructor])
218 do (argNames, destructorLists) <- unzip <$> traverse destruct args
219 return (argNames, concat destructorLists)
222destructCase :: N.Name -> Can.Pattern -> Names.Tracker [Opt.Destructor]
223destructCase rootName pattern =
224 reverse <$> destructHelp (Opt.Root rootName) pattern []
227destruct :: Can.Pattern -> Names.Tracker (N.Name, [Opt.Destructor])
228destruct pattern@(A.At _ ptrn) =
233 Can.PAlias subPattern name ->
234 do revDs <- destructHelp (Opt.Root name) subPattern []
235 pure (name, reverse revDs)
238 do name <- Names.generate
239 revDs <- destructHelp (Opt.Root name) pattern []
240 pure (name, reverse revDs)
243destructHelp :: Opt.Path -> Can.Pattern -> [Opt.Destructor] -> Names.Tracker [Opt.Destructor]
244destructHelp path (A.At region pattern) revDs =
250 pure (Opt.Destructor name path : revDs)
252 Can.PRecord fields ->
255 Opt.Destructor name (Opt.Field name path)
257 Names.registerFieldList fields (map toDestruct fields ++ revDs)
259 Can.PAlias subPattern name ->
260 destructHelp (Opt.Root name) subPattern $
261 Opt.Destructor name path : revDs
266 Can.PTuple a b Nothing ->
267 destructTwo path a b revDs
269 Can.PTuple a b (Just c) ->
272 destructHelp (Opt.Index Index.third path) c =<<
273 destructHelp (Opt.Index Index.second path) b =<<
274 destructHelp (Opt.Index Index.first path) a revDs
277 do name <- Names.generate
278 let newRoot = Opt.Root name
279 destructHelp (Opt.Index Index.third newRoot) c =<<
280 destructHelp (Opt.Index Index.second newRoot) b =<<
281 destructHelp (Opt.Index Index.first newRoot) a (Opt.Destructor name path : revDs)
287 destructTwo path hd (A.At region (Can.PList tl)) revDs
290 destructTwo path hd tl revDs
304 Can.PCtor _ _ (Can.Union _ _ _ opts) _ _ args ->
306 [Can.PatternCtorArg _ _ arg] ->
308 Can.Normal -> destructHelp (Opt.Index Index.first path) arg revDs
309 Can.Unbox -> destructHelp (Opt.Unbox path) arg revDs
310 Can.Enum -> destructHelp (Opt.Index Index.first path) arg revDs
315 foldM (destructCtorArg path) revDs args
318 do name <- Names.generate
319 foldM (destructCtorArg (Opt.Root name)) (Opt.Destructor name path : revDs) args
322destructTwo :: Opt.Path -> Can.Pattern -> Can.Pattern -> [Opt.Destructor] -> Names.Tracker [Opt.Destructor]
323destructTwo path a b revDs =
326 destructHelp (Opt.Index Index.second path) b =<<
327 destructHelp (Opt.Index Index.first path) a revDs
330 do name <- Names.generate
331 let newRoot = Opt.Root name
332 destructHelp (Opt.Index Index.second newRoot) b =<<
333 destructHelp (Opt.Index Index.first newRoot) a (Opt.Destructor name path : revDs)
336destructCtorArg :: Opt.Path -> [Opt.Destructor] -> Can.PatternCtorArg -> Names.Tracker [Opt.Destructor]
337destructCtorArg path revDs (Can.PatternCtorArg index _ arg) =
338 destructHelp (Opt.Index index path) arg revDs
345optimizePotentialTailCall :: Cycle -> Can.Def -> Names.Tracker Opt.Def
346optimizePotentialTailCall cycle def =
348 Can.Def (A.At _ name) args expr ->
349 do (argNames, destructors) <- destructArgs args
350 toTailDef name argNames destructors <$>
351 optimizeTail cycle name argNames expr
353 Can.TypedDef (A.At _ name) _ typedArgs expr _ ->
354 do (argNames, destructors) <- destructArgs (map fst typedArgs)
355 toTailDef name argNames destructors <$>
356 optimizeTail cycle name argNames expr
359optimizeTail :: Cycle -> N.Name -> [N.Name] -> Can.Expr -> Names.Tracker Opt.Expr
360optimizeTail cycle rootName argNames locExpr@(A.At _ expression) =
362 Can.Call func@(A.At _ (Can.VarTopLevel _ name)) args ->
363 do oargs <- traverse (optimize cycle) args
366 case Index.indexedZipWith (\_ a b -> (a,b)) argNames oargs of
367 Index.LengthMatch pairs ->
368 pure $ Opt.TailCall name pairs
370 Index.LengthMismatch _ _ ->
371 do ofunc <- optimize cycle func
372 pure $ Opt.Call ofunc oargs
374 do ofunc <- optimize cycle func
375 pure $ Opt.Call ofunc oargs
377 Can.If branches finally ->
379 optimizeBranch (condition, branch) =
381 <$> optimize cycle condition
382 <*> optimizeTail cycle rootName argNames branch
385 <$> traverse optimizeBranch branches
386 <*> optimizeTail cycle rootName argNames finally
389 optimizeDef cycle def =<< optimizeTail cycle rootName argNames body
391 Can.LetRec defs body ->
395 <$> optimizePotentialTailCall cycle def
396 <*> optimizeTail cycle rootName argNames body
399 do obody <- optimizeTail cycle rootName argNames body
400 foldM (\bod def -> optimizeDef cycle def bod) obody defs
402 Can.LetDestruct pattern expr body ->
403 do (dname, destructors) <- destruct pattern
404 oexpr <- optimize cycle expr
405 obody <- optimizeTail cycle dname argNames body
407 Opt.Let (Opt.Def dname oexpr) (foldr Opt.Destruct obody destructors)
409 Can.Case expr branches ->
411 optimizeBranch root (Can.CaseBranch pattern branch) =
412 do destructors <- destructCase root pattern
413 obranch <- optimizeTail cycle rootName argNames branch
414 pure (pattern, foldr Opt.Destruct obranch destructors)
416 do temp <- Names.generate
417 oexpr <- optimize cycle expr
420 Case.optimize temp root <$> traverse (optimizeBranch root) branches
423 do obranches <- traverse (optimizeBranch temp) branches
424 return $ Opt.Let (Opt.Def temp oexpr) (Case.optimize temp temp obranches)
427 optimize cycle locExpr
434toTailDef :: N.Name -> [N.Name] -> [Opt.Destructor] -> Opt.Expr -> Opt.Def
435toTailDef name argNames destructors body =
436 if hasTailCall body then
437 Opt.TailDef name argNames (foldr Opt.Destruct body destructors)
439 Opt.Def name (Opt.Function argNames (foldr Opt.Destruct body destructors))
442hasTailCall :: Opt.Expr -> Bool
443hasTailCall expression =
448 Opt.If branches finally ->
449 hasTailCall finally || any (hasTailCall . snd) branches
454 Opt.Destruct _ body ->
457 Opt.Case _ _ decider jumps ->
458 decidecHasTailCall decider || any (hasTailCall . snd) jumps
464decidecHasTailCall :: Opt.Decider Opt.Choice -> Bool
465decidecHasTailCall decider =
475 Opt.Chain _ success failure ->
476 decidecHasTailCall success || decidecHasTailCall failure
478 Opt.FanOut _ tests fallback ->
479 decidecHasTailCall fallback || any (decidecHasTailCall . snd) tests
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