11module Language.PureScript.Backend.IR.Optimizer where
22
3+ import Data.List.NonEmpty qualified as NE
34import Data.Map qualified as Map
5+ import Data.Set qualified as Set
46import Language.PureScript.Backend.IR.DCE qualified as DCE
57import Language.PureScript.Backend.IR.Linker (UberModule (.. ))
8+ import Language.PureScript.Backend.IR.Query (collectBoundNames )
69import Language.PureScript.Backend.IR.Types
710 ( Annotated
811 , Exp
@@ -25,9 +28,131 @@ import Language.PureScript.Backend.IR.Types
2528 , thenRewrite
2629 , unAnn
2730 )
31+ import Language.PureScript.Backend.IR.Types qualified as IR
2832
2933optimizedUberModule ∷ UberModule → UberModule
30- optimizedUberModule = idempotently $ DCE. eliminateDeadCode . optimizeModule
34+ optimizedUberModule =
35+ renameShadowedNames . idempotently (DCE. eliminateDeadCode . optimizeModule)
36+
37+ renameShadowedNames ∷ UberModule → UberModule
38+ renameShadowedNames UberModule {.. } =
39+ UberModule
40+ { uberModuleBindings = uberModuleBindings'
41+ , uberModuleExports = uberModuleExports'
42+ }
43+ where
44+ uberModuleBindings' ∷ [Grouping (QName , Exp )] = uberModuleBindings
45+ uberModuleExports' ∷ [(Name , Exp )] =
46+ renameShadowedNamesInExpr mempty <<$>> uberModuleExports
47+
48+ type RenamesInScope = Map Name [Name ]
49+
50+ renameShadowedNamesInExpr ∷ RenamesInScope → RawExp Identity → RawExp Identity
51+ renameShadowedNamesInExpr scope = go
52+ where
53+ go = \ case
54+ IR. LiteralInt i →
55+ IR. LiteralInt i
56+ IR. LiteralFloat f →
57+ IR. LiteralFloat f
58+ IR. LiteralString s →
59+ IR. LiteralString s
60+ IR. LiteralChar c →
61+ IR. LiteralChar c
62+ IR. LiteralBool b →
63+ IR. LiteralBool b
64+ IR. LiteralArray as →
65+ IR. LiteralArray (go <<$>> as)
66+ IR. LiteralObject ps →
67+ IR. LiteralObject ((go <$> ) <<$>> ps)
68+ IR. ReflectCtor a →
69+ IR. ReflectCtor (go <$> a)
70+ IR. Eq a b →
71+ IR. Eq (go <$> a) (go <$> b)
72+ IR. DataArgumentByIndex index a →
73+ IR. DataArgumentByIndex index (go <$> a)
74+ IR. ArrayLength a →
75+ IR. ArrayLength (go <$> a)
76+ IR. ArrayIndex a index →
77+ IR. ArrayIndex (go <$> a) index
78+ IR. ObjectProp a prop →
79+ IR. ObjectProp (go <$> a) prop
80+ IR. ObjectUpdate a ps →
81+ IR. ObjectUpdate (go <$> a) ((go <$> ) <<$>> ps)
82+ IR. Abs param body →
83+ IR. Abs param' (renameShadowedNamesInExpr scope' <$> body)
84+ where
85+ (param', scope') =
86+ case IR. unAnn param of
87+ IR. ParamUnused →
88+ (param, scope)
89+ IR. ParamNamed name →
90+ first
91+ (pure . IR. ParamNamed )
92+ (withScopedName (IR. unAnn body) scope name)
93+ IR. App a b →
94+ IR. App (go <$> a) (go <$> b)
95+ IR. Ref qname index →
96+ case qname of
97+ IR. Local lname
98+ | Just renames ← Map. lookup lname scope
99+ , Just rename ← renames !!? fromIntegral (IR. unIndex index) →
100+ IR. Ref (IR. Local rename) 0
101+ _ → IR. Ref qname index
102+ IR. Let binds body →
103+ IR. Let (NE. fromList (reverse binds')) body'
104+ where
105+ scope' ∷ RenamesInScope
106+ binds' ∷ [Grouping (Identity Name , Identity Exp )]
107+ (scope', binds') = foldl' f (scope, [] ) (toList binds)
108+ f
109+ ∷ (RenamesInScope , [Grouping (Identity Name , Identity Exp )])
110+ → Grouping (Identity Name , Identity Exp )
111+ → (RenamesInScope , [Grouping (Identity Name , Identity Exp )])
112+ f (sc, bs) = \ case
113+ Standalone (IR. unAnn → name, expr) →
114+ withScopedName (IR. unAnn expr) sc name & \ (name', sc') →
115+ let expr' = renameShadowedNamesInExpr sc <$> expr
116+ in (sc', Standalone (pure name', expr') : bs)
117+ RecursiveGroup (toList → recGroup) →
118+ (: bs) . RecursiveGroup . NE. fromList <$> foldl' g (sc, [] ) recGroup
119+ where
120+ g
121+ ∷ (RenamesInScope , [(Identity Name , Identity Exp )])
122+ → (Identity Name , Identity Exp )
123+ → (RenamesInScope , [(Identity Name , Identity Exp )])
124+ g (sc', recBinds) (IR. unAnn → name, expr) =
125+ withScopedName (IR. unAnn expr) sc' name & \ (name', sc'') →
126+ let expr' = renameShadowedNamesInExpr sc' <$> expr
127+ in (sc'', (pure name', expr') : recBinds)
128+ body' = renameShadowedNamesInExpr scope' <$> body
129+ IR. IfThenElse i t e →
130+ IR. IfThenElse (go <$> i) (go <$> t) (go <$> e)
131+ IR. Ctor aty ty ctr fs →
132+ IR. Ctor aty ty ctr fs
133+ IR. Exception m →
134+ IR. Exception m
135+ IR. ForeignImport m p →
136+ IR. ForeignImport m p
137+ where
138+ withScopedName ∷ Exp → Map Name [Name ] → Name → (Name , Map Name [Name ])
139+ withScopedName e sc name = case Map. lookup name sc of
140+ Nothing → (name, Map. insert name [name] sc)
141+ Just renames →
142+ ( rename
143+ , Map. insert rename [] $ Map. insert name (rename : renames) sc
144+ )
145+ where
146+ nextIndex = length renames
147+ usedNames = Map. keysSet sc <> collectBoundNames e
148+ rename = uniqueName usedNames name nextIndex
149+
150+ uniqueName ∷ Set Name → Name → Int → Name
151+ uniqueName usedNames n i =
152+ let nextName = Name (nameToText n <> show i)
153+ in if Set. member nextName usedNames
154+ then uniqueName usedNames n (i + 1 )
155+ else nextName
31156
32157idempotently ∷ Eq a ⇒ (a → a ) → a → a
33158idempotently = fix $ \ i f a →
@@ -43,7 +168,6 @@ optimizeModule UberModule {..} =
43168 UberModule
44169 { uberModuleBindings = uberModuleBindings'
45170 , uberModuleExports = uberModuleExports'
46- , ..
47171 }
48172 where
49173 (uberModuleBindings', uberModuleExports') =
0 commit comments