;; 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
  ;; Regression test in which we need to calculate a proper LUB.
  ;; CHECK:      (func $selectify-fresh-lub (type $4) (param $x i32) (result anyref)
  ;; CHECK-NEXT:  (select (result i31ref)
  ;; CHECK-NEXT:   (ref.null none)
  ;; CHECK-NEXT:   (ref.i31
  ;; CHECK-NEXT:    (i32.const 0)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:   (local.get $x)
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $selectify-fresh-lub (param $x i32) (result anyref)
    (if
      (local.get $x)
      (then
        (return
          (ref.null none)
        )
      )
      (else
        (return
          (ref.i31 (i32.const 0))
        )
      )
    )
  )

  ;; CHECK:      (func $selectify-simple (type $0) (param $0 i32) (result i32)
  ;; CHECK-NEXT:  (select
  ;; CHECK-NEXT:   (i32.const 1)
  ;; CHECK-NEXT:   (i32.lt_u
  ;; CHECK-NEXT:    (i32.sub
  ;; CHECK-NEXT:     (local.get $0)
  ;; CHECK-NEXT:     (i32.const 97)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (i32.const 6)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:   (i32.lt_u
  ;; CHECK-NEXT:    (i32.sub
  ;; CHECK-NEXT:     (local.get $0)
  ;; CHECK-NEXT:     (i32.const 48)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (i32.const 10)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $selectify-simple (param $0 i32) (result i32)
    (if (result i32)
      (i32.lt_u
        (i32.sub
          (local.get $0)
          (i32.const 48)
        )
        (i32.const 10)
      )
      (then
        (i32.const 1)
      )
      (else
        (i32.lt_u
          (i32.sub
            (local.get $0)
            (i32.const 97)
          )
          (i32.const 6)
        )
      )
    )
  )

  ;; CHECK:      (func $restructure-br_if (type $0) (param $x i32) (result i32)
  ;; CHECK-NEXT:  (if (result i32)
  ;; CHECK-NEXT:   (local.get $x)
  ;; CHECK-NEXT:   (then
  ;; CHECK-NEXT:    (i32.const 100)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:   (else
  ;; CHECK-NEXT:    (block $x (result i32)
  ;; CHECK-NEXT:     (nop)
  ;; CHECK-NEXT:     (drop
  ;; CHECK-NEXT:      (i32.const 200)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:     (i32.const 300)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $restructure-br_if (param $x i32) (result i32)
    ;; this block+br_if can be turned into an if.
    (block $x (result i32)
      (drop
        (br_if $x
          (i32.const 100)
          (local.get $x)
        )
      )
      (drop (i32.const 200))
      (i32.const 300)
    )
  )

  ;; CHECK:      (func $nothing (type $1)
  ;; CHECK-NEXT: )
  (func $nothing)


  ;; CHECK:      (func $restructure-br_if-condition-reorderable (type $0) (param $x i32) (result i32)
  ;; CHECK-NEXT:  (if (result i32)
  ;; CHECK-NEXT:   (block (result i32)
  ;; CHECK-NEXT:    (call $nothing)
  ;; CHECK-NEXT:    (local.get $x)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:   (then
  ;; CHECK-NEXT:    (i32.const 100)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:   (else
  ;; CHECK-NEXT:    (block $x (result i32)
  ;; CHECK-NEXT:     (nop)
  ;; CHECK-NEXT:     (drop
  ;; CHECK-NEXT:      (i32.const 200)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:     (i32.const 300)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $restructure-br_if-condition-reorderable (param $x i32) (result i32)
    (block $x (result i32)
      (drop
        (br_if $x
          (i32.const 100)
          ;; the condition has side effects, but can be reordered with the value
          (block (result i32)
            (call $nothing)
            (local.get $x)
          )
        )
      )
      (drop (i32.const 200))
      (i32.const 300)
    )
  )

  ;; CHECK:      (func $restructure-br_if-value-effectful (type $0) (param $x i32) (result i32)
  ;; CHECK-NEXT:  (select
  ;; CHECK-NEXT:   (block (result i32)
  ;; CHECK-NEXT:    (call $nothing)
  ;; CHECK-NEXT:    (i32.const 100)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:   (block $x (result i32)
  ;; CHECK-NEXT:    (nop)
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (i32.const 200)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (i32.const 300)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:   (block (result i32)
  ;; CHECK-NEXT:    (call $nothing)
  ;; CHECK-NEXT:    (local.get $x)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $restructure-br_if-value-effectful (param $x i32) (result i32)
    (block $x (result i32)
      (drop
        (br_if $x
          ;; the value has side effects, but we can use a select instead
          ;; of an if, which keeps the value first
          (block (result i32)
            (call $nothing)
            (i32.const 100)
          )
          ;; the condition has side effects too, but can be be reordered
          ;; to the end of the block
          (block (result i32)
            (call $nothing)
            (local.get $x)
          )
        )
      )
      (drop (i32.const 200))
      (i32.const 300)
    )
  )

  ;; CHECK:      (func $restructure-br_if-value-effectful-corner-case-1 (type $0) (param $x i32) (result i32)
  ;; CHECK-NEXT:  (block $x (result i32)
  ;; CHECK-NEXT:   (drop
  ;; CHECK-NEXT:    (br_if $x
  ;; CHECK-NEXT:     (block (result i32)
  ;; CHECK-NEXT:      (call $nothing)
  ;; CHECK-NEXT:      (i32.const 100)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:     (block (result i32)
  ;; CHECK-NEXT:      (call $nothing)
  ;; CHECK-NEXT:      (local.get $x)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:   (call $nothing)
  ;; CHECK-NEXT:   (i32.const 300)
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $restructure-br_if-value-effectful-corner-case-1 (param $x i32) (result i32)
    (block $x (result i32)
      (drop
        (br_if $x
          (block (result i32)
            (call $nothing)
            (i32.const 100)
          )
          (block (result i32)
            (call $nothing)
            (local.get $x)
          )
        )
      )
      ;; the condition cannot be reordered with this
      (call $nothing)
      (i32.const 300)
    )
  )

  ;; CHECK:      (func $get-i32 (type $2) (result i32)
  ;; CHECK-NEXT:  (i32.const 400)
  ;; CHECK-NEXT: )
  (func $get-i32 (result i32)
    (i32.const 400)
  )

  ;; CHECK:      (func $restructure-br_if-value-effectful-corner-case-2 (type $0) (param $x i32) (result i32)
  ;; CHECK-NEXT:  (block $x (result i32)
  ;; CHECK-NEXT:   (drop
  ;; CHECK-NEXT:    (br_if $x
  ;; CHECK-NEXT:     (block (result i32)
  ;; CHECK-NEXT:      (call $nothing)
  ;; CHECK-NEXT:      (i32.const 100)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:     (block (result i32)
  ;; CHECK-NEXT:      (call $nothing)
  ;; CHECK-NEXT:      (local.get $x)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:   (drop
  ;; CHECK-NEXT:    (i32.const 300)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:   (call $get-i32)
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $restructure-br_if-value-effectful-corner-case-2 (param $x i32) (result i32)
    (block $x (result i32)
      (drop
        (br_if $x
          (block (result i32)
            (call $nothing)
            (i32.const 100)
          )
          (block (result i32)
            (call $nothing)
            (local.get $x)
          )
        )
      )
      (drop (i32.const 300))
      ;; the condition cannot be reordered with this
      (call $get-i32)
    )
  )
  ;; CHECK:      (func $restructure-br_if-value-effectful-corner-case-3 (type $0) (param $x i32) (result i32)
  ;; CHECK-NEXT:  (block $x (result i32)
  ;; CHECK-NEXT:   (drop
  ;; CHECK-NEXT:    (br_if $x
  ;; CHECK-NEXT:     (block (result i32)
  ;; CHECK-NEXT:      (call $nothing)
  ;; CHECK-NEXT:      (i32.const 100)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:     (local.get $x)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:   (call $nothing)
  ;; CHECK-NEXT:   (i32.const 100)
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $restructure-br_if-value-effectful-corner-case-3 (param $x i32) (result i32)
    (block $x (result i32)
      (drop
        (br_if $x
          ;; we can't do an if because of effects here
          (block (result i32)
            (call $nothing)
            (i32.const 100)
          )
          (local.get $x)
        )
      )
      ;; and we can't do a select because of effects here
      (call $nothing)
      (i32.const 100)
    )
  )

  ;; CHECK:      (func $restructure-br_if-value-effectful-corner-case-4 (type $0) (param $x i32) (result i32)
  ;; CHECK-NEXT:  (block $x (result i32)
  ;; CHECK-NEXT:   (drop
  ;; CHECK-NEXT:    (br_if $x
  ;; CHECK-NEXT:     (block (result i32)
  ;; CHECK-NEXT:      (call $nothing)
  ;; CHECK-NEXT:      (i32.const 100)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:     (local.get $x)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:   (drop
  ;; CHECK-NEXT:    (i32.const 300)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:   (call $get-i32)
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $restructure-br_if-value-effectful-corner-case-4 (param $x i32) (result i32)
    (block $x (result i32)
      (drop
        (br_if $x
          ;; we can't do an if because of effects here
          (block (result i32)
            (call $nothing)
            (i32.const 100)
          )
          (local.get $x)
        )
      )
      (drop (i32.const 300))
      ;; and we can't do a select because of effects here
      (call $get-i32)
    )
  )

  ;; CHECK:      (func $restructure-br_if-constant-branch-1 (type $3) (param $x i32)
  ;; CHECK-NEXT:  (local $1 i32)
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (block $x (result i32)
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (block
  ;; CHECK-NEXT:      (local.set $1
  ;; CHECK-NEXT:       (local.tee $x
  ;; CHECK-NEXT:        (i32.const 42)
  ;; CHECK-NEXT:       )
  ;; CHECK-NEXT:      )
  ;; CHECK-NEXT:      (br $x
  ;; CHECK-NEXT:       (i32.const 10)
  ;; CHECK-NEXT:      )
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (i32.const 20)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (block $x0 (result i32)
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (block (result i32)
  ;; CHECK-NEXT:      (i32.const 10)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (i32.const 20)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $restructure-br_if-constant-branch-1 (param $x i32)
    ;;  We can see a nonzero constant falls through the tee, so this br always happens.
    (drop
      (block $x (result i32)
        (drop
          (br_if $x
            (i32.const 10)
            (local.tee $x
              (i32.const 42)
            )
          )
        )
        (i32.const 20)
      )
    )
    ;; We can see the zero condition, so just let the control flow fall through.
    (drop
      (block $x (result i32)
        (drop
          (br_if $x
            (i32.const 10)
            (i32.const 0)
          )
        )
        (i32.const 20)
      )
    )
  )
  ;; CHECK:      (func $restructure-br_if-constant-branch-2 (type $3) (param $x i32)
  ;; CHECK-NEXT:  (local $1 i32)
  ;; CHECK-NEXT:  (local $2 i32)
  ;; CHECK-NEXT:  (block $x
  ;; CHECK-NEXT:   (block
  ;; CHECK-NEXT:    (local.set $1
  ;; CHECK-NEXT:     (local.tee $x
  ;; CHECK-NEXT:      (i32.const 1)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (br $x)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (block $x0
  ;; CHECK-NEXT:   (block
  ;; CHECK-NEXT:    (local.set $2
  ;; CHECK-NEXT:     (local.tee $x
  ;; CHECK-NEXT:      (i32.const 0)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $restructure-br_if-constant-branch-2 (param $x i32)
    ;; as before, but now there is no value.
    (block $x
      (br_if $x
        (local.tee $x
          (i32.const 1)
        )
      )
    )
    (block $x
      (br_if $x
        (local.tee $x
          (i32.const 0)
        )
      )
    )
  )


  ;; CHECK:      (func $restructure-br_if-value-redundant-in-block-tail-1 (type $2) (result i32)
  ;; CHECK-NEXT:  (block $parent (result i32)
  ;; CHECK-NEXT:   (call $nothing)
  ;; CHECK-NEXT:   (drop
  ;; CHECK-NEXT:    (call $get-i32)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:   (i32.const 1)
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $restructure-br_if-value-redundant-in-block-tail-1 (result i32)
    ;; The br_if's value is equal to the value right after it, so we can remove it.
    (block $parent (result i32)
      (call $nothing)
      (drop
        (br_if $parent
          (i32.const 1)
          (call $get-i32)
        )
      )
      (i32.const 1)
    )
  )

  ;; CHECK:      (func $restructure-br_if-value-redundant-in-block-tail-2 (type $2) (result i32)
  ;; CHECK-NEXT:  (block $parent (result i32)
  ;; CHECK-NEXT:   (call $nothing)
  ;; CHECK-NEXT:   (drop
  ;; CHECK-NEXT:    (br_if $parent
  ;; CHECK-NEXT:     (i32.const 2)
  ;; CHECK-NEXT:     (call $get-i32)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:   (i32.const 1)
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $restructure-br_if-value-redundant-in-block-tail-2 (result i32)
    ;; As above, but now the value is different, so we do not optimize
    (block $parent (result i32)
      (call $nothing)
      (drop
        (br_if $parent
          (i32.const 2)
          (call $get-i32)
        )
      )
      (i32.const 1)
    )
  )

  ;; CHECK:      (func $restructure-br_if-value-redundant-in-block-tail-3 (type $0) (param $x i32) (result i32)
  ;; CHECK-NEXT:  (block $parent (result i32)
  ;; CHECK-NEXT:   (call $nothing)
  ;; CHECK-NEXT:   (drop
  ;; CHECK-NEXT:    (br_if $parent
  ;; CHECK-NEXT:     (call $get-i32)
  ;; CHECK-NEXT:     (call $get-i32)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:   (call $get-i32)
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $restructure-br_if-value-redundant-in-block-tail-3 (param $x i32) (result i32)
    ;; As above, but now the value has effects, so we do not optimize
    (block $parent (result i32)
      (call $nothing)
      (drop
        (br_if $parent
          (call $get-i32)
          (call $get-i32)
        )
      )
      (call $get-i32)
    )
  )

  ;; CHECK:      (func $restructure-br_if-value-redundant-in-block-tail-4 (type $2) (result i32)
  ;; CHECK-NEXT:  (block $outer (result i32)
  ;; CHECK-NEXT:   (block $inner (result i32)
  ;; CHECK-NEXT:    (call $nothing)
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (br_if $outer
  ;; CHECK-NEXT:      (i32.const 1)
  ;; CHECK-NEXT:      (call $get-i32)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (i32.const 1)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $restructure-br_if-value-redundant-in-block-tail-4 (result i32)
    ;; As above, but the br_if targets another block, so we do not optimize.
    (block $outer (result i32)
      (block $inner (result i32)
        (call $nothing)
        (drop
          (br_if $outer
            (i32.const 1)
            (call $get-i32)
          )
        )
        (i32.const 1)
      )
    )
  )

  ;; CHECK:      (func $restructure-br_if-value-redundant-in-block-tail-5 (type $2) (result i32)
  ;; CHECK-NEXT:  (block $parent (result i32)
  ;; CHECK-NEXT:   (call $nothing)
  ;; CHECK-NEXT:   (br $parent
  ;; CHECK-NEXT:    (i32.const 1)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:   (i32.const 1)
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $restructure-br_if-value-redundant-in-block-tail-5 (result i32)
    ;; As above, but the br lacks a condition. We do not bother to optimize
    ;; the dead code after it, but also should not error here.
    (block $parent (result i32)
      (call $nothing)
      (br $parent
        (i32.const 1)
      )
      (i32.const 1)
    )
  )

  ;; CHECK:      (func $restructure-br_if-condition-invalidates-6 (type $2) (result i32)
  ;; CHECK-NEXT:  (local $temp i32)
  ;; CHECK-NEXT:  (block $block (result i32)
  ;; CHECK-NEXT:   (drop
  ;; CHECK-NEXT:    (br_if $block
  ;; CHECK-NEXT:     (local.get $temp)
  ;; CHECK-NEXT:     (local.tee $temp
  ;; CHECK-NEXT:      (local.get $temp)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:   (local.get $temp)
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $restructure-br_if-condition-invalidates-6 (result i32)
    (local $temp i32)
    ;; The br value is syntactically identical to the value at the end of the
    ;; block, however, the local.tee changes that value so we cannot optimize.
    (block $block (result i32)
      (drop
        (br_if $block
          (local.get $temp)
          (local.tee $temp
            (local.get $temp)
          )
        )
      )
      (local.get $temp)
    )
  )

  ;; CHECK:      (func $restructure-select-no-multivalue (type $1)
  ;; CHECK-NEXT:  (local $x i32)
  ;; CHECK-NEXT:  (tuple.drop 2
  ;; CHECK-NEXT:   (block $block (type $5) (result i32 i32)
  ;; CHECK-NEXT:    (tuple.drop 2
  ;; CHECK-NEXT:     (br_if $block
  ;; CHECK-NEXT:      (tuple.make 2
  ;; CHECK-NEXT:       (i32.const 1)
  ;; CHECK-NEXT:       (call $restructure-br_if
  ;; CHECK-NEXT:        (i32.const 2)
  ;; CHECK-NEXT:       )
  ;; CHECK-NEXT:      )
  ;; CHECK-NEXT:      (local.get $x)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (tuple.make 2
  ;; CHECK-NEXT:     (i32.const 4)
  ;; CHECK-NEXT:     (i32.const 5)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $restructure-select-no-multivalue
    (local $x i32)
    (tuple.drop 2
      (block $block (result i32 i32)
        (tuple.drop 2
          (br_if $block
            (tuple.make 2
              (i32.const 1)
              ;; Add a side effect to prevent us turning $block into a
              ;; restructured if - instead, we will try a restructured select.
              ;; But, selects cannot return multiple values in the spec, so we
              ;; can do nothing here.
              (call $restructure-br_if
                (i32.const 2)
              )
            )
            (local.get $x)
          )
        )
        (tuple.make 2
          (i32.const 4)
          (i32.const 5)
        )
      )
    )
  )

  ;; CHECK:      (func $if-of-if (type $1)
  ;; CHECK-NEXT:  (local $x i32)
  ;; CHECK-NEXT:  (if
  ;; CHECK-NEXT:   (select
  ;; CHECK-NEXT:    (local.tee $x
  ;; CHECK-NEXT:     (i32.const 1)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (i32.const 0)
  ;; CHECK-NEXT:    (local.get $x)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:   (then
  ;; CHECK-NEXT:    (call $if-of-if)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $if-of-if
    (local $x i32)
    ;; The outer if has side effects in the condition while the inner one does
    ;; not, which means we can fold them.
    (if
      (local.tee $x
        (i32.const 1)
      )
      (then
        (if
          (local.get $x)
          (then
            (call $if-of-if)
          )
        )
      )
    )
  )

  ;; CHECK:      (func $if-of-if-but-side-effects (type $1)
  ;; CHECK-NEXT:  (local $x i32)
  ;; CHECK-NEXT:  (if
  ;; CHECK-NEXT:   (local.tee $x
  ;; CHECK-NEXT:    (i32.const 1)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:   (then
  ;; CHECK-NEXT:    (if
  ;; CHECK-NEXT:     (local.tee $x
  ;; CHECK-NEXT:      (i32.const 2)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:     (then
  ;; CHECK-NEXT:      (call $if-of-if-but-side-effects)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $if-of-if-but-side-effects
    (local $x i32)
    ;; The inner if has side effects in the condition, which prevents this
    ;; optimization.
    (if
      (local.tee $x
        (i32.const 1)
      )
      (then
        (if
          (local.tee $x
            (i32.const 2)
          )
          (then
            (call $if-of-if-but-side-effects)
          )
        )
      )
    )
  )

  ;; CHECK:      (func $if-of-if-but-too-costly (type $1)
  ;; CHECK-NEXT:  (local $x i32)
  ;; CHECK-NEXT:  (if
  ;; CHECK-NEXT:   (local.tee $x
  ;; CHECK-NEXT:    (i32.const 1)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:   (then
  ;; CHECK-NEXT:    (if
  ;; CHECK-NEXT:     (i32.eqz
  ;; CHECK-NEXT:      (i32.eqz
  ;; CHECK-NEXT:       (i32.eqz
  ;; CHECK-NEXT:        (i32.eqz
  ;; CHECK-NEXT:         (i32.eqz
  ;; CHECK-NEXT:          (i32.eqz
  ;; CHECK-NEXT:           (i32.eqz
  ;; CHECK-NEXT:            (i32.eqz
  ;; CHECK-NEXT:             (i32.eqz
  ;; CHECK-NEXT:              (local.get $x)
  ;; CHECK-NEXT:             )
  ;; CHECK-NEXT:            )
  ;; CHECK-NEXT:           )
  ;; CHECK-NEXT:          )
  ;; CHECK-NEXT:         )
  ;; CHECK-NEXT:        )
  ;; CHECK-NEXT:       )
  ;; CHECK-NEXT:      )
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:     (then
  ;; CHECK-NEXT:      (call $if-of-if-but-too-costly)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $if-of-if-but-too-costly
    (local $x i32)
    ;; The inner if's condition has no effects, but it is very costly, so do not
    ;; run it unconditionally - leave this unoptimized.
    (if
      (local.tee $x
        (i32.const 1)
      )
      (then
        (if
          (i32.eqz (i32.eqz (i32.eqz (i32.eqz (i32.eqz (i32.eqz (i32.eqz (i32.eqz (i32.eqz
            (local.get $x)
          )))))))))
          (then
            (call $if-of-if-but-too-costly)
          )
        )
      )
    )
  )

  ;; CHECK:      (func $if-of-if-but-inner-else (type $1)
  ;; CHECK-NEXT:  (local $x i32)
  ;; CHECK-NEXT:  (if
  ;; CHECK-NEXT:   (local.tee $x
  ;; CHECK-NEXT:    (i32.const 1)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:   (then
  ;; CHECK-NEXT:    (if
  ;; CHECK-NEXT:     (local.get $x)
  ;; CHECK-NEXT:     (then
  ;; CHECK-NEXT:      (call $if-of-if-but-inner-else)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:     (else
  ;; CHECK-NEXT:      (call $if-of-if)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $if-of-if-but-inner-else
    (local $x i32)
    ;; The inner if has an else. For now, leave this unoptimized.
    (if
      (local.tee $x
        (i32.const 1)
      )
      (then
        (if
          (local.get $x)
          (then
            (call $if-of-if-but-inner-else)
          )
          (else
            (call $if-of-if)
          )
        )
      )
    )
  )

  ;; CHECK:      (func $if-of-if-but-outer-else (type $1)
  ;; CHECK-NEXT:  (local $x i32)
  ;; CHECK-NEXT:  (if
  ;; CHECK-NEXT:   (local.tee $x
  ;; CHECK-NEXT:    (i32.const 1)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:   (then
  ;; CHECK-NEXT:    (if
  ;; CHECK-NEXT:     (local.get $x)
  ;; CHECK-NEXT:     (then
  ;; CHECK-NEXT:      (call $if-of-if-but-outer-else)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:   (else
  ;; CHECK-NEXT:    (call $if-of-if)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $if-of-if-but-outer-else
    (local $x i32)
    ;; The outer if has an else. For now, leave this unoptimized.
    (if
      (local.tee $x
        (i32.const 1)
      )
      (then
        (if
          (local.get $x)
          (then
            (call $if-of-if-but-outer-else)
          )
        )
      )
      (else
        (call $if-of-if)
      )
    )
  )

  ;; CHECK:      (func $unreachable-if (type $1)
  ;; CHECK-NEXT:  (block $block
  ;; CHECK-NEXT:   (if (result i32)
  ;; CHECK-NEXT:    (unreachable)
  ;; CHECK-NEXT:    (then
  ;; CHECK-NEXT:     (i32.const 0)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (else
  ;; CHECK-NEXT:     (br $block)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $unreachable-if
    ;; Regression test for a problem where blocks were sunk into ifs with
    ;; unreachable conditions, causing validation errors when the block type was
    ;; incompatible with the if type.
    (block $block
      (if (result i32)
        (unreachable)
        (then
          (i32.const 0)
        )
        (else
          (br $block)
        )
      )
    )
  )

  ;; CHECK:      (func $loop-with-unreachable-if (type $1)
  ;; CHECK-NEXT:  (loop $label
  ;; CHECK-NEXT:   (if (result i32)
  ;; CHECK-NEXT:    (unreachable)
  ;; CHECK-NEXT:    (then
  ;; CHECK-NEXT:     (unreachable)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (else
  ;; CHECK-NEXT:     (i32.const 0)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:   (br $label)
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $loop-with-unreachable-if
    ;; We normally move brs right after an if into one of the if arms, when
    ;; possible. That is almost possible here, but the if condition is
    ;; unreachable, which allows one of the arms to have a concrete type. It is
    ;; invalid to append to such an arm, so we should do nothing (leaving this
    ;; for DCE).
    (loop $label
      (if (result i32)
        (unreachable)
        (then
          (unreachable)
        )
        (else
          (i32.const 0)
        )
      )
      (br $label)
    )
  )
)
