blob: f9713a4b4c358b2116d292b3add6704519036c78 [file]
;; NOTE: Assertions have been generated by update_lit_checks.py --all-items and should not be edited.
;; RUN: foreach %s %t wasm-opt -all --make-shared-objects -S -o - | filecheck %s
(module
;; Check lowering of basic heap types.
;; CHECK: (type $0 (func (param (ref null (shared none))) (result (ref null (shared none)))))
;; CHECK: (type $1 (func (param (ref (shared none))) (result (ref (shared none)))))
;; CHECK: (type $2 (func (param (ref null (shared i31))) (result (ref null (shared i31)))))
;; CHECK: (type $3 (func (param (ref (shared i31))) (result (ref (shared i31)))))
;; CHECK: (type $4 (func (param (ref null (shared any))) (result (ref null (shared any)))))
;; CHECK: (type $5 (func (param (ref (shared any))) (result (ref (shared any)))))
;; CHECK: (type $6 (func (param (ref null (shared eq))) (result (ref null (shared eq)))))
;; CHECK: (type $7 (func (param (ref (shared eq))) (result (ref (shared eq)))))
;; CHECK: (type $8 (func (param (ref null (shared struct))) (result (ref null (shared struct)))))
;; CHECK: (type $9 (func (param (ref (shared struct))) (result (ref (shared struct)))))
;; CHECK: (type $10 (func (param (ref null (shared array))) (result (ref null (shared array)))))
;; CHECK: (type $11 (func (param (ref (shared array))) (result (ref (shared array)))))
;; CHECK: (func $funcref (type $2) (param $0 (ref null (shared i31))) (result (ref null (shared i31)))
;; CHECK-NEXT: (local $1 (ref null (shared i31)))
;; CHECK-NEXT: (local.get $0)
;; CHECK-NEXT: )
(func $funcref (param funcref) (result funcref)
(local funcref)
(local.get 0)
)
;; CHECK: (func $shared-funcref (type $3) (param $0 (ref (shared i31))) (result (ref (shared i31)))
;; CHECK-NEXT: (local $1 (ref (shared i31)))
;; CHECK-NEXT: (local.get $0)
;; CHECK-NEXT: )
(func $shared-funcref (param (ref (shared func))) (result (ref (shared func)))
(local (ref (shared func)))
(local.get 0)
)
;; CHECK: (func $nullfuncref (type $0) (param $0 (ref null (shared none))) (result (ref null (shared none)))
;; CHECK-NEXT: (local $1 (ref null (shared none)))
;; CHECK-NEXT: (local.get $0)
;; CHECK-NEXT: )
(func $nullfuncref (param nullfuncref) (result nullfuncref)
(local nullfuncref)
(local.get 0)
)
;; CHECK: (func $shared-nullfuncref (type $1) (param $0 (ref (shared none))) (result (ref (shared none)))
;; CHECK-NEXT: (local $1 (ref (shared none)))
;; CHECK-NEXT: (local.get $0)
;; CHECK-NEXT: )
(func $shared-nullfuncref (param (ref (shared nofunc))) (result (ref (shared nofunc)))
(local (ref (shared nofunc)))
(local.get 0)
)
;; CHECK: (func $anyref (type $4) (param $0 (ref null (shared any))) (result (ref null (shared any)))
;; CHECK-NEXT: (local $1 (ref null (shared any)))
;; CHECK-NEXT: (local.get $0)
;; CHECK-NEXT: )
(func $anyref (param anyref) (result anyref)
(local anyref)
(local.get 0)
)
;; CHECK: (func $shared-anyref (type $5) (param $0 (ref (shared any))) (result (ref (shared any)))
;; CHECK-NEXT: (local $1 (ref (shared any)))
;; CHECK-NEXT: (local.get $0)
;; CHECK-NEXT: )
(func $shared-anyref (param (ref (shared any))) (result (ref (shared any)))
(local (ref (shared any)))
(local.get 0)
)
;; CHECK: (func $eqref (type $6) (param $0 (ref null (shared eq))) (result (ref null (shared eq)))
;; CHECK-NEXT: (local $1 (ref null (shared eq)))
;; CHECK-NEXT: (local.get $0)
;; CHECK-NEXT: )
(func $eqref (param eqref) (result eqref)
(local eqref)
(local.get 0)
)
;; CHECK: (func $shared-eqref (type $7) (param $0 (ref (shared eq))) (result (ref (shared eq)))
;; CHECK-NEXT: (local $1 (ref (shared eq)))
;; CHECK-NEXT: (local.get $0)
;; CHECK-NEXT: )
(func $shared-eqref (param (ref (shared eq))) (result (ref (shared eq)))
(local (ref (shared eq)))
(local.get 0)
)
;; CHECK: (func $structref (type $8) (param $0 (ref null (shared struct))) (result (ref null (shared struct)))
;; CHECK-NEXT: (local $1 (ref null (shared struct)))
;; CHECK-NEXT: (local.get $0)
;; CHECK-NEXT: )
(func $structref (param structref) (result structref)
(local structref)
(local.get 0)
)
;; CHECK: (func $shared-structref (type $9) (param $0 (ref (shared struct))) (result (ref (shared struct)))
;; CHECK-NEXT: (local $1 (ref (shared struct)))
;; CHECK-NEXT: (local.get $0)
;; CHECK-NEXT: )
(func $shared-structref (param (ref (shared struct))) (result (ref (shared struct)))
(local (ref (shared struct)))
(local.get 0)
)
;; CHECK: (func $arrayref (type $10) (param $0 (ref null (shared array))) (result (ref null (shared array)))
;; CHECK-NEXT: (local $1 (ref null (shared array)))
;; CHECK-NEXT: (local.get $0)
;; CHECK-NEXT: )
(func $arrayref (param arrayref) (result arrayref)
(local arrayref)
(local.get 0)
)
;; CHECK: (func $shared-arrayref (type $11) (param $0 (ref (shared array))) (result (ref (shared array)))
;; CHECK-NEXT: (local $1 (ref (shared array)))
;; CHECK-NEXT: (local.get $0)
;; CHECK-NEXT: )
(func $shared-arrayref (param (ref (shared array))) (result (ref (shared array)))
(local (ref (shared array)))
(local.get 0)
)
;; CHECK: (func $nullref (type $0) (param $0 (ref null (shared none))) (result (ref null (shared none)))
;; CHECK-NEXT: (local $1 (ref null (shared none)))
;; CHECK-NEXT: (local.get $0)
;; CHECK-NEXT: )
(func $nullref (param nullref) (result nullref)
(local nullref)
(local.get 0)
)
;; CHECK: (func $shared-nullref (type $1) (param $0 (ref (shared none))) (result (ref (shared none)))
;; CHECK-NEXT: (local $1 (ref (shared none)))
;; CHECK-NEXT: (local.get $0)
;; CHECK-NEXT: )
(func $shared-nullref (param (ref (shared none))) (result (ref (shared none)))
(local (ref (shared none)))
(local.get 0)
)
;; TODO: Handle exnref, contref.
)
;; Recursive function types should be updated correctly.
(module
;; CHECK: (type $func (func (param (ref (shared i31))) (result (ref (shared i31)))))
(type $func (func (param (ref $func)) (result (ref $func))))
;; CHECK: (func $f (type $func) (param $0 (ref (shared i31))) (result (ref (shared i31)))
;; CHECK-NEXT: (local $1 (ref (shared i31)))
;; CHECK-NEXT: (local.get $0)
;; CHECK-NEXT: )
(func $f (type $func) (param (ref $func)) (result (ref $func))
(local (ref $func))
(local.get 0)
)
)
(module
;; Struct and array types should become shared. Function references inside
;; them should become shared i31refs. Shared struct and array types should
;; remain shared. Function types should become unshared. Distinct shared and
;; and unshared types can be merged, but that's ok because their values can
;; never flow into the same locations.
(type $func (func))
;; CHECK: (type $array (shared (array (ref (shared i31)))))
;; CHECK: (type $shared-func (func))
;; CHECK: (type $struct (shared (struct (field (ref (shared i31))) (field i32))))
(type $struct (struct (field (ref $func)) (field i32)))
(type $array (array (ref (exact $func))))
(type $shared-func (shared (func)))
;; CHECK: (type $shared-struct (shared (struct (field (ref null (shared i31))))))
(type $shared-struct (shared (struct (field (ref null (exact $shared-func))))))
(type $shared-array (shared (array (ref $shared-func))))
;; CHECK: (type $4 (func (param (ref $struct) (ref $array) (ref $shared-struct) (ref $array))))
;; CHECK: (func $use-types (type $4) (param $0 (ref $struct)) (param $1 (ref $array)) (param $2 (ref $shared-struct)) (param $3 (ref $array))
;; CHECK-NEXT: (nop)
;; CHECK-NEXT: )
(func $use-types (param (ref $struct) (ref $array) (ref $shared-struct) (ref $shared-array))
(nop)
)
;; CHECK: (func $f (type $shared-func)
;; CHECK-NEXT: (nop)
;; CHECK-NEXT: )
(func $f (type $func)
(nop)
)
;; CHECK: (func $f-shared (type $shared-func)
;; CHECK-NEXT: (nop)
;; CHECK-NEXT: )
(func $f-shared (type $shared-func)
(nop)
)
)
(module
;; Rec groups containing mutually recursive struct, array, and function types
;; should be preserved.
(rec
;; CHECK: (rec
;; CHECK-NEXT: (type $rec-func (func (param (ref $rec-struct))))
(type $rec-func (func (param (ref $rec-struct))))
;; CHECK: (type $rec-struct (shared (struct (field (ref $rec-array)) (field (ref (shared i31))))))
(type $rec-struct (struct (field (ref $rec-array)) (field (ref $rec-func))))
;; CHECK: (type $rec-array (shared (array (ref $rec-struct))))
(type $rec-array (array (ref $rec-struct)))
)
;; CHECK: (type $3 (func (param (ref $rec-struct) (ref $rec-array) (ref (shared i31)))))
;; CHECK: (func $rec-group (type $3) (param $0 (ref $rec-struct)) (param $1 (ref $rec-array)) (param $2 (ref (shared i31)))
;; CHECK-NEXT: (nop)
;; CHECK-NEXT: )
(func $rec-group (param (ref $rec-struct) (ref $rec-array) (ref $rec-func))
(nop)
)
)
(module
;; Function supertypes are preserved.
;; CHECK: (type $parent (sub (func)))
(type $parent (sub (shared (func))))
;; CHECK: (type $child (sub $parent (func)))
(type $child (sub $parent (shared (func))))
;; CHECK: (func $f1 (type $parent)
;; CHECK-NEXT: (nop)
;; CHECK-NEXT: )
(func $f1 (type $parent)
(nop)
)
;; CHECK: (func $f2 (type $child)
;; CHECK-NEXT: (nop)
;; CHECK-NEXT: )
(func $f2 (type $child)
(nop)
)
)
(module
;; Struct descriptor and described types become shared correctly.
(rec
;; CHECK: (rec
;; CHECK-NEXT: (type $struct (shared (descriptor $desc) (struct (field i32))))
(type $struct (descriptor $desc) (struct (field i32)))
;; CHECK: (type $desc (shared (describes $struct) (struct (field i32))))
(type $desc (describes $struct) (struct (field i32)))
)
;; CHECK: (type $2 (func (param (ref $struct) (ref $desc))))
;; CHECK: (func $descriptors (type $2) (param $0 (ref $struct)) (param $1 (ref $desc))
;; CHECK-NEXT: (nop)
;; CHECK-NEXT: )
(func $descriptors (param (ref $struct) (ref $desc))
(nop)
)
)
;; Check that references to different functions are consistently assigned
;; different indices. This module does not use the references with a call or
;; cast, so it does not get the new table.
(module
;; CHECK: (type $f (func))
(type $f (func))
;; CHECK: (type $1 (func (result (ref null (shared none)))))
;; CHECK: (type $2 (func (result (ref null (shared i31)))))
;; CHECK: (type $3 (func (result (ref (shared i31)))))
;; CHECK: (func $target1 (type $f)
;; CHECK-NEXT: )
(func $target1 (type $f))
;; CHECK: (func $target2 (type $f)
;; CHECK-NEXT: )
(func $target2 (type $f))
;; CHECK: (func $ref-null-nofunc (type $1) (result (ref null (shared none)))
;; CHECK-NEXT: (ref.null (shared none))
;; CHECK-NEXT: )
(func $ref-null-nofunc (result (ref null nofunc))
;; (ref.null nofunc) becomes (ref.null (shared none)).
(ref.null nofunc)
)
;; CHECK: (func $ref-null-shared-nofunc (type $1) (result (ref null (shared none)))
;; CHECK-NEXT: (ref.null (shared none))
;; CHECK-NEXT: )
(func $ref-null-shared-nofunc (result (ref null (shared nofunc)))
;; Same with a shared nofunc.
(ref.null (shared nofunc))
)
;; CHECK: (func $ref-func (type $2) (result (ref null (shared i31)))
;; CHECK-NEXT: (ref.i31_shared
;; CHECK-NEXT: (i32.const 0)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $ref-func (result funcref)
;; ref.func becomes a shared i31.
(ref.func $target1)
)
;; CHECK: (func $other-ref-func (type $3) (result (ref (shared i31)))
;; CHECK-NEXT: (ref.i31_shared
;; CHECK-NEXT: (i32.const 1)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $other-ref-func (result (ref (exact $f)))
;; Different referenced function, different i31 value.
(ref.func $target2)
)
;; CHECK: (func $multiple-ref-func (type $f)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.i31_shared
;; CHECK-NEXT: (i32.const 0)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.i31_shared
;; CHECK-NEXT: (i32.const 0)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.i31_shared
;; CHECK-NEXT: (i32.const 1)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $multiple-ref-func
;; Mapping of functions to i31 values should be consistent.
(drop (ref.func $target1))
(drop (ref.func $target1))
(drop (ref.func $target2))
)
)
;; Test replacement of references in module locations and lowering of calls.
(module
(type $sig (func (param i32) (result i32)))
;; CHECK: (type $0 (func (result i32)))
;; CHECK: (type $shared-sig (func (param i32) (result i32)))
(type $shared-sig (shared (func (param i32) (result i32))))
;; CHECK: (type $2 (func))
;; CHECK: (type $struct (shared (struct (field (ref null (shared i31))))))
(type $struct (struct (field (ref null func))))
(func $effect (import "" "") (result i32))
;; CHECK: (type $4 (func (param (ref (shared i31)) i32) (result i32)))
;; CHECK: (type $5 (func (param (ref (shared i31))) (result i32)))
;; CHECK: (type $6 (func (param i32 i32) (result i32)))
;; CHECK: (import "" "" (func $effect (type $0) (result i32)))
;; CHECK: (global $g (ref null (shared i31)) (ref.i31_shared
;; CHECK-NEXT: (i32.const 0)
;; CHECK-NEXT: ))
(global $g (ref null func) (ref.func $a))
;; CHECK: (global $g-struct (ref null $struct) (struct.new $struct
;; CHECK-NEXT: (ref.i31_shared
;; CHECK-NEXT: (i32.const 1)
;; CHECK-NEXT: )
;; CHECK-NEXT: ))
(global $g-struct (ref null $struct) (struct.new $struct (ref.func $b)))
;; CHECK: (table $t-init 1 1 (ref null (shared i31)) (ref.i31_shared
;; CHECK-NEXT: (i32.const 3)
;; CHECK-NEXT: ))
(table $t-init 1 1 (ref null func) (ref.func $c))
;; CHECK: (table $t 1 1 (ref null (shared i31)))
(table $t 1 1 (ref null $sig))
;; CHECK: (table $t-shared 1 1 (ref null (shared i31)))
(table $t-shared 1 1 (ref null (shared func)))
;; CHECK: (table $funcs 4 4 funcref)
;; CHECK: (elem $elem (ref null (shared i31)) (item (ref.i31_shared
;; CHECK-NEXT: (i32.const 2)
;; CHECK-NEXT: )))
(elem $elem funcref (ref.func $d))
;; CHECK: (elem $funcs (table $funcs) (i32.const 0) func $a $b $d $c)
;; CHECK: (func $a (type $2)
;; CHECK-NEXT: )
(func $a)
;; CHECK: (func $b (type $2)
;; CHECK-NEXT: )
(func $b)
;; CHECK: (func $c (type $2)
;; CHECK-NEXT: )
(func $c)
;; CHECK: (func $d (type $2)
;; CHECK-NEXT: )
(func $d)
;; CHECK: (func $call-ref (type $4) (param $0 (ref (shared i31))) (param $1 i32) (result i32)
;; CHECK-NEXT: (call_indirect $funcs (type $shared-sig)
;; CHECK-NEXT: (local.get $1)
;; CHECK-NEXT: (i31.get_u
;; CHECK-NEXT: (local.get $0)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $call-ref (param (ref $sig) i32) (result i32)
(call_ref $sig (local.get 1) (local.get 0))
)
;; CHECK: (func $unreachable-call-ref (type $0) (result i32)
;; CHECK-NEXT: (unreachable)
;; CHECK-NEXT: (unreachable)
;; CHECK-NEXT: )
(func $unreachable-call-ref (result i32)
(call_ref $sig (i32.const 0) (unreachable))
)
;; CHECK: (func $unreachable-call-ref-effect (type $0) (result i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (call $effect)
;; CHECK-NEXT: )
;; CHECK-NEXT: (unreachable)
;; CHECK-NEXT: (unreachable)
;; CHECK-NEXT: )
(func $unreachable-call-ref-effect (result i32)
(call_ref $sig (call $effect) (unreachable))
)
;; CHECK: (func $null-call-ref (type $0) (result i32)
;; CHECK-NEXT: (unreachable)
;; CHECK-NEXT: )
(func $null-call-ref (result i32)
(call_ref $sig (i32.const 0) (ref.null nofunc))
)
;; CHECK: (func $null-call-ref-effect (type $0) (result i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (call $effect)
;; CHECK-NEXT: )
;; CHECK-NEXT: (unreachable)
;; CHECK-NEXT: )
(func $null-call-ref-effect (result i32)
(call_ref $sig (call $effect) (ref.null nofunc))
)
;; CHECK: (func $shared-call-ref (type $5) (param $0 (ref (shared i31))) (result i32)
;; CHECK-NEXT: (call_indirect $funcs (type $shared-sig)
;; CHECK-NEXT: (i32.const 42)
;; CHECK-NEXT: (i31.get_u
;; CHECK-NEXT: (local.get $0)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $shared-call-ref (param (ref $shared-sig)) (result i32)
(call_ref $shared-sig (i32.const 42) (local.get 0))
)
;; CHECK: (func $shared-unreachable-call-ref (type $0) (result i32)
;; CHECK-NEXT: (unreachable)
;; CHECK-NEXT: (unreachable)
;; CHECK-NEXT: )
(func $shared-unreachable-call-ref (result i32)
(call_ref $shared-sig (i32.const 0) (unreachable))
)
;; CHECK: (func $shared-unreachable-call-ref-effect (type $0) (result i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (call $effect)
;; CHECK-NEXT: )
;; CHECK-NEXT: (unreachable)
;; CHECK-NEXT: (unreachable)
;; CHECK-NEXT: )
(func $shared-unreachable-call-ref-effect (result i32)
(call_ref $shared-sig (call $effect) (unreachable))
)
;; CHECK: (func $shared-null-call-ref (type $0) (result i32)
;; CHECK-NEXT: (unreachable)
;; CHECK-NEXT: )
(func $shared-null-call-ref (result i32)
(call_ref $shared-sig (i32.const 0) (ref.null (shared nofunc)))
)
;; CHECK: (func $shared-null-call-ref-effect (type $0) (result i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (call $effect)
;; CHECK-NEXT: )
;; CHECK-NEXT: (unreachable)
;; CHECK-NEXT: )
(func $shared-null-call-ref-effect (result i32)
(call_ref $shared-sig (call $effect) (ref.null (shared nofunc)))
)
;; CHECK: (func $return-call-ref (type $4) (param $0 (ref (shared i31))) (param $1 i32) (result i32)
;; CHECK-NEXT: (return_call_indirect $funcs (type $shared-sig)
;; CHECK-NEXT: (local.get $1)
;; CHECK-NEXT: (i31.get_u
;; CHECK-NEXT: (local.get $0)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $return-call-ref (param (ref $sig) i32) (result i32)
(return_call_ref $sig (local.get 1) (local.get 0))
)
;; call_indirect lowering
;; CHECK: (func $call-indirect (type $6) (param $0 i32) (param $1 i32) (result i32)
;; CHECK-NEXT: (call_indirect $funcs (type $shared-sig)
;; CHECK-NEXT: (local.get $0)
;; CHECK-NEXT: (i31.get_u
;; CHECK-NEXT: (table.get $t
;; CHECK-NEXT: (local.get $1)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $call-indirect (param i32 i32) (result i32)
(call_indirect $t (type $sig) (local.get 0) (local.get 1))
)
;; Unreachable call_indirect lowering.
;; CHECK: (func $unreachable-call-indirect (type $0) (result i32)
;; CHECK-NEXT: (call_indirect $funcs (type $shared-sig)
;; CHECK-NEXT: (i32.const 0)
;; CHECK-NEXT: (i31.get_u
;; CHECK-NEXT: (table.get $t
;; CHECK-NEXT: (unreachable)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $unreachable-call-indirect (result i32)
(call_indirect $t (type $sig) (i32.const 0) (unreachable))
)
;; call_indirect lowering of shared function.
;; CHECK: (func $shared-call-indirect (type $shared-sig) (param $0 i32) (result i32)
;; CHECK-NEXT: (call_indirect $funcs (type $shared-sig)
;; CHECK-NEXT: (i32.const 42)
;; CHECK-NEXT: (i31.get_u
;; CHECK-NEXT: (table.get $t-shared
;; CHECK-NEXT: (local.get $0)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $shared-call-indirect (param i32) (result i32)
(call_indirect $t-shared (type $shared-sig) (i32.const 42) (local.get 0))
)
;; unreachable call_indirect
;; CHECK: (func $unreachable-param-call-indirect (type $shared-sig) (param $0 i32) (result i32)
;; CHECK-NEXT: (call_indirect $funcs (type $shared-sig)
;; CHECK-NEXT: (unreachable)
;; CHECK-NEXT: (i31.get_u
;; CHECK-NEXT: (table.get $t
;; CHECK-NEXT: (local.get $0)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $unreachable-param-call-indirect (param i32) (result i32)
(call_indirect $t (type $sig) (unreachable) (local.get 0))
)
)
;; Test lowering of ref.test and ref.cast.
(module
(type $sig (func (param i32) (result i32)))
;; CHECK: (type $shared-sig (func (param i32) (result i32)))
(type $shared-sig (shared (func (param i32) (result i32))))
;; CHECK: (type $1 (func (param (ref null (shared i31))) (result i32)))
;; CHECK: (type $2 (func (param (ref null (shared i31))) (result (ref null (shared i31)))))
;; CHECK: (type $struct (shared (struct (field i32))))
(type $struct (struct (field i32)))
;; ref.test of funcref
;; CHECK: (type $4 (func (param (ref null (shared i31))) (result (ref (shared i31)))))
;; CHECK: (type $5 (func (param (ref (shared i31))) (result i32)))
;; CHECK: (type $6 (func (result i32)))
;; CHECK: (type $7 (func (param (ref null (shared i31))) (result (ref (shared none)))))
;; CHECK: (type $8 (func (param (ref null (shared i31))) (result (ref null (shared none)))))
;; CHECK: (type $9 (func (param (ref (shared i31))) (result (ref (shared i31)))))
;; CHECK: (type $10 (func (result (ref null (shared i31)))))
;; CHECK: (type $11 (func (param (ref null (shared any))) (result i32)))
;; CHECK: (type $12 (func (param (ref null $struct)) (result i32)))
;; CHECK: (type $13 (func (param (ref null (shared any))) (result (ref null (shared i31)))))
;; CHECK: (type $14 (func (param (ref null $struct)) (result (ref null $struct))))
;; CHECK: (table $funcs 0 0 funcref)
;; CHECK: (func $ref-test-func (type $1) (param $0 (ref null (shared i31))) (result i32)
;; CHECK-NEXT: (ref.test (ref (shared i31))
;; CHECK-NEXT: (local.get $0)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $ref-test-func (param funcref) (result i32)
(ref.test (ref func) (local.get 0))
)
;; CHECK: (func $ref-test-funcref (type $1) (param $0 (ref null (shared i31))) (result i32)
;; CHECK-NEXT: (ref.test (ref null (shared i31))
;; CHECK-NEXT: (local.get $0)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $ref-test-funcref (param funcref) (result i32)
(ref.test (ref null func) (local.get 0))
)
;; CHECK: (func $ref-test-nofunc (type $1) (param $0 (ref null (shared i31))) (result i32)
;; CHECK-NEXT: (ref.test (ref (shared none))
;; CHECK-NEXT: (local.get $0)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $ref-test-nofunc (param funcref) (result i32)
(ref.test (ref nofunc) (local.get 0))
)
;; CHECK: (func $ref-test-null-nofunc (type $1) (param $0 (ref null (shared i31))) (result i32)
;; CHECK-NEXT: (ref.test (ref null (shared none))
;; CHECK-NEXT: (local.get $0)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $ref-test-null-nofunc (param funcref) (result i32)
(ref.test (ref null nofunc) (local.get 0))
)
;; CHECK: (func $ref-test-shared-func (type $1) (param $0 (ref null (shared i31))) (result i32)
;; CHECK-NEXT: (ref.test (ref (shared i31))
;; CHECK-NEXT: (local.get $0)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $ref-test-shared-func (param (ref null (shared func))) (result i32)
(ref.test (ref (shared func)) (local.get 0))
)
;; CHECK: (func $ref-test-shared-funcref (type $1) (param $0 (ref null (shared i31))) (result i32)
;; CHECK-NEXT: (ref.test (ref null (shared i31))
;; CHECK-NEXT: (local.get $0)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $ref-test-shared-funcref (param (ref null (shared func))) (result i32)
(ref.test (ref null (shared func)) (local.get 0))
)
;; CHECK: (func $ref-test-shared-nofunc (type $1) (param $0 (ref null (shared i31))) (result i32)
;; CHECK-NEXT: (ref.test (ref (shared none))
;; CHECK-NEXT: (local.get $0)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $ref-test-shared-nofunc (param (ref null (shared func))) (result i32)
(ref.test (ref (shared nofunc)) (local.get 0))
)
;; CHECK: (func $ref-test-null-shared-nofunc (type $1) (param $0 (ref null (shared i31))) (result i32)
;; CHECK-NEXT: (ref.test (ref null (shared none))
;; CHECK-NEXT: (local.get $0)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $ref-test-null-shared-nofunc (param (ref null (shared func))) (result i32)
(ref.test (ref null (shared nofunc)) (local.get 0))
)
;; CHECK: (func $ref-test-i31 (type $11) (param $0 (ref null (shared any))) (result i32)
;; CHECK-NEXT: (ref.test (ref null (shared i31))
;; CHECK-NEXT: (local.get $0)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $ref-test-i31 (param (ref null any)) (result i32)
(ref.test (ref null i31) (local.get 0))
)
;; CHECK: (func $ref-test-no-nulls (type $5) (param $0 (ref (shared i31))) (result i32)
;; CHECK-NEXT: (ref.test (ref $shared-sig)
;; CHECK-NEXT: (table.get $funcs
;; CHECK-NEXT: (i31.get_u
;; CHECK-NEXT: (local.get $0)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $ref-test-no-nulls (param (ref func)) (result i32)
(ref.test (ref $sig) (local.get 0))
)
;; CHECK: (func $ref-test-non-nullable (type $1) (param $0 (ref null (shared i31))) (result i32)
;; CHECK-NEXT: (local $1 (ref null (shared i31)))
;; CHECK-NEXT: (if (result i32)
;; CHECK-NEXT: (ref.is_null
;; CHECK-NEXT: (local.tee $1
;; CHECK-NEXT: (local.get $0)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (then
;; CHECK-NEXT: (i32.const 0)
;; CHECK-NEXT: )
;; CHECK-NEXT: (else
;; CHECK-NEXT: (ref.test (ref $shared-sig)
;; CHECK-NEXT: (table.get $funcs
;; CHECK-NEXT: (i31.get_u
;; CHECK-NEXT: (local.get $1)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $ref-test-non-nullable (param funcref) (result i32)
(ref.test (ref $sig) (local.get 0))
)
;; CHECK: (func $ref-test-nullable (type $1) (param $0 (ref null (shared i31))) (result i32)
;; CHECK-NEXT: (local $1 (ref null (shared i31)))
;; CHECK-NEXT: (if (result i32)
;; CHECK-NEXT: (ref.is_null
;; CHECK-NEXT: (local.tee $1
;; CHECK-NEXT: (local.get $0)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (then
;; CHECK-NEXT: (i32.const 1)
;; CHECK-NEXT: )
;; CHECK-NEXT: (else
;; CHECK-NEXT: (ref.test (ref null $shared-sig)
;; CHECK-NEXT: (table.get $funcs
;; CHECK-NEXT: (i31.get_u
;; CHECK-NEXT: (local.get $1)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $ref-test-nullable (param funcref) (result i32)
(ref.test (ref null $sig) (local.get 0))
)
;; CHECK: (func $ref-test-nullable-exact (type $1) (param $0 (ref null (shared i31))) (result i32)
;; CHECK-NEXT: (local $1 (ref null (shared i31)))
;; CHECK-NEXT: (if (result i32)
;; CHECK-NEXT: (ref.is_null
;; CHECK-NEXT: (local.tee $1
;; CHECK-NEXT: (local.get $0)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (then
;; CHECK-NEXT: (i32.const 1)
;; CHECK-NEXT: )
;; CHECK-NEXT: (else
;; CHECK-NEXT: (ref.test (ref null (exact $shared-sig))
;; CHECK-NEXT: (table.get $funcs
;; CHECK-NEXT: (i31.get_u
;; CHECK-NEXT: (local.get $1)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $ref-test-nullable-exact (param funcref) (result i32)
(ref.test (ref null (exact $sig)) (local.get 0))
)
;; CHECK: (func $ref-test-shared-no-nulls (type $5) (param $0 (ref (shared i31))) (result i32)
;; CHECK-NEXT: (ref.test (ref $shared-sig)
;; CHECK-NEXT: (table.get $funcs
;; CHECK-NEXT: (i31.get_u
;; CHECK-NEXT: (local.get $0)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $ref-test-shared-no-nulls (param (ref (shared func))) (result i32)
(ref.test (ref $shared-sig) (local.get 0))
)
;; CHECK: (func $ref-test-shared-non-nullable (type $1) (param $0 (ref null (shared i31))) (result i32)
;; CHECK-NEXT: (local $1 (ref null (shared i31)))
;; CHECK-NEXT: (if (result i32)
;; CHECK-NEXT: (ref.is_null
;; CHECK-NEXT: (local.tee $1
;; CHECK-NEXT: (local.get $0)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (then
;; CHECK-NEXT: (i32.const 0)
;; CHECK-NEXT: )
;; CHECK-NEXT: (else
;; CHECK-NEXT: (ref.test (ref $shared-sig)
;; CHECK-NEXT: (table.get $funcs
;; CHECK-NEXT: (i31.get_u
;; CHECK-NEXT: (local.get $1)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $ref-test-shared-non-nullable (param (ref null (shared func))) (result i32)
(ref.test (ref $shared-sig) (local.get 0))
)
;; CHECK: (func $ref-test-shared-nullable (type $1) (param $0 (ref null (shared i31))) (result i32)
;; CHECK-NEXT: (local $1 (ref null (shared i31)))
;; CHECK-NEXT: (if (result i32)
;; CHECK-NEXT: (ref.is_null
;; CHECK-NEXT: (local.tee $1
;; CHECK-NEXT: (local.get $0)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (then
;; CHECK-NEXT: (i32.const 1)
;; CHECK-NEXT: )
;; CHECK-NEXT: (else
;; CHECK-NEXT: (ref.test (ref null $shared-sig)
;; CHECK-NEXT: (table.get $funcs
;; CHECK-NEXT: (i31.get_u
;; CHECK-NEXT: (local.get $1)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $ref-test-shared-nullable (param (ref null (shared func))) (result i32)
(ref.test (ref null $shared-sig) (local.get 0))
)
;; CHECK: (func $ref-test-shared-nullable-exact (type $1) (param $0 (ref null (shared i31))) (result i32)
;; CHECK-NEXT: (local $1 (ref null (shared i31)))
;; CHECK-NEXT: (if (result i32)
;; CHECK-NEXT: (ref.is_null
;; CHECK-NEXT: (local.tee $1
;; CHECK-NEXT: (local.get $0)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (then
;; CHECK-NEXT: (i32.const 1)
;; CHECK-NEXT: )
;; CHECK-NEXT: (else
;; CHECK-NEXT: (ref.test (ref null (exact $shared-sig))
;; CHECK-NEXT: (table.get $funcs
;; CHECK-NEXT: (i31.get_u
;; CHECK-NEXT: (local.get $1)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $ref-test-shared-nullable-exact (param (ref null (shared func))) (result i32)
(ref.test (ref null (exact $shared-sig)) (local.get 0))
)
;; ref.test with null input
;; CHECK: (func $ref-test-null-input (type $6) (result i32)
;; CHECK-NEXT: (ref.test (ref null (shared none))
;; CHECK-NEXT: (ref.null (shared none))
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $ref-test-null-input (result i32)
(ref.test (ref null $sig) (ref.null nofunc))
)
;; ref.test with unreachable input
;; CHECK: (func $ref-test-unreachable-input (type $6) (result i32)
;; CHECK-NEXT: (ref.test (ref null $shared-sig)
;; CHECK-NEXT: (unreachable)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $ref-test-unreachable-input (result i32)
(ref.test (ref null $sig) (unreachable))
)
;; ref.test of non-function type.
;; CHECK: (func $ref-test-non-func (type $12) (param $0 (ref null $struct)) (result i32)
;; CHECK-NEXT: (ref.test (ref null $struct)
;; CHECK-NEXT: (local.get $0)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $ref-test-non-func (param (ref null $struct)) (result i32)
;; This should not be changed.
(ref.test (ref null $struct) (local.get 0))
)
;; CHECK: (func $ref-cast-func (type $4) (param $0 (ref null (shared i31))) (result (ref (shared i31)))
;; CHECK-NEXT: (ref.cast (ref (shared i31))
;; CHECK-NEXT: (local.get $0)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $ref-cast-func (param funcref) (result (ref func))
(ref.cast (ref func) (local.get 0))
)
;; CHECK: (func $ref-cast-funcref (type $2) (param $0 (ref null (shared i31))) (result (ref null (shared i31)))
;; CHECK-NEXT: (ref.cast (ref null (shared i31))
;; CHECK-NEXT: (local.get $0)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $ref-cast-funcref (param funcref) (result (ref null func))
(ref.cast (ref null func) (local.get 0))
)
;; CHECK: (func $ref-cast-nofunc (type $7) (param $0 (ref null (shared i31))) (result (ref (shared none)))
;; CHECK-NEXT: (ref.cast (ref (shared none))
;; CHECK-NEXT: (local.get $0)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $ref-cast-nofunc (param funcref) (result (ref nofunc))
(ref.cast (ref nofunc) (local.get 0))
)
;; CHECK: (func $ref-cast-null-nofunc (type $8) (param $0 (ref null (shared i31))) (result (ref null (shared none)))
;; CHECK-NEXT: (ref.cast (ref null (shared none))
;; CHECK-NEXT: (local.get $0)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $ref-cast-null-nofunc (param funcref) (result (ref null nofunc))
(ref.cast (ref null nofunc) (local.get 0))
)
;; CHECK: (func $ref-cast-shared-func (type $4) (param $0 (ref null (shared i31))) (result (ref (shared i31)))
;; CHECK-NEXT: (ref.cast (ref (shared i31))
;; CHECK-NEXT: (local.get $0)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $ref-cast-shared-func (param (ref null (shared func))) (result (ref (shared func)))
(ref.cast (ref (shared func)) (local.get 0))
)
;; CHECK: (func $ref-cast-shared-funcref (type $2) (param $0 (ref null (shared i31))) (result (ref null (shared i31)))
;; CHECK-NEXT: (ref.cast (ref null (shared i31))
;; CHECK-NEXT: (local.get $0)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $ref-cast-shared-funcref (param (ref null (shared func))) (result (ref null (shared func)))
(ref.cast (ref null (shared func)) (local.get 0))
)
;; CHECK: (func $ref-cast-shared-nofunc (type $7) (param $0 (ref null (shared i31))) (result (ref (shared none)))
;; CHECK-NEXT: (ref.cast (ref (shared none))
;; CHECK-NEXT: (local.get $0)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $ref-cast-shared-nofunc (param (ref null (shared func))) (result (ref (shared nofunc)))
(ref.cast (ref (shared nofunc)) (local.get 0))
)
;; CHECK: (func $ref-cast-null-shared-nofunc (type $8) (param $0 (ref null (shared i31))) (result (ref null (shared none)))
;; CHECK-NEXT: (ref.cast (ref null (shared none))
;; CHECK-NEXT: (local.get $0)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $ref-cast-null-shared-nofunc (param (ref null (shared func))) (result (ref null (shared nofunc)))
(ref.cast (ref null (shared nofunc)) (local.get 0))
)
;; CHECK: (func $ref-cast-i31 (type $13) (param $0 (ref null (shared any))) (result (ref null (shared i31)))
;; CHECK-NEXT: (ref.cast (ref null (shared i31))
;; CHECK-NEXT: (local.get $0)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $ref-cast-i31 (param (ref null any)) (result (ref null i31))
(ref.cast (ref null i31) (local.get 0))
)
;; CHECK: (func $ref-cast-no-nulls (type $9) (param $0 (ref (shared i31))) (result (ref (shared i31)))
;; CHECK-NEXT: (local $1 (ref (shared i31)))
;; CHECK-NEXT: (if (result (ref (shared i31)))
;; CHECK-NEXT: (ref.is_null
;; CHECK-NEXT: (local.tee $1
;; CHECK-NEXT: (local.get $0)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (then
;; CHECK-NEXT: (unreachable)
;; CHECK-NEXT: )
;; CHECK-NEXT: (else
;; CHECK-NEXT: (if (result (ref (shared i31)))
;; CHECK-NEXT: (ref.test (ref $shared-sig)
;; CHECK-NEXT: (table.get $funcs
;; CHECK-NEXT: (i31.get_u
;; CHECK-NEXT: (local.get $1)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (then
;; CHECK-NEXT: (ref.as_non_null
;; CHECK-NEXT: (local.get $1)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (else
;; CHECK-NEXT: (unreachable)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $ref-cast-no-nulls (param (ref func)) (result (ref $sig))
(ref.cast (ref $sig) (local.get 0))
)
;; CHECK: (func $ref-cast-non-nullable (type $4) (param $0 (ref null (shared i31))) (result (ref (shared i31)))
;; CHECK-NEXT: (local $1 (ref null (shared i31)))
;; CHECK-NEXT: (if (result (ref (shared i31)))
;; CHECK-NEXT: (ref.is_null
;; CHECK-NEXT: (local.tee $1
;; CHECK-NEXT: (local.get $0)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (then
;; CHECK-NEXT: (unreachable)
;; CHECK-NEXT: )
;; CHECK-NEXT: (else
;; CHECK-NEXT: (if (result (ref (shared i31)))
;; CHECK-NEXT: (ref.test (ref $shared-sig)
;; CHECK-NEXT: (table.get $funcs
;; CHECK-NEXT: (i31.get_u
;; CHECK-NEXT: (local.get $1)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (then
;; CHECK-NEXT: (ref.as_non_null
;; CHECK-NEXT: (local.get $1)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (else
;; CHECK-NEXT: (unreachable)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $ref-cast-non-nullable (param funcref) (result (ref $sig))
(ref.cast (ref $sig) (local.get 0))
)
;; CHECK: (func $ref-cast-nullable (type $2) (param $0 (ref null (shared i31))) (result (ref null (shared i31)))
;; CHECK-NEXT: (local $1 (ref null (shared i31)))
;; CHECK-NEXT: (if (result (ref null (shared i31)))
;; CHECK-NEXT: (ref.is_null
;; CHECK-NEXT: (local.tee $1
;; CHECK-NEXT: (local.get $0)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (then
;; CHECK-NEXT: (local.get $1)
;; CHECK-NEXT: )
;; CHECK-NEXT: (else
;; CHECK-NEXT: (if (result (ref null (shared i31)))
;; CHECK-NEXT: (ref.test (ref null $shared-sig)
;; CHECK-NEXT: (table.get $funcs
;; CHECK-NEXT: (i31.get_u
;; CHECK-NEXT: (local.get $1)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (then
;; CHECK-NEXT: (local.get $1)
;; CHECK-NEXT: )
;; CHECK-NEXT: (else
;; CHECK-NEXT: (unreachable)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $ref-cast-nullable (param funcref) (result (ref null $sig))
(ref.cast (ref null $sig) (local.get 0))
)
;; CHECK: (func $ref-cast-nullable-exact (type $2) (param $0 (ref null (shared i31))) (result (ref null (shared i31)))
;; CHECK-NEXT: (local $1 (ref null (shared i31)))
;; CHECK-NEXT: (if (result (ref null (shared i31)))
;; CHECK-NEXT: (ref.is_null
;; CHECK-NEXT: (local.tee $1
;; CHECK-NEXT: (local.get $0)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (then
;; CHECK-NEXT: (local.get $1)
;; CHECK-NEXT: )
;; CHECK-NEXT: (else
;; CHECK-NEXT: (if (result (ref null (shared i31)))
;; CHECK-NEXT: (ref.test (ref null (exact $shared-sig))
;; CHECK-NEXT: (table.get $funcs
;; CHECK-NEXT: (i31.get_u
;; CHECK-NEXT: (local.get $1)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (then
;; CHECK-NEXT: (local.get $1)
;; CHECK-NEXT: )
;; CHECK-NEXT: (else
;; CHECK-NEXT: (unreachable)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $ref-cast-nullable-exact (param funcref) (result (ref null (exact $sig)))
(ref.cast (ref null (exact $sig)) (local.get 0))
)
;; CHECK: (func $ref-cast-shared-no-nulls (type $9) (param $0 (ref (shared i31))) (result (ref (shared i31)))
;; CHECK-NEXT: (local $1 (ref (shared i31)))
;; CHECK-NEXT: (if (result (ref (shared i31)))
;; CHECK-NEXT: (ref.is_null
;; CHECK-NEXT: (local.tee $1
;; CHECK-NEXT: (local.get $0)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (then
;; CHECK-NEXT: (unreachable)
;; CHECK-NEXT: )
;; CHECK-NEXT: (else
;; CHECK-NEXT: (if (result (ref (shared i31)))
;; CHECK-NEXT: (ref.test (ref $shared-sig)
;; CHECK-NEXT: (table.get $funcs
;; CHECK-NEXT: (i31.get_u
;; CHECK-NEXT: (local.get $1)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (then
;; CHECK-NEXT: (ref.as_non_null
;; CHECK-NEXT: (local.get $1)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (else
;; CHECK-NEXT: (unreachable)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $ref-cast-shared-no-nulls (param (ref (shared func))) (result (ref $shared-sig))
(ref.cast (ref $shared-sig) (local.get 0))
)
;; CHECK: (func $ref-cast-shared-non-nullable (type $4) (param $0 (ref null (shared i31))) (result (ref (shared i31)))
;; CHECK-NEXT: (local $1 (ref null (shared i31)))
;; CHECK-NEXT: (if (result (ref (shared i31)))
;; CHECK-NEXT: (ref.is_null
;; CHECK-NEXT: (local.tee $1
;; CHECK-NEXT: (local.get $0)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (then
;; CHECK-NEXT: (unreachable)
;; CHECK-NEXT: )
;; CHECK-NEXT: (else
;; CHECK-NEXT: (if (result (ref (shared i31)))
;; CHECK-NEXT: (ref.test (ref $shared-sig)
;; CHECK-NEXT: (table.get $funcs
;; CHECK-NEXT: (i31.get_u
;; CHECK-NEXT: (local.get $1)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (then
;; CHECK-NEXT: (ref.as_non_null
;; CHECK-NEXT: (local.get $1)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (else
;; CHECK-NEXT: (unreachable)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $ref-cast-shared-non-nullable (param (ref null (shared func))) (result (ref $shared-sig))
(ref.cast (ref $shared-sig) (local.get 0))
)
;; CHECK: (func $ref-cast-shared-nullable (type $2) (param $0 (ref null (shared i31))) (result (ref null (shared i31)))
;; CHECK-NEXT: (local $1 (ref null (shared i31)))
;; CHECK-NEXT: (if (result (ref null (shared i31)))
;; CHECK-NEXT: (ref.is_null
;; CHECK-NEXT: (local.tee $1
;; CHECK-NEXT: (local.get $0)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (then
;; CHECK-NEXT: (local.get $1)
;; CHECK-NEXT: )
;; CHECK-NEXT: (else
;; CHECK-NEXT: (if (result (ref null (shared i31)))
;; CHECK-NEXT: (ref.test (ref null $shared-sig)
;; CHECK-NEXT: (table.get $funcs
;; CHECK-NEXT: (i31.get_u
;; CHECK-NEXT: (local.get $1)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (then
;; CHECK-NEXT: (local.get $1)
;; CHECK-NEXT: )
;; CHECK-NEXT: (else
;; CHECK-NEXT: (unreachable)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $ref-cast-shared-nullable (param (ref null (shared func))) (result (ref null $shared-sig))
(ref.cast (ref null $shared-sig) (local.get 0))
)
;; CHECK: (func $ref-cast-shared-nullable-exact (type $2) (param $0 (ref null (shared i31))) (result (ref null (shared i31)))
;; CHECK-NEXT: (local $1 (ref null (shared i31)))
;; CHECK-NEXT: (if (result (ref null (shared i31)))
;; CHECK-NEXT: (ref.is_null
;; CHECK-NEXT: (local.tee $1
;; CHECK-NEXT: (local.get $0)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (then
;; CHECK-NEXT: (local.get $1)
;; CHECK-NEXT: )
;; CHECK-NEXT: (else
;; CHECK-NEXT: (if (result (ref null (shared i31)))
;; CHECK-NEXT: (ref.test (ref null (exact $shared-sig))
;; CHECK-NEXT: (table.get $funcs
;; CHECK-NEXT: (i31.get_u
;; CHECK-NEXT: (local.get $1)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (then
;; CHECK-NEXT: (local.get $1)
;; CHECK-NEXT: )
;; CHECK-NEXT: (else
;; CHECK-NEXT: (unreachable)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $ref-cast-shared-nullable-exact (param (ref null (shared func))) (result (ref null $shared-sig))
(ref.cast (ref null (exact $shared-sig)) (local.get 0))
)
;; CHECK: (func $ref-cast-null-input (type $10) (result (ref null (shared i31)))
;; CHECK-NEXT: (ref.cast (ref null (shared none))
;; CHECK-NEXT: (ref.null (shared none))
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $ref-cast-null-input (result (ref null $sig))
(ref.cast (ref null $sig) (ref.null nofunc))
)
;; CHECK: (func $ref-cast-unreachable-input (type $10) (result (ref null (shared i31)))
;; CHECK-NEXT: (block ;; (replaces unreachable RefCast we can't emit)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (unreachable)
;; CHECK-NEXT: )
;; CHECK-NEXT: (unreachable)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $ref-cast-unreachable-input (result (ref null $sig))
(ref.cast (ref null $sig) (unreachable))
)
;; CHECK: (func $ref-cast-non-func (type $14) (param $0 (ref null $struct)) (result (ref null $struct))
;; CHECK-NEXT: (ref.cast (ref null $struct)
;; CHECK-NEXT: (local.get $0)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $ref-cast-non-func (param (ref null $struct)) (result (ref null $struct))
;; This should not be changed.
(ref.cast (ref null $struct) (local.get 0))
)
;; CHECK: (func $br-on-cast-funcref (type $2) (param $0 (ref null (shared i31))) (result (ref null (shared i31)))
;; CHECK-NEXT: (block $label (result (ref null (shared i31)))
;; CHECK-NEXT: (br_on_cast $label (ref null (shared i31)) (ref null (shared i31))
;; CHECK-NEXT: (local.get $0)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $br-on-cast-funcref (param funcref) (result funcref)
(block $label (result funcref)
(br_on_cast $label funcref funcref (local.get 0))
)
)
;; CHECK: (func $br-on-cast-fail-funcref (type $2) (param $0 (ref null (shared i31))) (result (ref null (shared i31)))
;; CHECK-NEXT: (block $label (result (ref null (shared i31)))
;; CHECK-NEXT: (br_on_cast_fail $label (ref null (shared i31)) (ref null (shared i31))
;; CHECK-NEXT: (local.get $0)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $br-on-cast-fail-funcref (param funcref) (result funcref)
(block $label (result funcref)
(br_on_cast_fail $label funcref funcref (local.get 0))
)
)
;; CHECK: (func $br-on-cast-nullfuncref (type $2) (param $0 (ref null (shared i31))) (result (ref null (shared i31)))
;; CHECK-NEXT: (block $label (result (ref null (shared i31)))
;; CHECK-NEXT: (br_on_cast $label (ref null (shared i31)) (ref null (shared none))
;; CHECK-NEXT: (local.get $0)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $br-on-cast-nullfuncref (param funcref) (result funcref)
(block $label (result funcref)
(br_on_cast $label funcref nullfuncref (local.get 0))
)
)
;; CHECK: (func $br-on-cast-fail-nullfuncref (type $2) (param $0 (ref null (shared i31))) (result (ref null (shared i31)))
;; CHECK-NEXT: (block $label (result (ref null (shared i31)))
;; CHECK-NEXT: (br_on_cast_fail $label (ref null (shared i31)) (ref null (shared none))
;; CHECK-NEXT: (local.get $0)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $br-on-cast-fail-nullfuncref (param funcref) (result funcref)
(block $label (result funcref)
(br_on_cast_fail $label funcref nullfuncref (local.get 0))
)
)
;; TODO: other br_on_cast{_fail} lowering
)
(module
(type $sig (func (param i32) (result i32)))
;; Test that function types in globals, tables, element segments, and tags are updated.
;; CHECK: (type $0 (func (param (ref null (shared i31)))))
;; CHECK: (type $1 (func (param i32) (result (ref null (shared i31)))))
;; CHECK: (global $g (ref null (shared i31)) (ref.null (shared none)))
(global $g (ref null $sig) (ref.null $sig))
;; CHECK: (table $t 1 1 (ref null (shared i31)) (ref.null (shared none)))
(table $t 1 1 (ref null $sig) (ref.null $sig))
;; CHECK: (elem $e (ref null (shared i31)) (item (ref.null (shared none))))
(elem $e (ref null $sig) (ref.null $sig))
;; CHECK: (tag $tag (type $0) (param (ref null (shared i31))))
(tag $tag (param (ref null $sig)))
;; CHECK: (func $control-types (type $1) (param $0 i32) (result (ref null (shared i31)))
;; CHECK-NEXT: (if (result (ref null (shared none)))
;; CHECK-NEXT: (local.get $0)
;; CHECK-NEXT: (then
;; CHECK-NEXT: (ref.null (shared none))
;; CHECK-NEXT: )
;; CHECK-NEXT: (else
;; CHECK-NEXT: (ref.null (shared none))
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $control-types (param i32) (result (ref null $sig))
;; The result of the If should be updated.
(if (result (ref null $sig)) (local.get 0)
(then (ref.null $sig))
(else (ref.null $sig))
)
)
)
(module
;; Name collisions with the "funcs" table and "funcs" elements segment are handled correctly.
;; CHECK: (type $f (func))
(type $f (func))
;; CHECK: (table $funcs 1 1 (ref null (shared i31)))
(table $funcs 1 1 funcref)
;; CHECK: (table $funcs_1 1 1 funcref)
;; CHECK: (elem $funcs (table $funcs) (i32.const 0) (ref null (shared i31)) (item (ref.i31_shared
;; CHECK-NEXT: (i32.const 0)
;; CHECK-NEXT: )))
(elem $funcs (table $funcs) (i32.const 0) func $target)
;; CHECK: (elem $funcs_1 (table $funcs_1) (i32.const 0) func $target)
;; CHECK: (func $target (type $f)
;; CHECK-NEXT: )
(func $target (type $f))
;; CHECK: (func $name-collision (type $f)
;; CHECK-NEXT: (call_indirect $funcs_1 (type $f)
;; CHECK-NEXT: (i31.get_u
;; CHECK-NEXT: (ref.i31_shared
;; CHECK-NEXT: (i32.const 0)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $name-collision
(call_ref $f (ref.func $target))
)
)
(module
;; We want public types to be updated as well.
(type $sig (func))
;; CHECK: (import "" "" (global $g-funcref (ref null (shared i31))))
(import "" "" (global $g-funcref funcref))
;; CHECK: (import "" "" (global $g-sig (ref null (shared i31))))
(import "" "" (global $g-sig (ref null $sig)))
)
(module
;; Struct gets of signature fields must be properly refinalized to shared
;; i31 after rewriteTypes rewrites the struct types to shared.
(type $sig (func))
;; CHECK: (type $struct (shared (struct (field (ref (shared i31))))))
(type $struct (struct (field (ref $sig))))
;; CHECK: (type $1 (func (param (ref $struct)) (result (ref (shared i31)))))
;; CHECK: (func $struct-get (type $1) (param $0 (ref $struct)) (result (ref (shared i31)))
;; CHECK-NEXT: (struct.get $struct 0
;; CHECK-NEXT: (local.get $0)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $struct-get (param (ref $struct)) (result (ref $sig))
(struct.get $struct 0
(local.get 0)
)
)
)
(module
;; Extern references entering and exiting via imports and exports are wrapped.
(import "env" "import_extern" (func $im (param externref i32) (result externref)))
;; CHECK: (type $0 (func (param (ref null (shared i31)) i32) (result (ref null (shared i31)))))
;; CHECK: (type $1 (func (param (ref null (shared i31))) (result (ref null (shared i31)))))
;; CHECK: (type $2 (func (param externref i32) (result externref)))
;; CHECK: (type $3 (func (param externref) (result externref)))
;; CHECK: (type $4 (func (param externref) (result (ref null (shared i31)))))
;; CHECK: (type $5 (func (param (ref null (shared i31))) (result externref)))
;; CHECK: (import "env" "import_extern" (func $im$import (type $2) (param externref i32) (result externref)))
;; CHECK: (table $externs 0 externref)
;; CHECK: (export "export_extern" (func $test$export))
;; CHECK: (func $im (type $0) (param $0 (ref null (shared i31))) (param $1 i32) (result (ref null (shared i31)))
;; CHECK-NEXT: (call $extern_to_index
;; CHECK-NEXT: (call $im$import
;; CHECK-NEXT: (call $index_to_extern
;; CHECK-NEXT: (local.get $0)
;; CHECK-NEXT: )
;; CHECK-NEXT: (local.get $1)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK: (func $test (type $1) (param $e (ref null (shared i31))) (result (ref null (shared i31)))
;; CHECK-NEXT: (call $im
;; CHECK-NEXT: (local.get $e)
;; CHECK-NEXT: (i32.const 42)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $test (export "export_extern") (param $e externref) (result externref)
(call $im (local.get $e) (i32.const 42))
)
)
;; CHECK: (func $test$export (type $3) (param $0 externref) (result externref)
;; CHECK-NEXT: (call $index_to_extern
;; CHECK-NEXT: (call $test
;; CHECK-NEXT: (call $extern_to_index
;; CHECK-NEXT: (local.get $0)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK: (func $extern_to_index (type $4) (param $0 externref) (result (ref null (shared i31)))
;; CHECK-NEXT: (local $1 i32)
;; CHECK-NEXT: (if (result (ref null (shared i31)))
;; CHECK-NEXT: (ref.is_null
;; CHECK-NEXT: (local.get $0)
;; CHECK-NEXT: )
;; CHECK-NEXT: (then
;; CHECK-NEXT: (ref.null (shared none))
;; CHECK-NEXT: )
;; CHECK-NEXT: (else
;; CHECK-NEXT: (if (result (ref (shared i31)))
;; CHECK-NEXT: (i32.ge_s
;; CHECK-NEXT: (local.tee $1
;; CHECK-NEXT: (table.grow $externs
;; CHECK-NEXT: (local.get $0)
;; CHECK-NEXT: (i32.const 1)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.const 0)
;; CHECK-NEXT: )
;; CHECK-NEXT: (then
;; CHECK-NEXT: (ref.i31_shared
;; CHECK-NEXT: (local.get $1)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (else
;; CHECK-NEXT: (unreachable)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK: (func $index_to_extern (type $5) (param $0 (ref null (shared i31))) (result externref)
;; CHECK-NEXT: (if (result externref)
;; CHECK-NEXT: (ref.is_null
;; CHECK-NEXT: (local.get $0)
;; CHECK-NEXT: )
;; CHECK-NEXT: (then
;; CHECK-NEXT: (ref.null noextern)
;; CHECK-NEXT: )
;; CHECK-NEXT: (else
;; CHECK-NEXT: (table.get $externs
;; CHECK-NEXT: (i31.get_u
;; CHECK-NEXT: (local.get $0)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(module
;; Non-nullable extern references entering and exiting via imports and exports.
(import "env" "import_nonnull_extern" (func $im (param (ref extern)) (result (ref extern))))
;; CHECK: (type $0 (func (param (ref (shared i31))) (result (ref (shared i31)))))
;; CHECK: (type $1 (func (param (ref extern)) (result (ref extern))))
;; CHECK: (type $2 (func (param externref) (result (ref null (shared i31)))))
;; CHECK: (type $3 (func (param (ref null (shared i31))) (result externref)))
;; CHECK: (import "env" "import_nonnull_extern" (func $im$import (type $1) (param (ref extern)) (result (ref extern))))
;; CHECK: (table $externs 0 externref)
;; CHECK: (export "export_nonnull_extern" (func $test$export))
;; CHECK: (func $im (type $0) (param $0 (ref (shared i31))) (result (ref (shared i31)))
;; CHECK-NEXT: (ref.as_non_null
;; CHECK-NEXT: (call $extern_to_index
;; CHECK-NEXT: (call $im$import
;; CHECK-NEXT: (ref.cast (ref extern)
;; CHECK-NEXT: (call $index_to_extern
;; CHECK-NEXT: (local.get $0)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK: (func $test (type $0) (param $e (ref (shared i31))) (result (ref (shared i31)))
;; CHECK-NEXT: (call $im
;; CHECK-NEXT: (local.get $e)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $test (export "export_nonnull_extern") (param $e (ref extern)) (result (ref extern))
(call $im (local.get $e))
)
)
;; CHECK: (func $test$export (type $1) (param $0 (ref extern)) (result (ref extern))
;; CHECK-NEXT: (ref.cast (ref extern)
;; CHECK-NEXT: (call $index_to_extern
;; CHECK-NEXT: (call $test
;; CHECK-NEXT: (ref.as_non_null
;; CHECK-NEXT: (call $extern_to_index
;; CHECK-NEXT: (local.get $0)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK: (func $extern_to_index (type $2) (param $0 externref) (result (ref null (shared i31)))
;; CHECK-NEXT: (local $1 i32)
;; CHECK-NEXT: (if (result (ref null (shared i31)))
;; CHECK-NEXT: (ref.is_null
;; CHECK-NEXT: (local.get $0)
;; CHECK-NEXT: )
;; CHECK-NEXT: (then
;; CHECK-NEXT: (ref.null (shared none))
;; CHECK-NEXT: )
;; CHECK-NEXT: (else
;; CHECK-NEXT: (if (result (ref (shared i31)))
;; CHECK-NEXT: (i32.ge_s
;; CHECK-NEXT: (local.tee $1
;; CHECK-NEXT: (table.grow $externs
;; CHECK-NEXT: (local.get $0)
;; CHECK-NEXT: (i32.const 1)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.const 0)
;; CHECK-NEXT: )
;; CHECK-NEXT: (then
;; CHECK-NEXT: (ref.i31_shared
;; CHECK-NEXT: (local.get $1)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (else
;; CHECK-NEXT: (unreachable)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK: (func $index_to_extern (type $3) (param $0 (ref null (shared i31))) (result externref)
;; CHECK-NEXT: (if (result externref)
;; CHECK-NEXT: (ref.is_null
;; CHECK-NEXT: (local.get $0)
;; CHECK-NEXT: )
;; CHECK-NEXT: (then
;; CHECK-NEXT: (ref.null noextern)
;; CHECK-NEXT: )
;; CHECK-NEXT: (else
;; CHECK-NEXT: (table.get $externs
;; CHECK-NEXT: (i31.get_u
;; CHECK-NEXT: (local.get $0)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(module
;; Function references (closed world) and shared extern references are NOT wrapped.
;; CHECK: (type $0 (func (param (ref null (shared i31))) (result (ref null (shared i31)))))
;; CHECK: (type $1 (func (param (ref null (shared extern))) (result (ref null (shared extern)))))
;; CHECK: (import "env" "import_func" (func $im_fn (type $0) (param (ref null (shared i31))) (result (ref null (shared i31)))))
(import "env" "import_func" (func $im_fn (param funcref) (result funcref)))
;; CHECK: (import "env" "import_shared_extern" (func $im_sh_ext (type $1) (param (ref null (shared extern))) (result (ref null (shared extern)))))
(import "env" "import_shared_extern" (func $im_sh_ext (param (ref null (shared extern))) (result (ref null (shared extern)))))
;; CHECK: (export "export_func" (func $test_func))
;; CHECK: (export "export_shared_extern" (func $test_shared_extern))
;; CHECK: (func $test_func (type $0) (param $f (ref null (shared i31))) (result (ref null (shared i31)))
;; CHECK-NEXT: (call $im_fn
;; CHECK-NEXT: (local.get $f)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $test_func (export "export_func") (param $f funcref) (result funcref)
(call $im_fn (local.get $f))
)
;; CHECK: (func $test_shared_extern (type $1) (param $e (ref null (shared extern))) (result (ref null (shared extern)))
;; CHECK-NEXT: (call $im_sh_ext
;; CHECK-NEXT: (local.get $e)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $test_shared_extern (export "export_shared_extern") (param $e (ref null (shared extern))) (result (ref null (shared extern)))
(call $im_sh_ext (local.get $e))
)
)
(module
;; String references entering and exiting via imports and exports are wrapped with the extern table.
(import "env" "import_string" (func $im (param stringref (ref string)) (result stringref)))
;; CHECK: (type $0 (func (param (ref null (shared i31)) (ref (shared i31))) (result (ref null (shared i31)))))
;; CHECK: (type $1 (func (param (ref null (shared i31)) (ref (shared i31))) (result (ref (shared i31)))))
;; CHECK: (type $2 (func (param stringref (ref string)) (result stringref)))
;; CHECK: (type $3 (func (param stringref (ref string)) (result (ref string))))
;; CHECK: (type $4 (func (param externref) (result (ref null (shared i31)))))
;; CHECK: (type $5 (func (param (ref null (shared i31))) (result externref)))
;; CHECK: (import "env" "import_string" (func $im$import (type $2) (param stringref (ref string)) (result stringref)))
;; CHECK: (table $externs 0 externref)
;; CHECK: (export "export_string" (func $test$export))
;; CHECK: (func $im (type $0) (param $0 (ref null (shared i31))) (param $1 (ref (shared i31))) (result (ref null (shared i31)))
;; CHECK-NEXT: (call $extern_to_index
;; CHECK-NEXT: (call $im$import
;; CHECK-NEXT: (ref.cast stringref
;; CHECK-NEXT: (call $index_to_extern
;; CHECK-NEXT: (local.get $0)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (ref.cast (ref string)
;; CHECK-NEXT: (call $index_to_extern
;; CHECK-NEXT: (local.get $1)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK: (func $test (type $1) (param $s (ref null (shared i31))) (param $s_nn (ref (shared i31))) (result (ref (shared i31)))
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (call $im
;; CHECK-NEXT: (local.get $s)
;; CHECK-NEXT: (local.get $s_nn)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (local.get $s_nn)
;; CHECK-NEXT: )
(func $test (export "export_string") (param $s stringref) (param $s_nn (ref string)) (result (ref string))
(drop (call $im (local.get $s) (local.get $s_nn)))
(local.get $s_nn)
)
)
;; CHECK: (func $test$export (type $3) (param $0 stringref) (param $1 (ref string)) (result (ref string))
;; CHECK-NEXT: (ref.cast (ref string)
;; CHECK-NEXT: (call $index_to_extern
;; CHECK-NEXT: (call $test
;; CHECK-NEXT: (call $extern_to_index
;; CHECK-NEXT: (local.get $0)
;; CHECK-NEXT: )
;; CHECK-NEXT: (ref.as_non_null
;; CHECK-NEXT: (call $extern_to_index
;; CHECK-NEXT: (local.get $1)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK: (func $extern_to_index (type $4) (param $0 externref) (result (ref null (shared i31)))
;; CHECK-NEXT: (local $1 i32)
;; CHECK-NEXT: (if (result (ref null (shared i31)))
;; CHECK-NEXT: (ref.is_null
;; CHECK-NEXT: (local.get $0)
;; CHECK-NEXT: )
;; CHECK-NEXT: (then
;; CHECK-NEXT: (ref.null (shared none))
;; CHECK-NEXT: )
;; CHECK-NEXT: (else
;; CHECK-NEXT: (if (result (ref (shared i31)))
;; CHECK-NEXT: (i32.ge_s
;; CHECK-NEXT: (local.tee $1
;; CHECK-NEXT: (table.grow $externs
;; CHECK-NEXT: (local.get $0)
;; CHECK-NEXT: (i32.const 1)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.const 0)
;; CHECK-NEXT: )
;; CHECK-NEXT: (then
;; CHECK-NEXT: (ref.i31_shared
;; CHECK-NEXT: (local.get $1)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (else
;; CHECK-NEXT: (unreachable)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK: (func $index_to_extern (type $5) (param $0 (ref null (shared i31))) (result externref)
;; CHECK-NEXT: (if (result externref)
;; CHECK-NEXT: (ref.is_null
;; CHECK-NEXT: (local.get $0)
;; CHECK-NEXT: )
;; CHECK-NEXT: (then
;; CHECK-NEXT: (ref.null noextern)
;; CHECK-NEXT: )
;; CHECK-NEXT: (else
;; CHECK-NEXT: (table.get $externs
;; CHECK-NEXT: (i31.get_u
;; CHECK-NEXT: (local.get $0)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(module
;; Tuple results in import and export.
(import "env" "import_tuple" (func $im (param externref i32) (result externref (ref extern) i32)))
;; CHECK: (type $0 (func (param (ref null (shared i31)) i32) (result (ref null (shared i31)) (ref (shared i31)) i32)))
;; CHECK: (type $1 (func (param externref i32) (result externref (ref extern) i32)))
;; CHECK: (type $2 (func (param externref) (result (ref null (shared i31)))))
;; CHECK: (type $3 (func (param (ref null (shared i31))) (result externref)))
;; CHECK: (type $4 (func (result (ref null (shared i31)) (ref (shared i31)) i32)))
;; CHECK: (type $5 (func (result externref (ref extern) i32)))
;; CHECK: (import "env" "import_tuple" (func $im$import (type $1) (param externref i32) (result externref (ref extern) i32)))
;; CHECK: (table $externs 0 externref)
;; CHECK: (export "export_tuple" (func $test$export))
;; CHECK: (func $im (type $0) (param $0 (ref null (shared i31))) (param $1 i32) (result (ref null (shared i31)) (ref (shared i31)) i32)
;; CHECK-NEXT: (local $2 (tuple externref (ref extern) i32))
;; CHECK-NEXT: (local.set $2
;; CHECK-NEXT: (call $im$import
;; CHECK-NEXT: (call $index_to_extern
;; CHECK-NEXT: (local.get $0)
;; CHECK-NEXT: )
;; CHECK-NEXT: (local.get $1)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (tuple.make 3
;; CHECK-NEXT: (call $extern_to_index
;; CHECK-NEXT: (tuple.extract 3 0
;; CHECK-NEXT: (local.get $2)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (ref.as_non_null
;; CHECK-NEXT: (call $extern_to_index
;; CHECK-NEXT: (tuple.extract 3 1
;; CHECK-NEXT: (local.get $2)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (tuple.extract 3 2
;; CHECK-NEXT: (local.get $2)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK: (func $test (type $0) (param $e (ref null (shared i31))) (param $i i32) (result (ref null (shared i31)) (ref (shared i31)) i32)
;; CHECK-NEXT: (call $im
;; CHECK-NEXT: (local.get $e)
;; CHECK-NEXT: (local.get $i)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $test (export "export_tuple") (param $e externref) (param $i i32) (result externref (ref extern) i32)
(call $im (local.get $e) (local.get $i))
)
)
;; CHECK: (func $test$export (type $1) (param $0 externref) (param $1 i32) (result externref (ref extern) i32)
;; CHECK-NEXT: (local $2 (tuple (ref null (shared i31)) (ref (shared i31)) i32))
;; CHECK-NEXT: (local.set $2
;; CHECK-NEXT: (call $test
;; CHECK-NEXT: (call $extern_to_index
;; CHECK-NEXT: (local.get $0)
;; CHECK-NEXT: )
;; CHECK-NEXT: (local.get $1)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (tuple.make 3
;; CHECK-NEXT: (call $index_to_extern
;; CHECK-NEXT: (tuple.extract 3 0
;; CHECK-NEXT: (local.get $2)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (ref.cast (ref extern)
;; CHECK-NEXT: (call $index_to_extern
;; CHECK-NEXT: (tuple.extract 3 1
;; CHECK-NEXT: (local.get $2)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (tuple.extract 3 2
;; CHECK-NEXT: (local.get $2)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK: (func $extern_to_index (type $2) (param $0 externref) (result (ref null (shared i31)))
;; CHECK-NEXT: (local $1 i32)
;; CHECK-NEXT: (if (result (ref null (shared i31)))
;; CHECK-NEXT: (ref.is_null
;; CHECK-NEXT: (local.get $0)
;; CHECK-NEXT: )
;; CHECK-NEXT: (then
;; CHECK-NEXT: (ref.null (shared none))
;; CHECK-NEXT: )
;; CHECK-NEXT: (else
;; CHECK-NEXT: (if (result (ref (shared i31)))
;; CHECK-NEXT: (i32.ge_s
;; CHECK-NEXT: (local.tee $1
;; CHECK-NEXT: (table.grow $externs
;; CHECK-NEXT: (local.get $0)
;; CHECK-NEXT: (i32.const 1)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.const 0)
;; CHECK-NEXT: )
;; CHECK-NEXT: (then
;; CHECK-NEXT: (ref.i31_shared
;; CHECK-NEXT: (local.get $1)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (else
;; CHECK-NEXT: (unreachable)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK: (func $index_to_extern (type $3) (param $0 (ref null (shared i31))) (result externref)
;; CHECK-NEXT: (if (result externref)
;; CHECK-NEXT: (ref.is_null
;; CHECK-NEXT: (local.get $0)
;; CHECK-NEXT: )
;; CHECK-NEXT: (then
;; CHECK-NEXT: (ref.null noextern)
;; CHECK-NEXT: )
;; CHECK-NEXT: (else
;; CHECK-NEXT: (table.get $externs
;; CHECK-NEXT: (i31.get_u
;; CHECK-NEXT: (local.get $0)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(module
;; Convert between extern and any (nullable and non-nullable)
;; CHECK: (type $0 (func (param (ref null (shared i31))) (result (ref null (shared any)))))
;; CHECK: (type $1 (func (param (ref (shared i31))) (result (ref (shared any)))))
;; CHECK: (type $2 (func (param (ref null (shared any))) (result (ref null (shared i31)))))
;; CHECK: (type $3 (func (param (ref (shared any))) (result (ref (shared i31)))))
;; CHECK: (type $4 (func (param externref) (result (ref null (shared i31)))))
;; CHECK: (type $5 (func (param (ref null (shared i31))) (result externref)))
;; CHECK: (type $6 (func (param (ref null (shared any))) (result externref)))
;; CHECK: (type $7 (func (param externref) (result (ref null (shared any)))))
;; CHECK: (import "env" "any_to_extern" (func $any_to_extern (exact (type $6) (param (ref null (shared any))) (result externref))))
;; CHECK: (import "env" "extern_to_any" (func $extern_to_any (exact (type $7) (param externref) (result (ref null (shared any))))))
;; CHECK: (table $externs 0 externref)
;; CHECK: (func $any_convert_extern_nullable (type $0) (param $e (ref null (shared i31))) (result (ref null (shared any)))
;; CHECK-NEXT: (call $extern_to_any
;; CHECK-NEXT: (call $index_to_extern
;; CHECK-NEXT: (local.get $e)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $any_convert_extern_nullable (param $e externref) (result anyref)
(any.convert_extern (local.get $e))
)
;; CHECK: (func $any_convert_extern_non_nullable (type $1) (param $e (ref (shared i31))) (result (ref (shared any)))
;; CHECK-NEXT: (ref.as_non_null
;; CHECK-NEXT: (call $extern_to_any
;; CHECK-NEXT: (ref.cast (ref extern)
;; CHECK-NEXT: (call $index_to_extern
;; CHECK-NEXT: (local.get $e)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $any_convert_extern_non_nullable (param $e (ref extern)) (result (ref any))
(any.convert_extern (local.get $e))
)
;; CHECK: (func $extern_convert_any_nullable (type $2) (param $a (ref null (shared any))) (result (ref null (shared i31)))
;; CHECK-NEXT: (call $extern_to_index
;; CHECK-NEXT: (call $any_to_extern
;; CHECK-NEXT: (local.get $a)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $extern_convert_any_nullable (param $a anyref) (result externref)
(extern.convert_any (local.get $a))
)
;; CHECK: (func $extern_convert_any_non_nullable (type $3) (param $a (ref (shared any))) (result (ref (shared i31)))
;; CHECK-NEXT: (ref.as_non_null
;; CHECK-NEXT: (call $extern_to_index
;; CHECK-NEXT: (call $any_to_extern
;; CHECK-NEXT: (local.get $a)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $extern_convert_any_non_nullable (param $a (ref any)) (result (ref extern))
(extern.convert_any (local.get $a))
)
)
;; CHECK: (func $extern_to_index (type $4) (param $0 externref) (result (ref null (shared i31)))
;; CHECK-NEXT: (local $1 i32)
;; CHECK-NEXT: (if (result (ref null (shared i31)))
;; CHECK-NEXT: (ref.is_null
;; CHECK-NEXT: (local.get $0)
;; CHECK-NEXT: )
;; CHECK-NEXT: (then
;; CHECK-NEXT: (ref.null (shared none))
;; CHECK-NEXT: )
;; CHECK-NEXT: (else
;; CHECK-NEXT: (if (result (ref (shared i31)))
;; CHECK-NEXT: (i32.ge_s
;; CHECK-NEXT: (local.tee $1
;; CHECK-NEXT: (table.grow $externs
;; CHECK-NEXT: (local.get $0)
;; CHECK-NEXT: (i32.const 1)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.const 0)
;; CHECK-NEXT: )
;; CHECK-NEXT: (then
;; CHECK-NEXT: (ref.i31_shared
;; CHECK-NEXT: (local.get $1)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (else
;; CHECK-NEXT: (unreachable)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK: (func $index_to_extern (type $5) (param $0 (ref null (shared i31))) (result externref)
;; CHECK-NEXT: (if (result externref)
;; CHECK-NEXT: (ref.is_null
;; CHECK-NEXT: (local.get $0)
;; CHECK-NEXT: )
;; CHECK-NEXT: (then
;; CHECK-NEXT: (ref.null noextern)
;; CHECK-NEXT: )
;; CHECK-NEXT: (else
;; CHECK-NEXT: (table.get $externs
;; CHECK-NEXT: (i31.get_u
;; CHECK-NEXT: (local.get $0)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(module
;; Re-export an imported function with externrefs.
(import "env" "import_and_export" (func $im (param externref) (result externref)))
(export "export_import" (func $im))
)
;; CHECK: (type $0 (func (param externref) (result externref)))
;; CHECK: (type $1 (func (param (ref null (shared i31))) (result (ref null (shared i31)))))
;; CHECK: (type $2 (func (param externref) (result (ref null (shared i31)))))
;; CHECK: (type $3 (func (param (ref null (shared i31))) (result externref)))
;; CHECK: (import "env" "import_and_export" (func $im$import (type $0) (param externref) (result externref)))
;; CHECK: (table $externs 0 externref)
;; CHECK: (export "export_import" (func $im$export))
;; CHECK: (func $im (type $1) (param $0 (ref null (shared i31))) (result (ref null (shared i31)))
;; CHECK-NEXT: (call $extern_to_index
;; CHECK-NEXT: (call $im$import
;; CHECK-NEXT: (call $index_to_extern
;; CHECK-NEXT: (local.get $0)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK: (func $im$export (type $0) (param $0 externref) (result externref)
;; CHECK-NEXT: (call $index_to_extern
;; CHECK-NEXT: (call $im
;; CHECK-NEXT: (call $extern_to_index
;; CHECK-NEXT: (local.get $0)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK: (func $extern_to_index (type $2) (param $0 externref) (result (ref null (shared i31)))
;; CHECK-NEXT: (local $1 i32)
;; CHECK-NEXT: (if (result (ref null (shared i31)))
;; CHECK-NEXT: (ref.is_null
;; CHECK-NEXT: (local.get $0)
;; CHECK-NEXT: )
;; CHECK-NEXT: (then
;; CHECK-NEXT: (ref.null (shared none))
;; CHECK-NEXT: )
;; CHECK-NEXT: (else
;; CHECK-NEXT: (if (result (ref (shared i31)))
;; CHECK-NEXT: (i32.ge_s
;; CHECK-NEXT: (local.tee $1
;; CHECK-NEXT: (table.grow $externs
;; CHECK-NEXT: (local.get $0)
;; CHECK-NEXT: (i32.const 1)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.const 0)
;; CHECK-NEXT: )
;; CHECK-NEXT: (then
;; CHECK-NEXT: (ref.i31_shared
;; CHECK-NEXT: (local.get $1)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (else
;; CHECK-NEXT: (unreachable)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK: (func $index_to_extern (type $3) (param $0 (ref null (shared i31))) (result externref)
;; CHECK-NEXT: (if (result externref)
;; CHECK-NEXT: (ref.is_null
;; CHECK-NEXT: (local.get $0)
;; CHECK-NEXT: )
;; CHECK-NEXT: (then
;; CHECK-NEXT: (ref.null noextern)
;; CHECK-NEXT: )
;; CHECK-NEXT: (else
;; CHECK-NEXT: (table.get $externs
;; CHECK-NEXT: (i31.get_u
;; CHECK-NEXT: (local.get $0)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(module
;; Multiple exports of the same function are deduplicated.
;; CHECK: (type $0 (func (param (ref null (shared i31))) (result (ref null (shared i31)))))
;; CHECK: (type $1 (func (param externref) (result externref)))
;; CHECK: (type $2 (func (param externref) (result (ref null (shared i31)))))
;; CHECK: (type $3 (func (param (ref null (shared i31))) (result externref)))
;; CHECK: (table $externs 0 externref)
;; CHECK: (export "exp1" (func $multi$export))
;; CHECK: (export "exp2" (func $multi$export))
;; CHECK: (func $multi (type $0) (param $0 (ref null (shared i31))) (result (ref null (shared i31)))
;; CHECK-NEXT: (local.get $0)
;; CHECK-NEXT: )
(func $multi (export "exp1") (export "exp2") (param externref) (result externref)
(local.get 0)
)
)
;; CHECK: (func $multi$export (type $1) (param $0 externref) (result externref)
;; CHECK-NEXT: (call $index_to_extern
;; CHECK-NEXT: (call $multi
;; CHECK-NEXT: (call $extern_to_index
;; CHECK-NEXT: (local.get $0)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK: (func $extern_to_index (type $2) (param $0 externref) (result (ref null (shared i31)))
;; CHECK-NEXT: (local $1 i32)
;; CHECK-NEXT: (if (result (ref null (shared i31)))
;; CHECK-NEXT: (ref.is_null
;; CHECK-NEXT: (local.get $0)
;; CHECK-NEXT: )
;; CHECK-NEXT: (then
;; CHECK-NEXT: (ref.null (shared none))
;; CHECK-NEXT: )
;; CHECK-NEXT: (else
;; CHECK-NEXT: (if (result (ref (shared i31)))
;; CHECK-NEXT: (i32.ge_s
;; CHECK-NEXT: (local.tee $1
;; CHECK-NEXT: (table.grow $externs
;; CHECK-NEXT: (local.get $0)
;; CHECK-NEXT: (i32.const 1)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.const 0)
;; CHECK-NEXT: )
;; CHECK-NEXT: (then
;; CHECK-NEXT: (ref.i31_shared
;; CHECK-NEXT: (local.get $1)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (else
;; CHECK-NEXT: (unreachable)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK: (func $index_to_extern (type $3) (param $0 (ref null (shared i31))) (result externref)
;; CHECK-NEXT: (if (result externref)
;; CHECK-NEXT: (ref.is_null
;; CHECK-NEXT: (local.get $0)
;; CHECK-NEXT: )
;; CHECK-NEXT: (then
;; CHECK-NEXT: (ref.null noextern)
;; CHECK-NEXT: )
;; CHECK-NEXT: (else
;; CHECK-NEXT: (table.get $externs
;; CHECK-NEXT: (i31.get_u
;; CHECK-NEXT: (local.get $0)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(module
;; Tuple result without externrefs should not unpack and repack.
(import "env" "import_no_ext_tuple" (func $im_tuple (param externref) (result i32 i64)))
;; CHECK: (type $0 (func (param (ref null (shared i31))) (result i32 i64)))
;; CHECK: (type $1 (func (param externref) (result i32 i64)))
;; CHECK: (type $2 (func (param externref) (result (ref null (shared i31)))))
;; CHECK: (type $3 (func (param (ref null (shared i31))) (result externref)))
;; CHECK: (import "env" "import_no_ext_tuple" (func $im_tuple$import (type $1) (param externref) (result i32 i64)))
;; CHECK: (table $externs 0 externref)
;; CHECK: (export "export_no_ext_tuple" (func $test_no_ext_tuple$export))
;; CHECK: (func $im_tuple (type $0) (param $0 (ref null (shared i31))) (result i32 i64)
;; CHECK-NEXT: (call $im_tuple$import
;; CHECK-NEXT: (call $index_to_extern
;; CHECK-NEXT: (local.get $0)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK: (func $test_no_ext_tuple (type $0) (param $0 (ref null (shared i31))) (result i32 i64)
;; CHECK-NEXT: (call $im_tuple
;; CHECK-NEXT: (local.get $0)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $test_no_ext_tuple (export "export_no_ext_tuple") (param externref) (result i32 i64)
(call $im_tuple (local.get 0))
)
)
;; CHECK: (func $test_no_ext_tuple$export (type $1) (param $0 externref) (result i32 i64)
;; CHECK-NEXT: (call $test_no_ext_tuple
;; CHECK-NEXT: (call $extern_to_index
;; CHECK-NEXT: (local.get $0)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK: (func $extern_to_index (type $2) (param $0 externref) (result (ref null (shared i31)))
;; CHECK-NEXT: (local $1 i32)
;; CHECK-NEXT: (if (result (ref null (shared i31)))
;; CHECK-NEXT: (ref.is_null
;; CHECK-NEXT: (local.get $0)
;; CHECK-NEXT: )
;; CHECK-NEXT: (then
;; CHECK-NEXT: (ref.null (shared none))
;; CHECK-NEXT: )
;; CHECK-NEXT: (else
;; CHECK-NEXT: (if (result (ref (shared i31)))
;; CHECK-NEXT: (i32.ge_s
;; CHECK-NEXT: (local.tee $1
;; CHECK-NEXT: (table.grow $externs
;; CHECK-NEXT: (local.get $0)
;; CHECK-NEXT: (i32.const 1)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.const 0)
;; CHECK-NEXT: )
;; CHECK-NEXT: (then
;; CHECK-NEXT: (ref.i31_shared
;; CHECK-NEXT: (local.get $1)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (else
;; CHECK-NEXT: (unreachable)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK: (func $index_to_extern (type $3) (param $0 (ref null (shared i31))) (result externref)
;; CHECK-NEXT: (if (result externref)
;; CHECK-NEXT: (ref.is_null
;; CHECK-NEXT: (local.get $0)
;; CHECK-NEXT: )
;; CHECK-NEXT: (then
;; CHECK-NEXT: (ref.null noextern)
;; CHECK-NEXT: )
;; CHECK-NEXT: (else
;; CHECK-NEXT: (table.get $externs
;; CHECK-NEXT: (i31.get_u
;; CHECK-NEXT: (local.get $0)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(module
;; Mixed struct and externref at boundary.
;; CHECK: (type $struct (shared (struct (field (mut i32)))))
(type $struct (struct (field (mut i32))))
(import "env" "import_mixed" (func $im_mixed (param (ref $struct) externref) (result (ref $struct) externref)))
;; CHECK: (type $1 (func (param (ref $struct) (ref null (shared i31))) (result (ref $struct) (ref null (shared i31)))))
;; CHECK: (type $2 (func (param (ref $struct) externref) (result (ref $struct) externref)))
;; CHECK: (type $3 (func (param externref) (result (ref null (shared i31)))))
;; CHECK: (type $4 (func (param (ref null (shared i31))) (result externref)))
;; CHECK: (type $5 (func (result (ref $struct) (ref null (shared i31)))))
;; CHECK: (type $6 (func (result (ref $struct) externref)))
;; CHECK: (import "env" "import_mixed" (func $im_mixed$import (type $2) (param (ref $struct) externref) (result (ref $struct) externref)))
;; CHECK: (table $externs 0 externref)
;; CHECK: (export "export_mixed" (func $test_mixed$export))
;; CHECK: (func $im_mixed (type $1) (param $0 (ref $struct)) (param $1 (ref null (shared i31))) (result (ref $struct) (ref null (shared i31)))
;; CHECK-NEXT: (local $2 (tuple (ref $struct) externref))
;; CHECK-NEXT: (local.set $2
;; CHECK-NEXT: (call $im_mixed$import
;; CHECK-NEXT: (local.get $0)
;; CHECK-NEXT: (call $index_to_extern
;; CHECK-NEXT: (local.get $1)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (tuple.make 2
;; CHECK-NEXT: (tuple.extract 2 0
;; CHECK-NEXT: (local.get $2)
;; CHECK-NEXT: )
;; CHECK-NEXT: (call $extern_to_index
;; CHECK-NEXT: (tuple.extract 2 1
;; CHECK-NEXT: (local.get $2)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK: (func $test_mixed (type $1) (param $0 (ref $struct)) (param $1 (ref null (shared i31))) (result (ref $struct) (ref null (shared i31)))
;; CHECK-NEXT: (call $im_mixed
;; CHECK-NEXT: (local.get $0)
;; CHECK-NEXT: (local.get $1)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $test_mixed (export "export_mixed") (param (ref $struct) externref) (result (ref $struct) externref)
(call $im_mixed (local.get 0) (local.get 1))
)
)
;; CHECK: (func $test_mixed$export (type $2) (param $0 (ref $struct)) (param $1 externref) (result (ref $struct) externref)
;; CHECK-NEXT: (local $2 (tuple (ref $struct) (ref null (shared i31))))
;; CHECK-NEXT: (local.set $2
;; CHECK-NEXT: (call $test_mixed
;; CHECK-NEXT: (local.get $0)
;; CHECK-NEXT: (call $extern_to_index
;; CHECK-NEXT: (local.get $1)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (tuple.make 2
;; CHECK-NEXT: (tuple.extract 2 0
;; CHECK-NEXT: (local.get $2)
;; CHECK-NEXT: )
;; CHECK-NEXT: (call $index_to_extern
;; CHECK-NEXT: (tuple.extract 2 1
;; CHECK-NEXT: (local.get $2)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK: (func $extern_to_index (type $3) (param $0 externref) (result (ref null (shared i31)))
;; CHECK-NEXT: (local $1 i32)
;; CHECK-NEXT: (if (result (ref null (shared i31)))
;; CHECK-NEXT: (ref.is_null
;; CHECK-NEXT: (local.get $0)
;; CHECK-NEXT: )
;; CHECK-NEXT: (then
;; CHECK-NEXT: (ref.null (shared none))
;; CHECK-NEXT: )
;; CHECK-NEXT: (else
;; CHECK-NEXT: (if (result (ref (shared i31)))
;; CHECK-NEXT: (i32.ge_s
;; CHECK-NEXT: (local.tee $1
;; CHECK-NEXT: (table.grow $externs
;; CHECK-NEXT: (local.get $0)
;; CHECK-NEXT: (i32.const 1)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.const 0)
;; CHECK-NEXT: )
;; CHECK-NEXT: (then
;; CHECK-NEXT: (ref.i31_shared
;; CHECK-NEXT: (local.get $1)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (else
;; CHECK-NEXT: (unreachable)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK: (func $index_to_extern (type $4) (param $0 (ref null (shared i31))) (result externref)
;; CHECK-NEXT: (if (result externref)
;; CHECK-NEXT: (ref.is_null
;; CHECK-NEXT: (local.get $0)
;; CHECK-NEXT: )
;; CHECK-NEXT: (then
;; CHECK-NEXT: (ref.null noextern)
;; CHECK-NEXT: )
;; CHECK-NEXT: (else
;; CHECK-NEXT: (table.get $externs
;; CHECK-NEXT: (i31.get_u
;; CHECK-NEXT: (local.get $0)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )