2323// to allow removal of the copies later.
2424// * Apply the constant values of immutable globals.
2525//
26+ // Some globals may not have uses after these changes, which we leave
27+ // to other passes to optimize.
28+ //
2629
2730#include < atomic>
2831
2932#include " ir/utils.h"
3033#include " pass.h"
34+ #include " wasm-builder.h"
3135#include " wasm.h"
3236
3337namespace wasm {
@@ -105,9 +109,26 @@ struct ConstantGlobalApplier
105109} // anonymous namespace
106110
107111struct SimplifyGlobals : public Pass {
108- void run (PassRunner* runner, Module* module ) override {
112+ PassRunner* runner;
113+ Module* module ;
114+
115+ GlobalInfoMap map;
116+
117+ void run (PassRunner* runner_, Module* module_) override {
118+ runner = runner_;
119+ module = module_;
120+
121+ analyze ();
122+
123+ preferEarlierImports ();
124+
125+ propagateConstantsToGlobals ();
126+
127+ propagateConstantsToCode ();
128+ }
129+
130+ void analyze () {
109131 // First, find out all the relevant info.
110- GlobalInfoMap map;
111132 for (auto & global : module ->globals ) {
112133 auto & info = map[global->name ];
113134 if (global->imported ()) {
@@ -128,6 +149,9 @@ struct SimplifyGlobals : public Pass {
128149 global->mutable_ = false ;
129150 }
130151 }
152+ }
153+
154+ void preferEarlierImports () {
131155 // Optimize uses of immutable globals, prefer the earlier import when
132156 // there is a copy.
133157 NameNameMap copiedParentMap;
@@ -155,9 +179,34 @@ struct SimplifyGlobals : public Pass {
155179 // Apply to the gets.
156180 GlobalUseModifier (&copiedParentMap).run (runner, module );
157181 }
158- // If any immutable globals have constant values, we can just apply them
159- // (the global itself will be removed by another pass, as it/ won't have
160- // any uses).
182+ }
183+
184+ // Constant propagation part 1: even an mutable global with a constant
185+ // value can have that value propagated to another global that reads it,
186+ // since we do know the value during startup, it can't be modified until
187+ // code runs.
188+ void propagateConstantsToGlobals () {
189+ // Go over the list of globals in order, which is the order of
190+ // initialization as well, tracking their constant values.
191+ std::map<Name, Literal> constantGlobals;
192+ for (auto & global : module ->globals ) {
193+ if (!global->imported ()) {
194+ if (auto * c = global->init ->dynCast <Const>()) {
195+ constantGlobals[global->name ] = c->value ;
196+ } else if (auto * get = global->init ->dynCast <GlobalGet>()) {
197+ auto iter = constantGlobals.find (get->name );
198+ if (iter != constantGlobals.end ()) {
199+ Builder builder (*module );
200+ global->init = builder.makeConst (iter->second );
201+ }
202+ }
203+ }
204+ }
205+ }
206+
207+ // Constant propagation part 2: apply the values of immutable globals
208+ // with constant values to to global.gets in the code.
209+ void propagateConstantsToCode () {
161210 NameSet constantGlobals;
162211 for (auto & global : module ->globals ) {
163212 if (!global->mutable_ && !global->imported () &&
@@ -168,8 +217,6 @@ struct SimplifyGlobals : public Pass {
168217 if (!constantGlobals.empty ()) {
169218 ConstantGlobalApplier (&constantGlobals).run (runner, module );
170219 }
171- // TODO a mutable global's initial value can be applied to another global
172- // after it, as the mutable one can't mutate during instance startup
173220 }
174221};
175222
0 commit comments