Skip to content

Commit eb14b10

Browse files
committed
Update optimizer (issue #34); improve generated names
1 parent d2c06e0 commit eb14b10

File tree

8 files changed

+708
-222
lines changed

8 files changed

+708
-222
lines changed

src/CodeGen/IL.hs

Lines changed: 8 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -325,9 +325,7 @@ moduleToIL (Module _ coms mn _ imps _ foreigns decls) _ =
325325
genGuard (cond, val) = do
326326
cond' <- valueToIL cond
327327
val' <- valueToIL val
328-
return
329-
(AST.IfElse Nothing (AST.Binary Nothing AST.EqualTo cond' (AST.BooleanLiteral Nothing True))
330-
(AST.Block Nothing [AST.Return Nothing val']) Nothing)
328+
return $ AST.IfElse Nothing (unbox' bool cond') (AST.Block Nothing [AST.Return Nothing val']) Nothing
331329

332330
guardsToIL (Right v) = return . AST.Return Nothing <$> valueToIL v
333331

@@ -366,16 +364,15 @@ moduleToIL (Module _ coms mn _ imps _ foreigns decls) _ =
366364

367365
literalToBinderIL :: Text -> [AST] -> Literal (Binder Ann) -> m [AST]
368366
literalToBinderIL varName done (NumericLiteral num) =
369-
return [AST.IfElse Nothing (AST.Binary Nothing AST.EqualTo (AST.Var Nothing varName) (AST.NumericLiteral Nothing num)) (AST.Block Nothing done) Nothing]
367+
return [AST.IfElse Nothing (AST.Binary Nothing AST.EqualTo (unbox' int $ AST.Var Nothing varName) (AST.NumericLiteral Nothing num)) (AST.Block Nothing done) Nothing]
370368
literalToBinderIL varName done (CharLiteral c) =
371-
return [AST.IfElse Nothing (AST.Binary Nothing AST.EqualTo (AST.Var Nothing varName) (AST.StringLiteral Nothing (fromString [c]))) (AST.Block Nothing done) Nothing]
369+
return [AST.IfElse Nothing (AST.Binary Nothing AST.EqualTo (unbox' string $ AST.Var Nothing varName) (AST.StringLiteral Nothing (fromString [c]))) (AST.Block Nothing done) Nothing]
372370
literalToBinderIL varName done (StringLiteral str) =
373-
return [AST.IfElse Nothing (AST.Binary Nothing AST.EqualTo (AST.Var Nothing varName) (AST.StringLiteral Nothing str)) (AST.Block Nothing done) Nothing]
371+
return [AST.IfElse Nothing (AST.Binary Nothing AST.EqualTo (unbox' string $ AST.Var Nothing varName) (AST.StringLiteral Nothing str)) (AST.Block Nothing done) Nothing]
374372
literalToBinderIL varName done (BooleanLiteral True) =
375-
return [AST.IfElse Nothing (AST.Binary Nothing AST.EqualTo (AST.Var Nothing varName) (AST.BooleanLiteral Nothing True)) (AST.Block Nothing done) Nothing]
373+
return [AST.IfElse Nothing (unbox' bool $ AST.Var Nothing varName) (AST.Block Nothing done) Nothing]
376374
literalToBinderIL varName done (BooleanLiteral False) =
377-
return [AST.IfElse Nothing (AST.Binary Nothing AST.EqualTo (AST.Var Nothing varName) (AST.BooleanLiteral Nothing False)) (AST.Block Nothing done) Nothing]
378-
-- return [AST.IfElse Nothing (AST.Unary Nothing AST.Not (AST.Var Nothing varName)) (AST.Block Nothing done) Nothing]
375+
return [AST.IfElse Nothing (AST.Unary Nothing AST.Not (unbox' bool $ AST.Var Nothing varName)) (AST.Block Nothing done) Nothing]
379376
literalToBinderIL varName done (ObjectLiteral bs) = go done bs
380377
where
381378
go :: [AST] -> [(PSString, Binder Ann)] -> m [AST]
@@ -406,7 +403,5 @@ emptyAnn = (SourceSpan "" (SourcePos 0 0) (SourcePos 0 0), [], Nothing, Nothing)
406403
arrayLength :: AST -> AST
407404
arrayLength a = AST.App Nothing (AST.Var Nothing arrayLengthFn) [a]
408405

409-
freshName' :: MonadSupply m => m Text
410-
freshName' = do
411-
name <- freshName
412-
return $ T.replace "$" "_Local_" name
406+
unbox' :: Text -> AST -> AST
407+
unbox' ty e = AST.App Nothing (AST.StringLiteral Nothing $ mkString ty) [e]

src/CodeGen/IL/Common.hs

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ module CodeGen.IL.Common where
33

44
import Prelude.Compat
55

6+
import Control.Monad.Supply.Class (MonadSupply, freshName)
67
import Data.Char
78
import Data.Monoid ((<>))
89
import Data.Text (Text)
@@ -14,7 +15,7 @@ import Language.PureScript.Names
1415
moduleNameToIL :: ModuleName -> Text
1516
moduleNameToIL (ModuleName pns) =
1617
let name = T.intercalate "_" (runProperName `map` pns)
17-
in if nameIsILBuiltIn name then ("_" <> name <> "_") else name
18+
in if nameIsILBuiltIn name then (name <> "_") else name
1819

1920
-- | Convert an 'Ident' into a valid C++ identifier:
2021
--
@@ -29,11 +30,11 @@ identToIL (Ident name) = properToIL name
2930
identToIL (GenIdent _ _) = internalError "GenIdent in identToIL"
3031

3132
unusedName :: Text
32-
unusedName = "_Unused_"
33+
unusedName = "_"
3334

3435
properToIL :: Text -> Text
3536
properToIL name
36-
| nameIsILReserved name || nameIsILBuiltIn name || prefixIsReserved name = "_" <> name <> "_"
37+
| nameIsILReserved name || nameIsILBuiltIn name || prefixIsReserved name = name <> "_"
3738
| otherwise = T.concatMap identCharToText name
3839

3940
-- | Test if a string is a valid AST identifier without escaping.
@@ -45,9 +46,9 @@ identNeedsEscaping s = s /= properToIL s || T.null s
4546
identCharToText :: Char -> Text
4647
identCharToText c | isAlphaNum c = T.singleton c
4748
identCharToText '_' = "_"
48-
identCharToText '\'' = "_Prime_"
49+
identCharToText '\'' = "Prime_"
4950
identCharToText '$' = "$"
50-
identCharToText c = "_Code_Point_" <> T.pack (show (ord c))
51+
identCharToText c = "_code_point_" <> T.pack (show (ord c))
5152

5253
-- | Checks whether an identifier name is reserved in C++.
5354
nameIsILReserved :: Text -> Bool
@@ -209,14 +210,19 @@ bool = "bool"
209210
string :: Text
210211
string = "string"
211212

213+
auto :: Text
214+
auto = "const auto"
215+
212216
unbox :: Text -> Text
213217
unbox t = "unbox<" <> t <> ">"
214218

215219
arrayLengthFn :: Text
216220
arrayLengthFn = "array_length"
217221

218222
unretainedSuffix :: Text
219-
unretainedSuffix = "_Weak_"
223+
unretainedSuffix = "_weak_"
220224

221-
tcoLoop :: Text
222-
tcoLoop = "_TCO_Loop_"
225+
freshName' :: MonadSupply m => m Text
226+
freshName' = do
227+
name <- freshName
228+
return $ T.replace "$" "_" name

src/CodeGen/IL/Optimizer.hs

Lines changed: 20 additions & 93 deletions
Original file line numberDiff line numberDiff line change
@@ -8,31 +8,29 @@ import Data.Text (Text)
88
import Language.PureScript.CoreImp.AST
99
import Language.PureScript.CoreImp.Optimizer.Blocks
1010
import Language.PureScript.CoreImp.Optimizer.Common hiding (isDict)
11-
import Language.PureScript.CoreImp.Optimizer.Inliner hiding (inlineUnsafeCoerce, inlineUnsafePartial)
11+
import Language.PureScript.CoreImp.Optimizer.Inliner (etaConvert, evaluateIifes, inlineVariables, unThunk)
1212
import Language.PureScript.CoreImp.Optimizer.Unused
13-
import Language.PureScript.PSString (PSString, decodeString)
1413

1514
import CodeGen.IL.Common (unusedName)
15+
import CodeGen.IL.Optimizer.Inliner
16+
import CodeGen.IL.Optimizer.MagicDo
1617
import CodeGen.IL.Optimizer.TCO
1718

1819
import qualified Language.PureScript.Constants as C
1920

20-
21-
-- | Apply a series of optimizer passes to simplified C++ code
21+
-- | Apply a series of optimizer passes to simplified IL code
2222
optimize :: MonadSupply m => AST -> AST -> m AST
23-
-- optimize = untilFixedPoint $ return . inlineUnsafeCoerce . inlineUnsafePartial . tidyUp . tco
2423
optimize mn il = do
25-
il' <- untilFixedPoint (return . inlineApply . inlineUnsafeCoerce . inlineUnsafePartial . tidyUp) il
26-
untilFixedPoint (return . tidyUp) . tco mn
27-
=<< untilFixedPoint (return . magicDo')
28-
=<< untilFixedPoint (return . magicDo) il'
29-
30-
24+
il' <- untilFixedPoint (inlineFnComposition . inlineUnsafeCoerce . inlineUnsafePartial . tidyUp) il
25+
untilFixedPoint (return . ignoreUnusedResults . inlineCommonValues . inlineCommonOperators . tidyUp) . tco mn . inlineST
26+
=<< untilFixedPoint (return . magicDoST)
27+
=<< untilFixedPoint (return . magicDoEff)
28+
=<< untilFixedPoint (return . magicDoEffect) il'
3129
where
3230
tidyUp :: AST -> AST
3331
tidyUp = applyAll
3432
[ collapseNestedBlocks
35-
-- , collapseNestedIfs
33+
, collapseNestedIfs
3634
, collapseIfChecks
3735
, removeCodeAfterReturnStatements
3836
, unThunk
@@ -48,34 +46,6 @@ untilFixedPoint f = go
4846
a' <- f a
4947
if a' == a then return a' else go a'
5048

51-
-- | Overridden from CoreImp
52-
53-
inlineUnsafePartial :: AST -> AST
54-
inlineUnsafePartial = 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 ]
60-
convert other = other
61-
62-
inlineUnsafeCoerce :: AST -> AST
63-
inlineUnsafeCoerce = everywhereTopDown convert where
64-
convert (App _ (Indexer _ (Var _ unsafeCoerceFn) (Var _ unsafeCoerce)) [ comp ])
65-
| unsafeCoerceFn == C.unsafeCoerceFn && unsafeCoerce == C.unsafeCoerce
66-
= comp
67-
convert other = other
68-
69-
inlineApply :: AST -> AST
70-
inlineApply = everywhereTopDown convert where
71-
convert (App ss (App _ (Indexer _ (Var _ apply) (Var _ dataFunction)) [ f ]) [ arg ])
72-
| apply == C.apply && dataFunction == C.dataFunction
73-
= App ss f [ arg ]
74-
convert (App ss (App _ (Indexer _ (Var _ applyFlipped) (Var _ dataFunction)) [ arg ]) [ f ])
75-
| applyFlipped == C.applyFlipped && dataFunction == C.dataFunction
76-
= App ss f [ arg ]
77-
convert other = other
78-
7949
collapseIfChecks :: AST -> AST
8050
collapseIfChecks = everywhere collapse where
8151
collapse :: AST -> AST
@@ -84,57 +54,14 @@ collapseIfChecks = everywhere collapse where
8454
| prop == "otherwise" && val == "Data_Boolean" = exprs
8555
collapse exprs = exprs
8656

87-
magicDo :: AST -> AST
88-
magicDo = magicDo'' C.eff C.effDictionaries
89-
90-
magicDo' :: AST -> AST
91-
magicDo' = magicDo'' C.effect C.effectDictionaries
92-
93-
magicDo'' :: Text -> C.EffectDictionaries -> AST -> AST
94-
magicDo'' effectModule C.EffectDictionaries{..} = everywhereTopDown convert
57+
ignoreUnusedResults :: AST -> AST
58+
ignoreUnusedResults = everywhere $ removeFromBlock go
9559
where
96-
-- Desugar monomorphic calls to >>= and return for the Eff monad
97-
convert :: AST -> AST
98-
-- Desugar pure
99-
convert (App _ (App _ pure' [val]) []) | isPure pure' = val
100-
-- Desugar discard
101-
convert (App _ (App _ bind [m]) [Function s1 Nothing [unused] (Block s2 il)]) | isDiscard bind && unused == unusedName =
102-
Function s1 Nothing [] $ Block s2 (App s2 m [] : map applyReturns il )
103-
-- Desugar bind
104-
convert (App _ (App _ bind [m]) [Function s1 Nothing [arg] (Block s2 il)]) | isBind bind =
105-
Function s1 Nothing [] $ Block s2 (VariableIntroduction s2 arg (Just (App s2 m [])) : map applyReturns il)
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
110-
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
113-
isBind _ = False
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
119-
isDiscard _ = False
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
122-
isPure _ = False
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)
129-
130-
131-
applyReturns :: AST -> AST
132-
applyReturns (Return ss ret) = Return ss (App ss ret [])
133-
applyReturns (Block ss ils) = Block ss (map applyReturns ils)
134-
applyReturns (IfElse ss cond t f) = IfElse ss cond (applyReturns t) (applyReturns `fmap` f)
135-
applyReturns other = other
136-
137-
isDict :: (Text, PSString) -> AST -> Bool
138-
isDict (moduleName, dictName) (Indexer _ (Var _ x) (Var _ y)) =
139-
Just x == decodeString dictName && y == moduleName
140-
isDict _ _ = False
60+
go :: [AST] -> [AST]
61+
go [] = []
62+
go (VariableIntroduction ss var (Just s) : sts)
63+
| not $ any (everything (||) (isUsed var)) sts = sts'
64+
where
65+
sts' | App{} <- s = s : (go sts)
66+
| otherwise = go sts
67+
go (s:sts) = s : go sts

src/CodeGen/IL/Optimizer/Common.hs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
-- | Common functions used by the various optimizer phases
2+
module CodeGen.IL.Optimizer.Common where
3+
4+
import Prelude.Compat
5+
6+
import Data.Text (Text)
7+
8+
import Language.PureScript.CoreImp.AST
9+
import Language.PureScript.PSString (PSString, decodeString)
10+
11+
isDict :: (Text, PSString) -> AST -> Bool
12+
isDict (moduleName, dictName) (Indexer _ (Var _ x) (Var _ y)) =
13+
Just x == decodeString dictName && y == moduleName
14+
isDict _ _ = False
15+
16+
isDict' :: [(Text, PSString)] -> AST -> Bool
17+
isDict' xs il = any (`isDict` il) xs
18+

0 commit comments

Comments
 (0)