diff options
author | Alon Zakai <azakai@google.com> | 2023-07-05 13:12:26 -0700 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-07-05 13:12:26 -0700 |
commit | f963083cfb7ca42d76928f52889faf4aeaec54cf (patch) | |
tree | 3076145eb9281c320cd0d3fc526482c349195b75 /src | |
parent | ef7f98e50662374b17d88c149a2ba1c11f918e5c (diff) | |
download | binaryen-f963083cfb7ca42d76928f52889faf4aeaec54cf.tar.gz binaryen-f963083cfb7ca42d76928f52889faf4aeaec54cf.tar.bz2 binaryen-f963083cfb7ca42d76928f52889faf4aeaec54cf.zip |
OptimizeInstructions: Loop on fallthrough values in RefTest (#5797)
This parallels the code in RefCast. Previously we only looked at the type reaching us, but
intermediate fallthrough values can let us optimize too. In particular, we were not
optimizing (ref.test (local.tee ..)) if the tee was to a less-refined type.
Diffstat (limited to 'src')
-rw-r--r-- | src/passes/OptimizeInstructions.cpp | 74 |
1 files changed, 43 insertions, 31 deletions
diff --git a/src/passes/OptimizeInstructions.cpp b/src/passes/OptimizeInstructions.cpp index af7369994..44078545b 100644 --- a/src/passes/OptimizeInstructions.cpp +++ b/src/passes/OptimizeInstructions.cpp @@ -2178,37 +2178,49 @@ struct OptimizeInstructions Builder builder(*getModule()); - // Parallel to the code in visitRefCast - switch (GCTypeUtils::evaluateCastCheck(curr->ref->type, curr->castType)) { - case GCTypeUtils::Unknown: - break; - case GCTypeUtils::Success: - replaceCurrent(builder.makeBlock( - {builder.makeDrop(curr->ref), builder.makeConst(int32_t(1))})); - break; - case GCTypeUtils::Unreachable: - // Make sure to emit a block with the same type as us, to avoid other - // code in this pass needing to handle unexpected unreachable code - // (which is only properly propagated at the end of this pass when we - // refinalize). - replaceCurrent(builder.makeBlock( - {builder.makeDrop(curr->ref), builder.makeUnreachable()}, Type::i32)); - break; - case GCTypeUtils::Failure: - replaceCurrent(builder.makeSequence(builder.makeDrop(curr->ref), - builder.makeConst(int32_t(0)))); - break; - case GCTypeUtils::SuccessOnlyIfNull: - replaceCurrent(builder.makeRefIsNull(curr->ref)); - break; - case GCTypeUtils::SuccessOnlyIfNonNull: - // This adds an EqZ, but code size does not regress since ref.test also - // encodes a type, and ref.is_null does not. The EqZ may also add some - // work, but a cast is likely more expensive than a null check + a fast - // int operation. - replaceCurrent( - builder.makeUnary(EqZInt32, builder.makeRefIsNull(curr->ref))); - break; + // Parallel to the code in visitRefCast: we look not just at the final type + // we are given, but at fallthrough values as well. + auto* ref = curr->ref; + while (1) { + switch (GCTypeUtils::evaluateCastCheck(ref->type, curr->castType)) { + case GCTypeUtils::Unknown: + break; + case GCTypeUtils::Success: + replaceCurrent(builder.makeBlock( + {builder.makeDrop(curr->ref), builder.makeConst(int32_t(1))})); + return; + case GCTypeUtils::Unreachable: + // Make sure to emit a block with the same type as us, to avoid other + // code in this pass needing to handle unexpected unreachable code + // (which is only properly propagated at the end of this pass when we + // refinalize). + replaceCurrent(builder.makeBlock( + {builder.makeDrop(curr->ref), builder.makeUnreachable()}, + Type::i32)); + return; + case GCTypeUtils::Failure: + replaceCurrent(builder.makeSequence(builder.makeDrop(curr->ref), + builder.makeConst(int32_t(0)))); + return; + case GCTypeUtils::SuccessOnlyIfNull: + replaceCurrent(builder.makeRefIsNull(curr->ref)); + return; + case GCTypeUtils::SuccessOnlyIfNonNull: + // This adds an EqZ, but code size does not regress since ref.test + // also encodes a type, and ref.is_null does not. The EqZ may also add + // some work, but a cast is likely more expensive than a null check + + // a fast int operation. + replaceCurrent( + builder.makeUnary(EqZInt32, builder.makeRefIsNull(curr->ref))); + return; + } + + auto* fallthrough = Properties::getImmediateFallthrough( + ref, getPassOptions(), *getModule()); + if (fallthrough == ref) { + return; + } + ref = fallthrough; } } |