| ;; NOTE: Assertions have been generated by update_lit_checks.py and should not be edited. |
| ;; RUN: wasm-opt %s --strip-refining-casts --traps-never-happen -all -S -o - | filecheck %s --check-prefix TNH |
| ;; RUN: wasm-opt %s --strip-refining-casts -all -S -o - | filecheck %s --check-prefix NO_TNH |
| |
| (module |
| ;; TNH: (type $Super (sub (struct (field i32)))) |
| ;; NO_TNH: (type $Super (sub (struct (field i32)))) |
| (type $Super (sub (struct (field i32)))) |
| ;; TNH: (type $Sub (sub $Super (struct (field i32) (field i64)))) |
| ;; NO_TNH: (type $Sub (sub $Super (struct (field i32) (field i64)))) |
| (type $Sub (sub $Super (struct (field i32) (field i64)))) |
| |
| ;; TNH: (type $Sig (func (param (ref $Super)))) |
| |
| ;; TNH: (type $Container (sub (struct (field (mut (ref null $Super)))))) |
| |
| ;; TNH: (type $Arr (sub (array (mut (ref null $Super))))) |
| |
| ;; TNH: (type $SubSub (sub $Sub (struct (field i32) (field i64) (field f32)))) |
| ;; NO_TNH: (type $Sig (func (param (ref $Super)))) |
| |
| ;; NO_TNH: (type $Container (sub (struct (field (mut (ref null $Super)))))) |
| |
| ;; NO_TNH: (type $Arr (sub (array (mut (ref null $Super))))) |
| |
| ;; NO_TNH: (type $SubSub (sub $Sub (struct (field i32) (field i64) (field f32)))) |
| (type $SubSub (sub $Sub (struct (field i32) (field i64) (field f32)))) |
| ;; NO_TNH: (rec |
| ;; NO_TNH-NEXT: (type $Described (sub (descriptor $Desc) (struct))) |
| |
| ;; NO_TNH: (type $Desc (sub (describes $Described) (struct))) |
| |
| ;; NO_TNH: (type $Sub2 (sub $Super (struct (field i32) (field f64)))) |
| (type $Sub2 (sub $Super (struct (field i32) (field f64)))) |
| (type $Container (sub (struct (field (mut (ref null $Super)))))) |
| (type $Arr (sub (array (mut (ref null $Super))))) |
| (type $Sig (func (param (ref $Super)))) |
| |
| (rec |
| ;; TNH: (rec |
| ;; TNH-NEXT: (type $Described (sub (descriptor $Desc) (struct))) |
| (type $Described (sub (descriptor $Desc) (struct))) |
| ;; TNH: (type $Desc (sub (describes $Described) (struct))) |
| (type $Desc (sub (describes $Described) (struct))) |
| ) |
| |
| (import "binaryen-intrinsics" "call.without.effects" |
| (func $cwe (param (ref $Super)) (param funcref))) |
| |
| ;; TNH: (global $g (mut (ref null $Super)) (ref.null none)) |
| ;; NO_TNH: (global $g (mut (ref null $Super)) (ref.null none)) |
| (global $g (mut (ref null $Super)) (ref.null $Super)) |
| ;; TNH: (global $g-any (mut anyref) (ref.null none)) |
| ;; NO_TNH: (global $g-any (mut anyref) (ref.null none)) |
| (global $g-any (mut anyref) (ref.null any)) |
| ;; TNH: (table $t 1 1 funcref) |
| ;; NO_TNH: (table $t 1 1 funcref) |
| (table $t 1 1 funcref) |
| |
| ;; TNH: (func $callee (type $Sig) (param $s (ref $Super)) |
| ;; TNH-NEXT: (nop) |
| ;; TNH-NEXT: ) |
| ;; NO_TNH: (func $callee (type $Sig) (param $s (ref $Super)) |
| ;; NO_TNH-NEXT: (nop) |
| ;; NO_TNH-NEXT: ) |
| (func $callee (param $s (ref $Super)) |
| (nop) |
| ) |
| |
| ;; TNH: (func $target-sub (type $9) (param $s (ref $Sub)) |
| ;; TNH-NEXT: (nop) |
| ;; TNH-NEXT: ) |
| ;; NO_TNH: (func $target-sub (type $9) (param $s (ref $Sub)) |
| ;; NO_TNH-NEXT: (nop) |
| ;; NO_TNH-NEXT: ) |
| (func $target-sub (param $s (ref $Sub)) |
| (nop) |
| ) |
| |
| ;; TNH: (func $call (type $10) (param $x (ref $Super)) (param $ns (ref null $Super)) (param $any anyref) |
| ;; TNH-NEXT: (call $callee |
| ;; TNH-NEXT: (local.get $x) |
| ;; TNH-NEXT: ) |
| ;; TNH-NEXT: (call $callee |
| ;; TNH-NEXT: (local.get $x) |
| ;; TNH-NEXT: ) |
| ;; TNH-NEXT: (call $callee |
| ;; TNH-NEXT: (ref.as_non_null |
| ;; TNH-NEXT: (local.get $ns) |
| ;; TNH-NEXT: ) |
| ;; TNH-NEXT: ) |
| ;; TNH-NEXT: (call $callee |
| ;; TNH-NEXT: (ref.cast (ref $Sub) |
| ;; TNH-NEXT: (local.get $any) |
| ;; TNH-NEXT: ) |
| ;; TNH-NEXT: ) |
| ;; TNH-NEXT: (call $cwe |
| ;; TNH-NEXT: (ref.cast (ref $Sub) |
| ;; TNH-NEXT: (local.get $x) |
| ;; TNH-NEXT: ) |
| ;; TNH-NEXT: (ref.func $target-sub) |
| ;; TNH-NEXT: ) |
| ;; TNH-NEXT: ) |
| ;; NO_TNH: (func $call (type $10) (param $x (ref $Super)) (param $ns (ref null $Super)) (param $any anyref) |
| ;; NO_TNH-NEXT: (call $callee |
| ;; NO_TNH-NEXT: (ref.cast (ref $Sub) |
| ;; NO_TNH-NEXT: (local.get $x) |
| ;; NO_TNH-NEXT: ) |
| ;; NO_TNH-NEXT: ) |
| ;; NO_TNH-NEXT: (call $callee |
| ;; NO_TNH-NEXT: (ref.cast (ref $SubSub) |
| ;; NO_TNH-NEXT: (ref.cast (ref $Sub) |
| ;; NO_TNH-NEXT: (local.get $x) |
| ;; NO_TNH-NEXT: ) |
| ;; NO_TNH-NEXT: ) |
| ;; NO_TNH-NEXT: ) |
| ;; NO_TNH-NEXT: (call $callee |
| ;; NO_TNH-NEXT: (ref.cast (ref $Sub) |
| ;; NO_TNH-NEXT: (ref.as_non_null |
| ;; NO_TNH-NEXT: (local.get $ns) |
| ;; NO_TNH-NEXT: ) |
| ;; NO_TNH-NEXT: ) |
| ;; NO_TNH-NEXT: ) |
| ;; NO_TNH-NEXT: (call $callee |
| ;; NO_TNH-NEXT: (ref.cast (ref $Sub) |
| ;; NO_TNH-NEXT: (local.get $any) |
| ;; NO_TNH-NEXT: ) |
| ;; NO_TNH-NEXT: ) |
| ;; NO_TNH-NEXT: (call $cwe |
| ;; NO_TNH-NEXT: (ref.cast (ref $Sub) |
| ;; NO_TNH-NEXT: (local.get $x) |
| ;; NO_TNH-NEXT: ) |
| ;; NO_TNH-NEXT: (ref.func $target-sub) |
| ;; NO_TNH-NEXT: ) |
| ;; NO_TNH-NEXT: ) |
| (func $call (param $x (ref $Super)) (param $ns (ref null $Super)) (param $any anyref) |
| ;; The operand $x already satisfies the parameter type (ref $Super), so the |
| ;; downcast to $Sub can be skipped in TNH mode. |
| (call $callee |
| (ref.cast (ref $Sub) |
| (local.get $x) |
| ) |
| ) |
| ;; Chained casts where the innermost operand already satisfies the parameter |
| ;; type are all stripped. |
| (call $callee |
| (ref.cast (ref $SubSub) |
| (ref.cast (ref $Sub) |
| (local.get $x) |
| ) |
| ) |
| ) |
| ;; Here $ns is nullable while the parameter requires (ref $Super), so the |
| ;; outer cast to (ref $Sub) is stripped down to (ref.as_non_null $ns), which |
| ;; is kept because $ns does not satisfy (ref $Super). |
| (call $callee |
| (ref.cast (ref $Sub) |
| (ref.as_non_null |
| (local.get $ns) |
| ) |
| ) |
| ) |
| ;; Here $any is not a subtype of (ref $Super), so the cast must be kept. |
| (call $callee |
| (ref.cast (ref $Sub) |
| (local.get $any) |
| ) |
| ) |
| ;; Arguments of call.without.effects must match the parameters of the actual |
| ;; target, not the intrinsic import, so casts on them must be kept. |
| (call $cwe |
| (ref.cast (ref $Sub) |
| (local.get $x) |
| ) |
| (ref.func $target-sub) |
| ) |
| ) |
| |
| ;; TNH: (func $call-ref (type $11) (param $fn (ref $Sig)) (param $x (ref $Super)) (param $any anyref) |
| ;; TNH-NEXT: (call_ref $Sig |
| ;; TNH-NEXT: (local.get $x) |
| ;; TNH-NEXT: (local.get $fn) |
| ;; TNH-NEXT: ) |
| ;; TNH-NEXT: (call_ref $Sig |
| ;; TNH-NEXT: (ref.cast (ref $Sub) |
| ;; TNH-NEXT: (local.get $any) |
| ;; TNH-NEXT: ) |
| ;; TNH-NEXT: (local.get $fn) |
| ;; TNH-NEXT: ) |
| ;; TNH-NEXT: ) |
| ;; NO_TNH: (func $call-ref (type $11) (param $fn (ref $Sig)) (param $x (ref $Super)) (param $any anyref) |
| ;; NO_TNH-NEXT: (call_ref $Sig |
| ;; NO_TNH-NEXT: (ref.cast (ref $Sub) |
| ;; NO_TNH-NEXT: (local.get $x) |
| ;; NO_TNH-NEXT: ) |
| ;; NO_TNH-NEXT: (local.get $fn) |
| ;; NO_TNH-NEXT: ) |
| ;; NO_TNH-NEXT: (call_ref $Sig |
| ;; NO_TNH-NEXT: (ref.cast (ref $Sub) |
| ;; NO_TNH-NEXT: (local.get $any) |
| ;; NO_TNH-NEXT: ) |
| ;; NO_TNH-NEXT: (local.get $fn) |
| ;; NO_TNH-NEXT: ) |
| ;; NO_TNH-NEXT: ) |
| (func $call-ref (param $fn (ref $Sig)) (param $x (ref $Super)) (param $any anyref) |
| (call_ref $Sig |
| (ref.cast (ref $Sub) |
| (local.get $x) |
| ) |
| (local.get $fn) |
| ) |
| (call_ref $Sig |
| (ref.cast (ref $Sub) |
| (local.get $any) |
| ) |
| (local.get $fn) |
| ) |
| ) |
| |
| ;; TNH: (func $call-indirect (type $12) (param $x (ref $Super)) (param $any anyref) |
| ;; TNH-NEXT: (call_indirect $t (type $Sig) |
| ;; TNH-NEXT: (local.get $x) |
| ;; TNH-NEXT: (i32.const 0) |
| ;; TNH-NEXT: ) |
| ;; TNH-NEXT: (call_indirect $t (type $Sig) |
| ;; TNH-NEXT: (ref.cast (ref $Sub) |
| ;; TNH-NEXT: (local.get $any) |
| ;; TNH-NEXT: ) |
| ;; TNH-NEXT: (i32.const 0) |
| ;; TNH-NEXT: ) |
| ;; TNH-NEXT: ) |
| ;; NO_TNH: (func $call-indirect (type $12) (param $x (ref $Super)) (param $any anyref) |
| ;; NO_TNH-NEXT: (call_indirect $t (type $Sig) |
| ;; NO_TNH-NEXT: (ref.cast (ref $Sub) |
| ;; NO_TNH-NEXT: (local.get $x) |
| ;; NO_TNH-NEXT: ) |
| ;; NO_TNH-NEXT: (i32.const 0) |
| ;; NO_TNH-NEXT: ) |
| ;; NO_TNH-NEXT: (call_indirect $t (type $Sig) |
| ;; NO_TNH-NEXT: (ref.cast (ref $Sub) |
| ;; NO_TNH-NEXT: (local.get $any) |
| ;; NO_TNH-NEXT: ) |
| ;; NO_TNH-NEXT: (i32.const 0) |
| ;; NO_TNH-NEXT: ) |
| ;; NO_TNH-NEXT: ) |
| (func $call-indirect (param $x (ref $Super)) (param $any anyref) |
| (call_indirect $t (type $Sig) |
| (ref.cast (ref $Sub) |
| (local.get $x) |
| ) |
| (i32.const 0) |
| ) |
| (call_indirect $t (type $Sig) |
| (ref.cast (ref $Sub) |
| (local.get $any) |
| ) |
| (i32.const 0) |
| ) |
| ) |
| |
| ;; TNH: (func $return-cast (type $13) (param $x (ref $Super)) (result (ref $Super)) |
| ;; TNH-NEXT: (return |
| ;; TNH-NEXT: (local.get $x) |
| ;; TNH-NEXT: ) |
| ;; TNH-NEXT: ) |
| ;; NO_TNH: (func $return-cast (type $13) (param $x (ref $Super)) (result (ref $Super)) |
| ;; NO_TNH-NEXT: (return |
| ;; NO_TNH-NEXT: (ref.cast (ref $Sub) |
| ;; NO_TNH-NEXT: (local.get $x) |
| ;; NO_TNH-NEXT: ) |
| ;; NO_TNH-NEXT: ) |
| ;; NO_TNH-NEXT: ) |
| (func $return-cast (param $x (ref $Super)) (result (ref $Super)) |
| (return |
| (ref.cast (ref $Sub) |
| (local.get $x) |
| ) |
| ) |
| ) |
| |
| ;; TNH: (func $return-keep (type $14) (param $any anyref) (result (ref $Super)) |
| ;; TNH-NEXT: (return |
| ;; TNH-NEXT: (ref.cast (ref $Sub) |
| ;; TNH-NEXT: (local.get $any) |
| ;; TNH-NEXT: ) |
| ;; TNH-NEXT: ) |
| ;; TNH-NEXT: ) |
| ;; NO_TNH: (func $return-keep (type $14) (param $any anyref) (result (ref $Super)) |
| ;; NO_TNH-NEXT: (return |
| ;; NO_TNH-NEXT: (ref.cast (ref $Sub) |
| ;; NO_TNH-NEXT: (local.get $any) |
| ;; NO_TNH-NEXT: ) |
| ;; NO_TNH-NEXT: ) |
| ;; NO_TNH-NEXT: ) |
| (func $return-keep (param $any anyref) (result (ref $Super)) |
| (return |
| (ref.cast (ref $Sub) |
| (local.get $any) |
| ) |
| ) |
| ) |
| |
| ;; TNH: (func $local-and-global-set (type $15) (param $x (ref $Super)) (param $ns (ref null $Super)) (param $any anyref) (param $ext externref) |
| ;; TNH-NEXT: (local $l (ref null $Super)) |
| ;; TNH-NEXT: (local.set $l |
| ;; TNH-NEXT: (local.get $x) |
| ;; TNH-NEXT: ) |
| ;; TNH-NEXT: (local.set $l |
| ;; TNH-NEXT: (local.get $ns) |
| ;; TNH-NEXT: ) |
| ;; TNH-NEXT: (drop |
| ;; TNH-NEXT: (local.tee $l |
| ;; TNH-NEXT: (local.get $x) |
| ;; TNH-NEXT: ) |
| ;; TNH-NEXT: ) |
| ;; TNH-NEXT: (local.set $l |
| ;; TNH-NEXT: (unreachable) |
| ;; TNH-NEXT: ) |
| ;; TNH-NEXT: (local.set $l |
| ;; TNH-NEXT: (ref.cast (ref $Sub) |
| ;; TNH-NEXT: (local.get $any) |
| ;; TNH-NEXT: ) |
| ;; TNH-NEXT: ) |
| ;; TNH-NEXT: (global.set $g |
| ;; TNH-NEXT: (local.get $x) |
| ;; TNH-NEXT: ) |
| ;; TNH-NEXT: (global.set $g |
| ;; TNH-NEXT: (local.get $ns) |
| ;; TNH-NEXT: ) |
| ;; TNH-NEXT: (global.set $g-any |
| ;; TNH-NEXT: (any.convert_extern |
| ;; TNH-NEXT: (local.get $ext) |
| ;; TNH-NEXT: ) |
| ;; TNH-NEXT: ) |
| ;; TNH-NEXT: ) |
| ;; NO_TNH: (func $local-and-global-set (type $15) (param $x (ref $Super)) (param $ns (ref null $Super)) (param $any anyref) (param $ext externref) |
| ;; NO_TNH-NEXT: (local $l (ref null $Super)) |
| ;; NO_TNH-NEXT: (local.set $l |
| ;; NO_TNH-NEXT: (ref.cast (ref $Sub) |
| ;; NO_TNH-NEXT: (local.get $x) |
| ;; NO_TNH-NEXT: ) |
| ;; NO_TNH-NEXT: ) |
| ;; NO_TNH-NEXT: (local.set $l |
| ;; NO_TNH-NEXT: (ref.as_non_null |
| ;; NO_TNH-NEXT: (local.get $ns) |
| ;; NO_TNH-NEXT: ) |
| ;; NO_TNH-NEXT: ) |
| ;; NO_TNH-NEXT: (drop |
| ;; NO_TNH-NEXT: (local.tee $l |
| ;; NO_TNH-NEXT: (ref.cast (ref $Sub) |
| ;; NO_TNH-NEXT: (local.get $x) |
| ;; NO_TNH-NEXT: ) |
| ;; NO_TNH-NEXT: ) |
| ;; NO_TNH-NEXT: ) |
| ;; NO_TNH-NEXT: (local.set $l |
| ;; NO_TNH-NEXT: (ref.as_non_null |
| ;; NO_TNH-NEXT: (unreachable) |
| ;; NO_TNH-NEXT: ) |
| ;; NO_TNH-NEXT: ) |
| ;; NO_TNH-NEXT: (local.set $l |
| ;; NO_TNH-NEXT: (ref.cast (ref $Sub) |
| ;; NO_TNH-NEXT: (local.get $any) |
| ;; NO_TNH-NEXT: ) |
| ;; NO_TNH-NEXT: ) |
| ;; NO_TNH-NEXT: (global.set $g |
| ;; NO_TNH-NEXT: (ref.cast (ref $Sub) |
| ;; NO_TNH-NEXT: (local.get $x) |
| ;; NO_TNH-NEXT: ) |
| ;; NO_TNH-NEXT: ) |
| ;; NO_TNH-NEXT: (global.set $g |
| ;; NO_TNH-NEXT: (ref.as_non_null |
| ;; NO_TNH-NEXT: (local.get $ns) |
| ;; NO_TNH-NEXT: ) |
| ;; NO_TNH-NEXT: ) |
| ;; NO_TNH-NEXT: (global.set $g-any |
| ;; NO_TNH-NEXT: (any.convert_extern |
| ;; NO_TNH-NEXT: (local.get $ext) |
| ;; NO_TNH-NEXT: ) |
| ;; NO_TNH-NEXT: ) |
| ;; NO_TNH-NEXT: ) |
| (func $local-and-global-set (param $x (ref $Super)) (param $ns (ref null $Super)) (param $any anyref) (param $ext externref) |
| (local $l (ref null $Super)) |
| (local.set $l |
| (ref.cast (ref $Sub) |
| (local.get $x) |
| ) |
| ) |
| (local.set $l |
| (ref.as_non_null |
| (local.get $ns) |
| ) |
| ) |
| ;; In Binaryen IR, local.tee has the type of the local, so its cast is also |
| ;; removed. |
| (drop |
| (local.tee $l |
| (ref.cast (ref $Sub) |
| (local.get $x) |
| ) |
| ) |
| ) |
| ;; An unreachable cast is replaced with its unreachable operand. |
| (local.set $l |
| (ref.as_non_null |
| (unreachable) |
| ) |
| ) |
| ;; Non-subtype operand: cast must be kept. |
| (local.set $l |
| (ref.cast (ref $Sub) |
| (local.get $any) |
| ) |
| ) |
| (global.set $g |
| (ref.cast (ref $Sub) |
| (local.get $x) |
| ) |
| ) |
| (global.set $g |
| (ref.as_non_null |
| (local.get $ns) |
| ) |
| ) |
| ;; Non-RefAsNonNull operations like any.convert_extern must not be removed. |
| (global.set $g-any |
| (any.convert_extern |
| (local.get $ext) |
| ) |
| ) |
| ) |
| |
| ;; TNH: (func $struct-and-array (type $16) (param $c (ref $Container)) (param $a (ref $Arr)) (param $s (ref $Super)) (param $ns (ref null $Super)) (param $any anyref) |
| ;; TNH-NEXT: (struct.set $Container 0 |
| ;; TNH-NEXT: (local.get $c) |
| ;; TNH-NEXT: (local.get $s) |
| ;; TNH-NEXT: ) |
| ;; TNH-NEXT: (struct.set $Container 0 |
| ;; TNH-NEXT: (local.get $c) |
| ;; TNH-NEXT: (local.get $ns) |
| ;; TNH-NEXT: ) |
| ;; TNH-NEXT: (struct.set $Container 0 |
| ;; TNH-NEXT: (local.get $c) |
| ;; TNH-NEXT: (ref.cast (ref $Sub) |
| ;; TNH-NEXT: (local.get $any) |
| ;; TNH-NEXT: ) |
| ;; TNH-NEXT: ) |
| ;; TNH-NEXT: (array.set $Arr |
| ;; TNH-NEXT: (local.get $a) |
| ;; TNH-NEXT: (i32.const 0) |
| ;; TNH-NEXT: (local.get $s) |
| ;; TNH-NEXT: ) |
| ;; TNH-NEXT: (array.set $Arr |
| ;; TNH-NEXT: (local.get $a) |
| ;; TNH-NEXT: (i32.const 0) |
| ;; TNH-NEXT: (ref.cast (ref $Sub) |
| ;; TNH-NEXT: (local.get $any) |
| ;; TNH-NEXT: ) |
| ;; TNH-NEXT: ) |
| ;; TNH-NEXT: (drop |
| ;; TNH-NEXT: (struct.new $Container |
| ;; TNH-NEXT: (local.get $s) |
| ;; TNH-NEXT: ) |
| ;; TNH-NEXT: ) |
| ;; TNH-NEXT: (drop |
| ;; TNH-NEXT: (array.new $Arr |
| ;; TNH-NEXT: (local.get $s) |
| ;; TNH-NEXT: (i32.const 2) |
| ;; TNH-NEXT: ) |
| ;; TNH-NEXT: ) |
| ;; TNH-NEXT: (drop |
| ;; TNH-NEXT: (array.new_fixed $Arr 2 |
| ;; TNH-NEXT: (local.get $s) |
| ;; TNH-NEXT: (local.get $ns) |
| ;; TNH-NEXT: ) |
| ;; TNH-NEXT: ) |
| ;; TNH-NEXT: ) |
| ;; NO_TNH: (func $struct-and-array (type $16) (param $c (ref $Container)) (param $a (ref $Arr)) (param $s (ref $Super)) (param $ns (ref null $Super)) (param $any anyref) |
| ;; NO_TNH-NEXT: (struct.set $Container 0 |
| ;; NO_TNH-NEXT: (local.get $c) |
| ;; NO_TNH-NEXT: (ref.cast (ref $Sub) |
| ;; NO_TNH-NEXT: (local.get $s) |
| ;; NO_TNH-NEXT: ) |
| ;; NO_TNH-NEXT: ) |
| ;; NO_TNH-NEXT: (struct.set $Container 0 |
| ;; NO_TNH-NEXT: (local.get $c) |
| ;; NO_TNH-NEXT: (ref.as_non_null |
| ;; NO_TNH-NEXT: (local.get $ns) |
| ;; NO_TNH-NEXT: ) |
| ;; NO_TNH-NEXT: ) |
| ;; NO_TNH-NEXT: (struct.set $Container 0 |
| ;; NO_TNH-NEXT: (local.get $c) |
| ;; NO_TNH-NEXT: (ref.cast (ref $Sub) |
| ;; NO_TNH-NEXT: (local.get $any) |
| ;; NO_TNH-NEXT: ) |
| ;; NO_TNH-NEXT: ) |
| ;; NO_TNH-NEXT: (array.set $Arr |
| ;; NO_TNH-NEXT: (local.get $a) |
| ;; NO_TNH-NEXT: (i32.const 0) |
| ;; NO_TNH-NEXT: (ref.cast (ref $Sub) |
| ;; NO_TNH-NEXT: (local.get $s) |
| ;; NO_TNH-NEXT: ) |
| ;; NO_TNH-NEXT: ) |
| ;; NO_TNH-NEXT: (array.set $Arr |
| ;; NO_TNH-NEXT: (local.get $a) |
| ;; NO_TNH-NEXT: (i32.const 0) |
| ;; NO_TNH-NEXT: (ref.cast (ref $Sub) |
| ;; NO_TNH-NEXT: (local.get $any) |
| ;; NO_TNH-NEXT: ) |
| ;; NO_TNH-NEXT: ) |
| ;; NO_TNH-NEXT: (drop |
| ;; NO_TNH-NEXT: (struct.new $Container |
| ;; NO_TNH-NEXT: (ref.cast (ref $Sub) |
| ;; NO_TNH-NEXT: (local.get $s) |
| ;; NO_TNH-NEXT: ) |
| ;; NO_TNH-NEXT: ) |
| ;; NO_TNH-NEXT: ) |
| ;; NO_TNH-NEXT: (drop |
| ;; NO_TNH-NEXT: (array.new $Arr |
| ;; NO_TNH-NEXT: (ref.cast (ref $Sub) |
| ;; NO_TNH-NEXT: (local.get $s) |
| ;; NO_TNH-NEXT: ) |
| ;; NO_TNH-NEXT: (i32.const 2) |
| ;; NO_TNH-NEXT: ) |
| ;; NO_TNH-NEXT: ) |
| ;; NO_TNH-NEXT: (drop |
| ;; NO_TNH-NEXT: (array.new_fixed $Arr 2 |
| ;; NO_TNH-NEXT: (ref.cast (ref $Sub) |
| ;; NO_TNH-NEXT: (local.get $s) |
| ;; NO_TNH-NEXT: ) |
| ;; NO_TNH-NEXT: (ref.as_non_null |
| ;; NO_TNH-NEXT: (local.get $ns) |
| ;; NO_TNH-NEXT: ) |
| ;; NO_TNH-NEXT: ) |
| ;; NO_TNH-NEXT: ) |
| ;; NO_TNH-NEXT: ) |
| (func $struct-and-array (param $c (ref $Container)) (param $a (ref $Arr)) (param $s (ref $Super)) (param $ns (ref null $Super)) (param $any anyref) |
| (struct.set $Container 0 |
| (local.get $c) |
| (ref.cast (ref $Sub) |
| (local.get $s) |
| ) |
| ) |
| (struct.set $Container 0 |
| (local.get $c) |
| (ref.as_non_null |
| (local.get $ns) |
| ) |
| ) |
| (struct.set $Container 0 |
| (local.get $c) |
| (ref.cast (ref $Sub) |
| (local.get $any) |
| ) |
| ) |
| (array.set $Arr |
| (local.get $a) |
| (i32.const 0) |
| (ref.cast (ref $Sub) |
| (local.get $s) |
| ) |
| ) |
| (array.set $Arr |
| (local.get $a) |
| (i32.const 0) |
| (ref.cast (ref $Sub) |
| (local.get $any) |
| ) |
| ) |
| (drop |
| (struct.new $Container |
| (ref.cast (ref $Sub) |
| (local.get $s) |
| ) |
| ) |
| ) |
| (drop |
| (array.new $Arr |
| (ref.cast (ref $Sub) |
| (local.get $s) |
| ) |
| (i32.const 2) |
| ) |
| ) |
| (drop |
| (array.new_fixed $Arr 2 |
| (ref.cast (ref $Sub) |
| (local.get $s) |
| ) |
| (ref.as_non_null |
| (local.get $ns) |
| ) |
| ) |
| ) |
| ) |
| |
| ;; TNH: (func $select (type $17) (param $cond i32) (param $a (ref $Super)) (param $b (ref $Super)) (param $any anyref) (result (ref $Super)) |
| ;; TNH-NEXT: (drop |
| ;; TNH-NEXT: (select (result (ref $Super)) |
| ;; TNH-NEXT: (local.get $a) |
| ;; TNH-NEXT: (local.get $b) |
| ;; TNH-NEXT: (local.get $cond) |
| ;; TNH-NEXT: ) |
| ;; TNH-NEXT: ) |
| ;; TNH-NEXT: (select (result (ref $Super)) |
| ;; TNH-NEXT: (ref.cast (ref $Sub) |
| ;; TNH-NEXT: (local.get $any) |
| ;; TNH-NEXT: ) |
| ;; TNH-NEXT: (local.get $b) |
| ;; TNH-NEXT: (local.get $cond) |
| ;; TNH-NEXT: ) |
| ;; TNH-NEXT: ) |
| ;; NO_TNH: (func $select (type $17) (param $cond i32) (param $a (ref $Super)) (param $b (ref $Super)) (param $any anyref) (result (ref $Super)) |
| ;; NO_TNH-NEXT: (drop |
| ;; NO_TNH-NEXT: (select (result (ref $Super)) |
| ;; NO_TNH-NEXT: (ref.cast (ref $Sub) |
| ;; NO_TNH-NEXT: (local.get $a) |
| ;; NO_TNH-NEXT: ) |
| ;; NO_TNH-NEXT: (ref.cast (ref $Sub2) |
| ;; NO_TNH-NEXT: (local.get $b) |
| ;; NO_TNH-NEXT: ) |
| ;; NO_TNH-NEXT: (local.get $cond) |
| ;; NO_TNH-NEXT: ) |
| ;; NO_TNH-NEXT: ) |
| ;; NO_TNH-NEXT: (select (result (ref $Super)) |
| ;; NO_TNH-NEXT: (ref.cast (ref $Sub) |
| ;; NO_TNH-NEXT: (local.get $any) |
| ;; NO_TNH-NEXT: ) |
| ;; NO_TNH-NEXT: (local.get $b) |
| ;; NO_TNH-NEXT: (local.get $cond) |
| ;; NO_TNH-NEXT: ) |
| ;; NO_TNH-NEXT: ) |
| (func $select (param $cond i32) (param $a (ref $Super)) (param $b (ref $Super)) (param $any anyref) (result (ref $Super)) |
| (drop |
| (select (result (ref $Super)) |
| (ref.cast (ref $Sub) |
| (local.get $a) |
| ) |
| (ref.cast (ref $Sub2) |
| (local.get $b) |
| ) |
| (local.get $cond) |
| ) |
| ) |
| ;; Here $any is not a subtype of (ref $Super), so its cast must be kept. |
| (select (result (ref $Super)) |
| (ref.cast (ref $Sub) |
| (local.get $any) |
| ) |
| (local.get $b) |
| (local.get $cond) |
| ) |
| ) |
| |
| ;; TNH: (func $ref-test (type $18) (param $s (ref $Super)) (param $ns (ref null $Super)) |
| ;; TNH-NEXT: (drop |
| ;; TNH-NEXT: (ref.test (ref $SubSub) |
| ;; TNH-NEXT: (local.get $s) |
| ;; TNH-NEXT: ) |
| ;; TNH-NEXT: ) |
| ;; TNH-NEXT: (drop |
| ;; TNH-NEXT: (ref.test (ref $SubSub) |
| ;; TNH-NEXT: (local.get $ns) |
| ;; TNH-NEXT: ) |
| ;; TNH-NEXT: ) |
| ;; TNH-NEXT: (drop |
| ;; TNH-NEXT: (ref.test (ref $SubSub) |
| ;; TNH-NEXT: (local.get $ns) |
| ;; TNH-NEXT: ) |
| ;; TNH-NEXT: ) |
| ;; TNH-NEXT: (drop |
| ;; TNH-NEXT: (ref.test (ref $Super) |
| ;; TNH-NEXT: (ref.as_non_null |
| ;; TNH-NEXT: (local.get $ns) |
| ;; TNH-NEXT: ) |
| ;; TNH-NEXT: ) |
| ;; TNH-NEXT: ) |
| ;; TNH-NEXT: (drop |
| ;; TNH-NEXT: (ref.test (ref none) |
| ;; TNH-NEXT: (ref.cast (ref $Sub) |
| ;; TNH-NEXT: (local.get $s) |
| ;; TNH-NEXT: ) |
| ;; TNH-NEXT: ) |
| ;; TNH-NEXT: ) |
| ;; TNH-NEXT: ) |
| ;; NO_TNH: (func $ref-test (type $19) (param $s (ref $Super)) (param $ns (ref null $Super)) |
| ;; NO_TNH-NEXT: (drop |
| ;; NO_TNH-NEXT: (ref.test (ref $SubSub) |
| ;; NO_TNH-NEXT: (ref.cast (ref $Sub) |
| ;; NO_TNH-NEXT: (local.get $s) |
| ;; NO_TNH-NEXT: ) |
| ;; NO_TNH-NEXT: ) |
| ;; NO_TNH-NEXT: ) |
| ;; NO_TNH-NEXT: (drop |
| ;; NO_TNH-NEXT: (ref.test (ref $SubSub) |
| ;; NO_TNH-NEXT: (ref.cast (ref $Sub) |
| ;; NO_TNH-NEXT: (local.get $ns) |
| ;; NO_TNH-NEXT: ) |
| ;; NO_TNH-NEXT: ) |
| ;; NO_TNH-NEXT: ) |
| ;; NO_TNH-NEXT: (drop |
| ;; NO_TNH-NEXT: (ref.test (ref $SubSub) |
| ;; NO_TNH-NEXT: (ref.as_non_null |
| ;; NO_TNH-NEXT: (local.get $ns) |
| ;; NO_TNH-NEXT: ) |
| ;; NO_TNH-NEXT: ) |
| ;; NO_TNH-NEXT: ) |
| ;; NO_TNH-NEXT: (drop |
| ;; NO_TNH-NEXT: (ref.test (ref $Super) |
| ;; NO_TNH-NEXT: (ref.as_non_null |
| ;; NO_TNH-NEXT: (local.get $ns) |
| ;; NO_TNH-NEXT: ) |
| ;; NO_TNH-NEXT: ) |
| ;; NO_TNH-NEXT: ) |
| ;; NO_TNH-NEXT: (drop |
| ;; NO_TNH-NEXT: (ref.test (ref none) |
| ;; NO_TNH-NEXT: (ref.cast (ref $Sub) |
| ;; NO_TNH-NEXT: (local.get $s) |
| ;; NO_TNH-NEXT: ) |
| ;; NO_TNH-NEXT: ) |
| ;; NO_TNH-NEXT: ) |
| ;; NO_TNH-NEXT: ) |
| (func $ref-test (param $s (ref $Super)) (param $ns (ref null $Super)) |
| ;; Undecided ref.test: casts on the input do not affect the outcome and can |
| ;; be removed. |
| (drop |
| (ref.test (ref $SubSub) |
| (ref.cast (ref $Sub) |
| (local.get $s) |
| ) |
| ) |
| ) |
| (drop |
| (ref.test (ref $SubSub) |
| (ref.cast (ref $Sub) |
| (local.get $ns) |
| ) |
| ) |
| ) |
| (drop |
| (ref.test (ref $SubSub) |
| (ref.as_non_null |
| (local.get $ns) |
| ) |
| ) |
| ) |
| ;; Decided ref.test (always 1 if non-trapping): the ref.as_non_null |
| ;; determines the outcome, so it is left for OptimizeInstructions to |
| ;; resolve. |
| (drop |
| (ref.test (ref $Super) |
| (ref.as_non_null |
| (local.get $ns) |
| ) |
| ) |
| ) |
| ;; Decided ref.test (always 0 if non-trapping): $Sub and $Sub2 are disjoint, |
| ;; so the cast determines the outcome and is left for OptimizeInstructions. |
| (drop |
| (ref.test (ref $Sub2) |
| (ref.cast (ref $Sub) |
| (local.get $s) |
| ) |
| ) |
| ) |
| ) |
| |
| ;; TNH: (func $keep-descriptor-and-unreachable (type $19) (param $c i32) (param $x anyref) (param $d (ref $Desc)) |
| ;; TNH-NEXT: (local $l anyref) |
| ;; TNH-NEXT: (local.set $l |
| ;; TNH-NEXT: (local.get $x) |
| ;; TNH-NEXT: ) |
| ;; TNH-NEXT: (local.set $l |
| ;; TNH-NEXT: (ref.cast_desc_eq (ref $Described) |
| ;; TNH-NEXT: (local.get $x) |
| ;; TNH-NEXT: (block (result (ref $Desc)) |
| ;; TNH-NEXT: (call $callee |
| ;; TNH-NEXT: (struct.new_default $Super) |
| ;; TNH-NEXT: ) |
| ;; TNH-NEXT: (local.get $d) |
| ;; TNH-NEXT: ) |
| ;; TNH-NEXT: ) |
| ;; TNH-NEXT: ) |
| ;; TNH-NEXT: (drop |
| ;; TNH-NEXT: (block ;; (replaces unreachable StructNew we can't emit) |
| ;; TNH-NEXT: (drop |
| ;; TNH-NEXT: (unreachable) |
| ;; TNH-NEXT: ) |
| ;; TNH-NEXT: (unreachable) |
| ;; TNH-NEXT: ) |
| ;; TNH-NEXT: ) |
| ;; TNH-NEXT: (drop |
| ;; TNH-NEXT: (block ;; (replaces unreachable ArrayNew we can't emit) |
| ;; TNH-NEXT: (drop |
| ;; TNH-NEXT: (unreachable) |
| ;; TNH-NEXT: ) |
| ;; TNH-NEXT: (drop |
| ;; TNH-NEXT: (i32.const 1) |
| ;; TNH-NEXT: ) |
| ;; TNH-NEXT: (unreachable) |
| ;; TNH-NEXT: ) |
| ;; TNH-NEXT: ) |
| ;; TNH-NEXT: (drop |
| ;; TNH-NEXT: (block ;; (replaces unreachable ArrayNewFixed we can't emit) |
| ;; TNH-NEXT: (drop |
| ;; TNH-NEXT: (unreachable) |
| ;; TNH-NEXT: ) |
| ;; TNH-NEXT: (unreachable) |
| ;; TNH-NEXT: ) |
| ;; TNH-NEXT: ) |
| ;; TNH-NEXT: (drop |
| ;; TNH-NEXT: (select |
| ;; TNH-NEXT: (ref.as_non_null |
| ;; TNH-NEXT: (local.get $x) |
| ;; TNH-NEXT: ) |
| ;; TNH-NEXT: (unreachable) |
| ;; TNH-NEXT: (local.get $c) |
| ;; TNH-NEXT: ) |
| ;; TNH-NEXT: ) |
| ;; TNH-NEXT: (drop |
| ;; TNH-NEXT: (ref.test (ref $Super) |
| ;; TNH-NEXT: (block ;; (replaces unreachable RefCast we can't emit) |
| ;; TNH-NEXT: (drop |
| ;; TNH-NEXT: (unreachable) |
| ;; TNH-NEXT: ) |
| ;; TNH-NEXT: (unreachable) |
| ;; TNH-NEXT: ) |
| ;; TNH-NEXT: ) |
| ;; TNH-NEXT: ) |
| ;; TNH-NEXT: ) |
| ;; NO_TNH: (func $keep-descriptor-and-unreachable (type $20) (param $c i32) (param $x anyref) (param $d (ref $Desc)) |
| ;; NO_TNH-NEXT: (local $l anyref) |
| ;; NO_TNH-NEXT: (local.set $l |
| ;; NO_TNH-NEXT: (ref.cast_desc_eq (ref $Described) |
| ;; NO_TNH-NEXT: (local.get $x) |
| ;; NO_TNH-NEXT: (local.get $d) |
| ;; NO_TNH-NEXT: ) |
| ;; NO_TNH-NEXT: ) |
| ;; NO_TNH-NEXT: (local.set $l |
| ;; NO_TNH-NEXT: (ref.cast_desc_eq (ref $Described) |
| ;; NO_TNH-NEXT: (local.get $x) |
| ;; NO_TNH-NEXT: (block (result (ref $Desc)) |
| ;; NO_TNH-NEXT: (call $callee |
| ;; NO_TNH-NEXT: (struct.new_default $Super) |
| ;; NO_TNH-NEXT: ) |
| ;; NO_TNH-NEXT: (local.get $d) |
| ;; NO_TNH-NEXT: ) |
| ;; NO_TNH-NEXT: ) |
| ;; NO_TNH-NEXT: ) |
| ;; NO_TNH-NEXT: (drop |
| ;; NO_TNH-NEXT: (block ;; (replaces unreachable StructNew we can't emit) |
| ;; NO_TNH-NEXT: (drop |
| ;; NO_TNH-NEXT: (unreachable) |
| ;; NO_TNH-NEXT: ) |
| ;; NO_TNH-NEXT: (unreachable) |
| ;; NO_TNH-NEXT: ) |
| ;; NO_TNH-NEXT: ) |
| ;; NO_TNH-NEXT: (drop |
| ;; NO_TNH-NEXT: (block ;; (replaces unreachable ArrayNew we can't emit) |
| ;; NO_TNH-NEXT: (drop |
| ;; NO_TNH-NEXT: (unreachable) |
| ;; NO_TNH-NEXT: ) |
| ;; NO_TNH-NEXT: (drop |
| ;; NO_TNH-NEXT: (i32.const 1) |
| ;; NO_TNH-NEXT: ) |
| ;; NO_TNH-NEXT: (unreachable) |
| ;; NO_TNH-NEXT: ) |
| ;; NO_TNH-NEXT: ) |
| ;; NO_TNH-NEXT: (drop |
| ;; NO_TNH-NEXT: (block ;; (replaces unreachable ArrayNewFixed we can't emit) |
| ;; NO_TNH-NEXT: (drop |
| ;; NO_TNH-NEXT: (unreachable) |
| ;; NO_TNH-NEXT: ) |
| ;; NO_TNH-NEXT: (unreachable) |
| ;; NO_TNH-NEXT: ) |
| ;; NO_TNH-NEXT: ) |
| ;; NO_TNH-NEXT: (drop |
| ;; NO_TNH-NEXT: (select |
| ;; NO_TNH-NEXT: (ref.as_non_null |
| ;; NO_TNH-NEXT: (local.get $x) |
| ;; NO_TNH-NEXT: ) |
| ;; NO_TNH-NEXT: (unreachable) |
| ;; NO_TNH-NEXT: (local.get $c) |
| ;; NO_TNH-NEXT: ) |
| ;; NO_TNH-NEXT: ) |
| ;; NO_TNH-NEXT: (drop |
| ;; NO_TNH-NEXT: (ref.test (ref $Super) |
| ;; NO_TNH-NEXT: (block ;; (replaces unreachable RefCast we can't emit) |
| ;; NO_TNH-NEXT: (drop |
| ;; NO_TNH-NEXT: (unreachable) |
| ;; NO_TNH-NEXT: ) |
| ;; NO_TNH-NEXT: (unreachable) |
| ;; NO_TNH-NEXT: ) |
| ;; NO_TNH-NEXT: ) |
| ;; NO_TNH-NEXT: ) |
| ;; NO_TNH-NEXT: ) |
| (func $keep-descriptor-and-unreachable (param $c i32) (param $x anyref) (param $d (ref $Desc)) |
| (local $l anyref) |
| ;; Descriptor casts can be removed if the descriptor has no side effects. |
| (local.set $l |
| (ref.cast_desc_eq (ref $Described) |
| (local.get $x) |
| (local.get $d) |
| ) |
| ) |
| ;; Descriptor casts must not be removed if the descriptor has side effects. |
| (local.set $l |
| (ref.cast_desc_eq (ref $Described) |
| (local.get $x) |
| (block (result (ref $Desc)) |
| (call $callee |
| (struct.new_default $Super) |
| ) |
| (local.get $d) |
| ) |
| ) |
| ) |
| ;; Unreachable expressions must be handled safely. |
| (drop |
| (struct.new $Container |
| (unreachable) |
| ) |
| ) |
| (drop |
| (array.new $Arr |
| (unreachable) |
| (i32.const 1) |
| ) |
| ) |
| (drop |
| (array.new_fixed $Arr 1 |
| (unreachable) |
| ) |
| ) |
| (drop |
| (select (result anyref) |
| (ref.as_non_null |
| (local.get $x) |
| ) |
| (unreachable) |
| (local.get $c) |
| ) |
| ) |
| (drop |
| (ref.test (ref $Super) |
| (ref.cast (ref any) |
| (unreachable) |
| ) |
| ) |
| ) |
| ) |
| |
| ;; TNH: (func $control-flow (type $20) (param $c i32) (param $x (ref $Super)) (param $sub (ref $Sub)) (result (ref $Super)) |
| ;; TNH-NEXT: (drop |
| ;; TNH-NEXT: (if (result (ref $Super)) |
| ;; TNH-NEXT: (local.get $c) |
| ;; TNH-NEXT: (then |
| ;; TNH-NEXT: (local.get $x) |
| ;; TNH-NEXT: ) |
| ;; TNH-NEXT: (else |
| ;; TNH-NEXT: (local.get $x) |
| ;; TNH-NEXT: ) |
| ;; TNH-NEXT: ) |
| ;; TNH-NEXT: ) |
| ;; TNH-NEXT: (drop |
| ;; TNH-NEXT: (try (result (ref $Super)) |
| ;; TNH-NEXT: (do |
| ;; TNH-NEXT: (local.get $x) |
| ;; TNH-NEXT: ) |
| ;; TNH-NEXT: (catch_all |
| ;; TNH-NEXT: (local.get $x) |
| ;; TNH-NEXT: ) |
| ;; TNH-NEXT: ) |
| ;; TNH-NEXT: ) |
| ;; TNH-NEXT: (drop |
| ;; TNH-NEXT: (block $b (result (ref $Super)) |
| ;; TNH-NEXT: (if |
| ;; TNH-NEXT: (local.get $c) |
| ;; TNH-NEXT: (then |
| ;; TNH-NEXT: (br $b |
| ;; TNH-NEXT: (local.get $x) |
| ;; TNH-NEXT: ) |
| ;; TNH-NEXT: ) |
| ;; TNH-NEXT: ) |
| ;; TNH-NEXT: (drop |
| ;; TNH-NEXT: (br_if $b |
| ;; TNH-NEXT: (ref.cast (ref $Sub) |
| ;; TNH-NEXT: (local.get $x) |
| ;; TNH-NEXT: ) |
| ;; TNH-NEXT: (local.get $c) |
| ;; TNH-NEXT: ) |
| ;; TNH-NEXT: ) |
| ;; TNH-NEXT: (local.get $x) |
| ;; TNH-NEXT: ) |
| ;; TNH-NEXT: ) |
| ;; TNH-NEXT: (drop |
| ;; TNH-NEXT: (block $b-super (result (ref $Super)) |
| ;; TNH-NEXT: (block $b-sub (result (ref $Sub)) |
| ;; TNH-NEXT: (br_table $b-super $b-sub |
| ;; TNH-NEXT: (ref.cast (ref $Sub) |
| ;; TNH-NEXT: (local.get $x) |
| ;; TNH-NEXT: ) |
| ;; TNH-NEXT: (local.get $c) |
| ;; TNH-NEXT: ) |
| ;; TNH-NEXT: ) |
| ;; TNH-NEXT: ) |
| ;; TNH-NEXT: ) |
| ;; TNH-NEXT: (local.get $x) |
| ;; TNH-NEXT: ) |
| ;; NO_TNH: (func $control-flow (type $21) (param $c i32) (param $x (ref $Super)) (param $sub (ref $Sub)) (result (ref $Super)) |
| ;; NO_TNH-NEXT: (drop |
| ;; NO_TNH-NEXT: (if (result (ref $Super)) |
| ;; NO_TNH-NEXT: (local.get $c) |
| ;; NO_TNH-NEXT: (then |
| ;; NO_TNH-NEXT: (ref.cast (ref $Sub) |
| ;; NO_TNH-NEXT: (local.get $x) |
| ;; NO_TNH-NEXT: ) |
| ;; NO_TNH-NEXT: ) |
| ;; NO_TNH-NEXT: (else |
| ;; NO_TNH-NEXT: (local.get $x) |
| ;; NO_TNH-NEXT: ) |
| ;; NO_TNH-NEXT: ) |
| ;; NO_TNH-NEXT: ) |
| ;; NO_TNH-NEXT: (drop |
| ;; NO_TNH-NEXT: (try (result (ref $Super)) |
| ;; NO_TNH-NEXT: (do |
| ;; NO_TNH-NEXT: (ref.cast (ref $Sub) |
| ;; NO_TNH-NEXT: (local.get $x) |
| ;; NO_TNH-NEXT: ) |
| ;; NO_TNH-NEXT: ) |
| ;; NO_TNH-NEXT: (catch_all |
| ;; NO_TNH-NEXT: (ref.cast (ref $Sub) |
| ;; NO_TNH-NEXT: (local.get $x) |
| ;; NO_TNH-NEXT: ) |
| ;; NO_TNH-NEXT: ) |
| ;; NO_TNH-NEXT: ) |
| ;; NO_TNH-NEXT: ) |
| ;; NO_TNH-NEXT: (drop |
| ;; NO_TNH-NEXT: (block $b (result (ref $Super)) |
| ;; NO_TNH-NEXT: (if |
| ;; NO_TNH-NEXT: (local.get $c) |
| ;; NO_TNH-NEXT: (then |
| ;; NO_TNH-NEXT: (br $b |
| ;; NO_TNH-NEXT: (ref.cast (ref $Sub) |
| ;; NO_TNH-NEXT: (local.get $x) |
| ;; NO_TNH-NEXT: ) |
| ;; NO_TNH-NEXT: ) |
| ;; NO_TNH-NEXT: ) |
| ;; NO_TNH-NEXT: ) |
| ;; NO_TNH-NEXT: (drop |
| ;; NO_TNH-NEXT: (br_if $b |
| ;; NO_TNH-NEXT: (ref.cast (ref $Sub) |
| ;; NO_TNH-NEXT: (local.get $x) |
| ;; NO_TNH-NEXT: ) |
| ;; NO_TNH-NEXT: (local.get $c) |
| ;; NO_TNH-NEXT: ) |
| ;; NO_TNH-NEXT: ) |
| ;; NO_TNH-NEXT: (local.get $x) |
| ;; NO_TNH-NEXT: ) |
| ;; NO_TNH-NEXT: ) |
| ;; NO_TNH-NEXT: (drop |
| ;; NO_TNH-NEXT: (block $b-super (result (ref $Super)) |
| ;; NO_TNH-NEXT: (block $b-sub (result (ref $Sub)) |
| ;; NO_TNH-NEXT: (br_table $b-super $b-sub |
| ;; NO_TNH-NEXT: (ref.cast (ref $SubSub) |
| ;; NO_TNH-NEXT: (ref.cast (ref $Sub) |
| ;; NO_TNH-NEXT: (local.get $x) |
| ;; NO_TNH-NEXT: ) |
| ;; NO_TNH-NEXT: ) |
| ;; NO_TNH-NEXT: (local.get $c) |
| ;; NO_TNH-NEXT: ) |
| ;; NO_TNH-NEXT: ) |
| ;; NO_TNH-NEXT: ) |
| ;; NO_TNH-NEXT: ) |
| ;; NO_TNH-NEXT: (ref.cast (ref $Sub) |
| ;; NO_TNH-NEXT: (local.get $x) |
| ;; NO_TNH-NEXT: ) |
| ;; NO_TNH-NEXT: ) |
| (func $control-flow (param $c i32) (param $x (ref $Super)) (param $sub (ref $Sub)) (result (ref $Super)) |
| ;; If and try-catch arms flowing into a supertype result can have their |
| ;; casts stripped. |
| (drop |
| (if (result (ref $Super)) |
| (local.get $c) |
| (then |
| (ref.cast (ref $Sub) |
| (local.get $x) |
| ) |
| ) |
| (else |
| (local.get $x) |
| ) |
| ) |
| ) |
| (drop |
| (try (result (ref $Super)) |
| (do |
| (ref.cast (ref $Sub) |
| (local.get $x) |
| ) |
| ) |
| (catch_all |
| (ref.cast (ref $Sub) |
| (local.get $x) |
| ) |
| ) |
| ) |
| ) |
| ;; Unconditional br to a block with a supertype result strips its cast, |
| ;; while br_if keeps its cast because the br_if's own result type in |
| ;; Binaryen IR is the cast type (TODO: optimize through fallthrough |
| ;; expressions like br_if). |
| (drop |
| (block $b (result (ref $Super)) |
| (if |
| (local.get $c) |
| (then |
| (br $b |
| (ref.cast (ref $Sub) |
| (local.get $x) |
| ) |
| ) |
| ) |
| ) |
| (drop |
| (br_if $b |
| (ref.cast (ref $Sub) |
| (local.get $x) |
| ) |
| (local.get $c) |
| ) |
| ) |
| (local.get $x) |
| ) |
| ) |
| ;; br_table strips casts down to the greatest lower bound of all target |
| ;; block types (here (ref $Sub)), keeping the cast to $Sub while stripping |
| ;; the cast to $SubSub. |
| (drop |
| (block $b-super (result (ref $Super)) |
| (block $b-sub (result (ref $Sub)) |
| (br_table $b-super $b-sub |
| (ref.cast (ref $SubSub) |
| (ref.cast (ref $Sub) |
| (local.get $x) |
| ) |
| ) |
| (local.get $c) |
| ) |
| ) |
| ) |
| ) |
| ;; Function body result slot strips its cast. |
| (ref.cast (ref $Sub) |
| (local.get $x) |
| ) |
| ) |
| ) |