blob: 6376b7553f3d29e8faa42bb0b6356e0fa10d52ae [file] [edit]
;; 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))
)
)