;; NOTE: Assertions have been generated by update_lit_checks.py --all-items and should not be edited.
;; NOTE: This test was ported using port_passes_tests_to_lit.py and could be cleaned up.

;; RUN: foreach %s %t wasm-opt --simplify-globals -S -o - | filecheck %s

;; A global that is only read in order to be written is not needed.
(module
  ;; CHECK:      (type $0 (func))

  ;; CHECK:      (global $global i32 (i32.const 0))
  (global $global (mut i32) (i32.const 0))
  ;; CHECK:      (func $simple
  ;; CHECK-NEXT:  (if
  ;; CHECK-NEXT:   (i32.const 0)
  ;; CHECK-NEXT:   (then
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (i32.const 1)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $simple
    (if
      (global.get $global)
      (then
        (global.set $global (i32.const 1))
      )
    )
  )
  ;; CHECK:      (func $more-with-no-side-effects
  ;; CHECK-NEXT:  (if
  ;; CHECK-NEXT:   (i32.eqz
  ;; CHECK-NEXT:    (i32.const 0)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:   (then
  ;; CHECK-NEXT:    (nop)
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (i32.const 1)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $more-with-no-side-effects
    (if
      ;; Also test for other operations in the condition, with no effects.
      (i32.eqz
        (global.get $global)
      )
      ;; Also test for other operations in the body, with no effects.
      (then
        (block
          (nop)
          (global.set $global (i32.const 1))
        )
      )
    )
  )
  ;; CHECK:      (func $additional-set
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (i32.const 2)
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $additional-set
    ;; An additional set does not prevent this optimization: the value written
    ;; will never be read in a way that matters.
    (global.set $global (i32.const 2))
  )
)
;; An additional read prevents the read-only-to-write optimization.
(module
  ;; CHECK:      (type $0 (func))

  ;; CHECK:      (global $global (mut i32) (i32.const 0))
  (global $global (mut i32) (i32.const 0))
  ;; CHECK:      (func $additional-read
  ;; CHECK-NEXT:  (if
  ;; CHECK-NEXT:   (global.get $global)
  ;; CHECK-NEXT:   (then
  ;; CHECK-NEXT:    (global.set $global
  ;; CHECK-NEXT:     (i32.const 1)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (global.get $global)
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $additional-read
    (if
      (global.get $global)
      (then
        (global.set $global (i32.const 1))
      )
    )
    (drop
      (global.get $global)
    )
  )
)
;; We do not optimize if-elses in the read-only-to-write optimization.
(module
  ;; CHECK:      (type $0 (func))

  ;; CHECK:      (global $global (mut i32) (i32.const 0))
  (global $global (mut i32) (i32.const 0))
  ;; CHECK:      (func $if-else
  ;; CHECK-NEXT:  (if
  ;; CHECK-NEXT:   (global.get $global)
  ;; CHECK-NEXT:   (then
  ;; CHECK-NEXT:    (global.set $global
  ;; CHECK-NEXT:     (i32.const 1)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:   (else
  ;; CHECK-NEXT:    (nop)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $if-else
    (if
      (global.get $global)
      (then
        (global.set $global (i32.const 1))
      )
      (else
        (nop)
      )
    )
  )
)
;; Side effects in the body prevent the read-only-to-write optimization.
(module
  ;; CHECK:      (type $0 (func))

  ;; CHECK:      (global $global (mut i32) (i32.const 0))
  (global $global (mut i32) (i32.const 0))
  ;; CHECK:      (global $other (mut i32) (i32.const 0))
  (global $other (mut i32) (i32.const 0))
  ;; CHECK:      (func $side-effects-in-body
  ;; CHECK-NEXT:  (if
  ;; CHECK-NEXT:   (global.get $global)
  ;; CHECK-NEXT:   (then
  ;; CHECK-NEXT:    (global.set $global
  ;; CHECK-NEXT:     (i32.const 1)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (global.set $other
  ;; CHECK-NEXT:     (i32.const 2)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (i32.const 2)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $side-effects-in-body
    (if
      (global.get $global)
      (then
        (block
          (global.set $global (i32.const 1))
          (global.set $other (i32.const 2))
          (drop (global.get $other))
        )
      )
    )
  )
)
;; Nested patterns work as well, in a single run of the pass.
(module
  ;; CHECK:      (type $0 (func))

  ;; CHECK:      (global $a i32 (i32.const 0))
  (global $a (mut i32) (i32.const 0))
  ;; CHECK:      (global $b i32 (i32.const 0))
  (global $b (mut i32) (i32.const 0))
  ;; CHECK:      (global $c i32 (i32.const 0))
  (global $c (mut i32) (i32.const 0))

  ;; CHECK:      (func $nested
  ;; CHECK-NEXT:  (if
  ;; CHECK-NEXT:   (i32.const 0)
  ;; CHECK-NEXT:   (then
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (i32.const 1)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (if
  ;; CHECK-NEXT:     (i32.const 0)
  ;; CHECK-NEXT:     (then
  ;; CHECK-NEXT:      (if
  ;; CHECK-NEXT:       (i32.const 0)
  ;; CHECK-NEXT:       (then
  ;; CHECK-NEXT:        (drop
  ;; CHECK-NEXT:         (i32.const 2)
  ;; CHECK-NEXT:        )
  ;; CHECK-NEXT:       )
  ;; CHECK-NEXT:      )
  ;; CHECK-NEXT:      (drop
  ;; CHECK-NEXT:       (i32.const 3)
  ;; CHECK-NEXT:      )
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $nested
    (if
      (global.get $a)
      (then
        (block
          (global.set $a (i32.const 1))
          (if
            (global.get $b)
            (then
              (block
                (if
                  (global.get $c)
                  (then
                    (block
                      (global.set $c (i32.const 2))
                    )
                  )
                )
                (global.set $b (i32.const 3))
              )
            )
          )
        )
      )
    )
  )
)

(module
  ;; CHECK:      (type $0 (func))

  ;; CHECK:      (global $once i32 (i32.const 0))
  (global $once (mut i32) (i32.const 0))

  ;; CHECK:      (func $clinit
  ;; CHECK-NEXT:  (if
  ;; CHECK-NEXT:   (i32.const 0)
  ;; CHECK-NEXT:   (then
  ;; CHECK-NEXT:    (return)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (i32.const 1)
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $clinit
    ;; A read-only-to-write that takes an entire function body, and is in the
    ;; form if "if already set, return; set it". In particular, the set is not
    ;; in the if body in this case.
    (if
      (global.get $once)
      (then
        (return)
      )
    )
    (global.set $once
      (i32.const 1)
    )
  )
)

(module
  ;; CHECK:      (type $0 (func))

  ;; CHECK:      (global $once (mut i32) (i32.const 0))
  (global $once (mut i32) (i32.const 0))

  ;; CHECK:      (func $clinit
  ;; CHECK-NEXT:  (if
  ;; CHECK-NEXT:   (global.get $once)
  ;; CHECK-NEXT:   (then
  ;; CHECK-NEXT:    (return)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (global.set $once
  ;; CHECK-NEXT:   (i32.const 1)
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (nop)
  ;; CHECK-NEXT: )
  (func $clinit
    ;; As above, but the optimization fails because the function body has too
    ;; many elements - a nop is added at the end.
    (if
      (global.get $once)
      (then
        (return)
      )
    )
    (global.set $once
      (i32.const 1)
    )
    (nop)
  )
)

(module
  ;; CHECK:      (type $0 (func))

  ;; CHECK:      (global $once (mut i32) (i32.const 0))
  (global $once (mut i32) (i32.const 0))

  ;; CHECK:      (func $clinit
  ;; CHECK-NEXT:  (if
  ;; CHECK-NEXT:   (global.get $once)
  ;; CHECK-NEXT:   (then
  ;; CHECK-NEXT:    (return)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:   (else
  ;; CHECK-NEXT:    (nop)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (global.set $once
  ;; CHECK-NEXT:   (i32.const 1)
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $clinit
    ;; As above, but the optimization fails because the if has an else.
    (if
      (global.get $once)
      (then
        (return)
      )
      (else
        (nop)
      )
    )
    (global.set $once
      (i32.const 1)
    )
  )
)

(module
  ;; CHECK:      (type $0 (func))

  ;; CHECK:      (global $once (mut i32) (i32.const 0))
  (global $once (mut i32) (i32.const 0))

  ;; CHECK:      (func $clinit
  ;; CHECK-NEXT:  (if
  ;; CHECK-NEXT:   (global.get $once)
  ;; CHECK-NEXT:   (then
  ;; CHECK-NEXT:    (nop)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (global.set $once
  ;; CHECK-NEXT:   (i32.const 1)
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $clinit
    ;; As above, but the optimization fails because the if body is not a
    ;; return.
    (if
      (global.get $once)
      (then
        (nop)
      )
    )
    (global.set $once
      (i32.const 1)
    )
  )
)

(module
  ;; CHECK:      (type $0 (func))

  ;; CHECK:      (type $1 (func (param i32) (result i32)))

  ;; CHECK:      (global $once (mut i32) (i32.const 0))
  (global $once (mut i32) (i32.const 0))

  ;; CHECK:      (func $clinit
  ;; CHECK-NEXT:  (if
  ;; CHECK-NEXT:   (call $foo
  ;; CHECK-NEXT:    (global.get $once)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:   (then
  ;; CHECK-NEXT:    (return)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (global.set $once
  ;; CHECK-NEXT:   (i32.const 1)
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $clinit
    ;; As above, but the optimization fails because the if condition has effects.
    (if
      (call $foo ;; This call may have side effects and it receives the global's
                 ;; value, which is dangerous.
        (global.get $once)
      )
      (then
        (return)
      )
    )
    (global.set $once
      (i32.const 1)
    )
  )

  ;; CHECK:      (func $foo (param $x i32) (result i32)
  ;; CHECK-NEXT:  (unreachable)
  ;; CHECK-NEXT: )
  (func $foo (param $x i32) (result i32)
    (unreachable)
  )
)

;; Using the global's value in a way that can cause side effects prevents the
;; read-only-to-write optimization.
(module
  ;; CHECK:      (type $0 (func))

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

  ;; CHECK:      (global $global (mut i32) (i32.const 0))
  (global $global (mut i32) (i32.const 0))
  ;; CHECK:      (global $other i32 (i32.const 0))
  (global $other (mut i32) (i32.const 0))
  ;; CHECK:      (func $side-effects-in-condition
  ;; CHECK-NEXT:  (if
  ;; CHECK-NEXT:   (if (result i32)
  ;; CHECK-NEXT:    (global.get $global)
  ;; CHECK-NEXT:    (then
  ;; CHECK-NEXT:     (call $foo)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (else
  ;; CHECK-NEXT:     (i32.const 1)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:   (then
  ;; CHECK-NEXT:    (global.set $global
  ;; CHECK-NEXT:     (i32.const 1)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $side-effects-in-condition
    (if
      (if (result i32)
        (global.get $global) ;; the global's value may cause foo() to be called
        (then
          (call $foo)
        )
        (else
          (i32.const 1)
        )
      )
      (then
        (global.set $global (i32.const 1))
      )
    )
  )

  ;; CHECK:      (func $foo (result i32)
  ;; CHECK-NEXT:  (unreachable)
  ;; CHECK-NEXT: )
  (func $foo (result i32)
    (unreachable)
  )
)

;; As above, but now the global's value is not the condition of the if, so there
;; is no problem.
(module
  ;; CHECK:      (type $0 (func))

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

  ;; CHECK:      (global $global i32 (i32.const 0))
  (global $global (mut i32) (i32.const 0))
  ;; CHECK:      (global $other i32 (i32.const 0))
  (global $other (mut i32) (i32.const 0))
  ;; CHECK:      (func $side-effects-in-condition-2
  ;; CHECK-NEXT:  (if
  ;; CHECK-NEXT:   (if (result i32)
  ;; CHECK-NEXT:    (call $foo)
  ;; CHECK-NEXT:    (then
  ;; CHECK-NEXT:     (i32.const 1)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (else
  ;; CHECK-NEXT:     (i32.const 0)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:   (then
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (i32.const 1)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $side-effects-in-condition-2
    (if
      (if (result i32)
        (call $foo) ;; these side effects are not a problem, as the global's
                    ;; value cannot reach them.
        (then
          (i32.const 1)
        )
        (else
          (global.get $global) ;; the global's value flows out through the if,
        )
                             ;; safely
      )
      (then
        (global.set $global (i32.const 1))
      )
    )
  )

  ;; CHECK:      (func $foo (result i32)
  ;; CHECK-NEXT:  (unreachable)
  ;; CHECK-NEXT: )
  (func $foo (result i32)
    (unreachable)
  )
)

;; As above, but now the global's value flows into a side effect.
(module
  ;; CHECK:      (type $0 (func))

  ;; CHECK:      (global $global (mut i32) (i32.const 0))
  (global $global (mut i32) (i32.const 0))
  ;; CHECK:      (global $other i32 (i32.const 0))
  (global $other (mut i32) (i32.const 0))
  ;; CHECK:      (func $side-effects-in-condition-3
  ;; CHECK-NEXT:  (local $temp i32)
  ;; CHECK-NEXT:  (if
  ;; CHECK-NEXT:   (local.tee $temp
  ;; CHECK-NEXT:    (global.get $global)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:   (then
  ;; CHECK-NEXT:    (global.set $global
  ;; CHECK-NEXT:     (i32.const 1)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $side-effects-in-condition-3
    (local $temp i32)
    (if
      (local.tee $temp
        (global.get $global) ;; the global's value flows into a place that has
      )                      ;; side effects, so it may be noticed.
      (then
        (global.set $global (i32.const 1))
      )
    )
  )
)

;; As above, but now the global's value flows through multiple layers of
;; things that have no side effects and are safe.
(module
  (memory 1 1)

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

  ;; CHECK:      (global $once i32 (i32.const 0))
  (global $once (mut i32) (i32.const 0))

  ;; CHECK:      (memory $0 1 1)

  ;; CHECK:      (func $side-effects-in-condition-4
  ;; CHECK-NEXT:  (local $x i32)
  ;; CHECK-NEXT:  (local $y i32)
  ;; CHECK-NEXT:  (if
  ;; CHECK-NEXT:   (i32.eqz
  ;; CHECK-NEXT:    (select
  ;; CHECK-NEXT:     (local.tee $x
  ;; CHECK-NEXT:      (i32.const 1)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:     (i32.load
  ;; CHECK-NEXT:      (i32.const 2)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:     (i32.add
  ;; CHECK-NEXT:      (i32.const 0)
  ;; CHECK-NEXT:      (i32.const 1337)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:   (then
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (i32.const 1)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $side-effects-in-condition-4
    (local $x i32)
    (local $y i32)
    (if
      (i32.eqz
        (select
          (local.tee $x
            (i32.const 1)
          )
          (i32.load
            (i32.const 2)
          )
          (i32.add
            (global.get $once)
            (i32.const 1337)
          )
        )
      )
      (then
        (global.set $once
          (i32.const 1)
        )
      )
    )
  )
)

(module
  (memory 1 1)

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

  ;; CHECK:      (global $once i32 (i32.const 0))
  (global $once (mut i32) (i32.const 0))

  ;; CHECK:      (memory $0 1 1)

  ;; CHECK:      (func $nested-pattern
  ;; CHECK-NEXT:  (local $x i32)
  ;; CHECK-NEXT:  (local $y i32)
  ;; CHECK-NEXT:  (if
  ;; CHECK-NEXT:   (block (result i32)
  ;; CHECK-NEXT:    (if
  ;; CHECK-NEXT:     (i32.eqz
  ;; CHECK-NEXT:      (i32.const 0)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:     (then
  ;; CHECK-NEXT:      (drop
  ;; CHECK-NEXT:       (i32.const 1)
  ;; CHECK-NEXT:      )
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (i32.eq
  ;; CHECK-NEXT:     (i32.const 0)
  ;; CHECK-NEXT:     (i32.const 0)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:   (then
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (i32.const 1)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $nested-pattern
    (local $x i32)
    (local $y i32)
    (if
      (block (result i32)
        ;; Another appearance of the pattern nested inside this one. This should
        ;; not prevent us from optimizing.
        (if
          (i32.eqz
            (global.get $once)
          )
          (then
            (global.set $once
              (i32.const 1)
            )
          )
        )
        (i32.eq
          (global.get $once)
          (i32.const 0)
        )
      )
      (then
        (global.set $once
          (i32.const 1)
        )
      )
    )
  )
)

(module
  (memory 1 1)

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

  ;; CHECK:      (global $once (mut i32) (i32.const 0))
  (global $once (mut i32) (i32.const 0))

  ;; CHECK:      (memory $0 1 1)

  ;; CHECK:      (func $almost-nested-pattern
  ;; CHECK-NEXT:  (local $x i32)
  ;; CHECK-NEXT:  (local $y i32)
  ;; CHECK-NEXT:  (if
  ;; CHECK-NEXT:   (block (result i32)
  ;; CHECK-NEXT:    (if
  ;; CHECK-NEXT:     (i32.eqz
  ;; CHECK-NEXT:      (global.get $once)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:     (then
  ;; CHECK-NEXT:      (global.set $once
  ;; CHECK-NEXT:       (i32.const 1)
  ;; CHECK-NEXT:      )
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:     (else
  ;; CHECK-NEXT:      (nop)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (i32.eq
  ;; CHECK-NEXT:     (global.get $once)
  ;; CHECK-NEXT:     (i32.const 0)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:   (then
  ;; CHECK-NEXT:    (global.set $once
  ;; CHECK-NEXT:     (i32.const 1)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $almost-nested-pattern
    (local $x i32)
    (local $y i32)
    (if
      (block (result i32)
        ;; This is almost the nested pattern, but not quite, as it has an
        ;; "else" arm.
        (if
          (i32.eqz
            (global.get $once)
          )
          (then
            (global.set $once
              (i32.const 1)
            )
          )
          (else
            (nop) ;; This breaks the pattern we are looking for.
          )
        )
        (i32.eq
          (global.get $once)
          (i32.const 0)
        )
      )
      (then
        (global.set $once
          (i32.const 1)
        )
      )
    )
  )
)

(module
  (memory 1 1)

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

  ;; CHECK:      (global $once i32 (i32.const 0))
  (global $once (mut i32) (i32.const 0))

  ;; CHECK:      (memory $0 1 1)

  ;; CHECK:      (func $nested-pattern-thrice
  ;; CHECK-NEXT:  (local $x i32)
  ;; CHECK-NEXT:  (local $y i32)
  ;; CHECK-NEXT:  (if
  ;; CHECK-NEXT:   (block (result i32)
  ;; CHECK-NEXT:    (if
  ;; CHECK-NEXT:     (i32.eqz
  ;; CHECK-NEXT:      (block (result i32)
  ;; CHECK-NEXT:       (if
  ;; CHECK-NEXT:        (i32.const 0)
  ;; CHECK-NEXT:        (then
  ;; CHECK-NEXT:         (drop
  ;; CHECK-NEXT:          (i32.const 1)
  ;; CHECK-NEXT:         )
  ;; CHECK-NEXT:        )
  ;; CHECK-NEXT:       )
  ;; CHECK-NEXT:       (i32.const 0)
  ;; CHECK-NEXT:      )
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:     (then
  ;; CHECK-NEXT:      (drop
  ;; CHECK-NEXT:       (i32.const 1)
  ;; CHECK-NEXT:      )
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (i32.eq
  ;; CHECK-NEXT:     (i32.const 0)
  ;; CHECK-NEXT:     (i32.const 0)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:   (then
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (i32.const 1)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $nested-pattern-thrice
    (local $x i32)
    (local $y i32)
    (if
      (block (result i32)
        (if
          (i32.eqz
            (block (result i32)
              ;; A third nested appearance.
              (if
                (global.get $once)
                (then
                  (global.set $once
                    (i32.const 1)
                  )
                )
              )
              (global.get $once)
            )
          )
          (then
            (global.set $once
              (i32.const 1)
            )
          )
        )
        (i32.eq
          (global.get $once)
          (i32.const 0)
        )
      )
      (then
        (global.set $once
          (i32.const 1)
        )
      )
    )
  )
)

(module
  (memory 1 1)

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

  ;; CHECK:      (global $once (mut i32) (i32.const 0))
  (global $once (mut i32) (i32.const 0))

  ;; CHECK:      (memory $0 1 1)

  ;; CHECK:      (func $nested-pattern
  ;; CHECK-NEXT:  (local $x i32)
  ;; CHECK-NEXT:  (local $y i32)
  ;; CHECK-NEXT:  (if
  ;; CHECK-NEXT:   (block (result i32)
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (global.get $once)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (if
  ;; CHECK-NEXT:     (i32.eqz
  ;; CHECK-NEXT:      (global.get $once)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:     (then
  ;; CHECK-NEXT:      (global.set $once
  ;; CHECK-NEXT:       (i32.const 1)
  ;; CHECK-NEXT:      )
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (i32.eq
  ;; CHECK-NEXT:     (global.get $once)
  ;; CHECK-NEXT:     (i32.const 0)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:   (then
  ;; CHECK-NEXT:    (global.set $once
  ;; CHECK-NEXT:     (i32.const 1)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $nested-pattern
    (local $x i32)
    (local $y i32)
    (if
      (block (result i32)

        ;; As above, but adding a drop of another get. This is *not* the
        ;; pattern we are looking for, and it will prevent us from
        ;; optimizing as we will no longer see that the number of gets
        ;; matches the number of read-only-to-write patterns. In the
        ;; future we could do a more complex counting operation to handle
        ;; this too.
        (drop
          (global.get $once)
        )

        (if
          (i32.eqz
            (global.get $once)
          )
          (then
            (global.set $once
              (i32.const 1)
            )
          )
        )
        (i32.eq
          (global.get $once)
          (i32.const 0)
        )
      )
      (then
        (global.set $once
          (i32.const 1)
        )
      )
    )
  )
)
