1{-# OPTIONS_GHC -Wall #-}
2{-# LANGUAGE OverloadedStrings #-}
3module Optimize.Expression
6 , optimizePotentialTailCall
11import Prelude hiding (cycle)
12import Control.Monad (foldM)
13import qualified Data.Map as Map
14import qualified Data.Name as Name
15import qualified Data.Set as Set
17import qualified AST.Canonical as Can
18import qualified AST.Optimized as Opt
19import qualified AST.Utils.Shader as Shader
20import qualified Data.Index as Index
21import qualified Elm.ModuleName as ModuleName
22import qualified Optimize.Case as Case
23import qualified Optimize.Names as Names
24import qualified Reporting.Annotation as A
35optimize :: Cycle -> Can.Expr -> Names.Tracker Opt.Expr
36optimize cycle (A.At region expression) =
39 pure (Opt.VarLocal name)
41 Can.VarTopLevel home name ->
42 if Set.member name cycle then
43 pure (Opt.VarCycle home name)
45 Names.registerGlobal home name
47 Can.VarKernel home name ->
48 Names.registerKernel home (Opt.VarKernel home name)
50 Can.VarForeign home name _ ->
51 Names.registerGlobal home name
53 Can.VarCtor opts home name index _ ->
54 Names.registerCtor home name index opts
56 Can.VarDebug home name _ ->
57 Names.registerDebug name home region
59 Can.VarOperator _ home name _ ->
60 Names.registerGlobal home name
63 Names.registerKernel Name.utils (Opt.Chr chr)
72 pure (Opt.Float float)
75 Names.registerKernel Name.list Opt.List
76 <*> traverse (optimize cycle) entries
79 do func <- Names.registerGlobal ModuleName.basics Name.negate
80 arg <- optimize cycle expr
81 pure $ Opt.Call func [arg]
83 Can.Binop _ home name _ left right ->
84 do optFunc <- Names.registerGlobal home name
85 optLeft <- optimize cycle left
86 optRight <- optimize cycle right
87 return (Opt.Call optFunc [optLeft, optRight])
89 Can.Lambda args body ->
90 do (argNames, destructors) <- destructArgs args
91 obody <- optimize cycle body
92 pure $ Opt.Function argNames (foldr Opt.Destruct obody destructors)
96 <$> optimize cycle func
97 <*> traverse (optimize cycle) args
99 Can.If branches finally ->
101 optimizeBranch (condition, branch) =
103 <$> optimize cycle condition
104 <*> optimize cycle branch
107 <$> traverse optimizeBranch branches
108 <*> optimize cycle finally
111 optimizeDef cycle def =<< optimize cycle body
113 Can.LetRec defs body ->
117 <$> optimizePotentialTailCallDef cycle def
118 <*> optimize cycle body
121 do obody <- optimize cycle body
122 foldM (\bod def -> optimizeDef cycle def bod) obody defs
124 Can.LetDestruct pattern expr body ->
125 do (name, destructs) <- destruct pattern
126 oexpr <- optimize cycle expr
127 obody <- optimize cycle body
129 Opt.Let (Opt.Def name oexpr) (foldr Opt.Destruct obody destructs)
131 Can.Case expr branches ->
133 optimizeBranch root (Can.CaseBranch pattern branch) =
134 do destructors <- destructCase root pattern
135 obranch <- optimize cycle branch
136 pure (pattern, foldr Opt.Destruct obranch destructors)
138 do temp <- Names.generate
139 oexpr <- optimize cycle expr
142 Case.optimize temp root <$> traverse (optimizeBranch root) branches
145 do obranches <- traverse (optimizeBranch temp) branches
146 return $ Opt.Let (Opt.Def temp oexpr) (Case.optimize temp temp obranches)
148 Can.Accessor field ->
149 Names.registerField field (Opt.Accessor field)
151 Can.Access record (A.At _ field) ->
152 do optRecord <- optimize cycle record
153 Names.registerField field (Opt.Access optRecord field)
155 Can.Update _ record updates ->
156 Names.registerFieldDict updates Opt.Update
157 <*> optimize cycle record
158 <*> traverse (optimizeUpdate cycle) updates
161 Names.registerFieldDict fields Opt.Record
162 <*> traverse (optimize cycle) fields
165 Names.registerKernel Name.utils Opt.Unit
167 Can.Tuple a b maybeC ->
168 Names.registerKernel Name.utils Opt.Tuple
171 <*> traverse (optimize cycle) maybeC
173 Can.Shader src (Shader.Types attributes uniforms _varyings) ->
174 pure (Opt.Shader src (Map.keysSet attributes) (Map.keysSet uniforms))
181optimizeUpdate :: Cycle -> Can.FieldUpdate -> Names.Tracker Opt.Expr
182optimizeUpdate cycle (Can.FieldUpdate _ expr) =
190optimizeDef :: Cycle -> Can.Def -> Opt.Expr -> Names.Tracker Opt.Expr
191optimizeDef cycle def body =
193 Can.Def (A.At _ name) args expr ->
194 optimizeDefHelp cycle name args expr body
196 Can.TypedDef (A.At _ name) _ typedArgs expr _ ->
197 optimizeDefHelp cycle name (map fst typedArgs) expr body
200optimizeDefHelp :: Cycle -> Name.Name -> [Can.Pattern] -> Can.Expr -> Opt.Expr -> Names.Tracker Opt.Expr
201optimizeDefHelp cycle name args expr body =
202 do oexpr <- optimize cycle expr
205 pure $ Opt.Let (Opt.Def name oexpr) body
208 do (argNames, destructors) <- destructArgs args
209 let ofunc = Opt.Function argNames (foldr Opt.Destruct oexpr destructors)
210 pure $ Opt.Let (Opt.Def name ofunc) body
217destructArgs :: [Can.Pattern] -> Names.Tracker ([Name.Name], [Opt.Destructor])
219 do (argNames, destructorLists) <- unzip <$> traverse destruct args
220 return (argNames, concat destructorLists)
223destructCase :: Name.Name -> Can.Pattern -> Names.Tracker [Opt.Destructor]
224destructCase rootName pattern =
225 reverse <$> destructHelp (Opt.Root rootName) pattern []
228destruct :: Can.Pattern -> Names.Tracker (Name.Name, [Opt.Destructor])
229destruct pattern@(A.At _ ptrn) =
234 Can.PAlias subPattern name ->
235 do revDs <- destructHelp (Opt.Root name) subPattern []
236 pure (name, reverse revDs)
239 do name <- Names.generate
240 revDs <- destructHelp (Opt.Root name) pattern []
241 pure (name, reverse revDs)
244destructHelp :: Opt.Path -> Can.Pattern -> [Opt.Destructor] -> Names.Tracker [Opt.Destructor]
245destructHelp path (A.At region pattern) revDs =
251 pure (Opt.Destructor name path : revDs)
253 Can.PRecord fields ->
256 Opt.Destructor name (Opt.Field name path)
258 Names.registerFieldList fields (map toDestruct fields ++ revDs)
260 Can.PAlias subPattern name ->
261 destructHelp (Opt.Root name) subPattern $
262 Opt.Destructor name path : revDs
267 Can.PTuple a b Nothing ->
268 destructTwo path a b revDs
270 Can.PTuple a b (Just c) ->
273 destructHelp (Opt.Index Index.third path) c =<<
274 destructHelp (Opt.Index Index.second path) b =<<
275 destructHelp (Opt.Index Index.first path) a revDs
278 do name <- Names.generate
279 let newRoot = Opt.Root name
280 destructHelp (Opt.Index Index.third newRoot) c =<<
281 destructHelp (Opt.Index Index.second newRoot) b =<<
282 destructHelp (Opt.Index Index.first newRoot) a (Opt.Destructor name path : revDs)
288 destructTwo path hd (A.At region (Can.PList tl)) revDs
291 destructTwo path hd tl revDs
305 Can.PCtor _ _ (Can.Union _ _ _ opts) _ _ args ->
307 [Can.PatternCtorArg _ _ arg] ->
309 Can.Normal -> destructHelp (Opt.Index Index.first path) arg revDs
310 Can.Unbox -> destructHelp (Opt.Unbox path) arg revDs
311 Can.Enum -> destructHelp (Opt.Index Index.first path) arg revDs
316 foldM (destructCtorArg path) revDs args
319 do name <- Names.generate
320 foldM (destructCtorArg (Opt.Root name)) (Opt.Destructor name path : revDs) args
323destructTwo :: Opt.Path -> Can.Pattern -> Can.Pattern -> [Opt.Destructor] -> Names.Tracker [Opt.Destructor]
324destructTwo path a b revDs =
327 destructHelp (Opt.Index Index.second path) b =<<
328 destructHelp (Opt.Index Index.first path) a revDs
331 do name <- Names.generate
332 let newRoot = Opt.Root name
333 destructHelp (Opt.Index Index.second newRoot) b =<<
334 destructHelp (Opt.Index Index.first newRoot) a (Opt.Destructor name path : revDs)
337destructCtorArg :: Opt.Path -> [Opt.Destructor] -> Can.PatternCtorArg -> Names.Tracker [Opt.Destructor]
338destructCtorArg path revDs (Can.PatternCtorArg index _ arg) =
339 destructHelp (Opt.Index index path) arg revDs
346optimizePotentialTailCallDef :: Cycle -> Can.Def -> Names.Tracker Opt.Def
347optimizePotentialTailCallDef cycle def =
349 Can.Def (A.At _ name) args expr ->
350 optimizePotentialTailCall cycle name args expr
352 Can.TypedDef (A.At _ name) _ typedArgs expr _ ->
353 optimizePotentialTailCall cycle name (map fst typedArgs) expr
356optimizePotentialTailCall :: Cycle -> Name.Name -> [Can.Pattern] -> Can.Expr -> Names.Tracker Opt.Def
357optimizePotentialTailCall cycle name args expr =
358 do (argNames, destructors) <- destructArgs args
359 toTailDef name argNames destructors <$>
360 optimizeTail cycle name argNames expr
363optimizeTail :: Cycle -> Name.Name -> [Name.Name] -> Can.Expr -> Names.Tracker Opt.Expr
364optimizeTail cycle rootName argNames locExpr@(A.At _ expression) =
366 Can.Call func args ->
367 do oargs <- traverse (optimize cycle) args
370 case A.toValue func of
371 Can.VarLocal name -> rootName == name
372 Can.VarTopLevel _ name -> rootName == name
377 case Index.indexedZipWith (\_ a b -> (a,b)) argNames oargs of
378 Index.LengthMatch pairs ->
379 pure $ Opt.TailCall rootName pairs
381 Index.LengthMismatch _ _ ->
382 do ofunc <- optimize cycle func
383 pure $ Opt.Call ofunc oargs
385 do ofunc <- optimize cycle func
386 pure $ Opt.Call ofunc oargs
388 Can.If branches finally ->
390 optimizeBranch (condition, branch) =
392 <$> optimize cycle condition
393 <*> optimizeTail cycle rootName argNames branch
396 <$> traverse optimizeBranch branches
397 <*> optimizeTail cycle rootName argNames finally
400 optimizeDef cycle def =<< optimizeTail cycle rootName argNames body
402 Can.LetRec defs body ->
406 <$> optimizePotentialTailCallDef cycle def
407 <*> optimizeTail cycle rootName argNames body
410 do obody <- optimizeTail cycle rootName argNames body
411 foldM (\bod def -> optimizeDef cycle def bod) obody defs
413 Can.LetDestruct pattern expr body ->
414 do (dname, destructors) <- destruct pattern
415 oexpr <- optimize cycle expr
416 obody <- optimizeTail cycle rootName argNames body
418 Opt.Let (Opt.Def dname oexpr) (foldr Opt.Destruct obody destructors)
420 Can.Case expr branches ->
422 optimizeBranch root (Can.CaseBranch pattern branch) =
423 do destructors <- destructCase root pattern
424 obranch <- optimizeTail cycle rootName argNames branch
425 pure (pattern, foldr Opt.Destruct obranch destructors)
427 do temp <- Names.generate
428 oexpr <- optimize cycle expr
431 Case.optimize temp root <$> traverse (optimizeBranch root) branches
434 do obranches <- traverse (optimizeBranch temp) branches
435 return $ Opt.Let (Opt.Def temp oexpr) (Case.optimize temp temp obranches)
438 optimize cycle locExpr
445toTailDef :: Name.Name -> [Name.Name] -> [Opt.Destructor] -> Opt.Expr -> Opt.Def
446toTailDef name argNames destructors body =
447 if hasTailCall body then
448 Opt.TailDef name argNames (foldr Opt.Destruct body destructors)
450 Opt.Def name (Opt.Function argNames (foldr Opt.Destruct body destructors))
453hasTailCall :: Opt.Expr -> Bool
454hasTailCall expression =
459 Opt.If branches finally ->
460 hasTailCall finally || any (hasTailCall . snd) branches
465 Opt.Destruct _ body ->
468 Opt.Case _ _ decider jumps ->
469 decidecHasTailCall decider || any (hasTailCall . snd) jumps
475decidecHasTailCall :: Opt.Decider Opt.Choice -> Bool
476decidecHasTailCall decider =
486 Opt.Chain _ success failure ->
487 decidecHasTailCall success || decidecHasTailCall failure
489 Opt.FanOut _ tests fallback ->
490 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