on master help sign in
Begin reviving the optimize phase

So far it converts everything except for case expressions. Need to make some choices about how code gen should work for best gzipped size.

commit2da8c0d81c92d128451caa3104ab343d6a788fca authorEvan Czaplicki <evancz@users.noreply.github.com> dateThu 30 Nov 2017, 15:14 (9 years ago) parent086880c
8 files changed+710−1244
src/AST/Optimized.hs+94−111 src/AST/Variable.hs−32 src/Data/Index.hs+14−2 src/Optimize.hs+273−465 src/Optimize/DecisionTree.hs+224−159 src/Optimize/Environment.hs−192 src/Optimize/Inline.hs−283 src/Optimize/Names.hs+105
src/AST/Optimized.hs+94−111
@@ -1,22 +1,24 @@
11{-# OPTIONS_GHC -Wall #-}
22module AST.Optimized
3− ( Decl(..)
4− , Def(..)
3+ ( Def(..)
54 , Expr(..)
6− , Main(..)
7− , Decider(..), Choice(..)
5+ , Global(..)
6+ , Decider(..)
7+ , Choice(..)
8+ , Graph(..)
9+ , Node(..)
810 )
911 where
1012
1113
1214import Control.Monad (liftM, liftM2, liftM3, liftM4)
1315import Data.Binary
14−import qualified Data.Set as Set
16+import qualified Data.Map as Map
1517import Data.Text (Text)
1618
17−import qualified AST.Literal as Literal
1819import qualified AST.Module.Name as ModuleName
19−import qualified AST.Variable as Var
20+import qualified Data.Index as Index
21+import qualified Elm.Name as N
2022import qualified Optimize.DecisionTree as DT
2123import qualified Reporting.Region as R
2224
@@ -26,27 +28,34 @@ import qualified Reporting.Region as R
2628
2729
2830data Expr
29− = Literal Literal.Literal
30− | VarLocal Text
31− | VarGlobal Var.Global
31+ = Chr Text
32+ | Str Text
33+ | Int Int
34+ | Float Double
35+ | VarLocal N.Name
36+ | VarGlobal Global
37+ | VarDebug N.Name ModuleName.Canonical R.Region (Maybe Expr)
38+ | VarKernel N.Name N.Name
3239 | List [Expr]
33− | Binop Var.Global Expr Expr
34− | Function [Text] Expr
40+ | Function [N.Name] Expr
3541 | Call Expr [Expr]
36− | TailCall Text [Text] [Expr]
42+ | TailCall N.Name [N.Name] [Expr]
3743 | If [(Expr, Expr)] Expr
38− | Let [(Text, Def)] Expr
39− | Case Text (Decider Choice) [(Int, Expr)]
40− | Ctor Text [Expr]
41− | CtorAccess Expr Int
42− | Accessor Text
43− | Access Expr Text
44− | Update Expr [(Text, Expr)]
45− | Record [(Text, Expr)]
44+ | Let Def Expr
45+ | Case N.Name (Decider Choice) [(Int, Expr)]
46+ | Ctor N.Name [Expr]
47+ | CtorAccess Expr Index.ZeroBased
48+ | Accessor N.Name
49+ | Access Expr N.Name
50+ | Update Expr (Map.Map N.Name Expr)
51+ | Record (Map.Map N.Name Expr)
4652 | Unit
47− | Tuple Expr Expr [Expr]
48− | GLShader Text
49− | Crash ModuleName.Canonical R.Region (Maybe Expr)
53+ | Tuple Expr Expr (Maybe Expr)
54+ | Shader Text
55+
56+
57+data Global = Global ModuleName.Canonical N.Name
58+ deriving (Eq, Ord)
5059
5160
5261
@@ -54,8 +63,8 @@ data Expr
5463
5564
5665data Def
57− = Def Expr
58− | TailDef [Text] Expr
66+ = Def N.Name Expr
67+ | TailDef N.Name [N.Name] Expr
5968
6069
6170
@@ -88,120 +97,94 @@ data Choice
8897
8998data Graph =
9099 Graph
91− { _nodes :: Map.Map Var.Global Node
100+ { _nodes :: Map.Map Global Node
92101 }
93102
94103
95−
96−data Node
97− = Acyclic
98− { _deps :: [Var.Global]
99− , _body :: Expr
100− }
101− | TailCall
102− { _deps :: [Var.Global]
103− , _args :: [Text]
104− , _body :: Expr
105− }
106− | Cyclic Var.Global
107− | Cycle
108− { _deps :: [Var.Global]
109− , _values :: [(Var.Global, Expr)]
110− }
104+data Node = Node
111105
112106
113107
114108-- BINARY
115109
116110
111+instance Binary Global where
112+ get = liftM2 Global get get
113+ put (Global a b) = put a >> put b
114+
115+
117116instance Binary Expr where
118117 put expr =
119118 case expr of
120− Literal a -> putWord8 0 >> put a
121− VarLocal a -> putWord8 1 >> put a
122− VarGlobal a -> putWord8 2 >> put a
123− List a -> putWord8 3 >> put a
124− Binop a b c -> putWord8 4 >> put a >> put b >> put c
125− Function a b -> putWord8 5 >> put a >> put b
126− Call a b -> putWord8 6 >> put a >> put b
127− TailCall a b c -> putWord8 7 >> put a >> put b >> put c
128− If a b -> putWord8 8 >> put a >> put b
129− Let a b -> putWord8 9 >> put a >> put b
130− Case a b c -> putWord8 10 >> put a >> put b >> put c
131− Ctor a b -> putWord8 11 >> put a >> put b
132− CtorAccess a b -> putWord8 12 >> put a >> put b
133− Accessor a -> putWord8 13 >> put a
134− Access a b -> putWord8 14 >> put a >> put b
135− Update a b -> putWord8 15 >> put a >> put b
136− Record a -> putWord8 16 >> put a
137− Unit -> putWord8 17
138− Tuple a b c -> putWord8 18 >> put a >> put b >> put c
139− GLShader a -> putWord8 19 >> put a
140− Crash a b c -> putWord8 20 >> put a >> put b >> put c
119+ Chr a -> putWord8 0 >> put a
120+ Str a -> putWord8 1 >> put a
121+ Int a -> putWord8 2 >> put a
122+ Float a -> putWord8 3 >> put a
123+ VarLocal a -> putWord8 4 >> put a
124+ VarGlobal a -> putWord8 5 >> put a
125+ VarDebug a b c d -> putWord8 6 >> put a >> put b >> put c >> put d
126+ VarKernel a b -> putWord8 7 >> put a >> put b
127+ List a -> putWord8 8 >> put a
128+ Function a b -> putWord8 9 >> put a >> put b
129+ Call a b -> putWord8 10 >> put a >> put b
130+ TailCall a b c -> putWord8 11 >> put a >> put b >> put c
131+ If a b -> putWord8 12 >> put a >> put b
132+ Let a b -> putWord8 13 >> put a >> put b
133+ Case a b c -> putWord8 14 >> put a >> put b >> put c
134+ Ctor a b -> putWord8 15 >> put a >> put b
135+ CtorAccess a b -> putWord8 16 >> put a >> put b
136+ Accessor a -> putWord8 17 >> put a
137+ Access a b -> putWord8 18 >> put a >> put b
138+ Update a b -> putWord8 19 >> put a >> put b
139+ Record a -> putWord8 20 >> put a
140+ Unit -> putWord8 21
141+ Tuple a b c -> putWord8 22 >> put a >> put b >> put c
142+ Shader a -> putWord8 23 >> put a
141143
142144 get =
143145 do word <- getWord8
144146 case word of
145− 0 -> liftM Literal get
146− 1 -> liftM VarLocal get
147− 2 -> liftM VarGlobal get
148− 3 -> liftM List get
149− 4 -> liftM3 Binop get get get
150− 5 -> liftM2 Function get get
151− 6 -> liftM2 Call get get
152− 7 -> liftM3 TailCall get get get
153− 8 -> liftM2 If get get
154− 9 -> liftM2 Let get get
155− 10 -> liftM3 Case get get get
156− 11 -> liftM2 Ctor get get
157− 12 -> liftM2 CtorAccess get get
158− 13 -> liftM Accessor get
159− 14 -> liftM2 Access get get
160− 15 -> liftM2 Update get get
161− 16 -> liftM Record get
162− 17 -> pure Unit
163− 18 -> liftM3 Tuple get get get
164− 19 -> liftM GLShader get
165− 20 -> liftM3 Crash get get get
147+ 0 -> liftM Chr get
148+ 1 -> liftM Str get
149+ 2 -> liftM Int get
150+ 3 -> liftM Float get
151+ 4 -> liftM VarLocal get
152+ 5 -> liftM VarGlobal get
153+ 6 -> liftM4 VarDebug get get get get
154+ 7 -> liftM2 VarKernel get get
155+ 8 -> liftM List get
156+ 9 -> liftM2 Function get get
157+ 10 -> liftM2 Call get get
158+ 11 -> liftM3 TailCall get get get
159+ 12 -> liftM2 If get get
160+ 13 -> liftM2 Let get get
161+ 14 -> liftM3 Case get get get
162+ 15 -> liftM2 Ctor get get
163+ 16 -> liftM2 CtorAccess get get
164+ 17 -> liftM Accessor get
165+ 18 -> liftM2 Access get get
166+ 19 -> liftM2 Update get get
167+ 20 -> liftM Record get
168+ 21 -> pure Unit
169+ 22 -> liftM3 Tuple get get get
170+ 23 -> liftM Shader get
166171 _ -> error "problem getting Opt.Expr binary"
167172
168173
169−instance Binary Decl where
170− put (Decl a b c d) =
171− put a >> put b >> put c >> put d
172−
173− get =
174− liftM4 Decl get get get get
175−
176−
177174instance Binary Def where
178175 put def =
179176 case def of
180− Def body -> putWord8 0 >> put body
181− TailDef args body -> putWord8 1 >> put args >> put body
177+ Def a b -> putWord8 0 >> put a >> put b
178+ TailDef a b c -> putWord8 1 >> put a >> put b >> put c
182179
183180 get =
184181 do word <- getWord8
185182 case word of
186− 0 -> Def <$> get
187− 1 -> TailDef <$> get <*> get
183+ 0 -> liftM2 Def get get
184+ 1 -> liftM3 TailDef get get get
188185 _ -> error "problem getting Opt.Def binary"
189186
190187
191−instance Binary Main where
192− put main =
193− case main of
194− Static -> putWord8 0
195− Dynamic expr -> putWord8 1 >> put expr
196−
197− get =
198− do word <- getWord8
199− case word of
200− 0 -> pure Static
201− 1 -> liftM Dynamic get
202− _ -> error "problem getting Opt.Main binary"
203−
204−
205188instance (Binary a) => Binary (Decider a) where
206189 put decider =
207190 case decider of
src/AST/Variable.hsdeleted−32
@@ -1,32 +0,0 @@
1−{-# OPTIONS_GHC -Wall #-}
2−{-# LANGUAGE OverloadedStrings #-}
3−module AST.Variable
4− ( Global(..)
5− )
6− where
7−
8−
9−import Data.Binary
10−
11−import qualified AST.Module.Name as ModuleName
12−import qualified Elm.Name as N
13−
14−
15−
16−-- GLOBAL NAMES
17−
18−
19−data Global = Global !ModuleName.Canonical !N.Name
20− deriving (Eq, Ord)
21−
22−
23−
24−-- BINARY SERIALIZATION
25−
26−
27−instance Binary Global where
28− put (Global home name) =
29− put home >> put name
30−
31− get =
32− Global <$> get <*> get
src/Data/Index.hs+14−2
@@ -15,13 +15,16 @@ module Data.Index
1515 where
1616
1717
18+import Control.Monad (liftM)
19+import Data.Binary
20+
1821
1922
2023-- ZERO BASED
2124
2225
23−newtype ZeroBased =
24− ZeroBased Int
26+newtype ZeroBased = ZeroBased Int
27+ deriving (Eq, Ord)
2528
2629
2730first :: ZeroBased
@@ -112,3 +115,12 @@ indexedZipWithA func listX listY =
112115
113116 LengthMismatch x y ->
114117 pure (LengthMismatch x y)
118+
119+
120+
121+-- BINARY
122+
123+
124+instance Binary ZeroBased where
125+ get = liftM ZeroBased get
126+ put (ZeroBased n) = put n
src/Optimize.hs+273−465
@@ -1,25 +1,23 @@
11{-# OPTIONS_GHC -Wall #-}
22{-# LANGUAGE OverloadedStrings #-}
3−module Optimize (optimize) where
4−
5−import Control.Arrow (second)
6−import qualified Control.Monad as M
7−import Data.Monoid ((<>))
8−import qualified Data.Map as Map
9−import qualified Data.Set as Set
10−import qualified Data.Text as Text
11−import Data.Text (Text)
12−
13−import qualified AST.Expression.Canonical as Can
14−import qualified AST.Expression.Optimized as Opt
3+module Optimize
4+ ( optimizeExpr
5+ )
6+ where
7+
8+
9+import Control.Monad (foldM)
10+
11+import qualified AST.Canonical as Can
12+import qualified AST.Optimized as Opt
1513import qualified AST.Module.Name as ModuleName
16−import qualified AST.Pattern as P
17−import qualified AST.Variable as Var
18−import qualified Optimize.Case as Case
14+import qualified Data.Index as Index
15+import qualified Elm.Name as N
16+--import qualified Optimize.Case as Case
1917import qualified Optimize.DecisionTree as DT
20−import qualified Optimize.Environment as Env
21−import qualified Optimize.Inline as Inline
22−import qualified Optimize.Port as Port
18+import qualified Optimize.Names as Names
19+--import qualified Optimize.Inline as Inline
20+--import qualified Optimize.Port as Port
2321import qualified Reporting.Annotation as A
2422import qualified Reporting.Region as R
2523
@@ -28,543 +26,353 @@ import qualified Reporting.Region as R
2826-- OPTIMIZE
2927
3028
31−optimize :: DT.VariantDict -> ModuleName.Canonical -> [Can.Def] -> [(Text, Opt.Decl)]
32−optimize variantDict home defs =
33− concat $ zipWith (optimizeDecl variantDict home) [1 .. length defs] defs
34−
35−
36−
37−-- OPTIMIZE DECLS
38−
39−
40−optimizeDecl :: DT.VariantDict -> ModuleName.Canonical -> Int -> Can.Def -> [(Text, Opt.Decl)]
41−optimizeDecl variantDict home index (Can.Def _ pattern@(A.A _ ptrn) expression _) =
42− let
43− (rawArgs, rawBody) =
44− Can.collectLambdas expression
45− in
46− case (ptrn, rawArgs) of
47− (P.Var name, _) ->
48− (:[]) $ Env.run variantDict home $
49− optimizeNamedDef name rawArgs rawBody
50−
51− (_, []) ->
52− let
53− name = "_" <> Text.pack (show index)
54− var = Var.Global home name
55− deps = Set.singleton var
56− decl =
57− Env.run variantDict home $
58− ((,) name . Opt.Def) <$> optimizeExpr Nothing rawBody
59− destructors =
60− destruct (Opt.VarGlobal var) pattern
61− in
62− decl : map (second (Opt.Decl deps Set.empty Nothing)) destructors
63−
64− _ ->
65− error "bug manifesting in Optimize.optimizeDecl, please report"
66−
67−
68−
69−-- OPTIMIZE DEFS
70−
71−
72−optimizeLetDef :: Can.Def -> Env.Optimizer [(Text, Opt.Def)]
73−optimizeLetDef (Can.Def _ pattern@(A.A _ ptrn) expression _) =
74− let
75− (rawArgs, rawBody) =
76− Can.collectLambdas expression
77− in
78− case (ptrn, rawArgs) of
79− (P.Var name, _) ->
80− do def <- optimizeNamedDef name rawArgs rawBody
81− return [def]
82−
83− (_, []) ->
84− do name <- Env.freshName
85− body <- optimizeExpr Nothing rawBody
86− return $ (name, Opt.Def body) : destruct (Opt.VarLocal name) pattern
87−
88− _ ->
89− error "bug manifesting in Optimize.optimizeLetDef, please report"
90−
91−
92−optimizeNamedDef :: Text -> [P.Canonical] -> Can.Expr -> Env.Optimizer (Text, Opt.Def)
93−optimizeNamedDef name rawArgs rawBody =
94− case rawArgs of
95− [] ->
96− do hasTailCall <- Env.getTailCall
97− body <- optimizeExpr Nothing rawBody
98− Env.setTailCall hasTailCall
99− return (name, Opt.Def body)
100−
101− _ : _ ->
102− do htc <- Env.getTailCall
103− Env.setTailCall False
10429
105− (args, body) <- optimizeFunction (Just name) rawArgs rawBody
30+-- EXPRESSIONS
10631
107− isTailCall <- Env.getTailCall
108− Env.setTailCall htc
109−
110− return $ (,) name $
111− if isTailCall then
112− Opt.TailDef args body
113− else
114− Opt.Def (Opt.Function args body)
115−
116−
117−destruct :: Opt.Expr -> P.Canonical -> [(Text, Opt.Def)]
118−destruct root pattern =
119− map (second Opt.Def) $
120− patternToSubstitutions root pattern
121−
122−
123−
124−-- OPTIMIZE FUNCTION
125−
126−
127−optimizeFunction
128− :: Maybe Text
129− -> [P.Canonical]
130− -> Can.Expr
131− -> Env.Optimizer ([Text], Opt.Expr)
132−optimizeFunction maybeName patterns givenBody =
133− Env.indirectly $
134− do (argNames, body) <- M.foldM depatternArgs ([], givenBody) (reverse patterns)
135− optBody <- optimizeExpr (makeContext argNames =<< maybeName) body
136− return (argNames, optBody)
137−
138−
139−makeContext :: [Text] -> Text -> Context
140−makeContext argNames name =
141− Just (name, length argNames, argNames)
142−
143−
144−depatternArgs :: ([Text], Can.Expr) -> P.Canonical -> Env.Optimizer ([Text], Can.Expr)
145−depatternArgs (names, rawExpr) ptrn =
146− do (name, expr) <- depattern ptrn rawExpr
147− return (name : names, expr)
148−
149−
150−
151−-- TURN A PATTERN INTO A BUNCH OF SUBSTITUTIONS
15232
33+optimizeExpr :: Can.Expr -> Names.Tracker Opt.Expr
34+optimizeExpr (A.At region expression) =
35+ case expression of
36+ Can.VarLocal name ->
37+ pure (Opt.VarLocal name)
15338
154−patternToSubstitutions :: Opt.Expr -> P.Canonical -> [(Text, Opt.Expr)]
155−patternToSubstitutions expr (A.A _ pattern) =
156− case pattern of
157− P.Var name ->
158− [ (name, expr) ]
39+ Can.VarTopLevel home name ->
40+ Names.registerGlobal home name
15941
160− P.Literal _ ->
161− []
42+ Can.VarKernel home name ->
43+ Names.registerKernel home (Opt.VarKernel home name)
16244
163− P.Record fields ->
164− map (\name -> (name, Opt.Access expr name)) fields
45+ Can.VarForeign home name _ ->
46+ Names.registerGlobal home name
16547
166− P.Anything ->
167− []
48+ Can.VarDebug home name _ ->
49+ Names.registerKernel N.debug (Opt.VarDebug name home region Nothing)
16850
169− P.Alias alias realPattern ->
170− (alias, expr) : patternToSubstitutions expr realPattern
51+ Can.VarOperator _ home name _ ->
52+ Names.registerGlobal home name
17153
172− P.Ctor _ patterns ->
173− concat (zipWith (patternToSubstitutions . Opt.CtorAccess expr) [0..] patterns)
54+ Can.Chr chr ->
55+ pure (Opt.Chr chr)
17456
57+ Can.Str str ->
58+ pure (Opt.Str str)
17559
60+ Can.Int int ->
61+ pure (Opt.Int int)
17662
177−-- OPTIMIZE EXPRESSIONS
63+ Can.Float float ->
64+ pure (Opt.Float float)
17865
66+ Can.List entries ->
67+ Opt.List <$> traverse optimizeExpr entries
17968
180−type Context = Maybe (Text, Int, [Text])
69+ Can.Negate expr ->
70+ do func <- Names.registerGlobal ModuleName.basics N.negate
71+ arg <- optimizeExpr expr
72+ pure $ Opt.Call func [arg]
18173
74+ Can.Binop _ home name _ left right ->
75+ do optFunc <- Names.registerGlobal home name
76+ optLeft <- optimizeExpr left
77+ optRight <- optimizeExpr right
78+ return (Opt.Call optFunc [optLeft, optRight])
18279
183−{-| This optimizer detects tail calls. The `Context` holds a function name,
184−function arity, and list of argument names. If a tail call is possible, the
185−`Context` will be filled in and we check any function we run into. If we go
186−down a route that cannot possibly have tail calls, we remove the context.
187−-}
188−optimizeExpr :: Context -> Can.Expr -> Env.Optimizer Opt.Expr
189−optimizeExpr context annExpr@(A.A region expression) =
190− let
191− keepLooking =
192− optimizeExpr context
193− -- this *might* find a tail call, use this when something is a potential
194− -- tail call
80+ Can.Lambda args body ->
81+ do (argNames, defss) <- destructArgs args
82+ obody <- optimizeExpr body
83+ pure $
84+ Opt.Function argNames (foldr Opt.Let obody (concat defss))
19585
196− justConvert =
197− optimizeExpr Nothing
198− -- this will never find tail calls, use this when you are working with
199− -- expressions that cannot be turned into tail calls
200− in
201− case expression of
202− Can.Literal lit ->
203− pure (Opt.Literal lit)
204−
205− Can.Var var ->
206− optimizeVariable region var
207−
208− Can.List elements ->
209− Opt.List
210− <$> traverse justConvert elements
211−
212− Can.Binop op leftExpr rightExpr ->
213− optimizeBinop context region op leftExpr rightExpr
214−
215− Can.Lambda _ _ ->
216− let
217− (patterns, body) =
218− Can.collectLambdas annExpr
219− in
220− uncurry Opt.Function <$> optimizeFunction Nothing patterns body
221−
222− Can.App _ _ ->
223− let
224− (func:args) =
225− Can.collectApps annExpr
226− in
227− case getTailCallInfo context func (length args) of
228− Just (name, argNames) ->
229− do optArgs <- traverse justConvert args
230− Env.setTailCall True
231− return (Opt.TailCall name argNames optArgs)
232−
233− Nothing ->
234− do hasTailCall <- Env.getTailCall
235− optFunc <- justConvert func
236− optArgs <- traverse justConvert args
237− Env.setTailCall hasTailCall
238− return (Opt.Call optFunc optArgs)
86+ Can.Call func args ->
87+ Opt.Call
88+ <$> optimizeExpr func
89+ <*> traverse optimizeExpr args
23990
24091 Can.If branches finally ->
241− let
242− crawlBranch (cond,branch) =
243− (,) <$> justConvert cond <*> keepLooking branch
244− in
245− Opt.If
246− <$> traverse crawlBranch branches
247− <*> keepLooking finally
248−
249− Can.Let defs body ->
250− do optDefs <- concat <$> traverse optimizeLetDef defs
251− Opt.Let optDefs <$> keepLooking body
92+ let
93+ optimizeBranch (condition, branch) =
94+ (,)
95+ <$> optimizeExpr condition
96+ <*> optimizeExpr branch
97+ in
98+ Opt.If
99+ <$> traverse optimizeBranch branches
100+ <*> optimizeExpr finally
101+
102+ Can.Let def body ->
103+ optimizeDef def =<< optimizeExpr body
104+
105+ Can.LetRec defs body ->
106+ case defs of
107+ [def] ->
108+ Opt.Let
109+ <$> optimizePotentialTailCall def
110+ <*> optimizeExpr body
111+
112+ _ ->
113+ do obody <- optimizeExpr body
114+ foldM (\bod def -> optimizeDef def bod) obody defs
115+
116+ Can.LetDestruct pattern expr body ->
117+ do (name, defs) <- destruct pattern
118+ oexpr <- optimizeExpr expr
119+ obody <- optimizeExpr body
120+ pure $
121+ Opt.Let (Opt.Def name oexpr) (foldr Opt.Let obody defs)
252122
253123 Can.Case expr branches ->
254− do optExpr <- optimizeExpr Nothing expr
255− variantDict <- Env.getVariantDict
256−
257− name <- Env.freshName
258− optBranches <- traverse (optimizeBranch context region name) branches
259− let optCase = Case.optimize variantDict name optBranches
260− return $ Opt.Let [ (name, Opt.Def optExpr) ] optCase
124+ error "TODO"
261125
262− Can.Ctor (Var.Canonical _ name) exprs ->
263− Opt.Ctor name <$> traverse justConvert exprs
126+ Can.Accessor field ->
127+ pure (Opt.Accessor field)
264128
265129 Can.Access record field ->
266− Opt.Access
267− <$> justConvert record
268− <*> pure field
130+ do optRecord <- optimizeExpr record
131+ pure (Opt.Access optRecord field)
269132
270− Can.Update record fields ->
271− Opt.Update
272− <$> justConvert record
273− <*> traverse (traverse justConvert) fields
133+ Can.Update record updates ->
134+ Opt.Update
135+ <$> optimizeExpr record
136+ <*> traverse optimizeExpr updates
274137
275138 Can.Record fields ->
276− Opt.Record
277− <$> traverse (traverse justConvert) fields
139+ Opt.Record <$> traverse optimizeExpr fields
278140
279− Can.Cmd home manager ->
280− Opt.Cmd home <$> Env.registerEffects home manager
141+ Can.Unit ->
142+ Names.registerKernel N.utils Opt.Unit
281143
282− Can.Sub home manager ->
283− Opt.Sub home <$> Env.registerEffects home manager
144+ Can.Tuple a b maybeC ->
145+ Names.registerKernel N.utils Opt.Tuple
146+ <*> optimizeExpr a
147+ <*> optimizeExpr b
148+ <*> traverse optimizeExpr maybeC
284149
285− Can.OutgoingPort name tipe ->
286− Opt.OutgoingPort name <$> Port.toEncoder tipe
150+ Can.Shader _ src _ ->
151+ pure (Opt.Shader src)
287152
288− Can.IncomingPort name tipe ->
289− Opt.IncomingPort name <$> Port.toDecoder tipe
290153
291− Can.Program main expr ->
292− Opt.Program <$> optimizeMain main <*> justConvert expr
293154
294− Can.SaveEnv _ _ ->
295− error "save_the_environment should never make it to optimization phase"
155+-- DEFINITION
296156
297− Can.GLShader _ src _ ->
298− pure (Opt.GLShader src)
299157
158+optimizeDef :: Can.Def -> Opt.Expr -> Names.Tracker Opt.Expr
159+optimizeDef def body =
160+ case def of
161+ Can.Def (A.At _ name) args expr ->
162+ optimizeDefHelp name args expr body
300163
164+ Can.TypedDef (A.At _ name) _ typedArgs expr _ ->
165+ optimizeDefHelp name (map fst typedArgs) expr body
301166
302−-- OPTIMIZE VARIABLE
303167
304−
305−optimizeVariable :: R.Region -> Var.Canonical -> Env.Optimizer Opt.Expr
306−optimizeVariable region (Var.Canonical home name) =
307− case home of
308− Var.BuiltIn ->
309− pure (Opt.VarLocal name)
310−
311− Var.Local ->
312− pure (Opt.VarLocal name)
313−
314− Var.TopLevel modul ->
315− do let var = Var.Global modul name
316− Env.register var
317− pure (Opt.VarGlobal var)
318−
319− Var.Module modul ->
320− do let var = Var.Global modul name
321− Env.register var
322− if name == "crash" && modul == ModuleName.inCore "Debug"
323− then
324− do here <- Env.getHome
325− pure (Opt.Crash here region Nothing)
326− else
327− pure (Opt.VarGlobal var)
328−
329−
330−
331−-- OPTIMIZE MAIN
332−
333−
334−optimizeMain :: Can.Main -> Env.Optimizer Opt.Main
335−optimizeMain main =
336− case main of
337− Can.Static ->
338− return Opt.Static
339−
340− Can.Dynamic tipe ->
341− Opt.Dynamic <$> Port.toFlagsDecoder tipe
342−
343−
344−
345−-- OPTIMIZE CASE BRANCHES
346−
347−
348−optimizeBranch
349− :: Context
350− -> R.Region
351− -> Text
352− -> (P.Canonical, Can.Expr)
353− -> Env.Optimizer (P.Canonical, Opt.Expr)
354−optimizeBranch context region exprName (rawPattern, canBranch) =
355− do optBranch <- optimizeExpr context canBranch
356− (pattern, branch) <- tagCrashBranch region rawPattern optBranch
357−
358− let substitutions = Map.fromList $
359− patternToSubstitutions (Opt.VarLocal exprName) pattern
360−
361− (,) pattern <$> Inline.inline substitutions branch
362−
363−
364−tagCrashBranch
365− :: R.Region
366− -> P.Canonical
367− -> Opt.Expr
368− -> Env.Optimizer (P.Canonical, Opt.Expr)
369−tagCrashBranch region pattern@(A.A pr _) expr =
370− case expr of
371− Opt.Call (Opt.Crash home _ _) [arg] ->
372− do name <- Env.freshName
373− return
374− ( A.A pr (P.Alias name pattern)
375− , Opt.Call (Opt.Crash home region (Just (Opt.VarLocal name))) [arg]
376− )
168+optimizeDefHelp :: N.Name -> [Can.Pattern] -> Can.Expr -> Opt.Expr -> Names.Tracker Opt.Expr
169+optimizeDefHelp name args expr body =
170+ case args of
171+ [] ->
172+ do oexpr <- optimizeExpr expr
173+ pure $ Opt.Let (Opt.Def name oexpr) body
377174
378175 _ ->
379− return (pattern, expr)
380−
381−
382−
383−-- DETECT TAIL CALL
176+ do (argNames, defss) <- destructArgs args
177+ let func = Opt.Function argNames (foldr Opt.Let body (concat defss))
178+ pure $
179+ Opt.Let (Opt.Def name func) body
384180
385181
386−getTailCallInfo :: Context -> Can.Expr -> Int -> Maybe (Text, [Text])
387−getTailCallInfo context (A.A _ function) arity =
388− case (context, function) of
389− ( Just (ctxName, ctxArity, argNames), Can.Var (Var.Canonical home name) ) ->
390182
391− if name == ctxName && arity == ctxArity && Var.isLocalHome home then
392− Just (name, argNames)
183+-- DESTRUCTURING
393184
394− else
395− Nothing
396185
397− _ ->
398− Nothing
186+destructArgs :: [Can.Pattern] -> Names.Tracker ([N.Name], [[Opt.Def]])
187+destructArgs args =
188+ unzip <$> traverse destruct args
399189
400190
191+destruct :: Can.Pattern -> Names.Tracker (N.Name, [Opt.Def])
192+destruct pattern@(A.At _ ptrn) =
193+ case ptrn of
194+ Can.PVar name ->
195+ pure (name, [])
401196
402−-- DEPATTERN
403−-- given a pattern and an expression, push the actual pattern matching into the
404−-- expression as a case-expression if necessary. The pattern compiler will work
405−-- it out from there
197+ Can.PAlias subPattern name ->
198+ do revDefs <- destructHelp (Opt.VarLocal name) subPattern []
199+ pure (name, reverse revDefs)
406200
201+ _ ->
202+ do name <- Names.generate
203+ revDefs <- destructHelp (Opt.VarLocal name) pattern []
204+ pure (name, reverse revDefs)
407205
408−depattern :: P.Canonical -> Can.Expr -> Env.Optimizer (Text, Can.Expr)
409−depattern canPattern@(A.A _ pattern) expr =
410− let
411− ann =
412− A.A (error "the annotation added in 'depattern' should not be observed!")
413−
414− caseExpr e branches =
415− ann (Can.Case e branches)
416−
417− var name =
418− ann (Can.Var (Var.local name))
419206
420− caseify =
421− do name <- Env.freshName
422− return
423− ( name
424− , caseExpr (var name) [ (canPattern, expr) ]
425− )
426− in
207+destructHelp :: Opt.Expr -> Can.Pattern -> [Opt.Def] -> Names.Tracker [Opt.Def]
208+destructHelp root (A.At region pattern) revDefs =
427209 case pattern of
428− P.Var name ->
429− return (name, expr)
210+ Can.PAnything ->
211+ pure revDefs
430212
431− P.Literal _ ->
432− caseify
213+ Can.PVar name ->
214+ pure (Opt.Def name root : revDefs)
433215
434− P.Record _ ->
435− caseify
216+ Can.PRecord fields ->
217+ let
218+ toDef field =
219+ Opt.Def field (Opt.Access root field)
220+ in
221+ pure (map toDef fields ++ revDefs)
436222
437− P.Anything ->
438− do name <- Env.freshName
439− return (name, expr)
223+ Can.PAlias subPattern name ->
224+ destructHelp (Opt.VarLocal name) subPattern $
225+ Opt.Def name root : revDefs
440226
441− P.Alias _ _ ->
442− caseify
227+ Can.PUnit ->
228+ pure revDefs
443229
444− P.Ctor _ _ ->
445− caseify
230+ Can.PTuple a b maybeC ->
231+ do name <- Names.generate
232+ let tuple = Opt.VarLocal name
233+ let newRevDefs = Opt.Def name root : revDefs
234+ case maybeC of
235+ Nothing ->
236+ destructHelp (Opt.CtorAccess tuple Index.second) b =<<
237+ destructHelp (Opt.CtorAccess tuple Index.first) a newRevDefs
446238
239+ Just c ->
240+ destructHelp (Opt.CtorAccess tuple Index.third) c =<<
241+ destructHelp (Opt.CtorAccess tuple Index.second) b =<<
242+ destructHelp (Opt.CtorAccess tuple Index.first) a newRevDefs
447243
244+ Can.PList [] ->
245+ pure revDefs
448246
449−-- OPTIMIZE BINOPS
247+ Can.PList (hd:tl) ->
248+ destructCons root hd (A.At region (Can.PList tl)) revDefs
450249
250+ Can.PCons hd tl ->
251+ destructCons root hd tl revDefs
451252
452−optimizeBinop
453− :: Context
454− -> R.Region
455− -> Var.Canonical
456− -> Can.Expr
457− -> Can.Expr
458− -> Env.Optimizer Opt.Expr
459−optimizeBinop context region op leftExpr rightExpr =
460− let
461− ann = A.A region
462− binop = ann (Can.Binop op leftExpr rightExpr)
463− in
464− if op == forwardApply then
253+ Can.PChr _ ->
254+ pure revDefs
465255
466− optimizeExpr context (collect id left forwardApply binop)
256+ Can.PStr _ ->
257+ pure revDefs
467258
468− else if op == backwardApply then
259+ Can.PInt _ ->
260+ pure revDefs
469261
470− optimizeExpr context (collect id right backwardApply binop)
262+ Can.PCtor _ _ _ _ _ args ->
263+ do name <- Names.generate
264+ foldM
265+ (destructCtorArg (Opt.VarLocal name))
266+ (Opt.Def name root : revDefs)
267+ args
471268
472− else if op == forwardCompose then
473269
474− do var <- Env.freshName
475− let makeRoot func = ann (Can.App func (ann (Can.Var (Var.local var))))
476− let body = collect makeRoot left forwardCompose binop
477− optimizeExpr context (ann (Can.Lambda (ann (P.Var var)) body))
270+destructCons :: Opt.Expr -> Can.Pattern -> Can.Pattern -> [Opt.Def] -> Names.Tracker [Opt.Def]
271+destructCons root hd tl revDefs =
272+ do name <- Names.generate
273+ let list = Opt.VarLocal name
274+ destructHelp (Opt.CtorAccess list Index.first) hd =<<
275+ destructHelp (Opt.CtorAccess list Index.second) tl (Opt.Def name root : revDefs)
478276
479− else if op == backwardCompose then
480277
481− do var <- Env.freshName
482− let makeRoot func = ann (Can.App func (ann (Can.Var (Var.local var))))
483− let body = collect makeRoot right backwardCompose binop
484− optimizeExpr context (ann (Can.Lambda (ann (P.Var var)) body))
278+destructCtorArg :: Opt.Expr -> [Opt.Def] -> Can.PatternCtorArg -> Names.Tracker [Opt.Def]
279+destructCtorArg root revDefs (Can.PatternCtorArg index _ arg) =
280+ destructHelp (Opt.CtorAccess root index) arg revDefs
485281
486− else if op == cons then
487282
488− optimizeExpr context (ann (Can.Ctor cons [ leftExpr, rightExpr ]))
489−
490− else
491283
492− do optLeft <- optimizeExpr Nothing leftExpr
493− optRight <- optimizeExpr Nothing rightExpr
494− makeOptBinop op optLeft optRight
284+-- TAIL CALL
495285
496286
497−-- left-associative ((x |> f) |> g)
498−forwardApply :: Var.Canonical
499−forwardApply =
500− Var.inCore "Basics" "|>"
287+optimizePotentialTailCall :: Can.Def -> Names.Tracker Opt.Def
288+optimizePotentialTailCall def =
289+ case def of
290+ Can.Def (A.At _ name) args expr ->
291+ do (argNames, defss) <- destructArgs args
292+ toTailDef name argNames defss <$>
293+ optimizeTailExpr name argNames expr
501294
295+ Can.TypedDef (A.At _ name) _ typedArgs expr _ ->
296+ do (argNames, defss) <- destructArgs (map fst typedArgs)
297+ toTailDef name argNames defss <$>
298+ optimizeTailExpr name argNames expr
502299
503−-- right-associative (g <| (f <| x))
504−backwardApply :: Var.Canonical
505−backwardApply =
506− Var.inCore "Basics" "<|"
507300
301+optimizeTailExpr :: N.Name -> [N.Name] -> Can.Expr -> Names.Tracker Opt.Expr
302+optimizeTailExpr name argNames locExpr@(A.At _ expression) =
303+ case expression of
304+ Can.Call (A.At _ (Can.VarTopLevel _ funcName)) args ->
305+ if funcName == name && length args == length argNames then
306+ Opt.TailCall name argNames <$> traverse optimizeExpr args
307+ else
308+ optimizeExpr locExpr
508309
509−-- left-associative ((f >> g) >> h)
510−forwardCompose :: Var.Canonical
511−forwardCompose =
512− Var.inCore "Basics" ">>"
310+ Can.If branches finally ->
311+ let
312+ optimizeBranch (condition, branch) =
313+ (,)
314+ <$> optimizeExpr condition
315+ <*> optimizeTailExpr name argNames branch
316+ in
317+ Opt.If
318+ <$> traverse optimizeBranch branches
319+ <*> optimizeTailExpr name argNames finally
320+
321+ Can.Let def body ->
322+ optimizeDef def =<< optimizeTailExpr name argNames body
323+
324+ Can.LetRec defs body ->
325+ case defs of
326+ [def] ->
327+ Opt.Let
328+ <$> optimizePotentialTailCall def
329+ <*> optimizeTailExpr name argNames body
330+
331+ _ ->
332+ do obody <- optimizeTailExpr name argNames body
333+ foldM (\bod def -> optimizeDef def bod) obody defs
334+
335+ Can.LetDestruct pattern expr body ->
336+ do (dname, defs) <- destruct pattern
337+ oexpr <- optimizeExpr expr
338+ obody <- optimizeTailExpr dname argNames body
339+ pure $
340+ Opt.Let (Opt.Def dname oexpr) (foldr Opt.Let obody defs)
513341
342+ Can.Case expr branches ->
343+ error "TODO"
514344
515−-- right-associative (h << (g << f))
516−backwardCompose :: Var.Canonical
517−backwardCompose =
518− Var.inCore "Basics" "<<"
345+ _ ->
346+ optimizeExpr locExpr
519347
520348
521−cons :: Var.Canonical
522−cons =
523− Var.Canonical Var.BuiltIn "::"
524349
350+-- DETECT TAIL CALLS
525351
526−type Assoc =
527− Can.Expr -> Can.Expr -> (Can.Expr, Can.Expr)
528352
353+toTailDef :: N.Name -> [N.Name] -> [[Opt.Def]] -> Opt.Expr -> Opt.Def
354+toTailDef name argNames defss body =
355+ if hasTailCall body then
356+ Opt.TailDef name argNames (foldr Opt.Let body (concat defss))
357+ else
358+ Opt.Def name (Opt.Function argNames (foldr Opt.Let body (concat defss)))
529359
530−left :: Assoc
531−left =
532− flip (,)
533360
361+hasTailCall :: Opt.Expr -> Bool
362+hasTailCall expression =
363+ case expression of
364+ Opt.TailCall _ _ _ ->
365+ True
534366
535−right :: Assoc
536−right =
537− (,)
367+ Opt.If branches finally ->
368+ hasTailCall finally || any (hasTailCall . snd) branches
538369
370+ Opt.Let _ body ->
371+ hasTailCall body
539372
540−collect :: (Can.Expr -> Can.Expr) -> Assoc -> Var.Canonical -> Can.Expr -> Can.Expr
541−collect makeRoot assoc desiredOp annExpr@(A.A ann expr) =
542− case expr of
543− Can.Binop op leftExpr rightExpr | op == desiredOp ->
544− let
545− (func, arg) = assoc leftExpr rightExpr
546− in
547− A.A ann (Can.App func (collect makeRoot assoc desiredOp arg))
373+ Opt.Case _ _ branches ->
374+ any (hasTailCall . snd) branches
548375
549376 _ ->
550− makeRoot annExpr
551−
552−
553−makeOptBinop :: Var.Canonical -> Opt.Expr -> Opt.Expr -> Env.Optimizer Opt.Expr
554−makeOptBinop (Var.Canonical home op) leftExpr rightExpr =
555− case home of
556− Var.Local ->
557− error "bug manifesting in Optimize.makeOptBinop"
558−
559− Var.BuiltIn ->
560− error "bug manifesting in Optimize.makeOptBinop"
561−
562− Var.Module name ->
563− do let var = Var.Global name op
564− Env.register var
565− return $ Opt.Binop var leftExpr rightExpr
377+ False
566378
567− Var.TopLevel name ->
568− do let var = Var.Global name op
569− Env.register var
570− return $ Opt.Binop var leftExpr rightExpr
src/Optimize/DecisionTree.hs+224−159
@@ -1,5 +1,13 @@
11{-# OPTIONS_GHC -Wall #-}
2−module Optimize.DecisionTree where
2+{-# LANGUAGE OverloadedStrings #-}
3+module Optimize.DecisionTree
4+ ( compile
5+ , Path(..)
6+ , Test(..)
7+ )
8+ where
9+
10+
311{- To learn more about how this works, definitely read through:
412
513 "When Do Match-Compilation Heuristics Matter?"
@@ -12,24 +20,18 @@ as SML/NJ to get nice trees.
1220-}
1321
1422import Control.Arrow (second)
23+import Control.Monad (liftM, liftM2)
1524import Data.Binary
1625import qualified Data.List as List
17−import qualified Data.Map as Map
18−import qualified Data.Set as Set
1926import qualified Data.Maybe as Maybe
20−import qualified Data.Text as Text
27+import qualified Data.Set as Set
2128import Data.Text (Text)
2229
23−import qualified AST.Helpers as Help
24−import qualified AST.Literal as L
25−import qualified AST.Pattern as P
26−import qualified AST.Variable as Var
30+import qualified AST.Canonical as Can
31+import qualified Elm.Name as N
2732import qualified Reporting.Annotation as A
2833
2934
30−type CPattern = P.Canonical
31−
32−
3335
3436-- COMPILE CASES
3537
@@ -43,30 +45,13 @@ If 2 or more leaves point to the same label, we need to do some tricks in JS to
4345make that work nicely. When is JS getting goto?! ;) That is outside the scope
4446of this module though.
4547-}
46−compile :: VariantDict -> [(CPattern, Int)] -> DecisionTree
47−compile variantDict rawBranches =
48+compile :: [(Can.Pattern, Int)] -> DecisionTree
49+compile rawBranches =
4850 let
4951 format (pattern, index) =
5052 Branch index [(Empty, pattern)]
5153 in
52− toDecisionTree variantDict (map format rawBranches)
53−
54−
55−{-| When a certain union type is defined, you specify a certain number of tags.
56−This helps us do a few optimizations:
57−
58− * If there is only one possible tag, we can always skip checking what it is.
59− Tuples are a common example of this.
60− * If we use all possible tags, we can skip doing the last test. If we have
61− checked N-1 of N tags, there is no need to test the Nth, we know its the
62− one we want
63−
64−So this dictionary maps tags to the number of variants that exist, so it'll
65−contain things like [ ("Just", 2), ("Nothing", 2), ("#2", 1), ... ] which
66−we can use for these optimizations.
67−-}
68−type VariantDict =
69− Map.Map Var.Home (Map.Map Text Int)
54+ toDecisionTree (map format rawBranches)
7055
7156
7257
@@ -74,27 +59,29 @@ type VariantDict =
7459
7560
7661data DecisionTree
77− = Match Int
78− | Decision
79− { _test :: Path
80− , _edges :: [(Test, DecisionTree)]
81− , _default :: Maybe DecisionTree
82− }
83− deriving (Eq)
62+ = Match Int
63+ | Decision
64+ { _path :: Path
65+ , _edges :: [(Test, DecisionTree)]
66+ , _default :: Maybe DecisionTree
67+ }
68+ deriving (Eq)
8469
8570
8671data Test
87− = Constructor Var.Canonical
88− | Literal L.Literal
89− deriving (Eq, Ord)
72+ = IsCtor Int N.Name
73+ | IsInt Int
74+ | IsChr Text
75+ | IsStr Text
76+ deriving (Eq, Ord)
9077
9178
9279data Path
93− = Position Int Path
94− | Field Text Path
95− | Empty
96− | Alias
97− deriving (Eq)
80+ = Index Int Path
81+ | Field N.Name Path
82+ | Empty
83+ | Alias
84+ deriving (Eq)
9885
9986
10087
@@ -110,17 +97,17 @@ add path finalLink =
11097 Alias ->
11198 error "nothing should be added to an alias path"
11299
113− Position index subpath ->
114− Position index (add subpath finalLink)
100+ Index index subpath ->
101+ Index index (add subpath finalLink)
115102
116103 Field name subpath ->
117104 Field name (add subpath finalLink)
118105
119106
120−subPositions :: Path -> [CPattern] -> [(Path, CPattern)]
107+subPositions :: Path -> [Can.Pattern] -> [(Path, Can.Pattern)]
121108subPositions path patterns =
122109 zipWith
123− (\index pattern -> (add path (Position index Empty), pattern))
110+ (\index pattern -> (add path (Index index Empty), pattern))
124111 [0..]
125112 patterns
126113
@@ -132,15 +119,15 @@ subPositions path patterns =
132119data Branch =
133120 Branch
134121 { _goal :: Int
135− , _patterns :: [(Path, CPattern)]
122+ , _patterns :: [(Path, Can.Pattern)]
136123 }
137124
138125
139−toDecisionTree :: VariantDict -> [Branch] -> DecisionTree
140−toDecisionTree variantDict rawBranches =
126+toDecisionTree :: [Branch] -> DecisionTree
127+toDecisionTree rawBranches =
141128 let
142129 branches =
143− map (flattenPatterns variantDict) rawBranches
130+ map flattenPatterns rawBranches
144131 in
145132 case checkForMatch branches of
146133 Just goal ->
@@ -149,13 +136,13 @@ toDecisionTree variantDict rawBranches =
149136 Nothing ->
150137 let
151138 path =
152− pickPath variantDict branches
139+ pickPath branches
153140
154141 (edges, fallback) =
155− gatherEdges variantDict branches path
142+ gatherEdges branches path
156143
157144 decisionEdges =
158− map (second (toDecisionTree variantDict)) edges
145+ map (second toDecisionTree) edges
159146 in
160147 case (decisionEdges, fallback) of
161148 ([(_tag, decisionTree)], []) ->
@@ -165,41 +152,22 @@ toDecisionTree variantDict rawBranches =
165152 Decision path decisionEdges Nothing
166153
167154 ([], _ : _) ->
168− toDecisionTree variantDict fallback
155+ toDecisionTree fallback
169156
170157 (_, _) ->
171− Decision path decisionEdges (Just (toDecisionTree variantDict fallback))
158+ Decision path decisionEdges (Just (toDecisionTree fallback))
172159
173160
174−isComplete :: VariantDict -> [Test] -> Bool
175−isComplete variantDict tests =
161+isComplete :: [Test] -> Bool
162+isComplete tests =
176163 case head tests of
177− Constructor var ->
178− getArity variantDict var == length tests
179−
180− Literal (L.Boolean _) ->
181− length tests == 2
164+ IsCtor alts _ ->
165+ alts == length tests
182166
183167 _ ->
184168 False
185169
186170
187−getArity :: VariantDict -> Var.Canonical -> Int
188−getArity variantDict (Var.Canonical home name) =
189− case Map.lookup name =<< Map.lookup home variantDict of
190− Just arity ->
191− arity
192−
193− Nothing ->
194− if Help.isTuple name then
195− read (drop 6 (Text.unpack name))
196−
197− else
198− error
199− "Since the Optimize phase happens after canonicalization and type \
200− \inference, it is impossible that a pattern cannot be found."
201−
202−
203171
204172-- FLATTEN PATTERNS
205173
@@ -207,38 +175,63 @@ getArity variantDict (Var.Canonical home name) =
207175{-| Flatten type aliases and use the VariantDict to figure out when a tag is
208176the only variant so we can skip doing any tests on it.
209177-}
210−flattenPatterns :: VariantDict -> Branch -> Branch
211−flattenPatterns variantDict (Branch goal pathPatterns) =
212− Branch goal (concatMap (flatten variantDict) pathPatterns)
178+flattenPatterns :: Branch -> Branch
179+flattenPatterns (Branch goal pathPatterns) =
180+ Branch goal (concatMap flatten pathPatterns)
213181
214182
215−flatten :: VariantDict -> (Path, CPattern) -> [(Path, CPattern)]
216−flatten variantDict pathPattern@(path, A.A ann pattern) =
183+flatten :: (Path, Can.Pattern) -> [(Path, Can.Pattern)]
184+flatten pathPattern@(path, A.At region pattern) =
217185 case pattern of
218− P.Var _ ->
186+ Can.PVar _ ->
219187 [pathPattern]
220188
221− P.Anything ->
189+ Can.PAnything ->
222190 [pathPattern]
223191
224− P.Alias alias realPattern ->
225− (add path Alias, A.A ann (P.Var alias))
192+ Can.PAlias realPattern alias ->
193+ (add path Alias, A.At region (Can.PVar alias))
226194 :
227− flatten variantDict (path, realPattern)
195+ flatten (path, realPattern)
196+
197+ Can.PRecord _ ->
198+ [pathPattern]
228199
229− P.Record _ ->
200+ Can.PUnit ->
230201 [pathPattern]
231202
232− P.Ctor tag patterns ->
233− if getArity variantDict tag == 1 then
234− concatMap (flatten variantDict) (subPositions path patterns)
203+ Can.PTuple a b Nothing ->
204+ concatMap flatten (subPositions path [a,b])
235205
206+ Can.PTuple a b (Just c) ->
207+ concatMap flatten (subPositions path [a,b,c])
208+
209+ Can.PCtor _ _ _ (Can.CtorAlts numAlts _) _ args ->
210+ if numAlts == 1 then
211+ concatMap flatten (subPositions path (map dearg args))
236212 else
237− [pathPattern]
213+ [pathPattern]
238214
239− P.Literal _ ->
215+ Can.PList _ ->
240216 [pathPattern]
241217
218+ Can.PCons _ _ ->
219+ [pathPattern]
220+
221+ Can.PChr _ ->
222+ [pathPattern]
223+
224+ Can.PStr _ ->
225+ [pathPattern]
226+
227+ Can.PInt _ ->
228+ [pathPattern]
229+
230+
231+dearg :: Can.PatternCtorArg -> Can.Pattern
232+dearg (Can.PatternCtorArg _ _ pattern) =
233+ pattern
234+
242235
243236
244237-- SUCCESSFULLY MATCH
@@ -263,8 +256,8 @@ checkForMatch branches =
263256-- GATHER OUTGOING EDGES
264257
265258
266−gatherEdges :: VariantDict -> [Branch] -> Path -> ([(Test, [Branch])], [Branch])
267−gatherEdges variantDict branches path =
259+gatherEdges :: [Branch] -> Path -> ([(Test, [Branch])], [Branch])
260+gatherEdges branches path =
268261 let
269262 relevantTests =
270263 testsAtPath path branches
@@ -273,7 +266,7 @@ gatherEdges variantDict branches path =
273266 map (edgesFor path branches) relevantTests
274267
275268 fallbacks =
276− if isComplete variantDict relevantTests then
269+ if isComplete relevantTests then
277270 []
278271 else
279272 filter (isIrrelevantTo path) branches
@@ -308,26 +301,57 @@ testAtPath selectedPath (Branch _ pathPatterns) =
308301 Nothing ->
309302 Nothing
310303
311− Just (A.A _ pattern) ->
304+ Just (A.At _ pattern) ->
312305 case pattern of
313− P.Ctor name _ ->
314− Just (Constructor name)
306+ Can.PCtor _ _ _ (Can.CtorAlts numAlts _) name _ ->
307+ Just (IsCtor numAlts name)
308+
309+ Can.PInt int ->
310+ Just (IsInt int)
311+
312+ Can.PStr str ->
313+ Just (IsStr str)
315314
316− P.Literal lit ->
317− Just (Literal lit)
315+ Can.PChr chr ->
316+ Just (IsChr chr)
318317
319− P.Var _ ->
318+ Can.PList [] ->
319+ Just nilTest
320+
321+ Can.PList _ ->
322+ Just consTest
323+
324+ Can.PCons _ _ ->
325+ Just consTest
326+
327+ Can.PVar _ ->
320328 Nothing
321329
322− P.Alias _ _ ->
330+ Can.PAlias _ _ ->
323331 error "aliases should never reach 'testAtPath' function"
324332
325− P.Anything ->
333+ Can.PAnything ->
326334 Nothing
327335
328− P.Record _ ->
336+ Can.PUnit ->
329337 Nothing
330338
339+ Can.PTuple _ _ _ ->
340+ Nothing
341+
342+ Can.PRecord _ ->
343+ Nothing
344+
345+
346+{-# NOINLINE nilTest #-}
347+nilTest :: Test
348+nilTest = IsCtor 2 "[]"
349+
350+
351+{-# NOINLINE consTest #-}
352+consTest :: Test
353+consTest = IsCtor 2 "::"
354+
331355
332356
333357-- BUILD EDGES
@@ -343,19 +367,48 @@ edgesFor path branches test =
343367toRelevantBranch :: Test -> Path -> Branch -> Maybe Branch
344368toRelevantBranch test path branch@(Branch goal pathPatterns) =
345369 case extract path pathPatterns of
346− Just (start, A.A _ pattern, end) ->
370+ Just (start, A.At region pattern, end) ->
347371 case pattern of
348− P.Ctor name patterns ->
349− if test == Constructor name then
350− Just (Branch goal (start ++ subPositions path patterns ++ end))
372+ Can.PCtor _ _ _ (Can.CtorAlts numAlts _) name args ->
373+ if test == IsCtor numAlts name then
374+ Just (Branch goal (start ++ subPositions path (map dearg args) ++ end))
375+ else
376+ Nothing
377+
378+ Can.PList [] ->
379+ if test == IsCtor 2 "[]" then
380+ Just (Branch goal (start ++ end))
381+ else
382+ Nothing
383+
384+ Can.PList (hd:tl) ->
385+ if test == IsCtor 2 "::" then
386+ let tl' = A.At region (Can.PList tl) in
387+ Just (Branch goal (start ++ subPositions path [ hd, tl' ] ++ end))
388+ else
389+ Nothing
390+
391+ Can.PCons hd tl ->
392+ if test == IsCtor 2 "::" then
393+ Just (Branch goal (start ++ subPositions path [hd,tl] ++ end))
394+ else
395+ Nothing
351396
397+ Can.PChr chr ->
398+ if test == IsChr chr then
399+ Just (Branch goal (start ++ end))
352400 else
353401 Nothing
354402
355− P.Literal lit ->
356− if test == Literal lit then
403+ Can.PStr str ->
404+ if test == IsStr str then
357405 Just (Branch goal (start ++ end))
406+ else
407+ Nothing
358408
409+ Can.PInt int ->
410+ if test == IsInt int then
411+ Just (Branch goal (start ++ end))
359412 else
360413 Nothing
361414
@@ -368,8 +421,8 @@ toRelevantBranch test path branch@(Branch goal pathPatterns) =
368421
369422extract
370423 :: Path
371− -> [(Path, CPattern)]
372− -> Maybe ([(Path, CPattern)], CPattern, [(Path, CPattern)])
424+ -> [(Path, Can.Pattern)]
425+ -> Maybe ([(Path, Can.Pattern)], Can.Pattern, [(Path, Can.Pattern)])
373426extract selectedPath pathPatterns =
374427 case pathPatterns of
375428 [] ->
@@ -402,25 +455,43 @@ isIrrelevantTo selectedPath (Branch _ pathPatterns) =
402455 not (needsTests pattern)
403456
404457
405−needsTests :: CPattern -> Bool
406−needsTests (A.A _ pattern) =
458+needsTests :: Can.Pattern -> Bool
459+needsTests (A.At _ pattern) =
407460 case pattern of
408− P.Var _ ->
461+ Can.PVar _ ->
409462 False
410463
411− P.Anything ->
464+ Can.PAnything ->
412465 False
413466
414− P.Alias _ _ ->
467+ Can.PAlias _ _ ->
415468 error "aliases should never reach 'isIrrelevantTo' function"
416469
417− P.Record _ ->
470+ Can.PRecord _ ->
471+ False
472+
473+ Can.PCtor _ _ _ _ _ _ ->
474+ True
475+
476+ Can.PList _ ->
477+ True
478+
479+ Can.PCons _ _ ->
480+ True
481+
482+ Can.PUnit ->
483+ False
484+
485+ Can.PTuple _ _ _ ->
418486 False
419487
420− P.Ctor _ _ ->
488+ Can.PChr _ ->
489+ True
490+
491+ Can.PStr _ ->
421492 True
422493
423− P.Literal _ ->
494+ Can.PInt _ ->
424495 True
425496
426497
@@ -428,8 +499,8 @@ needsTests (A.A _ pattern) =
428499-- PICK A PATH
429500
430501
431−pickPath :: VariantDict -> [Branch] -> Path
432−pickPath variantDict branches =
502+pickPath :: [Branch] -> Path
503+pickPath branches =
433504 let
434505 allPaths =
435506 Maybe.mapMaybe isChoicePath (concatMap _patterns branches)
@@ -439,10 +510,10 @@ pickPath variantDict branches =
439510 path
440511
441512 tiedPaths ->
442− head (bests (addWeights (smallBranchingFactor variantDict branches) tiedPaths))
513+ head (bests (addWeights (smallBranchingFactor branches) tiedPaths))
443514
444515
445−isChoicePath :: (Path, CPattern) -> Maybe Path
516+isChoicePath :: (Path, Can.Pattern) -> Maybe Path
446517isChoicePath (path, pattern) =
447518 if needsTests pattern then
448519 Just path
@@ -485,11 +556,11 @@ smallDefaults branches path =
485556 length (filter (isIrrelevantTo path) branches)
486557
487558
488−smallBranchingFactor :: VariantDict -> [Branch] -> Path -> Int
489−smallBranchingFactor variantDict branches path =
559+smallBranchingFactor :: [Branch] -> Path -> Int
560+smallBranchingFactor branches path =
490561 let
491562 (edges, fallback) =
492− gatherEdges variantDict branches path
563+ gatherEdges branches path
493564 in
494565 length edges + (if null fallback then 0 else 1)
495566
@@ -499,42 +570,36 @@ smallBranchingFactor variantDict branches path =
499570
500571
501572instance Binary Test where
573+ put test =
574+ case test of
575+ IsCtor a b -> putWord8 0 >> put a >> put b
576+ IsChr a -> putWord8 1 >> put a
577+ IsStr a -> putWord8 2 >> put a
578+ IsInt a -> putWord8 3 >> put a
579+
502580 get =
503581 do word <- getWord8
504582 case word of
505− 0 -> Constructor <$> get
506− 1 -> Literal <$> get
583+ 0 -> liftM2 IsCtor get get
584+ 1 -> liftM IsChr get
585+ 2 -> liftM IsStr get
586+ 3 -> liftM IsInt get
507587 _ -> error "problem getting DecisionTree.Test binary"
508588
509− put test =
510− case test of
511− Constructor var ->
512− putWord8 0 >> put var
513−
514− Literal literal ->
515− putWord8 1 >> put literal
516−
517589
518590instance Binary Path where
591+ put path =
592+ case path of
593+ Index a b -> putWord8 0 >> put a >> put b
594+ Field a b -> putWord8 1 >> put a >> put b
595+ Empty -> putWord8 2
596+ Alias -> putWord8 3
597+
519598 get =
520599 do word <- getWord8
521600 case word of
522− 0 -> Position <$> get <*> get
523− 1 -> Field <$> get <*> get
601+ 0 -> liftM2 Index get get
602+ 1 -> liftM2 Field get get
524603 2 -> pure Empty
525604 3 -> pure Alias
526605 _ -> error "problem getting DecisionTree.Path binary"
527−
528− put path =
529− case path of
530− Position index rest ->
531− putWord8 0 >> put index >> put rest
532−
533− Field field rest ->
534− putWord8 1 >> put field >> put rest
535−
536− Empty ->
537− putWord8 2
538−
539− Alias ->
540− putWord8 3
src/Optimize/Environment.hsdeleted−192
@@ -1,192 +0,0 @@
1−{-# OPTIONS_GHC -Wall #-}
2−{-# LANGUAGE OverloadedStrings #-}
3−module Optimize.Environment
4− ( Optimizer, run
5− , Env
6− , getVariantDict
7− , getHome
8− , getTailCall, setTailCall
9− , freshName
10− , register
11− , registerEffects
12− , indirectly
13− )
14− where
15−
16−import qualified Control.Monad.State.Strict as State
17−import Data.Monoid ((<>))
18−import qualified Data.Set as Set
19−import qualified Data.Text as Text
20−import Data.Text (Text)
21−
22−import qualified AST.Effects as Effects
23−import qualified AST.Expression.Optimized as Opt
24−import qualified AST.Module.Name as ModuleName
25−import qualified AST.Variable as Var
26−import qualified Optimize.DecisionTree as DT
27−
28−
29−
30−-- ENVIRONMENT
31−
32−
33−data Env =
34− Env
35− { _read_only_variants :: !DT.VariantDict
36− , _read_only_home :: !ModuleName.Canonical
37− , _uid :: !Int
38− , _deps :: Deps
39− , _effects :: Maybe Effects.ManagerType
40− , _has_tail_call :: !Bool
41− }
42−
43−
44−
45−-- DEPS
46−
47−
48−data Deps
49− = Direct { _direct :: Set.Set Var.Global, _indirect :: Set.Set Var.Global }
50− | Indirect (Set.Set Var.Global)
51−
52−
53−emptyDeps :: Deps
54−emptyDeps =
55− Direct Set.empty Set.empty
56−
57−
58−insertDep :: Var.Global -> Deps -> Deps
59−insertDep var deps =
60− case deps of
61− Direct direct indirect ->
62− Direct (Set.insert var direct) indirect
63−
64− Indirect indirect ->
65− Indirect (Set.insert var indirect)
66−
67−
68−unionDeps :: Set.Set Var.Global -> Deps -> Deps
69−unionDeps vars deps =
70− case deps of
71− Direct direct indirect ->
72− Direct (Set.union vars direct) indirect
73−
74− Indirect indirect ->
75− Indirect (Set.union vars indirect)
76−
77−
78−
79−-- OPTIMIZER
80−
81−
82−type Optimizer a =
83− State.State Env a
84−
85−
86−run
87− :: DT.VariantDict
88− -> ModuleName.Canonical
89− -> Optimizer (Text, Opt.Def)
90− -> (Text, Opt.Decl)
91−run variantDict home optimizer =
92− let
93− ((name, def), Env _ _ _ (Direct direct indirect) fx _) =
94− State.runState optimizer $
95− Env variantDict home 0 emptyDeps Nothing False
96− in
97− ( name, Opt.Decl direct indirect fx def )
98−
99−
100−
101−-- READ ONLY
102−
103−
104−getVariantDict :: Optimizer DT.VariantDict
105−getVariantDict =
106− State.gets _read_only_variants
107−
108−
109−getHome :: Optimizer ModuleName.Canonical
110−getHome =
111− State.gets _read_only_home
112−
113−
114−
115−-- TAIL CALLS
116−
117−
118−getTailCall :: Optimizer Bool
119−getTailCall =
120− State.gets _has_tail_call
121−
122−
123−setTailCall :: Bool -> Optimizer ()
124−setTailCall bool =
125− do env <- State.get
126− State.put (env { _has_tail_call = bool })
127−
128−
129−
130−-- FRESH VARIABLES
131−
132−
133−freshName :: Optimizer Text
134−freshName =
135− do (Env vs home uid deps fx htc) <- State.get
136− State.put (Env vs home (uid + 1) deps fx htc)
137− return ("_p" <> Text.pack (show uid))
138−
139−
140−
141−-- REGISTER DEPENDENCIES
142−
143−
144−register :: Var.Global -> Optimizer ()
145−register global =
146− State.modify' (registerHelp global)
147−
148−
149−registerHelp :: Var.Global -> Env -> Env
150−registerHelp dep (Env vs home uid deps fx htc) =
151− Env vs home uid (insertDep dep deps) fx htc
152−
153−
154−indirectly :: Optimizer a -> Optimizer a
155−indirectly optimizer =
156− do (Env vs home uid deps fx htc) <- State.get
157− case deps of
158− Indirect _ ->
159− optimizer
160−
161− Direct direct indirect ->
162− do State.put (Env vs home uid (Indirect indirect) fx htc)
163− result <- optimizer
164− (Env vs_ home_ uid_ (Indirect indirect_) fx_ htc_) <- State.get
165− State.put (Env vs_ home_ uid_ (Direct direct indirect_) fx_ htc_)
166− return result
167−
168−
169−
170−-- REGISTER EFFECTS
171−
172−
173−registerEffects :: ModuleName.Canonical -> Effects.ManagerType -> Optimizer Effects.ManagerType
174−registerEffects home manager =
175− do (Env vs hm uid deps _ htc) <- State.get
176− let newDeps = unionDeps (getEffectDeps home manager) deps
177− State.put (Env vs hm uid newDeps (Just manager) htc)
178− return manager
179−
180−
181−getEffectDeps :: ModuleName.Canonical -> Effects.ManagerType -> Set.Set Var.Global
182−getEffectDeps home manager =
183− Set.fromList $ map (Var.Global home) $
184− case manager of
185− Effects.Cmds ->
186− [ "init", "onEffects", "onSelfMsg", "cmdMap" ]
187−
188− Effects.Subs ->
189− [ "init", "onEffects", "onSelfMsg", "subMap" ]
190−
191− Effects.Both ->
192− [ "init", "onEffects", "onSelfMsg", "cmdMap", "subMap" ]
src/Optimize/Inline.hsdeleted−283
@@ -1,283 +0,0 @@
1−{-# OPTIONS_GHC -Wall #-}
2−{-# LANGUAGE OverloadedStrings #-}
3−module Optimize.Inline (inline) where
4−
5−import Control.Arrow (second, (***))
6−import Control.Monad (foldM)
7−import qualified Data.List as List
8−import qualified Data.Map as Map
9−import Data.Text (Text)
10−
11−import AST.Expression.Optimized (Expr(..), Decider(..), Choice(..))
12−import qualified AST.Expression.Optimized as Opt
13−import qualified Optimize.Environment as Env
14−
15−
16−
17−inline :: Map.Map Text Opt.Expr -> Opt.Expr -> Env.Optimizer Opt.Expr
18−inline rawSubs expression =
19− let
20− counts =
21− count expression
22−
23− annotatedSubs =
24− Map.toList (Map.intersectionWith (,) counts rawSubs)
25− in
26− do (Subs subs defs) <- foldM processSubs (Subs Map.empty []) annotatedSubs
27− let inlinedExpr = replace subs expression
28− return $
29− if null defs then
30− inlinedExpr
31−
32− else
33− Let (map (second Opt.Def) defs) inlinedExpr
34−
35−
36−data Subs =
37− Subs
38− { _substitutions :: Map.Map Text Opt.Expr
39− , _definitions :: [(Text, Opt.Expr)]
40− }
41−
42−
43−processSubs :: Subs -> (Text, (Int, Opt.Expr)) -> Env.Optimizer Subs
44−processSubs (Subs subs defs) (name, (n, expr)) =
45− if n == 1 then
46− return $ Subs (Map.insert name expr subs) defs
47−
48− else
49− do uniqueName <- Env.freshName
50− return $ Subs
51− (Map.insert name (Opt.VarLocal uniqueName) subs)
52− ((uniqueName, expr) : defs)
53−
54−
55−
56−-- HELPERS
57−
58−
59−deleteBatch :: [Text] -> Map.Map Text a -> Map.Map Text a
60−deleteBatch names dict =
61− List.foldl' (flip Map.delete) dict names
62−
63−
64−
65−-- COUNT VARIABLE APPEARANCES
66−
67−
68−count :: Opt.Expr -> Map.Map Text Int
69−count expression =
70− let
71− count2 a b =
72− Map.unionWith (+) (count a) (count b)
73−
74− countMany xs =
75− Map.unionsWith (+) (map count xs)
76− in
77− case expression of
78− Literal _ ->
79− Map.empty
80−
81− VarLocal name ->
82− Map.singleton name 1
83−
84− VarGlobal _ ->
85− Map.empty
86−
87− List exprs ->
88− countMany exprs
89−
90− Binop _ left right ->
91− count2 left right
92−
93− Function args body ->
94− deleteBatch args (count body)
95−
96− Call func args ->
97− Map.unionWith (+) (count func) (countMany args)
98−
99− TailCall _name _argNames args ->
100− countMany args
101−
102− If branches finally ->
103− Map.unionsWith (+) (count finally : map (uncurry count2) branches)
104−
105− Let defs expr ->
106− let
107− countDef (name, def) =
108− case def of
109− Opt.Def body ->
110− Map.delete name (count body)
111−
112− Opt.TailDef argNames body ->
113− deleteBatch (name:argNames) (count body)
114−
115− exprCount =
116− deleteBatch (map fst defs) (count expr)
117− in
118− Map.unionsWith (+) (exprCount : map countDef defs)
119−
120− Case _ decider jumps ->
121− let
122− countDecider dcdr =
123− case dcdr of
124− Leaf (Inline expr) ->
125− count expr
126−
127− Leaf (Jump _) ->
128− Map.empty
129−
130− Chain _ success failure ->
131− Map.unionWith (+) (countDecider success) (countDecider failure)
132−
133− FanOut _path tests fallback ->
134− Map.unionsWith (+) (map countDecider (fallback : map snd tests))
135− in
136− Map.unionsWith (+) (countDecider decider : map (count . snd) jumps)
137−
138− Ctor _tag values ->
139− countMany values
140−
141− CtorAccess root _index ->
142− count root
143−
144− Access record _field ->
145− count record
146−
147− Update record fields ->
148− Map.unionWith (+) (count record) (countMany (map snd fields))
149−
150− Record fields ->
151− countMany (map snd fields)
152−
153− Cmd _ _ ->
154− Map.empty
155−
156− Sub _ _ ->
157− Map.empty
158−
159− OutgoingPort _ _ ->
160− Map.empty
161−
162− IncomingPort _ _ ->
163− Map.empty
164−
165− Program _ expr ->
166− count expr
167−
168− GLShader _ ->
169− Map.empty
170−
171− Crash _ _ maybeBranchProblem ->
172− maybe Map.empty count maybeBranchProblem
173−
174−
175−
176−-- REPLACE
177−
178−
179−replace :: Map.Map Text Opt.Expr -> Opt.Expr -> Opt.Expr
180−replace substitutions expression =
181− let
182− go = replace substitutions
183− in
184− case expression of
185− Literal _ ->
186− expression
187−
188− VarLocal name ->
189− maybe expression id (Map.lookup name substitutions)
190−
191− VarGlobal _ ->
192− expression
193−
194− List exprs ->
195− List (map go exprs)
196−
197− Binop op left right ->
198− Binop op (go left) (go right)
199−
200− Function args body ->
201− Function args (replace (deleteBatch args substitutions) body)
202−
203− Call func args ->
204− Call (go func) (map go args)
205−
206− TailCall name argNames args ->
207− TailCall name argNames (map go args)
208−
209− If branches finally ->
210− If (map (go *** go) branches) (go finally)
211−
212− Let defs expr ->
213− let
214− replaceDef (name, def) =
215− case def of
216− Opt.Def body ->
217− (,) name $ Opt.Def $
218− replace (Map.delete name substitutions) body
219−
220− Opt.TailDef argNames body ->
221− (,) name $ Opt.TailDef argNames $
222− replace (deleteBatch (name:argNames) substitutions) body
223−
224− boundNames =
225− map fst defs
226− in
227− Let
228− (map replaceDef defs)
229− (replace (deleteBatch boundNames substitutions) expr)
230−
231− Case exprName decider jumps ->
232− let
233− goDecider dcdr =
234− case dcdr of
235− Leaf (Inline expr) ->
236− Leaf (Inline (go expr))
237−
238− Leaf (Jump _target) ->
239− dcdr
240−
241− Chain chain success failure ->
242− Chain chain (goDecider success) (goDecider failure)
243−
244− FanOut path tests fallback ->
245− FanOut path (map (second goDecider) tests) (goDecider fallback)
246− in
247− Case exprName (goDecider decider) (map (second go) jumps)
248−
249− Ctor tag values ->
250− Ctor tag (map go values)
251−
252− CtorAccess root index ->
253− CtorAccess (go root) index
254−
255− Access record field ->
256− Access (go record) field
257−
258− Update record fields ->
259− Update (go record) (map (second go) fields)
260−
261− Record fields ->
262− Record (map (second go) fields)
263−
264− Cmd _ _ ->
265− expression
266−
267− Sub _ _ ->
268− expression
269−
270− OutgoingPort _ _ ->
271− expression
272−
273− IncomingPort _ _ ->
274− expression
275−
276− Program kind expr ->
277− Program kind (go expr)
278−
279− GLShader _ ->
280− expression
281−
282− Crash home region maybeBranchProblem ->
283− Crash home region (fmap go maybeBranchProblem)
src/Optimize/Names.hsnew file+105
@@ -0,0 +1,105 @@
1+{-# OPTIONS_GHC -Wall #-}
2+{-# LANGUAGE OverloadedStrings #-}
3+{-# LANGUAGE Rank2Types #-}
4+module Optimize.Names
5+ ( Tracker
6+ , run
7+ , generate
8+ , registerKernel
9+ , registerGlobal
10+ )
11+ where
12+
13+
14+import Data.Monoid ((<>))
15+import qualified Data.Set as Set
16+import qualified Data.Text as Text
17+
18+import qualified AST.Optimized as Opt
19+import qualified AST.Module.Name as ModuleName
20+import qualified Elm.Name as N
21+
22+
23+
24+-- GENERATOR
25+
26+
27+newtype Tracker a =
28+ Tracker (
29+ forall r.
30+ Int
31+ -> Set.Set N.Name
32+ -> Set.Set Opt.Global
33+ -> (Int -> Set.Set N.Name -> Set.Set Opt.Global -> a -> r)
34+ -> r
35+ )
36+
37+
38+run :: Tracker a -> (Set.Set N.Name, Set.Set Opt.Global, a)
39+run (Tracker k) =
40+ k 0 Set.empty Set.empty
41+ (\_uid kernels globals value -> (kernels, globals, value))
42+
43+
44+generate :: Tracker N.Name
45+generate =
46+ Tracker $ \n k g ok ->
47+ ok (n + 1) k g ("_n" <> Text.pack (show n))
48+
49+
50+registerKernel :: N.Name -> a -> Tracker a
51+registerKernel name value =
52+ Tracker $ \n k g ok ->
53+ ok n (Set.insert name k) g value
54+
55+
56+registerGlobal :: ModuleName.Canonical -> N.Name -> Tracker Opt.Expr
57+registerGlobal home name =
58+ Tracker $ \n k g ok ->
59+ let global = Opt.Global home name in
60+ ok n k (Set.insert global g) (Opt.VarGlobal global)
61+
62+
63+
64+-- INSTANCES
65+
66+
67+instance Functor Tracker where
68+ fmap func (Tracker kv) =
69+ Tracker $ \n k g ok ->
70+ let
71+ ok1 n1 k1 g1 value =
72+ ok n1 k1 g1 (func value)
73+ in
74+ kv n k g ok1
75+
76+
77+instance Applicative Tracker where
78+ {-# INLINE pure #-}
79+ pure value =
80+ Tracker $ \n k g ok -> ok n k g value
81+
82+ (<*>) (Tracker kf) (Tracker kv) =
83+ Tracker $ \n0 k0 g0 ok ->
84+ let
85+ ok1 n1 k1 g1 func =
86+ let
87+ ok2 n2 k2 g2 value =
88+ ok n2 k2 g2 (func value)
89+ in
90+ kv n1 k1 g1 ok2
91+ in
92+ kf n0 k0 g0 ok1
93+
94+
95+instance Monad Tracker where
96+ return = pure
97+
98+ (>>=) (Tracker ka) callback =
99+ Tracker $ \n k g ok ->
100+ let
101+ ok1 n1 k1 g1 a =
102+ case callback a of
103+ Tracker kb -> kb n1 k1 g1 ok
104+ in
105+ ka n k g ok1