blob: d8fe7a67705fa0e0ae4fab92e34de64c74c90a5e [file] [log] [blame] [edit]
;; NOTE: Assertions have been generated by update_lit_checks.py and should not be edited.
;; RUN: wasm-opt %s --optimize-instructions --traps-never-happen -all --nominal -S -o - | filecheck %s --check-prefix TNH
;; RUN: wasm-opt %s --optimize-instructions -all --nominal -S -o - | filecheck %s --check-prefix NO_TNH
(module
;; TNH: (type $struct (struct_subtype data))
;; NO_TNH: (type $struct (struct_subtype data))
(type $struct (struct_subtype data))
;; TNH: (func $ref.eq (type $eqref_eqref_=>_i32) (param $a eqref) (param $b eqref) (result i32)
;; TNH-NEXT: (ref.eq
;; TNH-NEXT: (local.get $a)
;; TNH-NEXT: (local.get $b)
;; TNH-NEXT: )
;; TNH-NEXT: )
;; NO_TNH: (func $ref.eq (type $eqref_eqref_=>_i32) (param $a eqref) (param $b eqref) (result i32)
;; NO_TNH-NEXT: (ref.eq
;; NO_TNH-NEXT: (ref.as_non_null
;; NO_TNH-NEXT: (ref.cast_static $struct
;; NO_TNH-NEXT: (local.get $a)
;; NO_TNH-NEXT: )
;; NO_TNH-NEXT: )
;; NO_TNH-NEXT: (ref.as_data
;; NO_TNH-NEXT: (local.get $b)
;; NO_TNH-NEXT: )
;; NO_TNH-NEXT: )
;; NO_TNH-NEXT: )
(func $ref.eq (param $a (ref null eq)) (param $b (ref null eq)) (result i32)
;; When traps never happen we can remove all the casts here, since they do
;; not affect the comparison of the references.
(ref.eq
(ref.as_data
(ref.as_non_null
(ref.cast_static $struct
(local.get $a)
)
)
)
;; Note that we can remove the non-null casts here in both modes, as the
;; ref.as_data also checks for null.
(ref.as_data
(ref.as_non_null
(ref.as_non_null
(local.get $b)
)
)
)
)
)
;; TNH: (func $ref.eq-no (type $eqref_eqref_=>_none) (param $a eqref) (param $b eqref)
;; TNH-NEXT: (drop
;; TNH-NEXT: (i32.const 1)
;; TNH-NEXT: )
;; TNH-NEXT: )
;; NO_TNH: (func $ref.eq-no (type $eqref_eqref_=>_none) (param $a eqref) (param $b eqref)
;; NO_TNH-NEXT: (drop
;; NO_TNH-NEXT: (ref.eq
;; NO_TNH-NEXT: (block (result (ref $struct))
;; NO_TNH-NEXT: (drop
;; NO_TNH-NEXT: (ref.func $ref.eq-no)
;; NO_TNH-NEXT: )
;; NO_TNH-NEXT: (unreachable)
;; NO_TNH-NEXT: )
;; NO_TNH-NEXT: (block (result (ref data))
;; NO_TNH-NEXT: (drop
;; NO_TNH-NEXT: (ref.func $ref.eq-no)
;; NO_TNH-NEXT: )
;; NO_TNH-NEXT: (unreachable)
;; NO_TNH-NEXT: )
;; NO_TNH-NEXT: )
;; NO_TNH-NEXT: )
;; NO_TNH-NEXT: )
(func $ref.eq-no (param $a (ref null eq)) (param $b (ref null eq))
;; We must leave the inputs to ref.eq of type eqref or a subtype. Note that
;; these casts will trap, so other opts might get in the way before we can
;; do anything. The crucial thing we test here is that we do not emit
;; something that does not validate (as ref.eq inputs must be eqrefs).
(drop
(ref.eq
(ref.cast_static $struct
(ref.func $ref.eq-no) ;; *Not* an eqref!
)
(ref.as_non_null
(ref.as_data
(ref.as_non_null
(ref.func $ref.eq-no) ;; *Not* an eqref!
)
)
)
)
)
)
;; TNH: (func $ref.is (type $eqref_=>_i32) (param $a eqref) (result i32)
;; TNH-NEXT: (drop
;; TNH-NEXT: (ref.cast_static $struct
;; TNH-NEXT: (ref.as_data
;; TNH-NEXT: (local.get $a)
;; TNH-NEXT: )
;; TNH-NEXT: )
;; TNH-NEXT: )
;; TNH-NEXT: (i32.const 0)
;; TNH-NEXT: )
;; NO_TNH: (func $ref.is (type $eqref_=>_i32) (param $a eqref) (result i32)
;; NO_TNH-NEXT: (drop
;; NO_TNH-NEXT: (ref.cast_static $struct
;; NO_TNH-NEXT: (ref.as_data
;; NO_TNH-NEXT: (local.get $a)
;; NO_TNH-NEXT: )
;; NO_TNH-NEXT: )
;; NO_TNH-NEXT: )
;; NO_TNH-NEXT: (i32.const 0)
;; NO_TNH-NEXT: )
(func $ref.is (param $a (ref null eq)) (result i32)
;; In this case non-nullability is enough to tell that the ref.is will
;; return 0. TNH does not help here.
(ref.is_null
(ref.cast_static $struct
(ref.as_non_null
(ref.as_data
(local.get $a)
)
)
)
)
)
;; TNH: (func $ref.is_b (type $eqref_=>_i32) (param $a eqref) (result i32)
;; TNH-NEXT: (ref.is_null
;; TNH-NEXT: (local.get $a)
;; TNH-NEXT: )
;; TNH-NEXT: )
;; NO_TNH: (func $ref.is_b (type $eqref_=>_i32) (param $a eqref) (result i32)
;; NO_TNH-NEXT: (ref.is_null
;; NO_TNH-NEXT: (ref.cast_static $struct
;; NO_TNH-NEXT: (local.get $a)
;; NO_TNH-NEXT: )
;; NO_TNH-NEXT: )
;; NO_TNH-NEXT: )
(func $ref.is_b(param $a (ref null eq)) (result i32)
;; Here we only have a cast, and no ref.as operations that force the value
;; to be non-nullable. That means we cannot remove the ref.is, but we can
;; remove the cast in TNH.
(ref.is_null
(ref.cast_static $struct
(local.get $a)
)
)
)
;; TNH: (func $ref.is_func_a (type $anyref_=>_i32) (param $a anyref) (result i32)
;; TNH-NEXT: (drop
;; TNH-NEXT: (ref.as_func
;; TNH-NEXT: (local.get $a)
;; TNH-NEXT: )
;; TNH-NEXT: )
;; TNH-NEXT: (i32.const 1)
;; TNH-NEXT: )
;; NO_TNH: (func $ref.is_func_a (type $anyref_=>_i32) (param $a anyref) (result i32)
;; NO_TNH-NEXT: (drop
;; NO_TNH-NEXT: (ref.as_func
;; NO_TNH-NEXT: (local.get $a)
;; NO_TNH-NEXT: )
;; NO_TNH-NEXT: )
;; NO_TNH-NEXT: (i32.const 1)
;; NO_TNH-NEXT: )
(func $ref.is_func_a (param $a (ref null any)) (result i32)
;; The check must succeed. We can return 1 here, and drop the rest, with or
;; without TNH (in particular, TNH should not just remove the cast but not
;; return a 1).
(ref.is_func
(ref.as_func
(local.get $a)
)
)
)
;; TNH: (func $ref.is_func_b (type $anyref_=>_i32) (param $a anyref) (result i32)
;; TNH-NEXT: (drop
;; TNH-NEXT: (ref.as_data
;; TNH-NEXT: (local.get $a)
;; TNH-NEXT: )
;; TNH-NEXT: )
;; TNH-NEXT: (i32.const 0)
;; TNH-NEXT: )
;; NO_TNH: (func $ref.is_func_b (type $anyref_=>_i32) (param $a anyref) (result i32)
;; NO_TNH-NEXT: (drop
;; NO_TNH-NEXT: (ref.as_data
;; NO_TNH-NEXT: (local.get $a)
;; NO_TNH-NEXT: )
;; NO_TNH-NEXT: )
;; NO_TNH-NEXT: (i32.const 0)
;; NO_TNH-NEXT: )
(func $ref.is_func_b (param $a (ref null any)) (result i32)
;; A case where the type cannot match, and we return 0.
(ref.is_func
(ref.as_data
(local.get $a)
)
)
)
)