summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorAlon Zakai <azakai@google.com>2022-09-27 14:11:08 -0700
committerGitHub <noreply@github.com>2022-09-27 14:11:08 -0700
commitcd86449cd5f5b08f41e47c929bc47cdedce05fa2 (patch)
tree19fcbad09abe415a91cc2011ed4cbe45e82b3b57 /src
parenteb42407e6bc027a40cc569ad0c1b915c4f285b60 (diff)
downloadbinaryen-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.cpp41
-rw-r--r--src/passes/GUFA.cpp29
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,