| ;; NOTE: Assertions have been generated by update_lit_checks.py --all-items and should not be edited. |
| |
| ;; RUN: foreach %s %t wasm-opt -all --closed-world --gto --preserve-type-order -S -o - | filecheck %s |
| |
| (module |
| (rec |
| ;; We can optimize out the externref field on the struct because it is never |
| ;; used. |
| ;; CHECK: (rec |
| ;; CHECK-NEXT: (type $struct (descriptor $desc) (struct)) |
| (type $struct (descriptor $desc) (struct (field externref))) |
| ;; The externef field on the descriptor is visible from JS because it holds |
| ;; the prototype, so we cannot remove it. |
| ;; CHECK: (type $desc (describes $struct) (struct (field externref))) |
| (type $desc (describes $struct) (struct (field externref))) |
| ) |
| |
| ;; CHECK: (type $2 (func)) |
| |
| ;; CHECK: (type $3 (func (result (ref $struct)))) |
| |
| ;; CHECK: (type $prototypes (array (mut externref))) |
| (type $prototypes (array (mut externref))) |
| ;; CHECK: (type $funcs (array (mut funcref))) |
| (type $funcs (array (mut funcref))) |
| ;; CHECK: (type $data (array (mut i8))) |
| (type $data (array (mut i8))) |
| ;; CHECK: (type $configureAll (func (param (ref null $prototypes) (ref null $funcs) (ref null $data) externref))) |
| (type $configureAll (func (param (ref null $prototypes)) (param (ref null $funcs)) (param (ref null $data)) (param externref))) |
| |
| ;; CHECK: (import "wasm:js-prototypes" "configureAll" (func $configureAll (type $configureAll) (param (ref null $prototypes) (ref null $funcs) (ref null $data) externref))) |
| (import "wasm:js-prototypes" "configureAll" (func $configureAll (type $configureAll))) |
| |
| ;; CHECK: (data $data "12345678") |
| (data $data "12345678") |
| |
| ;; CHECK: (elem $prototypes externref (item (ref.null noextern))) |
| (elem $prototypes externref (ref.null extern)) |
| |
| ;; CHECK: (elem $funcs func $return-struct) |
| (elem $funcs funcref (ref.func $return-struct)) |
| |
| ;; CHECK: (start $start) |
| (start $start) |
| |
| ;; CHECK: (func $start (type $2) |
| ;; CHECK-NEXT: (call $configureAll |
| ;; CHECK-NEXT: (array.new_elem $prototypes $prototypes |
| ;; CHECK-NEXT: (i32.const 0) |
| ;; CHECK-NEXT: (i32.const 1) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (array.new_elem $funcs $funcs |
| ;; CHECK-NEXT: (i32.const 0) |
| ;; CHECK-NEXT: (i32.const 1) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (array.new_data $data $data |
| ;; CHECK-NEXT: (i32.const 0) |
| ;; CHECK-NEXT: (i32.const 8) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: (ref.null noextern) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| (func $start |
| (call $configureAll |
| (array.new_elem $prototypes $prototypes (i32.const 0) (i32.const 1)) |
| (array.new_elem $funcs $funcs (i32.const 0) (i32.const 1)) |
| (array.new_data $data $data (i32.const 0) (i32.const 8)) |
| (ref.null extern) |
| ) |
| ) |
| |
| ;; CHECK: (func $return-struct (type $3) (result (ref $struct)) |
| ;; CHECK-NEXT: (unreachable) |
| ;; CHECK-NEXT: ) |
| (func $return-struct (result (ref $struct)) |
| ;; It doesn't matter that the function does not actually return a struct; we |
| ;; just look at the signature. |
| (unreachable) |
| ) |
| ) |
| |
| (module |
| (rec |
| ;; We can optimize out the externref field on the field because it is never |
| ;; used. |
| ;; CHECK: (rec |
| ;; CHECK-NEXT: (type $struct (descriptor $desc) (struct)) |
| (type $struct (descriptor $desc) (struct (field externref))) |
| ;; The externef field on the descriptor is visible from JS because it holds |
| ;; the prototype, so we cannot remove it. |
| ;; CHECK: (type $desc (describes $struct) (struct (field externref))) |
| (type $desc (describes $struct) (struct (field externref))) |
| ) |
| |
| ;; CHECK: (type $2 (func)) |
| |
| ;; CHECK: (func $externalize (type $2) |
| ;; CHECK-NEXT: (local $struct (ref null $struct)) |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (extern.convert_any |
| ;; CHECK-NEXT: (local.get $struct) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| (func $externalize |
| (local $struct (ref null $struct)) |
| ;; Externalizing a reference may in general make it available to JS and |
| ;; and force us to keep fields holding exposed prototypes. |
| (drop |
| (extern.convert_any |
| (local.get $struct) |
| ) |
| ) |
| ) |
| ) |
| |
| (module |
| (rec |
| ;; CHECK: (rec |
| ;; CHECK-NEXT: (type $struct (descriptor $desc) (struct)) |
| (type $struct (descriptor $desc) (struct)) |
| ;; Non-nullable extern refs can also hold prototypes. |
| ;; CHECK: (type $desc (describes $struct) (struct (field (ref extern)))) |
| (type $desc (describes $struct) (struct (field (ref extern)))) |
| ) |
| |
| ;; CHECK: (type $2 (func)) |
| |
| ;; CHECK: (func $externalize (type $2) |
| ;; CHECK-NEXT: (local $struct (ref null $struct)) |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (extern.convert_any |
| ;; CHECK-NEXT: (local.get $struct) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| (func $externalize |
| (local $struct (ref null $struct)) |
| (drop |
| (extern.convert_any |
| (local.get $struct) |
| ) |
| ) |
| ) |
| ) |
| |
| |
| (module |
| (rec |
| ;; CHECK: (rec |
| ;; CHECK-NEXT: (type $struct (descriptor $desc) (struct)) |
| (type $struct (descriptor $desc) (struct)) |
| ;; Only externref fields can hold prototypes. We can optimize out e.g. |
| ;; anyref fields. |
| ;; CHECK: (type $desc (describes $struct) (struct)) |
| (type $desc (describes $struct) (struct (field anyref))) |
| ) |
| |
| ;; CHECK: (type $2 (func)) |
| |
| ;; CHECK: (func $externalize (type $2) |
| ;; CHECK-NEXT: (local $struct (ref null $struct)) |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (extern.convert_any |
| ;; CHECK-NEXT: (local.get $struct) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| (func $externalize |
| (local $struct (ref null $struct)) |
| (drop |
| (extern.convert_any |
| (local.get $struct) |
| ) |
| ) |
| ) |
| ) |
| |
| (module |
| (rec |
| ;; CHECK: (rec |
| ;; CHECK-NEXT: (type $struct (descriptor $desc) (struct)) |
| (type $struct (descriptor $desc) (struct)) |
| ;; Bottom externrefs can only hold null prototypes, but that's the default |
| ;; prototype value anyway, so we can still optimize them out. |
| ;; CHECK: (type $desc (describes $struct) (struct)) |
| (type $desc (describes $struct) (struct (field nullexternref))) |
| ) |
| |
| ;; CHECK: (type $2 (func)) |
| |
| ;; CHECK: (func $externalize (type $2) |
| ;; CHECK-NEXT: (local $struct (ref null $struct)) |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (extern.convert_any |
| ;; CHECK-NEXT: (local.get $struct) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| (func $externalize |
| (local $struct (ref null $struct)) |
| (drop |
| (extern.convert_any |
| (local.get $struct) |
| ) |
| ) |
| ) |
| ) |
| |
| (module |
| (rec |
| ;; CHECK: (rec |
| ;; CHECK-NEXT: (type $struct (descriptor $desc) (struct)) |
| (type $struct (descriptor $desc) (struct)) |
| ;; Mutable fields cannot hold exposed prototypes, so they can be optimized |
| ;; normally. |
| ;; CHECK: (type $desc (describes $struct) (struct)) |
| (type $desc (describes $struct) (struct (field (mut externref)))) |
| ) |
| |
| ;; CHECK: (type $2 (func)) |
| |
| ;; CHECK: (func $externalize (type $2) |
| ;; CHECK-NEXT: (local $struct (ref null $struct)) |
| ;; CHECK-NEXT: (drop |
| ;; CHECK-NEXT: (extern.convert_any |
| ;; CHECK-NEXT: (local.get $struct) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| ;; CHECK-NEXT: ) |
| (func $externalize |
| (local $struct (ref null $struct)) |
| (drop |
| (extern.convert_any |
| (local.get $struct) |
| ) |
| ) |
| ) |
| ) |
| |
| (module |
| ;; Supertype on the boundary propagates exposure to subtypes. |
| (rec |
| ;; CHECK: (rec |
| ;; CHECK-NEXT: (type $super (sub (descriptor $super-desc) (struct (field i32)))) |
| (type $super (sub (descriptor $super-desc) (struct (field i32)))) |
| ;; CHECK: (type $super-desc (sub (describes $super) (struct))) |
| (type $super-desc (sub (describes $super) (struct))) |
| ) |
| (rec |
| ;; CHECK: (rec |
| ;; CHECK-NEXT: (type $sub (sub $super (descriptor $sub-desc) (struct (field i32)))) |
| (type $sub (sub $super (descriptor $sub-desc) (struct (field i32 i64)))) |
| ;; CHECK: (type $sub-desc (sub $super-desc (describes $sub) (struct (field externref)))) |
| (type $sub-desc (sub $super-desc (describes $sub) (struct (field externref i64)))) |
| ) |
| |
| ;; $super flows out, so $sub is exposed, so $sub-desc's externref field is |
| ;; kept. |
| ;; CHECK: (type $4 (func)) |
| |
| ;; CHECK: (type $5 (func (param (ref null $super)))) |
| |
| ;; CHECK: (import "" "" (func $import (type $5) (param (ref null $super)))) |
| (import "" "" (func $import (param (ref null $super)))) |
| |
| ;; CHECK: (func $use-sub (type $4) |
| ;; CHECK-NEXT: (local $0 (ref null $sub)) |
| ;; CHECK-NEXT: ) |
| (func $use-sub |
| (local (ref null $sub)) |
| ) |
| ) |
| |
| (module |
| ;; Same, but now the type is exact on the boundary, so it does not propagate |
| ;; exposure to subtypes. We can remove all of $sub-desc's fields, unlike |
| ;; before. |
| (rec |
| ;; CHECK: (rec |
| ;; CHECK-NEXT: (type $super (sub (descriptor $super-desc) (struct (field i32)))) |
| (type $super (sub (descriptor $super-desc) (struct (field i32)))) |
| ;; CHECK: (type $super-desc (sub (describes $super) (struct))) |
| (type $super-desc (sub (describes $super) (struct))) |
| ) |
| (rec |
| ;; CHECK: (rec |
| ;; CHECK-NEXT: (type $sub (sub $super (descriptor $sub-desc) (struct (field i32)))) |
| (type $sub (sub $super (descriptor $sub-desc) (struct (field i32 i64)))) |
| ;; CHECK: (type $sub-desc (sub $super-desc (describes $sub) (struct))) |
| (type $sub-desc (sub $super-desc (describes $sub) (struct (field externref i64)))) |
| ) |
| |
| ;; CHECK: (type $4 (func)) |
| |
| ;; CHECK: (type $5 (func (param (ref null (exact $super))))) |
| |
| ;; CHECK: (import "" "" (func $import (type $5) (param (ref null (exact $super))))) |
| (import "" "" (func $import (param (ref null (exact $super))))) |
| |
| ;; CHECK: (func $use-sub (type $4) |
| ;; CHECK-NEXT: (local $0 (ref null $sub)) |
| ;; CHECK-NEXT: ) |
| (func $use-sub |
| (local (ref null $sub)) |
| ) |
| ) |
| |
| (module |
| ;; Same, but now there is an abstract supertype on the boundary. We still |
| ;; propagate the fact that the type flows out and keep the externref field in |
| ;; $sub-desc. |
| (rec |
| ;; CHECK: (rec |
| ;; CHECK-NEXT: (type $super (sub (descriptor $super-desc) (struct))) |
| (type $super (sub (descriptor $super-desc) (struct (field i32)))) |
| ;; CHECK: (type $super-desc (sub (describes $super) (struct))) |
| (type $super-desc (sub (describes $super) (struct))) |
| ) |
| (rec |
| ;; CHECK: (type $sub (sub $super (descriptor $sub-desc) (struct))) |
| (type $sub (sub $super (descriptor $sub-desc) (struct (field i32 i64)))) |
| ;; CHECK: (type $sub-desc (sub $super-desc (describes $sub) (struct (field externref)))) |
| (type $sub-desc (sub $super-desc (describes $sub) (struct (field externref i64)))) |
| ) |
| |
| ;; CHECK: (type $4 (func)) |
| |
| ;; CHECK: (type $5 (func (param anyref))) |
| |
| ;; CHECK: (import "" "" (func $import (type $5) (param anyref))) |
| (import "" "" (func $import (param anyref))) |
| |
| ;; CHECK: (func $use-sub (type $4) |
| ;; CHECK-NEXT: (local $0 (ref null $sub)) |
| ;; CHECK-NEXT: ) |
| (func $use-sub |
| (local (ref null $sub)) |
| ) |
| ) |
| |
| (module |
| ;; Now we have to propagate through multiple supertypes without configurable |
| ;; prototypes. We cannot optimize the externref field in the subtype |
| ;; descriptor. |
| (rec |
| ;; CHECK: (rec |
| ;; CHECK-NEXT: (type $super (sub (descriptor $super-desc) (struct (field i32)))) |
| (type $super (sub (descriptor $super-desc) (struct (field i32)))) |
| ;; CHECK: (type $super-desc (sub (describes $super) (struct))) |
| (type $super-desc (sub (describes $super) (struct))) |
| ) |
| (rec |
| ;; CHECK: (rec |
| ;; CHECK-NEXT: (type $mid (sub $super (descriptor $mid-desc) (struct (field i32)))) |
| (type $mid (sub $super (descriptor $mid-desc) (struct (field i32)))) |
| ;; CHECK: (type $mid-desc (sub $super-desc (describes $mid) (struct))) |
| (type $mid-desc (sub $super-desc (describes $mid) (struct))) |
| ) |
| (rec |
| ;; CHECK: (type $sub (sub $mid (descriptor $sub-desc) (struct (field i32)))) |
| (type $sub (sub $mid (descriptor $sub-desc) (struct (field i32 i64)))) |
| ;; CHECK: (type $sub-desc (sub $mid-desc (describes $sub) (struct (field externref)))) |
| (type $sub-desc (sub $mid-desc (describes $sub) (struct (field externref i64)))) |
| ) |
| |
| ;; CHECK: (type $6 (func)) |
| |
| ;; CHECK: (type $7 (func (param (ref null $super)))) |
| |
| ;; CHECK: (import "" "" (func $import (type $7) (param (ref null $super)))) |
| (import "" "" (func $import (param (ref null $super)))) |
| |
| ;; CHECK: (func $use-sub (type $6) |
| ;; CHECK-NEXT: (local $0 (ref null $sub)) |
| ;; CHECK-NEXT: ) |
| (func $use-sub |
| (local (ref null $sub)) |
| ) |
| ) |
| |
| (module |
| ;; Now the supertype is a result of the imported function rather than a |
| ;; parameter. It does not flow out, so we can optimize the subtype's |
| ;; descriptor. |
| (rec |
| ;; CHECK: (rec |
| ;; CHECK-NEXT: (type $super (sub (descriptor $super-desc) (struct (field i32)))) |
| (type $super (sub (descriptor $super-desc) (struct (field i32)))) |
| ;; CHECK: (type $super-desc (sub (describes $super) (struct))) |
| (type $super-desc (sub (describes $super) (struct))) |
| ) |
| |
| (rec |
| ;; CHECK: (rec |
| ;; CHECK-NEXT: (type $sub (sub $super (descriptor $sub-desc) (struct (field i32)))) |
| (type $sub (sub $super (descriptor $sub-desc) (struct (field i32 i64)))) |
| ;; CHECK: (type $sub-desc (sub $super-desc (describes $sub) (struct))) |
| (type $sub-desc (sub $super-desc (describes $sub) (struct (field externref i64)))) |
| ) |
| |
| ;; CHECK: (type $4 (func)) |
| |
| ;; CHECK: (type $5 (func (result (ref null $super)))) |
| |
| ;; CHECK: (import "" "" (func $import (type $5) (result (ref null $super)))) |
| (import "" "" (func $import (result (ref null $super)))) |
| |
| ;; CHECK: (func $use-sub (type $4) |
| ;; CHECK-NEXT: (local $0 (ref null $sub)) |
| ;; CHECK-NEXT: ) |
| (func $use-sub |
| (local (ref null $sub)) |
| ) |
| ) |
| |
| (module |
| ;; An exported function instead of an imported function. The supertype flows |
| ;; out as a result, so we cannot optimize the externref in $sub-desc. |
| (rec |
| ;; CHECK: (rec |
| ;; CHECK-NEXT: (type $super (sub (descriptor $super-desc) (struct (field i32)))) |
| (type $super (sub (descriptor $super-desc) (struct (field i32)))) |
| ;; CHECK: (type $super-desc (sub (describes $super) (struct))) |
| (type $super-desc (sub (describes $super) (struct))) |
| ) |
| (rec |
| ;; CHECK: (rec |
| ;; CHECK-NEXT: (type $sub (sub $super (descriptor $sub-desc) (struct (field i32)))) |
| (type $sub (sub $super (descriptor $sub-desc) (struct (field i32 i64)))) |
| ;; CHECK: (type $sub-desc (sub $super-desc (describes $sub) (struct (field externref)))) |
| (type $sub-desc (sub $super-desc (describes $sub) (struct (field externref i64)))) |
| ) |
| |
| ;; CHECK: (type $4 (func)) |
| |
| ;; CHECK: (type $5 (func (result (ref null $super)))) |
| |
| ;; CHECK: (export "export" (func $export)) |
| (export "export" (func $export)) |
| |
| ;; CHECK: (func $export (type $5) (result (ref null $super)) |
| ;; CHECK-NEXT: (unreachable) |
| ;; CHECK-NEXT: ) |
| (func $export (result (ref null $super)) |
| (unreachable) |
| ) |
| |
| ;; CHECK: (func $use-sub (type $4) |
| ;; CHECK-NEXT: (local $0 (ref null $sub)) |
| ;; CHECK-NEXT: ) |
| (func $use-sub |
| (local (ref null $sub)) |
| ) |
| ) |
| |
| (module |
| ;; Now The supertype is a parameter of the exported function. It does not flow |
| ;; out and we can optimize. |
| (rec |
| ;; CHECK: (rec |
| ;; CHECK-NEXT: (type $super (sub (descriptor $super-desc) (struct (field i32)))) |
| (type $super (sub (descriptor $super-desc) (struct (field i32)))) |
| ;; CHECK: (type $super-desc (sub (describes $super) (struct))) |
| (type $super-desc (sub (describes $super) (struct))) |
| ) |
| (rec |
| ;; CHECK: (rec |
| ;; CHECK-NEXT: (type $sub (sub $super (descriptor $sub-desc) (struct (field i32)))) |
| (type $sub (sub $super (descriptor $sub-desc) (struct (field i32 i64)))) |
| ;; CHECK: (type $sub-desc (sub $super-desc (describes $sub) (struct))) |
| (type $sub-desc (sub $super-desc (describes $sub) (struct (field externref i64)))) |
| ) |
| |
| ;; CHECK: (type $4 (func)) |
| |
| ;; CHECK: (type $5 (func (param (ref null $super)))) |
| |
| ;; CHECK: (export "export" (func $export)) |
| (export "export" (func $export)) |
| |
| ;; CHECK: (func $export (type $5) (param $0 (ref null $super)) |
| ;; CHECK-NEXT: (nop) |
| ;; CHECK-NEXT: ) |
| (func $export (param (ref null $super)) |
| (nop) |
| ) |
| |
| ;; CHECK: (func $use-sub (type $4) |
| ;; CHECK-NEXT: (local $0 (ref null $sub)) |
| ;; CHECK-NEXT: ) |
| (func $use-sub |
| (local (ref null $sub)) |
| ) |
| ) |
| |
| (module |
| ;; The supertype flows out via an imported mutable global. We cannot optimize |
| ;; the externref field in $sub-desc. |
| (rec |
| ;; CHECK: (rec |
| ;; CHECK-NEXT: (type $super (sub (descriptor $super-desc) (struct (field i32)))) |
| (type $super (sub (descriptor $super-desc) (struct (field i32)))) |
| ;; CHECK: (type $super-desc (sub (describes $super) (struct))) |
| (type $super-desc (sub (describes $super) (struct))) |
| ) |
| (rec |
| ;; CHECK: (rec |
| ;; CHECK-NEXT: (type $sub (sub $super (descriptor $sub-desc) (struct (field i32)))) |
| (type $sub (sub $super (descriptor $sub-desc) (struct (field i32 i64)))) |
| ;; CHECK: (type $sub-desc (sub $super-desc (describes $sub) (struct (field externref)))) |
| (type $sub-desc (sub $super-desc (describes $sub) (struct (field externref i64)))) |
| ) |
| |
| ;; CHECK: (type $4 (func)) |
| |
| ;; CHECK: (import "" "" (global $import (mut (ref null $super)))) |
| (import "" "" (global $import (mut (ref null $super)))) |
| |
| ;; CHECK: (func $use-sub (type $4) |
| ;; CHECK-NEXT: (local $0 (ref null $sub)) |
| ;; CHECK-NEXT: ) |
| (func $use-sub |
| (local (ref null $sub)) |
| ) |
| ) |
| |
| (module |
| ;; Now the imported global is immutable. The value does not flow out and we |
| ;; can optimize $sub-desc. |
| (rec |
| ;; CHECK: (rec |
| ;; CHECK-NEXT: (type $super (sub (descriptor $super-desc) (struct (field i32)))) |
| (type $super (sub (descriptor $super-desc) (struct (field i32)))) |
| ;; CHECK: (type $super-desc (sub (describes $super) (struct))) |
| (type $super-desc (sub (describes $super) (struct))) |
| ) |
| (rec |
| ;; CHECK: (rec |
| ;; CHECK-NEXT: (type $sub (sub $super (descriptor $sub-desc) (struct (field i32)))) |
| (type $sub (sub $super (descriptor $sub-desc) (struct (field i32 i64)))) |
| ;; CHECK: (type $sub-desc (sub $super-desc (describes $sub) (struct))) |
| (type $sub-desc (sub $super-desc (describes $sub) (struct (field externref i64)))) |
| ) |
| |
| ;; CHECK: (type $4 (func)) |
| |
| ;; CHECK: (import "" "" (global $import (ref null $super))) |
| (import "" "" (global $import (ref null $super))) |
| |
| ;; CHECK: (func $use-sub (type $4) |
| ;; CHECK-NEXT: (local $0 (ref null $sub)) |
| ;; CHECK-NEXT: ) |
| (func $use-sub |
| (local (ref null $sub)) |
| ) |
| ) |
| |
| (module |
| ;; The supertype flows out via an exported mutable global. We cannot optimize |
| ;; the externref field in $sub-desc. |
| (rec |
| ;; CHECK: (rec |
| ;; CHECK-NEXT: (type $super (sub (descriptor $super-desc) (struct (field i32)))) |
| (type $super (sub (descriptor $super-desc) (struct (field i32)))) |
| ;; CHECK: (type $super-desc (sub (describes $super) (struct))) |
| (type $super-desc (sub (describes $super) (struct))) |
| ) |
| (rec |
| ;; CHECK: (rec |
| ;; CHECK-NEXT: (type $sub (sub $super (descriptor $sub-desc) (struct (field i32)))) |
| (type $sub (sub $super (descriptor $sub-desc) (struct (field i32 i64)))) |
| ;; CHECK: (type $sub-desc (sub $super-desc (describes $sub) (struct (field externref)))) |
| (type $sub-desc (sub $super-desc (describes $sub) (struct (field externref i64)))) |
| ) |
| |
| ;; CHECK: (type $4 (func)) |
| |
| ;; CHECK: (global $export (mut (ref null $super)) (ref.null none)) |
| (global $export (export "export") (mut (ref null $super)) (ref.null none)) |
| |
| ;; CHECK: (export "export" (global $export)) |
| |
| ;; CHECK: (func $use-sub (type $4) |
| ;; CHECK-NEXT: (local $0 (ref null $sub)) |
| ;; CHECK-NEXT: ) |
| (func $use-sub |
| (local (ref null $sub)) |
| ) |
| ) |
| |
| (module |
| ;; Now the exported global is immutable. The supertype still flows out, so we |
| ;; cannot optimize the externref field in $sub-desc. |
| (rec |
| ;; CHECK: (rec |
| ;; CHECK-NEXT: (type $super (sub (descriptor $super-desc) (struct (field i32)))) |
| (type $super (sub (descriptor $super-desc) (struct (field i32)))) |
| ;; CHECK: (type $super-desc (sub (describes $super) (struct))) |
| (type $super-desc (sub (describes $super) (struct))) |
| ) |
| (rec |
| ;; CHECK: (rec |
| ;; CHECK-NEXT: (type $sub (sub $super (descriptor $sub-desc) (struct (field i32)))) |
| (type $sub (sub $super (descriptor $sub-desc) (struct (field i32 i64)))) |
| ;; CHECK: (type $sub-desc (sub $super-desc (describes $sub) (struct (field externref)))) |
| (type $sub-desc (sub $super-desc (describes $sub) (struct (field externref i64)))) |
| ) |
| |
| ;; CHECK: (type $4 (func)) |
| |
| ;; CHECK: (global $export (ref null $super) (ref.null none)) |
| (global $export (export "export") (ref null $super) (ref.null none)) |
| |
| ;; CHECK: (export "export" (global $export)) |
| |
| ;; CHECK: (func $use-sub (type $4) |
| ;; CHECK-NEXT: (local $0 (ref null $sub)) |
| ;; CHECK-NEXT: ) |
| (func $use-sub |
| (local (ref null $sub)) |
| ) |
| ) |
| |
| (module |
| ;; The supertype flows out via an imported table. We cannot optimize the |
| ;; externref field in $sub-desc. |
| (rec |
| ;; CHECK: (rec |
| ;; CHECK-NEXT: (type $super (sub (descriptor $super-desc) (struct (field i32)))) |
| (type $super (sub (descriptor $super-desc) (struct (field i32)))) |
| ;; CHECK: (type $super-desc (sub (describes $super) (struct))) |
| (type $super-desc (sub (describes $super) (struct))) |
| ) |
| (rec |
| ;; CHECK: (rec |
| ;; CHECK-NEXT: (type $sub (sub $super (descriptor $sub-desc) (struct (field i32)))) |
| (type $sub (sub $super (descriptor $sub-desc) (struct (field i32 i64)))) |
| ;; CHECK: (type $sub-desc (sub $super-desc (describes $sub) (struct (field externref)))) |
| (type $sub-desc (sub $super-desc (describes $sub) (struct (field externref i64)))) |
| ) |
| |
| ;; CHECK: (type $4 (func)) |
| |
| ;; CHECK: (import "" "" (table $t 1 (ref null $super))) |
| (import "" "" (table $t 1 (ref null $super))) |
| |
| ;; CHECK: (func $use-sub (type $4) |
| ;; CHECK-NEXT: (local $0 (ref null $sub)) |
| ;; CHECK-NEXT: ) |
| (func $use-sub |
| (local (ref null $sub)) |
| ) |
| ) |
| |
| (module |
| ;; The supertype flows out via an exported table. We cannot optimize the |
| ;; externref field in $sub-desc. |
| (rec |
| ;; CHECK: (rec |
| ;; CHECK-NEXT: (type $super (sub (descriptor $super-desc) (struct (field i32)))) |
| (type $super (sub (descriptor $super-desc) (struct (field i32)))) |
| ;; CHECK: (type $super-desc (sub (describes $super) (struct))) |
| (type $super-desc (sub (describes $super) (struct))) |
| ) |
| (rec |
| ;; CHECK: (rec |
| ;; CHECK-NEXT: (type $sub (sub $super (descriptor $sub-desc) (struct (field i32)))) |
| (type $sub (sub $super (descriptor $sub-desc) (struct (field i32 i64)))) |
| ;; CHECK: (type $sub-desc (sub $super-desc (describes $sub) (struct (field externref)))) |
| (type $sub-desc (sub $super-desc (describes $sub) (struct (field externref i64)))) |
| ) |
| |
| ;; CHECK: (type $4 (func)) |
| |
| ;; CHECK: (table $t 1 (ref null $super)) |
| (table $t (export "export") 1 (ref null $super)) |
| |
| ;; CHECK: (export "export" (table $t)) |
| |
| ;; CHECK: (func $use-sub (type $4) |
| ;; CHECK-NEXT: (local $0 (ref null $sub)) |
| ;; CHECK-NEXT: ) |
| (func $use-sub |
| (local (ref null $sub)) |
| ) |
| ) |