diff options
author | Alon Zakai <azakai@google.com> | 2021-12-08 11:22:03 -0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-12-08 11:22:03 -0800 |
commit | f7be757a71e5562afad898992574681d50a67dbf (patch) | |
tree | 6f65e6caded06351e5172cf3f22f276a232fb2d0 /src | |
parent | ba01236b26d7ea97f165af310fbb6fb99be6239a (diff) | |
download | binaryen-f7be757a71e5562afad898992574681d50a67dbf.tar.gz binaryen-f7be757a71e5562afad898992574681d50a67dbf.tar.bz2 binaryen-f7be757a71e5562afad898992574681d50a67dbf.zip |
SimplifyGlobals: Handle nested read-only-to-write patterns (#4365)
The general pattern is
if (!global) { global = 1 }
This PR generalizes that to handle nested appearances,
if ({
if (!global) { global = 1 }
!global
}) {
global = 1
}
With this I can finally see no more "once" global operations on the hottest
function in the currently slowest j2wasm benchmark ("filter").
Also added a failing testcase for something we do not handle yet.
Diffstat (limited to 'src')
-rw-r--r-- | src/passes/SimplifyGlobals.cpp | 26 |
1 files changed, 21 insertions, 5 deletions
diff --git a/src/passes/SimplifyGlobals.cpp b/src/passes/SimplifyGlobals.cpp index 9730400d6..daaa82447 100644 --- a/src/passes/SimplifyGlobals.cpp +++ b/src/passes/SimplifyGlobals.cpp @@ -193,12 +193,17 @@ struct GlobalUseScanner : public WalkerPass<PostWalker<GlobalUseScanner>> { struct FlowScanner : public ExpressionStackWalker<FlowScanner, UnifiedExpressionVisitor<FlowScanner>> { + GlobalUseScanner& globalUseScanner; Name writtenGlobal; PassOptions& passOptions; Module& wasm; - FlowScanner(Name writtenGlobal, PassOptions& passOptions, Module& wasm) - : writtenGlobal(writtenGlobal), passOptions(passOptions), wasm(wasm) {} + FlowScanner(GlobalUseScanner& globalUseScanner, + Name writtenGlobal, + PassOptions& passOptions, + Module& wasm) + : globalUseScanner(globalUseScanner), writtenGlobal(writtenGlobal), + passOptions(passOptions), wasm(wasm) {} bool ok = true; @@ -208,7 +213,7 @@ struct GlobalUseScanner : public WalkerPass<PostWalker<GlobalUseScanner>> { // We found the get of the global. Check where its value flows to, // and how it is used there. assert(expressionStack.back() == get); - for (Index i = 0; i < expressionStack.size() - 1; i++) { + for (int i = int(expressionStack.size()) - 2; i >= 0; i--) { // Consider one pair of parent->child, and check if the parent // causes any problems when the child's value reaches it. auto* parent = expressionStack[i]; @@ -225,7 +230,18 @@ struct GlobalUseScanner : public WalkerPass<PostWalker<GlobalUseScanner>> { if (auto* iff = parent->dynCast<If>()) { if (iff->condition == child) { // The child is used to decide what code to run, which is - // dangerous. + // dangerous: check what effects it causes. If it is a nested + // appearance of the pattern, that is one case that we know is + // actually safe. + if (!iff->ifFalse && + globalUseScanner.readsGlobalOnlyToWriteIt( + iff->condition, iff->ifTrue) == writtenGlobal) { + // This is safe, and we can stop here: the value does not + // flow any further. + break; + } + + // Otherwise, we found a problem, and can stop. ok = false; break; } @@ -236,7 +252,7 @@ struct GlobalUseScanner : public WalkerPass<PostWalker<GlobalUseScanner>> { } }; - FlowScanner scanner(writtenGlobal, getPassOptions(), *getModule()); + FlowScanner scanner(*this, writtenGlobal, getPassOptions(), *getModule()); scanner.walk(condition); return scanner.ok ? writtenGlobal : Name(); } |