summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/passes/SimplifyGlobals.cpp61
1 files changed, 61 insertions, 0 deletions
diff --git a/src/passes/SimplifyGlobals.cpp b/src/passes/SimplifyGlobals.cpp
index 02e685ca7..0e66b5926 100644
--- a/src/passes/SimplifyGlobals.cpp
+++ b/src/passes/SimplifyGlobals.cpp
@@ -477,6 +477,11 @@ struct SimplifyGlobals : public Pass {
bool iteration() {
analyze();
+ // Fold single uses first, as it is simple to update the info from analyze()
+ // in this code (and harder to do in the things we do later, which is why we
+ // call analyze from scratch in each iteration).
+ foldSingleUses();
+
// Removing unneeded writes can in some cases lead to more optimizations
// that we need an entire additional iteration to perform, see below.
bool more = removeUnneededWrites();
@@ -672,6 +677,62 @@ struct SimplifyGlobals : public Pass {
}
ConstantGlobalApplier(&constantGlobals, optimize)
.run(getPassRunner(), module);
+ // Note that we don't need to run on module code here, since we already
+ // handle applying constants in globals in propagateConstantsToGlobals (and
+ // in a more sophisticated manner, which takes into account that no sets of
+ // globals are possible during global instantiation).
+ }
+
+ // If we have a global that has a single use in the entire program, we can
+ // fold it into that use, if it is global. For example:
+ //
+ // var x = { foo: 5 };
+ // var y = { bar: x };
+ //
+ // This can become:
+ //
+ // var y = { bar: { foo: 5 } };
+ //
+ // If there is more than one use, or the use is in a function (where it might
+ // execute more than once) then we can't do this.
+ void foldSingleUses() {
+ struct Folder : public PostWalker<Folder> {
+ Module& wasm;
+ GlobalInfoMap& infos;
+
+ Folder(Module& wasm, GlobalInfoMap& infos) : wasm(wasm), infos(infos) {}
+
+ void visitGlobalGet(GlobalGet* curr) {
+ // If this is a get of a global with a single get and no sets, then we
+ // can fold that code into here.
+ auto name = curr->name;
+ auto& info = infos[name];
+ if (info.written == 0 && info.read == 1) {
+ auto* global = wasm.getGlobal(name);
+ if (global->init) {
+ // Copy that global's code. For simplicity we copy it as we have to
+ // keep that global valid for the operations that happen after us,
+ // even though that global will be removed later (we could remove it
+ // here, but it would add more complexity than seems worth it).
+ replaceCurrent(ExpressionManipulator::copy(global->init, wasm));
+
+ // Update info for later parts of this pass: we are removing a
+ // global.get, which is a read, so now there are 0 reads (we also
+ // have 0 writes, so no other work is needed here, but update to
+ // avoid confusion when debugging, and for possible future changes).
+ info.read = 0;
+ }
+ }
+ }
+ };
+
+ Folder folder(*module, map);
+
+ for (auto& global : module->globals) {
+ if (global->init) {
+ folder.walk(global->init);
+ }
+ }
}
};