| ;; NOTE: Assertions have been generated by update_lit_checks.py --all-items and should not be edited. |
| ;; RUN: foreach %s %t wasm-opt -all --gufa -S -o - | filecheck %s --check-prefix OPEND |
| ;; RUN: foreach %s %t wasm-opt -all --gufa --closed-world -S -o - | filecheck %s --check-prefix CLOSE |
| |
| ;; Compare behavior on closed and open world. In open world we must assume that |
| ;; funcrefs, for example, can be called from outside. |
| |
| (module |
| ;; OPEND: (type $0 (func (param funcref))) |
| |
| ;; OPEND: (type $1 (func)) |
| |
| ;; OPEND: (type $2 (func (param i32))) |
| |
| ;; OPEND: (import "outside" "call-ref-catch" (func $external-caller (type $0) (param funcref))) |
| ;; CLOSE: (type $0 (func (param funcref))) |
| |
| ;; CLOSE: (type $1 (func)) |
| |
| ;; CLOSE: (type $2 (func (param i32))) |
| |
| ;; CLOSE: (import "outside" "call-ref-catch" (func $external-caller (type $0) (param funcref))) |
| (import "outside" "call-ref-catch" (func $external-caller (param funcref))) |
| |
| ;; OPEND: (elem declare func $func) |
| |
| ;; OPEND: (export "call-import" (func $call-import)) |
| |
| ;; OPEND: (func $call-import (type $1) |
| ;; OPEND-NEXT: (call $external-caller |
| ;; OPEND-NEXT: (ref.func $func) |
| ;; OPEND-NEXT: ) |
| ;; OPEND-NEXT: ) |
| ;; CLOSE: (elem declare func $func) |
| |
| ;; CLOSE: (export "call-import" (func $call-import)) |
| |
| ;; CLOSE: (func $call-import (type $1) |
| ;; CLOSE-NEXT: (call $external-caller |
| ;; CLOSE-NEXT: (ref.func $func) |
| ;; CLOSE-NEXT: ) |
| ;; CLOSE-NEXT: ) |
| (func $call-import (export "call-import") |
| ;; Send a reference to $func to the outside, which may call it. |
| (call $external-caller |
| (ref.func $func) |
| ) |
| ) |
| |
| ;; OPEND: (func $func (type $2) (param $0 i32) |
| ;; OPEND-NEXT: (drop |
| ;; OPEND-NEXT: (local.get $0) |
| ;; OPEND-NEXT: ) |
| ;; OPEND-NEXT: ) |
| ;; CLOSE: (func $func (type $2) (param $0 i32) |
| ;; CLOSE-NEXT: (drop |
| ;; CLOSE-NEXT: (unreachable) |
| ;; CLOSE-NEXT: ) |
| ;; CLOSE-NEXT: ) |
| (func $func (param $0 i32) |
| ;; This is called from the outside, so this is not dead code, and nothing |
| ;; should change here in open world. In closed world, this can become an |
| ;; unreachable, since nothing can call it. |
| (drop |
| (local.get $0) |
| ) |
| ) |
| ) |
| |
| ;; Import a struct in a global. |
| (module |
| ;; OPEND: (type $A (struct (field i32))) |
| ;; CLOSE: (type $A (struct (field i32))) |
| (type $A (struct (field i32))) |
| |
| ;; OPEND: (type $1 (func (result i32))) |
| |
| ;; OPEND: (import "primary" "global" (global $import (ref null $A))) |
| ;; CLOSE: (type $1 (func (result i32))) |
| |
| ;; CLOSE: (import "primary" "global" (global $import (ref null $A))) |
| (import "primary" "global" (global $import (ref null $A))) |
| |
| ;; OPEND: (func $read (type $1) (result i32) |
| ;; OPEND-NEXT: (struct.get $A 0 |
| ;; OPEND-NEXT: (global.get $import) |
| ;; OPEND-NEXT: ) |
| ;; OPEND-NEXT: ) |
| ;; CLOSE: (func $read (type $1) (result i32) |
| ;; CLOSE-NEXT: (unreachable) |
| ;; CLOSE-NEXT: ) |
| (func $read (result i32) |
| ;; In closed world, we can assume no work happens on this struct outside, so |
| ;; it can only be null. In open world, we can do nothing here. |
| (struct.get $A 0 |
| (global.get $import) |
| ) |
| ) |
| ) |
| |
| ;; Import an array. |
| (module |
| ;; OPEND: (type $A (array (mut i32))) |
| ;; CLOSE: (type $A (array (mut i32))) |
| (type $A (array (mut i32))) |
| |
| ;; OPEND: (type $1 (func (result i32))) |
| |
| ;; OPEND: (import "primary" "global" (global $import (ref null $A))) |
| ;; CLOSE: (type $1 (func (result i32))) |
| |
| ;; CLOSE: (import "primary" "global" (global $import (ref null $A))) |
| (import "primary" "global" (global $import (ref null $A))) |
| |
| ;; OPEND: (func $read (type $1) (result i32) |
| ;; OPEND-NEXT: (array.get $A |
| ;; OPEND-NEXT: (global.get $import) |
| ;; OPEND-NEXT: (i32.const 0) |
| ;; OPEND-NEXT: ) |
| ;; OPEND-NEXT: ) |
| ;; CLOSE: (func $read (type $1) (result i32) |
| ;; CLOSE-NEXT: (unreachable) |
| ;; CLOSE-NEXT: ) |
| (func $read (result i32) |
| ;; We do not optimize in open world. |
| (array.get $A |
| (global.get $import) |
| (i32.const 0) |
| ) |
| ) |
| ) |
| |
| ;; Import a struct with a descriptor. |
| (module |
| (rec |
| ;; OPEND: (rec |
| ;; OPEND-NEXT: (type $A (sub (descriptor $A.desc) (struct))) |
| ;; CLOSE: (rec |
| ;; CLOSE-NEXT: (type $A (sub (descriptor $A.desc) (struct))) |
| (type $A (sub (descriptor $A.desc) (struct))) |
| ;; OPEND: (type $A.desc (sub (describes $A) (struct))) |
| ;; CLOSE: (type $A.desc (sub (describes $A) (struct))) |
| (type $A.desc (sub (describes $A) (struct))) |
| ) |
| |
| ;; OPEND: (type $2 (func (result anyref))) |
| |
| ;; OPEND: (import "primary" "global" (global $import (ref null $A))) |
| ;; CLOSE: (type $2 (func (result anyref))) |
| |
| ;; CLOSE: (import "primary" "global" (global $import (ref null $A))) |
| (import "primary" "global" (global $import (ref null $A))) |
| |
| ;; OPEND: (func $read (type $2) (result anyref) |
| ;; OPEND-NEXT: (ref.get_desc $A |
| ;; OPEND-NEXT: (global.get $import) |
| ;; OPEND-NEXT: ) |
| ;; OPEND-NEXT: ) |
| ;; CLOSE: (func $read (type $2) (result anyref) |
| ;; CLOSE-NEXT: (unreachable) |
| ;; CLOSE-NEXT: ) |
| (func $read (result anyref) |
| ;; We do not optimize in open world. |
| (ref.get_desc $A |
| (global.get $import) |
| ) |
| ) |
| ) |
| |
| ;; Write to an array using string.encode. |
| (module |
| ;; OPEND: (type $array (array (mut i16))) |
| ;; CLOSE: (type $array (array (mut i16))) |
| (type $array (array (mut i16))) |
| |
| ;; OPEND: (type $1 (func)) |
| |
| ;; OPEND: (type $2 (func (result i32))) |
| |
| ;; OPEND: (global $global (ref $array) (array.new_default $array |
| ;; OPEND-NEXT: (i32.const 42) |
| ;; OPEND-NEXT: )) |
| ;; CLOSE: (type $1 (func)) |
| |
| ;; CLOSE: (type $2 (func (result i32))) |
| |
| ;; CLOSE: (global $global (ref $array) (array.new_default $array |
| ;; CLOSE-NEXT: (i32.const 42) |
| ;; CLOSE-NEXT: )) |
| (global $global (ref $array) (array.new_default $array |
| (i32.const 42) |
| )) |
| |
| ;; OPEND: (export "encode" (func $encode)) |
| |
| ;; OPEND: (export "read" (func $read)) |
| |
| ;; OPEND: (func $encode (type $1) |
| ;; OPEND-NEXT: (drop |
| ;; OPEND-NEXT: (string.encode_wtf16_array |
| ;; OPEND-NEXT: (string.const "hello") |
| ;; OPEND-NEXT: (global.get $global) |
| ;; OPEND-NEXT: (i32.const 0) |
| ;; OPEND-NEXT: ) |
| ;; OPEND-NEXT: ) |
| ;; OPEND-NEXT: ) |
| ;; CLOSE: (export "encode" (func $encode)) |
| |
| ;; CLOSE: (export "read" (func $read)) |
| |
| ;; CLOSE: (func $encode (type $1) |
| ;; CLOSE-NEXT: (drop |
| ;; CLOSE-NEXT: (string.encode_wtf16_array |
| ;; CLOSE-NEXT: (string.const "hello") |
| ;; CLOSE-NEXT: (global.get $global) |
| ;; CLOSE-NEXT: (i32.const 0) |
| ;; CLOSE-NEXT: ) |
| ;; CLOSE-NEXT: ) |
| ;; CLOSE-NEXT: ) |
| (func $encode (export "encode") |
| (drop |
| (string.encode_wtf16_array |
| (string.const "hello") |
| (global.get $global) |
| (i32.const 0) |
| ) |
| ) |
| ) |
| |
| ;; OPEND: (func $read (type $2) (result i32) |
| ;; OPEND-NEXT: (array.get_s $array |
| ;; OPEND-NEXT: (global.get $global) |
| ;; OPEND-NEXT: (i32.const 0) |
| ;; OPEND-NEXT: ) |
| ;; OPEND-NEXT: ) |
| ;; CLOSE: (func $read (type $2) (result i32) |
| ;; CLOSE-NEXT: (array.get_s $array |
| ;; CLOSE-NEXT: (global.get $global) |
| ;; CLOSE-NEXT: (i32.const 0) |
| ;; CLOSE-NEXT: ) |
| ;; CLOSE-NEXT: ) |
| (func $read (export "read") (result i32) |
| ;; We could infer what the value is here, since there is only one write. TODO |
| ;; Meanwhile, we should not infer a wrong value, even in closed world. |
| (array.get_s $array |
| (global.get $global) |
| (i32.const 0) |
| ) |
| ) |
| ) |
| |
| ;; Export parameter test. In open world, a function reference parameter of an |
| ;; export can have any value from the outside, so the call_ref is preserved. |
| ;; In closed world, we assume no such function is called from the outside. |
| (module |
| ;; OPEND: (type $sig (func (result i32))) |
| ;; CLOSE: (type $sig (func (result i32))) |
| (type $sig (func (result i32))) |
| |
| ;; OPEND: (type $1 (func (param (ref $sig)) (result i32))) |
| |
| ;; OPEND: (export "test-export-param" (func $export-param)) |
| |
| ;; OPEND: (func $export-param (type $1) (param $f (ref $sig)) (result i32) |
| ;; OPEND-NEXT: (call_ref $sig |
| ;; OPEND-NEXT: (local.get $f) |
| ;; OPEND-NEXT: ) |
| ;; OPEND-NEXT: ) |
| ;; CLOSE: (type $1 (func (param (ref $sig)) (result i32))) |
| |
| ;; CLOSE: (export "test-export-param" (func $export-param)) |
| |
| ;; CLOSE: (func $export-param (type $1) (param $f (ref $sig)) (result i32) |
| ;; CLOSE-NEXT: (drop |
| ;; CLOSE-NEXT: (call_ref $sig |
| ;; CLOSE-NEXT: (local.get $f) |
| ;; CLOSE-NEXT: ) |
| ;; CLOSE-NEXT: ) |
| ;; CLOSE-NEXT: (unreachable) |
| ;; CLOSE-NEXT: ) |
| (func $export-param (export "test-export-param") (param $f (ref $sig)) (result i32) |
| (call_ref $sig |
| (local.get $f) |
| ) |
| ) |
| ) |
| |
| ;; Import result test. In open world, the return value of the imported function |
| ;; can be any function reference, which when called via call_ref preserves it. |
| ;; In closed world, it optimizes to unreachable. |
| (module |
| ;; OPEND: (type $sig (func (result i32))) |
| ;; CLOSE: (type $sig (func (result i32))) |
| (type $sig (func (result i32))) |
| ;; OPEND: (type $1 (func (result (ref $sig)))) |
| |
| ;; OPEND: (import "env" "get-sig" (func $get-sig (type $1) (result (ref $sig)))) |
| ;; CLOSE: (type $1 (func (result (ref $sig)))) |
| |
| ;; CLOSE: (import "env" "get-sig" (func $get-sig (type $1) (result (ref $sig)))) |
| (import "env" "get-sig" (func $get-sig (result (ref $sig)))) |
| |
| ;; OPEND: (export "test-import-result" (func $import-result)) |
| |
| ;; OPEND: (func $import-result (type $sig) (result i32) |
| ;; OPEND-NEXT: (call_ref $sig |
| ;; OPEND-NEXT: (call $get-sig) |
| ;; OPEND-NEXT: ) |
| ;; OPEND-NEXT: ) |
| ;; CLOSE: (export "test-import-result" (func $import-result)) |
| |
| ;; CLOSE: (func $import-result (type $sig) (result i32) |
| ;; CLOSE-NEXT: (drop |
| ;; CLOSE-NEXT: (call_ref $sig |
| ;; CLOSE-NEXT: (call $get-sig) |
| ;; CLOSE-NEXT: ) |
| ;; CLOSE-NEXT: ) |
| ;; CLOSE-NEXT: (unreachable) |
| ;; CLOSE-NEXT: ) |
| (func $import-result (export "test-import-result") (result i32) |
| (call_ref $sig |
| (call $get-sig) |
| ) |
| ) |
| ) |
| |