diff options
Diffstat (limited to 'test')
-rw-r--r-- | test/lit/help/wasm-opt.test | 3 | ||||
-rw-r--r-- | test/lit/help/wasm2js.test | 3 | ||||
-rw-r--r-- | test/lit/passes/abstract-type-refining.wast | 1293 |
3 files changed, 1299 insertions, 0 deletions
diff --git a/test/lit/help/wasm-opt.test b/test/lit/help/wasm-opt.test index 186382fd4..351f2c93e 100644 --- a/test/lit/help/wasm-opt.test +++ b/test/lit/help/wasm-opt.test @@ -83,6 +83,9 @@ ;; CHECK-NEXT: Optimization passes: ;; CHECK-NEXT: -------------------- ;; CHECK-NEXT: +;; CHECK-NEXT: --abstract-type-refining refine and merge abstract +;; CHECK-NEXT: (never-created) types +;; CHECK-NEXT: ;; CHECK-NEXT: --alignment-lowering lower unaligned loads and stores ;; CHECK-NEXT: to smaller aligned ones ;; CHECK-NEXT: diff --git a/test/lit/help/wasm2js.test b/test/lit/help/wasm2js.test index 501504027..502419cf2 100644 --- a/test/lit/help/wasm2js.test +++ b/test/lit/help/wasm2js.test @@ -42,6 +42,9 @@ ;; CHECK-NEXT: Optimization passes: ;; CHECK-NEXT: -------------------- ;; CHECK-NEXT: +;; CHECK-NEXT: --abstract-type-refining refine and merge abstract +;; CHECK-NEXT: (never-created) types +;; CHECK-NEXT: ;; CHECK-NEXT: --alignment-lowering lower unaligned loads and stores ;; CHECK-NEXT: to smaller aligned ones ;; CHECK-NEXT: diff --git a/test/lit/passes/abstract-type-refining.wast b/test/lit/passes/abstract-type-refining.wast new file mode 100644 index 000000000..f373acd87 --- /dev/null +++ b/test/lit/passes/abstract-type-refining.wast @@ -0,0 +1,1293 @@ +;; NOTE: Assertions have been generated by update_lit_checks.py --all-items and should not be edited. + +;; RUN: foreach %s %t wasm-opt --abstract-type-refining --traps-never-happen -all --closed-world --nominal -S -o - | filecheck %s --check-prefix=YESTNH +;; RUN: foreach %s %t wasm-opt --abstract-type-refining -all --closed-world --nominal -S -o - | filecheck %s --check-prefix=NO_TNH + +;; Run in both TNH and non-TNH mode. + +;; $A :> $B :> $C :> $D :> $E +;; +;; $A and $D have no struct.news, so any operations on them must, in TNH mode, +;; actually refer to a subtype of them (that has a struct.new). As a result, in +;; TNH mode $A and $D will also not be emitted in the output anymore. +(module + ;; NO_TNH: (type $anyref_=>_none (func (param anyref))) + + ;; NO_TNH: (type $A (struct )) + (type $A (struct)) + + ;; YESTNH: (type $B (struct )) + ;; NO_TNH: (type $B (struct_subtype $A)) + (type $B (struct_subtype $A)) + + ;; YESTNH: (type $anyref_=>_none (func (param anyref))) + + ;; YESTNH: (type $C (struct_subtype $B)) + ;; NO_TNH: (type $C (struct_subtype $B)) + (type $C (struct_subtype $B)) + + ;; NO_TNH: (type $D (struct_subtype $C)) + (type $D (struct_subtype $C)) + + ;; YESTNH: (type $E (struct_subtype $C)) + ;; NO_TNH: (type $E (struct_subtype $D)) + (type $E (struct_subtype $D)) + + ;; YESTNH: (type $none_=>_none (func)) + + ;; YESTNH: (global $global anyref (struct.new_default $B)) + ;; NO_TNH: (type $none_=>_none (func)) + + ;; NO_TNH: (global $global anyref (struct.new_default $B)) + (global $global anyref (struct.new $B)) + + ;; YESTNH: (func $new (type $anyref_=>_none) (param $x anyref) + ;; YESTNH-NEXT: (drop + ;; YESTNH-NEXT: (struct.new_default $C) + ;; YESTNH-NEXT: ) + ;; YESTNH-NEXT: (drop + ;; YESTNH-NEXT: (struct.new_default $E) + ;; YESTNH-NEXT: ) + ;; YESTNH-NEXT: ) + ;; NO_TNH: (func $new (type $anyref_=>_none) (param $x anyref) + ;; NO_TNH-NEXT: (drop + ;; NO_TNH-NEXT: (struct.new_default $C) + ;; NO_TNH-NEXT: ) + ;; NO_TNH-NEXT: (drop + ;; NO_TNH-NEXT: (struct.new_default $E) + ;; NO_TNH-NEXT: ) + ;; NO_TNH-NEXT: ) + (func $new (param $x anyref) + (drop + (struct.new $C) + ) + (drop + (struct.new $E) + ) + ) + + ;; YESTNH: (func $ref.cast (type $anyref_=>_none) (param $x anyref) + ;; YESTNH-NEXT: (drop + ;; YESTNH-NEXT: (ref.cast $B + ;; YESTNH-NEXT: (local.get $x) + ;; YESTNH-NEXT: ) + ;; YESTNH-NEXT: ) + ;; YESTNH-NEXT: (drop + ;; YESTNH-NEXT: (ref.cast $B + ;; YESTNH-NEXT: (local.get $x) + ;; YESTNH-NEXT: ) + ;; YESTNH-NEXT: ) + ;; YESTNH-NEXT: (drop + ;; YESTNH-NEXT: (ref.cast $C + ;; YESTNH-NEXT: (local.get $x) + ;; YESTNH-NEXT: ) + ;; YESTNH-NEXT: ) + ;; YESTNH-NEXT: (drop + ;; YESTNH-NEXT: (ref.cast $E + ;; YESTNH-NEXT: (local.get $x) + ;; YESTNH-NEXT: ) + ;; YESTNH-NEXT: ) + ;; YESTNH-NEXT: (drop + ;; YESTNH-NEXT: (ref.cast $E + ;; YESTNH-NEXT: (local.get $x) + ;; YESTNH-NEXT: ) + ;; YESTNH-NEXT: ) + ;; YESTNH-NEXT: ) + ;; NO_TNH: (func $ref.cast (type $anyref_=>_none) (param $x anyref) + ;; NO_TNH-NEXT: (drop + ;; NO_TNH-NEXT: (ref.cast $A + ;; NO_TNH-NEXT: (local.get $x) + ;; NO_TNH-NEXT: ) + ;; NO_TNH-NEXT: ) + ;; NO_TNH-NEXT: (drop + ;; NO_TNH-NEXT: (ref.cast $B + ;; NO_TNH-NEXT: (local.get $x) + ;; NO_TNH-NEXT: ) + ;; NO_TNH-NEXT: ) + ;; NO_TNH-NEXT: (drop + ;; NO_TNH-NEXT: (ref.cast $C + ;; NO_TNH-NEXT: (local.get $x) + ;; NO_TNH-NEXT: ) + ;; NO_TNH-NEXT: ) + ;; NO_TNH-NEXT: (drop + ;; NO_TNH-NEXT: (ref.cast $D + ;; NO_TNH-NEXT: (local.get $x) + ;; NO_TNH-NEXT: ) + ;; NO_TNH-NEXT: ) + ;; NO_TNH-NEXT: (drop + ;; NO_TNH-NEXT: (ref.cast $E + ;; NO_TNH-NEXT: (local.get $x) + ;; NO_TNH-NEXT: ) + ;; NO_TNH-NEXT: ) + ;; NO_TNH-NEXT: ) + (func $ref.cast (param $x anyref) + ;; List out all possible casts for comprehensiveness. For other instructions + ;; we are more focused, below. + (drop + (ref.cast $A ;; This will be $B in TNH. + (local.get $x) + ) + ) + (drop + (ref.cast $B + (local.get $x) + ) + ) + (drop + (ref.cast $C + (local.get $x) + ) + ) + (drop + (ref.cast $D ;; This will be $E in TNH. + (local.get $x) + ) + ) + (drop + (ref.cast $E + (local.get $x) + ) + ) + ) + + ;; YESTNH: (func $ref.test (type $anyref_=>_none) (param $x anyref) + ;; YESTNH-NEXT: (drop + ;; YESTNH-NEXT: (ref.test $B + ;; YESTNH-NEXT: (local.get $x) + ;; YESTNH-NEXT: ) + ;; YESTNH-NEXT: ) + ;; YESTNH-NEXT: ) + ;; NO_TNH: (func $ref.test (type $anyref_=>_none) (param $x anyref) + ;; NO_TNH-NEXT: (drop + ;; NO_TNH-NEXT: (ref.test $A + ;; NO_TNH-NEXT: (local.get $x) + ;; NO_TNH-NEXT: ) + ;; NO_TNH-NEXT: ) + ;; NO_TNH-NEXT: ) + (func $ref.test (param $x anyref) + (drop + (ref.test $A + (local.get $x) + ) + ) + ) + + ;; YESTNH: (func $br_on (type $anyref_=>_none) (param $x anyref) + ;; YESTNH-NEXT: (drop + ;; YESTNH-NEXT: (block $block (result (ref $B)) + ;; YESTNH-NEXT: (drop + ;; YESTNH-NEXT: (br_on_cast $block $B + ;; YESTNH-NEXT: (local.get $x) + ;; YESTNH-NEXT: ) + ;; YESTNH-NEXT: ) + ;; YESTNH-NEXT: (unreachable) + ;; YESTNH-NEXT: ) + ;; YESTNH-NEXT: ) + ;; YESTNH-NEXT: ) + ;; NO_TNH: (func $br_on (type $anyref_=>_none) (param $x anyref) + ;; NO_TNH-NEXT: (drop + ;; NO_TNH-NEXT: (block $block (result anyref) + ;; NO_TNH-NEXT: (drop + ;; NO_TNH-NEXT: (br_on_cast $block $A + ;; NO_TNH-NEXT: (local.get $x) + ;; NO_TNH-NEXT: ) + ;; NO_TNH-NEXT: ) + ;; NO_TNH-NEXT: (unreachable) + ;; NO_TNH-NEXT: ) + ;; NO_TNH-NEXT: ) + ;; NO_TNH-NEXT: ) + (func $br_on (param $x anyref) + (drop + (block $block (result anyref) + (drop + (br_on_cast $block $A + (local.get $x) + ) + ) + (unreachable) + ) + ) + ) + + ;; YESTNH: (func $basic (type $anyref_=>_none) (param $x anyref) + ;; YESTNH-NEXT: (drop + ;; YESTNH-NEXT: (ref.cast struct + ;; YESTNH-NEXT: (local.get $x) + ;; YESTNH-NEXT: ) + ;; YESTNH-NEXT: ) + ;; YESTNH-NEXT: (drop + ;; YESTNH-NEXT: (ref.as_i31 + ;; YESTNH-NEXT: (local.get $x) + ;; YESTNH-NEXT: ) + ;; YESTNH-NEXT: ) + ;; YESTNH-NEXT: ) + ;; NO_TNH: (func $basic (type $anyref_=>_none) (param $x anyref) + ;; NO_TNH-NEXT: (drop + ;; NO_TNH-NEXT: (ref.cast struct + ;; NO_TNH-NEXT: (local.get $x) + ;; NO_TNH-NEXT: ) + ;; NO_TNH-NEXT: ) + ;; NO_TNH-NEXT: (drop + ;; NO_TNH-NEXT: (ref.as_i31 + ;; NO_TNH-NEXT: (local.get $x) + ;; NO_TNH-NEXT: ) + ;; NO_TNH-NEXT: ) + ;; NO_TNH-NEXT: ) + (func $basic (param $x anyref) + ;; Casts to basic types should not be modified. + (drop + (ref.cast struct + (local.get $x) + ) + ) + (drop + (ref.as_i31 + (local.get $x) + ) + ) + ) + + ;; YESTNH: (func $locals (type $none_=>_none) + ;; YESTNH-NEXT: (local $A (ref $B)) + ;; YESTNH-NEXT: (local $B (ref $B)) + ;; YESTNH-NEXT: (local $C (ref $C)) + ;; YESTNH-NEXT: (local $D (ref $E)) + ;; YESTNH-NEXT: (local $E (ref $E)) + ;; YESTNH-NEXT: (nop) + ;; YESTNH-NEXT: ) + ;; NO_TNH: (func $locals (type $none_=>_none) + ;; NO_TNH-NEXT: (local $A (ref $A)) + ;; NO_TNH-NEXT: (local $B (ref $B)) + ;; NO_TNH-NEXT: (local $C (ref $C)) + ;; NO_TNH-NEXT: (local $D (ref $D)) + ;; NO_TNH-NEXT: (local $E (ref $E)) + ;; NO_TNH-NEXT: (nop) + ;; NO_TNH-NEXT: ) + (func $locals + ;; Local variable types are also updated. + (local $A (ref $A)) + (local $B (ref $B)) + (local $C (ref $C)) + (local $D (ref $D)) + (local $E (ref $E)) + ) +) + +;; $A has two subtypes. As a result, we cannot optimize it. +(module + ;; YESTNH: (type $A (struct )) + ;; NO_TNH: (type $A (struct )) + (type $A (struct)) + + ;; YESTNH: (type $B (struct_subtype $A)) + ;; NO_TNH: (type $B (struct_subtype $A)) + (type $B (struct_subtype $A)) + + ;; YESTNH: (type $anyref_=>_none (func (param anyref))) + + ;; YESTNH: (type $B1 (struct_subtype $A)) + ;; NO_TNH: (type $anyref_=>_none (func (param anyref))) + + ;; NO_TNH: (type $B1 (struct_subtype $A)) + (type $B1 (struct_subtype $A)) ;; this is a new type + + ;; YESTNH: (global $global anyref (struct.new_default $B)) + ;; NO_TNH: (global $global anyref (struct.new_default $B)) + (global $global anyref (struct.new $B)) + + ;; YESTNH: (func $new (type $anyref_=>_none) (param $x anyref) + ;; YESTNH-NEXT: (drop + ;; YESTNH-NEXT: (struct.new_default $B1) + ;; YESTNH-NEXT: ) + ;; YESTNH-NEXT: ) + ;; NO_TNH: (func $new (type $anyref_=>_none) (param $x anyref) + ;; NO_TNH-NEXT: (drop + ;; NO_TNH-NEXT: (struct.new_default $B1) + ;; NO_TNH-NEXT: ) + ;; NO_TNH-NEXT: ) + (func $new (param $x anyref) + (drop + (struct.new $B1) + ) + ) + + ;; YESTNH: (func $ref.cast (type $anyref_=>_none) (param $x anyref) + ;; YESTNH-NEXT: (drop + ;; YESTNH-NEXT: (ref.cast $A + ;; YESTNH-NEXT: (local.get $x) + ;; YESTNH-NEXT: ) + ;; YESTNH-NEXT: ) + ;; YESTNH-NEXT: (drop + ;; YESTNH-NEXT: (ref.cast $B + ;; YESTNH-NEXT: (local.get $x) + ;; YESTNH-NEXT: ) + ;; YESTNH-NEXT: ) + ;; YESTNH-NEXT: (drop + ;; YESTNH-NEXT: (ref.cast $B1 + ;; YESTNH-NEXT: (local.get $x) + ;; YESTNH-NEXT: ) + ;; YESTNH-NEXT: ) + ;; YESTNH-NEXT: ) + ;; NO_TNH: (func $ref.cast (type $anyref_=>_none) (param $x anyref) + ;; NO_TNH-NEXT: (drop + ;; NO_TNH-NEXT: (ref.cast $A + ;; NO_TNH-NEXT: (local.get $x) + ;; NO_TNH-NEXT: ) + ;; NO_TNH-NEXT: ) + ;; NO_TNH-NEXT: (drop + ;; NO_TNH-NEXT: (ref.cast $B + ;; NO_TNH-NEXT: (local.get $x) + ;; NO_TNH-NEXT: ) + ;; NO_TNH-NEXT: ) + ;; NO_TNH-NEXT: (drop + ;; NO_TNH-NEXT: (ref.cast $B1 + ;; NO_TNH-NEXT: (local.get $x) + ;; NO_TNH-NEXT: ) + ;; NO_TNH-NEXT: ) + ;; NO_TNH-NEXT: ) + (func $ref.cast (param $x anyref) + (drop + (ref.cast $A ;; This will not be optimized like before. + (local.get $x) + ) + ) + (drop + (ref.cast $B + (local.get $x) + ) + ) + (drop + (ref.cast $B1 + (local.get $x) + ) + ) + ) +) + +;; As above, but now $B is never created, so we can optimize casts of $A to +;; $B1. +(module + ;; NO_TNH: (type $anyref_=>_none (func (param anyref))) + + ;; NO_TNH: (type $A (struct )) + (type $A (struct)) + + (type $B (struct_subtype $A)) + + ;; YESTNH: (type $B1 (struct )) + ;; NO_TNH: (type $B1 (struct_subtype $A)) + (type $B1 (struct_subtype $A)) ;; this is a new type + + ;; YESTNH: (type $anyref_=>_none (func (param anyref))) + + ;; YESTNH: (func $new (type $anyref_=>_none) (param $x anyref) + ;; YESTNH-NEXT: (drop + ;; YESTNH-NEXT: (struct.new_default $B1) + ;; YESTNH-NEXT: ) + ;; YESTNH-NEXT: ) + ;; NO_TNH: (func $new (type $anyref_=>_none) (param $x anyref) + ;; NO_TNH-NEXT: (drop + ;; NO_TNH-NEXT: (struct.new_default $B1) + ;; NO_TNH-NEXT: ) + ;; NO_TNH-NEXT: ) + (func $new (param $x anyref) + (drop + (struct.new $B1) + ) + ) + + ;; YESTNH: (func $ref.cast (type $anyref_=>_none) (param $x anyref) + ;; YESTNH-NEXT: (drop + ;; YESTNH-NEXT: (ref.cast $B1 + ;; YESTNH-NEXT: (local.get $x) + ;; YESTNH-NEXT: ) + ;; YESTNH-NEXT: ) + ;; YESTNH-NEXT: (drop + ;; YESTNH-NEXT: (ref.cast none + ;; YESTNH-NEXT: (local.get $x) + ;; YESTNH-NEXT: ) + ;; YESTNH-NEXT: ) + ;; YESTNH-NEXT: (drop + ;; YESTNH-NEXT: (ref.cast $B1 + ;; YESTNH-NEXT: (local.get $x) + ;; YESTNH-NEXT: ) + ;; YESTNH-NEXT: ) + ;; YESTNH-NEXT: ) + ;; NO_TNH: (func $ref.cast (type $anyref_=>_none) (param $x anyref) + ;; NO_TNH-NEXT: (drop + ;; NO_TNH-NEXT: (ref.cast $A + ;; NO_TNH-NEXT: (local.get $x) + ;; NO_TNH-NEXT: ) + ;; NO_TNH-NEXT: ) + ;; NO_TNH-NEXT: (drop + ;; NO_TNH-NEXT: (ref.cast none + ;; NO_TNH-NEXT: (local.get $x) + ;; NO_TNH-NEXT: ) + ;; NO_TNH-NEXT: ) + ;; NO_TNH-NEXT: (drop + ;; NO_TNH-NEXT: (ref.cast $B1 + ;; NO_TNH-NEXT: (local.get $x) + ;; NO_TNH-NEXT: ) + ;; NO_TNH-NEXT: ) + ;; NO_TNH-NEXT: ) + (func $ref.cast (param $x anyref) + (drop + (ref.cast $A ;; This will be optimized to $B1. + (local.get $x) + ) + ) + (drop + (ref.cast $B ;; $B is never created, so this will trap, in both TNH + (local.get $x) ;; and non-TNH modes. + ) + ) + (drop + (ref.cast $B1 + (local.get $x) + ) + ) + ) +) + +;; A chain, $A :> $B :> $C, where we can optimize $A all the way to $C. +(module + ;; NO_TNH: (type $anyref_=>_none (func (param anyref))) + + ;; NO_TNH: (type $A (struct )) + (type $A (struct)) + + ;; NO_TNH: (type $B (struct_subtype $A)) + (type $B (struct_subtype $A)) + + ;; YESTNH: (type $C (struct )) + ;; NO_TNH: (type $C (struct_subtype $B)) + (type $C (struct_subtype $B)) + + ;; YESTNH: (type $anyref_=>_none (func (param anyref))) + + ;; YESTNH: (func $new (type $anyref_=>_none) (param $x anyref) + ;; YESTNH-NEXT: (drop + ;; YESTNH-NEXT: (struct.new_default $C) + ;; YESTNH-NEXT: ) + ;; YESTNH-NEXT: ) + ;; NO_TNH: (func $new (type $anyref_=>_none) (param $x anyref) + ;; NO_TNH-NEXT: (drop + ;; NO_TNH-NEXT: (struct.new_default $C) + ;; NO_TNH-NEXT: ) + ;; NO_TNH-NEXT: ) + (func $new (param $x anyref) + (drop + (struct.new $C) + ) + ) + + ;; YESTNH: (func $ref.cast (type $anyref_=>_none) (param $x anyref) + ;; YESTNH-NEXT: (drop + ;; YESTNH-NEXT: (ref.cast $C + ;; YESTNH-NEXT: (local.get $x) + ;; YESTNH-NEXT: ) + ;; YESTNH-NEXT: ) + ;; YESTNH-NEXT: (drop + ;; YESTNH-NEXT: (ref.cast $C + ;; YESTNH-NEXT: (local.get $x) + ;; YESTNH-NEXT: ) + ;; YESTNH-NEXT: ) + ;; YESTNH-NEXT: (drop + ;; YESTNH-NEXT: (ref.cast $C + ;; YESTNH-NEXT: (local.get $x) + ;; YESTNH-NEXT: ) + ;; YESTNH-NEXT: ) + ;; YESTNH-NEXT: ) + ;; NO_TNH: (func $ref.cast (type $anyref_=>_none) (param $x anyref) + ;; NO_TNH-NEXT: (drop + ;; NO_TNH-NEXT: (ref.cast $A + ;; NO_TNH-NEXT: (local.get $x) + ;; NO_TNH-NEXT: ) + ;; NO_TNH-NEXT: ) + ;; NO_TNH-NEXT: (drop + ;; NO_TNH-NEXT: (ref.cast $B + ;; NO_TNH-NEXT: (local.get $x) + ;; NO_TNH-NEXT: ) + ;; NO_TNH-NEXT: ) + ;; NO_TNH-NEXT: (drop + ;; NO_TNH-NEXT: (ref.cast $C + ;; NO_TNH-NEXT: (local.get $x) + ;; NO_TNH-NEXT: ) + ;; NO_TNH-NEXT: ) + ;; NO_TNH-NEXT: ) + (func $ref.cast (param $x anyref) + (drop + (ref.cast $A ;; This can be $C. + (local.get $x) + ) + ) + (drop + (ref.cast $B ;; This can also be $C. + (local.get $x) + ) + ) + (drop + (ref.cast $C + (local.get $x) + ) + ) + ) +) + +;; More testing for cases where no types or subtypes are created. No type is +;; created here. No type needs to be emitted in the output. +(module + (type $A (struct)) + + (type $B (struct_subtype $A)) + + (type $C1 (struct_subtype $B)) + + (type $C2 (struct_subtype $B)) + + ;; YESTNH: (type $anyref_=>_none (func (param anyref))) + + ;; YESTNH: (type $none_=>_none (func)) + + ;; YESTNH: (func $ref.cast (type $anyref_=>_none) (param $x anyref) + ;; YESTNH-NEXT: (drop + ;; YESTNH-NEXT: (ref.cast none + ;; YESTNH-NEXT: (local.get $x) + ;; YESTNH-NEXT: ) + ;; YESTNH-NEXT: ) + ;; YESTNH-NEXT: (drop + ;; YESTNH-NEXT: (ref.cast none + ;; YESTNH-NEXT: (local.get $x) + ;; YESTNH-NEXT: ) + ;; YESTNH-NEXT: ) + ;; YESTNH-NEXT: (drop + ;; YESTNH-NEXT: (ref.cast none + ;; YESTNH-NEXT: (local.get $x) + ;; YESTNH-NEXT: ) + ;; YESTNH-NEXT: ) + ;; YESTNH-NEXT: (drop + ;; YESTNH-NEXT: (ref.cast none + ;; YESTNH-NEXT: (local.get $x) + ;; YESTNH-NEXT: ) + ;; YESTNH-NEXT: ) + ;; YESTNH-NEXT: ) + ;; NO_TNH: (type $anyref_=>_none (func (param anyref))) + + ;; NO_TNH: (type $none_=>_none (func)) + + ;; NO_TNH: (func $ref.cast (type $anyref_=>_none) (param $x anyref) + ;; NO_TNH-NEXT: (drop + ;; NO_TNH-NEXT: (ref.cast none + ;; NO_TNH-NEXT: (local.get $x) + ;; NO_TNH-NEXT: ) + ;; NO_TNH-NEXT: ) + ;; NO_TNH-NEXT: (drop + ;; NO_TNH-NEXT: (ref.cast none + ;; NO_TNH-NEXT: (local.get $x) + ;; NO_TNH-NEXT: ) + ;; NO_TNH-NEXT: ) + ;; NO_TNH-NEXT: (drop + ;; NO_TNH-NEXT: (ref.cast none + ;; NO_TNH-NEXT: (local.get $x) + ;; NO_TNH-NEXT: ) + ;; NO_TNH-NEXT: ) + ;; NO_TNH-NEXT: (drop + ;; NO_TNH-NEXT: (ref.cast none + ;; NO_TNH-NEXT: (local.get $x) + ;; NO_TNH-NEXT: ) + ;; NO_TNH-NEXT: ) + ;; NO_TNH-NEXT: ) + (func $ref.cast (param $x anyref) + ;; All these will trap. + (drop + (ref.cast $A + (local.get $x) + ) + ) + (drop + (ref.cast $B + (local.get $x) + ) + ) + (drop + (ref.cast $C1 + (local.get $x) + ) + ) + (drop + (ref.cast $C2 + (local.get $x) + ) + ) + ) + + ;; YESTNH: (func $ref.cast.null (type $anyref_=>_none) (param $x anyref) + ;; YESTNH-NEXT: (drop + ;; YESTNH-NEXT: (ref.cast null none + ;; YESTNH-NEXT: (local.get $x) + ;; YESTNH-NEXT: ) + ;; YESTNH-NEXT: ) + ;; YESTNH-NEXT: (drop + ;; YESTNH-NEXT: (ref.cast null none + ;; YESTNH-NEXT: (local.get $x) + ;; YESTNH-NEXT: ) + ;; YESTNH-NEXT: ) + ;; YESTNH-NEXT: (drop + ;; YESTNH-NEXT: (ref.cast null none + ;; YESTNH-NEXT: (local.get $x) + ;; YESTNH-NEXT: ) + ;; YESTNH-NEXT: ) + ;; YESTNH-NEXT: (drop + ;; YESTNH-NEXT: (ref.cast null none + ;; YESTNH-NEXT: (local.get $x) + ;; YESTNH-NEXT: ) + ;; YESTNH-NEXT: ) + ;; YESTNH-NEXT: ) + ;; NO_TNH: (func $ref.cast.null (type $anyref_=>_none) (param $x anyref) + ;; NO_TNH-NEXT: (drop + ;; NO_TNH-NEXT: (ref.cast null none + ;; NO_TNH-NEXT: (local.get $x) + ;; NO_TNH-NEXT: ) + ;; NO_TNH-NEXT: ) + ;; NO_TNH-NEXT: (drop + ;; NO_TNH-NEXT: (ref.cast null none + ;; NO_TNH-NEXT: (local.get $x) + ;; NO_TNH-NEXT: ) + ;; NO_TNH-NEXT: ) + ;; NO_TNH-NEXT: (drop + ;; NO_TNH-NEXT: (ref.cast null none + ;; NO_TNH-NEXT: (local.get $x) + ;; NO_TNH-NEXT: ) + ;; NO_TNH-NEXT: ) + ;; NO_TNH-NEXT: (drop + ;; NO_TNH-NEXT: (ref.cast null none + ;; NO_TNH-NEXT: (local.get $x) + ;; NO_TNH-NEXT: ) + ;; NO_TNH-NEXT: ) + ;; NO_TNH-NEXT: ) + (func $ref.cast.null (param $x anyref) + ;; These can only pass through a null. + (drop + (ref.cast null $A + (local.get $x) + ) + ) + (drop + (ref.cast null $B + (local.get $x) + ) + ) + (drop + (ref.cast null $C1 + (local.get $x) + ) + ) + (drop + (ref.cast null $C2 + (local.get $x) + ) + ) + ) + + ;; YESTNH: (func $ref.test (type $anyref_=>_none) (param $x anyref) + ;; YESTNH-NEXT: (drop + ;; YESTNH-NEXT: (ref.test none + ;; YESTNH-NEXT: (local.get $x) + ;; YESTNH-NEXT: ) + ;; YESTNH-NEXT: ) + ;; YESTNH-NEXT: (drop + ;; YESTNH-NEXT: (ref.test null none + ;; YESTNH-NEXT: (local.get $x) + ;; YESTNH-NEXT: ) + ;; YESTNH-NEXT: ) + ;; YESTNH-NEXT: ) + ;; NO_TNH: (func $ref.test (type $anyref_=>_none) (param $x anyref) + ;; NO_TNH-NEXT: (drop + ;; NO_TNH-NEXT: (ref.test none + ;; NO_TNH-NEXT: (local.get $x) + ;; NO_TNH-NEXT: ) + ;; NO_TNH-NEXT: ) + ;; NO_TNH-NEXT: (drop + ;; NO_TNH-NEXT: (ref.test null none + ;; NO_TNH-NEXT: (local.get $x) + ;; NO_TNH-NEXT: ) + ;; NO_TNH-NEXT: ) + ;; NO_TNH-NEXT: ) + (func $ref.test (param $x anyref) + ;; This will return 0. + (drop + (ref.test $A + (local.get $x) + ) + ) + ;; This can test for a null. + (drop + (ref.test null $A + (local.get $x) + ) + ) + ) + + ;; YESTNH: (func $br_on (type $anyref_=>_none) (param $x anyref) + ;; YESTNH-NEXT: (drop + ;; YESTNH-NEXT: (block $block (result (ref none)) + ;; YESTNH-NEXT: (drop + ;; YESTNH-NEXT: (br_on_cast $block none + ;; YESTNH-NEXT: (local.get $x) + ;; YESTNH-NEXT: ) + ;; YESTNH-NEXT: ) + ;; YESTNH-NEXT: (unreachable) + ;; YESTNH-NEXT: ) + ;; YESTNH-NEXT: ) + ;; YESTNH-NEXT: (drop + ;; YESTNH-NEXT: (block $block0 (result (ref any)) + ;; YESTNH-NEXT: (br_on_non_null $block0 + ;; YESTNH-NEXT: (local.get $x) + ;; YESTNH-NEXT: ) + ;; YESTNH-NEXT: (unreachable) + ;; YESTNH-NEXT: ) + ;; YESTNH-NEXT: ) + ;; YESTNH-NEXT: ) + ;; NO_TNH: (func $br_on (type $anyref_=>_none) (param $x anyref) + ;; NO_TNH-NEXT: (drop + ;; NO_TNH-NEXT: (block $block (result (ref none)) + ;; NO_TNH-NEXT: (drop + ;; NO_TNH-NEXT: (br_on_cast $block none + ;; NO_TNH-NEXT: (local.get $x) + ;; NO_TNH-NEXT: ) + ;; NO_TNH-NEXT: ) + ;; NO_TNH-NEXT: (unreachable) + ;; NO_TNH-NEXT: ) + ;; NO_TNH-NEXT: ) + ;; NO_TNH-NEXT: (drop + ;; NO_TNH-NEXT: (block $block0 (result (ref any)) + ;; NO_TNH-NEXT: (br_on_non_null $block0 + ;; NO_TNH-NEXT: (local.get $x) + ;; NO_TNH-NEXT: ) + ;; NO_TNH-NEXT: (unreachable) + ;; NO_TNH-NEXT: ) + ;; NO_TNH-NEXT: ) + ;; NO_TNH-NEXT: ) + (func $br_on (param $x anyref) + ;; As above, this can be a cast to the bottom type. + (drop + (block $block (result anyref) + (drop + (br_on_cast $block $B + (local.get $x) + ) + ) + (unreachable) + ) + ) + ;; Non-cast br_on* can be ignored. + (drop + (block $block (result anyref) + (br_on_non_null $block + (local.get $x) + ) + (unreachable) + ) + ) + ) + + ;; YESTNH: (func $locals (type $none_=>_none) + ;; YESTNH-NEXT: (local $A (ref none)) + ;; YESTNH-NEXT: (local $B (ref none)) + ;; YESTNH-NEXT: (local $C1 (ref none)) + ;; YESTNH-NEXT: (local $C2 nullref) + ;; YESTNH-NEXT: (nop) + ;; YESTNH-NEXT: ) + ;; NO_TNH: (func $locals (type $none_=>_none) + ;; NO_TNH-NEXT: (local $A (ref none)) + ;; NO_TNH-NEXT: (local $B (ref none)) + ;; NO_TNH-NEXT: (local $C1 (ref none)) + ;; NO_TNH-NEXT: (local $C2 nullref) + ;; NO_TNH-NEXT: (nop) + ;; NO_TNH-NEXT: ) + (func $locals + ;; All these locals can become nullable or even non-nullable null types. + ;; This checks no problem happens due to that. + (local $A (ref $A)) + (local $B (ref $B)) + (local $C1 (ref $C1)) + (local $C2 (ref null $C2)) + ) +) + +;; As above, but now $C1 is created. +(module + ;; NO_TNH: (type $A (struct )) + (type $A (struct)) + + ;; NO_TNH: (type $B (struct_subtype $A)) + (type $B (struct_subtype $A)) + + ;; YESTNH: (type $C1 (struct )) + ;; NO_TNH: (type $C1 (struct_subtype $B)) + (type $C1 (struct_subtype $B)) + + (type $C2 (struct_subtype $B)) + + ;; YESTNH: (type $anyref_=>_none (func (param anyref))) + + ;; YESTNH: (global $global anyref (struct.new_default $C1)) + ;; NO_TNH: (type $anyref_=>_none (func (param anyref))) + + ;; NO_TNH: (global $global anyref (struct.new_default $C1)) + (global $global anyref (struct.new $C1)) + + ;; YESTNH: (func $ref.cast (type $anyref_=>_none) (param $x anyref) + ;; YESTNH-NEXT: (drop + ;; YESTNH-NEXT: (ref.cast $C1 + ;; YESTNH-NEXT: (local.get $x) + ;; YESTNH-NEXT: ) + ;; YESTNH-NEXT: ) + ;; YESTNH-NEXT: (drop + ;; YESTNH-NEXT: (ref.cast $C1 + ;; YESTNH-NEXT: (local.get $x) + ;; YESTNH-NEXT: ) + ;; YESTNH-NEXT: ) + ;; YESTNH-NEXT: (drop + ;; YESTNH-NEXT: (ref.cast $C1 + ;; YESTNH-NEXT: (local.get $x) + ;; YESTNH-NEXT: ) + ;; YESTNH-NEXT: ) + ;; YESTNH-NEXT: (drop + ;; YESTNH-NEXT: (ref.cast none + ;; YESTNH-NEXT: (local.get $x) + ;; YESTNH-NEXT: ) + ;; YESTNH-NEXT: ) + ;; YESTNH-NEXT: ) + ;; NO_TNH: (func $ref.cast (type $anyref_=>_none) (param $x anyref) + ;; NO_TNH-NEXT: (drop + ;; NO_TNH-NEXT: (ref.cast $A + ;; NO_TNH-NEXT: (local.get $x) + ;; NO_TNH-NEXT: ) + ;; NO_TNH-NEXT: ) + ;; NO_TNH-NEXT: (drop + ;; NO_TNH-NEXT: (ref.cast $B + ;; NO_TNH-NEXT: (local.get $x) + ;; NO_TNH-NEXT: ) + ;; NO_TNH-NEXT: ) + ;; NO_TNH-NEXT: (drop + ;; NO_TNH-NEXT: (ref.cast $C1 + ;; NO_TNH-NEXT: (local.get $x) + ;; NO_TNH-NEXT: ) + ;; NO_TNH-NEXT: ) + ;; NO_TNH-NEXT: (drop + ;; NO_TNH-NEXT: (ref.cast none + ;; NO_TNH-NEXT: (local.get $x) + ;; NO_TNH-NEXT: ) + ;; NO_TNH-NEXT: ) + ;; NO_TNH-NEXT: ) + (func $ref.cast (param $x anyref) + ;; These three can be cast to $C1 in TNH. + (drop + (ref.cast $A + (local.get $x) + ) + ) + (drop + (ref.cast $B + (local.get $x) + ) + ) + (drop + (ref.cast $C1 + (local.get $x) + ) + ) + ;; This will trap. + (drop + (ref.cast $C2 + (local.get $x) + ) + ) + ) + + ;; YESTNH: (func $ref.cast.null (type $anyref_=>_none) (param $x anyref) + ;; YESTNH-NEXT: (drop + ;; YESTNH-NEXT: (ref.cast null $C1 + ;; YESTNH-NEXT: (local.get $x) + ;; YESTNH-NEXT: ) + ;; YESTNH-NEXT: ) + ;; YESTNH-NEXT: (drop + ;; YESTNH-NEXT: (ref.cast null $C1 + ;; YESTNH-NEXT: (local.get $x) + ;; YESTNH-NEXT: ) + ;; YESTNH-NEXT: ) + ;; YESTNH-NEXT: (drop + ;; YESTNH-NEXT: (ref.cast null $C1 + ;; YESTNH-NEXT: (local.get $x) + ;; YESTNH-NEXT: ) + ;; YESTNH-NEXT: ) + ;; YESTNH-NEXT: (drop + ;; YESTNH-NEXT: (ref.cast null none + ;; YESTNH-NEXT: (local.get $x) + ;; YESTNH-NEXT: ) + ;; YESTNH-NEXT: ) + ;; YESTNH-NEXT: ) + ;; NO_TNH: (func $ref.cast.null (type $anyref_=>_none) (param $x anyref) + ;; NO_TNH-NEXT: (drop + ;; NO_TNH-NEXT: (ref.cast null $A + ;; NO_TNH-NEXT: (local.get $x) + ;; NO_TNH-NEXT: ) + ;; NO_TNH-NEXT: ) + ;; NO_TNH-NEXT: (drop + ;; NO_TNH-NEXT: (ref.cast null $B + ;; NO_TNH-NEXT: (local.get $x) + ;; NO_TNH-NEXT: ) + ;; NO_TNH-NEXT: ) + ;; NO_TNH-NEXT: (drop + ;; NO_TNH-NEXT: (ref.cast null $C1 + ;; NO_TNH-NEXT: (local.get $x) + ;; NO_TNH-NEXT: ) + ;; NO_TNH-NEXT: ) + ;; NO_TNH-NEXT: (drop + ;; NO_TNH-NEXT: (ref.cast null none + ;; NO_TNH-NEXT: (local.get $x) + ;; NO_TNH-NEXT: ) + ;; NO_TNH-NEXT: ) + ;; NO_TNH-NEXT: ) + (func $ref.cast.null (param $x anyref) + ;; These three can be cast to $C1 in TNH. + (drop + (ref.cast null $A + (local.get $x) + ) + ) + (drop + (ref.cast null $B + (local.get $x) + ) + ) + (drop + (ref.cast null $C1 + (local.get $x) + ) + ) + ;; This returns null. + (drop + (ref.cast null $C2 + (local.get $x) + ) + ) + ) +) + +;; Function subtyping, which is a TODO - for now we do nothing. +(module + ;; YESTNH: (type $A (func)) + ;; NO_TNH: (type $A (func)) + (type $A (func)) + + ;; YESTNH: (type $funcref_=>_none (func (param funcref))) + + ;; YESTNH: (type $B (func_subtype $A)) + ;; NO_TNH: (type $funcref_=>_none (func (param funcref))) + + ;; NO_TNH: (type $B (func_subtype $A)) + (type $B (func_subtype $A)) + + ;; YESTNH: (type $C (func_subtype $B)) + ;; NO_TNH: (type $C (func_subtype $B)) + (type $C (func_subtype $B)) + + ;; YESTNH: (func $A (type $A) + ;; YESTNH-NEXT: (nop) + ;; YESTNH-NEXT: ) + ;; NO_TNH: (func $A (type $A) + ;; NO_TNH-NEXT: (nop) + ;; NO_TNH-NEXT: ) + (func $A (type $A) + ) + + ;; YESTNH: (func $C (type $A) + ;; YESTNH-NEXT: (nop) + ;; YESTNH-NEXT: ) + ;; NO_TNH: (func $C (type $A) + ;; NO_TNH-NEXT: (nop) + ;; NO_TNH-NEXT: ) + (func $C (type $A) + ) + + ;; YESTNH: (func $casts (type $funcref_=>_none) (param $x funcref) + ;; YESTNH-NEXT: (drop + ;; YESTNH-NEXT: (ref.cast $A + ;; YESTNH-NEXT: (local.get $x) + ;; YESTNH-NEXT: ) + ;; YESTNH-NEXT: ) + ;; YESTNH-NEXT: (drop + ;; YESTNH-NEXT: (ref.cast $B + ;; YESTNH-NEXT: (local.get $x) + ;; YESTNH-NEXT: ) + ;; YESTNH-NEXT: ) + ;; YESTNH-NEXT: (drop + ;; YESTNH-NEXT: (ref.cast $C + ;; YESTNH-NEXT: (local.get $x) + ;; YESTNH-NEXT: ) + ;; YESTNH-NEXT: ) + ;; YESTNH-NEXT: ) + ;; NO_TNH: (func $casts (type $funcref_=>_none) (param $x funcref) + ;; NO_TNH-NEXT: (drop + ;; NO_TNH-NEXT: (ref.cast $A + ;; NO_TNH-NEXT: (local.get $x) + ;; NO_TNH-NEXT: ) + ;; NO_TNH-NEXT: ) + ;; NO_TNH-NEXT: (drop + ;; NO_TNH-NEXT: (ref.cast $B + ;; NO_TNH-NEXT: (local.get $x) + ;; NO_TNH-NEXT: ) + ;; NO_TNH-NEXT: ) + ;; NO_TNH-NEXT: (drop + ;; NO_TNH-NEXT: (ref.cast $C + ;; NO_TNH-NEXT: (local.get $x) + ;; NO_TNH-NEXT: ) + ;; NO_TNH-NEXT: ) + ;; NO_TNH-NEXT: ) + (func $casts (param $x funcref) + ;; $A and $C have functions of their types, so in theory we could optimize + ;; $B here. + (drop + (ref.cast $A + (local.get $x) + ) + ) + (drop + (ref.cast $B + (local.get $x) + ) + ) + (drop + (ref.cast $C + (local.get $x) + ) + ) + ) +) + +;; As above, but now the functions are also public types (exported). We should +;; be careful here in the future even when we do optimize function types. +(module + ;; YESTNH: (type $A (func)) + ;; NO_TNH: (type $A (func)) + (type $A (func)) + + ;; YESTNH: (type $B (func_subtype $A)) + ;; NO_TNH: (type $B (func_subtype $A)) + (type $B (func_subtype $A)) + + ;; YESTNH: (type $C (func_subtype $B)) + ;; NO_TNH: (type $C (func_subtype $B)) + (type $C (func_subtype $B)) + + ;; YESTNH: (type $funcref_=>_none (func (param funcref))) + + ;; YESTNH: (elem declare func $A $C) + + ;; YESTNH: (export "A" (func $A)) + + ;; YESTNH: (func $A (type $A) + ;; YESTNH-NEXT: (drop + ;; YESTNH-NEXT: (ref.func $A) + ;; YESTNH-NEXT: ) + ;; YESTNH-NEXT: ) + ;; NO_TNH: (type $funcref_=>_none (func (param funcref))) + + ;; NO_TNH: (elem declare func $A $C) + + ;; NO_TNH: (export "A" (func $A)) + + ;; NO_TNH: (func $A (type $A) + ;; NO_TNH-NEXT: (drop + ;; NO_TNH-NEXT: (ref.func $A) + ;; NO_TNH-NEXT: ) + ;; NO_TNH-NEXT: ) + (func $A (export "A") (type $A) + ;; Also create a function reference to use the type in that way as well. + (drop + (ref.func $A) + ) + ) + + ;; YESTNH: (func $C (type $C) + ;; YESTNH-NEXT: (drop + ;; YESTNH-NEXT: (ref.func $C) + ;; YESTNH-NEXT: ) + ;; YESTNH-NEXT: ) + ;; NO_TNH: (func $C (type $C) + ;; NO_TNH-NEXT: (drop + ;; NO_TNH-NEXT: (ref.func $C) + ;; NO_TNH-NEXT: ) + ;; NO_TNH-NEXT: ) + (func $C (type $C) + (drop + (ref.func $C) + ) + ) + + ;; YESTNH: (func $casts (type $funcref_=>_none) (param $x funcref) + ;; YESTNH-NEXT: (drop + ;; YESTNH-NEXT: (ref.cast $A + ;; YESTNH-NEXT: (local.get $x) + ;; YESTNH-NEXT: ) + ;; YESTNH-NEXT: ) + ;; YESTNH-NEXT: (drop + ;; YESTNH-NEXT: (ref.cast $B + ;; YESTNH-NEXT: (local.get $x) + ;; YESTNH-NEXT: ) + ;; YESTNH-NEXT: ) + ;; YESTNH-NEXT: (drop + ;; YESTNH-NEXT: (ref.cast $C + ;; YESTNH-NEXT: (local.get $x) + ;; YESTNH-NEXT: ) + ;; YESTNH-NEXT: ) + ;; YESTNH-NEXT: ) + ;; NO_TNH: (func $casts (type $funcref_=>_none) (param $x funcref) + ;; NO_TNH-NEXT: (drop + ;; NO_TNH-NEXT: (ref.cast $A + ;; NO_TNH-NEXT: (local.get $x) + ;; NO_TNH-NEXT: ) + ;; NO_TNH-NEXT: ) + ;; NO_TNH-NEXT: (drop + ;; NO_TNH-NEXT: (ref.cast $B + ;; NO_TNH-NEXT: (local.get $x) + ;; NO_TNH-NEXT: ) + ;; NO_TNH-NEXT: ) + ;; NO_TNH-NEXT: (drop + ;; NO_TNH-NEXT: (ref.cast $C + ;; NO_TNH-NEXT: (local.get $x) + ;; NO_TNH-NEXT: ) + ;; NO_TNH-NEXT: ) + ;; NO_TNH-NEXT: ) + (func $casts (param $x funcref) + ;; $A and $C have functions of their types, and references to them, so in + ;; theory we could optimize $B here. + (drop + (ref.cast $A + (local.get $x) + ) + ) + (drop + (ref.cast $B + (local.get $x) + ) + ) + (drop + (ref.cast $C + (local.get $x) + ) + ) + ) +) + +;; Array subtyping, which is a TODO - for now we do nothing. +(module + ;; YESTNH: (type $A (array (mut i32))) + ;; NO_TNH: (type $A (array (mut i32))) + (type $A (array (mut i32))) + + ;; YESTNH: (type $B (array_subtype (mut i32) $A)) + ;; NO_TNH: (type $B (array_subtype (mut i32) $A)) + (type $B (array_subtype (mut i32) $A)) + + ;; YESTNH: (type $C (array_subtype (mut i32) $B)) + ;; NO_TNH: (type $C (array_subtype (mut i32) $B)) + (type $C (array_subtype (mut i32) $B)) + + ;; YESTNH: (type $anyref_=>_none (func (param anyref))) + + ;; YESTNH: (global $A (ref $A) (array.new $A + ;; YESTNH-NEXT: (i32.const 10) + ;; YESTNH-NEXT: (i32.const 20) + ;; YESTNH-NEXT: )) + ;; NO_TNH: (type $anyref_=>_none (func (param anyref))) + + ;; NO_TNH: (global $A (ref $A) (array.new $A + ;; NO_TNH-NEXT: (i32.const 10) + ;; NO_TNH-NEXT: (i32.const 20) + ;; NO_TNH-NEXT: )) + (global $A (ref $A) (array.new $A + (i32.const 10) + (i32.const 20) + )) + + ;; YESTNH: (global $B (ref $B) (array.new $B + ;; YESTNH-NEXT: (i32.const 10) + ;; YESTNH-NEXT: (i32.const 20) + ;; YESTNH-NEXT: )) + ;; NO_TNH: (global $B (ref $B) (array.new $B + ;; NO_TNH-NEXT: (i32.const 10) + ;; NO_TNH-NEXT: (i32.const 20) + ;; NO_TNH-NEXT: )) + (global $B (ref $B) (array.new $B + (i32.const 10) + (i32.const 20) + )) + + ;; YESTNH: (global $C (ref $C) (array.new $C + ;; YESTNH-NEXT: (i32.const 10) + ;; YESTNH-NEXT: (i32.const 20) + ;; YESTNH-NEXT: )) + ;; NO_TNH: (global $C (ref $C) (array.new $C + ;; NO_TNH-NEXT: (i32.const 10) + ;; NO_TNH-NEXT: (i32.const 20) + ;; NO_TNH-NEXT: )) + (global $C (ref $C) (array.new $C + (i32.const 10) + (i32.const 20) + )) + + ;; YESTNH: (func $casts (type $anyref_=>_none) (param $x anyref) + ;; YESTNH-NEXT: (drop + ;; YESTNH-NEXT: (ref.cast $A + ;; YESTNH-NEXT: (local.get $x) + ;; YESTNH-NEXT: ) + ;; YESTNH-NEXT: ) + ;; YESTNH-NEXT: (drop + ;; YESTNH-NEXT: (ref.cast $B + ;; YESTNH-NEXT: (local.get $x) + ;; YESTNH-NEXT: ) + ;; YESTNH-NEXT: ) + ;; YESTNH-NEXT: (drop + ;; YESTNH-NEXT: (ref.cast $C + ;; YESTNH-NEXT: (local.get $x) + ;; YESTNH-NEXT: ) + ;; YESTNH-NEXT: ) + ;; YESTNH-NEXT: ) + ;; NO_TNH: (func $casts (type $anyref_=>_none) (param $x anyref) + ;; NO_TNH-NEXT: (drop + ;; NO_TNH-NEXT: (ref.cast $A + ;; NO_TNH-NEXT: (local.get $x) + ;; NO_TNH-NEXT: ) + ;; NO_TNH-NEXT: ) + ;; NO_TNH-NEXT: (drop + ;; NO_TNH-NEXT: (ref.cast $B + ;; NO_TNH-NEXT: (local.get $x) + ;; NO_TNH-NEXT: ) + ;; NO_TNH-NEXT: ) + ;; NO_TNH-NEXT: (drop + ;; NO_TNH-NEXT: (ref.cast $C + ;; NO_TNH-NEXT: (local.get $x) + ;; NO_TNH-NEXT: ) + ;; NO_TNH-NEXT: ) + ;; NO_TNH-NEXT: ) + (func $casts (param $x anyref) + (drop + (ref.cast $A + (local.get $x) + ) + ) + (drop + (ref.cast $B + (local.get $x) + ) + ) + (drop + (ref.cast $C + (local.get $x) + ) + ) + ) +) |