diff options
Diffstat (limited to 'src/passes/SimplifyGlobals.cpp')
-rw-r--r-- | src/passes/SimplifyGlobals.cpp | 42 |
1 files changed, 32 insertions, 10 deletions
diff --git a/src/passes/SimplifyGlobals.cpp b/src/passes/SimplifyGlobals.cpp index be7cc6ca1..39414abe7 100644 --- a/src/passes/SimplifyGlobals.cpp +++ b/src/passes/SimplifyGlobals.cpp @@ -25,6 +25,7 @@ // * Apply the constant values of previous global.sets, in a linear // execution trace. // * Remove writes to globals that are never read from. +// * Remove writes to globals that are always assigned the same value. // * Remove writes to globals that are only read from in order to write (see // below, "readOnlyToWrite"). // @@ -60,6 +61,9 @@ struct GlobalInfo { std::atomic<Index> written{0}; std::atomic<Index> read{0}; + // Whether the global is written a value different from its initial value. + std::atomic<bool> nonInitWritten{false}; + // How many times the global is "read, but only to write", that is, is used in // this pattern: // @@ -93,7 +97,20 @@ struct GlobalUseScanner : public WalkerPass<PostWalker<GlobalUseScanner>> { GlobalUseScanner* create() override { return new GlobalUseScanner(infos); } - void visitGlobalSet(GlobalSet* curr) { (*infos)[curr->name].written++; } + void visitGlobalSet(GlobalSet* curr) { + (*infos)[curr->name].written++; + + // Check if there is a write of a value that may differ from the initial + // one. If there is anything but identical constants in both the initial + // value and the written value then we must assume that. + auto* global = getModule()->getGlobal(curr->name); + if (global->imported() || !Properties::isConstantExpression(curr->value) || + !Properties::isConstantExpression(global->init) || + Properties::getLiterals(curr->value) != + Properties::getLiterals(global->init)) { + (*infos)[curr->name].nonInitWritten = true; + } + } void visitGlobalGet(GlobalGet* curr) { (*infos)[curr->name].read++; } @@ -394,10 +411,11 @@ struct SimplifyGlobals : public Pass { bool removeUnneededWrites() { bool more = false; - // Globals that are not exports and not read from are unnecessary (even if - // they are written to). Likewise, globals that are only read from in order - // to write to themselves are unnecessary. First, find such globals. - NameSet unnecessaryGlobals; + // Globals that are not exports and not read from do not need their sets. + // Likewise, globals that only write their initial value later also do not + // need those writes. And, globals that are only read from in order to write + // to themselves as well. First, find such globals. + NameSet globalsNotNeedingSets; for (auto& global : module->globals) { auto& info = map[global->name]; @@ -431,15 +449,15 @@ struct SimplifyGlobals : public Pass { // our logic is wrong somewhere. assert(info.written >= info.readOnlyToWrite); - if (!info.read || onlyReadOnlyToWrite) { - unnecessaryGlobals.insert(global->name); + if (!info.read || !info.nonInitWritten || onlyReadOnlyToWrite) { + globalsNotNeedingSets.insert(global->name); // We can now mark this global as immutable, and un-written, since we - // are about to remove all the operations on it. + // are about to remove all the sets on it. global->mutable_ = false; info.written = 0; - // Nested old-read-to-write expressions require another full iteration + // Nested only-read-to-write expressions require another full iteration // to optimize, as we have: // // if (a) { @@ -452,6 +470,10 @@ struct SimplifyGlobals : public Pass { // The first iteration can only optimize b, as the outer if's body has // more effects than we understand. After finishing the first iteration, // b will no longer exist, removing those effects. + // + // TODO: In principle other situations exist as well where more + // iterations help, like if we remove a set that turns something + // into a read-only-to-write. if (onlyReadOnlyToWrite) { more = true; } @@ -462,7 +484,7 @@ struct SimplifyGlobals : public Pass { // then see that since the global has no writes, it is a constant, which // will lead to removal of gets, and after removing them, the global itself // will be removed as well. - GlobalSetRemover(&unnecessaryGlobals, optimize).run(runner, module); + GlobalSetRemover(&globalsNotNeedingSets, optimize).run(runner, module); return more; } |