diff options
-rw-r--r-- | src/passes/RemoveUnusedBrs.cpp | 14 | ||||
-rw-r--r-- | test/lit/passes/remove-unused-brs-gc.wast | 29 |
2 files changed, 41 insertions, 2 deletions
diff --git a/src/passes/RemoveUnusedBrs.cpp b/src/passes/RemoveUnusedBrs.cpp index 96db281d8..44549f68d 100644 --- a/src/passes/RemoveUnusedBrs.cpp +++ b/src/passes/RemoveUnusedBrs.cpp @@ -1146,6 +1146,7 @@ struct RemoveUnusedBrs : public WalkerPass<PostWalker<RemoveUnusedBrs>> { PassOptions& passOptions; bool needUniqify = false; + bool refinalize = false; FinalOptimizer(PassOptions& passOptions) : passOptions(passOptions) {} @@ -1419,8 +1420,14 @@ struct RemoveUnusedBrs : public WalkerPass<PostWalker<RemoveUnusedBrs>> { if (condition.invalidates(ifTrue) || condition.invalidates(ifFalse)) { return nullptr; } - return Builder(*getModule()) - .makeSelect(iff->condition, iff->ifTrue, iff->ifFalse); + auto* select = Builder(*getModule()) + .makeSelect(iff->condition, iff->ifTrue, iff->ifFalse); + if (select->type != iff->type) { + // If the select is more refined than the if it replaces, we must + // propagate that outwards. + refinalize = true; + } + return select; } void visitLocalSet(LocalSet* curr) { @@ -1793,6 +1800,9 @@ struct RemoveUnusedBrs : public WalkerPass<PostWalker<RemoveUnusedBrs>> { if (finalOptimizer.needUniqify) { wasm::UniqueNameMapper::uniquify(func->body); } + if (finalOptimizer.refinalize) { + ReFinalize().walkFunctionInModule(func, getModule()); + } } }; diff --git a/test/lit/passes/remove-unused-brs-gc.wast b/test/lit/passes/remove-unused-brs-gc.wast index 0a9e08858..fa7a6d727 100644 --- a/test/lit/passes/remove-unused-brs-gc.wast +++ b/test/lit/passes/remove-unused-brs-gc.wast @@ -864,4 +864,33 @@ ) ) ) + + ;; CHECK: (func $select-refinalize (type $13) (param $param (ref $struct)) (result (ref struct)) + ;; CHECK-NEXT: (select (result (ref $struct)) + ;; CHECK-NEXT: (select (result (ref $struct)) + ;; CHECK-NEXT: (struct.new_default $struct) + ;; CHECK-NEXT: (struct.new_default $struct) + ;; CHECK-NEXT: (i32.const 0) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (local.get $param) + ;; CHECK-NEXT: (i32.const 0) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $select-refinalize (param $param (ref $struct)) (result (ref struct)) + ;; The inner if can turn into a select. The type then changes, allowing the + ;; outer select to be refined, which will error if we do not refinalize. + (select (result (ref struct)) + (if (result (ref struct)) + (i32.const 0) + (then + (struct.new_default $struct) + ) + (else + (struct.new_default $struct) + ) + ) + (local.get $param) + (i32.const 0) + ) + ) ) |