diff --git a/src/passes/Heap2Local.cpp b/src/passes/Heap2Local.cpp index 7f8381e2a6c..0e41774957b 100644 --- a/src/passes/Heap2Local.cpp +++ b/src/passes/Heap2Local.cpp @@ -1194,6 +1194,9 @@ struct Struct2Local : PostWalker { builder.makeDrop(curr->expected), builder.makeDrop(curr->replacement), structGet}); + if (block->type != curr->type) { + refinalize = true; + } replaceCurrent(block); return; } @@ -1226,6 +1229,9 @@ struct Struct2Local : PostWalker { builder.makeDrop(curr->expected), builder.makeDrop(curr->replacement), arrayGet}); + if (block->type != curr->type) { + refinalize = true; + } replaceCurrent(block); // Since `ref` must be an array and arrays are processed before structs, // it is not possible that `ref` will be processed later. We therefore do diff --git a/test/lit/passes/heap2local-rmw.wast b/test/lit/passes/heap2local-rmw.wast index 07fc1eadac1..e7565e52287 100644 --- a/test/lit/passes/heap2local-rmw.wast +++ b/test/lit/passes/heap2local-rmw.wast @@ -13,9 +13,11 @@ ;; CHECK: (type $3 (func (param (ref null $struct)) (result (ref null $struct)))) - ;; CHECK: (type $4 (func (param (ref null $struct) (ref null $struct)) (result (ref null $struct)))) + ;; CHECK: (type $4 (func (param (ref $struct)))) - ;; CHECK: (type $5 (func (param i32) (result i32))) + ;; CHECK: (type $5 (func (param (ref null $struct) (ref null $struct)) (result (ref null $struct)))) + + ;; CHECK: (type $6 (func (param i32) (result i32))) ;; CHECK: (type $arr (array (mut i32))) (type $arr (array (mut i32))) @@ -81,6 +83,55 @@ ) ) + ;; CHECK: (func $no-escape-cmpxchg-expected-null-ref (type $4) (param $x (ref $struct)) + ;; CHECK-NEXT: (local $1 (ref null $struct)) + ;; CHECK-NEXT: (local $2 nullref) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (block $block (result (ref none)) + ;; CHECK-NEXT: (br_on_cast_fail $block (ref none) (ref none) + ;; CHECK-NEXT: (block (result (ref none)) + ;; CHECK-NEXT: (local.set $2 + ;; CHECK-NEXT: (ref.null none) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (block (result nullref) + ;; CHECK-NEXT: (local.set $1 + ;; CHECK-NEXT: (ref.null none) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (ref.null none) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (local.get $x) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (block ;; (replaces unreachable StructGet we can't emit) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (local.get $2) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (unreachable) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $no-escape-cmpxchg-expected-null-ref (param $x (ref $struct)) + ;; When `ref` is null, replacing the cmpxchg with a struct.get refines the + ;; result type from the replacement type `(ref $struct)` to `(ref none)`, + ;; which requires refinalization. + (drop + (block $block (result (ref $struct)) + (br_on_cast_fail $block (ref $struct) (ref $struct) + (struct.atomic.rmw.cmpxchg $struct 0 + (ref.null none) + (struct.new_default $struct) + (local.get $x) + ) + ) + ) + ) + ) + ;; CHECK: (func $rmw-add-i32 (type $1) (result i32) ;; CHECK-NEXT: (local $0 i32) ;; CHECK-NEXT: (local $1 i32) @@ -587,7 +638,7 @@ ) ) - ;; CHECK: (func $rmw-cmpxchg-ref (type $4) (param $0 (ref null $struct)) (param $1 (ref null $struct)) (result (ref null $struct)) + ;; CHECK: (func $rmw-cmpxchg-ref (type $5) (param $0 (ref null $struct)) (param $1 (ref null $struct)) (result (ref null $struct)) ;; CHECK-NEXT: (local $2 (ref null $struct)) ;; CHECK-NEXT: (local $3 (ref null $struct)) ;; CHECK-NEXT: (local $4 eqref) @@ -875,7 +926,7 @@ ) ) - ;; CHECK: (func $array-rmw-nonconstant-index (type $5) (param $idx i32) (result i32) + ;; CHECK: (func $array-rmw-nonconstant-index (type $6) (param $idx i32) (result i32) ;; CHECK-NEXT: (array.atomic.rmw.add $arr ;; CHECK-NEXT: (array.new_fixed $arr 2 ;; CHECK-NEXT: (i32.const 0) @@ -1495,6 +1546,8 @@ ;; CHECK: (type $1 (func (param (ref $array)))) + ;; CHECK: (type $2 (func (param (ref eq)))) + ;; CHECK: (func $array-cmpxchg-expected (type $1) (param $array (ref $array)) ;; CHECK-NEXT: (local $1 eqref) ;; CHECK-NEXT: (local $2 (ref null $array)) @@ -1540,6 +1593,64 @@ ) ) ) + + ;; CHECK: (func $array-cmpxchg-expected-null-ref (type $2) (param $x (ref eq)) + ;; CHECK-NEXT: (local $1 eqref) + ;; CHECK-NEXT: (local $2 nullref) + ;; CHECK-NEXT: (local $3 i32) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (block $block (result (ref none)) + ;; CHECK-NEXT: (br_on_cast_fail $block (ref none) (ref none) + ;; CHECK-NEXT: (block (result (ref none)) + ;; CHECK-NEXT: (local.set $2 + ;; CHECK-NEXT: (ref.null none) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (local.set $3 + ;; CHECK-NEXT: (i32.const 0) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (block (result nullref) + ;; CHECK-NEXT: (local.set $1 + ;; CHECK-NEXT: (ref.null none) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (ref.null none) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (local.get $x) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (block ;; (replaces unreachable ArrayGet we can't emit) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (local.get $2) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (local.get $3) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (unreachable) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $array-cmpxchg-expected-null-ref (param $x (ref eq)) + ;; When `ref` is null, replacing the cmpxchg with an array.get refines the + ;; result type from `(ref eq)` to `(ref none)`, requiring refinalization. + (drop + (block $block (result (ref eq)) + (br_on_cast_fail $block (ref eq) (ref eq) + (array.atomic.rmw.cmpxchg $array + (ref.null none) + (i32.const 0) + (array.new_default $array + (i32.const 1) + ) + (local.get $x) + ) + ) + ) + ) + ) ) (module