diff options
author | Thomas Lively <tlively@google.com> | 2023-01-11 16:29:09 -0600 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-01-11 22:29:09 +0000 |
commit | 4663321f956c5a4c0ceed2e7be7a81be57e8f921 (patch) | |
tree | 65c5ffc27a2813bdfe2ce5f9ecb323368bf920dc /src | |
parent | bbc1cad759aa6a3eb3626adbca51a09fd569d772 (diff) | |
download | binaryen-4663321f956c5a4c0ceed2e7be7a81be57e8f921.tar.gz binaryen-4663321f956c5a4c0ceed2e7be7a81be57e8f921.tar.bz2 binaryen-4663321f956c5a4c0ceed2e7be7a81be57e8f921.zip |
[NFC] Remove GCTypeUtils::evaluateKindCheck (#5421)
Since we refactored all the old kind-checking instructions to be represented as
general cast instructions, `GCTypeUtils::evaluateKindCheck` had become a
vestigial wrapper around `GCTypeUtils::evaluateCastCheck` that was only used in
RemoveUnusedBrs. Remove `evaluateKindCheck` and use `evaluateCastCheck` in
RemoveUnusedBrs without changing any functionality. A future PR may use the
extra information from `evaluateCastCheck` to further optimize branching casts.
Diffstat (limited to 'src')
-rw-r--r-- | src/ir/gc-type-utils.h | 77 | ||||
-rw-r--r-- | src/passes/RemoveUnusedBrs.cpp | 26 |
2 files changed, 33 insertions, 70 deletions
diff --git a/src/ir/gc-type-utils.h b/src/ir/gc-type-utils.h index 318b1b3a3..6dbb3157a 100644 --- a/src/ir/gc-type-utils.h +++ b/src/ir/gc-type-utils.h @@ -39,6 +39,22 @@ enum EvaluationResult { SuccessOnlyIfNonNull, }; +inline EvaluationResult flipEvaluationResult(EvaluationResult result) { + switch (result) { + case Unknown: + return Unknown; + case Success: + return Failure; + case Failure: + return Success; + case SuccessOnlyIfNull: + return SuccessOnlyIfNonNull; + case SuccessOnlyIfNonNull: + return SuccessOnlyIfNull; + } + WASM_UNREACHABLE("unexpected result"); +} + // Given the type of a reference and a type to attempt to cast it to, return // what we know about the result. inline EvaluationResult evaluateCastCheck(Type refType, Type castType) { @@ -85,67 +101,6 @@ inline EvaluationResult evaluateCastCheck(Type refType, Type castType) { return Unknown; } -// Given an instruction that checks if the child reference is of a certain kind -// (like br_on_func checks if it is a function), see if type info lets us -// determine that at compile time. -// This ignores nullability - it just checks the kind. -inline EvaluationResult evaluateKindCheck(Expression* curr) { - Kind expected; - Expression* child; - - // Some operations flip the condition. - bool flip = false; - - if (auto* br = curr->dynCast<BrOn>()) { - switch (br->op) { - // We don't check nullability here. - case BrOnNull: - case BrOnNonNull: - return Unknown; - case BrOnCastFail: - flip = true; - [[fallthrough]]; - case BrOnCast: { - auto result = - GCTypeUtils::evaluateCastCheck(br->ref->type, br->castType); - if (result == Success) { - return flip ? Failure : Success; - } else if (result == Failure) { - return flip ? Success : Failure; - } - return Unknown; - } - default: - WASM_UNREACHABLE("unhandled BrOn"); - } - child = br->ref; - } else { - WASM_UNREACHABLE("invalid input to evaluateKindCheck"); - } - - auto childType = child->type; - - Kind actual; - - if (childType == Type::unreachable) { - return Unknown; - } else if (childType.isFunction()) { - actual = Func; - } else if (childType.isData()) { - actual = Data; - } else if (childType.getHeapType() == HeapType::i31) { - actual = I31; - } else { - return Unknown; - } - - auto success = actual == expected; - if (flip) { - success = !success; - } - return success ? Success : Failure; -} - } // namespace wasm::GCTypeUtils #endif // wasm_ir_gc_type_utils_h diff --git a/src/passes/RemoveUnusedBrs.cpp b/src/passes/RemoveUnusedBrs.cpp index 4edfb8b5e..a7011abe0 100644 --- a/src/passes/RemoveUnusedBrs.cpp +++ b/src/passes/RemoveUnusedBrs.cpp @@ -712,18 +712,21 @@ struct RemoveUnusedBrs : public WalkerPass<PostWalker<RemoveUnusedBrs>> { return; } - // First, check for a possible null which would prevent all other - // optimizations (except for br_on_cast variants). + // First, check for a possible null which would prevent optimizations on + // null checks. // TODO: Look into using BrOnNonNull here, to replace a br_on_func whose // input is (ref null func) with br_on_non_null (as only the null check // would be needed). + // TODO: Use the fallthrough to determine in more cases that we + // definitely have a null. auto refType = curr->ref->type; - if (refType.isNullable() && curr->op != BrOnCast && - curr->op != BrOnCastFail) { + if (refType.isNullable() && + (curr->op == BrOnNull || curr->op == BrOnNonNull)) { return; } if (curr->op == BrOnNull) { + assert(refType.isNonNullable()); // This cannot be null, so the br is never taken, and the non-null // value flows through. replaceCurrent(curr->ref); @@ -731,6 +734,7 @@ struct RemoveUnusedBrs : public WalkerPass<PostWalker<RemoveUnusedBrs>> { return; } if (curr->op == BrOnNonNull) { + assert(refType.isNonNullable()); // This cannot be null, so the br is always taken. replaceCurrent( Builder(*getModule()).makeBreak(curr->name, curr->ref)); @@ -739,20 +743,24 @@ struct RemoveUnusedBrs : public WalkerPass<PostWalker<RemoveUnusedBrs>> { } // Check if the type is the kind we are checking for. - auto result = GCTypeUtils::evaluateKindCheck(curr); + auto result = GCTypeUtils::evaluateCastCheck(refType, curr->castType); + if (curr->op == BrOnCastFail) { + result = GCTypeUtils::flipEvaluationResult(result); + } if (result == GCTypeUtils::Success) { - // The type is what we are looking for, so we can switch from BrOn to - // a simple br which is always taken. + // The cast succeeds, so we can switch from BrOn to a simple br that + // is always taken. replaceCurrent( Builder(*getModule()).makeBreak(curr->name, curr->ref)); worked = true; } else if (result == GCTypeUtils::Failure) { - // The type is not what we are looking for, so the branch is never - // taken, and the value just flows through. + // The cast fails, so the branch is never taken, and the value just + // flows through. replaceCurrent(curr->ref); worked = true; } + // TODO: Handle SuccessOnlyIfNull and SuccessOnlyIfNonNull. } } optimizer; |