diff options
author | Alon Zakai <azakai@google.com> | 2022-09-26 13:49:50 -0700 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-09-26 20:49:50 +0000 |
commit | b23b47d54a2fb02b048e7eb8de8043358599ec8b (patch) | |
tree | a0df6c52cae239318893b069172674145903598f /src/passes/GUFA.cpp | |
parent | b40fa4a885f219d8f317f125880aa0ee9f46b62f (diff) | |
download | binaryen-b23b47d54a2fb02b048e7eb8de8043358599ec8b.tar.gz binaryen-b23b47d54a2fb02b048e7eb8de8043358599ec8b.tar.bz2 binaryen-b23b47d54a2fb02b048e7eb8de8043358599ec8b.zip |
[GUFA] Infer a RefEq value of 0 when possible (#5081)
If the PossibleContents for the two sides have no possible intersection then the
result must be 0.
Diffstat (limited to 'src/passes/GUFA.cpp')
-rw-r--r-- | src/passes/GUFA.cpp | 53 |
1 files changed, 52 insertions, 1 deletions
diff --git a/src/passes/GUFA.cpp b/src/passes/GUFA.cpp index 1467b1312..53693420e 100644 --- a/src/passes/GUFA.cpp +++ b/src/passes/GUFA.cpp @@ -69,6 +69,34 @@ struct GUFAOptimizer bool optimized = false; + // As we optimize, we replace expressions and create new ones. For new ones + // we can infer their contents based on what they replaced, e.g., if we + // replaced a local.get with a const, then the PossibleContents of the const + // are the same as the local.get (in this simple example, we could also just + // infer them from the const itself, of course). Rather than update the + // ContentOracle with new contents, which is a shared object among threads, + // each function-parallel worker stores a map of new things it created to the + // contents for them. + std::unordered_map<Expression*, PossibleContents> newContents; + + Expression* replaceCurrent(Expression* rep) { + newContents[rep] = oracle.getContents(getCurrent()); + + return WalkerPass< + PostWalker<GUFAOptimizer, + UnifiedExpressionVisitor<GUFAOptimizer>>>::replaceCurrent(rep); + } + + const PossibleContents getContents(Expression* curr) { + // If this is something we added ourselves, use that; otherwise the info is + // in the oracle. + if (auto iter = newContents.find(curr); iter != newContents.end()) { + return iter->second; + } + + return oracle.getContents(curr); + } + void visitExpression(Expression* curr) { // Skip things we can't improve in any way. auto type = curr->type; @@ -91,7 +119,7 @@ struct GUFAOptimizer // Ok, this is an interesting location that we might optimize. See what the // oracle says is possible there. - auto contents = oracle.getContents(ExpressionLocation{curr, 0}); + auto contents = getContents(curr); auto& options = getPassOptions(); auto& wasm = *getModule(); @@ -182,6 +210,29 @@ struct GUFAOptimizer } } + void visitRefEq(RefEq* curr) { + if (curr->type == Type::unreachable) { + // Leave this for DCE. + return; + } + + auto leftContents = getContents(curr->left); + auto rightContents = getContents(curr->right); + + if (!PossibleContents::haveIntersection(leftContents, rightContents)) { + // The contents prove the two sides cannot contain the same reference, so + // we infer 0. + // + // Note that this is fine even if one of the sides is None. In that case, + // no value is possible there, and the intersection is empty, so we will + // get here and emit a 0. That 0 will never be reached as the None child + // will be turned into an unreachable, so it does not cause any problem. + auto* result = Builder(*getModule()).makeConst(Literal(int32_t(0))); + replaceCurrent(getDroppedChildrenAndAppend( + curr, *getModule(), getPassOptions(), result)); + } + } + // TODO: If an instruction would trap on null, like struct.get, we could // remove it here if it has no possible contents and if we are in // traps-never-happen mode (that is, we'd have proven it can only trap, |