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

(module
  ;; CHECK:      (import "a" "b" (func $i32 (type $3) (result i32)))
  (import "a" "b" (func $i32 (result i32)))
  ;; CHECK:      (import "a" "b" (func $none (type $2)))
  (import "a" "b" (func $none))

  ;; CHECK:      (tag $e (type $2))
  (tag $e)

  ;; CHECK:      (func $if-br (type $1) (param $x i32) (param $y i32)
  ;; CHECK-NEXT:  (block $out
  ;; CHECK-NEXT:   (nop)
  ;; CHECK-NEXT:   (@metadata.code.branch_hint "\01")
  ;; CHECK-NEXT:   (br_if $out
  ;; CHECK-NEXT:    (local.get $x)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $if-br (param $x i32) (param $y i32)
    (block $out
      ;; This nop prevents the entire testcase from being trivial.
      (nop)
      ;; The if-br will turn into a br_if. The branch hint should then go on the
      ;; br_if, and remain 01.
      (@metadata.code.branch_hint "\01")
      (if
        (local.get $x)
        (then
          (br $out)
        )
      )
    )
  )

  ;; CHECK:      (func $if-br_0 (type $1) (param $x i32) (param $y i32)
  ;; CHECK-NEXT:  (block $out
  ;; CHECK-NEXT:   (nop)
  ;; CHECK-NEXT:   (@metadata.code.branch_hint "\00")
  ;; CHECK-NEXT:   (br_if $out
  ;; CHECK-NEXT:    (local.get $x)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $if-br_0 (param $x i32) (param $y i32)
    (block $out
      (nop)
      ;; As above, but a hint of 0.
      (@metadata.code.branch_hint "\00")
      (if
        (local.get $x)
        (then
          (br $out)
        )
      )
    )
  )

  ;; CHECK:      (func $if-br_if (type $1) (param $x i32) (param $y i32)
  ;; CHECK-NEXT:  (block $out
  ;; CHECK-NEXT:   (nop)
  ;; CHECK-NEXT:   (@metadata.code.branch_hint "\01")
  ;; CHECK-NEXT:   (br_if $out
  ;; CHECK-NEXT:    (select
  ;; CHECK-NEXT:     (local.get $x)
  ;; CHECK-NEXT:     (i32.const 0)
  ;; CHECK-NEXT:     (local.get $y)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $if-br_if (param $x i32) (param $y i32)
    (block $out
      (nop)
      ;; As above, but the br has a condition. We can merge conditions (using a
      ;; select), and then move the hint to the br_if, as the br_if has the
      ;; same hint as the if.
      (@metadata.code.branch_hint "\01")
      (if
        (local.get $x)
        (then
          (@metadata.code.branch_hint "\01")
          (br_if $out
            (local.get $y)
          )
        )
      )
    )
  )

  ;; CHECK:      (func $if-br_if-no (type $1) (param $x i32) (param $y i32)
  ;; CHECK-NEXT:  (block $out
  ;; CHECK-NEXT:   (nop)
  ;; CHECK-NEXT:   (br_if $out
  ;; CHECK-NEXT:    (select
  ;; CHECK-NEXT:     (local.get $x)
  ;; CHECK-NEXT:     (i32.const 0)
  ;; CHECK-NEXT:     (local.get $y)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $if-br_if-no (param $x i32) (param $y i32)
    (block $out
      (nop)
      ;; As above, but the br lacks a hint, so we emit no hint.
      (@metadata.code.branch_hint "\01")
      (if
        (local.get $x)
        (then
          (br_if $out
            (local.get $y)
          )
        )
      )
    )
  )

  ;; CHECK:      (func $if-br_if-no-2 (type $1) (param $x i32) (param $y i32)
  ;; CHECK-NEXT:  (block $out
  ;; CHECK-NEXT:   (nop)
  ;; CHECK-NEXT:   (br_if $out
  ;; CHECK-NEXT:    (select
  ;; CHECK-NEXT:     (local.get $x)
  ;; CHECK-NEXT:     (i32.const 0)
  ;; CHECK-NEXT:     (local.get $y)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $if-br_if-no-2 (param $x i32) (param $y i32)
    (block $out
      (nop)
      ;; As above, but now the if lacks a hint, so we emit no hint.
      (if
        (local.get $x)
        (then
          (@metadata.code.branch_hint "\01")
          (br_if $out
            (local.get $y)
          )
        )
      )
    )
  )

  ;; CHECK:      (func $if-if-1* (type $1) (param $x i32) (param $y i32)
  ;; CHECK-NEXT:  (@metadata.code.branch_hint "\01")
  ;; CHECK-NEXT:  (if
  ;; CHECK-NEXT:   (select
  ;; CHECK-NEXT:    (local.get $x)
  ;; CHECK-NEXT:    (i32.const 0)
  ;; CHECK-NEXT:    (local.get $y)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:   (then
  ;; CHECK-NEXT:    (call $none)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (if
  ;; CHECK-NEXT:   (select
  ;; CHECK-NEXT:    (local.get $x)
  ;; CHECK-NEXT:    (i32.const 0)
  ;; CHECK-NEXT:    (local.get $y)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:   (then
  ;; CHECK-NEXT:    (call $none)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (if
  ;; CHECK-NEXT:   (select
  ;; CHECK-NEXT:    (local.get $x)
  ;; CHECK-NEXT:    (i32.const 0)
  ;; CHECK-NEXT:    (local.get $y)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:   (then
  ;; CHECK-NEXT:    (call $none)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $if-if-1* (param $x i32) (param $y i32)
    ;; Both ifs have a hint of 1, so after we merge the ifs the combined
    ;; condition remains likely.
    (@metadata.code.branch_hint "\01")
    (if
      (local.get $x)
      (then
        (@metadata.code.branch_hint "\01")
        (if
          (local.get $y)
          (then
            (call $none)
          )
        )
      )
    )
    ;; The outer if still has a hint of 1, but the inner is 0. We emit no hint.
    (@metadata.code.branch_hint "\01")
    (if
      (local.get $x)
      (then
        (@metadata.code.branch_hint "\00")
        (if
          (local.get $y)
          (then
            (call $none)
          )
        )
      )
    )
    ;; The outer if still has a hint of 1, but the inner has none. We emit no
    ;; hint.
    (@metadata.code.branch_hint "\01")
    (if
      (local.get $x)
      (then
        (if
          (local.get $y)
          (then
            (call $none)
          )
        )
      )
    )
  )

  ;; CHECK:      (func $if-if-0* (type $1) (param $x i32) (param $y i32)
  ;; CHECK-NEXT:  (if
  ;; CHECK-NEXT:   (select
  ;; CHECK-NEXT:    (local.get $x)
  ;; CHECK-NEXT:    (i32.const 0)
  ;; CHECK-NEXT:    (local.get $y)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:   (then
  ;; CHECK-NEXT:    (call $none)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (@metadata.code.branch_hint "\00")
  ;; CHECK-NEXT:  (if
  ;; CHECK-NEXT:   (select
  ;; CHECK-NEXT:    (local.get $x)
  ;; CHECK-NEXT:    (i32.const 0)
  ;; CHECK-NEXT:    (local.get $y)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:   (then
  ;; CHECK-NEXT:    (call $none)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (if
  ;; CHECK-NEXT:   (select
  ;; CHECK-NEXT:    (local.get $x)
  ;; CHECK-NEXT:    (i32.const 0)
  ;; CHECK-NEXT:    (local.get $y)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:   (then
  ;; CHECK-NEXT:    (call $none)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $if-if-0* (param $x i32) (param $y i32)
    ;; As above, but now the outer if has hints of 0.

    ;; The hints do not match, so we emit no hint.
    (@metadata.code.branch_hint "\00")
    (if
      (local.get $x)
      (then
        (@metadata.code.branch_hint "\01")
        (if
          (local.get $y)
          (then
            (call $none)
          )
        )
      )
    )
    ;; The hints match, so the combined condition is unlikely.
    (@metadata.code.branch_hint "\00")
    (if
      (local.get $x)
      (then
        (@metadata.code.branch_hint "\00")
        (if
          (local.get $y)
          (then
            (call $none)
          )
        )
      )
    )
    ;; Inner lacks a hint, so we emit nothing.
    (@metadata.code.branch_hint "\01")
    (if
      (local.get $x)
      (then
        (if
          (local.get $y)
          (then
            (call $none)
          )
        )
      )
    )
  )

  ;; CHECK:      (func $if-if-?* (type $1) (param $x i32) (param $y i32)
  ;; CHECK-NEXT:  (if
  ;; CHECK-NEXT:   (select
  ;; CHECK-NEXT:    (local.get $x)
  ;; CHECK-NEXT:    (i32.const 0)
  ;; CHECK-NEXT:    (local.get $y)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:   (then
  ;; CHECK-NEXT:    (call $none)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (if
  ;; CHECK-NEXT:   (select
  ;; CHECK-NEXT:    (local.get $x)
  ;; CHECK-NEXT:    (i32.const 0)
  ;; CHECK-NEXT:    (local.get $y)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:   (then
  ;; CHECK-NEXT:    (call $none)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (if
  ;; CHECK-NEXT:   (select
  ;; CHECK-NEXT:    (local.get $x)
  ;; CHECK-NEXT:    (i32.const 0)
  ;; CHECK-NEXT:    (local.get $y)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:   (then
  ;; CHECK-NEXT:    (call $none)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $if-if-?* (param $x i32) (param $y i32)
    ;; As above, but now the outer if has no hint. We emit no hints here.

    (if
      (local.get $x)
      (then
        (@metadata.code.branch_hint "\01")
        (if
          (local.get $y)
          (then
            (call $none)
          )
        )
      )
    )
    (if
      (local.get $x)
      (then
        (@metadata.code.branch_hint "\00")
        (if
          (local.get $y)
          (then
            (call $none)
          )
        )
      )
    )
    (if
      (local.get $x)
      (then
        (if
          (local.get $y)
          (then
            (call $none)
          )
        )
      )
    )
  )

  ;; CHECK:      (func $loop-br_if-flip (type $0) (param $x i32)
  ;; CHECK-NEXT:  (loop $loop
  ;; CHECK-NEXT:   (block $block
  ;; CHECK-NEXT:    (block
  ;; CHECK-NEXT:     (@metadata.code.branch_hint "\01")
  ;; CHECK-NEXT:     (br_if $loop
  ;; CHECK-NEXT:      (i32.eqz
  ;; CHECK-NEXT:       (local.get $x)
  ;; CHECK-NEXT:      )
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $loop-br_if-flip (param $x i32)
    (block $block
      (loop $loop
        ;; This br_if's condition will flip when it is turned from a break out
        ;; of the loop to a continue inside it. The hint should flip too.
        (@metadata.code.branch_hint "\00")
        (br_if $block
          (local.get $x)
        )
        (br $loop)
      )
    )
  )

  ;; CHECK:      (func $loop-br_if-flip-reverse (type $0) (param $x i32)
  ;; CHECK-NEXT:  (loop $loop
  ;; CHECK-NEXT:   (block $block
  ;; CHECK-NEXT:    (block
  ;; CHECK-NEXT:     (@metadata.code.branch_hint "\00")
  ;; CHECK-NEXT:     (br_if $loop
  ;; CHECK-NEXT:      (i32.eqz
  ;; CHECK-NEXT:       (local.get $x)
  ;; CHECK-NEXT:      )
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $loop-br_if-flip-reverse (param $x i32)
    ;; As above, with a hint of 1, that should flip to 0.
    (block $block
      (loop $loop
        (@metadata.code.branch_hint "\01")
        (br_if $block
          (local.get $x)
        )
        (br $loop)
      )
    )
  )

  ;; CHECK:      (func $loop-br_if-if (type $0) (param $x i32)
  ;; CHECK-NEXT:  (loop $loop
  ;; CHECK-NEXT:   (@metadata.code.branch_hint "\00")
  ;; CHECK-NEXT:   (if
  ;; CHECK-NEXT:    (local.get $x)
  ;; CHECK-NEXT:    (then
  ;; CHECK-NEXT:     (block $block
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (else
  ;; CHECK-NEXT:     (drop
  ;; CHECK-NEXT:      (i32.const 42)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:     (br $loop)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $loop-br_if-if (param $x i32)
    (loop $loop
      (block $block
        ;; This br_if will turn into an if with the same condition. The hint can
        ;; be copied over.
        (@metadata.code.branch_hint "\00")
        (br_if $block
          (local.get $x)
        )
        ;; Extra code so simpler optimizations do not kick in.
        (drop (i32.const 42))
        (br $loop)
      )
    )
  )

  ;; CHECK:      (func $throw-if-br_if-0 (type $0) (param $x i32)
  ;; CHECK-NEXT:  (block $catch
  ;; CHECK-NEXT:   (try_table (catch_all $catch)
  ;; CHECK-NEXT:    (@metadata.code.branch_hint "\00")
  ;; CHECK-NEXT:    (br_if $catch
  ;; CHECK-NEXT:     (local.get $x)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $throw-if-br_if-0 (param $x i32)
    (block $catch
      (try_table (catch_all $catch)
        ;; This if can turn into a br_if. The branch hint should be copied.
        (@metadata.code.branch_hint "\00")
        (if
          (local.get $x)
          (then
            (throw $e)
          )
        )
      )
    )
  )

  ;; CHECK:      (func $throw-if-br_if-1 (type $0) (param $x i32)
  ;; CHECK-NEXT:  (block $catch
  ;; CHECK-NEXT:   (try_table (catch_all $catch)
  ;; CHECK-NEXT:    (@metadata.code.branch_hint "\01")
  ;; CHECK-NEXT:    (br_if $catch
  ;; CHECK-NEXT:     (local.get $x)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $throw-if-br_if-1 (param $x i32)
    ;; As above, but the hint is 1.
    (block $catch
      (try_table (catch_all $catch)
        (@metadata.code.branch_hint "\01")
        (if
          (local.get $x)
          (then
            (throw $e)
          )
        )
      )
    )
  )

  ;; CHECK:      (func $throw-if-br_if-no (type $0) (param $x i32)
  ;; CHECK-NEXT:  (block $catch
  ;; CHECK-NEXT:   (try_table (catch_all $catch)
  ;; CHECK-NEXT:    (br_if $catch
  ;; CHECK-NEXT:     (local.get $x)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $throw-if-br_if-no (param $x i32)
    ;; As above, but there is no branch hint, so we should emit none.
    (block $catch
      (try_table (catch_all $catch)
        (if
          (local.get $x)
          (then
            (throw $e)
          )
        )
      )
    )
  )

  ;; CHECK:      (func $loop-if-br (type $0) (param $x i32)
  ;; CHECK-NEXT:  (loop $loop
  ;; CHECK-NEXT:   (@metadata.code.branch_hint "\01")
  ;; CHECK-NEXT:   (br_if $loop
  ;; CHECK-NEXT:    (local.get $x)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:   (call $none)
  ;; CHECK-NEXT:   (call $none)
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $loop-if-br (param $x i32)
    ;; This if with a br arm can turn into a br_if. The hint should be copied.
    (loop $loop
      (@metadata.code.branch_hint "\01")
      (if
        (local.get $x)
        (then
          (br $loop)
        )
        (else
          ;; This call, and the one below, are needed for the pattern that is
          ;; recognized here.
          (call $none)
        )
      )
      (call $none)
    )
  )

  ;; CHECK:      (func $loop-if-br-reverse (type $0) (param $x i32)
  ;; CHECK-NEXT:  (loop $loop
  ;; CHECK-NEXT:   (@metadata.code.branch_hint "\00")
  ;; CHECK-NEXT:   (br_if $loop
  ;; CHECK-NEXT:    (i32.eqz
  ;; CHECK-NEXT:     (local.get $x)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:   (call $none)
  ;; CHECK-NEXT:   (call $none)
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $loop-if-br-reverse (param $x i32)
    ;; As above, with arms flipped. Now the condition flips.
    (loop $loop
      (@metadata.code.branch_hint "\01")
      (if
        (local.get $x)
        (then
          (call $none)
        )
        (else
          (br $loop)
        )
      )
      (call $none)
    )
  )

  ;; CHECK:      (func $restructure-if (type $0) (param $x i32)
  ;; CHECK-NEXT:  (@metadata.code.branch_hint "\00")
  ;; CHECK-NEXT:  (if
  ;; CHECK-NEXT:   (i32.eqz
  ;; CHECK-NEXT:    (local.get $x)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:   (then
  ;; CHECK-NEXT:    (block $block
  ;; CHECK-NEXT:     (nop)
  ;; CHECK-NEXT:     (call $none)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $restructure-if (param $x i32)
    (block $block
      ;; We will emit an if with flipped condition, which should get a flipped
      ;; hint.
      (@metadata.code.branch_hint "\01")
      (br_if $block
        (local.get $x)
      )
      (call $none)
    )
  )

  ;; CHECK:      (func $restructure-if-value (type $4) (param $x i32) (result i32)
  ;; CHECK-NEXT:  (@metadata.code.branch_hint "\01")
  ;; CHECK-NEXT:  (if (result i32)
  ;; CHECK-NEXT:   (local.get $x)
  ;; CHECK-NEXT:   (then
  ;; CHECK-NEXT:    (i32.const 0)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:   (else
  ;; CHECK-NEXT:    (block $value (result i32)
  ;; CHECK-NEXT:     (nop)
  ;; CHECK-NEXT:     (unreachable)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $restructure-if-value (param $x i32) (result i32)
    ;; We will emit an if with the same condition, which should get the same
    ;; hint.
    (block $value (result i32)
      (drop
        (@metadata.code.branch_hint "\01")
        (br_if $value
          (i32.const 0)
          (local.get $x)
        )
      )
      (unreachable)
    )
  )

  ;; CHECK:      (func $set-if-br-arm (type $0) (param $x i32)
  ;; CHECK-NEXT:  (local $temp i32)
  ;; CHECK-NEXT:  (block $out
  ;; CHECK-NEXT:   (block
  ;; CHECK-NEXT:    (@metadata.code.branch_hint "\00")
  ;; CHECK-NEXT:    (br_if $out
  ;; CHECK-NEXT:     (local.get $x)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (local.set $temp
  ;; CHECK-NEXT:     (i32.const 0)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $set-if-br-arm (param $x i32)
    (local $temp i32)
    ;; The if will turn into a br_if, with the same hint.
    (block $out
      (local.set $temp
        (@metadata.code.branch_hint "\00")
        (if (result i32)
          (local.get $x)
          (then
            (br $out)
          )
          (else
            (i32.const 0)
          )
        )
      )
    )
  )

  ;; CHECK:      (func $set-if-br-arm-flip (type $0) (param $x i32)
  ;; CHECK-NEXT:  (local $temp i32)
  ;; CHECK-NEXT:  (block $out
  ;; CHECK-NEXT:   (block
  ;; CHECK-NEXT:    (@metadata.code.branch_hint "\01")
  ;; CHECK-NEXT:    (br_if $out
  ;; CHECK-NEXT:     (i32.eqz
  ;; CHECK-NEXT:      (local.get $x)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (local.set $temp
  ;; CHECK-NEXT:     (i32.const 0)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $set-if-br-arm-flip (param $x i32)
    (local $temp i32)
    ;; As above, but with arms reversed.
    ;; The if will turn into a flipped br_if, with a flipped hint.
    (block $out
      (local.set $temp
        (@metadata.code.branch_hint "\00")
        (if (result i32)
          (local.get $x)
          (then
            (i32.const 0)
          )
          (else
            (br $out)
          )
        )
      )
    )
  )
)
