1-- | This module optimizes code in the intermediate representation.
2module CodeGen.Cpp.Optimizer (optimize) where
6import Control.Monad.Supply.Class (MonadSupply)
8import Language.PureScript.CoreImp.AST
9import Language.PureScript.CoreImp.Optimizer.Blocks
10import Language.PureScript.CoreImp.Optimizer.Common hiding (isDict)
11import Language.PureScript.CoreImp.Optimizer.Inliner hiding (inlineUnsafeCoerce, inlineUnsafePartial)
12import Language.PureScript.CoreImp.Optimizer.Unused
13import Language.PureScript.PSString (PSString, decodeString)
15import CodeGen.Cpp.Common (unusedName)
16import CodeGen.Cpp.Optimizer.TCO
18import qualified Language.PureScript.Constants as C
21-- | Apply a series of optimizer passes to simplified Objective-C code
22optimize :: MonadSupply m => AST -> AST -> m AST
23-- optimize = untilFixedPoint $ return . inlineUnsafeCoerce . inlineUnsafePartial . tidyUp . tco
25 cpp' <- untilFixedPoint (return . inlineApply . inlineUnsafeCoerce . inlineUnsafePartial . tidyUp) cpp
26 untilFixedPoint (return . tidyUp) . tco mn
27 =<< untilFixedPoint (return . magicDo')
28 =<< untilFixedPoint (return . magicDo) cpp'
34 [ collapseNestedBlocks
35 -- , collapseNestedIfs
37 , removeCodeAfterReturnStatements
44untilFixedPoint :: (Monad m, Eq a) => (a -> m a) -> a -> m a
49 if a' == a then return a' else go a'
51-- | Overridden from CoreImp
53inlineUnsafePartial :: AST -> AST
54inlineUnsafePartial = everywhereTopDown convert where
55 convert (App ss (Indexer _ (Var _ unsafePartial) (Var _ partialUnsafe)) [ comp ])
56 | unsafePartial == C.unsafePartial && partialUnsafe == C.partialUnsafe
57 -- Apply to undefined here, the application should be optimized away
58 -- if it is safe to do so
59 = App ss comp [ Var ss C.undefined ]
62inlineUnsafeCoerce :: AST -> AST
63inlineUnsafeCoerce = everywhereTopDown convert where
64 convert (App _ (Indexer _ (Var _ unsafeCoerceFn) (Var _ unsafeCoerce)) [ comp ])
65 | unsafeCoerceFn == C.unsafeCoerceFn && unsafeCoerce == C.unsafeCoerce
69inlineApply :: AST -> AST
70inlineApply = everywhereTopDown convert where
71 convert (App ss (App _ (Indexer _ (Var _ apply) (Var _ dataFunction)) [ f ]) [ arg ])
72 | apply == C.apply && dataFunction == C.dataFunction
74 convert (App ss (App _ (Indexer _ (Var _ applyFlipped) (Var _ dataFunction)) [ arg ]) [ f ])
75 | applyFlipped == C.applyFlipped && dataFunction == C.dataFunction
79collapseIfChecks :: AST -> AST
80collapseIfChecks = everywhere collapse where
81 collapse :: AST -> AST
82 collapse (IfElse _ (Binary _ EqualTo (BooleanLiteral _ True) (BooleanLiteral _ True)) (Block _ [exprs]) _) = exprs
83 collapse (IfElse _ (Binary _ EqualTo (Indexer _ (Var _ prop) (Var _ val)) (BooleanLiteral _ True)) (Block _ [exprs]) _)
84 | prop == "otherwise" && val == "Data_Boolean" = exprs
85 collapse exprs = exprs
88magicDo = magicDo'' C.eff C.effDictionaries
91magicDo' = magicDo'' C.effect C.effectDictionaries
93magicDo'' :: Text -> C.EffectDictionaries -> AST -> AST
94magicDo'' effectModule C.EffectDictionaries{..} = everywhereTopDown convert
96 -- Desugar monomorphic calls to >>= and return for the Eff monad
99 convert (App _ (App _ pure' [val]) []) | isPure pure' = val
101 convert (App _ (App _ bind [m]) [Function s1 Nothing [unused] (Block s2 cpp)]) | isDiscard bind && unused == unusedName =
102 Function s1 Nothing [] $ Block s2 (App s2 m [] : map applyReturns cpp )
104 convert (App _ (App _ bind [m]) [Function s1 Nothing [arg] (Block s2 cpp)]) | isBind bind =
105 Function s1 Nothing [] $ Block s2 (VariableIntroduction s2 arg (Just (App s2 m [])) : map applyReturns cpp)
106 -- Inline double applications
107 convert (App _ (App s1 (Function s2 Nothing [] (Block ss body)) []) []) =
108 App s1 (Function s2 Nothing [] (Block ss (applyReturns `fmap` body))) []
109 convert other = other
111 -- Check if an expression represents a monomorphic call to >>= for the Eff monad
112 isBind (App _ fn [dict]) | isDict (effectModule, edBindDict) dict && isBindPoly fn = True
114 -- Check if an expression represents a call to @discard@
115 isDiscard (App _ (App _ fn [dict1]) [dict2])
116 | isDict (C.controlBind, C.discardUnitDictionary) dict1 &&
117 isDict (effectModule, edBindDict) dict2 &&
118 isDiscardPoly fn = True
120 -- Check if an expression represents a monomorphic call to pure or return for the Eff applicative
121 isPure (App _ fn [dict]) | isDict (effectModule, edApplicativeDict) dict && isPurePoly fn = True
123 -- Check if an expression represents the polymorphic >>= function
124 isBindPoly = isDict (C.controlBind, C.bind)
125 -- Check if an expression represents the polymorphic pure function
126 isPurePoly = isDict (C.controlApplicative, C.pure')
127 -- Check if an expression represents the polymorphic discard function
128 isDiscardPoly = isDict (C.controlBind, C.discard)
131 applyReturns :: AST -> AST
132 applyReturns (Return ss ret) = Return ss (App ss ret [])
133 applyReturns (Block ss cpps) = Block ss (map applyReturns cpps)
134 applyReturns (IfElse ss cond t f) = IfElse ss cond (applyReturns t) (applyReturns `fmap` f)
135 applyReturns other = other
137 isDict :: (Text, PSString) -> AST -> Bool
138 isDict (moduleName, dictName) (Indexer _ (Var _ x) (Var _ y)) =
139 Just x == decodeString dictName && y == moduleName
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