blob: 0ee1137438c13beb3ed1be04cb64ce3652ce3fc5 [file] [edit]
;; NOTE: Assertions have been generated by update_lit_checks.py --all-items and should not be edited.
;; RUN: foreach %s %t wasm-opt -all --gufa --closed-world -S -o - | filecheck %s
;; Function subtyping in results.
(module
(rec
;; CHECK: (rec
;; CHECK-NEXT: (type $super (sub (func (result i32))))
(type $super (sub (func (result i32))))
;; CHECK: (type $sub (sub $super (func (result i32))))
(type $sub (sub $super (func (result i32))))
)
;; CHECK: (type $2 (func (param i32)))
;; CHECK: (table $table 3 funcref)
(table $table i32 3 funcref)
;; CHECK: (elem $elem (i32.const 0) $super $sub)
(elem $elem (i32.const 0) $super $sub)
;; CHECK: (export "export" (func $export))
;; CHECK: (func $super (type $super) (result i32)
;; CHECK-NEXT: (i32.const 42)
;; CHECK-NEXT: )
(func $super (type $super) (result i32)
(i32.const 42)
)
;; CHECK: (func $sub (type $sub) (result i32)
;; CHECK-NEXT: (i32.const 1337)
;; CHECK-NEXT: )
(func $sub (type $sub) (result i32)
(i32.const 1337)
)
;; CHECK: (func $export (type $2) (param $x i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (call_indirect $table (type $super)
;; CHECK-NEXT: (local.get $x)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (block (result i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (call_indirect $table (type $sub)
;; CHECK-NEXT: (local.get $x)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.const 1337)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $export (export "export") (param $x i32)
;; Call using the supertype. We might be calling the subtype too, so we can't
;; infer the result.
(drop
(call_indirect $table (type $super)
(local.get $x)
)
)
;; Call using the subtype. Now we can infer the return value. (It might also
;; trap, of course, if the table slot is null, but that does not prevent us
;; from setting the result of 1 here, which is only used if it does not trap.)
(drop
(call_indirect $table (type $sub)
(local.get $x)
)
)
)
)
;; As above, but now the functions return the same.
(module
(rec
;; CHECK: (rec
;; CHECK-NEXT: (type $super (sub (func (result i32))))
(type $super (sub (func (result i32))))
;; CHECK: (type $sub (sub $super (func (result i32))))
(type $sub (sub $super (func (result i32))))
)
;; CHECK: (type $2 (func (param i32)))
;; CHECK: (table $table 3 funcref)
(table $table i32 3 funcref)
;; CHECK: (elem $elem (i32.const 0) $super $sub)
(elem $elem (i32.const 0) $super $sub)
;; CHECK: (export "export" (func $export))
;; CHECK: (func $super (type $super) (result i32)
;; CHECK-NEXT: (i32.const 42)
;; CHECK-NEXT: )
(func $super (type $super) (result i32)
(i32.const 42)
)
;; CHECK: (func $sub (type $sub) (result i32)
;; CHECK-NEXT: (i32.const 42)
;; CHECK-NEXT: )
(func $sub (type $sub) (result i32)
(i32.const 42) ;; this changed
)
;; CHECK: (func $export (type $2) (param $x i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (block (result i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (call_indirect $table (type $super)
;; CHECK-NEXT: (local.get $x)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.const 42)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (block (result i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (call_indirect $table (type $sub)
;; CHECK-NEXT: (local.get $x)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.const 42)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $export (export "export") (param $x i32)
(drop
(call_indirect $table (type $super)
(local.get $x)
)
)
;; They both return 42 now, so we can optimize this.
(drop
(call_indirect $table (type $sub)
(local.get $x)
)
)
)
)
;; Function subtyping in params.
(module
(rec
;; CHECK: (rec
;; CHECK-NEXT: (type $super (sub (func (param i32))))
(type $super (sub (func (param i32))))
;; CHECK: (type $sub (sub $super (func (param i32))))
(type $sub (sub $super (func (param i32))))
)
;; CHECK: (type $2 (func (param i32)))
;; CHECK: (table $table 3 funcref)
(table $table i32 3 funcref)
;; CHECK: (elem $elem (i32.const 0) $super $sub)
(elem $elem (i32.const 0) $super $sub)
;; CHECK: (export "export" (func $export))
;; CHECK: (func $super (type $super) (param $x i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (i32.const 42)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $super (type $super) (param $x i32)
;; This type is called with only one possible value, 42.
(drop
(local.get $x)
)
)
;; CHECK: (func $sub (type $sub) (param $x i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (local.get $x)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $sub (type $sub) (param $x i32)
;; We might be called with our supertype too, and the values differ, so we do
;; not infer anything here.
(drop
(local.get $x)
)
)
;; CHECK: (func $export (type $2) (param $x i32)
;; CHECK-NEXT: (call_indirect $table (type $super)
;; CHECK-NEXT: (i32.const 42)
;; CHECK-NEXT: (local.get $x)
;; CHECK-NEXT: )
;; CHECK-NEXT: (call_indirect $table (type $sub)
;; CHECK-NEXT: (i32.const 1337)
;; CHECK-NEXT: (local.get $x)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $export (export "export") (param $x i32)
;; Call using the supertype.
(call_indirect $table (type $super)
(i32.const 42)
(local.get $x)
)
;; Call using the subtype.
(call_indirect $table (type $sub)
(i32.const 1337)
(local.get $x)
)
)
)
;; As above, but now send the same thing to both types.
(module
(rec
;; CHECK: (rec
;; CHECK-NEXT: (type $super (sub (func (param i32))))
(type $super (sub (func (param i32))))
;; CHECK: (type $sub (sub $super (func (param i32))))
(type $sub (sub $super (func (param i32))))
)
;; CHECK: (type $2 (func (param i32)))
;; CHECK: (table $table 3 funcref)
(table $table i32 3 funcref)
;; CHECK: (elem $elem (i32.const 0) $super $sub)
(elem $elem (i32.const 0) $super $sub)
;; CHECK: (export "export" (func $export))
;; CHECK: (func $super (type $super) (param $x i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (i32.const 42)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $super (type $super) (param $x i32)
(drop
(local.get $x)
)
)
;; CHECK: (func $sub (type $sub) (param $x i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (i32.const 42)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $sub (type $sub) (param $x i32)
;; We can now infer 42 here.
(drop
(local.get $x)
)
)
;; CHECK: (func $export (type $2) (param $x i32)
;; CHECK-NEXT: (call_indirect $table (type $super)
;; CHECK-NEXT: (i32.const 42)
;; CHECK-NEXT: (local.get $x)
;; CHECK-NEXT: )
;; CHECK-NEXT: (call_indirect $table (type $sub)
;; CHECK-NEXT: (i32.const 42)
;; CHECK-NEXT: (local.get $x)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $export (export "export") (param $x i32)
(call_indirect $table (type $super)
(i32.const 42)
(local.get $x)
)
(call_indirect $table (type $sub)
(i32.const 42) ;; this changed
(local.get $x)
)
)
)
;; CallRef, where exactness matters.
(module
(rec
;; CHECK: (rec
;; CHECK-NEXT: (type $super (sub (func (result i32))))
(type $super (sub (func (result i32))))
;; CHECK: (type $sub (sub $super (func (result i32))))
(type $sub (sub $super (func (result i32))))
)
;; CHECK: (type $2 (func (param (ref $super) (ref (exact $super)) (ref $sub) (ref (exact $sub)))))
;; CHECK: (table $table 3 funcref)
(table $table i32 3 funcref)
;; CHECK: (elem $elem (i32.const 0) $super $sub)
(elem $elem (i32.const 0) $super $sub)
;; CHECK: (export "export" (func $export))
;; CHECK: (func $super (type $super) (result i32)
;; CHECK-NEXT: (i32.const 42)
;; CHECK-NEXT: )
(func $super (type $super) (result i32)
(i32.const 42)
)
;; CHECK: (func $sub (type $sub) (result i32)
;; CHECK-NEXT: (i32.const 1337)
;; CHECK-NEXT: )
(func $sub (type $sub) (result i32)
(i32.const 1337)
)
;; CHECK: (func $export (type $2) (param $super (ref $super)) (param $super-exact (ref (exact $super))) (param $sub (ref $sub)) (param $sub-exact (ref (exact $sub)))
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (call_ref $super
;; CHECK-NEXT: (local.get $super)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (block (result i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (call_ref $super
;; CHECK-NEXT: (local.get $super-exact)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.const 42)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (block (result i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (call_ref $sub
;; CHECK-NEXT: (local.get $sub)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.const 1337)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (block (result i32)
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (call_ref $sub
;; CHECK-NEXT: (local.get $sub-exact)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (i32.const 1337)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $export (export "export") (param $super (ref $super)) (param $super-exact (ref (exact $super)))
(param $sub (ref $sub)) (param $sub-exact (ref (exact $sub)))
;; This could call anything, so we infer nothing.
(drop
(call_ref $super
(local.get $super)
)
)
;; This calls exactly super, so it returns 42.
(drop
(call_ref $super
(local.get $super-exact)
)
)
;; Called exactly or not, we can infer 1337 here.
(drop
(call_ref $sub
(local.get $sub)
)
)
(drop
(call_ref $sub
(local.get $sub-exact)
)
)
)
)