2525// * Apply the constant values of previous global.sets, in a linear
2626// execution trace.
2727// * Remove writes to globals that are never read from.
28+ // * Remove writes to globals that are always assigned the same value.
2829// * Remove writes to globals that are only read from in order to write (see
2930// below, "readOnlyToWrite").
3031//
@@ -60,6 +61,9 @@ struct GlobalInfo {
6061 std::atomic<Index> written{0 };
6162 std::atomic<Index> read{0 };
6263
64+ // Whether the global is written a value different from its initial value.
65+ std::atomic<bool > nonInitWritten{false };
66+
6367 // How many times the global is "read, but only to write", that is, is used in
6468 // this pattern:
6569 //
@@ -93,7 +97,20 @@ struct GlobalUseScanner : public WalkerPass<PostWalker<GlobalUseScanner>> {
9397
9498 GlobalUseScanner* create () override { return new GlobalUseScanner (infos); }
9599
96- void visitGlobalSet (GlobalSet* curr) { (*infos)[curr->name ].written ++; }
100+ void visitGlobalSet (GlobalSet* curr) {
101+ (*infos)[curr->name ].written ++;
102+
103+ // Check if there is a write of a value that may differ from the initial
104+ // one. If there is anything but identical constants in both the initial
105+ // value and the written value then we must assume that.
106+ auto * global = getModule ()->getGlobal (curr->name );
107+ if (global->imported () || !Properties::isConstantExpression (curr->value ) ||
108+ !Properties::isConstantExpression (global->init ) ||
109+ Properties::getLiterals (curr->value ) !=
110+ Properties::getLiterals (global->init )) {
111+ (*infos)[curr->name ].nonInitWritten = true ;
112+ }
113+ }
97114
98115 void visitGlobalGet (GlobalGet* curr) { (*infos)[curr->name ].read ++; }
99116
@@ -394,10 +411,11 @@ struct SimplifyGlobals : public Pass {
394411 bool removeUnneededWrites () {
395412 bool more = false ;
396413
397- // Globals that are not exports and not read from are unnecessary (even if
398- // they are written to). Likewise, globals that are only read from in order
399- // to write to themselves are unnecessary. First, find such globals.
400- NameSet unnecessaryGlobals;
414+ // Globals that are not exports and not read from do not need their sets.
415+ // Likewise, globals that only write their initial value later also do not
416+ // need those writes. And, globals that are only read from in order to write
417+ // to themselves as well. First, find such globals.
418+ NameSet globalsNotNeedingSets;
401419 for (auto & global : module ->globals ) {
402420 auto & info = map[global->name ];
403421
@@ -431,15 +449,15 @@ struct SimplifyGlobals : public Pass {
431449 // our logic is wrong somewhere.
432450 assert (info.written >= info.readOnlyToWrite );
433451
434- if (!info.read || onlyReadOnlyToWrite) {
435- unnecessaryGlobals .insert (global->name );
452+ if (!info.read || !info. nonInitWritten || onlyReadOnlyToWrite) {
453+ globalsNotNeedingSets .insert (global->name );
436454
437455 // We can now mark this global as immutable, and un-written, since we
438- // are about to remove all the operations on it.
456+ // are about to remove all the sets on it.
439457 global->mutable_ = false ;
440458 info.written = 0 ;
441459
442- // Nested old -read-to-write expressions require another full iteration
460+ // Nested only -read-to-write expressions require another full iteration
443461 // to optimize, as we have:
444462 //
445463 // if (a) {
@@ -452,6 +470,10 @@ struct SimplifyGlobals : public Pass {
452470 // The first iteration can only optimize b, as the outer if's body has
453471 // more effects than we understand. After finishing the first iteration,
454472 // b will no longer exist, removing those effects.
473+ //
474+ // TODO: In principle other situations exist as well where more
475+ // iterations help, like if we remove a set that turns something
476+ // into a read-only-to-write.
455477 if (onlyReadOnlyToWrite) {
456478 more = true ;
457479 }
@@ -462,7 +484,7 @@ struct SimplifyGlobals : public Pass {
462484 // then see that since the global has no writes, it is a constant, which
463485 // will lead to removal of gets, and after removing them, the global itself
464486 // will be removed as well.
465- GlobalSetRemover (&unnecessaryGlobals , optimize).run (runner, module );
487+ GlobalSetRemover (&globalsNotNeedingSets , optimize).run (runner, module );
466488
467489 return more;
468490 }
0 commit comments