From a5c295528c4c988c0f5746f8472447e539aaae97 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Tue, 14 Apr 2026 12:54:51 -0700 Subject: [PATCH 1/2] start --- src/passes/RemoveUnusedBrs.cpp | 6 +- .../remove-unused-brs_all-features.wast | 116 +++++++++++++++++- 2 files changed, 116 insertions(+), 6 deletions(-) diff --git a/src/passes/RemoveUnusedBrs.cpp b/src/passes/RemoveUnusedBrs.cpp index 77fd6840818..bc7e1e5b7c3 100644 --- a/src/passes/RemoveUnusedBrs.cpp +++ b/src/passes/RemoveUnusedBrs.cpp @@ -1224,11 +1224,7 @@ struct RemoveUnusedBrs : public WalkerPass> { // if this block has just one child, a sub-block, then jumps to the // former are jumps to us, really if (auto* child = list[0]->dynCast()) { - // the two blocks must have the same type for us to update the - // branch, as otherwise one block may be unreachable and the other - // concrete, so one might lack a value - if (child->name.is() && child->name != curr->name && - child->type == curr->type) { + if (child->name.is()) { redirectBranches(child, curr->name); } } diff --git a/test/lit/passes/remove-unused-brs_all-features.wast b/test/lit/passes/remove-unused-brs_all-features.wast index 87c1b2ae197..6156c81b07a 100644 --- a/test/lit/passes/remove-unused-brs_all-features.wast +++ b/test/lit/passes/remove-unused-brs_all-features.wast @@ -26,9 +26,15 @@ ;; CHECK: (type $10 (func (result funcref))) + ;; CHECK: (type $11 (func (param i32 i32) (result (ref func)))) + + ;; CHECK: (type $12 (func (param i32 i32) (result funcref))) + + ;; CHECK: (type $13 (func (param i32 i32))) + ;; CHECK: (import "out" "log" (func $log (type $2) (param i32))) (import "out" "log" (func $log (param i32))) - ;; CHECK: (elem declare func $br_on_non_null $br_on_null $i32_=>_none $none_=>_i32) + ;; CHECK: (elem declare func $br_on_non_null $br_on_null $foo $i32_=>_none $none_=>_i32 $redirect_child) ;; CHECK: (func $foo (type $3) (result (ref null $struct)) ;; CHECK-NEXT: (if (result (ref null $struct)) @@ -283,4 +289,112 @@ (unreachable) ) ) + + ;; CHECK: (func $redirect_child (type $11) (param $x i32) (param $y i32) (result (ref func)) + ;; CHECK-NEXT: (block $outer (result (ref func)) + ;; CHECK-NEXT: (block $inner (result (ref func)) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (br_if $inner + ;; CHECK-NEXT: (ref.func $foo) + ;; CHECK-NEXT: (local.get $x) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (br_if $inner + ;; CHECK-NEXT: (ref.func $redirect_child) + ;; CHECK-NEXT: (local.get $y) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (unreachable) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $redirect_child (param $x i32) (param $y i32) (result (ref func)) + ;; The br_if can go to the outer block instead of the inner. + (block $outer (result (ref func)) + (block $inner (result (ref func)) + (drop + (br_if $inner + (ref.func $foo) + (local.get $x) + ) + ) + (drop + (br_if $inner + (ref.func $redirect_child) + (local.get $y) + ) + ) + (unreachable) + ) + ) + ) + + ;; CHECK: (func $redirect_child_subtype (type $12) (param $x i32) (param $y i32) (result funcref) + ;; CHECK-NEXT: (block $outer (result funcref) + ;; CHECK-NEXT: (block $inner (result (ref func)) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (br_if $inner + ;; CHECK-NEXT: (ref.func $foo) + ;; CHECK-NEXT: (local.get $x) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (br_if $inner + ;; CHECK-NEXT: (ref.func $redirect_child) + ;; CHECK-NEXT: (local.get $y) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (unreachable) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $redirect_child_subtype (param $x i32) (param $y i32) (result (ref null func)) + ;; As above, but now the inner block has a subtype. We can still redirect. + (block $outer (result (ref null func)) + (block $inner (result (ref func)) + (drop + (br_if $inner + (ref.func $foo) + (local.get $x) + ) + ) + (drop + (br_if $inner + (ref.func $redirect_child) + (local.get $y) + ) + ) + (unreachable) + ) + ) + ) + + ;; CHECK: (func $redirect_child_none (type $13) (param $x i32) (param $y i32) + ;; CHECK-NEXT: (block $outer + ;; CHECK-NEXT: (block $inner + ;; CHECK-NEXT: (br_if $outer + ;; CHECK-NEXT: (local.get $x) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (br_if $outer + ;; CHECK-NEXT: (local.get $y) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (unreachable) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $redirect_child_none (param $x i32) (param $y i32) + ;; As above, but now the blocks are none-typed. We can still redirect. + (block $outer + (block $inner + (br_if $inner + (local.get $x) + ) + (br_if $inner + (local.get $y) + ) + (unreachable) + ) + ) + ) ) From 423e494f517cb0ccf0dca651f22e8a93ba00b52b Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Tue, 14 Apr 2026 13:14:15 -0700 Subject: [PATCH 2/2] undo --- .../remove-unused-brs_all-features.wast | 116 +----------------- 1 file changed, 1 insertion(+), 115 deletions(-) diff --git a/test/lit/passes/remove-unused-brs_all-features.wast b/test/lit/passes/remove-unused-brs_all-features.wast index 6156c81b07a..87c1b2ae197 100644 --- a/test/lit/passes/remove-unused-brs_all-features.wast +++ b/test/lit/passes/remove-unused-brs_all-features.wast @@ -26,15 +26,9 @@ ;; CHECK: (type $10 (func (result funcref))) - ;; CHECK: (type $11 (func (param i32 i32) (result (ref func)))) - - ;; CHECK: (type $12 (func (param i32 i32) (result funcref))) - - ;; CHECK: (type $13 (func (param i32 i32))) - ;; CHECK: (import "out" "log" (func $log (type $2) (param i32))) (import "out" "log" (func $log (param i32))) - ;; CHECK: (elem declare func $br_on_non_null $br_on_null $foo $i32_=>_none $none_=>_i32 $redirect_child) + ;; CHECK: (elem declare func $br_on_non_null $br_on_null $i32_=>_none $none_=>_i32) ;; CHECK: (func $foo (type $3) (result (ref null $struct)) ;; CHECK-NEXT: (if (result (ref null $struct)) @@ -289,112 +283,4 @@ (unreachable) ) ) - - ;; CHECK: (func $redirect_child (type $11) (param $x i32) (param $y i32) (result (ref func)) - ;; CHECK-NEXT: (block $outer (result (ref func)) - ;; CHECK-NEXT: (block $inner (result (ref func)) - ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (br_if $inner - ;; CHECK-NEXT: (ref.func $foo) - ;; CHECK-NEXT: (local.get $x) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (br_if $inner - ;; CHECK-NEXT: (ref.func $redirect_child) - ;; CHECK-NEXT: (local.get $y) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (unreachable) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: ) - (func $redirect_child (param $x i32) (param $y i32) (result (ref func)) - ;; The br_if can go to the outer block instead of the inner. - (block $outer (result (ref func)) - (block $inner (result (ref func)) - (drop - (br_if $inner - (ref.func $foo) - (local.get $x) - ) - ) - (drop - (br_if $inner - (ref.func $redirect_child) - (local.get $y) - ) - ) - (unreachable) - ) - ) - ) - - ;; CHECK: (func $redirect_child_subtype (type $12) (param $x i32) (param $y i32) (result funcref) - ;; CHECK-NEXT: (block $outer (result funcref) - ;; CHECK-NEXT: (block $inner (result (ref func)) - ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (br_if $inner - ;; CHECK-NEXT: (ref.func $foo) - ;; CHECK-NEXT: (local.get $x) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (br_if $inner - ;; CHECK-NEXT: (ref.func $redirect_child) - ;; CHECK-NEXT: (local.get $y) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (unreachable) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: ) - (func $redirect_child_subtype (param $x i32) (param $y i32) (result (ref null func)) - ;; As above, but now the inner block has a subtype. We can still redirect. - (block $outer (result (ref null func)) - (block $inner (result (ref func)) - (drop - (br_if $inner - (ref.func $foo) - (local.get $x) - ) - ) - (drop - (br_if $inner - (ref.func $redirect_child) - (local.get $y) - ) - ) - (unreachable) - ) - ) - ) - - ;; CHECK: (func $redirect_child_none (type $13) (param $x i32) (param $y i32) - ;; CHECK-NEXT: (block $outer - ;; CHECK-NEXT: (block $inner - ;; CHECK-NEXT: (br_if $outer - ;; CHECK-NEXT: (local.get $x) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (br_if $outer - ;; CHECK-NEXT: (local.get $y) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (unreachable) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: ) - (func $redirect_child_none (param $x i32) (param $y i32) - ;; As above, but now the blocks are none-typed. We can still redirect. - (block $outer - (block $inner - (br_if $inner - (local.get $x) - ) - (br_if $inner - (local.get $y) - ) - (unreachable) - ) - ) - ) )