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.VarDebug home name _ ->
53 Names.registerKernel N.debug (Opt.VarDebug name home region Nothing)
55 Can.VarOperator _ home name _ ->
56 Names.registerGlobal home name
68 pure (Opt.Float float)
71 Opt.List <$> traverse (optimize cycle) entries
74 do func <- Names.registerGlobal ModuleName.basics N.negate
75 arg <- optimize cycle expr
76 pure $ Opt.Call func [arg]
78 Can.Binop _ home name _ left right ->
79 do optFunc <- Names.registerGlobal home name
80 optLeft <- optimize cycle left
81 optRight <- optimize cycle right
82 return (Opt.Call optFunc [optLeft, optRight])
84 Can.Lambda args body ->
85 do (argNames, defss) <- destructArgs args
86 obody <- optimize cycle body
87 pure $ Opt.Function argNames (foldr Opt.Let obody (concat defss))
91 <$> optimize cycle func
92 <*> traverse (optimize cycle) args
94 Can.If branches finally ->
96 optimizeBranch (condition, branch) =
98 <$> optimize cycle condition
99 <*> optimize cycle branch
102 <$> traverse optimizeBranch branches
103 <*> optimize cycle finally
106 optimizeDef cycle def =<< optimize cycle body
108 Can.LetRec defs body ->
112 <$> optimizePotentialTailCall cycle def
113 <*> optimize cycle body
116 do obody <- optimize cycle body
117 foldM (\bod def -> optimizeDef cycle def bod) obody defs
119 Can.LetDestruct pattern expr body ->
120 do (name, defs) <- destruct pattern
121 oexpr <- optimize cycle expr
122 obody <- optimize cycle body
124 Opt.Let (Opt.Def name oexpr) (foldr Opt.Let obody defs)
126 Can.Case expr branches ->
128 optimizeBranch root (Can.CaseBranch pattern branch) =
129 do defs <- destructHelp (Opt.VarLocal root) pattern []
130 obranch <- optimize cycle branch
131 pure (pattern, foldr Opt.Let obranch defs)
133 do temp <- Names.generate
134 oexpr <- optimize cycle expr
137 Case.optimize temp root <$> traverse (optimizeBranch root) branches
140 Case.optimize temp temp <$> traverse (optimizeBranch temp) branches
142 Can.Accessor field ->
143 Names.registerField field (Opt.Accessor field)
145 Can.Access record field ->
146 do optRecord <- optimize cycle record
147 Names.registerField field (Opt.Access optRecord field)
149 Can.Update record updates ->
150 Names.registerFieldDict updates Opt.Update
151 <*> optimize cycle record
152 <*> traverse (optimize cycle) updates
155 Names.registerFieldDict fields Opt.Record
156 <*> traverse (optimize cycle) fields
159 Names.registerKernel N.utils Opt.Unit
161 Can.Tuple a b maybeC ->
162 Names.registerKernel N.utils Opt.Tuple
165 <*> traverse (optimize cycle) maybeC
167 Can.Shader _ src _ ->
168 pure (Opt.Shader src)
175optimizeDef :: Cycle -> Can.Def -> Opt.Expr -> Names.Tracker Opt.Expr
176optimizeDef cycle def body =
178 Can.Def (A.At _ name) args expr ->
179 optimizeDefHelp cycle name args expr body
181 Can.TypedDef (A.At _ name) _ typedArgs expr _ ->
182 optimizeDefHelp cycle name (map fst typedArgs) expr body
185optimizeDefHelp :: Cycle -> N.Name -> [Can.Pattern] -> Can.Expr -> Opt.Expr -> Names.Tracker Opt.Expr
186optimizeDefHelp cycle name args expr body =
189 do oexpr <- optimize cycle expr
190 pure $ Opt.Let (Opt.Def name oexpr) body
193 do (argNames, defss) <- destructArgs args
194 let oexpr = Opt.Function argNames (foldr Opt.Let body (concat defss))
195 pure $ Opt.Let (Opt.Def name oexpr) body
202destructArgs :: [Can.Pattern] -> Names.Tracker ([N.Name], [[Opt.Def]])
204 unzip <$> traverse destruct args
207destruct :: Can.Pattern -> Names.Tracker (N.Name, [Opt.Def])
208destruct pattern@(A.At _ ptrn) =
213 Can.PAlias subPattern name ->
214 do revDefs <- destructHelp (Opt.VarLocal name) subPattern []
215 pure (name, reverse revDefs)
218 do name <- Names.generate
219 revDefs <- destructHelp (Opt.VarLocal name) pattern []
220 pure (name, reverse revDefs)
223destructHelp :: Opt.Expr -> Can.Pattern -> [Opt.Def] -> Names.Tracker [Opt.Def]
224destructHelp root (A.At region pattern) revDefs =
230 pure (Opt.Def name root : revDefs)
232 Can.PRecord fields ->
233 let toDef name = Opt.Def name (Opt.Access root name) in
234 Names.registerFieldList fields (map toDef fields ++ revDefs)
236 Can.PAlias subPattern name ->
237 destructHelp (Opt.VarLocal name) subPattern $
238 Opt.Def name root : revDefs
243 Can.PTuple a b maybeC ->
244 do name <- Names.generate
245 let tuple = Opt.VarLocal name
246 let newRevDefs = Opt.Def name root : revDefs
249 destructHelp (Opt.Index tuple 1) b =<<
250 destructHelp (Opt.Index tuple 0) a newRevDefs
253 destructHelp (Opt.Index tuple 2) c =<<
254 destructHelp (Opt.Index tuple 1) b =<<
255 destructHelp (Opt.Index tuple 0) a newRevDefs
261 destructCons root hd (A.At region (Can.PList tl)) revDefs
264 destructCons root hd tl revDefs
275 Can.PCtor _ _ _ _ _ _ args ->
276 do name <- Names.generate
278 (destructCtorArg (Opt.VarLocal name))
279 (Opt.Def name root : revDefs)
283destructCons :: Opt.Expr -> Can.Pattern -> Can.Pattern -> [Opt.Def] -> Names.Tracker [Opt.Def]
284destructCons root hd tl revDefs =
285 do name <- Names.generate
286 let list = Opt.VarLocal name
287 destructHelp (Opt.Index list 0) hd =<<
288 destructHelp (Opt.Index list 1) tl (Opt.Def name root : revDefs)
291destructCtorArg :: Opt.Expr -> [Opt.Def] -> Can.PatternCtorArg -> Names.Tracker [Opt.Def]
292destructCtorArg root revDefs (Can.PatternCtorArg index _ arg) =
293 destructHelp (Opt.Index root (Index.toZeroBased index)) arg revDefs
300optimizePotentialTailCall :: Cycle -> Can.Def -> Names.Tracker Opt.Def
301optimizePotentialTailCall cycle def =
303 Can.Def (A.At _ name) args expr ->
304 do (argNames, defss) <- destructArgs args
305 toTailDef name argNames defss <$>
306 optimizeTail cycle name argNames expr
308 Can.TypedDef (A.At _ name) _ typedArgs expr _ ->
309 do (argNames, defss) <- destructArgs (map fst typedArgs)
310 toTailDef name argNames defss <$>
311 optimizeTail cycle name argNames expr
314optimizeTail :: Cycle -> N.Name -> [N.Name] -> Can.Expr -> Names.Tracker Opt.Expr
315optimizeTail cycle rootName argNames locExpr@(A.At _ expression) =
317 Can.Call func@(A.At _ (Can.VarTopLevel _ name)) args ->
318 do oargs <- traverse (optimize cycle) args
321 case Index.indexedZipWith (\_ a b -> (a,b)) argNames oargs of
322 Index.LengthMatch pairs ->
323 pure $ Opt.TailCall name pairs
325 Index.LengthMismatch _ _ ->
326 do ofunc <- optimize cycle func
327 pure $ Opt.Call ofunc oargs
329 do ofunc <- optimize cycle func
330 pure $ Opt.Call ofunc oargs
332 Can.If branches finally ->
334 optimizeBranch (condition, branch) =
336 <$> optimize cycle condition
337 <*> optimizeTail cycle rootName argNames branch
340 <$> traverse optimizeBranch branches
341 <*> optimizeTail cycle rootName argNames finally
344 optimizeDef cycle def =<< optimizeTail cycle rootName argNames body
346 Can.LetRec defs body ->
350 <$> optimizePotentialTailCall cycle def
351 <*> optimizeTail cycle rootName argNames body
354 do obody <- optimizeTail cycle rootName argNames body
355 foldM (\bod def -> optimizeDef cycle def bod) obody defs
357 Can.LetDestruct pattern expr body ->
358 do (dname, defs) <- destruct pattern
359 oexpr <- optimize cycle expr
360 obody <- optimizeTail cycle dname argNames body
362 Opt.Let (Opt.Def dname oexpr) (foldr Opt.Let obody defs)
364 Can.Case expr branches ->
366 optimizeBranch root (Can.CaseBranch pattern branch) =
367 do defs <- destructHelp (Opt.VarLocal root) pattern []
368 obranch <- optimizeTail cycle rootName argNames branch
369 pure (pattern, foldr Opt.Let obranch defs)
371 do temp <- Names.generate
372 oexpr <- optimize cycle expr
375 Case.optimize temp root <$> traverse (optimizeBranch root) branches
378 Case.optimize temp temp <$> traverse (optimizeBranch temp) branches
381 optimize cycle locExpr
388toTailDef :: N.Name -> [N.Name] -> [[Opt.Def]] -> Opt.Expr -> Opt.Def
389toTailDef name argNames defss body =
390 if hasTailCall body then
391 Opt.TailDef name argNames (foldr Opt.Let body (concat defss))
393 Opt.Def name (Opt.Function argNames (foldr Opt.Let body (concat defss)))
396hasTailCall :: Opt.Expr -> Bool
397hasTailCall expression =
402 Opt.If branches finally ->
403 hasTailCall finally || any (hasTailCall . snd) branches
408 Opt.Case _ _ _ branches ->
409 any (hasTailCall . snd) branches
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