summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorAlon Zakai <azakai@google.com>2022-09-19 13:16:18 -0700
committerGitHub <noreply@github.com>2022-09-19 20:16:18 +0000
commitbd76598f8525e15d6649335e1308a27284c4b0ae (patch)
treed6916ece5f70f3e1058b2e19178b1db1c853f5d0 /src
parentb65d325ac6ec9e5d92e41f1479ef6157ccca64c7 (diff)
downloadbinaryen-bd76598f8525e15d6649335e1308a27284c4b0ae.tar.gz
binaryen-bd76598f8525e15d6649335e1308a27284c4b0ae.tar.bz2
binaryen-bd76598f8525e15d6649335e1308a27284c4b0ae.zip
Vacuum: Ignore effects at the entire function scope when possible (#5053)
Recently we added logic to ignore effects that don't "escape" past the function call. That is, e.g. local.set only affects the current function scope, and once the call stack is unwound it no longer matters as an effect. This moves that logic to a shared place, and uses it in the core Vacuum logic. The new constructor in EffectAnalyzer receives a function and then scans it as a whole. This works just like e.g. scanning a Block as a whole (if we see a break in the block, that has an effect only inside it, and the Block + children doesn't have a branch effect). Various tests are updated so they don't optimize away trivially, by adding new return values for them.
Diffstat (limited to 'src')
-rw-r--r--src/ir/effects.h36
-rw-r--r--src/passes/GlobalEffects.cpp13
-rw-r--r--src/passes/Vacuum.cpp2
3 files changed, 32 insertions, 19 deletions
diff --git a/src/ir/effects.h b/src/ir/effects.h
index 4b8c9a921..c2ba794d9 100644
--- a/src/ir/effects.h
+++ b/src/ir/effects.h
@@ -27,16 +27,22 @@ namespace wasm {
class EffectAnalyzer {
public:
- EffectAnalyzer(const PassOptions& passOptions,
- Module& module,
- Expression* ast = nullptr)
+ EffectAnalyzer(const PassOptions& passOptions, Module& module)
: ignoreImplicitTraps(passOptions.ignoreImplicitTraps),
trapsNeverHappen(passOptions.trapsNeverHappen),
funcEffectsMap(passOptions.funcEffectsMap), module(module),
- features(module.features) {
- if (ast) {
- walk(ast);
- }
+ features(module.features) {}
+
+ EffectAnalyzer(const PassOptions& passOptions,
+ Module& module,
+ Expression* ast)
+ : EffectAnalyzer(passOptions, module) {
+ walk(ast);
+ }
+
+ EffectAnalyzer(const PassOptions& passOptions, Module& module, Function* func)
+ : EffectAnalyzer(passOptions, module) {
+ walk(func);
}
bool ignoreImplicitTraps;
@@ -59,6 +65,22 @@ public:
post();
}
+ // Walk an entire function body. This will ignore effects that are not
+ // noticeable from the perspective of the caller, that is, effects that are
+ // only noticeable during the call, but "vanish" when the call stack is
+ // unwound.
+ void walk(Function* func) {
+ walk(func->body);
+
+ // We can ignore branching out of the function body - this can only be
+ // a return, and that is only noticeable in the function, not outside.
+ branchesOut = false;
+
+ // When the function exits, changes to locals cannot be noticed any more.
+ localsWritten.clear();
+ localsRead.clear();
+ }
+
// Core effect tracking
// Definitely branches out of this expression, or does a return, etc.
diff --git a/src/passes/GlobalEffects.cpp b/src/passes/GlobalEffects.cpp
index 1dd91e5d7..2f816a0bd 100644
--- a/src/passes/GlobalEffects.cpp
+++ b/src/passes/GlobalEffects.cpp
@@ -49,8 +49,8 @@ struct GenerateGlobalEffects : public Pass {
}
// Gather the effects.
- auto effects = std::make_unique<EffectAnalyzer>(
- runner->options, *module, func->body);
+ auto effects =
+ std::make_unique<EffectAnalyzer>(runner->options, *module, func);
// If the body has a call, give up - that means we can't infer a more
// specific set of effects than the pessimistic case of just assuming
@@ -60,15 +60,6 @@ struct GenerateGlobalEffects : public Pass {
return;
}
- // We can ignore branching out of the function body - this can only be
- // a return, and that is only noticeable in the function, not outside.
- effects->branchesOut = false;
-
- // Ignore local effects - when the function exits, those become
- // unnoticeable anyhow.
- effects->localsWritten.clear();
- effects->localsRead.clear();
-
// Save the useful effects we found.
storedEffects = std::move(effects);
});
diff --git a/src/passes/Vacuum.cpp b/src/passes/Vacuum.cpp
index 208e973da..a29c74a89 100644
--- a/src/passes/Vacuum.cpp
+++ b/src/passes/Vacuum.cpp
@@ -390,7 +390,7 @@ struct Vacuum : public WalkerPass<ExpressionStackWalker<Vacuum>> {
ExpressionManipulator::nop(curr->body);
}
if (curr->getResults() == Type::none &&
- !EffectAnalyzer(getPassOptions(), *getModule(), curr->body)
+ !EffectAnalyzer(getPassOptions(), *getModule(), curr)
.hasUnremovableSideEffects()) {
ExpressionManipulator::nop(curr->body);
}