;; NOTE: Assertions have been generated by update_lit_checks.py and should not be edited.

;; RUN: wasm-opt %s -all --optimize-instructions -S -o - | filecheck %s

(module
 ;; CHECK:      (type $foo (sub (struct)))
 (type $foo (sub (struct)))

 ;; CHECK:      (func $ref-cast-exact-fallthrough (type $2) (param $exact (ref (exact $foo))) (result (ref $foo))
 ;; CHECK-NEXT:  (local $inexact (ref $foo))
 ;; CHECK-NEXT:  (local $2 (ref (exact $foo)))
 ;; CHECK-NEXT:  (drop
 ;; CHECK-NEXT:   (local.tee $inexact
 ;; CHECK-NEXT:    (local.tee $2
 ;; CHECK-NEXT:     (local.get $exact)
 ;; CHECK-NEXT:    )
 ;; CHECK-NEXT:   )
 ;; CHECK-NEXT:  )
 ;; CHECK-NEXT:  (local.get $2)
 ;; CHECK-NEXT: )
 (func $ref-cast-exact-fallthrough (param $exact (ref (exact $foo))) (result (ref $foo))
  (local $inexact (ref $foo))
  ;; We should find that the local.get is the most precise fallthrough value and
  ;; hoist it to eliminate the cast.
  (ref.cast (ref $foo)
   (local.tee $inexact
    (local.get $exact)
   )
  )
 )

 ;; CHECK:      (func $prefer-exactness (type $3) (param $exact-null (ref null (exact $foo))) (result (ref $foo))
 ;; CHECK-NEXT:  (local $inexact-nn (ref $foo))
 ;; CHECK-NEXT:  (local $inexact-null (ref null $foo))
 ;; CHECK-NEXT:  (local $3 (ref null (exact $foo)))
 ;; CHECK-NEXT:  (drop
 ;; CHECK-NEXT:   (local.tee $inexact-nn
 ;; CHECK-NEXT:    (ref.as_non_null
 ;; CHECK-NEXT:     (local.tee $inexact-null
 ;; CHECK-NEXT:      (local.tee $3
 ;; CHECK-NEXT:       (local.get $exact-null)
 ;; CHECK-NEXT:      )
 ;; CHECK-NEXT:     )
 ;; CHECK-NEXT:    )
 ;; CHECK-NEXT:   )
 ;; CHECK-NEXT:  )
 ;; CHECK-NEXT:  (ref.as_non_null
 ;; CHECK-NEXT:   (local.get $3)
 ;; CHECK-NEXT:  )
 ;; CHECK-NEXT: )
 (func $prefer-exactness (param $exact-null (ref null (exact $foo))) (result (ref $foo))
  (local $inexact-nn (ref $foo))
  (local $inexact-null (ref null $foo))
  ;; We should prefer to hoist the exact expression and introduce another null
  ;; check rather than hoisting the non-null, inexact expression.
  (ref.cast (ref $foo)
   (local.tee $inexact-nn
    (ref.as_non_null
     (local.tee $inexact-null
      (local.get $exact-null)
     )
    )
   )
  )
 )

 ;; CHECK:      (func $combine-non-null (type $1) (param $foo (ref null $foo)) (result (ref (exact $foo)))
 ;; CHECK-NEXT:  (ref.cast (ref (exact $foo))
 ;; CHECK-NEXT:   (local.get $foo)
 ;; CHECK-NEXT:  )
 ;; CHECK-NEXT: )
 (func $combine-non-null (param $foo (ref null $foo)) (result (ref (exact $foo)))
  ;; We should not lose the exactness of the cast when we combine the
  ;; ref.as_non_null into it.
  (ref.cast (ref null (exact $foo))
   (ref.as_non_null
    (local.get $foo)
   )
  )
 )

 ;; CHECK:      (func $combine-non-null-reverse (type $1) (param $foo (ref null $foo)) (result (ref (exact $foo)))
 ;; CHECK-NEXT:  (ref.cast (ref (exact $foo))
 ;; CHECK-NEXT:   (local.get $foo)
 ;; CHECK-NEXT:  )
 ;; CHECK-NEXT: )
 (func $combine-non-null-reverse (param $foo (ref null $foo)) (result (ref (exact $foo)))
  ;; As above, but flipped.
  (ref.as_non_null
   (ref.cast (ref null (exact $foo))
    (local.get $foo)
   )
  )
 )
)
