1{-# OPTIONS_GHC -Wall #-}
8import Control.Arrow (second)
9import qualified Data.Map as Map
11import qualified Data.Maybe as Maybe
12import qualified Data.Name as Name
14import qualified AST.Canonical as Can
15import qualified AST.Optimized as Opt
16import qualified Optimize.DecisionTree as DT
20-- OPTIMIZE A CASE EXPRESSION
23optimize :: Name.Name -> Name.Name -> [(Can.Pattern, Opt.Expr)] -> Opt.Expr
24optimize temp root optBranches =
26 (patterns, indexedBranches) =
27 unzip (zipWith indexify [0..] optBranches)
29 decider = treeToDecider (DT.compile patterns)
30 targetCounts = countTargets decider
32 (choices, maybeJumps) =
33 unzip (map (createChoices targetCounts) indexedBranches)
36 (insertChoices (Map.fromList choices) decider)
37 (Maybe.catMaybes maybeJumps)
40indexify :: Int -> (a,b) -> ((a,Int), (Int,b))
41indexify index (pattern, branch) =
50-- Decision trees may have some redundancies, so we convert them to a Decider
51-- which has special constructs to avoid code duplication when possible.
54treeToDecider :: DT.DecisionTree -> Opt.Decider Int
61 DT.Decision _ [] Nothing ->
62 error "compiler bug, somehow created an empty decision tree"
65 DT.Decision _ [(_, subTree)] Nothing ->
68 DT.Decision _ [] (Just subTree) ->
72 DT.Decision path [(test, successTree)] (Just failureTree) ->
73 toChain path test successTree failureTree
75 DT.Decision path [(test, successTree), (_, failureTree)] Nothing ->
76 toChain path test successTree failureTree
79 DT.Decision path edges Nothing ->
81 (necessaryTests, fallback) =
82 (init edges, snd (last edges))
86 (map (second treeToDecider) necessaryTests)
87 (treeToDecider fallback)
89 DT.Decision path edges (Just fallback) ->
90 Opt.FanOut path (map (second treeToDecider) edges) (treeToDecider fallback)
93toChain :: DT.Path -> DT.Test -> DT.DecisionTree -> DT.DecisionTree -> Opt.Decider Int
94toChain path test successTree failureTree =
97 treeToDecider failureTree
99 case treeToDecider successTree of
100 Opt.Chain testChain success subFailure | failure == subFailure ->
101 Opt.Chain ((path, test) : testChain) success failure
104 Opt.Chain [(path, test)] success failure
110-- If a target appears exactly once in a Decider, the corresponding expression
111-- can be inlined. Whether things are inlined or jumps is called a "choice".
114countTargets :: Opt.Decider Int -> Map.Map Int Int
115countTargets decisionTree =
118 Map.singleton target 1
120 Opt.Chain _ success failure ->
121 Map.unionWith (+) (countTargets success) (countTargets failure)
123 Opt.FanOut _ tests fallback ->
124 Map.unionsWith (+) (map countTargets (fallback : map snd tests))
130 -> ( (Int, Opt.Choice), Maybe (Int, Opt.Expr) )
131createChoices targetCounts (target, branch) =
132 if targetCounts ! target == 1 then
133 ( (target, Opt.Inline branch)
138 ( (target, Opt.Jump target)
139 , Just (target, branch)
144 :: Map.Map Int Opt.Choice
146 -> Opt.Decider Opt.Choice
147insertChoices choiceDict decider =
150 insertChoices choiceDict
154 Opt.Leaf (choiceDict ! target)
156 Opt.Chain testChain success failure ->
157 Opt.Chain testChain (go success) (go failure)
159 Opt.FanOut path tests fallback ->
160 Opt.FanOut path (map (second go) tests) (go fallback)
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