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.registerKernel N.debug (Opt.VarDebug name home region Nothing)
58 Can.VarOperator _ home name _ ->
59 Names.registerGlobal home name
62 Names.registerKernel N.utils (Opt.Chr chr)
71 pure (Opt.Float float)
74 Opt.List <$> traverse (optimize cycle) entries
77 do func <- Names.registerGlobal ModuleName.basics N.negate
78 arg <- optimize cycle expr
79 pure $ Opt.Call func [arg]
81 Can.Binop _ home name _ left right ->
82 do optFunc <- Names.registerGlobal home name
83 optLeft <- optimize cycle left
84 optRight <- optimize cycle right
85 return (Opt.Call optFunc [optLeft, optRight])
87 Can.Lambda args body ->
88 do (argNames, destructors) <- destructArgs args
89 obody <- optimize cycle body
90 pure $ Opt.Function argNames (foldr Opt.Destruct obody destructors)
94 <$> optimize cycle func
95 <*> traverse (optimize cycle) args
97 Can.If branches finally ->
99 optimizeBranch (condition, branch) =
101 <$> optimize cycle condition
102 <*> optimize cycle branch
105 <$> traverse optimizeBranch branches
106 <*> optimize cycle finally
109 optimizeDef cycle def =<< optimize cycle body
111 Can.LetRec defs body ->
115 <$> optimizePotentialTailCall cycle def
116 <*> optimize cycle body
119 do obody <- optimize cycle body
120 foldM (\bod def -> optimizeDef cycle def bod) obody defs
122 Can.LetDestruct pattern expr body ->
123 do (name, destructs) <- destruct pattern
124 oexpr <- optimize cycle expr
125 obody <- optimize cycle body
127 Opt.Let (Opt.Def name oexpr) (foldr Opt.Destruct obody destructs)
129 Can.Case expr branches ->
131 optimizeBranch root (Can.CaseBranch pattern branch) =
132 do destructors <- destructHelp (Opt.Root root) pattern []
133 obranch <- optimize cycle branch
134 pure (pattern, foldr Opt.Destruct obranch destructors)
136 do temp <- Names.generate
137 oexpr <- optimize cycle expr
140 Case.optimize temp root <$> traverse (optimizeBranch root) branches
143 do obranches <- traverse (optimizeBranch temp) branches
144 return $ Opt.Let (Opt.Def temp oexpr) (Case.optimize temp temp obranches)
146 Can.Accessor field ->
147 Names.registerField field (Opt.Accessor field)
149 Can.Access record field ->
150 do optRecord <- optimize cycle record
151 Names.registerField field (Opt.Access optRecord field)
153 Can.Update record updates ->
154 Names.registerFieldDict updates Opt.Update
155 <*> optimize cycle record
156 <*> traverse (optimize cycle) updates
159 Names.registerFieldDict fields Opt.Record
160 <*> traverse (optimize cycle) fields
163 Names.registerKernel N.utils Opt.Unit
165 Can.Tuple a b maybeC ->
166 Names.registerKernel N.utils Opt.Tuple
169 <*> traverse (optimize cycle) maybeC
171 Can.Shader _ src _ ->
172 pure (Opt.Shader src)
179optimizeDef :: Cycle -> Can.Def -> Opt.Expr -> Names.Tracker Opt.Expr
180optimizeDef cycle def body =
182 Can.Def (A.At _ name) args expr ->
183 optimizeDefHelp cycle name args expr body
185 Can.TypedDef (A.At _ name) _ typedArgs expr _ ->
186 optimizeDefHelp cycle name (map fst typedArgs) expr body
189optimizeDefHelp :: Cycle -> N.Name -> [Can.Pattern] -> Can.Expr -> Opt.Expr -> Names.Tracker Opt.Expr
190optimizeDefHelp cycle name args expr body =
191 do oexpr <- optimize cycle expr
194 pure $ Opt.Let (Opt.Def name oexpr) body
197 do (argNames, destructors) <- destructArgs args
198 let ofunc = Opt.Function argNames (foldr Opt.Destruct oexpr destructors)
199 pure $ Opt.Let (Opt.Def name ofunc) body
206destructArgs :: [Can.Pattern] -> Names.Tracker ([N.Name], [Opt.Destructor])
208 do (argNames, destructorLists) <- unzip <$> traverse destruct args
209 return (argNames, concat destructorLists)
212destruct :: Can.Pattern -> Names.Tracker (N.Name, [Opt.Destructor])
213destruct pattern@(A.At _ ptrn) =
218 Can.PAlias subPattern name ->
219 do revDs <- destructHelp (Opt.Root name) subPattern []
220 pure (name, reverse revDs)
223 do name <- Names.generate
224 revDs <- destructHelp (Opt.Root name) pattern []
225 pure (name, reverse revDs)
228destructHelp :: Opt.Path -> Can.Pattern -> [Opt.Destructor] -> Names.Tracker [Opt.Destructor]
229destructHelp path (A.At region pattern) revDs =
235 pure (Opt.Destructor name path : revDs)
237 Can.PRecord fields ->
240 Opt.Destructor name (Opt.Field name path)
242 Names.registerFieldList fields (map toDestruct fields ++ revDs)
244 Can.PAlias subPattern name ->
245 destructHelp (Opt.Root name) subPattern $
246 Opt.Destructor name path : revDs
251 Can.PTuple a b Nothing ->
252 destructTwo path a b revDs
254 Can.PTuple a b (Just c) ->
257 destructHelp (Opt.Index Index.first path) a =<<
258 destructHelp (Opt.Index Index.second path) b =<<
259 destructHelp (Opt.Index Index.third path) c revDs
262 do name <- Names.generate
263 let newRoot = Opt.Root name
264 destructHelp (Opt.Index Index.first newRoot) a =<<
265 destructHelp (Opt.Index Index.second newRoot) b =<<
266 destructHelp (Opt.Index Index.third newRoot) c (Opt.Destructor name path : revDs)
272 destructTwo path hd (A.At region (Can.PList tl)) revDs
275 destructTwo path hd tl revDs
286 Can.PCtor _ _ _ _ _ args ->
289 foldM (destructCtorArg path) revDs args
292 do name <- Names.generate
293 foldM (destructCtorArg (Opt.Root name)) (Opt.Destructor name path : revDs) args
296destructTwo :: Opt.Path -> Can.Pattern -> Can.Pattern -> [Opt.Destructor] -> Names.Tracker [Opt.Destructor]
297destructTwo path a b revDs =
300 destructHelp (Opt.Index Index.first path) a =<<
301 destructHelp (Opt.Index Index.second path) b revDs
304 do name <- Names.generate
305 let newRoot = Opt.Root name
306 destructHelp (Opt.Index Index.first newRoot) a =<<
307 destructHelp (Opt.Index Index.second newRoot) b (Opt.Destructor name path : revDs)
310destructCtorArg :: Opt.Path -> [Opt.Destructor] -> Can.PatternCtorArg -> Names.Tracker [Opt.Destructor]
311destructCtorArg path revDs (Can.PatternCtorArg index _ arg) =
312 destructHelp (Opt.Index index path) arg revDs
319optimizePotentialTailCall :: Cycle -> Can.Def -> Names.Tracker Opt.Def
320optimizePotentialTailCall cycle def =
322 Can.Def (A.At _ name) args expr ->
323 do (argNames, destructors) <- destructArgs args
324 toTailDef name argNames destructors <$>
325 optimizeTail cycle name argNames expr
327 Can.TypedDef (A.At _ name) _ typedArgs expr _ ->
328 do (argNames, destructors) <- destructArgs (map fst typedArgs)
329 toTailDef name argNames destructors <$>
330 optimizeTail cycle name argNames expr
333optimizeTail :: Cycle -> N.Name -> [N.Name] -> Can.Expr -> Names.Tracker Opt.Expr
334optimizeTail cycle rootName argNames locExpr@(A.At _ expression) =
336 Can.Call func@(A.At _ (Can.VarTopLevel _ name)) args ->
337 do oargs <- traverse (optimize cycle) args
340 case Index.indexedZipWith (\_ a b -> (a,b)) argNames oargs of
341 Index.LengthMatch pairs ->
342 pure $ Opt.TailCall name pairs
344 Index.LengthMismatch _ _ ->
345 do ofunc <- optimize cycle func
346 pure $ Opt.Call ofunc oargs
348 do ofunc <- optimize cycle func
349 pure $ Opt.Call ofunc oargs
351 Can.If branches finally ->
353 optimizeBranch (condition, branch) =
355 <$> optimize cycle condition
356 <*> optimizeTail cycle rootName argNames branch
359 <$> traverse optimizeBranch branches
360 <*> optimizeTail cycle rootName argNames finally
363 optimizeDef cycle def =<< optimizeTail cycle rootName argNames body
365 Can.LetRec defs body ->
369 <$> optimizePotentialTailCall cycle def
370 <*> optimizeTail cycle rootName argNames body
373 do obody <- optimizeTail cycle rootName argNames body
374 foldM (\bod def -> optimizeDef cycle def bod) obody defs
376 Can.LetDestruct pattern expr body ->
377 do (dname, destructors) <- destruct pattern
378 oexpr <- optimize cycle expr
379 obody <- optimizeTail cycle dname argNames body
381 Opt.Let (Opt.Def dname oexpr) (foldr Opt.Destruct obody destructors)
383 Can.Case expr branches ->
385 optimizeBranch root (Can.CaseBranch pattern branch) =
386 do destructors <- destructHelp (Opt.Root root) pattern []
387 obranch <- optimizeTail cycle rootName argNames branch
388 pure (pattern, foldr Opt.Destruct obranch destructors)
390 do temp <- Names.generate
391 oexpr <- optimize cycle expr
394 Case.optimize temp root <$> traverse (optimizeBranch root) branches
397 Case.optimize temp temp <$> traverse (optimizeBranch temp) branches
400 optimize cycle locExpr
407toTailDef :: N.Name -> [N.Name] -> [Opt.Destructor] -> Opt.Expr -> Opt.Def
408toTailDef name argNames destructors body =
409 if hasTailCall body then
410 Opt.TailDef name argNames (foldr Opt.Destruct body destructors)
412 Opt.Def name (Opt.Function argNames (foldr Opt.Destruct body destructors))
415hasTailCall :: Opt.Expr -> Bool
416hasTailCall expression =
421 Opt.If branches finally ->
422 hasTailCall finally || any (hasTailCall . snd) branches
427 Opt.Destruct _ body ->
430 Opt.Case _ _ decider jumps ->
431 decidecHasTailCall decider || any (hasTailCall . snd) jumps
437decidecHasTailCall :: Opt.Decider Opt.Choice -> Bool
438decidecHasTailCall decider =
448 Opt.Chain _ success failure ->
449 decidecHasTailCall success || decidecHasTailCall failure
451 Opt.FanOut _ tests fallback ->
452 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