blob: fa7643ec74db04c45fca544422d460a6fbd1109e [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 --cfp-reftest --closed-world -all -S -o - | filecheck %s
;; When a ref.get_desc can only read from two types, and those types have a
;; constant field, we can select between those two values using a ref.test.
(module
(rec
;; CHECK: (rec
;; CHECK-NEXT: (type $super (sub (descriptor $super.desc) (struct)))
(type $super (sub (descriptor $super.desc) (struct)))
;; CHECK: (type $super.desc (sub (describes $super) (struct)))
(type $super.desc (sub (describes $super) (struct)))
;; CHECK: (type $A (sub $super (descriptor $A.desc) (struct)))
(type $A (sub $super (descriptor $A.desc) (struct)))
;; CHECK: (type $A.desc (sub $super.desc (describes $A) (struct)))
(type $A.desc (sub $super.desc (describes $A) (struct)))
;; CHECK: (type $B (sub $super (descriptor $B.desc) (struct)))
(type $B (sub $super (descriptor $B.desc) (struct)))
;; CHECK: (type $B.desc (sub $super.desc (describes $B) (struct)))
(type $B.desc (sub $super.desc (describes $B) (struct)))
)
;; CHECK: (type $6 (func (param (ref null $super) (ref null $A) (ref null $B))))
;; CHECK: (global $A.desc (ref (exact $A.desc)) (struct.new_default $A.desc))
(global $A.desc (ref (exact $A.desc)) (struct.new $A.desc))
;; CHECK: (global $B.desc (ref (exact $B.desc)) (struct.new_default $B.desc))
(global $B.desc (ref (exact $B.desc)) (struct.new $B.desc))
;; CHECK: (func $test (type $6) (param $super (ref null $super)) (param $A (ref null $A)) (param $B (ref null $B))
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (struct.new_default_desc $A
;; CHECK-NEXT: (global.get $A.desc)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (struct.new_default_desc $B
;; CHECK-NEXT: (global.get $B.desc)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (select (result (ref $super.desc))
;; CHECK-NEXT: (global.get $A.desc)
;; CHECK-NEXT: (global.get $B.desc)
;; CHECK-NEXT: (ref.test (ref $A)
;; CHECK-NEXT: (ref.as_non_null
;; CHECK-NEXT: (local.get $super)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (block (result (ref (exact $A.desc)))
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.as_non_null
;; CHECK-NEXT: (local.get $A)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (global.get $A.desc)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (block (result (ref (exact $B.desc)))
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.as_non_null
;; CHECK-NEXT: (local.get $B)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (global.get $B.desc)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $test (param $super (ref null $super)) (param $A (ref null $A)) (param $B (ref null $B))
(drop
(struct.new_desc $A
(global.get $A.desc)
)
)
(drop
(struct.new_desc $B
(global.get $B.desc)
)
)
;; We can optimize the read from the super here, using a ref.test.
(drop
(ref.get_desc $super
(local.get $super)
)
)
;; These are optimizable even without ref.test.
(drop
(ref.get_desc $A
(local.get $A)
)
)
(drop
(ref.get_desc $B
(local.get $B)
)
)
)
)
(module
(rec
;; CHECK: (rec
;; CHECK-NEXT: (type $super (sub (descriptor $super.desc) (struct)))
(type $super (sub (descriptor $super.desc) (struct)))
;; CHECK: (type $super.desc (sub (describes $super) (struct)))
(type $super.desc (sub (describes $super) (struct)))
;; CHECK: (type $func (func (param i32) (result i32)))
(type $func (func (param i32) (result i32)))
;; CHECK: (type $sub (sub $super (descriptor $sub.desc) (struct)))
(type $sub (sub $super (descriptor $sub.desc) (struct)))
;; CHECK: (type $sub.desc (sub $super.desc (describes $sub) (struct)))
(type $sub.desc (sub $super.desc (describes $sub) (struct)))
)
;; CHECK: (type $5 (func (result (ref (exact $super.desc)))))
;; CHECK: (global $A (ref (exact $super.desc)) (struct.new_default $super.desc))
(global $A (ref (exact $super.desc)) (struct.new $super.desc))
;; CHECK: (global $B (ref (exact $sub.desc)) (struct.new_default $sub.desc))
(global $B (ref (exact $sub.desc)) (struct.new $sub.desc))
;; CHECK: (func $test (type $5) (result (ref (exact $super.desc)))
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (struct.new_default_desc $super
;; CHECK-NEXT: (global.get $A)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (struct.new_default_desc $sub
;; CHECK-NEXT: (global.get $B)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (block (result (ref (exact $super.desc)))
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (ref.as_non_null
;; CHECK-NEXT: (block (result nullref)
;; CHECK-NEXT: (ref.null none)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: )
;; CHECK-NEXT: (global.get $A)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
(func $test (result (ref (exact $super.desc)))
(drop
(struct.new_default_desc $super
(global.get $A)
)
)
(drop
(struct.new_default_desc $sub
(global.get $B)
)
)
;; We read from an exact $super here, so the type of the ref.get_desc is
;; exact as well. If we ignore that in the optimization, we might think that
;; the two struct.news before us are two possible values, one from $super and
;; one from $sub, and if we emitted a ref.test between those values, we'd get
;; a non-exact value that does not validate.
;;
;; Instead, we should look only at $super itself, and optimize to $A.
(ref.get_desc $super
(block (result (ref null (exact $super)))
(ref.null $super)
)
)
)
;; CHECK: (func $func (type $func) (param $0 i32) (result i32)
;; CHECK-NEXT: (i32.const 42)
;; CHECK-NEXT: )
(func $func (type $func) (param $0 i32) (result i32)
(i32.const 42)
)
)