;; NOTE: Assertions have been generated by update_lit_checks.py and should not be edited.
;; RUN: wasm-opt %s --remove-unused-names --heap-store-optimization -all -S -o - \
;; RUN:   | filecheck %s
;;
;; --remove-unused-names allows the optimizer to see that the blocks have no
;; breaks to them, and so they have no nonlinear control flow.

(module
  ;; CHECK:      (type $struct (struct (field (mut i32))))

  ;; CHECK:      (type $struct2 (struct (field (mut i32)) (field (mut i32))))

  ;; CHECK:      (type $struct3 (struct (field (mut i32)) (field (mut i32)) (field (mut i32))))

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

  (type $struct (struct (field (mut i32))))

  (type $struct2 (struct (field (mut i32)) (field (mut i32))))

  (type $struct3 (struct (field (mut i32)) (field (mut i32)) (field (mut i32))))

  ;; CHECK:      (func $tee (type $1)
  ;; CHECK-NEXT:  (local $ref (ref null $struct))
  ;; CHECK-NEXT:  (local.set $ref
  ;; CHECK-NEXT:   (struct.new $struct
  ;; CHECK-NEXT:    (i32.const 20)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $tee
    (local $ref (ref null $struct))
    ;; The set is not needed as we can apply the 20 in the new.
    (struct.set $struct 0
      (local.tee $ref
        (struct.new $struct
          (i32.const 10)
        )
      )
      (i32.const 20)
    )
  )

  ;; CHECK:      (func $side-effects-in-old-value (type $1)
  ;; CHECK-NEXT:  (local $ref (ref null $struct))
  ;; CHECK-NEXT:  (local.set $ref
  ;; CHECK-NEXT:   (struct.new $struct
  ;; CHECK-NEXT:    (block (result i32)
  ;; CHECK-NEXT:     (drop
  ;; CHECK-NEXT:      (call $helper-i32
  ;; CHECK-NEXT:       (i32.const 0)
  ;; CHECK-NEXT:      )
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:     (i32.const 20)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $side-effects-in-old-value
    (local $ref (ref null $struct))
    (struct.set $struct 0
      (local.tee $ref
        (struct.new $struct
          ;; Side effects here force us to keep the old value around.
          (call $helper-i32 (i32.const 0))
        )
      )
      (i32.const 20)
    )
  )

  ;; CHECK:      (func $side-effects-in-new-value (type $1)
  ;; CHECK-NEXT:  (local $ref (ref null $struct))
  ;; CHECK-NEXT:  (local.set $ref
  ;; CHECK-NEXT:   (struct.new $struct
  ;; CHECK-NEXT:    (call $helper-i32
  ;; CHECK-NEXT:     (i32.const 0)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $side-effects-in-new-value
    (local $ref (ref null $struct))
    (struct.set $struct 0
      (local.tee $ref
        (struct.new $struct
          (i32.const 10)
        )
      )
      ;; Side effects here are not a problem.
      (call $helper-i32 (i32.const 0))
    )
  )

  ;; CHECK:      (func $many-fields (type $1)
  ;; CHECK-NEXT:  (local $ref (ref null $struct2))
  ;; CHECK-NEXT:  (local.set $ref
  ;; CHECK-NEXT:   (struct.new $struct2
  ;; CHECK-NEXT:    (i32.const 30)
  ;; CHECK-NEXT:    (i32.const 20)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (local.set $ref
  ;; CHECK-NEXT:   (struct.new $struct2
  ;; CHECK-NEXT:    (i32.const 40)
  ;; CHECK-NEXT:    (i32.const 60)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $many-fields
    (local $ref (ref null $struct2))
    ;; Set to the first field.
    (struct.set $struct2 0
      (local.tee $ref
        (struct.new $struct2
          (i32.const 10)
          (i32.const 20)
        )
      )
      (i32.const 30)
    )
    ;; Set to the second.
    (struct.set $struct2 1
      (local.tee $ref
        (struct.new $struct2
          (i32.const 40)
          (i32.const 50)
        )
      )
      (i32.const 60)
    )
  )

  ;; CHECK:      (func $side-effect-conflict (type $1)
  ;; CHECK-NEXT:  (local $ref (ref null $struct2))
  ;; CHECK-NEXT:  (struct.set $struct2 0
  ;; CHECK-NEXT:   (local.tee $ref
  ;; CHECK-NEXT:    (struct.new $struct2
  ;; CHECK-NEXT:     (i32.const 10)
  ;; CHECK-NEXT:     (call $helper-i32
  ;; CHECK-NEXT:      (i32.const 0)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:   (call $helper-i32
  ;; CHECK-NEXT:    (i32.const 1)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $side-effect-conflict
    (local $ref (ref null $struct2))
    (struct.set $struct2 0
      (local.tee $ref
        (struct.new $struct2
          (i32.const 10)
          ;; Side effects on the second field prevent us from moving the set's
          ;; value past it to replace the first field above it.
          (call $helper-i32 (i32.const 0))
        )
      )
      (call $helper-i32 (i32.const 1))
    )
  )

  ;; CHECK:      (func $side-effect-ok (type $1)
  ;; CHECK-NEXT:  (local $ref (ref null $struct2))
  ;; CHECK-NEXT:  (local.set $ref
  ;; CHECK-NEXT:   (struct.new $struct2
  ;; CHECK-NEXT:    (block (result i32)
  ;; CHECK-NEXT:     (drop
  ;; CHECK-NEXT:      (call $helper-i32
  ;; CHECK-NEXT:       (i32.const 0)
  ;; CHECK-NEXT:      )
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:     (call $helper-i32
  ;; CHECK-NEXT:      (i32.const 1)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (i32.const 10)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $side-effect-ok
    (local $ref (ref null $struct2))
    (struct.set $struct2 0
      (local.tee $ref
        (struct.new $struct2
          ;; Side effects on the first field do not interfere.
          (call $helper-i32 (i32.const 0))
          (i32.const 10)
        )
      )
      (call $helper-i32 (i32.const 1))
    )
  )

  ;; CHECK:      (func $optimize-subsequent (type $1)
  ;; CHECK-NEXT:  (local $ref (ref null $struct))
  ;; CHECK-NEXT:  (local.set $ref
  ;; CHECK-NEXT:   (struct.new $struct
  ;; CHECK-NEXT:    (i32.const 20)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (nop)
  ;; CHECK-NEXT: )
  (func $optimize-subsequent
    (local $ref (ref null $struct))
    (local.set $ref
      (struct.new $struct
        (i32.const 10)
      )
    )
    ;; A set that comes right after can be optimized too.
    (struct.set $struct 0
      (local.get $ref)
      (i32.const 20)
    )
  )

  ;; CHECK:      (func $optimize-subsequent-bad-local (type $1)
  ;; CHECK-NEXT:  (local $ref (ref null $struct))
  ;; CHECK-NEXT:  (local $other (ref null $struct))
  ;; CHECK-NEXT:  (local.set $ref
  ;; CHECK-NEXT:   (struct.new $struct
  ;; CHECK-NEXT:    (i32.const 10)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (struct.set $struct 0
  ;; CHECK-NEXT:   (local.get $other)
  ;; CHECK-NEXT:   (i32.const 20)
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $optimize-subsequent-bad-local
    (local $ref (ref null $struct))
    (local $other (ref null $struct))
    (local.set $ref
      (struct.new $struct
        (i32.const 10)
      )
    )
    ;; As above, but the local.get uses a different local, so we have nothing
    ;; to optimize.
    (struct.set $struct 0
      (local.get $other)
      (i32.const 20)
    )
  )

  ;; CHECK:      (func $optimize-chain (type $1)
  ;; CHECK-NEXT:  (local $ref (ref null $struct))
  ;; CHECK-NEXT:  (local.set $ref
  ;; CHECK-NEXT:   (struct.new $struct
  ;; CHECK-NEXT:    (i32.const 30)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (nop)
  ;; CHECK-NEXT:  (nop)
  ;; CHECK-NEXT: )
  (func $optimize-chain
    (local $ref (ref null $struct))
    (local.set $ref
      (struct.new $struct
        (i32.const 10)
      )
    )
    (struct.set $struct 0
      (local.get $ref)
      (i32.const 20)
    )
    ;; The value in the last item in the chain should apply.
    (struct.set $struct 0
      (local.get $ref)
      (i32.const 30)
    )
  )

  ;; CHECK:      (func $pattern-breaker (type $1)
  ;; CHECK-NEXT:  (local $ref (ref null $struct))
  ;; CHECK-NEXT:  (local $ref2 (ref null $struct))
  ;; CHECK-NEXT:  (local.set $ref
  ;; CHECK-NEXT:   (struct.new $struct
  ;; CHECK-NEXT:    (i32.const 10)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (local.set $ref2
  ;; CHECK-NEXT:   (local.get $ref)
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (struct.set $struct 0
  ;; CHECK-NEXT:   (local.get $ref)
  ;; CHECK-NEXT:   (i32.const 20)
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $pattern-breaker
    (local $ref (ref null $struct))
    (local $ref2 (ref null $struct))
    (local.set $ref
      (struct.new $struct
        (i32.const 10)
      )
    )
    ;; Any instruction that can not be swapped and is not
    ;; the expected struct.set breaks the pattern.
    (local.set $ref2 (local.get $ref))
    (struct.set $struct 0
      (local.get $ref)
      (i32.const 20)
    )
  )

  ;; CHECK:      (func $dont-swap-subsequent-struct-new (type $1)
  ;; CHECK-NEXT:  (local $ref (ref null $struct))
  ;; CHECK-NEXT:  (local $ref2 (ref null $struct))
  ;; CHECK-NEXT:  (nop)
  ;; CHECK-NEXT:  (local.set $ref
  ;; CHECK-NEXT:   (struct.new $struct
  ;; CHECK-NEXT:    (i32.const 10)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (local.set $ref2
  ;; CHECK-NEXT:   (struct.new $struct
  ;; CHECK-NEXT:    (i32.const 20)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (struct.set $struct 0
  ;; CHECK-NEXT:   (local.get $ref)
  ;; CHECK-NEXT:   (i32.const 20)
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $dont-swap-subsequent-struct-new
    (local $ref (ref null $struct))
    (local $ref2 (ref null $struct))
    (local.set $ref
      (struct.new $struct
        (i32.const 10)
      )
    )
    (nop)
    ;; We do not swap with another local.set of struct.new.
    (local.set $ref2
      (struct.new $struct
        (i32.const 20)
      )
    )
    ;; last instruction in the block won't be swapped.
    (struct.set $struct 0
      (local.get $ref)
      (i32.const 20)
    )
  )

  ;; CHECK:      (func $ref-local-write (type $1)
  ;; CHECK-NEXT:  (local $ref (ref null $struct))
  ;; CHECK-NEXT:  (local.set $ref
  ;; CHECK-NEXT:   (struct.new $struct
  ;; CHECK-NEXT:    (i32.const 10)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (struct.set $struct 0
  ;; CHECK-NEXT:   (local.get $ref)
  ;; CHECK-NEXT:   (block (result i32)
  ;; CHECK-NEXT:    (local.set $ref
  ;; CHECK-NEXT:     (ref.null none)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (i32.const 20)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $ref-local-write
    (local $ref (ref null $struct))
    (local.set $ref
      (struct.new $struct
        (i32.const 10)
      )
    )
    (struct.set $struct 0
      (local.get $ref)
      (block (result i32)
        ;; A write to the ref local prevents us from optimizing.
        (local.set $ref
          (ref.null $struct)
        )
        (i32.const 20)
      )
    )
  )

  ;; CHECK:      (func $ref-local-write-tee (type $1)
  ;; CHECK-NEXT:  (local $ref (ref null $struct))
  ;; CHECK-NEXT:  (struct.set $struct 0
  ;; CHECK-NEXT:   (local.tee $ref
  ;; CHECK-NEXT:    (struct.new $struct
  ;; CHECK-NEXT:     (i32.const 10)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:   (block (result i32)
  ;; CHECK-NEXT:    (local.set $ref
  ;; CHECK-NEXT:     (ref.null none)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (i32.const 20)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $ref-local-write-tee
    (local $ref (ref null $struct))
    (struct.set $struct 0
      (local.tee $ref
        (struct.new $struct
          (i32.const 10)
        )
      )
      (block (result i32)
        ;; As above, but now in a tee.
        (local.set $ref
          (ref.null $struct)
        )
        (i32.const 20)
      )
    )
  )

  ;; CHECK:      (func $other-local-write (type $1)
  ;; CHECK-NEXT:  (local $ref (ref null $struct))
  ;; CHECK-NEXT:  (local $other (ref null $struct))
  ;; CHECK-NEXT:  (local.set $ref
  ;; CHECK-NEXT:   (struct.new $struct
  ;; CHECK-NEXT:    (block (result i32)
  ;; CHECK-NEXT:     (local.set $other
  ;; CHECK-NEXT:      (ref.null none)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:     (i32.const 20)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (nop)
  ;; CHECK-NEXT: )
  (func $other-local-write
    (local $ref (ref null $struct))
    (local $other (ref null $struct))
    (local.set $ref
      (struct.new $struct
        (i32.const 10)
      )
    )
    (struct.set $struct 0
      (local.get $ref)
      (block (result i32)
        ;; A write to another local is fine.
        (local.set $other
          (ref.null $struct)
        )
        (i32.const 20)
      )
    )
  )

  ;; CHECK:      (func $ref-local-read (type $1)
  ;; CHECK-NEXT:  (local $ref (ref null $struct))
  ;; CHECK-NEXT:  (local.set $ref
  ;; CHECK-NEXT:   (struct.new $struct
  ;; CHECK-NEXT:    (i32.const 10)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (struct.set $struct 0
  ;; CHECK-NEXT:   (local.get $ref)
  ;; CHECK-NEXT:   (block (result i32)
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (local.get $ref)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (i32.const 20)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $ref-local-read
    (local $ref (ref null $struct))
    (local.set $ref
      (struct.new $struct
        (i32.const 10)
      )
    )
    (struct.set $struct 0
      (local.get $ref)
      (block (result i32)
        ;; A read of the ref local prevents us from optimizing.
        (drop
          (local.get $ref)
        )
        (i32.const 20)
      )
    )
  )

  ;; CHECK:      (func $ref-local-read-tee (type $1)
  ;; CHECK-NEXT:  (local $ref (ref null $struct))
  ;; CHECK-NEXT:  (struct.set $struct 0
  ;; CHECK-NEXT:   (local.tee $ref
  ;; CHECK-NEXT:    (struct.new $struct
  ;; CHECK-NEXT:     (i32.const 10)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:   (block (result i32)
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (local.get $ref)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (i32.const 20)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $ref-local-read-tee
    (local $ref (ref null $struct))
    (struct.set $struct 0
      (local.tee $ref
        (struct.new $struct
          (i32.const 10)
        )
      )
      (block (result i32)
        ;; As above, but now in a tee.
        (drop
          (local.get $ref)
        )
        (i32.const 20)
      )
    )
  )

  ;; CHECK:      (func $ref-other-read (type $1)
  ;; CHECK-NEXT:  (local $ref (ref null $struct))
  ;; CHECK-NEXT:  (local $other (ref null $struct))
  ;; CHECK-NEXT:  (local.set $ref
  ;; CHECK-NEXT:   (struct.new $struct
  ;; CHECK-NEXT:    (block (result i32)
  ;; CHECK-NEXT:     (drop
  ;; CHECK-NEXT:      (local.get $other)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:     (i32.const 20)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (nop)
  ;; CHECK-NEXT: )
  (func $ref-other-read
    (local $ref (ref null $struct))
    (local $other (ref null $struct))
    (local.set $ref
      (struct.new $struct
        (i32.const 10)
      )
    )
    (struct.set $struct 0
      (local.get $ref)
      (block (result i32)
        ;; A read of another local is fine.
        (drop
          (local.get $other)
        )
        (i32.const 20)
      )
    )
  )

  ;; CHECK:      (func $tee-and-subsequent (type $1)
  ;; CHECK-NEXT:  (local $ref (ref null $struct3))
  ;; CHECK-NEXT:  (local.set $ref
  ;; CHECK-NEXT:   (struct.new $struct3
  ;; CHECK-NEXT:    (i32.const 40)
  ;; CHECK-NEXT:    (i32.const 50)
  ;; CHECK-NEXT:    (i32.const 60)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (nop)
  ;; CHECK-NEXT:  (nop)
  ;; CHECK-NEXT: )
  (func $tee-and-subsequent
    (local $ref (ref null $struct3))
    ;; Test the common pattern of several subsequent sets, one of which is
    ;; using a tee.
    (struct.set $struct3 0
      (local.tee $ref
        (struct.new $struct3
          (i32.const 10)
          (i32.const 20)
          (i32.const 30)
        )
      )
      (i32.const 40)
    )
    (struct.set $struct3 1
      (local.get $ref)
      (i32.const 50)
    )
    (struct.set $struct3 2
      (local.get $ref)
      (i32.const 60)
    )
  )

  ;; CHECK:      (func $side-effect-subsequent-ok (type $1)
  ;; CHECK-NEXT:  (local $ref (ref null $struct2))
  ;; CHECK-NEXT:  (local.set $ref
  ;; CHECK-NEXT:   (struct.new $struct2
  ;; CHECK-NEXT:    (call $helper-i32
  ;; CHECK-NEXT:     (i32.const 0)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (call $helper-i32
  ;; CHECK-NEXT:     (i32.const 1)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (nop)
  ;; CHECK-NEXT: )
  (func $side-effect-subsequent-ok
    (local $ref (ref null $struct2))
    (local.set $ref
      (struct.new $struct2
        ;; The first field has side effects, but the second does not.
        (call $helper-i32 (i32.const 0))
        (i32.const 10)
      )
    )
    ;; Replace the second field with something with side effects.
    (struct.set $struct2 1
      (local.get $ref)
      (call $helper-i32 (i32.const 1))
    )
  )

  ;; CHECK:      (func $default (type $1)
  ;; CHECK-NEXT:  (local $ref (ref null $struct))
  ;; CHECK-NEXT:  (local $ref3 (ref null $struct3))
  ;; CHECK-NEXT:  (local.set $ref
  ;; CHECK-NEXT:   (struct.new $struct
  ;; CHECK-NEXT:    (i32.const 10)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (local.set $ref3
  ;; CHECK-NEXT:   (struct.new $struct3
  ;; CHECK-NEXT:    (i32.const 0)
  ;; CHECK-NEXT:    (i32.const 33)
  ;; CHECK-NEXT:    (i32.const 0)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $default
    (local $ref (ref null $struct))
    (local $ref3 (ref null $struct3))
    ;; We optimize new_default as well, adding default values as needed.
    (struct.set $struct 0
      (local.tee $ref
        (struct.new_default $struct)
      )
      (i32.const 10)
    )
    (struct.set $struct3 1
      (local.tee $ref3
        (struct.new_default $struct3)
      )
      (i32.const 33)
    )
  )

  ;; CHECK:      (func $many-news (type $1)
  ;; CHECK-NEXT:  (local $ref (ref null $struct3))
  ;; CHECK-NEXT:  (local $ref2 (ref null $struct3))
  ;; CHECK-NEXT:  (nop)
  ;; CHECK-NEXT:  (nop)
  ;; CHECK-NEXT:  (nop)
  ;; CHECK-NEXT:  (nop)
  ;; CHECK-NEXT:  (local.set $ref
  ;; CHECK-NEXT:   (struct.new $struct3
  ;; CHECK-NEXT:    (i32.const 40)
  ;; CHECK-NEXT:    (i32.const 50)
  ;; CHECK-NEXT:    (i32.const 60)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (local.set $ref
  ;; CHECK-NEXT:   (struct.new $struct3
  ;; CHECK-NEXT:    (i32.const 400)
  ;; CHECK-NEXT:    (i32.const 200)
  ;; CHECK-NEXT:    (i32.const 500)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (nop)
  ;; CHECK-NEXT:  (block
  ;; CHECK-NEXT:   (local.set $ref
  ;; CHECK-NEXT:    (struct.new $struct3
  ;; CHECK-NEXT:     (i32.const 40)
  ;; CHECK-NEXT:     (i32.const 20)
  ;; CHECK-NEXT:     (i32.const 30)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:   (local.set $ref2
  ;; CHECK-NEXT:    (struct.new $struct3
  ;; CHECK-NEXT:     (i32.const 400)
  ;; CHECK-NEXT:     (i32.const 600)
  ;; CHECK-NEXT:     (i32.const 500)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:   (nop)
  ;; CHECK-NEXT:   (nop)
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $many-news
    (local $ref (ref null $struct3))
    (local $ref2 (ref null $struct3))
    ;; Test that we optimize for multiple struct.news in the same function.
    (struct.set $struct3 0
      (local.tee $ref
        (struct.new $struct3
          (i32.const 10)
          (i32.const 20)
          (i32.const 30)
        )
      )
      (i32.const 40)
    )
    (struct.set $struct3 1
      (local.get $ref)
      (i32.const 50)
    )
    (nop)
    (struct.set $struct3 2
      (local.get $ref)
      (i32.const 60)
    )
    (nop)
    (struct.set $struct3 0
      (local.tee $ref
        (struct.new $struct3
          (i32.const 100)
          (i32.const 200)
          (i32.const 300)
        )
      )
      (i32.const 400)
    )
    (struct.set $struct3 2
      (local.get $ref)
      (i32.const 500)
    )
    ;; Test inside an inner block.
    (block $inner
      (struct.set $struct3 0
        (local.tee $ref
          (struct.new $struct3
            (i32.const 10)
            (i32.const 20)
            (i32.const 30)
          )
        )
        (i32.const 40)
      )
      ;; Use a different ref local here.
      (struct.set $struct3 0
        (local.tee $ref2
          (struct.new $struct3
            (i32.const 100)
            (i32.const 200)
            (i32.const 300)
          )
        )
        (i32.const 400)
      )
      (struct.set $struct3 2
        (local.get $ref2)
        (i32.const 500)
      )
      (struct.set $struct3 1
        (local.get $ref2)
        (i32.const 600)
      )
    )
  )

  ;; CHECK:      (func $unreachable (type $1)
  ;; CHECK-NEXT:  (local $ref (ref null $struct))
  ;; CHECK-NEXT:  (local.tee $ref
  ;; CHECK-NEXT:   (block ;; (replaces unreachable StructNew we can't emit)
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (unreachable)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (unreachable)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (struct.set $struct 0
  ;; CHECK-NEXT:   (local.get $ref)
  ;; CHECK-NEXT:   (i32.const 10)
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (nop)
  ;; CHECK-NEXT:  (local.set $ref
  ;; CHECK-NEXT:   (struct.new $struct
  ;; CHECK-NEXT:    (i32.const 20)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (struct.set $struct 0
  ;; CHECK-NEXT:   (local.get $ref)
  ;; CHECK-NEXT:   (unreachable)
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $unreachable
    (local $ref (ref null $struct))
    ;; Do not optimize unreachable code, either in the new (first pair) or the
    ;; set (second pair)
    (local.set $ref
      (struct.new $struct
        (unreachable)
      )
    )
    (struct.set $struct 0
      (local.get $ref)
      (i32.const 10)
    )
    (nop)
    (local.set $ref
      (struct.new $struct
        (i32.const 20)
      )
    )
    (struct.set $struct 0
      (local.get $ref)
      (unreachable)
    )
  )

  ;; CHECK:      (func $helper-i32 (type $7) (param $x i32) (result i32)
  ;; CHECK-NEXT:  (i32.const 42)
  ;; CHECK-NEXT: )
  (func $helper-i32 (param $x i32) (result i32)
    (i32.const 42)
  )

  ;; CHECK:      (func $control-flow-in-set-value (type $4) (result i32)
  ;; CHECK-NEXT:  (local $ref (ref null $struct))
  ;; CHECK-NEXT:  (block $label
  ;; CHECK-NEXT:   (struct.set $struct 0
  ;; CHECK-NEXT:    (local.tee $ref
  ;; CHECK-NEXT:     (struct.new $struct
  ;; CHECK-NEXT:      (i32.const 1)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (if (result i32)
  ;; CHECK-NEXT:     (i32.const 1)
  ;; CHECK-NEXT:     (then
  ;; CHECK-NEXT:      (br $label)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:     (else
  ;; CHECK-NEXT:      (i32.const 42)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (struct.get $struct 0
  ;; CHECK-NEXT:   (local.get $ref)
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $control-flow-in-set-value (result i32)
    ;; Test we handle control flow in the struct.set's value when we combine a
    ;; struct.set with a struct.new. We should not optimize here.
    (local $ref (ref null $struct))
    (block $label
      (struct.set $struct 0
        (local.tee $ref
          (struct.new $struct
            (i32.const 1)
          )
        )
        (if (result i32)
          (i32.const 1)
          (then
            ;; This conditional break happens *after* the local.tee of $ref. We
            ;; must not move code around that reorders it, since there is a use
            ;; of the local below that could notice changes.
            (br $label)
          )
          (else
            (i32.const 42)
          )
        )
      )
    )
    ;; We did not reach the struct.set, but we did reach the local.tee, so this
    ;; reads the initial value of 1 (and does not trap on a nullref).
    (struct.get $struct 0
      (local.get $ref)
    )
  )

  ;; CHECK:      (func $control-flow-in-set-value-safe (type $4) (result i32)
  ;; CHECK-NEXT:  (local $ref (ref null $struct))
  ;; CHECK-NEXT:  (block
  ;; CHECK-NEXT:   (local.set $ref
  ;; CHECK-NEXT:    (struct.new $struct
  ;; CHECK-NEXT:     (if (result i32)
  ;; CHECK-NEXT:      (i32.const 1)
  ;; CHECK-NEXT:      (then
  ;; CHECK-NEXT:       (i32.const 1337)
  ;; CHECK-NEXT:      )
  ;; CHECK-NEXT:      (else
  ;; CHECK-NEXT:       (i32.const 42)
  ;; CHECK-NEXT:      )
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (struct.get $struct 0
  ;; CHECK-NEXT:   (local.get $ref)
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $control-flow-in-set-value-safe (result i32)
    ;; As above, but now the control flow in the value is safe: it does not
    ;; escape out. We should optimize here.
    (local $ref (ref null $struct))
    (block $label
      (struct.set $struct 0
        (local.tee $ref
          (struct.new $struct
            (i32.const 1)
          )
        )
        (if (result i32)
          (i32.const 1)
          (then
            (i32.const 1337)  ;; the break to $out was replaced
          )
          (else
            (i32.const 42)
          )
        )
      )
    )
    (struct.get $struct 0
      (local.get $ref)
    )
  )

  ;; CHECK:      (func $control-flow-in-set-value-safe-call (type $4) (result i32)
  ;; CHECK-NEXT:  (local $ref (ref null $struct))
  ;; CHECK-NEXT:  (block
  ;; CHECK-NEXT:   (local.set $ref
  ;; CHECK-NEXT:    (struct.new $struct
  ;; CHECK-NEXT:     (call $helper-i32
  ;; CHECK-NEXT:      (i32.const 42)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (struct.get $struct 0
  ;; CHECK-NEXT:   (local.get $ref)
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $control-flow-in-set-value-safe-call (result i32)
    ;; As above, but now the possible control flow is a call. It may throw, but
    ;; that would go outside of the function, which is fine.
    (local $ref (ref null $struct))
    (block $label
      (struct.set $struct 0
        (local.tee $ref
          (struct.new $struct
            (i32.const 1)
          )
        )
        (call $helper-i32 (i32.const 42))  ;; the if was replaced by this call
      )
    )
    (struct.get $struct 0
      (local.get $ref)
    )
  )

  ;; CHECK:      (func $control-flow-in-set-value-safe-return (type $4) (result i32)
  ;; CHECK-NEXT:  (local $ref (ref null $struct))
  ;; CHECK-NEXT:  (block
  ;; CHECK-NEXT:   (local.set $ref
  ;; CHECK-NEXT:    (struct.new $struct
  ;; CHECK-NEXT:     (if (result i32)
  ;; CHECK-NEXT:      (i32.const 1)
  ;; CHECK-NEXT:      (then
  ;; CHECK-NEXT:       (return
  ;; CHECK-NEXT:        (i32.const 42)
  ;; CHECK-NEXT:       )
  ;; CHECK-NEXT:      )
  ;; CHECK-NEXT:      (else
  ;; CHECK-NEXT:       (i32.const 42)
  ;; CHECK-NEXT:      )
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (struct.get $struct 0
  ;; CHECK-NEXT:   (local.get $ref)
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $control-flow-in-set-value-safe-return (result i32)
    ;; As above, but replace the call with a return in an if. We can still
    ;; optimize (if the return is taken, we go outside of the function anyhow).
    (local $ref (ref null $struct))
    (block $label
      (struct.set $struct 0
        (local.tee $ref
          (struct.new $struct
            (i32.const 1)
          )
        )
        (if (result i32)
          (i32.const 1)
          (then
            (return (i32.const 42))
          )
          (else
            (i32.const 42)
          )
        )
      )
    )
    (struct.get $struct 0
      (local.get $ref)
    )
  )

  ;; CHECK:      (func $control-flow-in-set-value-unsafe-call (type $4) (result i32)
  ;; CHECK-NEXT:  (local $ref (ref null $struct))
  ;; CHECK-NEXT:  (block $label
  ;; CHECK-NEXT:   (try_table (catch $tag $label)
  ;; CHECK-NEXT:    (struct.set $struct 0
  ;; CHECK-NEXT:     (local.tee $ref
  ;; CHECK-NEXT:      (struct.new $struct
  ;; CHECK-NEXT:       (i32.const 1)
  ;; CHECK-NEXT:      )
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:     (call $helper-i32
  ;; CHECK-NEXT:      (i32.const 42)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (struct.get $struct 0
  ;; CHECK-NEXT:   (local.get $ref)
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $control-flow-in-set-value-unsafe-call (result i32)
    ;; As above, but now the call's possible throw could be caught *inside* the
    ;; function, which means it is dangerous, and we do not optimize.
    (local $ref (ref null $struct))
    (block $label
      (try_table (catch $tag $label)  ;; this try was added
        (struct.set $struct 0
          (local.tee $ref
            (struct.new $struct
              (i32.const 1)
            )
          )
          (call $helper-i32 (i32.const 42))
        )
      )
    )
    (struct.get $struct 0
      (local.get $ref)
    )
  )

  ;; CHECK:      (func $control-flow-later (type $5) (param $x i32)
  ;; CHECK-NEXT:  (local $ref (ref null $struct))
  ;; CHECK-NEXT:  (block $out
  ;; CHECK-NEXT:   (br_if $out
  ;; CHECK-NEXT:    (local.get $x)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (local.set $ref
  ;; CHECK-NEXT:   (struct.new $struct
  ;; CHECK-NEXT:    (i32.const 42)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (if
  ;; CHECK-NEXT:   (local.get $x)
  ;; CHECK-NEXT:   (then
  ;; CHECK-NEXT:    (nop)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $control-flow-later (param $x i32)
    (local $ref (ref null $struct))
    (struct.set $struct 0
      (local.tee $ref
        (struct.new $struct
          (i32.const 1)
        )
      )
      (i32.const 42)
    )
    ;; This later control flow should not prevent optimizing the struct.set
    ;; before it.
    (block $out
      (br_if $out
        (local.get $x)
      )
    )
    (if
      (local.get $x)
      (then
        (nop)
      )
    )
  )

  ;; CHECK:      (func $loop (type $1)
  ;; CHECK-NEXT:  (local $ref (ref null $struct))
  ;; CHECK-NEXT:  (loop $loop
  ;; CHECK-NEXT:   (drop
  ;; CHECK-NEXT:    (struct.get $struct 0
  ;; CHECK-NEXT:     (local.get $ref)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:   (struct.set $struct 0
  ;; CHECK-NEXT:    (local.tee $ref
  ;; CHECK-NEXT:     (struct.new $struct
  ;; CHECK-NEXT:      (i32.const 1)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (if (result i32)
  ;; CHECK-NEXT:     (i32.const 1)
  ;; CHECK-NEXT:     (then
  ;; CHECK-NEXT:      (br $loop)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:     (else
  ;; CHECK-NEXT:      (i32.const 42)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $loop
    (local $ref (ref null $struct))
    (loop $loop
      ;; There is a use of the reference at the top of the loop, and the br_if
      ;; may get here, so this is a basic block before the struct.set that we
      ;; need to be careful of reaching. We should not optimize here.
      (drop
        (struct.get $struct 0
          (local.get $ref)
        )
      )
      (struct.set $struct 0
        (local.tee $ref
          (struct.new $struct
            (i32.const 1)
          )
        )
        (if (result i32)
          (i32.const 1)
          (then
            (br $loop)
          )
          (else
            (i32.const 42)
          )
        )
      )
    )
  )

  ;; CHECK:      (func $loop-more-flow (type $1)
  ;; CHECK-NEXT:  (local $ref (ref null $struct))
  ;; CHECK-NEXT:  (loop $loop
  ;; CHECK-NEXT:   (if
  ;; CHECK-NEXT:    (i32.const 1)
  ;; CHECK-NEXT:    (then
  ;; CHECK-NEXT:     (br $loop)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:   (drop
  ;; CHECK-NEXT:    (struct.get $struct 0
  ;; CHECK-NEXT:     (local.get $ref)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:   (struct.set $struct 0
  ;; CHECK-NEXT:    (local.tee $ref
  ;; CHECK-NEXT:     (struct.new $struct
  ;; CHECK-NEXT:      (i32.const 1)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (if (result i32)
  ;; CHECK-NEXT:     (i32.const 1)
  ;; CHECK-NEXT:     (then
  ;; CHECK-NEXT:      (br $loop)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:     (else
  ;; CHECK-NEXT:      (i32.const 42)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $loop-more-flow
    (local $ref (ref null $struct))
    (loop $loop
      ;; As above, but add this if which adds more control flow at the loop top.
      ;; We should still not optimize here.
      (if
        (i32.const 1)
        (then
          (br $loop)
        )
      )
      (drop
        (struct.get $struct 0
          (local.get $ref)
        )
      )
      (struct.set $struct 0
        (local.tee $ref
          (struct.new $struct
            (i32.const 1)
          )
        )
        (if (result i32)
          (i32.const 1)
          (then
            (br $loop)
          )
          (else
            (i32.const 42)
          )
        )
      )
    )
  )

  ;; CHECK:      (func $loop-in-value (type $5) (param $x i32)
  ;; CHECK-NEXT:  (local $ref (ref null $struct))
  ;; CHECK-NEXT:  (local.set $ref
  ;; CHECK-NEXT:   (struct.new $struct
  ;; CHECK-NEXT:    (loop $loop (result i32)
  ;; CHECK-NEXT:     (br_if $loop
  ;; CHECK-NEXT:      (local.get $x)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:     (i32.const 42)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $loop-in-value (param $x i32)
    (local $ref (ref null $struct))
    ;; The struct.set's value has a loop in it, but that is fine, as while there
    ;; are backedges there, they are still contained in the value: we can't skip
    ;; the struct.set. We can optimize here.
    (struct.set $struct 0
      (local.tee $ref
        (struct.new $struct
          (i32.const 1)
        )
      )
      (loop $loop (result i32)
        (br_if $loop
          (local.get $x)
        )
        (i32.const 42)
      )
    )
  )

  ;; CHECK:      (func $in-if-arm (type $6) (param $x i32) (param $y i32) (result i32)
  ;; CHECK-NEXT:  (local $ref (ref null $struct))
  ;; CHECK-NEXT:  (if
  ;; CHECK-NEXT:   (local.get $x)
  ;; CHECK-NEXT:   (then
  ;; CHECK-NEXT:    (block $out
  ;; CHECK-NEXT:     (struct.set $struct 0
  ;; CHECK-NEXT:      (local.tee $ref
  ;; CHECK-NEXT:       (struct.new $struct
  ;; CHECK-NEXT:        (i32.const 1)
  ;; CHECK-NEXT:       )
  ;; CHECK-NEXT:      )
  ;; CHECK-NEXT:      (block (result i32)
  ;; CHECK-NEXT:       (br_if $out
  ;; CHECK-NEXT:        (local.get $x)
  ;; CHECK-NEXT:       )
  ;; CHECK-NEXT:       (i32.const 42)
  ;; CHECK-NEXT:      )
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (struct.get $struct 0
  ;; CHECK-NEXT:   (local.get $ref)
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $in-if-arm (param $x i32) (param $y i32) (result i32)
    (local $ref (ref null $struct))
    (if
      (local.get $x)
      (then
        (block $out
          ;; We cannot optimize here, as the struct.get outside of the if can
          ;; read different state if the br_if happens.
          (struct.set $struct 0
            (local.tee $ref
              (struct.new $struct
                (i32.const 1)
              )
            )
            (block (result i32)
              (br_if $out
                (local.get $x)
              )
              (i32.const 42)
            )
          )
        )
      )
    )
    (struct.get $struct 0
      (local.get $ref)
    )
  )

  ;; CHECK:      (func $in-if-arm-yes (type $6) (param $x i32) (param $y i32) (result i32)
  ;; CHECK-NEXT:  (local $ref (ref null $struct))
  ;; CHECK-NEXT:  (if
  ;; CHECK-NEXT:   (local.get $x)
  ;; CHECK-NEXT:   (then
  ;; CHECK-NEXT:    (block $out
  ;; CHECK-NEXT:     (local.set $ref
  ;; CHECK-NEXT:      (struct.new $struct
  ;; CHECK-NEXT:       (block (result i32)
  ;; CHECK-NEXT:        (br_if $out
  ;; CHECK-NEXT:         (local.get $x)
  ;; CHECK-NEXT:        )
  ;; CHECK-NEXT:        (i32.const 42)
  ;; CHECK-NEXT:       )
  ;; CHECK-NEXT:      )
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (i32.const 1337)
  ;; CHECK-NEXT: )
  (func $in-if-arm-yes (param $x i32) (param $y i32) (result i32)
    (local $ref (ref null $struct))
    ;; As before, but the struct.get at the end is removed, so we can optimize.
    (if
      (local.get $x)
      (then
        (block $out
          (struct.set $struct 0
            (local.tee $ref
              (struct.new $struct
                (i32.const 1)
              )
            )
            (block (result i32)
              (br_if $out
                (local.get $x)
              )
              (i32.const 42)
            )
          )
        )
      )
    )
    (i32.const 1337) ;; this changed
  )

  ;; CHECK:      (func $control-flow-in-set-value-sequence (type $4) (result i32)
  ;; CHECK-NEXT:  (local $ref (ref null $struct))
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (block $out (result i32)
  ;; CHECK-NEXT:    (local.set $ref
  ;; CHECK-NEXT:     (struct.new_default $struct)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (struct.set $struct 0
  ;; CHECK-NEXT:     (local.get $ref)
  ;; CHECK-NEXT:     (br_if $out
  ;; CHECK-NEXT:      (i32.const 1)
  ;; CHECK-NEXT:      (i32.const 2)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (struct.set $struct 0
  ;; CHECK-NEXT:     (local.get $ref)
  ;; CHECK-NEXT:     (i32.const 3)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (struct.get $struct 0
  ;; CHECK-NEXT:      (local.get $ref)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (i32.const 42)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (struct.get $struct 0
  ;; CHECK-NEXT:   (local.get $ref)
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $control-flow-in-set-value-sequence (result i32)
    (local $ref (ref null $struct))
    (drop
      (block $out (result i32)
        (local.set $ref
          ;; Also test struct.new_default here, with control flow.
          (struct.new_default $struct)
        )
        ;; The struct.get outside is a problem, so we do not optimize here,
        ;; nor the set after us.
        (struct.set $struct 0
          (local.get $ref)
          (br_if $out
            (i32.const 1)
            (i32.const 2)
          )
        )
        (struct.set $struct 0
          (local.get $ref)
          (i32.const 3)
        )
        ;; This struct.set is not a problem: if we branch, we don't reach it
        ;; anyhow.
        (drop
          (struct.get $struct 0
            (local.get $ref)
          )
        )
        (i32.const 42)
      )
    )
    (struct.get $struct 0
      (local.get $ref)
    )
  )

  ;; CHECK:      (func $control-flow-in-set-value-sequence-2 (type $4) (result i32)
  ;; CHECK-NEXT:  (local $ref (ref null $struct))
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (block $out (result i32)
  ;; CHECK-NEXT:    (local.set $ref
  ;; CHECK-NEXT:     (struct.new $struct
  ;; CHECK-NEXT:      (i32.const 3)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (nop)
  ;; CHECK-NEXT:    (struct.set $struct 0
  ;; CHECK-NEXT:     (local.get $ref)
  ;; CHECK-NEXT:     (br_if $out
  ;; CHECK-NEXT:      (i32.const 1)
  ;; CHECK-NEXT:      (i32.const 2)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (struct.get $struct 0
  ;; CHECK-NEXT:      (local.get $ref)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (i32.const 42)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (struct.get $struct 0
  ;; CHECK-NEXT:   (local.get $ref)
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $control-flow-in-set-value-sequence-2 (result i32)
    (local $ref (ref null $struct))
    (drop
      (block $out (result i32)
        (local.set $ref
          (struct.new_default $struct)
        )
        ;; As above, but the order of struct.sets is flipped. We can at least
        ;; optimize the first here.
        (struct.set $struct 0
          (local.get $ref)
          (i32.const 3)
        )
        (struct.set $struct 0
          (local.get $ref)
          (br_if $out
            (i32.const 1)
            (i32.const 2)
          )
        )
        (drop
          (struct.get $struct 0
            (local.get $ref)
          )
        )
        (i32.const 42)
      )
    )
    (struct.get $struct 0
      (local.get $ref)
    )
  )

  ;; CHECK:      (func $control-flow-in-set-value-sequence-yes (type $4) (result i32)
  ;; CHECK-NEXT:  (local $ref (ref null $struct))
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (block $out (result i32)
  ;; CHECK-NEXT:    (local.set $ref
  ;; CHECK-NEXT:     (struct.new $struct
  ;; CHECK-NEXT:      (br_if $out
  ;; CHECK-NEXT:       (i32.const 1)
  ;; CHECK-NEXT:       (i32.const 2)
  ;; CHECK-NEXT:      )
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (nop)
  ;; CHECK-NEXT:    (nop)
  ;; CHECK-NEXT:    (drop
  ;; CHECK-NEXT:     (struct.get $struct 0
  ;; CHECK-NEXT:      (local.get $ref)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (i32.const 42)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (i32.const 1337)
  ;; CHECK-NEXT: )
  (func $control-flow-in-set-value-sequence-yes (result i32)
    (local $ref (ref null $struct))
    ;; As above, but the struct.get at the end is removed, allowing us to
    ;; optimize it all.
    (drop
      (block $out (result i32)
        (local.set $ref
          (struct.new_default $struct)
        )
        (struct.set $struct 0
          (local.get $ref)
          (i32.const 3)
        )
        (struct.set $struct 0
          (local.get $ref)
          (br_if $out
            (i32.const 1)
            (i32.const 2)
          )
        )
        ;; Note how this struct.get remains and does not stop us.
        (drop
          (struct.get $struct 0
            (local.get $ref)
          )
        )
        (i32.const 42)
      )
    )
    (i32.const 1337)
  )

  ;; CHECK:      (func $multi-control-flow-in-set-value-sequence-yes (type $4) (result i32)
  ;; CHECK-NEXT:  (local $ref (ref null $struct))
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (block $out (result i32)
  ;; CHECK-NEXT:    (local.set $ref
  ;; CHECK-NEXT:     (struct.new $struct
  ;; CHECK-NEXT:      (br_if $out
  ;; CHECK-NEXT:       (i32.const 1)
  ;; CHECK-NEXT:       (i32.const 2)
  ;; CHECK-NEXT:      )
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (nop)
  ;; CHECK-NEXT:    (struct.set $struct 0
  ;; CHECK-NEXT:     (local.get $ref)
  ;; CHECK-NEXT:     (br_if $out
  ;; CHECK-NEXT:      (i32.const 3)
  ;; CHECK-NEXT:      (i32.const 4)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (struct.set $struct 0
  ;; CHECK-NEXT:     (local.get $ref)
  ;; CHECK-NEXT:     (br_if $out
  ;; CHECK-NEXT:      (i32.const 5)
  ;; CHECK-NEXT:      (i32.const 6)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (i32.const 42)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (i32.const 1337)
  ;; CHECK-NEXT: )
  (func $multi-control-flow-in-set-value-sequence-yes (result i32)
    (local $ref (ref null $struct))
    ;; As above, but now we have multiple br_ifs. We optimize one, but then
    ;; stop because of the control flow that is now in the struct.new. TODO we
    ;; could be more precise here.
    (drop
      (block $out (result i32)
        (local.set $ref
          (struct.new_default $struct)
        )
        (struct.set $struct 0
          (local.get $ref)
          (br_if $out
            (i32.const 1)
            (i32.const 2)
          )
        )
        (struct.set $struct 0
          (local.get $ref)
          (br_if $out
            (i32.const 3)
            (i32.const 4)
          )
        )
        (struct.set $struct 0
          (local.get $ref)
          (br_if $out
            (i32.const 5)
            (i32.const 6)
          )
        )
        (i32.const 42)
      )
    )
    (i32.const 1337)
  )

  ;; CHECK:      (func $multi-control-flow-in-set-value-sequence-no (type $8) (result anyref)
  ;; CHECK-NEXT:  (local $ref (ref null $struct))
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (block $out (result i32)
  ;; CHECK-NEXT:    (local.set $ref
  ;; CHECK-NEXT:     (struct.new_default $struct)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (struct.set $struct 0
  ;; CHECK-NEXT:     (local.get $ref)
  ;; CHECK-NEXT:     (br_if $out
  ;; CHECK-NEXT:      (i32.const 1)
  ;; CHECK-NEXT:      (i32.const 2)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (struct.set $struct 0
  ;; CHECK-NEXT:     (local.get $ref)
  ;; CHECK-NEXT:     (br_if $out
  ;; CHECK-NEXT:      (i32.const 3)
  ;; CHECK-NEXT:      (i32.const 4)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (struct.set $struct 0
  ;; CHECK-NEXT:     (local.get $ref)
  ;; CHECK-NEXT:     (br_if $out
  ;; CHECK-NEXT:      (i32.const 5)
  ;; CHECK-NEXT:      (i32.const 6)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (i32.const 42)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (local.get $ref)
  ;; CHECK-NEXT: )
  (func $multi-control-flow-in-set-value-sequence-no (result anyref)
    (local $ref (ref null $struct))
    ;; As above, but now we have a dangerous local.get at the end, stopping us
    ;; from optimizing.
    (drop
      (block $out (result i32)
        (local.set $ref
          (struct.new_default $struct)
        )
        (struct.set $struct 0
          (local.get $ref)
          (br_if $out
            (i32.const 1)
            (i32.const 2)
          )
        )
        (struct.set $struct 0
          (local.get $ref)
          (br_if $out
            (i32.const 3)
            (i32.const 4)
          )
        )
        (struct.set $struct 0
          (local.get $ref)
          (br_if $out
            (i32.const 5)
            (i32.const 6)
          )
        )
        (i32.const 42)
      )
    )
    (local.get $ref)
  )
)
