diff options
author | Alon Zakai <azakai@google.com> | 2022-09-27 14:11:08 -0700 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-09-27 14:11:08 -0700 |
commit | cd86449cd5f5b08f41e47c929bc47cdedce05fa2 (patch) | |
tree | 19fcbad09abe415a91cc2011ed4cbe45e82b3b57 /src | |
parent | eb42407e6bc027a40cc569ad0c1b915c4f285b60 (diff) | |
download | binaryen-cd86449cd5f5b08f41e47c929bc47cdedce05fa2.tar.gz binaryen-cd86449cd5f5b08f41e47c929bc47cdedce05fa2.tar.bz2 binaryen-cd86449cd5f5b08f41e47c929bc47cdedce05fa2.zip |
[GUFA] Simplify RefTest logic [NFC] (#5084)
Move the logic to the GUFA pass.
Diffstat (limited to 'src')
-rw-r--r-- | src/ir/possible-contents.cpp | 41 | ||||
-rw-r--r-- | src/passes/GUFA.cpp | 29 |
2 files changed, 30 insertions, 40 deletions
diff --git a/src/ir/possible-contents.cpp b/src/ir/possible-contents.cpp index fd186a74f..167890d63 100644 --- a/src/ir/possible-contents.cpp +++ b/src/ir/possible-contents.cpp @@ -471,9 +471,7 @@ struct InfoCollector void visitRefCast(RefCast* curr) { addChildParentLink(curr->ref, curr); } - void visitRefTest(RefTest* curr) { - addChildParentLink(curr->ref, curr); - } + void visitRefTest(RefTest* curr) { addRoot(curr); } void visitBrOn(BrOn* curr) { // TODO: optimize when possible handleBreakValue(curr); @@ -1161,13 +1159,6 @@ private: // values to flow through it. void flowRefCast(const PossibleContents& contents, RefCast* cast); - // The possible contents may allow us to infer an outcome in various - // instructions. If the expression has a single child, that is what is - // updated by the new |contents| (which we pass in to avoid doing an extra - // lookup); if there is more than one child, then to keep the code simple we - // expect the function to look up the children's effects manually. - void flowRefTest(const PossibleContents& contents, RefTest* test); - // We will need subtypes during the flow, so compute them once ahead of time. std::unique_ptr<SubTypes> subTypes; @@ -1502,9 +1493,6 @@ void Flower::flowAfterUpdate(LocationIndex locationIndex) { } else if (auto* cast = parent->dynCast<RefCast>()) { assert(cast->ref == child); flowRefCast(contents, cast); - } else if (auto* test = parent->dynCast<RefTest>()) { - assert(test->ref == child); - flowRefTest(contents, test); } else { // TODO: ref.test and all other casts can be optimized (see the cast // helper code used in OptimizeInstructions and RemoveUnusedBrs) @@ -1766,33 +1754,6 @@ void Flower::flowRefCast(const PossibleContents& contents, RefCast* cast) { } } -void Flower::flowRefTest(const PossibleContents& contents, RefTest* test) { - // TODO move to gufa pass; this must happen at the end - PossibleContents filtered; - if (contents.isMany()) { - // Just pass the Many through. - filtered = contents; - } else { - // RefTest returns 1 iff the input is not null and is also a subtype. - bool isSubType = - HeapType::isSubType(contents.getType().getHeapType(), test->intendedType); - bool mayBeNull = contents.getType().isNullable(); - if (!isSubType) { - filtered = PossibleContents::literal(Literal(int32_t(0))); - } else if (!mayBeNull) { - filtered = PossibleContents::literal(Literal(int32_t(1))); - } else { - filtered = PossibleContents::many(); - } - } -#if defined(POSSIBLE_CONTENTS_DEBUG) && POSSIBLE_CONTENTS_DEBUG >= 2 - std::cout << " ref.test passing through\n"; - filtered.dump(std::cout); - std::cout << '\n'; -#endif - updateContents(ExpressionLocation{test, 0}, filtered); -} - #if defined(POSSIBLE_CONTENTS_DEBUG) && POSSIBLE_CONTENTS_DEBUG >= 2 void Flower::dump(Location location) { if (auto* loc = std::get_if<ExpressionLocation>(&location)) { diff --git a/src/passes/GUFA.cpp b/src/passes/GUFA.cpp index 53693420e..1f620f8db 100644 --- a/src/passes/GUFA.cpp +++ b/src/passes/GUFA.cpp @@ -233,6 +233,35 @@ struct GUFAOptimizer } } + void visitRefTest(RefTest* curr) { + if (curr->type == Type::unreachable) { + // Leave this for DCE. + return; + } + + auto refContents = getContents(curr->ref); + auto refType = refContents.getType(); + if (refType.isRef()) { + // We have some knowledge of the type here. Use that to optimize: RefTest + // returns 1 iff the input is not null and is also a subtype. + bool isSubType = + HeapType::isSubType(refType.getHeapType(), curr->intendedType); + bool mayBeNull = refType.isNullable(); + + auto optimize = [&](int32_t result) { + auto* last = Builder(*getModule()).makeConst(Literal(int32_t(result))); + replaceCurrent(getDroppedChildrenAndAppend( + curr, *getModule(), getPassOptions(), last)); + }; + + if (!isSubType) { + optimize(0); + } else if (!mayBeNull) { + optimize(1); + } + } + } + // 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, |