Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 6 additions & 3 deletions src/passes/Heap2Local.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -898,7 +898,8 @@ struct Struct2Local : PostWalker<Struct2Local> {
// side effects, but that local.set would not be reflected in the parent
// map, so it would not be updated if the allocation flowing through
// that desc operand were later optimized.
if (allocIsCastDescEq && !allocIsCastRef && curr->type.isNullable()) {
if (allocIsCastDescEq && !allocIsCastRef && curr->type.isNullable() &&
curr->ref->type != Type::unreachable) {
// There might be a null value to let through. Reuse curr as a cast to
// null. Use a scratch local to move the reference value past the desc
// value.
Expand Down Expand Up @@ -1117,7 +1118,8 @@ struct Struct2Local : PostWalker<Struct2Local> {
}

void visitStructCmpxchg(StructCmpxchg* curr) {
if (curr->type == Type::unreachable) {
if (curr->type == Type::unreachable ||
curr->ref->type == Type::unreachable) {
// Leave this for DCE.
return;
}
Expand Down Expand Up @@ -1199,7 +1201,8 @@ struct Struct2Local : PostWalker<Struct2Local> {
}

void visitArrayCmpxchg(ArrayCmpxchg* curr) {
if (curr->type == Type::unreachable) {
if (curr->type == Type::unreachable ||
curr->ref->type == Type::unreachable) {
// Leave this for DCE.
return;
}
Expand Down
38 changes: 38 additions & 0 deletions test/lit/passes/heap2local-desc.wast
Original file line number Diff line number Diff line change
Expand Up @@ -519,6 +519,44 @@
)
)

;; CHECK: (func $cast-desc-eq-fail-became-unreachable-nullable (type $10)
;; CHECK-NEXT: (local $desc (ref null (exact $super.desc)))
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (block
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (block
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (block (result nullref)
;; CHECK-NEXT: (ref.null none)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (unreachable)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.null none)
;; CHECK-NEXT: )
;; CHECK-NEXT: (unreachable)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $cast-desc-eq-fail-became-unreachable-nullable
;; The cast admits nulls and the allocation flows into the descriptor, but
;; the reference operand becomes unreachable during the walk due to an inner
;; failing cast of the same allocation.
(local $desc (ref null (exact $super.desc)))
(drop
(ref.cast_desc_eq (ref null (exact $super))
(ref.cast (ref null $super)
(local.tee $desc
(struct.new $super.desc)
)
)
(local.get $desc)
)
)
)

;; CHECK: (func $cast-no-desc (type $11) (param $desc (ref null (exact $super.desc)))
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (block
Expand Down
124 changes: 124 additions & 0 deletions test/lit/passes/heap2local-rmw.wast
Original file line number Diff line number Diff line change
Expand Up @@ -1739,3 +1739,127 @@
)
)
)

(module
(type $s0 (shared (struct (field (mut (ref null (shared eq)))))))
;; CHECK: (type $0 (func))

;; CHECK: (type $s1 (shared (struct)))

;; CHECK: (type $a0 (shared (array (mut (ref null (shared eq))))))
(type $a0 (shared (array (mut (ref null (shared eq))))))
(type $s1 (shared (struct)))

;; CHECK: (type $3 (func (param (ref $a0))))

;; CHECK: (func $cmpxchg-became-unreachable-ref (type $0)
;; CHECK-NEXT: (local $x (ref null $s1))
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (block ;; (replaces unreachable StructCmpxchg we can't emit)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (block
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (block (result (ref null (shared none)))
;; CHECK-NEXT: (ref.null (shared none))
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (unreachable)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.null (shared none))
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.null (shared none))
;; CHECK-NEXT: )
;; CHECK-NEXT: (unreachable)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $cmpxchg-became-unreachable-ref
;; The allocation flows into both a failing cast in `ref` and into
;; `expected`. During the post-order walk, `ref` is replaced with an
;; unreachable block before the cmpxchg is visited (and before ReFinalize
;; runs), so `visitStructCmpxchg` must check for an unreachable `ref`.
(local $x (ref null $s1))
(drop
(struct.atomic.rmw.cmpxchg $s0 0
(ref.cast (ref $s0)
(local.tee $x
(struct.new_default $s1)
)
)
(local.get $x)
(ref.null (shared none))
)
)
)

;; CHECK: (func $array-cmpxchg-became-unreachable-ref (type $0)
;; CHECK-NEXT: (local $x (ref null $s1))
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (block ;; (replaces unreachable ArrayCmpxchg we can't emit)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (block
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (block (result (ref null (shared none)))
;; CHECK-NEXT: (ref.null (shared none))
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (unreachable)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (i32.const 0)
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.null (shared none))
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.null (shared none))
;; CHECK-NEXT: )
;; CHECK-NEXT: (unreachable)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $array-cmpxchg-became-unreachable-ref
;; Same as above, for array.atomic.rmw.cmpxchg.
(local $x (ref null $s1))
(drop
(array.atomic.rmw.cmpxchg $a0
(ref.cast (ref $a0)
(local.tee $x
(struct.new_default $s1)
)
)
(i32.const 0)
(local.get $x)
(ref.null (shared none))
)
)
)

;; CHECK: (func $array-cmpxchg-unreachable (type $3) (param $a (ref $a0))
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (array.atomic.rmw.cmpxchg $a0
;; CHECK-NEXT: (local.get $a)
;; CHECK-NEXT: (i32.const 0)
;; CHECK-NEXT: (block (result (ref null (shared none)))
;; CHECK-NEXT: (ref.null (shared none))
;; CHECK-NEXT: )
;; CHECK-NEXT: (unreachable)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $array-cmpxchg-unreachable (param $a (ref $a0))
;; An unreachable array.atomic.rmw.cmpxchg is left for DCE.
(drop
(array.atomic.rmw.cmpxchg $a0
(local.get $a)
(i32.const 0)
(struct.new_default $s1)
(unreachable)
)
)
)
)
Loading