;; NOTE: Assertions have been generated by update_lit_checks.py --all-items and should not be edited.
;; RUN: wasm-opt %s -all --translate-to-exnref -S -o - | filecheck %s
;; RUN: wasm-opt %s -all --translate-to-exnref -S -o %t
;; RUN: wasm-opt %t -all --optimize-level=3 --generate-stack-ir --optimize-stack-ir --print-stack-ir | filecheck %s --check-prefix STACKIR-OPT

(module
  ;; CHECK:      (type $0 (func (result i32 i64)))

  ;; CHECK:      (type $1 (func))

  ;; CHECK:      (type $2 (func (result i32)))

  ;; CHECK:      (type $3 (func (result i32 (ref exn))))

  ;; CHECK:      (type $4 (func (result i32 i64 (ref exn))))

  ;; CHECK:      (type $5 (func (param i32)))

  ;; CHECK:      (type $6 (func (param i32 i64)))

  ;; CHECK:      (tag $e-empty (type $1))
  ;; STACKIR-OPT:      (type $0 (func (result i32 i64)))

  ;; STACKIR-OPT:      (type $1 (func))

  ;; STACKIR-OPT:      (type $2 (func (result i32)))

  ;; STACKIR-OPT:      (type $3 (func (result i32 (ref exn))))

  ;; STACKIR-OPT:      (type $4 (func (result i32 i64 (ref exn))))

  ;; STACKIR-OPT:      (type $5 (func (param i32)))

  ;; STACKIR-OPT:      (type $6 (func (param i32 i64)))

  ;; STACKIR-OPT:      (tag $e-empty (type $1))
  (tag $e-empty)
  ;; CHECK:      (tag $e-i32 (type $5) (param i32))
  ;; STACKIR-OPT:      (tag $e-i32 (type $5) (param i32))
  (tag $e-i32 (param i32))
  ;; CHECK:      (tag $e-i32-i64 (type $6) (param i32 i64))
  ;; STACKIR-OPT:      (tag $e-i32-i64 (type $6) (param i32 i64))
  (tag $e-i32-i64 (param i32 i64))

  ;; CHECK:      (func $foo (type $1)
  ;; CHECK-NEXT: )
  ;; STACKIR-OPT:      (func $foo (type $1)
  ;; STACKIR-OPT-NEXT: )
  (func $foo)
  ;; CHECK:      (func $bar (type $1)
  ;; CHECK-NEXT: )
  ;; STACKIR-OPT:      (func $bar (type $1)
  ;; STACKIR-OPT-NEXT: )
  (func $bar)
  ;; CHECK:      (func $baz (type $1)
  ;; CHECK-NEXT: )
  ;; STACKIR-OPT:      (func $baz (type $1)
  ;; STACKIR-OPT-NEXT: )
  (func $baz)

  ;; ---------------------------------------------------------------------------
  ;; Basic tests for all combinations of try body's type (none, single, and
  ;; tuple) and the catch's tag type (none, single, and tuple) and with /
  ;; without rethrows

  ;; CHECK:      (func $try-none-tag-none (type $1)
  ;; CHECK-NEXT:  (block $outer0
  ;; CHECK-NEXT:   (block $catch_all2
  ;; CHECK-NEXT:    (block $catch1
  ;; CHECK-NEXT:     (try_table (catch $e-empty $catch1) (catch_all $catch_all2)
  ;; CHECK-NEXT:      (call $foo)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:     (br $outer0)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (call $foo)
  ;; CHECK-NEXT:    (br $outer0)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:   (call $bar)
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  ;; STACKIR-OPT:      (func $try-none-tag-none (type $1)
  ;; STACKIR-OPT-NEXT:  block $outer0
  ;; STACKIR-OPT-NEXT:   block $catch_all2
  ;; STACKIR-OPT-NEXT:    block $catch1
  ;; STACKIR-OPT-NEXT:     try_table (catch $e-empty $catch1) (catch_all $catch_all2)
  ;; STACKIR-OPT-NEXT:      call $foo
  ;; STACKIR-OPT-NEXT:     end
  ;; STACKIR-OPT-NEXT:     br $outer0
  ;; STACKIR-OPT-NEXT:    end
  ;; STACKIR-OPT-NEXT:    call $foo
  ;; STACKIR-OPT-NEXT:    br $outer0
  ;; STACKIR-OPT-NEXT:   end
  ;; STACKIR-OPT-NEXT:   call $bar
  ;; STACKIR-OPT-NEXT:  end
  ;; STACKIR-OPT-NEXT: )
  (func $try-none-tag-none
    ;; try's type is none and catch's tag type is none
    (try $l0
      (do
        (call $foo)
      )
      (catch $e-empty ;; converted to catch
        (call $foo)
      )
      (catch_all      ;; converted to catch_all
        (call $bar)
      )
    )
  )

  ;; CHECK:      (func $try-none-tag-none-with-rethrow (type $1)
  ;; CHECK-NEXT:  (local $0 exnref)
  ;; CHECK-NEXT:  (block $outer0
  ;; CHECK-NEXT:   (local.set $0
  ;; CHECK-NEXT:    (block $catch_all2 (result (ref exn))
  ;; CHECK-NEXT:     (local.set $0
  ;; CHECK-NEXT:      (block $catch1 (result (ref exn))
  ;; CHECK-NEXT:       (try_table (catch_ref $e-empty $catch1) (catch_all_ref $catch_all2)
  ;; CHECK-NEXT:        (call $foo)
  ;; CHECK-NEXT:       )
  ;; CHECK-NEXT:       (br $outer0)
  ;; CHECK-NEXT:      )
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:     (throw_ref
  ;; CHECK-NEXT:      (local.get $0)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:   (throw_ref
  ;; CHECK-NEXT:    (local.get $0)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  ;; STACKIR-OPT:      (func $try-none-tag-none-with-rethrow (type $1)
  ;; STACKIR-OPT-NEXT:  (local $0 exnref)
  ;; STACKIR-OPT-NEXT:  block $outer0
  ;; STACKIR-OPT-NEXT:   block $catch_all2 (result (ref exn))
  ;; STACKIR-OPT-NEXT:    block $catch1 (result (ref exn))
  ;; STACKIR-OPT-NEXT:     try_table (catch_ref $e-empty $catch1) (catch_all_ref $catch_all2)
  ;; STACKIR-OPT-NEXT:      call $foo
  ;; STACKIR-OPT-NEXT:     end
  ;; STACKIR-OPT-NEXT:     br $outer0
  ;; STACKIR-OPT-NEXT:    end
  ;; STACKIR-OPT-NEXT:    throw_ref
  ;; STACKIR-OPT-NEXT:   end
  ;; STACKIR-OPT-NEXT:   throw_ref
  ;; STACKIR-OPT-NEXT:  end
  ;; STACKIR-OPT-NEXT: )
  (func $try-none-tag-none-with-rethrow
    ;; try's type is none and catch's tag type is none, and there are rethrows
    (try $l0
      (do
        (call $foo)
      )
      (catch $e-empty ;; converted to catch_ref, because of rethrow
        (rethrow $l0)
      )
      (catch_all      ;; converted to catch_all_ref, because of rethrow
        (rethrow $l0)
      )
    )
  )

  ;; CHECK:      (func $try-none-tag-single (type $1)
  ;; CHECK-NEXT:  (local $0 i32)
  ;; CHECK-NEXT:  (block $outer0
  ;; CHECK-NEXT:   (block $catch_all2
  ;; CHECK-NEXT:    (local.set $0
  ;; CHECK-NEXT:     (block $catch1 (result i32)
  ;; CHECK-NEXT:      (try_table (catch $e-i32 $catch1) (catch_all $catch_all2)
  ;; CHECK-NEXT:       (call $foo)
  ;; CHECK-NEXT:      )
  ;; CHECK-NEXT:      (br $outer0)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (local.get $0)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (br $outer0)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:   (call $bar)
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  ;; STACKIR-OPT:      (func $try-none-tag-single (type $1)
  ;; STACKIR-OPT-NEXT:  (local $0 i32)
  ;; STACKIR-OPT-NEXT:  block $outer0
  ;; STACKIR-OPT-NEXT:   block $catch_all2
  ;; STACKIR-OPT-NEXT:    block $catch1 (result i32)
  ;; STACKIR-OPT-NEXT:     try_table (catch $e-i32 $catch1) (catch_all $catch_all2)
  ;; STACKIR-OPT-NEXT:      call $foo
  ;; STACKIR-OPT-NEXT:     end
  ;; STACKIR-OPT-NEXT:     br $outer0
  ;; STACKIR-OPT-NEXT:    end
  ;; STACKIR-OPT-NEXT:    drop
  ;; STACKIR-OPT-NEXT:    br $outer0
  ;; STACKIR-OPT-NEXT:   end
  ;; STACKIR-OPT-NEXT:   call $bar
  ;; STACKIR-OPT-NEXT:  end
  ;; STACKIR-OPT-NEXT: )
  (func $try-none-tag-single
    ;; try's type is none and catch's tag type is single
    (try $l0
      (do
        (call $foo)
      )
      (catch $e-i32
        (drop
          (pop i32)
        )
      )
      (catch_all
        (call $bar)
      )
    )
  )

  ;; CHECK:      (func $try-none-tag-single-with-rethrow (type $1)
  ;; CHECK-NEXT:  (local $0 exnref)
  ;; CHECK-NEXT:  (local $1 i32)
  ;; CHECK-NEXT:  (local $2 (tuple i32 (ref exn)))
  ;; CHECK-NEXT:  (block $outer0
  ;; CHECK-NEXT:   (local.set $0
  ;; CHECK-NEXT:    (block $catch_all2 (result (ref exn))
  ;; CHECK-NEXT:     (local.set $2
  ;; CHECK-NEXT:      (block $catch1 (type $3) (result i32 (ref exn))
  ;; CHECK-NEXT:       (try_table (catch_ref $e-i32 $catch1) (catch_all_ref $catch_all2)
  ;; CHECK-NEXT:        (call $foo)
  ;; CHECK-NEXT:       )
  ;; CHECK-NEXT:       (br $outer0)
  ;; CHECK-NEXT:      )
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:     (local.set $1
  ;; CHECK-NEXT:      (tuple.extract 2 0
  ;; CHECK-NEXT:       (local.get $2)
  ;; CHECK-NEXT:      )
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:     (local.set $0
  ;; CHECK-NEXT:      (tuple.extract 2 1
  ;; CHECK-NEXT:       (local.get $2)
  ;; CHECK-NEXT:      )
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:     (block
  ;; CHECK-NEXT:      (drop
  ;; CHECK-NEXT:       (local.get $1)
  ;; CHECK-NEXT:      )
  ;; CHECK-NEXT:      (throw_ref
  ;; CHECK-NEXT:       (local.get $0)
  ;; CHECK-NEXT:      )
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:   (throw_ref
  ;; CHECK-NEXT:    (local.get $0)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  ;; STACKIR-OPT:      (func $try-none-tag-single-with-rethrow (type $1)
  ;; STACKIR-OPT-NEXT:  (local $0 exnref)
  ;; STACKIR-OPT-NEXT:  (local $1 i32)
  ;; STACKIR-OPT-NEXT:  (local $2 (tuple i32 (ref exn)))
  ;; STACKIR-OPT-NEXT:  block $outer0
  ;; STACKIR-OPT-NEXT:   block $catch_all2 (result (ref exn))
  ;; STACKIR-OPT-NEXT:    block $catch1 (type $3) (result i32 (ref exn))
  ;; STACKIR-OPT-NEXT:     try_table (catch_ref $e-i32 $catch1) (catch_all_ref $catch_all2)
  ;; STACKIR-OPT-NEXT:      call $foo
  ;; STACKIR-OPT-NEXT:     end
  ;; STACKIR-OPT-NEXT:     br $outer0
  ;; STACKIR-OPT-NEXT:    end
  ;; STACKIR-OPT-NEXT:    local.set $2
  ;; STACKIR-OPT-NEXT:    local.get $2
  ;; STACKIR-OPT-NEXT:    tuple.extract 2 0
  ;; STACKIR-OPT-NEXT:    local.get $2
  ;; STACKIR-OPT-NEXT:    tuple.extract 2 1
  ;; STACKIR-OPT-NEXT:    local.set $0
  ;; STACKIR-OPT-NEXT:    drop
  ;; STACKIR-OPT-NEXT:    local.get $0
  ;; STACKIR-OPT-NEXT:    throw_ref
  ;; STACKIR-OPT-NEXT:   end
  ;; STACKIR-OPT-NEXT:   throw_ref
  ;; STACKIR-OPT-NEXT:  end
  ;; STACKIR-OPT-NEXT: )
  (func $try-none-tag-single-with-rethrow
    ;; try's type is none and catch's tag type is single, and there are rethrows
    (try $l0
      (do
        (call $foo)
      )
      (catch $e-i32
        (drop
          (pop i32)
        )
        (rethrow $l0)
      )
      (catch_all
        (rethrow $l0)
      )
    )
  )

  ;; CHECK:      (func $try-none-tag-tuple (type $1)
  ;; CHECK-NEXT:  (local $0 (tuple i32 i64))
  ;; CHECK-NEXT:  (block $outer0
  ;; CHECK-NEXT:   (block $catch_all2
  ;; CHECK-NEXT:    (local.set $0
  ;; CHECK-NEXT:     (block $catch1 (type $0) (result i32 i64)
  ;; CHECK-NEXT:      (try_table (catch $e-i32-i64 $catch1) (catch_all $catch_all2)
  ;; CHECK-NEXT:       (call $foo)
  ;; CHECK-NEXT:      )
  ;; CHECK-NEXT:      (br $outer0)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (tuple.drop 2
  ;; CHECK-NEXT:     (local.get $0)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (br $outer0)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:   (call $bar)
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  ;; STACKIR-OPT:      (func $try-none-tag-tuple (type $1)
  ;; STACKIR-OPT-NEXT:  (local $0 (tuple i32 i64))
  ;; STACKIR-OPT-NEXT:  block $outer0
  ;; STACKIR-OPT-NEXT:   block $catch_all2
  ;; STACKIR-OPT-NEXT:    block $catch1 (type $0) (result i32 i64)
  ;; STACKIR-OPT-NEXT:     try_table (catch $e-i32-i64 $catch1) (catch_all $catch_all2)
  ;; STACKIR-OPT-NEXT:      call $foo
  ;; STACKIR-OPT-NEXT:     end
  ;; STACKIR-OPT-NEXT:     br $outer0
  ;; STACKIR-OPT-NEXT:    end
  ;; STACKIR-OPT-NEXT:    local.set $0
  ;; STACKIR-OPT-NEXT:    local.get $0
  ;; STACKIR-OPT-NEXT:    tuple.drop 2
  ;; STACKIR-OPT-NEXT:    br $outer0
  ;; STACKIR-OPT-NEXT:   end
  ;; STACKIR-OPT-NEXT:   call $bar
  ;; STACKIR-OPT-NEXT:  end
  ;; STACKIR-OPT-NEXT: )
  (func $try-none-tag-tuple
    ;; try's type is none and catch's tag type is tuple
    (try $l0
      (do
        (call $foo)
      )
      (catch $e-i32-i64
        (tuple.drop 2
          (pop (tuple i32 i64))
        )
      )
      (catch_all
        (call $bar)
      )
    )
  )

  ;; CHECK:      (func $try-none-tag-tuple-with-rethrow (type $1)
  ;; CHECK-NEXT:  (local $0 exnref)
  ;; CHECK-NEXT:  (local $1 (tuple i32 i64))
  ;; CHECK-NEXT:  (local $2 (tuple i32 i64 (ref exn)))
  ;; CHECK-NEXT:  (block $outer0
  ;; CHECK-NEXT:   (local.set $0
  ;; CHECK-NEXT:    (block $catch_all2 (result (ref exn))
  ;; CHECK-NEXT:     (local.set $2
  ;; CHECK-NEXT:      (block $catch1 (type $4) (result i32 i64 (ref exn))
  ;; CHECK-NEXT:       (try_table (catch_ref $e-i32-i64 $catch1) (catch_all_ref $catch_all2)
  ;; CHECK-NEXT:        (call $foo)
  ;; CHECK-NEXT:       )
  ;; CHECK-NEXT:       (br $outer0)
  ;; CHECK-NEXT:      )
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:     (local.set $1
  ;; CHECK-NEXT:      (tuple.make 2
  ;; CHECK-NEXT:       (tuple.extract 3 0
  ;; CHECK-NEXT:        (local.get $2)
  ;; CHECK-NEXT:       )
  ;; CHECK-NEXT:       (tuple.extract 3 1
  ;; CHECK-NEXT:        (local.get $2)
  ;; CHECK-NEXT:       )
  ;; CHECK-NEXT:      )
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:     (local.set $0
  ;; CHECK-NEXT:      (tuple.extract 3 2
  ;; CHECK-NEXT:       (local.get $2)
  ;; CHECK-NEXT:      )
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:     (block
  ;; CHECK-NEXT:      (tuple.drop 2
  ;; CHECK-NEXT:       (local.get $1)
  ;; CHECK-NEXT:      )
  ;; CHECK-NEXT:      (throw_ref
  ;; CHECK-NEXT:       (local.get $0)
  ;; CHECK-NEXT:      )
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:   (throw_ref
  ;; CHECK-NEXT:    (local.get $0)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  ;; STACKIR-OPT:      (func $try-none-tag-tuple-with-rethrow (type $1)
  ;; STACKIR-OPT-NEXT:  (local $0 exnref)
  ;; STACKIR-OPT-NEXT:  (local $1 (tuple i32 i64))
  ;; STACKIR-OPT-NEXT:  (local $2 (tuple i32 i64 (ref exn)))
  ;; STACKIR-OPT-NEXT:  block $outer0
  ;; STACKIR-OPT-NEXT:   block $catch_all2 (result (ref exn))
  ;; STACKIR-OPT-NEXT:    block $catch1 (type $4) (result i32 i64 (ref exn))
  ;; STACKIR-OPT-NEXT:     try_table (catch_ref $e-i32-i64 $catch1) (catch_all_ref $catch_all2)
  ;; STACKIR-OPT-NEXT:      call $foo
  ;; STACKIR-OPT-NEXT:     end
  ;; STACKIR-OPT-NEXT:     br $outer0
  ;; STACKIR-OPT-NEXT:    end
  ;; STACKIR-OPT-NEXT:    local.set $2
  ;; STACKIR-OPT-NEXT:    local.get $2
  ;; STACKIR-OPT-NEXT:    tuple.extract 3 0
  ;; STACKIR-OPT-NEXT:    local.get $2
  ;; STACKIR-OPT-NEXT:    tuple.extract 3 1
  ;; STACKIR-OPT-NEXT:    tuple.make 2
  ;; STACKIR-OPT-NEXT:    local.set $1
  ;; STACKIR-OPT-NEXT:    local.get $2
  ;; STACKIR-OPT-NEXT:    tuple.extract 3 2
  ;; STACKIR-OPT-NEXT:    local.get $1
  ;; STACKIR-OPT-NEXT:    tuple.drop 2
  ;; STACKIR-OPT-NEXT:    throw_ref
  ;; STACKIR-OPT-NEXT:   end
  ;; STACKIR-OPT-NEXT:   throw_ref
  ;; STACKIR-OPT-NEXT:  end
  ;; STACKIR-OPT-NEXT: )
  (func $try-none-tag-tuple-with-rethrow
    ;; try's type is none and catch's tag type is tuple, and there are rethrows
    (try $l0
      (do
        (call $foo)
      )
      (catch $e-i32-i64
        (tuple.drop 2
          (pop (tuple i32 i64))
        )
        (rethrow $l0)
      )
      (catch_all
        (rethrow $l0)
      )
    )
  )

  ;; CHECK:      (func $try-single-tag-none (type $2) (result i32)
  ;; CHECK-NEXT:  (block $outer0 (result i32)
  ;; CHECK-NEXT:   (block $catch_all2
  ;; CHECK-NEXT:    (block $catch1
  ;; CHECK-NEXT:     (br $outer0
  ;; CHECK-NEXT:      (try_table (result i32) (catch $e-empty $catch1) (catch_all $catch_all2)
  ;; CHECK-NEXT:       (call $foo)
  ;; CHECK-NEXT:       (i32.const 0)
  ;; CHECK-NEXT:      )
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (br $outer0
  ;; CHECK-NEXT:     (i32.const 1)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:   (i32.const 2)
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  ;; STACKIR-OPT:      (func $try-single-tag-none (type $2) (result i32)
  ;; STACKIR-OPT-NEXT:  block $outer0 (result i32)
  ;; STACKIR-OPT-NEXT:   block $catch_all2
  ;; STACKIR-OPT-NEXT:    block $catch1
  ;; STACKIR-OPT-NEXT:     try_table (result i32) (catch $e-empty $catch1) (catch_all $catch_all2)
  ;; STACKIR-OPT-NEXT:      call $foo
  ;; STACKIR-OPT-NEXT:      i32.const 0
  ;; STACKIR-OPT-NEXT:     end
  ;; STACKIR-OPT-NEXT:     br $outer0
  ;; STACKIR-OPT-NEXT:    end
  ;; STACKIR-OPT-NEXT:    i32.const 1
  ;; STACKIR-OPT-NEXT:    br $outer0
  ;; STACKIR-OPT-NEXT:   end
  ;; STACKIR-OPT-NEXT:   i32.const 2
  ;; STACKIR-OPT-NEXT:  end
  ;; STACKIR-OPT-NEXT: )
  (func $try-single-tag-none (result i32)
    ;; try's type is single and catch's tag type is none
    (try $l0 (result i32)
      (do
        (call $foo)
        (i32.const 0)
      )
      (catch $e-empty
        (i32.const 1)
      )
      (catch_all
        (i32.const 2)
      )
    )
  )

  ;; CHECK:      (func $try-single-tag-none-with-rethrow (type $2) (result i32)
  ;; CHECK-NEXT:  (local $0 exnref)
  ;; CHECK-NEXT:  (block $outer0 (result i32)
  ;; CHECK-NEXT:   (local.set $0
  ;; CHECK-NEXT:    (block $catch_all2 (result (ref exn))
  ;; CHECK-NEXT:     (local.set $0
  ;; CHECK-NEXT:      (block $catch1 (result (ref exn))
  ;; CHECK-NEXT:       (br $outer0
  ;; CHECK-NEXT:        (try_table (result i32) (catch_ref $e-empty $catch1) (catch_all_ref $catch_all2)
  ;; CHECK-NEXT:         (call $foo)
  ;; CHECK-NEXT:         (i32.const 0)
  ;; CHECK-NEXT:        )
  ;; CHECK-NEXT:       )
  ;; CHECK-NEXT:      )
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:     (throw_ref
  ;; CHECK-NEXT:      (local.get $0)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:   (throw_ref
  ;; CHECK-NEXT:    (local.get $0)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  ;; STACKIR-OPT:      (func $try-single-tag-none-with-rethrow (type $2) (result i32)
  ;; STACKIR-OPT-NEXT:  (local $0 exnref)
  ;; STACKIR-OPT-NEXT:  block $outer0 (result i32)
  ;; STACKIR-OPT-NEXT:   block $catch_all2 (result (ref exn))
  ;; STACKIR-OPT-NEXT:    block $catch1 (result (ref exn))
  ;; STACKIR-OPT-NEXT:     try_table (result i32) (catch_ref $e-empty $catch1) (catch_all_ref $catch_all2)
  ;; STACKIR-OPT-NEXT:      call $foo
  ;; STACKIR-OPT-NEXT:      i32.const 0
  ;; STACKIR-OPT-NEXT:     end
  ;; STACKIR-OPT-NEXT:     br $outer0
  ;; STACKIR-OPT-NEXT:    end
  ;; STACKIR-OPT-NEXT:    throw_ref
  ;; STACKIR-OPT-NEXT:   end
  ;; STACKIR-OPT-NEXT:   throw_ref
  ;; STACKIR-OPT-NEXT:  end
  ;; STACKIR-OPT-NEXT: )
  (func $try-single-tag-none-with-rethrow (result i32)
    ;; try's type is single and catch's tag type is none, and there are rethrows
    (try $l0 (result i32)
      (do
        (call $foo)
        (i32.const 0)
      )
      (catch $e-empty
        (rethrow $l0)
      )
      (catch_all
        (rethrow $l0)
      )
    )
  )

  ;; CHECK:      (func $try-single-tag-single (type $2) (result i32)
  ;; CHECK-NEXT:  (local $0 i32)
  ;; CHECK-NEXT:  (block $outer0 (result i32)
  ;; CHECK-NEXT:   (block $catch_all2
  ;; CHECK-NEXT:    (local.set $0
  ;; CHECK-NEXT:     (block $catch1 (result i32)
  ;; CHECK-NEXT:      (br $outer0
  ;; CHECK-NEXT:       (try_table (result i32) (catch $e-i32 $catch1) (catch_all $catch_all2)
  ;; CHECK-NEXT:        (call $foo)
  ;; CHECK-NEXT:        (i32.const 0)
  ;; CHECK-NEXT:       )
  ;; CHECK-NEXT:      )
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (br $outer0
  ;; CHECK-NEXT:     (local.get $0)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:   (i32.const 2)
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  ;; STACKIR-OPT:      (func $try-single-tag-single (type $2) (result i32)
  ;; STACKIR-OPT-NEXT:  (local $0 i32)
  ;; STACKIR-OPT-NEXT:  block $outer0 (result i32)
  ;; STACKIR-OPT-NEXT:   block $catch_all2
  ;; STACKIR-OPT-NEXT:    block $catch1 (result i32)
  ;; STACKIR-OPT-NEXT:     try_table (result i32) (catch $e-i32 $catch1) (catch_all $catch_all2)
  ;; STACKIR-OPT-NEXT:      call $foo
  ;; STACKIR-OPT-NEXT:      i32.const 0
  ;; STACKIR-OPT-NEXT:     end
  ;; STACKIR-OPT-NEXT:     br $outer0
  ;; STACKIR-OPT-NEXT:    end
  ;; STACKIR-OPT-NEXT:    br $outer0
  ;; STACKIR-OPT-NEXT:   end
  ;; STACKIR-OPT-NEXT:   i32.const 2
  ;; STACKIR-OPT-NEXT:  end
  ;; STACKIR-OPT-NEXT: )
  (func $try-single-tag-single (result i32)
    ;; try's type is single and catch's tag type is single
    (try $l0 (result i32)
      (do
        (call $foo)
        (i32.const 0)
      )
      (catch $e-i32
        (pop i32)
      )
      (catch_all
        (i32.const 2)
      )
    )
  )

  ;; CHECK:      (func $try-single-tag-single-with-rethrow (type $2) (result i32)
  ;; CHECK-NEXT:  (local $0 exnref)
  ;; CHECK-NEXT:  (local $1 i32)
  ;; CHECK-NEXT:  (local $2 (tuple i32 (ref exn)))
  ;; CHECK-NEXT:  (block $outer0 (result i32)
  ;; CHECK-NEXT:   (local.set $0
  ;; CHECK-NEXT:    (block $catch_all2 (result (ref exn))
  ;; CHECK-NEXT:     (local.set $2
  ;; CHECK-NEXT:      (block $catch1 (type $3) (result i32 (ref exn))
  ;; CHECK-NEXT:       (br $outer0
  ;; CHECK-NEXT:        (try_table (result i32) (catch_ref $e-i32 $catch1) (catch_all_ref $catch_all2)
  ;; CHECK-NEXT:         (call $foo)
  ;; CHECK-NEXT:         (i32.const 0)
  ;; CHECK-NEXT:        )
  ;; CHECK-NEXT:       )
  ;; CHECK-NEXT:      )
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:     (local.set $1
  ;; CHECK-NEXT:      (tuple.extract 2 0
  ;; CHECK-NEXT:       (local.get $2)
  ;; CHECK-NEXT:      )
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:     (local.set $0
  ;; CHECK-NEXT:      (tuple.extract 2 1
  ;; CHECK-NEXT:       (local.get $2)
  ;; CHECK-NEXT:      )
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:     (br $outer0
  ;; CHECK-NEXT:      (block (result i32)
  ;; CHECK-NEXT:       (drop
  ;; CHECK-NEXT:        (local.get $1)
  ;; CHECK-NEXT:       )
  ;; CHECK-NEXT:       (throw_ref
  ;; CHECK-NEXT:        (local.get $0)
  ;; CHECK-NEXT:       )
  ;; CHECK-NEXT:      )
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:   (throw_ref
  ;; CHECK-NEXT:    (local.get $0)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  ;; STACKIR-OPT:      (func $try-single-tag-single-with-rethrow (type $2) (result i32)
  ;; STACKIR-OPT-NEXT:  (local $0 exnref)
  ;; STACKIR-OPT-NEXT:  (local $1 i32)
  ;; STACKIR-OPT-NEXT:  (local $2 (tuple i32 (ref exn)))
  ;; STACKIR-OPT-NEXT:  block $outer0 (result i32)
  ;; STACKIR-OPT-NEXT:   block $catch_all2 (result (ref exn))
  ;; STACKIR-OPT-NEXT:    block $catch1 (type $3) (result i32 (ref exn))
  ;; STACKIR-OPT-NEXT:     try_table (result i32) (catch_ref $e-i32 $catch1) (catch_all_ref $catch_all2)
  ;; STACKIR-OPT-NEXT:      call $foo
  ;; STACKIR-OPT-NEXT:      i32.const 0
  ;; STACKIR-OPT-NEXT:     end
  ;; STACKIR-OPT-NEXT:     br $outer0
  ;; STACKIR-OPT-NEXT:    end
  ;; STACKIR-OPT-NEXT:    local.set $2
  ;; STACKIR-OPT-NEXT:    local.get $2
  ;; STACKIR-OPT-NEXT:    tuple.extract 2 0
  ;; STACKIR-OPT-NEXT:    local.get $2
  ;; STACKIR-OPT-NEXT:    tuple.extract 2 1
  ;; STACKIR-OPT-NEXT:    local.set $0
  ;; STACKIR-OPT-NEXT:    drop
  ;; STACKIR-OPT-NEXT:    local.get $0
  ;; STACKIR-OPT-NEXT:    throw_ref
  ;; STACKIR-OPT-NEXT:   end
  ;; STACKIR-OPT-NEXT:   throw_ref
  ;; STACKIR-OPT-NEXT:  end
  ;; STACKIR-OPT-NEXT: )
  (func $try-single-tag-single-with-rethrow (result i32)
    ;; try's type is single and catch's tag type is single, and there are
    ;; rethrows
    (try $l0 (result i32)
      (do
        (call $foo)
        (i32.const 0)
      )
      (catch $e-i32
        (drop
          (pop i32)
        )
        (rethrow $l0)
      )
      (catch_all
        (rethrow $l0)
      )
    )
  )

  ;; CHECK:      (func $try-single-tag-tuple (type $2) (result i32)
  ;; CHECK-NEXT:  (local $0 (tuple i32 i64))
  ;; CHECK-NEXT:  (block $outer0 (result i32)
  ;; CHECK-NEXT:   (block $catch_all2
  ;; CHECK-NEXT:    (local.set $0
  ;; CHECK-NEXT:     (block $catch1 (type $0) (result i32 i64)
  ;; CHECK-NEXT:      (br $outer0
  ;; CHECK-NEXT:       (try_table (result i32) (catch $e-i32-i64 $catch1) (catch_all $catch_all2)
  ;; CHECK-NEXT:        (call $foo)
  ;; CHECK-NEXT:        (i32.const 0)
  ;; CHECK-NEXT:       )
  ;; CHECK-NEXT:      )
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (br $outer0
  ;; CHECK-NEXT:     (block (result i32)
  ;; CHECK-NEXT:      (tuple.drop 2
  ;; CHECK-NEXT:       (local.get $0)
  ;; CHECK-NEXT:      )
  ;; CHECK-NEXT:      (i32.const 1)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:   (i32.const 2)
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  ;; STACKIR-OPT:      (func $try-single-tag-tuple (type $2) (result i32)
  ;; STACKIR-OPT-NEXT:  (local $0 (tuple i32 i64))
  ;; STACKIR-OPT-NEXT:  block $outer0 (result i32)
  ;; STACKIR-OPT-NEXT:   block $catch_all2
  ;; STACKIR-OPT-NEXT:    block $catch1 (type $0) (result i32 i64)
  ;; STACKIR-OPT-NEXT:     try_table (result i32) (catch $e-i32-i64 $catch1) (catch_all $catch_all2)
  ;; STACKIR-OPT-NEXT:      call $foo
  ;; STACKIR-OPT-NEXT:      i32.const 0
  ;; STACKIR-OPT-NEXT:     end
  ;; STACKIR-OPT-NEXT:     br $outer0
  ;; STACKIR-OPT-NEXT:    end
  ;; STACKIR-OPT-NEXT:    local.set $0
  ;; STACKIR-OPT-NEXT:    local.get $0
  ;; STACKIR-OPT-NEXT:    tuple.drop 2
  ;; STACKIR-OPT-NEXT:    i32.const 1
  ;; STACKIR-OPT-NEXT:    br $outer0
  ;; STACKIR-OPT-NEXT:   end
  ;; STACKIR-OPT-NEXT:   i32.const 2
  ;; STACKIR-OPT-NEXT:  end
  ;; STACKIR-OPT-NEXT: )
  (func $try-single-tag-tuple (result i32)
    ;; try's type is single and catch's tag type is tuple
    (try $l0 (result i32)
      (do
        (call $foo)
        (i32.const 0)
      )
      (catch $e-i32-i64
        (tuple.drop 2
          (pop (tuple i32 i64))
        )
        (i32.const 1)
      )
      (catch_all
        (i32.const 2)
      )
    )
  )

  ;; CHECK:      (func $try-single-tag-tuple-with-rethrow (type $2) (result i32)
  ;; CHECK-NEXT:  (local $0 exnref)
  ;; CHECK-NEXT:  (local $1 (tuple i32 i64))
  ;; CHECK-NEXT:  (local $2 (tuple i32 i64 (ref exn)))
  ;; CHECK-NEXT:  (block $outer0 (result i32)
  ;; CHECK-NEXT:   (local.set $0
  ;; CHECK-NEXT:    (block $catch_all2 (result (ref exn))
  ;; CHECK-NEXT:     (local.set $2
  ;; CHECK-NEXT:      (block $catch1 (type $4) (result i32 i64 (ref exn))
  ;; CHECK-NEXT:       (br $outer0
  ;; CHECK-NEXT:        (try_table (result i32) (catch_ref $e-i32-i64 $catch1) (catch_all_ref $catch_all2)
  ;; CHECK-NEXT:         (call $foo)
  ;; CHECK-NEXT:         (i32.const 0)
  ;; CHECK-NEXT:        )
  ;; CHECK-NEXT:       )
  ;; CHECK-NEXT:      )
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:     (local.set $1
  ;; CHECK-NEXT:      (tuple.make 2
  ;; CHECK-NEXT:       (tuple.extract 3 0
  ;; CHECK-NEXT:        (local.get $2)
  ;; CHECK-NEXT:       )
  ;; CHECK-NEXT:       (tuple.extract 3 1
  ;; CHECK-NEXT:        (local.get $2)
  ;; CHECK-NEXT:       )
  ;; CHECK-NEXT:      )
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:     (local.set $0
  ;; CHECK-NEXT:      (tuple.extract 3 2
  ;; CHECK-NEXT:       (local.get $2)
  ;; CHECK-NEXT:      )
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:     (br $outer0
  ;; CHECK-NEXT:      (block (result i32)
  ;; CHECK-NEXT:       (tuple.drop 2
  ;; CHECK-NEXT:        (local.get $1)
  ;; CHECK-NEXT:       )
  ;; CHECK-NEXT:       (throw_ref
  ;; CHECK-NEXT:        (local.get $0)
  ;; CHECK-NEXT:       )
  ;; CHECK-NEXT:      )
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:   (throw_ref
  ;; CHECK-NEXT:    (local.get $0)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  ;; STACKIR-OPT:      (func $try-single-tag-tuple-with-rethrow (type $2) (result i32)
  ;; STACKIR-OPT-NEXT:  (local $0 exnref)
  ;; STACKIR-OPT-NEXT:  (local $1 (tuple i32 i64))
  ;; STACKIR-OPT-NEXT:  (local $2 (tuple i32 i64 (ref exn)))
  ;; STACKIR-OPT-NEXT:  block $outer0 (result i32)
  ;; STACKIR-OPT-NEXT:   block $catch_all2 (result (ref exn))
  ;; STACKIR-OPT-NEXT:    block $catch1 (type $4) (result i32 i64 (ref exn))
  ;; STACKIR-OPT-NEXT:     try_table (result i32) (catch_ref $e-i32-i64 $catch1) (catch_all_ref $catch_all2)
  ;; STACKIR-OPT-NEXT:      call $foo
  ;; STACKIR-OPT-NEXT:      i32.const 0
  ;; STACKIR-OPT-NEXT:     end
  ;; STACKIR-OPT-NEXT:     br $outer0
  ;; STACKIR-OPT-NEXT:    end
  ;; STACKIR-OPT-NEXT:    local.set $2
  ;; STACKIR-OPT-NEXT:    local.get $2
  ;; STACKIR-OPT-NEXT:    tuple.extract 3 0
  ;; STACKIR-OPT-NEXT:    local.get $2
  ;; STACKIR-OPT-NEXT:    tuple.extract 3 1
  ;; STACKIR-OPT-NEXT:    tuple.make 2
  ;; STACKIR-OPT-NEXT:    local.set $1
  ;; STACKIR-OPT-NEXT:    local.get $2
  ;; STACKIR-OPT-NEXT:    tuple.extract 3 2
  ;; STACKIR-OPT-NEXT:    local.get $1
  ;; STACKIR-OPT-NEXT:    tuple.drop 2
  ;; STACKIR-OPT-NEXT:    throw_ref
  ;; STACKIR-OPT-NEXT:   end
  ;; STACKIR-OPT-NEXT:   throw_ref
  ;; STACKIR-OPT-NEXT:  end
  ;; STACKIR-OPT-NEXT: )
  (func $try-single-tag-tuple-with-rethrow (result i32)
    ;; try's type is single and catch's tag type is tuple, and there are
    ;; rethrows
    (try $l0 (result i32)
      (do
        (call $foo)
        (i32.const 0)
      )
      (catch $e-i32-i64
        (tuple.drop 2
          (pop (tuple i32 i64))
        )
        (rethrow $l0)
      )
      (catch_all
        (rethrow $l0)
      )
    )
  )

  ;; CHECK:      (func $try-tuple-tag-none (type $0) (result i32 i64)
  ;; CHECK-NEXT:  (block $outer0 (type $0) (result i32 i64)
  ;; CHECK-NEXT:   (block $catch_all2
  ;; CHECK-NEXT:    (block $catch1
  ;; CHECK-NEXT:     (br $outer0
  ;; CHECK-NEXT:      (try_table (type $0) (result i32 i64) (catch $e-empty $catch1) (catch_all $catch_all2)
  ;; CHECK-NEXT:       (call $foo)
  ;; CHECK-NEXT:       (tuple.make 2
  ;; CHECK-NEXT:        (i32.const 0)
  ;; CHECK-NEXT:        (i64.const 0)
  ;; CHECK-NEXT:       )
  ;; CHECK-NEXT:      )
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (br $outer0
  ;; CHECK-NEXT:     (tuple.make 2
  ;; CHECK-NEXT:      (i32.const 1)
  ;; CHECK-NEXT:      (i64.const 1)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:   (tuple.make 2
  ;; CHECK-NEXT:    (i32.const 2)
  ;; CHECK-NEXT:    (i64.const 0)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  ;; STACKIR-OPT:      (func $try-tuple-tag-none (type $0) (result i32 i64)
  ;; STACKIR-OPT-NEXT:  block $outer0 (type $0) (result i32 i64)
  ;; STACKIR-OPT-NEXT:   block $catch_all2
  ;; STACKIR-OPT-NEXT:    block $catch1
  ;; STACKIR-OPT-NEXT:     try_table (type $0) (result i32 i64) (catch $e-empty $catch1) (catch_all $catch_all2)
  ;; STACKIR-OPT-NEXT:      call $foo
  ;; STACKIR-OPT-NEXT:      i32.const 0
  ;; STACKIR-OPT-NEXT:      i64.const 0
  ;; STACKIR-OPT-NEXT:      tuple.make 2
  ;; STACKIR-OPT-NEXT:     end
  ;; STACKIR-OPT-NEXT:     br $outer0
  ;; STACKIR-OPT-NEXT:    end
  ;; STACKIR-OPT-NEXT:    i32.const 1
  ;; STACKIR-OPT-NEXT:    i64.const 1
  ;; STACKIR-OPT-NEXT:    tuple.make 2
  ;; STACKIR-OPT-NEXT:    br $outer0
  ;; STACKIR-OPT-NEXT:   end
  ;; STACKIR-OPT-NEXT:   i32.const 2
  ;; STACKIR-OPT-NEXT:   i64.const 0
  ;; STACKIR-OPT-NEXT:   tuple.make 2
  ;; STACKIR-OPT-NEXT:  end
  ;; STACKIR-OPT-NEXT: )
  (func $try-tuple-tag-none (result i32 i64)
    ;; try's type is tuple and catch's tag type is none
    (try $l0 (result i32 i64)
      (do
        (call $foo)
        (tuple.make 2
          (i32.const 0)
          (i64.const 0)
        )
      )
      (catch $e-empty
        (tuple.make 2
          (i32.const 1)
          (i64.const 1)
        )
      )
      (catch_all
        (tuple.make 2
          (i32.const 2)
          (i64.const 0)
        )
      )
    )
  )

  ;; CHECK:      (func $try-tuple-tag-none-with-rethrow (type $0) (result i32 i64)
  ;; CHECK-NEXT:  (local $0 exnref)
  ;; CHECK-NEXT:  (block $outer0 (type $0) (result i32 i64)
  ;; CHECK-NEXT:   (local.set $0
  ;; CHECK-NEXT:    (block $catch_all2 (result (ref exn))
  ;; CHECK-NEXT:     (local.set $0
  ;; CHECK-NEXT:      (block $catch1 (result (ref exn))
  ;; CHECK-NEXT:       (br $outer0
  ;; CHECK-NEXT:        (try_table (type $0) (result i32 i64) (catch_ref $e-empty $catch1) (catch_all_ref $catch_all2)
  ;; CHECK-NEXT:         (call $foo)
  ;; CHECK-NEXT:         (tuple.make 2
  ;; CHECK-NEXT:          (i32.const 0)
  ;; CHECK-NEXT:          (i64.const 0)
  ;; CHECK-NEXT:         )
  ;; CHECK-NEXT:        )
  ;; CHECK-NEXT:       )
  ;; CHECK-NEXT:      )
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:     (throw_ref
  ;; CHECK-NEXT:      (local.get $0)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:   (throw_ref
  ;; CHECK-NEXT:    (local.get $0)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  ;; STACKIR-OPT:      (func $try-tuple-tag-none-with-rethrow (type $0) (result i32 i64)
  ;; STACKIR-OPT-NEXT:  (local $0 exnref)
  ;; STACKIR-OPT-NEXT:  block $outer0 (type $0) (result i32 i64)
  ;; STACKIR-OPT-NEXT:   block $catch_all2 (result (ref exn))
  ;; STACKIR-OPT-NEXT:    block $catch1 (result (ref exn))
  ;; STACKIR-OPT-NEXT:     try_table (type $0) (result i32 i64) (catch_ref $e-empty $catch1) (catch_all_ref $catch_all2)
  ;; STACKIR-OPT-NEXT:      call $foo
  ;; STACKIR-OPT-NEXT:      i32.const 0
  ;; STACKIR-OPT-NEXT:      i64.const 0
  ;; STACKIR-OPT-NEXT:      tuple.make 2
  ;; STACKIR-OPT-NEXT:     end
  ;; STACKIR-OPT-NEXT:     br $outer0
  ;; STACKIR-OPT-NEXT:    end
  ;; STACKIR-OPT-NEXT:    throw_ref
  ;; STACKIR-OPT-NEXT:   end
  ;; STACKIR-OPT-NEXT:   throw_ref
  ;; STACKIR-OPT-NEXT:  end
  ;; STACKIR-OPT-NEXT: )
  (func $try-tuple-tag-none-with-rethrow (result i32 i64)
    ;; try's type is tuple and catch's tag type is none, and there are rethrows
    (try $l0 (result i32 i64)
      (do
        (call $foo)
        (tuple.make 2
          (i32.const 0)
          (i64.const 0)
        )
      )
      (catch $e-empty
        (rethrow $l0)
      )
      (catch_all
        (rethrow $l0)
      )
    )
  )

  ;; CHECK:      (func $try-tuple-tag-single (type $0) (result i32 i64)
  ;; CHECK-NEXT:  (local $0 i32)
  ;; CHECK-NEXT:  (block $outer0 (type $0) (result i32 i64)
  ;; CHECK-NEXT:   (block $catch_all2
  ;; CHECK-NEXT:    (local.set $0
  ;; CHECK-NEXT:     (block $catch1 (result i32)
  ;; CHECK-NEXT:      (br $outer0
  ;; CHECK-NEXT:       (try_table (type $0) (result i32 i64) (catch $e-i32 $catch1) (catch_all $catch_all2)
  ;; CHECK-NEXT:        (call $foo)
  ;; CHECK-NEXT:        (tuple.make 2
  ;; CHECK-NEXT:         (i32.const 0)
  ;; CHECK-NEXT:         (i64.const 0)
  ;; CHECK-NEXT:        )
  ;; CHECK-NEXT:       )
  ;; CHECK-NEXT:      )
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (br $outer0
  ;; CHECK-NEXT:     (tuple.make 2
  ;; CHECK-NEXT:      (local.get $0)
  ;; CHECK-NEXT:      (i64.const 0)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:   (tuple.make 2
  ;; CHECK-NEXT:    (i32.const 2)
  ;; CHECK-NEXT:    (i64.const 2)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  ;; STACKIR-OPT:      (func $try-tuple-tag-single (type $0) (result i32 i64)
  ;; STACKIR-OPT-NEXT:  (local $0 i32)
  ;; STACKIR-OPT-NEXT:  block $outer0 (type $0) (result i32 i64)
  ;; STACKIR-OPT-NEXT:   block $catch_all2
  ;; STACKIR-OPT-NEXT:    block $catch1 (result i32)
  ;; STACKIR-OPT-NEXT:     try_table (type $0) (result i32 i64) (catch $e-i32 $catch1) (catch_all $catch_all2)
  ;; STACKIR-OPT-NEXT:      call $foo
  ;; STACKIR-OPT-NEXT:      i32.const 0
  ;; STACKIR-OPT-NEXT:      i64.const 0
  ;; STACKIR-OPT-NEXT:      tuple.make 2
  ;; STACKIR-OPT-NEXT:     end
  ;; STACKIR-OPT-NEXT:     br $outer0
  ;; STACKIR-OPT-NEXT:    end
  ;; STACKIR-OPT-NEXT:    i64.const 0
  ;; STACKIR-OPT-NEXT:    tuple.make 2
  ;; STACKIR-OPT-NEXT:    br $outer0
  ;; STACKIR-OPT-NEXT:   end
  ;; STACKIR-OPT-NEXT:   i32.const 2
  ;; STACKIR-OPT-NEXT:   i64.const 2
  ;; STACKIR-OPT-NEXT:   tuple.make 2
  ;; STACKIR-OPT-NEXT:  end
  ;; STACKIR-OPT-NEXT: )
  (func $try-tuple-tag-single (result i32 i64)
    ;; try's type is tuple and catch's tag type is single
    (try $l0 (result i32 i64)
      (do
        (call $foo)
        (tuple.make 2
          (i32.const 0)
          (i64.const 0)
        )
      )
      (catch $e-i32
        (tuple.make 2
          (pop i32)
          (i64.const 0)
        )
      )
      (catch_all
        (tuple.make 2
          (i32.const 2)
          (i64.const 2)
        )
      )
    )
  )

  ;; CHECK:      (func $try-tuple-tag-single-with-rethrow (type $0) (result i32 i64)
  ;; CHECK-NEXT:  (local $0 exnref)
  ;; CHECK-NEXT:  (local $1 i32)
  ;; CHECK-NEXT:  (local $2 (tuple i32 (ref exn)))
  ;; CHECK-NEXT:  (block $outer0 (type $0) (result i32 i64)
  ;; CHECK-NEXT:   (local.set $0
  ;; CHECK-NEXT:    (block $catch_all2 (result (ref exn))
  ;; CHECK-NEXT:     (local.set $2
  ;; CHECK-NEXT:      (block $catch1 (type $3) (result i32 (ref exn))
  ;; CHECK-NEXT:       (br $outer0
  ;; CHECK-NEXT:        (try_table (type $0) (result i32 i64) (catch_ref $e-i32 $catch1) (catch_all_ref $catch_all2)
  ;; CHECK-NEXT:         (call $foo)
  ;; CHECK-NEXT:         (tuple.make 2
  ;; CHECK-NEXT:          (i32.const 0)
  ;; CHECK-NEXT:          (i64.const 0)
  ;; CHECK-NEXT:         )
  ;; CHECK-NEXT:        )
  ;; CHECK-NEXT:       )
  ;; CHECK-NEXT:      )
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:     (local.set $1
  ;; CHECK-NEXT:      (tuple.extract 2 0
  ;; CHECK-NEXT:       (local.get $2)
  ;; CHECK-NEXT:      )
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:     (local.set $0
  ;; CHECK-NEXT:      (tuple.extract 2 1
  ;; CHECK-NEXT:       (local.get $2)
  ;; CHECK-NEXT:      )
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:     (br $outer0
  ;; CHECK-NEXT:      (block (type $0) (result i32 i64)
  ;; CHECK-NEXT:       (drop
  ;; CHECK-NEXT:        (local.get $1)
  ;; CHECK-NEXT:       )
  ;; CHECK-NEXT:       (throw_ref
  ;; CHECK-NEXT:        (local.get $0)
  ;; CHECK-NEXT:       )
  ;; CHECK-NEXT:      )
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:   (throw_ref
  ;; CHECK-NEXT:    (local.get $0)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  ;; STACKIR-OPT:      (func $try-tuple-tag-single-with-rethrow (type $0) (result i32 i64)
  ;; STACKIR-OPT-NEXT:  (local $0 exnref)
  ;; STACKIR-OPT-NEXT:  (local $1 i32)
  ;; STACKIR-OPT-NEXT:  (local $2 (tuple i32 (ref exn)))
  ;; STACKIR-OPT-NEXT:  block $outer0 (type $0) (result i32 i64)
  ;; STACKIR-OPT-NEXT:   block $catch_all2 (result (ref exn))
  ;; STACKIR-OPT-NEXT:    block $catch1 (type $3) (result i32 (ref exn))
  ;; STACKIR-OPT-NEXT:     try_table (type $0) (result i32 i64) (catch_ref $e-i32 $catch1) (catch_all_ref $catch_all2)
  ;; STACKIR-OPT-NEXT:      call $foo
  ;; STACKIR-OPT-NEXT:      i32.const 0
  ;; STACKIR-OPT-NEXT:      i64.const 0
  ;; STACKIR-OPT-NEXT:      tuple.make 2
  ;; STACKIR-OPT-NEXT:     end
  ;; STACKIR-OPT-NEXT:     br $outer0
  ;; STACKIR-OPT-NEXT:    end
  ;; STACKIR-OPT-NEXT:    local.set $2
  ;; STACKIR-OPT-NEXT:    local.get $2
  ;; STACKIR-OPT-NEXT:    tuple.extract 2 0
  ;; STACKIR-OPT-NEXT:    local.get $2
  ;; STACKIR-OPT-NEXT:    tuple.extract 2 1
  ;; STACKIR-OPT-NEXT:    local.set $0
  ;; STACKIR-OPT-NEXT:    drop
  ;; STACKIR-OPT-NEXT:    local.get $0
  ;; STACKIR-OPT-NEXT:    throw_ref
  ;; STACKIR-OPT-NEXT:   end
  ;; STACKIR-OPT-NEXT:   throw_ref
  ;; STACKIR-OPT-NEXT:  end
  ;; STACKIR-OPT-NEXT: )
  (func $try-tuple-tag-single-with-rethrow (result i32 i64)
    ;; try's type is tuple and catch's tag type is single, and there are
    ;; rethrows
    (try $l0 (result i32 i64)
      (do
        (call $foo)
        (tuple.make 2
          (i32.const 0)
          (i64.const 0)
        )
      )
      (catch $e-i32
        (drop
          (pop i32)
        )
        (rethrow $l0)
      )
      (catch_all
        (rethrow $l0)
      )
    )
  )

  ;; CHECK:      (func $try-tuple-tag-tuple (type $0) (result i32 i64)
  ;; CHECK-NEXT:  (local $0 (tuple i32 i64))
  ;; CHECK-NEXT:  (block $outer0 (type $0) (result i32 i64)
  ;; CHECK-NEXT:   (block $catch_all2
  ;; CHECK-NEXT:    (local.set $0
  ;; CHECK-NEXT:     (block $catch1 (type $0) (result i32 i64)
  ;; CHECK-NEXT:      (br $outer0
  ;; CHECK-NEXT:       (try_table (type $0) (result i32 i64) (catch $e-i32-i64 $catch1) (catch_all $catch_all2)
  ;; CHECK-NEXT:        (call $foo)
  ;; CHECK-NEXT:        (tuple.make 2
  ;; CHECK-NEXT:         (i32.const 0)
  ;; CHECK-NEXT:         (i64.const 0)
  ;; CHECK-NEXT:        )
  ;; CHECK-NEXT:       )
  ;; CHECK-NEXT:      )
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (br $outer0
  ;; CHECK-NEXT:     (local.get $0)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:   (tuple.make 2
  ;; CHECK-NEXT:    (i32.const 2)
  ;; CHECK-NEXT:    (i64.const 2)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  ;; STACKIR-OPT:      (func $try-tuple-tag-tuple (type $0) (result i32 i64)
  ;; STACKIR-OPT-NEXT:  (local $0 (tuple i32 i64))
  ;; STACKIR-OPT-NEXT:  block $outer0 (type $0) (result i32 i64)
  ;; STACKIR-OPT-NEXT:   block $catch_all2
  ;; STACKIR-OPT-NEXT:    block $catch1 (type $0) (result i32 i64)
  ;; STACKIR-OPT-NEXT:     try_table (type $0) (result i32 i64) (catch $e-i32-i64 $catch1) (catch_all $catch_all2)
  ;; STACKIR-OPT-NEXT:      call $foo
  ;; STACKIR-OPT-NEXT:      i32.const 0
  ;; STACKIR-OPT-NEXT:      i64.const 0
  ;; STACKIR-OPT-NEXT:      tuple.make 2
  ;; STACKIR-OPT-NEXT:     end
  ;; STACKIR-OPT-NEXT:     br $outer0
  ;; STACKIR-OPT-NEXT:    end
  ;; STACKIR-OPT-NEXT:    local.set $0
  ;; STACKIR-OPT-NEXT:    local.get $0
  ;; STACKIR-OPT-NEXT:    br $outer0
  ;; STACKIR-OPT-NEXT:   end
  ;; STACKIR-OPT-NEXT:   i32.const 2
  ;; STACKIR-OPT-NEXT:   i64.const 2
  ;; STACKIR-OPT-NEXT:   tuple.make 2
  ;; STACKIR-OPT-NEXT:  end
  ;; STACKIR-OPT-NEXT: )
  (func $try-tuple-tag-tuple (result i32 i64)
    ;; try's type is tuple and catch's tag type is tuple
    (try $l0 (result i32 i64)
      (do
        (call $foo)
        (tuple.make 2
          (i32.const 0)
          (i64.const 0)
        )
      )
      (catch $e-i32-i64
        (pop (tuple i32 i64))
      )
      (catch_all
        (tuple.make 2
          (i32.const 2)
          (i64.const 2)
        )
      )
    )
  )

  ;; CHECK:      (func $try-tuple-tag-tuple-with-rethrow (type $0) (result i32 i64)
  ;; CHECK-NEXT:  (local $0 exnref)
  ;; CHECK-NEXT:  (local $1 (tuple i32 i64))
  ;; CHECK-NEXT:  (local $2 (tuple i32 i64 (ref exn)))
  ;; CHECK-NEXT:  (block $outer0 (type $0) (result i32 i64)
  ;; CHECK-NEXT:   (local.set $0
  ;; CHECK-NEXT:    (block $catch_all2 (result (ref exn))
  ;; CHECK-NEXT:     (local.set $2
  ;; CHECK-NEXT:      (block $catch1 (type $4) (result i32 i64 (ref exn))
  ;; CHECK-NEXT:       (br $outer0
  ;; CHECK-NEXT:        (try_table (type $0) (result i32 i64) (catch_ref $e-i32-i64 $catch1) (catch_all_ref $catch_all2)
  ;; CHECK-NEXT:         (call $foo)
  ;; CHECK-NEXT:         (tuple.make 2
  ;; CHECK-NEXT:          (i32.const 0)
  ;; CHECK-NEXT:          (i64.const 0)
  ;; CHECK-NEXT:         )
  ;; CHECK-NEXT:        )
  ;; CHECK-NEXT:       )
  ;; CHECK-NEXT:      )
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:     (local.set $1
  ;; CHECK-NEXT:      (tuple.make 2
  ;; CHECK-NEXT:       (tuple.extract 3 0
  ;; CHECK-NEXT:        (local.get $2)
  ;; CHECK-NEXT:       )
  ;; CHECK-NEXT:       (tuple.extract 3 1
  ;; CHECK-NEXT:        (local.get $2)
  ;; CHECK-NEXT:       )
  ;; CHECK-NEXT:      )
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:     (local.set $0
  ;; CHECK-NEXT:      (tuple.extract 3 2
  ;; CHECK-NEXT:       (local.get $2)
  ;; CHECK-NEXT:      )
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:     (br $outer0
  ;; CHECK-NEXT:      (block (type $0) (result i32 i64)
  ;; CHECK-NEXT:       (tuple.drop 2
  ;; CHECK-NEXT:        (local.get $1)
  ;; CHECK-NEXT:       )
  ;; CHECK-NEXT:       (throw_ref
  ;; CHECK-NEXT:        (local.get $0)
  ;; CHECK-NEXT:       )
  ;; CHECK-NEXT:      )
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:   (throw_ref
  ;; CHECK-NEXT:    (local.get $0)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  ;; STACKIR-OPT:      (func $try-tuple-tag-tuple-with-rethrow (type $0) (result i32 i64)
  ;; STACKIR-OPT-NEXT:  (local $0 exnref)
  ;; STACKIR-OPT-NEXT:  (local $1 (tuple i32 i64))
  ;; STACKIR-OPT-NEXT:  (local $2 (tuple i32 i64 (ref exn)))
  ;; STACKIR-OPT-NEXT:  block $outer0 (type $0) (result i32 i64)
  ;; STACKIR-OPT-NEXT:   block $catch_all2 (result (ref exn))
  ;; STACKIR-OPT-NEXT:    block $catch1 (type $4) (result i32 i64 (ref exn))
  ;; STACKIR-OPT-NEXT:     try_table (type $0) (result i32 i64) (catch_ref $e-i32-i64 $catch1) (catch_all_ref $catch_all2)
  ;; STACKIR-OPT-NEXT:      call $foo
  ;; STACKIR-OPT-NEXT:      i32.const 0
  ;; STACKIR-OPT-NEXT:      i64.const 0
  ;; STACKIR-OPT-NEXT:      tuple.make 2
  ;; STACKIR-OPT-NEXT:     end
  ;; STACKIR-OPT-NEXT:     br $outer0
  ;; STACKIR-OPT-NEXT:    end
  ;; STACKIR-OPT-NEXT:    local.set $2
  ;; STACKIR-OPT-NEXT:    local.get $2
  ;; STACKIR-OPT-NEXT:    tuple.extract 3 0
  ;; STACKIR-OPT-NEXT:    local.get $2
  ;; STACKIR-OPT-NEXT:    tuple.extract 3 1
  ;; STACKIR-OPT-NEXT:    tuple.make 2
  ;; STACKIR-OPT-NEXT:    local.set $1
  ;; STACKIR-OPT-NEXT:    local.get $2
  ;; STACKIR-OPT-NEXT:    tuple.extract 3 2
  ;; STACKIR-OPT-NEXT:    local.get $1
  ;; STACKIR-OPT-NEXT:    tuple.drop 2
  ;; STACKIR-OPT-NEXT:    throw_ref
  ;; STACKIR-OPT-NEXT:   end
  ;; STACKIR-OPT-NEXT:   throw_ref
  ;; STACKIR-OPT-NEXT:  end
  ;; STACKIR-OPT-NEXT: )
  (func $try-tuple-tag-tuple-with-rethrow (result i32 i64)
    ;; try's type is tuple and catch's tag type is tuple, and there are
    ;; rethrows
    (try $l0 (result i32 i64)
      (do
        (call $foo)
        (tuple.make 2
          (i32.const 0)
          (i64.const 0)
        )
      )
      (catch $e-i32-i64
        (tuple.drop 2
          (pop (tuple i32 i64))
        )
        (rethrow $l0)
      )
      (catch_all
        (rethrow $l0)
      )
    )
  )

  ;; ---------------------------------------------------------------------------
  ;; More try-catch tests

  ;; CHECK:      (func $catchless-delegateless-try (type $1)
  ;; CHECK-NEXT:  (try_table
  ;; CHECK-NEXT:   (call $foo)
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  ;; STACKIR-OPT:      (func $catchless-delegateless-try (type $1)
  ;; STACKIR-OPT-NEXT:  try_table
  ;; STACKIR-OPT-NEXT:   call $foo
  ;; STACKIR-OPT-NEXT:  end
  ;; STACKIR-OPT-NEXT: )
  (func $catchless-delegateless-try
    (try
      (do
        (call $foo)
      )
    )
  )

  ;; CHECK:      (func $multiple-catches-and-catch_all (type $1)
  ;; CHECK-NEXT:  (local $0 exnref)
  ;; CHECK-NEXT:  (local $1 i32)
  ;; CHECK-NEXT:  (local $2 (tuple i32 i64))
  ;; CHECK-NEXT:  (local $3 (tuple i32 (ref exn)))
  ;; CHECK-NEXT:  (local $4 (tuple i32 i64 (ref exn)))
  ;; CHECK-NEXT:  (block $outer0
  ;; CHECK-NEXT:   (local.set $0
  ;; CHECK-NEXT:    (block $catch_all4 (result (ref exn))
  ;; CHECK-NEXT:     (local.set $4
  ;; CHECK-NEXT:      (block $catch3 (type $4) (result i32 i64 (ref exn))
  ;; CHECK-NEXT:       (local.set $3
  ;; CHECK-NEXT:        (block $catch2 (type $3) (result i32 (ref exn))
  ;; CHECK-NEXT:         (local.set $0
  ;; CHECK-NEXT:          (block $catch1 (result (ref exn))
  ;; CHECK-NEXT:           (try_table (catch_ref $e-empty $catch1) (catch_ref $e-i32 $catch2) (catch_ref $e-i32-i64 $catch3) (catch_all_ref $catch_all4)
  ;; CHECK-NEXT:            (call $foo)
  ;; CHECK-NEXT:           )
  ;; CHECK-NEXT:           (br $outer0)
  ;; CHECK-NEXT:          )
  ;; CHECK-NEXT:         )
  ;; CHECK-NEXT:         (throw_ref
  ;; CHECK-NEXT:          (local.get $0)
  ;; CHECK-NEXT:         )
  ;; CHECK-NEXT:        )
  ;; CHECK-NEXT:       )
  ;; CHECK-NEXT:       (local.set $1
  ;; CHECK-NEXT:        (tuple.extract 2 0
  ;; CHECK-NEXT:         (local.get $3)
  ;; CHECK-NEXT:        )
  ;; CHECK-NEXT:       )
  ;; CHECK-NEXT:       (local.set $0
  ;; CHECK-NEXT:        (tuple.extract 2 1
  ;; CHECK-NEXT:         (local.get $3)
  ;; CHECK-NEXT:        )
  ;; CHECK-NEXT:       )
  ;; CHECK-NEXT:       (block
  ;; CHECK-NEXT:        (drop
  ;; CHECK-NEXT:         (local.get $1)
  ;; CHECK-NEXT:        )
  ;; CHECK-NEXT:        (throw_ref
  ;; CHECK-NEXT:         (local.get $0)
  ;; CHECK-NEXT:        )
  ;; CHECK-NEXT:       )
  ;; CHECK-NEXT:      )
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:     (local.set $2
  ;; CHECK-NEXT:      (tuple.make 2
  ;; CHECK-NEXT:       (tuple.extract 3 0
  ;; CHECK-NEXT:        (local.get $4)
  ;; CHECK-NEXT:       )
  ;; CHECK-NEXT:       (tuple.extract 3 1
  ;; CHECK-NEXT:        (local.get $4)
  ;; CHECK-NEXT:       )
  ;; CHECK-NEXT:      )
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:     (local.set $0
  ;; CHECK-NEXT:      (tuple.extract 3 2
  ;; CHECK-NEXT:       (local.get $4)
  ;; CHECK-NEXT:      )
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:     (block
  ;; CHECK-NEXT:      (tuple.drop 2
  ;; CHECK-NEXT:       (local.get $2)
  ;; CHECK-NEXT:      )
  ;; CHECK-NEXT:      (throw_ref
  ;; CHECK-NEXT:       (local.get $0)
  ;; CHECK-NEXT:      )
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:   (throw_ref
  ;; CHECK-NEXT:    (local.get $0)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  ;; STACKIR-OPT:      (func $multiple-catches-and-catch_all (type $1)
  ;; STACKIR-OPT-NEXT:  (local $0 exnref)
  ;; STACKIR-OPT-NEXT:  (local $1 i32)
  ;; STACKIR-OPT-NEXT:  (local $2 (tuple i32 i64))
  ;; STACKIR-OPT-NEXT:  (local $3 (tuple i32 (ref exn)))
  ;; STACKIR-OPT-NEXT:  (local $4 (tuple i32 i64 (ref exn)))
  ;; STACKIR-OPT-NEXT:  block $outer0
  ;; STACKIR-OPT-NEXT:   block $catch_all4 (result (ref exn))
  ;; STACKIR-OPT-NEXT:    block $catch3 (type $4) (result i32 i64 (ref exn))
  ;; STACKIR-OPT-NEXT:     block $catch2 (type $3) (result i32 (ref exn))
  ;; STACKIR-OPT-NEXT:      block $catch1 (result (ref exn))
  ;; STACKIR-OPT-NEXT:       try_table (catch_ref $e-empty $catch1) (catch_ref $e-i32 $catch2) (catch_ref $e-i32-i64 $catch3) (catch_all_ref $catch_all4)
  ;; STACKIR-OPT-NEXT:        call $foo
  ;; STACKIR-OPT-NEXT:       end
  ;; STACKIR-OPT-NEXT:       br $outer0
  ;; STACKIR-OPT-NEXT:      end
  ;; STACKIR-OPT-NEXT:      throw_ref
  ;; STACKIR-OPT-NEXT:     end
  ;; STACKIR-OPT-NEXT:     local.set $3
  ;; STACKIR-OPT-NEXT:     local.get $3
  ;; STACKIR-OPT-NEXT:     tuple.extract 2 0
  ;; STACKIR-OPT-NEXT:     local.get $3
  ;; STACKIR-OPT-NEXT:     tuple.extract 2 1
  ;; STACKIR-OPT-NEXT:     local.set $0
  ;; STACKIR-OPT-NEXT:     drop
  ;; STACKIR-OPT-NEXT:     local.get $0
  ;; STACKIR-OPT-NEXT:     throw_ref
  ;; STACKIR-OPT-NEXT:    end
  ;; STACKIR-OPT-NEXT:    local.set $4
  ;; STACKIR-OPT-NEXT:    local.get $4
  ;; STACKIR-OPT-NEXT:    tuple.extract 3 0
  ;; STACKIR-OPT-NEXT:    local.get $4
  ;; STACKIR-OPT-NEXT:    tuple.extract 3 1
  ;; STACKIR-OPT-NEXT:    tuple.make 2
  ;; STACKIR-OPT-NEXT:    local.set $2
  ;; STACKIR-OPT-NEXT:    local.get $4
  ;; STACKIR-OPT-NEXT:    tuple.extract 3 2
  ;; STACKIR-OPT-NEXT:    local.get $2
  ;; STACKIR-OPT-NEXT:    tuple.drop 2
  ;; STACKIR-OPT-NEXT:    throw_ref
  ;; STACKIR-OPT-NEXT:   end
  ;; STACKIR-OPT-NEXT:   throw_ref
  ;; STACKIR-OPT-NEXT:  end
  ;; STACKIR-OPT-NEXT: )
  (func $multiple-catches-and-catch_all
    (try $l0
      (do
        (call $foo)
      )
      (catch $e-empty
        (rethrow $l0)
      )
      (catch $e-i32
        (drop
          (pop i32)
        )
        (rethrow $l0)
      )
      (catch $e-i32-i64
        (tuple.drop 2
          (pop (tuple i32 i64))
        )
        (rethrow $l0)
      )
      (catch_all
        (rethrow $l0)
      )
    )
  )

  ;; CHECK:      (func $nested-catch-rethrows (type $1)
  ;; CHECK-NEXT:  (local $0 exnref)
  ;; CHECK-NEXT:  (local $1 exnref)
  ;; CHECK-NEXT:  (block $outer3
  ;; CHECK-NEXT:   (local.set $0
  ;; CHECK-NEXT:    (block $catch_all4 (result (ref exn))
  ;; CHECK-NEXT:     (try_table (catch_all_ref $catch_all4)
  ;; CHECK-NEXT:      (call $foo)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:     (br $outer3)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:   (block $outer0
  ;; CHECK-NEXT:    (local.set $1
  ;; CHECK-NEXT:     (block $catch2 (result (ref exn))
  ;; CHECK-NEXT:      (block $catch1
  ;; CHECK-NEXT:       (try_table (catch $e-empty $catch1) (catch_ref $e-empty $catch2)
  ;; CHECK-NEXT:        (call $foo)
  ;; CHECK-NEXT:       )
  ;; CHECK-NEXT:       (br $outer0)
  ;; CHECK-NEXT:      )
  ;; CHECK-NEXT:      (throw_ref
  ;; CHECK-NEXT:       (local.get $0)
  ;; CHECK-NEXT:      )
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (throw_ref
  ;; CHECK-NEXT:     (local.get $1)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  ;; STACKIR-OPT:      (func $nested-catch-rethrows (type $1)
  ;; STACKIR-OPT-NEXT:  (local $0 exnref)
  ;; STACKIR-OPT-NEXT:  (local $1 exnref)
  ;; STACKIR-OPT-NEXT:  block $outer3
  ;; STACKIR-OPT-NEXT:   block $catch_all4 (result (ref exn))
  ;; STACKIR-OPT-NEXT:    try_table (catch_all_ref $catch_all4)
  ;; STACKIR-OPT-NEXT:     call $foo
  ;; STACKIR-OPT-NEXT:    end
  ;; STACKIR-OPT-NEXT:    br $outer3
  ;; STACKIR-OPT-NEXT:   end
  ;; STACKIR-OPT-NEXT:   local.set $0
  ;; STACKIR-OPT-NEXT:   block $outer0
  ;; STACKIR-OPT-NEXT:    block $catch2 (result (ref exn))
  ;; STACKIR-OPT-NEXT:     block $catch1
  ;; STACKIR-OPT-NEXT:      try_table (catch $e-empty $catch1) (catch_ref $e-empty $catch2)
  ;; STACKIR-OPT-NEXT:       call $foo
  ;; STACKIR-OPT-NEXT:      end
  ;; STACKIR-OPT-NEXT:      br $outer0
  ;; STACKIR-OPT-NEXT:     end
  ;; STACKIR-OPT-NEXT:     local.get $0
  ;; STACKIR-OPT-NEXT:     throw_ref
  ;; STACKIR-OPT-NEXT:    end
  ;; STACKIR-OPT-NEXT:    throw_ref
  ;; STACKIR-OPT-NEXT:   end
  ;; STACKIR-OPT-NEXT:  end
  ;; STACKIR-OPT-NEXT: )
  (func $nested-catch-rethrows
    (try $l0
      (do
        (call $foo)
      )
      (catch_all
        (try $l1
          (do
            (call $foo)
          )
          ;; This catch will be converted to a 'catch' clause in a try_table,
          ;; because the rethrow in this catch body does not refer to the
          ;; current try
          (catch $e-empty
            (rethrow $l0)
          )
          ;; This catch will be converted to a 'catch_ref' clause in a
          ;; try_table, because the rethrow in this catch body refers to the
          ;; current try
          (catch $e-empty
            (rethrow $l1)
          )
        )
      )
    )
  )

  ;; ---------------------------------------------------------------------------
  ;; try-delegate tests

  ;; CHECK:      (func $delegate-target-outer-try-none (type $1)
  ;; CHECK-NEXT:  (block $outer1
  ;; CHECK-NEXT:   (block $catch_all2
  ;; CHECK-NEXT:    (try_table (catch_all $catch_all2)
  ;; CHECK-NEXT:     (throw_ref
  ;; CHECK-NEXT:      (block $l00 (result exnref)
  ;; CHECK-NEXT:       (call $foo)
  ;; CHECK-NEXT:       (try_table (catch_all_ref $l00)
  ;; CHECK-NEXT:        (call $bar)
  ;; CHECK-NEXT:       )
  ;; CHECK-NEXT:       (call $baz)
  ;; CHECK-NEXT:       (br $outer1)
  ;; CHECK-NEXT:      )
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:   (block
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  ;; STACKIR-OPT:      (func $delegate-target-outer-try-none (type $1)
  ;; STACKIR-OPT-NEXT:  block $outer1
  ;; STACKIR-OPT-NEXT:   block $catch_all2
  ;; STACKIR-OPT-NEXT:    try_table (catch_all $catch_all2)
  ;; STACKIR-OPT-NEXT:     block $l00 (result exnref)
  ;; STACKIR-OPT-NEXT:      call $foo
  ;; STACKIR-OPT-NEXT:      try_table (catch_all_ref $l00)
  ;; STACKIR-OPT-NEXT:       call $bar
  ;; STACKIR-OPT-NEXT:      end
  ;; STACKIR-OPT-NEXT:      call $baz
  ;; STACKIR-OPT-NEXT:      br $outer1
  ;; STACKIR-OPT-NEXT:     end
  ;; STACKIR-OPT-NEXT:     throw_ref
  ;; STACKIR-OPT-NEXT:    end
  ;; STACKIR-OPT-NEXT:    unreachable
  ;; STACKIR-OPT-NEXT:   end
  ;; STACKIR-OPT-NEXT:  end
  ;; STACKIR-OPT-NEXT: )
  (func $delegate-target-outer-try-none
    ;; An inner try-delegate targets an outer try whose type is none
    (try $l0
      (do
        (call $foo)
        (try
          (do
            (call $bar)
          )
          (delegate $l0)
        )
        (call $baz)
      )
      (catch_all)
    )
  )

  ;; CHECK:      (func $multiple-delegates-target-outer-try-none (type $1)
  ;; CHECK-NEXT:  (block $outer1
  ;; CHECK-NEXT:   (block $catch_all2
  ;; CHECK-NEXT:    (try_table (catch_all $catch_all2)
  ;; CHECK-NEXT:     (throw_ref
  ;; CHECK-NEXT:      (block $l00 (result exnref)
  ;; CHECK-NEXT:       (call $foo)
  ;; CHECK-NEXT:       (try_table (catch_all_ref $l00)
  ;; CHECK-NEXT:        (call $bar)
  ;; CHECK-NEXT:       )
  ;; CHECK-NEXT:       (try_table (catch_all_ref $l00)
  ;; CHECK-NEXT:        (call $bar)
  ;; CHECK-NEXT:       )
  ;; CHECK-NEXT:       (call $baz)
  ;; CHECK-NEXT:       (br $outer1)
  ;; CHECK-NEXT:      )
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:   (block
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  ;; STACKIR-OPT:      (func $multiple-delegates-target-outer-try-none (type $1)
  ;; STACKIR-OPT-NEXT:  block $outer1
  ;; STACKIR-OPT-NEXT:   block $catch_all2
  ;; STACKIR-OPT-NEXT:    try_table (catch_all $catch_all2)
  ;; STACKIR-OPT-NEXT:     block $l00 (result exnref)
  ;; STACKIR-OPT-NEXT:      call $foo
  ;; STACKIR-OPT-NEXT:      try_table (catch_all_ref $l00)
  ;; STACKIR-OPT-NEXT:       call $bar
  ;; STACKIR-OPT-NEXT:      end
  ;; STACKIR-OPT-NEXT:      try_table (catch_all_ref $l00)
  ;; STACKIR-OPT-NEXT:       call $bar
  ;; STACKIR-OPT-NEXT:      end
  ;; STACKIR-OPT-NEXT:      call $baz
  ;; STACKIR-OPT-NEXT:      br $outer1
  ;; STACKIR-OPT-NEXT:     end
  ;; STACKIR-OPT-NEXT:     throw_ref
  ;; STACKIR-OPT-NEXT:    end
  ;; STACKIR-OPT-NEXT:    unreachable
  ;; STACKIR-OPT-NEXT:   end
  ;; STACKIR-OPT-NEXT:  end
  ;; STACKIR-OPT-NEXT: )
  (func $multiple-delegates-target-outer-try-none
    ;; Multiple inner try-delegates target an outer try whose type is none
    (try $l0
      (do
        (call $foo)
        (try
          (do
            (call $bar)
          )
          (delegate $l0)
        )
        (try
          (do
            (call $bar)
          )
          (delegate $l0)
        )
        (call $baz)
      )
      (catch_all)
    )
  )

  ;; CHECK:      (func $delegate-target-outer-try-concrete (type $2) (result i32)
  ;; CHECK-NEXT:  (block $outer1 (result i32)
  ;; CHECK-NEXT:   (block $catch_all2
  ;; CHECK-NEXT:    (br $outer1
  ;; CHECK-NEXT:     (try_table (result i32) (catch_all $catch_all2)
  ;; CHECK-NEXT:      (throw_ref
  ;; CHECK-NEXT:       (block $l00 (result exnref)
  ;; CHECK-NEXT:        (br $outer1
  ;; CHECK-NEXT:         (block (result i32)
  ;; CHECK-NEXT:          (call $foo)
  ;; CHECK-NEXT:          (try_table (result i32) (catch_all_ref $l00)
  ;; CHECK-NEXT:           (call $bar)
  ;; CHECK-NEXT:           (i32.const 0)
  ;; CHECK-NEXT:          )
  ;; CHECK-NEXT:         )
  ;; CHECK-NEXT:        )
  ;; CHECK-NEXT:       )
  ;; CHECK-NEXT:      )
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:   (i32.const 1)
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  ;; STACKIR-OPT:      (func $delegate-target-outer-try-concrete (type $2) (result i32)
  ;; STACKIR-OPT-NEXT:  block $outer1 (result i32)
  ;; STACKIR-OPT-NEXT:   block $catch_all2
  ;; STACKIR-OPT-NEXT:    try_table (result i32) (catch_all $catch_all2)
  ;; STACKIR-OPT-NEXT:     block $l00 (result exnref)
  ;; STACKIR-OPT-NEXT:      call $foo
  ;; STACKIR-OPT-NEXT:      try_table (result i32) (catch_all_ref $l00)
  ;; STACKIR-OPT-NEXT:       call $bar
  ;; STACKIR-OPT-NEXT:       i32.const 0
  ;; STACKIR-OPT-NEXT:      end
  ;; STACKIR-OPT-NEXT:      br $outer1
  ;; STACKIR-OPT-NEXT:     end
  ;; STACKIR-OPT-NEXT:     throw_ref
  ;; STACKIR-OPT-NEXT:    end
  ;; STACKIR-OPT-NEXT:    br $outer1
  ;; STACKIR-OPT-NEXT:   end
  ;; STACKIR-OPT-NEXT:   i32.const 1
  ;; STACKIR-OPT-NEXT:  end
  ;; STACKIR-OPT-NEXT: )
  (func $delegate-target-outer-try-concrete (result i32)
    ;; An inner try-delegate targets an outer try whose type is concrete
    (try $l0 (result i32)
      (do
        (call $foo)
        (try (result i32)
          (do
            (call $bar)
            (i32.const 0)
          )
          (delegate $l0)
        )
      )
      (catch_all
        (i32.const 1)
      )
    )
  )

  ;; CHECK:      (func $deletate-target-outer-try-unreachable (type $1)
  ;; CHECK-NEXT:  (try_table
  ;; CHECK-NEXT:   (throw_ref
  ;; CHECK-NEXT:    (block $l00 (result exnref)
  ;; CHECK-NEXT:     (try_table (catch_all_ref $l00)
  ;; CHECK-NEXT:      (call $foo)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:     (return)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  ;; STACKIR-OPT:      (func $deletate-target-outer-try-unreachable (type $1)
  ;; STACKIR-OPT-NEXT:  try_table
  ;; STACKIR-OPT-NEXT:   block $l00 (result exnref)
  ;; STACKIR-OPT-NEXT:    try_table (catch_all_ref $l00)
  ;; STACKIR-OPT-NEXT:     call $foo
  ;; STACKIR-OPT-NEXT:    end
  ;; STACKIR-OPT-NEXT:    return
  ;; STACKIR-OPT-NEXT:   end
  ;; STACKIR-OPT-NEXT:   throw_ref
  ;; STACKIR-OPT-NEXT:  end
  ;; STACKIR-OPT-NEXT:  unreachable
  ;; STACKIR-OPT-NEXT: )
  (func $deletate-target-outer-try-unreachable
    ;; An inner try-delegate targets an outer try whose body type is unreachable
    ;; (due to a return). In this case we don't need an additional 'br' to an
    ;; outer block.
    (try $l0
      (do
        (try
          (do
            (call $foo)
          )
          (delegate $l0)
        )
        (return)
      )
    )
  )

  ;; CHECK:      (func $delegate-target-caller-none (type $1)
  ;; CHECK-NEXT:  (throw_ref
  ;; CHECK-NEXT:   (block $__binaryen_delegate_caller_target0 (result exnref)
  ;; CHECK-NEXT:    (call $foo)
  ;; CHECK-NEXT:    (try_table (catch_all_ref $__binaryen_delegate_caller_target0)
  ;; CHECK-NEXT:     (call $bar)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (call $baz)
  ;; CHECK-NEXT:    (return)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  ;; STACKIR-OPT:      (func $delegate-target-caller-none (type $1)
  ;; STACKIR-OPT-NEXT:  block $__binaryen_delegate_caller_target0 (result exnref)
  ;; STACKIR-OPT-NEXT:   call $foo
  ;; STACKIR-OPT-NEXT:   try_table (catch_all_ref $__binaryen_delegate_caller_target0)
  ;; STACKIR-OPT-NEXT:    call $bar
  ;; STACKIR-OPT-NEXT:   end
  ;; STACKIR-OPT-NEXT:   call $baz
  ;; STACKIR-OPT-NEXT:   return
  ;; STACKIR-OPT-NEXT:  end
  ;; STACKIR-OPT-NEXT:  throw_ref
  ;; STACKIR-OPT-NEXT: )
  (func $delegate-target-caller-none
    ;; A try-delegate targets the caller whose type is none
    (call $foo)
    (try
      (do
        (call $bar)
      )
      (delegate 0)
    )
    (call $baz)
  )

  ;; CHECK:      (func $multiple-delegates-target-caller-none (type $1)
  ;; CHECK-NEXT:  (throw_ref
  ;; CHECK-NEXT:   (block $__binaryen_delegate_caller_target0 (result exnref)
  ;; CHECK-NEXT:    (call $foo)
  ;; CHECK-NEXT:    (try_table (catch_all_ref $__binaryen_delegate_caller_target0)
  ;; CHECK-NEXT:     (call $bar)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (try_table (catch_all_ref $__binaryen_delegate_caller_target0)
  ;; CHECK-NEXT:     (call $bar)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (call $baz)
  ;; CHECK-NEXT:    (return)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  ;; STACKIR-OPT:      (func $multiple-delegates-target-caller-none (type $1)
  ;; STACKIR-OPT-NEXT:  block $__binaryen_delegate_caller_target0 (result exnref)
  ;; STACKIR-OPT-NEXT:   call $foo
  ;; STACKIR-OPT-NEXT:   try_table (catch_all_ref $__binaryen_delegate_caller_target0)
  ;; STACKIR-OPT-NEXT:    call $bar
  ;; STACKIR-OPT-NEXT:   end
  ;; STACKIR-OPT-NEXT:   try_table (catch_all_ref $__binaryen_delegate_caller_target0)
  ;; STACKIR-OPT-NEXT:    call $bar
  ;; STACKIR-OPT-NEXT:   end
  ;; STACKIR-OPT-NEXT:   call $baz
  ;; STACKIR-OPT-NEXT:   return
  ;; STACKIR-OPT-NEXT:  end
  ;; STACKIR-OPT-NEXT:  throw_ref
  ;; STACKIR-OPT-NEXT: )
  (func $multiple-delegates-target-caller-none
    ;; Multiple try-delegates target the caller whose type is none
    (call $foo)
    (try
      (do
        (call $bar)
      )
      (delegate 0)
    )
    (try
      (do
        (call $bar)
      )
      (delegate 0)
    )
    (call $baz)
  )

  ;; CHECK:      (func $delegate-target-caller-concrete (type $2) (result i32)
  ;; CHECK-NEXT:  (throw_ref
  ;; CHECK-NEXT:   (block $__binaryen_delegate_caller_target0 (result exnref)
  ;; CHECK-NEXT:    (return
  ;; CHECK-NEXT:     (block (result i32)
  ;; CHECK-NEXT:      (call $foo)
  ;; CHECK-NEXT:      (try_table (result i32) (catch_all_ref $__binaryen_delegate_caller_target0)
  ;; CHECK-NEXT:       (call $bar)
  ;; CHECK-NEXT:       (i32.const 0)
  ;; CHECK-NEXT:      )
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  ;; STACKIR-OPT:      (func $delegate-target-caller-concrete (type $2) (result i32)
  ;; STACKIR-OPT-NEXT:  block $__binaryen_delegate_caller_target0 (result exnref)
  ;; STACKIR-OPT-NEXT:   call $foo
  ;; STACKIR-OPT-NEXT:   try_table (result i32) (catch_all_ref $__binaryen_delegate_caller_target0)
  ;; STACKIR-OPT-NEXT:    call $bar
  ;; STACKIR-OPT-NEXT:    i32.const 0
  ;; STACKIR-OPT-NEXT:   end
  ;; STACKIR-OPT-NEXT:   return
  ;; STACKIR-OPT-NEXT:  end
  ;; STACKIR-OPT-NEXT:  throw_ref
  ;; STACKIR-OPT-NEXT: )
  (func $delegate-target-caller-concrete (result i32)
    ;; A try-delegate targets the caller whose type is concrete
    (call $foo)
    (try (result i32)
      (do
        (call $bar)
        (i32.const 0)
      )
      (delegate 0)
    )
  )

  ;; CHECK:      (func $delegate-nested-more (type $1)
  ;; CHECK-NEXT:  (block $outer3
  ;; CHECK-NEXT:   (block $catch_all4
  ;; CHECK-NEXT:    (try_table (catch_all $catch_all4)
  ;; CHECK-NEXT:     (throw_ref
  ;; CHECK-NEXT:      (block $l00 (result exnref)
  ;; CHECK-NEXT:       (block $outer1
  ;; CHECK-NEXT:        (block $catch_all2
  ;; CHECK-NEXT:         (try_table (catch_all $catch_all2)
  ;; CHECK-NEXT:          (try_table (catch_all_ref $l00)
  ;; CHECK-NEXT:           (call $foo)
  ;; CHECK-NEXT:          )
  ;; CHECK-NEXT:         )
  ;; CHECK-NEXT:         (br $outer1)
  ;; CHECK-NEXT:        )
  ;; CHECK-NEXT:        (block
  ;; CHECK-NEXT:        )
  ;; CHECK-NEXT:       )
  ;; CHECK-NEXT:       (br $outer3)
  ;; CHECK-NEXT:      )
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:   (block
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  ;; STACKIR-OPT:      (func $delegate-nested-more (type $1)
  ;; STACKIR-OPT-NEXT:  block $outer3
  ;; STACKIR-OPT-NEXT:   block $catch_all4
  ;; STACKIR-OPT-NEXT:    try_table (catch_all $catch_all4)
  ;; STACKIR-OPT-NEXT:     block $l00 (result exnref)
  ;; STACKIR-OPT-NEXT:      block $outer1
  ;; STACKIR-OPT-NEXT:       block $catch_all2
  ;; STACKIR-OPT-NEXT:        try_table (catch_all $catch_all2)
  ;; STACKIR-OPT-NEXT:         try_table (catch_all_ref $l00)
  ;; STACKIR-OPT-NEXT:          call $foo
  ;; STACKIR-OPT-NEXT:         end
  ;; STACKIR-OPT-NEXT:        end
  ;; STACKIR-OPT-NEXT:        br $outer1
  ;; STACKIR-OPT-NEXT:       end
  ;; STACKIR-OPT-NEXT:      end
  ;; STACKIR-OPT-NEXT:      br $outer3
  ;; STACKIR-OPT-NEXT:     end
  ;; STACKIR-OPT-NEXT:     throw_ref
  ;; STACKIR-OPT-NEXT:    end
  ;; STACKIR-OPT-NEXT:    unreachable
  ;; STACKIR-OPT-NEXT:   end
  ;; STACKIR-OPT-NEXT:  end
  ;; STACKIR-OPT-NEXT: )
  (func $delegate-nested-more
    (try $l0
      (do
        (try
          (do
            (try
              (do
                (call $foo)
              )
              (delegate $l0)
            )
          )
          (catch_all)
        )
      )
      (catch_all)
    )
  )

  ;; CHECK:      (func $delegate-target-outer-try-delegate (type $1)
  ;; CHECK-NEXT:  (throw_ref
  ;; CHECK-NEXT:   (block $__binaryen_delegate_caller_target0 (result exnref)
  ;; CHECK-NEXT:    (block $outer2
  ;; CHECK-NEXT:     (try_table (catch_all_ref $__binaryen_delegate_caller_target0)
  ;; CHECK-NEXT:      (throw_ref
  ;; CHECK-NEXT:       (block $l01 (result exnref)
  ;; CHECK-NEXT:        (try_table (catch_all_ref $l01)
  ;; CHECK-NEXT:         (call $foo)
  ;; CHECK-NEXT:        )
  ;; CHECK-NEXT:        (br $outer2)
  ;; CHECK-NEXT:       )
  ;; CHECK-NEXT:      )
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (return)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  ;; STACKIR-OPT:      (func $delegate-target-outer-try-delegate (type $1)
  ;; STACKIR-OPT-NEXT:  block $__binaryen_delegate_caller_target0 (result exnref)
  ;; STACKIR-OPT-NEXT:   block $outer2
  ;; STACKIR-OPT-NEXT:    try_table (catch_all_ref $__binaryen_delegate_caller_target0)
  ;; STACKIR-OPT-NEXT:     block $l01 (result exnref)
  ;; STACKIR-OPT-NEXT:      try_table (catch_all_ref $l01)
  ;; STACKIR-OPT-NEXT:       call $foo
  ;; STACKIR-OPT-NEXT:      end
  ;; STACKIR-OPT-NEXT:      br $outer2
  ;; STACKIR-OPT-NEXT:     end
  ;; STACKIR-OPT-NEXT:     throw_ref
  ;; STACKIR-OPT-NEXT:    end
  ;; STACKIR-OPT-NEXT:    unreachable
  ;; STACKIR-OPT-NEXT:   end
  ;; STACKIR-OPT-NEXT:   return
  ;; STACKIR-OPT-NEXT:  end
  ;; STACKIR-OPT-NEXT:  throw_ref
  ;; STACKIR-OPT-NEXT: )
  (func $delegate-target-outer-try-delegate
    ;; An inner try-delegate targets an outer try-delegate that targets the
    ;; caller
    (try $l0
      (do
        (try
          (do
            (call $foo)
          )
          (delegate $l0)
        )
      )
      (delegate 0)
    )
  )

  ;; CHECK:      (func $delegate-target-outer-try-delegate-concrete (type $2) (result i32)
  ;; CHECK-NEXT:  (throw_ref
  ;; CHECK-NEXT:   (block $__binaryen_delegate_caller_target0 (result exnref)
  ;; CHECK-NEXT:    (return
  ;; CHECK-NEXT:     (block $outer2 (result i32)
  ;; CHECK-NEXT:      (try_table (catch_all_ref $__binaryen_delegate_caller_target0)
  ;; CHECK-NEXT:       (throw_ref
  ;; CHECK-NEXT:        (block $l01 (result exnref)
  ;; CHECK-NEXT:         (br $outer2
  ;; CHECK-NEXT:          (try_table (result i32) (catch_all_ref $l01)
  ;; CHECK-NEXT:           (call $foo)
  ;; CHECK-NEXT:           (i32.const 0)
  ;; CHECK-NEXT:          )
  ;; CHECK-NEXT:         )
  ;; CHECK-NEXT:        )
  ;; CHECK-NEXT:       )
  ;; CHECK-NEXT:      )
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  ;; STACKIR-OPT:      (func $delegate-target-outer-try-delegate-concrete (type $2) (result i32)
  ;; STACKIR-OPT-NEXT:  block $__binaryen_delegate_caller_target0 (result exnref)
  ;; STACKIR-OPT-NEXT:   block $outer2 (result i32)
  ;; STACKIR-OPT-NEXT:    try_table (catch_all_ref $__binaryen_delegate_caller_target0)
  ;; STACKIR-OPT-NEXT:     block $l01 (result exnref)
  ;; STACKIR-OPT-NEXT:      try_table (result i32) (catch_all_ref $l01)
  ;; STACKIR-OPT-NEXT:       call $foo
  ;; STACKIR-OPT-NEXT:       i32.const 0
  ;; STACKIR-OPT-NEXT:      end
  ;; STACKIR-OPT-NEXT:      br $outer2
  ;; STACKIR-OPT-NEXT:     end
  ;; STACKIR-OPT-NEXT:     throw_ref
  ;; STACKIR-OPT-NEXT:    end
  ;; STACKIR-OPT-NEXT:    unreachable
  ;; STACKIR-OPT-NEXT:   end
  ;; STACKIR-OPT-NEXT:   return
  ;; STACKIR-OPT-NEXT:  end
  ;; STACKIR-OPT-NEXT:  throw_ref
  ;; STACKIR-OPT-NEXT: )
  (func $delegate-target-outer-try-delegate-concrete (result i32)
    ;; An inner try-delegate targets an outer try-delegate that targets the
    ;; caller, where the type of the try-delegates and the caller is concrete
    (try $l0 (result i32)
      (do
        (try (result i32)
          (do
            (call $foo)
            (i32.const 0)
          )
          (delegate $l0)
        )
      )
      (delegate 0)
    )
  )

  ;; CHECK:      (func $throw_ref-in-resultless-block (type $2) (result i32)
  ;; CHECK-NEXT:  (throw_ref
  ;; CHECK-NEXT:   (block $__binaryen_delegate_caller_target0 (result exnref)
  ;; CHECK-NEXT:    (return
  ;; CHECK-NEXT:     (block
  ;; CHECK-NEXT:      (try_table (catch_all_ref $__binaryen_delegate_caller_target0)
  ;; CHECK-NEXT:       (call $foo)
  ;; CHECK-NEXT:      )
  ;; CHECK-NEXT:      (unreachable)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  ;; STACKIR-OPT:      (func $throw_ref-in-resultless-block (type $2) (result i32)
  ;; STACKIR-OPT-NEXT:  block $__binaryen_delegate_caller_target0 (result exnref)
  ;; STACKIR-OPT-NEXT:   try_table (catch_all_ref $__binaryen_delegate_caller_target0)
  ;; STACKIR-OPT-NEXT:    call $foo
  ;; STACKIR-OPT-NEXT:   end
  ;; STACKIR-OPT-NEXT:   unreachable
  ;; STACKIR-OPT-NEXT:  end
  ;; STACKIR-OPT-NEXT:  throw_ref
  ;; STACKIR-OPT-NEXT: )
  (func $throw_ref-in-resultless-block (result i32)
    ;; When the function return type is concrete, try-delegate that targets the
    ;; caller is translated to
    ;; (throw_ref
    ;;   (block $__binaryen_delegate_caller_target (result exnref)
    ;;     (return
    ;;       function body
    ;;     )
    ;;   )
    ;; )
    ;; We should do that even if the function body's type is not concrete.
    (block ;; This block doesn't have concrete result type
      (try
        (do
          (call $foo)
        )
        (delegate 1)
      )
      (unreachable)
    )
  )

  ;; CHECK:      (func $try-delegate-within-catchless-try (type $1)
  ;; CHECK-NEXT:  (block $outer1
  ;; CHECK-NEXT:   (try_table
  ;; CHECK-NEXT:    (throw_ref
  ;; CHECK-NEXT:     (block $l00 (result exnref)
  ;; CHECK-NEXT:      (try_table (catch_all_ref $l00)
  ;; CHECK-NEXT:       (call $foo)
  ;; CHECK-NEXT:      )
  ;; CHECK-NEXT:      (br $outer1)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  ;; STACKIR-OPT:      (func $try-delegate-within-catchless-try (type $1)
  ;; STACKIR-OPT-NEXT:  block $outer1
  ;; STACKIR-OPT-NEXT:   try_table
  ;; STACKIR-OPT-NEXT:    block $l00 (result exnref)
  ;; STACKIR-OPT-NEXT:     try_table (catch_all_ref $l00)
  ;; STACKIR-OPT-NEXT:      call $foo
  ;; STACKIR-OPT-NEXT:     end
  ;; STACKIR-OPT-NEXT:     br $outer1
  ;; STACKIR-OPT-NEXT:    end
  ;; STACKIR-OPT-NEXT:    throw_ref
  ;; STACKIR-OPT-NEXT:   end
  ;; STACKIR-OPT-NEXT:   unreachable
  ;; STACKIR-OPT-NEXT:  end
  ;; STACKIR-OPT-NEXT: )
  (func $try-delegate-within-catchless-try
    (try $l0
      (do
        (try
          (do
            (call $foo)
          )
          (delegate $l0)
        )
      )
    )
  )

  ;; CHECK:      (func $try-catch-rethrow-with-inner-delegate (type $1)
  ;; CHECK-NEXT:  (local $0 exnref)
  ;; CHECK-NEXT:  (block $outer2
  ;; CHECK-NEXT:   (local.set $0
  ;; CHECK-NEXT:    (block $catch3 (result (ref exn))
  ;; CHECK-NEXT:     (try_table (catch_ref $e-empty $catch3)
  ;; CHECK-NEXT:      (call $foo)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:     (br $outer2)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:   (block
  ;; CHECK-NEXT:    (block $outer1
  ;; CHECK-NEXT:     (try_table
  ;; CHECK-NEXT:      (throw_ref
  ;; CHECK-NEXT:       (block $l10 (result exnref)
  ;; CHECK-NEXT:        (try_table (catch_all_ref $l10)
  ;; CHECK-NEXT:         (call $foo)
  ;; CHECK-NEXT:        )
  ;; CHECK-NEXT:        (br $outer1)
  ;; CHECK-NEXT:       )
  ;; CHECK-NEXT:      )
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (throw_ref
  ;; CHECK-NEXT:     (local.get $0)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  ;; STACKIR-OPT:      (func $try-catch-rethrow-with-inner-delegate (type $1)
  ;; STACKIR-OPT-NEXT:  (local $0 exnref)
  ;; STACKIR-OPT-NEXT:  block $outer2
  ;; STACKIR-OPT-NEXT:   block $catch3 (result (ref exn))
  ;; STACKIR-OPT-NEXT:    try_table (catch_ref $e-empty $catch3)
  ;; STACKIR-OPT-NEXT:     call $foo
  ;; STACKIR-OPT-NEXT:    end
  ;; STACKIR-OPT-NEXT:    br $outer2
  ;; STACKIR-OPT-NEXT:   end
  ;; STACKIR-OPT-NEXT:   block $outer1
  ;; STACKIR-OPT-NEXT:    try_table
  ;; STACKIR-OPT-NEXT:     block $l10 (result exnref)
  ;; STACKIR-OPT-NEXT:      try_table (catch_all_ref $l10)
  ;; STACKIR-OPT-NEXT:       call $foo
  ;; STACKIR-OPT-NEXT:      end
  ;; STACKIR-OPT-NEXT:      br $outer1
  ;; STACKIR-OPT-NEXT:     end
  ;; STACKIR-OPT-NEXT:     throw_ref
  ;; STACKIR-OPT-NEXT:    end
  ;; STACKIR-OPT-NEXT:    unreachable
  ;; STACKIR-OPT-NEXT:   end
  ;; STACKIR-OPT-NEXT:   throw_ref
  ;; STACKIR-OPT-NEXT:  end
  ;; STACKIR-OPT-NEXT: )
  (func $try-catch-rethrow-with-inner-delegate
    (try $l0
      (do
        (call $foo)
      )
      (catch $e-empty
        (try $l1
          (do
            (try
              (do
                (call $foo)
              )
              (delegate $l1)
            )
          )
        )
        (rethrow $l0)
      )
    )
  )
)
