| ;; 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 $struct (shared (struct (field (ref null (shared i31)))))) | |
| (type $struct (struct (field (ref null func)))) | |
| (func $effect (import "" "") (result i32)) | |
| ;; CHECK: (type $3 (func)) | |
| ;; CHECK: (type $4 (func (param (ref (shared i31)) i32) (result i32))) | |
| ;; CHECK: (type $5 (func (param (ref $struct)))) | |
| ;; CHECK: (type $6 (func (param (ref (shared i31))) (result i32))) | |
| ;; CHECK: (type $7 (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 $5) (param $0 (ref $struct)) | |
| ;; CHECK-NEXT: ) | |
| (func $a (param (ref $struct))) | |
| ;; CHECK: (func $b (type $3) | |
| ;; CHECK-NEXT: ) | |
| (func $b) | |
| ;; CHECK: (func $c (type $3) | |
| ;; CHECK-NEXT: ) | |
| (func $c) | |
| ;; CHECK: (func $d (type $3) | |
| ;; 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 $6) (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 $7) (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: ) | |
| (module | |
| ;; Imported externref globals should remain externref imports, be inserted | |
| ;; into the externs table at instantiation, and have internal uses replaced | |
| ;; with i31 globals referring to their table indices. | |
| ;; CHECK: (type $struct (shared (struct (field (ref null (shared i31))) (field (ref (shared i31)))))) | |
| (type $struct (struct (field externref) (field (ref extern)))) | |
| (import "env" "g_nullable" (global $g_nullable externref)) | |
| (import "env" "g_non_null" (global $g_non_null (ref extern))) | |
| ;; CHECK: (type $1 (func (result externref (ref extern)))) | |
| ;; CHECK: (type $2 (func (result (ref null (shared i31)) (ref (shared i31))))) | |
| ;; CHECK: (type $3 (func (param (ref null (shared i31))) (result externref))) | |
| ;; CHECK: (import "env" "g_nullable" (global $g_nullable$import externref)) | |
| ;; CHECK: (import "env" "g_non_null" (global $g_non_null$import (ref extern))) | |
| ;; CHECK: (global $g_nullable (ref null (shared i31)) (ref.i31_shared | |
| ;; CHECK-NEXT: (i32.const 0) | |
| ;; CHECK-NEXT: )) | |
| ;; CHECK: (global $g_non_null (ref (shared i31)) (ref.i31_shared | |
| ;; CHECK-NEXT: (i32.const 1) | |
| ;; CHECK-NEXT: )) | |
| ;; CHECK: (global $user (ref $struct) (struct.new $struct | |
| ;; CHECK-NEXT: (global.get $g_nullable) | |
| ;; CHECK-NEXT: (global.get $g_non_null) | |
| ;; CHECK-NEXT: )) | |
| (global $user (ref $struct) (struct.new $struct | |
| (global.get $g_nullable) | |
| (global.get $g_non_null) | |
| )) | |
| ;; CHECK: (table $externs 2 externref) | |
| ;; CHECK: (elem $externs (table $externs) (i32.const 0) externref (item (global.get $g_nullable$import)) (item (global.get $g_non_null$import))) | |
| ;; CHECK: (export "get-globals" (func $get-globals$export)) | |
| ;; CHECK: (func $get-globals (type $2) (result (ref null (shared i31)) (ref (shared i31))) | |
| ;; CHECK-NEXT: (tuple.make 2 | |
| ;; CHECK-NEXT: (global.get $g_nullable) | |
| ;; CHECK-NEXT: (global.get $g_non_null) | |
| ;; CHECK-NEXT: ) | |
| ;; CHECK-NEXT: ) | |
| (func $get-globals (export "get-globals") (result externref (ref extern)) | |
| ;; Read both imported externref globals inside an exported function. | |
| (tuple.make 2 | |
| (global.get $g_nullable) | |
| (global.get $g_non_null) | |
| ) | |
| ) | |
| ) | |
| ;; CHECK: (func $get-globals$export (type $1) (result externref (ref extern)) | |
| ;; CHECK-NEXT: (local $0 (tuple (ref null (shared i31)) (ref (shared i31)))) | |
| ;; CHECK-NEXT: (local.set $0 | |
| ;; CHECK-NEXT: (call $get-globals) | |
| ;; CHECK-NEXT: ) | |
| ;; CHECK-NEXT: (tuple.make 2 | |
| ;; CHECK-NEXT: (call $index_to_extern | |
| ;; CHECK-NEXT: (tuple.extract 2 0 | |
| ;; CHECK-NEXT: (local.get $0) | |
| ;; CHECK-NEXT: ) | |
| ;; CHECK-NEXT: ) | |
| ;; CHECK-NEXT: (ref.cast (ref extern) | |
| ;; CHECK-NEXT: (call $index_to_extern | |
| ;; CHECK-NEXT: (tuple.extract 2 1 | |
| ;; CHECK-NEXT: (local.get $0) | |
| ;; 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 | |
| ;; If imported externref globals are never used in a way that requires the | |
| ;; externs table, they still get table indices, but no table is emitted. | |
| (import "env" "g_nullable" (global $g_nullable externref)) | |
| (import "env" "g_non_null" (global $g_non_null (ref extern))) | |
| ) | |
| ;; CHECK: (import "env" "g_nullable" (global $g_nullable$import externref)) | |
| ;; CHECK: (import "env" "g_non_null" (global $g_non_null$import (ref extern))) | |
| ;; CHECK: (global $g_nullable (ref null (shared i31)) (ref.i31_shared | |
| ;; CHECK-NEXT: (i32.const 0) | |
| ;; CHECK-NEXT: )) | |
| ;; CHECK: (global $g_non_null (ref (shared i31)) (ref.i31_shared | |
| ;; CHECK-NEXT: (i32.const 1) | |
| ;; CHECK-NEXT: )) | |
| (module | |
| ;; Imported string constants should remain externref/stringref imports, be | |
| ;; inserted into the externs table, and be converted back when passed to | |
| ;; string builtins. | |
| (import "'" "hello" (global $hello (ref extern))) | |
| (import "'" "world" (global $world (ref string))) | |
| (import "wasm:js-string" "equals" (func $equals (param externref externref) (result i32))) | |
| ;; CHECK: (type $0 (func (param (ref null (shared i31)) (ref null (shared i31))) (result i32))) | |
| ;; CHECK: (type $1 (func (result i32))) | |
| ;; CHECK: (type $2 (func (param externref externref) (result i32))) | |
| ;; CHECK: (type $3 (func (param (ref null (shared i31))) (result externref))) | |
| ;; CHECK: (import "\'" "hello" (global $hello$import (ref extern))) | |
| ;; CHECK: (import "\'" "world" (global $world$import (ref string))) | |
| ;; CHECK: (import "wasm:js-string" "equals" (func $equals$import (type $2) (param externref externref) (result i32))) | |
| ;; CHECK: (global $hello (ref (shared i31)) (ref.i31_shared | |
| ;; CHECK-NEXT: (i32.const 0) | |
| ;; CHECK-NEXT: )) | |
| ;; CHECK: (global $world (ref (shared i31)) (ref.i31_shared | |
| ;; CHECK-NEXT: (i32.const 1) | |
| ;; CHECK-NEXT: )) | |
| ;; CHECK: (table $externs 2 externref) | |
| ;; CHECK: (elem $externs (table $externs) (i32.const 0) externref (item (global.get $hello$import)) (item (global.get $world$import))) | |
| ;; CHECK: (func $equals (type $0) (param $0 (ref null (shared i31))) (param $1 (ref null (shared i31))) (result i32) | |
| ;; CHECK-NEXT: (call $equals$import | |
| ;; CHECK-NEXT: (call $index_to_extern | |
| ;; CHECK-NEXT: (local.get $0) | |
| ;; CHECK-NEXT: ) | |
| ;; CHECK-NEXT: (call $index_to_extern | |
| ;; CHECK-NEXT: (local.get $1) | |
| ;; CHECK-NEXT: ) | |
| ;; CHECK-NEXT: ) | |
| ;; CHECK-NEXT: ) | |
| ;; CHECK: (func $compare-strings (type $1) (result i32) | |
| ;; CHECK-NEXT: (call $equals | |
| ;; CHECK-NEXT: (global.get $hello) | |
| ;; CHECK-NEXT: (global.get $world) | |
| ;; CHECK-NEXT: ) | |
| ;; CHECK-NEXT: ) | |
| (func $compare-strings (result i32) | |
| ;; Compare two imported string constants using wasm:js-string equals. | |
| (call $equals | |
| (global.get $hello) | |
| (global.get $world) | |
| ) | |
| ) | |
| ) | |
| ;; 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: ) |