diff options
author | Alon Zakai <azakai@google.com> | 2022-09-19 13:16:18 -0700 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-09-19 20:16:18 +0000 |
commit | bd76598f8525e15d6649335e1308a27284c4b0ae (patch) | |
tree | d6916ece5f70f3e1058b2e19178b1db1c853f5d0 /src | |
parent | b65d325ac6ec9e5d92e41f1479ef6157ccca64c7 (diff) | |
download | binaryen-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.h | 36 | ||||
-rw-r--r-- | src/passes/GlobalEffects.cpp | 13 | ||||
-rw-r--r-- | src/passes/Vacuum.cpp | 2 |
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); } |