1{-# OPTIONS_GHC -Wall #-}
2{-# LANGUAGE OverloadedStrings #-}
3module Optimize (optimize) where
5import Control.Arrow (second)
6import qualified Control.Monad as M
7import Data.Monoid ((<>))
8import qualified Data.Map as Map
9import qualified Data.Set as Set
10import qualified Data.Text as Text
11import Data.Text (Text)
13import qualified AST.Expression.Canonical as Can
14import qualified AST.Expression.Optimized as Opt
15import qualified AST.Module.Name as ModuleName
16import qualified AST.Pattern as P
17import qualified AST.Variable as Var
18import qualified Optimize.Case as Case
19import qualified Optimize.DecisionTree as DT
20import qualified Optimize.Environment as Env
21import qualified Optimize.Inline as Inline
22import qualified Reporting.Annotation as A
23import qualified Reporting.Region as R
30optimize :: DT.VariantDict -> ModuleName.Canonical -> [Can.Def] -> [(Text, Opt.Decl)]
31optimize variantDict home defs =
32 concat $ zipWith (optimizeDecl variantDict home) [1 .. length defs] defs
39optimizeDecl :: DT.VariantDict -> ModuleName.Canonical -> Int -> Can.Def -> [(Text, Opt.Decl)]
40optimizeDecl variantDict home index (Can.Def _ pattern@(A.A _ ptrn) expression _) =
43 Can.collectLambdas expression
45 case (ptrn, rawArgs) of
47 (:[]) $ Env.run variantDict home $
48 optimizeNamedDef name rawArgs rawBody
52 name = "_" <> Text.pack (show index)
53 deps = Set.singleton (Var.Global home name)
55 Env.run variantDict home $
56 ((,) name . Opt.Def) <$> optimizeExpr Nothing rawBody
58 destruct (Var.topLevel home name) pattern
60 decl : map (second (Opt.Decl deps Nothing)) destructors
63 error "bug manifesting in Optimize.optimizeDecl, please report"
70optimizeLetDef :: Can.Def -> Env.Optimizer [(Text, Opt.Def)]
71optimizeLetDef (Can.Def _ pattern@(A.A _ ptrn) expression _) =
74 Can.collectLambdas expression
76 case (ptrn, rawArgs) of
78 do def <- optimizeNamedDef name rawArgs rawBody
82 do name <- Env.freshName
83 body <- optimizeExpr Nothing rawBody
84 return $ (name, Opt.Def body) : destruct (Var.local name) pattern
87 error "bug manifesting in Optimize.optimizeLetDef, please report"
90optimizeNamedDef :: Text -> [P.Canonical] -> Can.Expr -> Env.Optimizer (Text, Opt.Def)
91optimizeNamedDef name rawArgs rawBody =
94 do hasTailCall <- Env.getTailCall
95 body <- optimizeExpr Nothing rawBody
96 Env.setTailCall hasTailCall
97 return (name, Opt.Def body)
100 do htc <- Env.getTailCall
101 Env.setTailCall False
103 (args, body) <- optimizeFunction (Just name) rawArgs rawBody
105 isTailCall <- Env.getTailCall
110 Opt.TailDef args body
112 Opt.Def (Opt.Function args body)
115destruct :: Var.Canonical -> P.Canonical -> [(Text, Opt.Def)]
116destruct var pattern =
117 map (second Opt.Def) $
118 patternToSubstitutions (Opt.Var var) pattern
129 -> Env.Optimizer ([Text], Opt.Expr)
130optimizeFunction maybeName patterns givenBody =
131 do (argNames, body) <- M.foldM depatternArgs ([], givenBody) (reverse patterns)
132 optBody <- optimizeExpr (makeContext argNames =<< maybeName) body
133 return (argNames, optBody)
136makeContext :: [Text] -> Text -> Context
137makeContext argNames name =
138 Just (name, length argNames, argNames)
141depatternArgs :: ([Text], Can.Expr) -> P.Canonical -> Env.Optimizer ([Text], Can.Expr)
142depatternArgs (names, rawExpr) ptrn =
143 do (name, expr) <- depattern ptrn rawExpr
144 return (name : names, expr)
148-- TURN A PATTERN INTO A BUNCH OF SUBSTITUTIONS
151patternToSubstitutions :: Opt.Expr -> P.Canonical -> [(Text, Opt.Expr)]
152patternToSubstitutions expr (A.A _ pattern) =
161 map (\name -> (name, Opt.Access expr name)) fields
166 P.Alias alias realPattern ->
167 (alias, expr) : patternToSubstitutions expr realPattern
170 concat (zipWith (patternToSubstitutions . Opt.CtorAccess expr) [0..] patterns)
174-- OPTIMIZE EXPRESSIONS
177type Context = Maybe (Text, Int, [Text])
180{-| This optimizer detects tail calls. The `Context` holds a function name,
181function arity, and list of argument names. If a tail call is possible, the
182`Context` will be filled in and we check any function we run into. If we go
183down a route that cannot possibly have tail calls, we remove the context.
185optimizeExpr :: Context -> Can.Expr -> Env.Optimizer Opt.Expr
186optimizeExpr context annExpr@(A.A region expression) =
190 -- this *might* find a tail call, use this when something is a potential
195 -- this will never find tail calls, use this when you are working with
196 -- expressions that cannot be turned into tail calls
200 pure (Opt.Literal lit)
204 if name == debugCrash
206 do home <- Env.getHome
207 pure (Opt.Crash home region Nothing)
213 <$> traverse justConvert elements
215 Can.Binop op leftExpr rightExpr ->
216 optimizeBinop context region op leftExpr rightExpr
221 Can.collectLambdas annExpr
223 uncurry Opt.Function <$> optimizeFunction Nothing patterns body
228 Can.collectApps annExpr
230 case getTailCallInfo context func (length args) of
231 Just (name, argNames) ->
232 do optArgs <- traverse justConvert args
234 return (Opt.TailCall name argNames optArgs)
237 do hasTailCall <- Env.getTailCall
238 optFunc <- justConvert func
239 optArgs <- traverse justConvert args
240 Env.setTailCall hasTailCall
241 return (Opt.Call optFunc optArgs)
243 Can.If branches finally ->
245 crawlBranch (cond,branch) =
246 (,) <$> justConvert cond <*> keepLooking branch
249 <$> traverse crawlBranch branches
250 <*> keepLooking finally
253 do optDefs <- concat <$> traverse optimizeLetDef defs
254 Opt.Let optDefs <$> keepLooking body
256 Can.Case expr branches ->
257 do optExpr <- optimizeExpr Nothing expr
258 variantDict <- Env.getVariantDict
260 name <- Env.freshName
261 optBranches <- traverse (optimizeBranch context region name) branches
262 let optCase = Case.optimize variantDict name optBranches
263 return $ Opt.Let [ (name, Opt.Def optExpr) ] optCase
265 Can.Ctor (Var.Canonical _ name) exprs ->
266 Opt.Ctor name <$> traverse justConvert exprs
268 Can.Access record field ->
270 <$> justConvert record
273 Can.Update record fields ->
275 <$> justConvert record
276 <*> traverse (traverse justConvert) fields
280 <$> traverse (traverse justConvert) fields
282 Can.Cmd moduleName manager ->
283 Opt.Cmd moduleName <$> Env.registerEffects manager
285 Can.Sub moduleName manager ->
286 Opt.Sub moduleName <$> Env.registerEffects manager
288 Can.OutgoingPort name tipe ->
289 pure (Opt.OutgoingPort name tipe)
291 Can.IncomingPort name tipe ->
292 pure (Opt.IncomingPort name tipe)
294 Can.Program kind expr ->
295 Opt.Program kind <$> justConvert expr
298 error "save_the_environment should never make it to optimization phase"
300 Can.GLShader uid src gltipe ->
301 pure (Opt.GLShader uid src gltipe)
305-- OPTIMIZE CASE BRANCHES
312 -> (P.Canonical, Can.Expr)
313 -> Env.Optimizer (P.Canonical, Opt.Expr)
314optimizeBranch context region exprName (rawPattern, canBranch) =
317 Opt.Var (Var.Canonical Var.Local exprName)
319 do optBranch <- optimizeExpr context canBranch
320 (pattern, branch) <- tagCrashBranch region rawPattern optBranch
323 Map.fromList (patternToSubstitutions root pattern)
325 (,) pattern <$> Inline.inline substitutions branch
332 -> Env.Optimizer (P.Canonical, Opt.Expr)
333tagCrashBranch region pattern@(A.A pr _) expr =
335 Opt.Call (Opt.Crash home _ _) [arg] ->
336 do name <- Env.freshName
338 ( A.A pr (P.Alias name pattern)
339 , Opt.Call (Opt.Crash home region (Just (Opt.Var (Var.local name)))) [arg]
343 return (pattern, expr)
350getTailCallInfo :: Context -> Can.Expr -> Int -> Maybe (Text, [Text])
351getTailCallInfo context (A.A _ function) arity =
352 case (context, function) of
353 ( Just (ctxName, ctxArity, argNames), Can.Var (Var.Canonical home name) ) ->
355 if name == ctxName && arity == ctxArity && Var.isLocalHome home then
356 Just (name, argNames)
367-- given a pattern and an expression, push the actual pattern matching into the
368-- expression as a case-expression if necessary. The pattern compiler will work
372depattern :: P.Canonical -> Can.Expr -> Env.Optimizer (Text, Can.Expr)
373depattern canPattern@(A.A _ pattern) expr =
376 A.A (error "the annotation added in 'depattern' should not be observed!")
378 caseExpr e branches =
379 ann (Can.Case e branches)
382 ann (Can.Var (Var.local name))
385 do name <- Env.freshName
388 , caseExpr (var name) [ (canPattern, expr) ]
402 do name <- Env.freshName
422 -> Env.Optimizer Opt.Expr
423optimizeBinop context region op leftExpr rightExpr =
426 binop = ann (Can.Binop op leftExpr rightExpr)
428 if op == forwardApply then
430 optimizeExpr context (collect id left forwardApply binop)
432 else if op == backwardApply then
434 optimizeExpr context (collect id right backwardApply binop)
436 else if op == forwardCompose then
438 do var <- Env.freshName
439 let makeRoot func = ann (Can.App func (ann (Can.Var (Var.local var))))
440 let body = collect makeRoot left forwardCompose binop
441 optimizeExpr context (ann (Can.Lambda (ann (P.Var var)) body))
443 else if op == backwardCompose then
445 do var <- Env.freshName
446 let makeRoot func = ann (Can.App func (ann (Can.Var (Var.local var))))
447 let body = collect makeRoot right backwardCompose binop
448 optimizeExpr context (ann (Can.Lambda (ann (P.Var var)) body))
450 else if op == cons then
452 optimizeExpr context (ann (Can.Ctor cons [ leftExpr, rightExpr ]))
457 <$> optimizeExpr Nothing leftExpr
458 <*> optimizeExpr Nothing rightExpr
461-- left-associative ((x |> f) |> g)
462forwardApply :: Var.Canonical
464 Var.inCore "Basics" "|>"
467-- right-associative (g <| (f <| x))
468backwardApply :: Var.Canonical
470 Var.inCore "Basics" "<|"
473-- left-associative ((f >> g) >> h)
474forwardCompose :: Var.Canonical
476 Var.inCore "Basics" ">>"
479-- right-associative (h << (g << f))
480backwardCompose :: Var.Canonical
482 Var.inCore "Basics" "<<"
487 Var.Canonical Var.BuiltIn "::"
490debugCrash :: Var.Canonical
492 Var.inCore "Debug" "crash"
496 Can.Expr -> Can.Expr -> (Can.Expr, Can.Expr)
509collect :: (Can.Expr -> Can.Expr) -> Assoc -> Var.Canonical -> Can.Expr -> Can.Expr
510collect makeRoot assoc desiredOp annExpr@(A.A ann expr) =
512 Can.Binop op leftExpr rightExpr | op == desiredOp ->
514 (func, arg) = assoc leftExpr rightExpr
516 A.A ann (Can.App func (collect makeRoot assoc desiredOp arg))
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