summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorAlon Zakai <azakai@google.com>2021-03-24 08:03:57 -0700
committerGitHub <noreply@github.com>2021-03-24 08:03:57 -0700
commit683c31381f5798016f683a6b42e2a8fad0f871cb (patch)
treeaa93d42c319410d76d0a339363425ec7d7120dda /src
parent182a1fbc41becdfdfbfcf02a2d67798fb087e7c1 (diff)
downloadbinaryen-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.cpp57
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