;; NOTE: Assertions have been generated by update_lit_checks.py and should not be edited.
;; RUN: wasm-opt %s --dce -all -S -o - | filecheck %s

;; If either try_table body or any of catch handler is reachable, the whole
;; try_table construct is reachable.
(module
  ;; CHECK:      (tag $e (type $0))
  (tag $e)

  ;; CHECK:      (tag $e-i32 (type $1) (param i32))
  (tag $e-i32 (param i32))

  ;; CHECK:      (func $foo (type $0)
  ;; CHECK-NEXT: )
  (func $foo)

  ;; CHECK:      (func $try_table_unreachable (type $0)
  ;; CHECK-NEXT:  (block $catch
  ;; CHECK-NEXT:   (try_table (catch_all $catch)
  ;; CHECK-NEXT:    (unreachable)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (call $foo)
  ;; CHECK-NEXT: )
  (func $try_table_unreachable
    (block $catch
      (try_table (catch_all $catch)
        (unreachable)
      )
    )
    (call $foo) ;; shouldn't be dce'd
  )

  ;; CHECK:      (func $catch_unreachable (type $0)
  ;; CHECK-NEXT:  (block $tryend
  ;; CHECK-NEXT:   (block $catch
  ;; CHECK-NEXT:    (try_table (catch_all $catch)
  ;; CHECK-NEXT:     (br $tryend)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:   (unreachable)
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (call $foo)
  ;; CHECK-NEXT: )
  (func $catch_unreachable
    (block $tryend
      (block $catch
        (try_table (catch_all $catch)
          (br $tryend)
        )
      )
      (unreachable)
    )
    (call $foo) ;; shouldn't be dce'd
  )

  ;; CHECK:      (func $both_unreachable (type $0)
  ;; CHECK-NEXT:  (block $tryend
  ;; CHECK-NEXT:   (block $catch
  ;; CHECK-NEXT:    (try_table (catch_all $catch)
  ;; CHECK-NEXT:     (unreachable)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:   (unreachable)
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $both_unreachable
    (block $tryend
      (block $catch
        (try_table (catch_all $catch)
          (unreachable)
        )
      )
      (unreachable)
    )
    (call $foo) ;; should be dce'd
  )

  ;; CHECK:      (func $throw (type $0)
  ;; CHECK-NEXT:  (block $label$0
  ;; CHECK-NEXT:   (block $label$1
  ;; CHECK-NEXT:    (throw $e)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $throw
    ;; All these wrapping expressions before 'throw' will be dce'd.
    (drop
      (block $label$0 (result externref)
        (if
          (i32.clz
            (block $label$1 (result i32)
              (throw $e)
            )
          )
          (then
            (nop)
          )
        )
        (ref.null extern)
      )
    )
  )

  ;; CHECK:      (func $throw_ref (type $0)
  ;; CHECK-NEXT:  (local $ex exnref)
  ;; CHECK-NEXT:  (block $tryend
  ;; CHECK-NEXT:   (local.set $ex
  ;; CHECK-NEXT:    (block $catch (result exnref)
  ;; CHECK-NEXT:     (try_table (catch_all_ref $catch)
  ;; CHECK-NEXT:      (br $tryend)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:   (block
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (i32.const 0)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (throw_ref
  ;; CHECK-NEXT:     (local.get $ex)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $throw_ref
    (local $ex exnref)
    (block $tryend
      (local.set $ex
        (block $catch (result exnref)
          (try_table (catch_all_ref $catch)
            (br $tryend)
          )
        )
      )
      (drop
        ;; This i32.add will be dce'd.
        (i32.add
          (i32.const 0)
          (throw_ref (local.get $ex))
        )
      )
    )
  )
)
