blob: 7750ee02a430e8e86687eb511462953d3a8db0d6 [file] [edit]
;; NOTE: Assertions have been generated by update_lit_checks.py and should not be edited.
;; RUN: wasm-opt -all %s --remove-unused-brs -S -o - | filecheck %s
(module
(rec
;; CHECK: (rec
;; CHECK-NEXT: (type $super (sub (descriptor $super.desc) (struct)))
(type $super (sub (descriptor $super.desc) (struct)))
;; CHECK: (type $super.desc (sub (describes $super) (struct)))
(type $super.desc (sub (describes $super) (struct)))
;; CHECK: (type $sub (sub $super (descriptor $sub.desc) (struct)))
(type $sub (sub $super (descriptor $sub.desc) (struct)))
;; CHECK: (type $sub.desc (sub $super.desc (describes $sub) (struct)))
(type $sub.desc (sub $super.desc (describes $sub) (struct)))
;; CHECK: (type $other (descriptor $other.desc) (struct))
(type $other (descriptor $other.desc) (struct))
;; CHECK: (type $other.desc (describes $other) (struct))
(type $other.desc (describes $other) (struct))
)
;; CHECK: (import "" "" (func $effect (type $14)))
(import "" "" (func $effect))
;; CHECK: (func $no-glb (type $6) (param $sub (ref $sub)) (param $super.desc (ref $super.desc)) (result anyref)
;; CHECK-NEXT: (block $l (result anyref)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (br_on_cast_desc $l (ref $sub) (ref $super)
;; CHECK-NEXT: (local.get $sub)
;; CHECK-NEXT: (local.get $super.desc)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (ref.null none)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $no-glb (param $sub (ref $sub)) (param $super.desc (ref $super.desc)) (result anyref)
(block $l (result anyref)
(drop
;; We cannot improve the cast type even though it is a supertype of the
;; ref type because the cast type is determined by the descriptor.
(br_on_cast_desc $l (ref $sub) (ref $super)
(local.get $sub)
(local.get $super.desc)
)
)
(ref.null none)
)
)
;; CHECK: (func $improve-nullability (type $6) (param $sub (ref $sub)) (param $super.desc (ref $super.desc)) (result anyref)
;; CHECK-NEXT: (block $l (result (ref null $super))
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.as_non_null
;; CHECK-NEXT: (br_on_cast_desc $l (ref $sub) (ref $super)
;; CHECK-NEXT: (block (result (ref $sub))
;; CHECK-NEXT: (local.get $sub)
;; CHECK-NEXT: )
;; CHECK-NEXT: (local.get $super.desc)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (ref.null none)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $improve-nullability (param $sub (ref $sub)) (param $super.desc (ref $super.desc)) (result anyref)
(block $l (result anyref)
(drop
;; We can improve the nullability, though, even via fallthrough.
(br_on_cast_desc $l anyref (ref null $super)
(block (result anyref)
(local.get $sub)
)
(local.get $super.desc)
)
)
(ref.null none)
)
)
;; CHECK: (func $only-improve-nullability (type $10) (param $sub (ref null $sub)) (param $super.desc (ref $super.desc)) (result anyref)
;; CHECK-NEXT: (block $l (result anyref)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (br_on_cast_desc $l anyref (ref $super)
;; CHECK-NEXT: (block (result anyref)
;; CHECK-NEXT: (local.get $sub)
;; CHECK-NEXT: )
;; CHECK-NEXT: (local.get $super.desc)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (ref.null none)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $only-improve-nullability (param $sub (ref null $sub)) (param $super.desc (ref $super.desc)) (result anyref)
(block $l (result anyref)
(drop
;; We do not flip the nullability if the target is already non-nullable.
(br_on_cast_desc $l anyref (ref $super)
(block (result anyref)
(local.get $sub)
)
(local.get $super.desc)
)
)
(ref.null none)
)
)
;; CHECK: (func $fail-no-glb (type $6) (param $sub (ref $sub)) (param $super.desc (ref $super.desc)) (result anyref)
;; CHECK-NEXT: (block $l (result anyref)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (br_on_cast_desc_fail $l (ref $sub) (ref $super)
;; CHECK-NEXT: (local.get $sub)
;; CHECK-NEXT: (local.get $super.desc)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (ref.null none)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $fail-no-glb (param $sub (ref $sub)) (param $super.desc (ref $super.desc)) (result anyref)
(block $l (result anyref)
(drop
;; We cannot improve the cast type even though it is a supertype of the
;; ref type because the cast type is determined by the descriptor.
(br_on_cast_desc_fail $l (ref $sub) (ref $super)
(local.get $sub)
(local.get $super.desc)
)
)
(ref.null none)
)
)
;; CHECK: (func $fail-no-improve-nullability (type $6) (param $sub (ref $sub)) (param $super.desc (ref $super.desc)) (result anyref)
;; CHECK-NEXT: (block $l (result anyref)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (br_on_cast_desc_fail $l anyref (ref null $super)
;; CHECK-NEXT: (block (result anyref)
;; CHECK-NEXT: (local.get $sub)
;; CHECK-NEXT: )
;; CHECK-NEXT: (local.get $super.desc)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (ref.null none)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $fail-no-improve-nullability (param $sub (ref $sub)) (param $super.desc (ref $super.desc)) (result anyref)
(block $l (result anyref)
(drop
;; In the fail case we cannot improve the nullability, either, because
;; that would make the sent values nullable, which might not be allowed.
(br_on_cast_desc_fail $l anyref (ref null $super)
(block (result anyref)
(local.get $sub)
)
(local.get $super.desc)
)
)
(ref.null none)
)
)
;; CHECK: (func $fail-only-improve-nullability (type $10) (param $sub (ref null $sub)) (param $super.desc (ref $super.desc)) (result anyref)
;; CHECK-NEXT: (block $l (result anyref)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (br_on_cast_desc_fail $l anyref (ref $super)
;; CHECK-NEXT: (block (result anyref)
;; CHECK-NEXT: (local.get $sub)
;; CHECK-NEXT: )
;; CHECK-NEXT: (local.get $super.desc)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (ref.null none)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $fail-only-improve-nullability (param $sub (ref null $sub)) (param $super.desc (ref $super.desc)) (result anyref)
(block $l (result anyref)
(drop
;; We do not flip the nullability if the target is already non-nullable.
(br_on_cast_desc_fail $l anyref (ref $super)
(block (result anyref)
(local.get $sub)
)
(local.get $super.desc)
)
)
(ref.null none)
)
)
;; CHECK: (func $unknown-result (type $11) (param $super (ref $super)) (param $sub.desc (ref $sub.desc)) (result anyref)
;; CHECK-NEXT: (block $l (result anyref)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (br_on_cast_desc $l (ref $super) (ref $sub)
;; CHECK-NEXT: (local.get $super)
;; CHECK-NEXT: (local.get $sub.desc)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (ref.null none)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $unknown-result (param $super (ref $super)) (param $sub.desc (ref $sub.desc)) (result anyref)
(block $l (result anyref)
(drop
;; We do not know anything about the result of this cast and cannot
;; optimize.
(br_on_cast_desc $l anyref (ref $sub)
(local.get $super)
(local.get $sub.desc)
)
)
(ref.null none)
)
)
;; CHECK: (func $fail-unknown-result (type $11) (param $super (ref $super)) (param $sub.desc (ref $sub.desc)) (result anyref)
;; CHECK-NEXT: (block $l (result anyref)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (br_on_cast_desc_fail $l (ref $super) (ref $sub)
;; CHECK-NEXT: (local.get $super)
;; CHECK-NEXT: (local.get $sub.desc)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (ref.null none)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $fail-unknown-result (param $super (ref $super)) (param $sub.desc (ref $sub.desc)) (result anyref)
(block $l (result anyref)
(drop
;; We do not know anything about the result of this cast and cannot
;; optimize.
(br_on_cast_desc_fail $l anyref (ref $sub)
(local.get $super)
(local.get $sub.desc)
)
)
(ref.null none)
)
)
;; CHECK: (func $uninhabitable-source (type $7) (param $uninhabitable (ref none)) (param $super.desc (ref $super.desc)) (result anyref)
;; CHECK-NEXT: (block $l (result nullref)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (unreachable)
;; CHECK-NEXT: )
;; CHECK-NEXT: (ref.null none)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $uninhabitable-source (param $uninhabitable (ref none)) (param $super.desc (ref $super.desc)) (result anyref)
(block $l (result anyref)
(drop
;; The cast cannot be reached, so we can optimize it out entirely.
(br_on_cast_desc $l anyref (ref $super)
(local.get $uninhabitable)
(local.get $super.desc)
)
)
(ref.null none)
)
)
;; CHECK: (func $uninhabitable-source-effects (type $7) (param $uninhabitable (ref none)) (param $super.desc (ref $super.desc)) (result anyref)
;; CHECK-NEXT: (block $l (result nullref)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (block
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (block (result (ref none))
;; CHECK-NEXT: (call $effect)
;; CHECK-NEXT: (local.get $uninhabitable)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (block (result (ref $super.desc))
;; CHECK-NEXT: (call $effect)
;; CHECK-NEXT: (local.get $super.desc)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (unreachable)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (ref.null none)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $uninhabitable-source-effects (param $uninhabitable (ref none)) (param $super.desc (ref $super.desc)) (result anyref)
(block $l (result anyref)
(drop
;; Same, but now there are effects we must preserve.
(br_on_cast_desc $l anyref (ref $super)
(block (result (ref none))
(call $effect)
(local.get $uninhabitable)
)
(block (result (ref $super.desc))
(call $effect)
(local.get $super.desc)
)
)
)
(ref.null none)
)
)
;; CHECK: (func $fail-uninhabitable-source (type $7) (param $uninhabitable (ref none)) (param $super.desc (ref $super.desc)) (result anyref)
;; CHECK-NEXT: (block $l (result nullref)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (unreachable)
;; CHECK-NEXT: )
;; CHECK-NEXT: (ref.null none)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $fail-uninhabitable-source (param $uninhabitable (ref none)) (param $super.desc (ref $super.desc)) (result anyref)
(block $l (result anyref)
(drop
;; The cast cannot be reached, so we can optimize it out entirely.
(br_on_cast_desc_fail $l anyref (ref $super)
(local.get $uninhabitable)
(local.get $super.desc)
)
)
(ref.null none)
)
)
;; CHECK: (func $fail-uninhabitable-source-effects (type $7) (param $uninhabitable (ref none)) (param $super.desc (ref $super.desc)) (result anyref)
;; CHECK-NEXT: (block $l (result nullref)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (block
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (block (result (ref none))
;; CHECK-NEXT: (call $effect)
;; CHECK-NEXT: (local.get $uninhabitable)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (block (result (ref $super.desc))
;; CHECK-NEXT: (call $effect)
;; CHECK-NEXT: (local.get $super.desc)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (unreachable)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (ref.null none)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $fail-uninhabitable-source-effects (param $uninhabitable (ref none)) (param $super.desc (ref $super.desc)) (result anyref)
(block $l (result anyref)
(drop
;; Same, but now there are effects we must preserve.
(br_on_cast_desc_fail $l anyref (ref $super)
(block (result (ref none))
(call $effect)
(local.get $uninhabitable)
)
(block (result (ref $super.desc))
(call $effect)
(local.get $super.desc)
)
)
)
(ref.null none)
)
)
;; CHECK: (func $cast-success-on-null (type $9) (param $other (ref null $other)) (param $super.desc (ref $super.desc)) (result anyref)
;; CHECK-NEXT: (block $l (result anyref)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (br_on_cast_desc $l (ref null $other) (ref null $super)
;; CHECK-NEXT: (local.get $other)
;; CHECK-NEXT: (local.get $super.desc)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (ref.null none)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $cast-success-on-null (param $other (ref null $other)) (param $super.desc (ref $super.desc)) (result anyref)
(block $l (result anyref)
(drop
;; We know the cast can only succeed if the value is null. We can
;; optimize to a branch on null in principle, but we do not do this yet
;; TODO.
(br_on_cast_desc $l anyref (ref null $super)
(local.get $other)
(local.get $super.desc)
)
)
(ref.null none)
)
)
;; CHECK: (func $fail-cast-success-on-null (type $9) (param $other (ref null $other)) (param $super.desc (ref $super.desc)) (result anyref)
;; CHECK-NEXT: (block $l (result (ref null $other))
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (block (result nullref)
;; CHECK-NEXT: (br_on_non_null $l
;; CHECK-NEXT: (block (result (ref null $other))
;; CHECK-NEXT: (local.get $other)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (ref.null none)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (ref.null none)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $fail-cast-success-on-null (param $other (ref null $other)) (param $super.desc (ref $super.desc)) (result anyref)
(block $l (result anyref)
(drop
;; We know the cast can only succeed if the value is null. We can
;; optimize to a branch on non-null.
(br_on_cast_desc_fail $l anyref (ref null $super)
(local.get $other)
(local.get $super.desc)
)
)
(ref.null none)
)
)
;; CHECK: (func $fail-cast-success-on-null-nullable-desc (type $15) (param $other (ref null $other)) (param $super.desc (ref null $super.desc)) (result anyref)
;; CHECK-NEXT: (local $2 (ref $super.desc))
;; CHECK-NEXT: (block $l (result (ref null $other))
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (block (result nullref)
;; CHECK-NEXT: (br_on_non_null $l
;; CHECK-NEXT: (block (result (ref null $other))
;; CHECK-NEXT: (local.set $2
;; CHECK-NEXT: (ref.as_non_null
;; CHECK-NEXT: (local.get $super.desc)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (local.get $other)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (ref.null none)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (ref.null none)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $fail-cast-success-on-null-nullable-desc (param $other (ref null $other)) (param $super.desc (ref null $super.desc)) (result anyref)
(block $l (result anyref)
(drop
;; Same as above, but now the descriptor is nullable so we have to
;; insert a ref.as_non_null to preserve the trap on a null descriptor.
(br_on_cast_desc_fail $l anyref (ref null $super)
(local.get $other)
(local.get $super.desc)
)
)
(ref.null none)
)
)
;; CHECK: (func $fail-cast-success-on-null-effect (type $9) (param $other (ref null $other)) (param $super.desc (ref $super.desc)) (result anyref)
;; CHECK-NEXT: (local $2 (ref null $other))
;; CHECK-NEXT: (local $3 (ref $super.desc))
;; CHECK-NEXT: (block $l (result (ref null $other))
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (block (result nullref)
;; CHECK-NEXT: (br_on_non_null $l
;; CHECK-NEXT: (block (result (ref null $other))
;; CHECK-NEXT: (local.set $2
;; CHECK-NEXT: (block (result (ref null $other))
;; CHECK-NEXT: (call $effect)
;; CHECK-NEXT: (local.get $other)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (local.set $3
;; CHECK-NEXT: (block (result (ref $super.desc))
;; CHECK-NEXT: (call $effect)
;; CHECK-NEXT: (local.get $super.desc)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (local.get $2)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (ref.null none)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (ref.null none)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $fail-cast-success-on-null-effect (param $other (ref null $other)) (param $super.desc (ref $super.desc)) (result anyref)
(block $l (result anyref)
(drop
;; Same, but now there are other effects we must preserve instead.
(br_on_cast_desc_fail $l anyref (ref null $super)
(block (result (ref null $other))
(call $effect)
(local.get $other)
)
(block (result (ref $super.desc))
(call $effect)
(local.get $super.desc)
)
)
)
(ref.null none)
)
)
;; CHECK: (func $cast-success-on-nonnull (type $12) (param $super (ref null $super)) (param $super.desc (ref $super.desc)) (result anyref)
;; CHECK-NEXT: (block $l (result anyref)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (br_on_cast_desc $l (ref null $super) (ref $super)
;; CHECK-NEXT: (local.get $super)
;; CHECK-NEXT: (local.get $super.desc)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (ref.null none)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $cast-success-on-nonnull (param $super (ref null $super)) (param $super.desc (ref $super.desc)) (result anyref)
(block $l (result anyref)
(drop
;; We cannot replace this with a br_on_non_null because we would also
;; have to check that the descriptor values match.
(br_on_cast_desc $l anyref (ref $super)
(local.get $super)
(local.get $super.desc)
)
)
(ref.null none)
)
)
;; CHECK: (func $fail-cast-success-on-nonnull (type $12) (param $super (ref null $super)) (param $super.desc (ref $super.desc)) (result anyref)
;; CHECK-NEXT: (block $l (result anyref)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (br_on_cast_desc_fail $l (ref null $super) (ref $super)
;; CHECK-NEXT: (local.get $super)
;; CHECK-NEXT: (local.get $super.desc)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (ref.null none)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $fail-cast-success-on-nonnull (param $super (ref null $super)) (param $super.desc (ref $super.desc)) (result anyref)
(block $l (result anyref)
(drop
;; We cannot replace this with a br_on_null because we would also have
;; to check that the descriptor values match.
(br_on_cast_desc_fail $l anyref (ref $super)
(local.get $super)
(local.get $super.desc)
)
)
(ref.null none)
)
)
;; CHECK: (func $cast-failure (type $8) (param $other (ref $other)) (param $super.desc (ref $super.desc)) (result anyref)
;; CHECK-NEXT: (block $l (result nullref)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (block (result (ref $other))
;; CHECK-NEXT: (local.get $other)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (ref.null none)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $cast-failure (param $other (ref $other)) (param $super.desc (ref $super.desc)) (result anyref)
(block $l (result anyref)
(drop
;; We know based on the types that the cast will fail. We can remove it.
(br_on_cast_desc $l anyref (ref $super)
(local.get $other)
(local.get $super.desc)
)
)
(ref.null none)
)
)
;; CHECK: (func $cast-failure-nullable-desc (type $13) (param $other (ref $other)) (param $super.desc (ref null $super.desc)) (result anyref)
;; CHECK-NEXT: (local $2 (ref $super.desc))
;; CHECK-NEXT: (block $l (result nullref)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (block (result (ref $other))
;; CHECK-NEXT: (local.set $2
;; CHECK-NEXT: (ref.as_non_null
;; CHECK-NEXT: (local.get $super.desc)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (local.get $other)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (ref.null none)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $cast-failure-nullable-desc (param $other (ref $other)) (param $super.desc (ref null $super.desc)) (result anyref)
(block $l (result anyref)
(drop
;; Same, but the descriptor is now nullable, so we need to insert a
;; ref.as_non_null to preserve the trap on null descriptor.
(br_on_cast_desc $l anyref (ref $super)
(local.get $other)
(local.get $super.desc)
)
)
(ref.null none)
)
)
;; CHECK: (func $cast-failure-effect (type $8) (param $other (ref $other)) (param $super.desc (ref $super.desc)) (result anyref)
;; CHECK-NEXT: (local $2 (ref $other))
;; CHECK-NEXT: (local $3 (ref $super.desc))
;; CHECK-NEXT: (block $l (result nullref)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (block (result (ref $other))
;; CHECK-NEXT: (local.set $2
;; CHECK-NEXT: (block (result (ref $other))
;; CHECK-NEXT: (call $effect)
;; CHECK-NEXT: (local.get $other)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (local.set $3
;; CHECK-NEXT: (block (result (ref $super.desc))
;; CHECK-NEXT: (call $effect)
;; CHECK-NEXT: (local.get $super.desc)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (local.get $2)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (ref.null none)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $cast-failure-effect (param $other (ref $other)) (param $super.desc (ref $super.desc)) (result anyref)
(block $l (result anyref)
(drop
;; Same, but now there are other effects to preserve.
(br_on_cast_desc $l anyref (ref $super)
(block (result (ref $other))
(call $effect)
(local.get $other)
)
(block (result (ref $super.desc))
(call $effect)
(local.get $super.desc)
)
)
)
(ref.null none)
)
)
;; CHECK: (func $fail-cast-failure (type $8) (param $other (ref $other)) (param $super.desc (ref $super.desc)) (result anyref)
;; CHECK-NEXT: (block $l (result (ref null $other))
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (br $l
;; CHECK-NEXT: (block (result (ref $other))
;; CHECK-NEXT: (local.get $other)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (ref.null none)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $fail-cast-failure (param $other (ref $other)) (param $super.desc (ref $super.desc)) (result anyref)
(block $l (result anyref)
(drop
;; We know based on the types that the cast will fail. We can replace it
;; with an unconditional branch.
(br_on_cast_desc_fail $l anyref (ref $super)
(local.get $other)
(local.get $super.desc)
)
)
(ref.null none)
)
)
;; CHECK: (func $fail-cast-failure-nullable-desc (type $13) (param $other (ref $other)) (param $super.desc (ref null $super.desc)) (result anyref)
;; CHECK-NEXT: (local $2 (ref $super.desc))
;; CHECK-NEXT: (block $l (result (ref null $other))
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (br $l
;; CHECK-NEXT: (block (result (ref $other))
;; CHECK-NEXT: (local.set $2
;; CHECK-NEXT: (ref.as_non_null
;; CHECK-NEXT: (local.get $super.desc)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (local.get $other)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (ref.null none)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $fail-cast-failure-nullable-desc (param $other (ref $other)) (param $super.desc (ref null $super.desc)) (result anyref)
(block $l (result anyref)
(drop
;; Same, but now the descriptor is nullable and we need to preserve the
;; trap on null descriptor.
(br_on_cast_desc_fail $l anyref (ref $super)
(local.get $other)
(local.get $super.desc)
)
)
(ref.null none)
)
)
;; CHECK: (func $fail-cast-failure-effect (type $8) (param $other (ref $other)) (param $super.desc (ref $super.desc)) (result anyref)
;; CHECK-NEXT: (local $2 (ref $other))
;; CHECK-NEXT: (local $3 (ref $super.desc))
;; CHECK-NEXT: (block $l (result (ref null $other))
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (br $l
;; CHECK-NEXT: (block (result (ref $other))
;; CHECK-NEXT: (local.set $2
;; CHECK-NEXT: (block (result (ref $other))
;; CHECK-NEXT: (call $effect)
;; CHECK-NEXT: (local.get $other)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (local.set $3
;; CHECK-NEXT: (block (result (ref $super.desc))
;; CHECK-NEXT: (call $effect)
;; CHECK-NEXT: (local.get $super.desc)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (local.get $2)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (ref.null none)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $fail-cast-failure-effect (param $other (ref $other)) (param $super.desc (ref $super.desc)) (result anyref)
(block $l (result anyref)
(drop
;; Same, but now there are other effects to preserve.
(br_on_cast_desc_fail $l anyref (ref $super)
(block (result (ref $other))
(call $effect)
(local.get $other)
)
(block (result (ref $super.desc))
(call $effect)
(local.get $super.desc)
)
)
)
(ref.null none)
)
)
;; CHECK: (func $refinalize-untaken (type $16) (result anyref)
;; CHECK-NEXT: (block $block
;; CHECK-NEXT: (block
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.null none)
;; CHECK-NEXT: )
;; CHECK-NEXT: (block $block0
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (struct.new_default $super.desc)
;; CHECK-NEXT: )
;; CHECK-NEXT: (unreachable)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $refinalize-untaken (result anyref)
(block $block (result anyref)
;; 3) ReFinalize will make this unreachable BrOn a block. The ref.null
;; below needs to be dropped for the block to be valid.
(br_on_cast_desc $block nullref (ref null $super)
(ref.null none)
;; 2) ReFinalize will make this block unreachable because it is no
;; longer a branch target.
(block $block (result (ref $super.desc))
(drop
;; 1) This branch will be optimized out, prompting ReFinalization.
(br_on_cast_fail $block (ref $super.desc) (ref $super.desc)
(struct.new_default $super.desc)
)
)
(unreachable)
)
)
)
)
)