summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorAlon Zakai <azakai@google.com>2024-07-08 14:18:31 -0700
committerGitHub <noreply@github.com>2024-07-08 14:18:31 -0700
commite93babcd71a89bd8c8e170d11652ca7375ef01f3 (patch)
treeb1c9bbcd1a13db9051838e9f13ab85292c5c439b /src
parent4179603f8c21f5676cf4826ec4e41a1513c41540 (diff)
downloadbinaryen-e93babcd71a89bd8c8e170d11652ca7375ef01f3.tar.gz
binaryen-e93babcd71a89bd8c8e170d11652ca7375ef01f3.tar.bz2
binaryen-e93babcd71a89bd8c8e170d11652ca7375ef01f3.zip
StackIR: Optimize away a drop before an unreachable (#6719)
Anything else right before an unreachable is removed by the main DCE pass anyhow, but because of the structured form of BinaryenIR we can't remove a drop. That is, this is the difference between (i32.eqz (i32.const 42) (unreachable) ) and (drop (call $foo) ) (unreachable) In both cases the unreachable is preceded by something we don't need, but in the latter case it must remain in BinaryenIR for validation. To optimize this, add a rule in StackIR. Fixes #6715
Diffstat (limited to 'src')
-rw-r--r--src/wasm/wasm-stack-opts.cpp39
1 files changed, 38 insertions, 1 deletions
diff --git a/src/wasm/wasm-stack-opts.cpp b/src/wasm/wasm-stack-opts.cpp
index ae9fee394..5e18cf26f 100644
--- a/src/wasm/wasm-stack-opts.cpp
+++ b/src/wasm/wasm-stack-opts.cpp
@@ -44,8 +44,9 @@ void StackIROptimizer::run() {
vacuum();
}
-// Remove unreachable code.
void StackIROptimizer::dce() {
+ // Remove code after an unreachable instruction: anything after it, up to the
+ // next control flow barrier, can simply be removed.
bool inUnreachableCode = false;
for (Index i = 0; i < insts.size(); i++) {
auto* inst = insts[i];
@@ -64,6 +65,42 @@ void StackIROptimizer::dce() {
inUnreachableCode = true;
}
}
+
+ // Remove code before an Unreachable. Consider this:
+ //
+ // (drop
+ // ..
+ // )
+ // (unreachable)
+ //
+ // The drop is not needed, as the unreachable puts the stack in the
+ // polymorphic state anyhow. Note that we don't need to optimize anything
+ // other than a drop here, as in general the Binaryen IR DCE pass will handle
+ // everything else. A drop followed by an unreachable is the only thing that
+ // pass cannot handle, as the structured form of Binaryen IR does not allow
+ // removing such a drop, and so we can only do it here in StackIR.
+ //
+ // TODO: We can look even further back, say if there is another drop of
+ // something before, then we can remove that drop as well. To do that
+ // we'd need to inspect the stack going backwards.
+ for (Index i = 1; i < insts.size(); i++) {
+ auto* inst = insts[i];
+ if (!inst || inst->op != StackInst::Basic ||
+ !inst->origin->is<Unreachable>()) {
+ continue;
+ }
+
+ // Look back past nulls.
+ Index j = i - 1;
+ while (j > 0 && !insts[j]) {
+ j--;
+ }
+
+ auto*& prev = insts[j];
+ if (prev && prev->op == StackInst::Basic && prev->origin->is<Drop>()) {
+ prev = nullptr;
+ }
+ }
}
// Remove obviously-unneeded code.