1-- | This module optimizes code in the simplified-Objective-C intermediate representation.
3-- The following optimizations are supported:
5-- * Collapsing nested blocks
7-- * Tail call elimination
9-- * Inlining of (>>=) and ret for the Eff monad
11-- * Removal of unnecessary thunks
15-- * Inlining variables
17-- * Inline Prelude.($), Prelude.(#), Prelude.(++), Prelude.(!!)
19-- * Inlining primitive Objective-C operators
20module CodeGen.Cpp.Optimizer (optimize) where
24import Control.Monad.Supply.Class (MonadSupply)
25import Data.Text (Text)
26import Language.PureScript.CoreImp.AST
27import Language.PureScript.CoreImp.Optimizer.Blocks
28import Language.PureScript.CoreImp.Optimizer.Common hiding (isDict)
29import Language.PureScript.CoreImp.Optimizer.Inliner hiding (inlineUnsafeCoerce, inlineUnsafePartial)
30import Language.PureScript.CoreImp.Optimizer.Unused
31import Language.PureScript.PSString (PSString, decodeString)
33import CodeGen.Cpp.Common (unusedName)
34import CodeGen.Cpp.Optimizer.TCO
36import qualified Language.PureScript.Constants as C
39-- | Apply a series of optimizer passes to simplified Objective-C code
40optimize :: MonadSupply m => AST -> m AST
41-- optimize = untilFixedPoint $ return . inlineUnsafeCoerce . inlineUnsafePartial . tidyUp . tco
43 cpp' <- untilFixedPoint (return . inlineUnsafeCoerce . inlineUnsafePartial . tidyUp) cpp
44 untilFixedPoint (return . tidyUp) . tco
45 =<< untilFixedPoint (return . magicDo')
46 =<< untilFixedPoint (return . magicDo) cpp'
52 [ collapseNestedBlocks
53 -- , collapseNestedIfs
55 , removeCodeAfterReturnStatements
62untilFixedPoint :: (Monad m, Eq a) => (a -> m a) -> a -> m a
67 if a' == a then return a' else go a'
69-- | Overridden from CoreImp
71inlineUnsafePartial :: AST -> AST
72inlineUnsafePartial = everywhereTopDown convert where
73 convert (App ss (Indexer _ (Var _ unsafePartial) (Var _ partialUnsafe)) [ comp ])
74 | unsafePartial == C.unsafePartial && partialUnsafe == C.partialUnsafe
75 -- Apply to undefined here, the application should be optimized away
76 -- if it is safe to do so
77 = App ss comp [ Var ss C.undefined ]
80inlineUnsafeCoerce :: AST -> AST
81inlineUnsafeCoerce = everywhereTopDown convert where
82 convert (App _ (Indexer _ (Var _ unsafeCoerceFn) (Var _ unsafeCoerce)) [ comp ])
83 | unsafeCoerceFn == C.unsafeCoerceFn && unsafeCoerce == C.unsafeCoerce
87collapseIfChecks :: AST -> AST
88collapseIfChecks = everywhere collapse where
89 collapse :: AST -> AST
90 collapse (IfElse _ (Binary _ EqualTo (BooleanLiteral _ True) (BooleanLiteral _ True)) (Block _ [exprs]) _) = exprs
91 collapse (IfElse _ (Binary _ EqualTo (Indexer _ (Var _ prop) (Var _ val)) (BooleanLiteral _ True)) (Block _ [exprs]) _)
92 | prop == "otherwise" && val == "Data_Boolean" = exprs
93 collapse exprs = exprs
96magicDo = magicDo'' C.eff C.effDictionaries
99magicDo' = magicDo'' C.effect C.effectDictionaries
101magicDo'' :: Text -> C.EffectDictionaries -> AST -> AST
102magicDo'' effectModule C.EffectDictionaries{..} = everywhereTopDown convert
104 -- Desugar monomorphic calls to >>= and return for the Eff monad
105 convert :: AST -> AST
107 convert (App _ (App _ pure' [val]) []) | isPure pure' = val
109 convert (App _ (App _ bind [m]) [Function s1 Nothing [unused] (Block s2 cpp)]) | isDiscard bind && unused == unusedName =
110 Function s1 Nothing [] $ Block s2 (App s2 m [] : map applyReturns cpp )
112 convert (App _ (App _ bind [m]) [Function s1 Nothing [arg] (Block s2 cpp)]) | isBind bind =
113 Function s1 Nothing [] $ Block s2 (VariableIntroduction s2 arg (Just (App s2 m [])) : map applyReturns cpp)
114 -- Inline double applications
115 convert (App _ (App s1 (Function s2 Nothing [] (Block ss body)) []) []) =
116 App s1 (Function s2 Nothing [] (Block ss (applyReturns `fmap` body))) []
117 convert other = other
119 -- Check if an expression represents a monomorphic call to >>= for the Eff monad
120 isBind (App _ fn [dict]) | isDict (effectModule, edBindDict) dict && isBindPoly fn = True
122 -- Check if an expression represents a call to @discard@
123 isDiscard (App _ (App _ fn [dict1]) [dict2])
124 | isDict (C.controlBind, C.discardUnitDictionary) dict1 &&
125 isDict (effectModule, edBindDict) dict2 &&
126 isDiscardPoly fn = True
128 -- Check if an expression represents a monomorphic call to pure or return for the Eff applicative
129 isPure (App _ fn [dict]) | isDict (effectModule, edApplicativeDict) dict && isPurePoly fn = True
131 -- Check if an expression represents the polymorphic >>= function
132 isBindPoly = isDict (C.controlBind, C.bind)
133 -- Check if an expression represents the polymorphic pure function
134 isPurePoly = isDict (C.controlApplicative, C.pure')
135 -- Check if an expression represents the polymorphic discard function
136 isDiscardPoly = isDict (C.controlBind, C.discard)
139 applyReturns :: AST -> AST
140 applyReturns (Return ss ret) = Return ss (App ss ret [])
141 applyReturns (Block ss cpps) = Block ss (map applyReturns cpps)
142 applyReturns (IfElse ss cond t f) = IfElse ss cond (applyReturns t) (applyReturns `fmap` f)
143 applyReturns other = other
145 isDict :: (Text, PSString) -> AST -> Bool
146 isDict (moduleName, dictName) (Indexer _ (Var _ x) (Var _ y)) =
147 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