diff options
author | Alon Zakai <azakai@google.com> | 2021-03-24 08:03:57 -0700 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-03-24 08:03:57 -0700 |
commit | 683c31381f5798016f683a6b42e2a8fad0f871cb (patch) | |
tree | aa93d42c319410d76d0a339363425ec7d7120dda /src | |
parent | 182a1fbc41becdfdfbfcf02a2d67798fb087e7c1 (diff) | |
download | binaryen-683c31381f5798016f683a6b42e2a8fad0f871cb.tar.gz binaryen-683c31381f5798016f683a6b42e2a8fad0f871cb.tar.bz2 binaryen-683c31381f5798016f683a6b42e2a8fad0f871cb.zip |
[Wasm GC] Optimize br_on_* (#3719)
The type may prove the value is not null, and may also show it to be
of the type we are casting to. In that case, we can simplify things.
Diffstat (limited to 'src')
-rw-r--r-- | src/passes/RemoveUnusedBrs.cpp | 57 |
1 files changed, 55 insertions, 2 deletions
diff --git a/src/passes/RemoveUnusedBrs.cpp b/src/passes/RemoveUnusedBrs.cpp index eaf681a08..3bf56838e 100644 --- a/src/passes/RemoveUnusedBrs.cpp +++ b/src/passes/RemoveUnusedBrs.cpp @@ -380,6 +380,60 @@ struct RemoveUnusedBrs : public WalkerPass<PostWalker<RemoveUnusedBrs>> { // later down, see visitLocalSet. } + void visitBrOn(BrOn* curr) { + // Ignore unreachable BrOns which we cannot improve anyhow. + if (curr->type == Type::unreachable) { + return; + } + + // If the type provides enough information we may be able to know if this + // br is taken or not. If so, the br_on* may be unneeded. First, check for a + // possible null which would prevent such an optimization. + auto refType = curr->ref->type; + if (refType.isNullable()) { + return; + } + + // Nulls are not possible, so specialization may be achievable, either + // removing the br_on* entirely or replacing it with a br. + auto replaceWithBr = [&]() { + replaceCurrent(Builder(*getModule()).makeBreak(curr->name, curr->ref)); + anotherCycle = true; + }; + + switch (curr->op) { + case BrOnNull: { + // This cannot be null, so the br is never taken, and the non-null value + // flows through. + replaceCurrent(curr->ref); + anotherCycle = true; + break; + } + case BrOnCast: { + // Casts can only be done at runtime, using RTTs. + break; + } + case BrOnFunc: { + if (refType.isFunction()) { + replaceWithBr(); + } + break; + } + case BrOnData: { + if (refType.isData()) { + replaceWithBr(); + } + break; + } + case BrOnI31: { + if (refType.getHeapType() == HeapType::i31) { + replaceWithBr(); + } + break; + } + } + } + // override scan to add a pre and a post check task to all nodes static void scan(RemoveUnusedBrs* self, Expression** currp) { self->pushTask(visitAny, currp); @@ -657,12 +711,11 @@ struct RemoveUnusedBrs : public WalkerPass<PostWalker<RemoveUnusedBrs>> { if (!flow->value) { // return => nop ExpressionManipulator::nop(flow); - anotherCycle = true; } else { // return with value => value *flows[i] = flow->value; - anotherCycle = true; } + anotherCycle = true; } flows.clear(); // optimize loops (we don't do it while tracking flows, as they can |