;; NOTE: Assertions have been generated by update_lit_checks.py and should not be edited.
;; RUN: wasm-opt %s -all --traps-never-happen --simplify-locals -S -o - | filecheck %s

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

  ;; CHECK:      (type $unshared-struct (struct (field (mut i32))))
  (type $unshared-struct (struct (field (mut i32))))

  (type $shared-array (shared (array (mut i32))))

  ;; CHECK:      (memory $shared 1 1 shared)
  (memory $shared 1 1 shared)
  ;; CHECK:      (memory $unshared 1 1)
  (memory $unshared 1 1)

  ;; CHECK:      (func $memory.size-shared-shared (type $3) (param $shared (ref null $shared-struct)) (result i32)
  ;; CHECK-NEXT:  (local $x i32)
  ;; CHECK-NEXT:  (local.set $x
  ;; CHECK-NEXT:   (memory.size $shared)
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (struct.atomic.set $shared-struct 0
  ;; CHECK-NEXT:   (local.get $shared)
  ;; CHECK-NEXT:   (i32.const 0)
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (local.get $x)
  ;; CHECK-NEXT: )
  (func $memory.size-shared-shared (param $shared (ref null $shared-struct)) (result i32)
    (local $x i32)
    ;; memory.size can synchronize with memory.grow on another thread when the
    ;; memory is shared. It cannot be moved past a write to a shared struct.
    (local.set $x
      (memory.size $shared)
    )
    (struct.atomic.set $shared-struct 0 (local.get $shared) (i32.const 0))
    (local.get $x)
  )

  ;; CHECK:      (func $memory.size-unshared-shared (type $3) (param $shared (ref null $shared-struct)) (result i32)
  ;; CHECK-NEXT:  (local $x i32)
  ;; CHECK-NEXT:  (nop)
  ;; CHECK-NEXT:  (struct.atomic.set $shared-struct 0
  ;; CHECK-NEXT:   (local.get $shared)
  ;; CHECK-NEXT:   (i32.const 0)
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (memory.size $unshared)
  ;; CHECK-NEXT: )
  (func $memory.size-unshared-shared (param $shared (ref null $shared-struct)) (result i32)
    (local $x i32)
    ;; Now the memory is unshared. We can reorder because no other thread can
    ;; observe the reordering.
    (local.set $x
      (memory.size $unshared)
    )
    (struct.atomic.set $shared-struct 0 (local.get $shared) (i32.const 0))
    (local.get $x)
  )

  ;; CHECK:      (func $memory.size-shared-unshared (type $5) (param $unshared (ref null $unshared-struct)) (result i32)
  ;; CHECK-NEXT:  (local $x i32)
  ;; CHECK-NEXT:  (nop)
  ;; CHECK-NEXT:  (struct.atomic.set $unshared-struct 0
  ;; CHECK-NEXT:   (local.get $unshared)
  ;; CHECK-NEXT:   (i32.const 0)
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (memory.size $shared)
  ;; CHECK-NEXT: )
  (func $memory.size-shared-unshared (param $unshared (ref null $unshared-struct)) (result i32)
    (local $x i32)
    ;; Now the memory is shared but the struct is unshared. Again, we can
    ;; reorder.
    (local.set $x
      (memory.size $shared)
    )
    (struct.atomic.set $unshared-struct 0 (local.get $unshared) (i32.const 0))
    (local.get $x)
  )

  ;; CHECK:      (func $memory.size-unshared-unshared (type $5) (param $unshared (ref null $unshared-struct)) (result i32)
  ;; CHECK-NEXT:  (local $x i32)
  ;; CHECK-NEXT:  (nop)
  ;; CHECK-NEXT:  (struct.atomic.set $unshared-struct 0
  ;; CHECK-NEXT:   (local.get $unshared)
  ;; CHECK-NEXT:   (i32.const 0)
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (memory.size $unshared)
  ;; CHECK-NEXT: )
  (func $memory.size-unshared-unshared (param $unshared (ref null $unshared-struct)) (result i32)
    (local $x i32)
    ;; Now both the memory and struct are unshared, so neither can synchronize
    ;; with anything and we reorder freely.
    (local.set $x
      (memory.size $unshared)
    )
    (struct.atomic.set $unshared-struct 0 (local.get $unshared) (i32.const 0))
    (local.get $x)
  )

  ;; CHECK:      (func $read-acquire (type $3) (param $shared (ref null $shared-struct)) (result i32)
  ;; CHECK-NEXT:  (local $x i32)
  ;; CHECK-NEXT:  (nop)
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (struct.atomic.get acqrel $shared-struct 0
  ;; CHECK-NEXT:    (local.get $shared)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (struct.get $shared-struct 0
  ;; CHECK-NEXT:   (local.get $shared)
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $read-acquire (param $shared (ref null $shared-struct)) (result i32)
    ;; A normal read can be moved past an acquire read.
    (local $x i32)
    (local.set $x
      (struct.get $shared-struct 0
        (local.get $shared)
      )
    )
    (drop
      (struct.atomic.get acqrel $shared-struct 0
        (local.get $shared)
      )
    )
    (local.get $x)
  )

  ;; CHECK:      (func $acquire-read (type $3) (param $shared (ref null $shared-struct)) (result i32)
  ;; CHECK-NEXT:  (local $x i32)
  ;; CHECK-NEXT:  (local.set $x
  ;; CHECK-NEXT:   (struct.atomic.get acqrel $shared-struct 0
  ;; CHECK-NEXT:    (local.get $shared)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (struct.get $shared-struct 0
  ;; CHECK-NEXT:    (local.get $shared)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (local.get $x)
  ;; CHECK-NEXT: )
  (func $acquire-read (param $shared (ref null $shared-struct)) (result i32)
    ;; But an acquire read cannot be ordered past a normal read.
    (local $x i32)
    (local.set $x
      (struct.atomic.get acqrel $shared-struct 0
        (local.get $shared)
      )
    )
    (drop
      (struct.get $shared-struct 0
        (local.get $shared)
      )
    )
    (local.get $x)
  )

  ;; CHECK:      (func $store-acquire (type $2) (param $shared (ref null $shared-struct)) (param $shared-array (ref null $shared-array)) (result i32)
  ;; CHECK-NEXT:  (local $x i32)
  ;; CHECK-NEXT:  (nop)
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (struct.atomic.get acqrel $shared-struct 0
  ;; CHECK-NEXT:    (local.get $shared)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (block (result i32)
  ;; CHECK-NEXT:   (array.set $shared-array
  ;; CHECK-NEXT:    (local.get $shared-array)
  ;; CHECK-NEXT:    (i32.const 0)
  ;; CHECK-NEXT:    (i32.const 0)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:   (i32.const 1)
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $store-acquire (param $shared (ref null $shared-struct))
                       (param $shared-array (ref null $shared-array))
                       (result i32)
    ;; A normal store can be moved past a non-aliasing acquire read. (This
    ;; depends on traps-never-happen being enabled.)
    (local $x i32)
    (local.set $x
      (block (result i32)
        (array.set $shared-array
          (local.get $shared-array)
          (i32.const 0)
          (i32.const 0)
        )
        (i32.const 1)
      )
    )
    (drop
      (struct.atomic.get acqrel $shared-struct 0
        (local.get $shared)
      )
    )
    (local.get $x)
  )

  ;; CHECK:      (func $acquire-store (type $2) (param $shared (ref null $shared-struct)) (param $shared-array (ref null $shared-array)) (result i32)
  ;; CHECK-NEXT:  (local $x i32)
  ;; CHECK-NEXT:  (local.set $x
  ;; CHECK-NEXT:   (struct.atomic.get acqrel $shared-struct 0
  ;; CHECK-NEXT:    (local.get $shared)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (array.set $shared-array
  ;; CHECK-NEXT:   (local.get $shared-array)
  ;; CHECK-NEXT:   (i32.const 0)
  ;; CHECK-NEXT:   (i32.const 0)
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (local.get $x)
  ;; CHECK-NEXT: )
  (func $acquire-store (param $shared (ref null $shared-struct))
                       (param $shared-array (ref null $shared-array))
                       (result i32)
    ;; But an acquire load cannot be moved past a normal store.
    (local $x i32)
    (local.set $x
      (struct.atomic.get acqrel $shared-struct 0
        (local.get $shared)
      )
    )
    (array.set $shared-array
      (local.get $shared-array)
      (i32.const 0)
      (i32.const 0)
    )
    (local.get $x)
  )

  ;; CHECK:      (func $read-release (type $2) (param $shared (ref null $shared-struct)) (param $shared-array (ref null $shared-array)) (result i32)
  ;; CHECK-NEXT:  (local $x i32)
  ;; CHECK-NEXT:  (local.set $x
  ;; CHECK-NEXT:   (array.get $shared-array
  ;; CHECK-NEXT:    (local.get $shared-array)
  ;; CHECK-NEXT:    (i32.const 0)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (struct.atomic.set acqrel $shared-struct 0
  ;; CHECK-NEXT:   (local.get $shared)
  ;; CHECK-NEXT:   (i32.const 0)
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (local.get $x)
  ;; CHECK-NEXT: )
  (func $read-release (param $shared (ref null $shared-struct))
                      (param $shared-array (ref null $shared-array))
                      (result i32)
    ;; A normal read cannot be moved past a release store.
    (local $x i32)
    (local.set $x
      (array.get $shared-array
        (local.get $shared-array)
        (i32.const 0)
      )
    )
    (struct.atomic.set acqrel $shared-struct 0
      (local.get $shared)
      (i32.const 0)
    )
    (local.get $x)
  )

  ;; CHECK:      (func $release-read (type $2) (param $shared (ref null $shared-struct)) (param $shared-array (ref null $shared-array)) (result i32)
  ;; CHECK-NEXT:  (local $x i32)
  ;; CHECK-NEXT:  (nop)
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (array.get $shared-array
  ;; CHECK-NEXT:    (local.get $shared-array)
  ;; CHECK-NEXT:    (i32.const 0)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (block (result i32)
  ;; CHECK-NEXT:   (struct.atomic.set acqrel $shared-struct 0
  ;; CHECK-NEXT:    (local.get $shared)
  ;; CHECK-NEXT:    (i32.const 0)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:   (i32.const 1)
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $release-read (param $shared (ref null $shared-struct))
                      (param $shared-array (ref null $shared-array))
                      (result i32)
    ;; But a release store can be moved past a non-aliasing normal read.
    (local $x i32)
    (local.set $x
      (block (result i32)
        (struct.atomic.set acqrel $shared-struct 0
          (local.get $shared)
          (i32.const 0)
        )
        (i32.const 1)
      )
    )
    (drop
      (array.get $shared-array
        (local.get $shared-array)
        (i32.const 0)
      )
    )
    (local.get $x)
  )

  ;; CHECK:      (func $store-release (type $2) (param $shared (ref null $shared-struct)) (param $shared-array (ref null $shared-array)) (result i32)
  ;; CHECK-NEXT:  (local $x i32)
  ;; CHECK-NEXT:  (local.set $x
  ;; CHECK-NEXT:   (block (result i32)
  ;; CHECK-NEXT:    (array.set $shared-array
  ;; CHECK-NEXT:     (local.get $shared-array)
  ;; CHECK-NEXT:     (i32.const 0)
  ;; CHECK-NEXT:     (i32.const 0)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (i32.const 1)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (struct.atomic.set acqrel $shared-struct 0
  ;; CHECK-NEXT:   (local.get $shared)
  ;; CHECK-NEXT:   (i32.const 0)
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (local.get $x)
  ;; CHECK-NEXT: )
  (func $store-release (param $shared (ref null $shared-struct))
                       (param $shared-array (ref null $shared-array))
                       (result i32)
    ;; A normal store cannot be moved past a release store.
    (local $x i32)
    (local.set $x
      (block (result i32)
        (array.set $shared-array
          (local.get $shared-array)
          (i32.const 0)
          (i32.const 0)
        )
        (i32.const 1)
      )
    )
    (struct.atomic.set acqrel $shared-struct 0
      (local.get $shared)
      (i32.const 0)
    )
    (local.get $x)
  )

  ;; CHECK:      (func $release-store (type $2) (param $shared (ref null $shared-struct)) (param $shared-array (ref null $shared-array)) (result i32)
  ;; CHECK-NEXT:  (local $x i32)
  ;; CHECK-NEXT:  (nop)
  ;; CHECK-NEXT:  (array.set $shared-array
  ;; CHECK-NEXT:   (local.get $shared-array)
  ;; CHECK-NEXT:   (i32.const 0)
  ;; CHECK-NEXT:   (i32.const 0)
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (block (result i32)
  ;; CHECK-NEXT:   (struct.atomic.set acqrel $shared-struct 0
  ;; CHECK-NEXT:    (local.get $shared)
  ;; CHECK-NEXT:    (i32.const 0)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:   (i32.const 1)
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $release-store (param $shared (ref null $shared-struct))
                       (param $shared-array (ref null $shared-array))
                       (result i32)
    ;; But a release store can be moved past a non-aliasing normal store.
    (local $x i32)
    (local.set $x
      (block (result i32)
        (struct.atomic.set acqrel $shared-struct 0
          (local.get $shared)
          (i32.const 0)
        )
        (i32.const 1)
      )
    )
    (array.set $shared-array
      (local.get $shared-array)
      (i32.const 0)
      (i32.const 0)
    )
    (local.get $x)
  )

  ;; CHECK:      (func $read-seqcst-read (type $2) (param $shared (ref null $shared-struct)) (param $shared-array (ref null $shared-array)) (result i32)
  ;; CHECK-NEXT:  (local $x i32)
  ;; CHECK-NEXT:  (local.set $x
  ;; CHECK-NEXT:   (array.get $shared-array
  ;; CHECK-NEXT:    (local.get $shared-array)
  ;; CHECK-NEXT:    (i32.const 0)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (struct.atomic.get $shared-struct 0
  ;; CHECK-NEXT:    (local.get $shared)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (local.get $x)
  ;; CHECK-NEXT: )
  (func $read-seqcst-read (param $shared (ref null $shared-struct))
                          (param $shared-array (ref null $shared-array))
                          (result i32)
    ;; A normal read cannot be moved past a seqcst read.
    (local $x i32)
    (local.set $x
      (array.get $shared-array
        (local.get $shared-array)
        (i32.const 0)
      )
    )
    (drop
      (struct.atomic.get seqcst $shared-struct 0
        (local.get $shared)
      )
    )
    (local.get $x)
  )

  ;; CHECK:      (func $seqcst-read-read (type $2) (param $shared (ref null $shared-struct)) (param $shared-array (ref null $shared-array)) (result i32)
  ;; CHECK-NEXT:  (local $x i32)
  ;; CHECK-NEXT:  (local.set $x
  ;; CHECK-NEXT:   (struct.atomic.get $shared-struct 0
  ;; CHECK-NEXT:    (local.get $shared)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (array.get $shared-array
  ;; CHECK-NEXT:    (local.get $shared-array)
  ;; CHECK-NEXT:    (i32.const 0)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (local.get $x)
  ;; CHECK-NEXT: )
  (func $seqcst-read-read (param $shared (ref null $shared-struct))
                          (param $shared-array (ref null $shared-array))
                          (result i32)
    ;; A seqcst read cannot be moved past a normal read.
    (local $x i32)
    (local.set $x
      (struct.atomic.get seqcst $shared-struct 0
        (local.get $shared)
      )
    )
    (drop
      (array.get $shared-array
        (local.get $shared-array)
        (i32.const 0)
      )
    )
    (local.get $x)
  )

  ;; CHECK:      (func $store-seqcst-read (type $2) (param $shared (ref null $shared-struct)) (param $shared-array (ref null $shared-array)) (result i32)
  ;; CHECK-NEXT:  (local $x i32)
  ;; CHECK-NEXT:  (local.set $x
  ;; CHECK-NEXT:   (block (result i32)
  ;; CHECK-NEXT:    (array.set $shared-array
  ;; CHECK-NEXT:     (local.get $shared-array)
  ;; CHECK-NEXT:     (i32.const 0)
  ;; CHECK-NEXT:     (i32.const 0)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (i32.const 1)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (struct.atomic.get $shared-struct 0
  ;; CHECK-NEXT:    (local.get $shared)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (local.get $x)
  ;; CHECK-NEXT: )
  (func $store-seqcst-read (param $shared (ref null $shared-struct))
                           (param $shared-array (ref null $shared-array))
                           (result i32)
    ;; A normal store cannot be moved past a seqcst read.
    (local $x i32)
    (local.set $x
      (block (result i32)
        (array.set $shared-array
          (local.get $shared-array)
          (i32.const 0)
          (i32.const 0)
        )
        (i32.const 1)
      )
    )
    (drop
      (struct.atomic.get seqcst $shared-struct 0
        (local.get $shared)
      )
    )
    (local.get $x)
  )

  ;; CHECK:      (func $seqcst-read-store (type $2) (param $shared (ref null $shared-struct)) (param $shared-array (ref null $shared-array)) (result i32)
  ;; CHECK-NEXT:  (local $x i32)
  ;; CHECK-NEXT:  (local.set $x
  ;; CHECK-NEXT:   (struct.atomic.get $shared-struct 0
  ;; CHECK-NEXT:    (local.get $shared)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (array.set $shared-array
  ;; CHECK-NEXT:   (local.get $shared-array)
  ;; CHECK-NEXT:   (i32.const 0)
  ;; CHECK-NEXT:   (i32.const 0)
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (local.get $x)
  ;; CHECK-NEXT: )
  (func $seqcst-read-store (param $shared (ref null $shared-struct))
                          (param $shared-array (ref null $shared-array))
                          (result i32)
    ;; A seqcst read cannot be moved past a normal store.
    (local $x i32)
    (local.set $x
      (struct.atomic.get seqcst $shared-struct 0
        (local.get $shared)
      )
    )
    (array.set $shared-array
      (local.get $shared-array)
      (i32.const 0)
      (i32.const 0)
    )
    (local.get $x)
  )

  ;; CHECK:      (func $read-seqcst-store (type $2) (param $shared (ref null $shared-struct)) (param $shared-array (ref null $shared-array)) (result i32)
  ;; CHECK-NEXT:  (local $x i32)
  ;; CHECK-NEXT:  (local.set $x
  ;; CHECK-NEXT:   (array.get $shared-array
  ;; CHECK-NEXT:    (local.get $shared-array)
  ;; CHECK-NEXT:    (i32.const 0)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (struct.atomic.set $shared-struct 0
  ;; CHECK-NEXT:   (local.get $shared)
  ;; CHECK-NEXT:   (i32.const 0)
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (local.get $x)
  ;; CHECK-NEXT: )
  (func $read-seqcst-store (param $shared (ref null $shared-struct))
                          (param $shared-array (ref null $shared-array))
                          (result i32)
    ;; A normal read cannot be moved past a seqcst store.
    (local $x i32)
    (local.set $x
      (array.get $shared-array
        (local.get $shared-array)
        (i32.const 0)
      )
    )
    (struct.atomic.set seqcst $shared-struct 0
      (local.get $shared)
      (i32.const 0)
    )
    (local.get $x)
  )

  ;; CHECK:      (func $seqcst-store-read (type $2) (param $shared (ref null $shared-struct)) (param $shared-array (ref null $shared-array)) (result i32)
  ;; CHECK-NEXT:  (local $x i32)
  ;; CHECK-NEXT:  (local.set $x
  ;; CHECK-NEXT:   (block (result i32)
  ;; CHECK-NEXT:    (struct.atomic.set $shared-struct 0
  ;; CHECK-NEXT:     (local.get $shared)
  ;; CHECK-NEXT:     (i32.const 0)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (i32.const 1)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (drop
  ;; CHECK-NEXT:   (array.get $shared-array
  ;; CHECK-NEXT:    (local.get $shared-array)
  ;; CHECK-NEXT:    (i32.const 0)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (local.get $x)
  ;; CHECK-NEXT: )
  (func $seqcst-store-read (param $shared (ref null $shared-struct))
                          (param $shared-array (ref null $shared-array))
                          (result i32)
    ;; A seqcst store cannot be moved past a normal read.
    (local $x i32)
    (local.set $x
      (block (result i32)
        (struct.atomic.set seqcst $shared-struct 0
          (local.get $shared)
          (i32.const 0)
        )
        (i32.const 1)
      )
    )
    (drop
      (array.get $shared-array
        (local.get $shared-array)
        (i32.const 0)
      )
    )
    (local.get $x)
  )

  ;; CHECK:      (func $store-seqcst-store (type $2) (param $shared (ref null $shared-struct)) (param $shared-array (ref null $shared-array)) (result i32)
  ;; CHECK-NEXT:  (local $x i32)
  ;; CHECK-NEXT:  (local.set $x
  ;; CHECK-NEXT:   (block (result i32)
  ;; CHECK-NEXT:    (array.set $shared-array
  ;; CHECK-NEXT:     (local.get $shared-array)
  ;; CHECK-NEXT:     (i32.const 0)
  ;; CHECK-NEXT:     (i32.const 0)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (i32.const 1)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (struct.atomic.set $shared-struct 0
  ;; CHECK-NEXT:   (local.get $shared)
  ;; CHECK-NEXT:   (i32.const 0)
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (local.get $x)
  ;; CHECK-NEXT: )
  (func $store-seqcst-store (param $shared (ref null $shared-struct))
                           (param $shared-array (ref null $shared-array))
                           (result i32)
    ;; A normal store cannot be moved past a seqcst store.
    (local $x i32)
    (local.set $x
      (block (result i32)
        (array.set $shared-array
          (local.get $shared-array)
          (i32.const 0)
          (i32.const 0)
        )
        (i32.const 1)
      )
    )
    (struct.atomic.set seqcst $shared-struct 0
      (local.get $shared)
      (i32.const 0)
    )
    (local.get $x)
  )

  ;; CHECK:      (func $seqcst-store-store (type $2) (param $shared (ref null $shared-struct)) (param $shared-array (ref null $shared-array)) (result i32)
  ;; CHECK-NEXT:  (local $x i32)
  ;; CHECK-NEXT:  (local.set $x
  ;; CHECK-NEXT:   (block (result i32)
  ;; CHECK-NEXT:    (struct.atomic.set $shared-struct 0
  ;; CHECK-NEXT:     (local.get $shared)
  ;; CHECK-NEXT:     (i32.const 0)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:    (i32.const 1)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (array.set $shared-array
  ;; CHECK-NEXT:   (local.get $shared-array)
  ;; CHECK-NEXT:   (i32.const 0)
  ;; CHECK-NEXT:   (i32.const 0)
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (local.get $x)
  ;; CHECK-NEXT: )
  (func $seqcst-store-store (param $shared (ref null $shared-struct))
                           (param $shared-array (ref null $shared-array))
                           (result i32)
    ;; A seqcst store cannot be moved past a normal store.
    (local $x i32)
    (local.set $x
      (block (result i32)
        (struct.atomic.set seqcst $shared-struct 0
          (local.get $shared)
          (i32.const 0)
        )
        (i32.const 1)
      )
    )
    (array.set $shared-array
      (local.get $shared-array)
      (i32.const 0)
      (i32.const 0)
    )
    (local.get $x)
  )

  ;; CHECK:      (func $br-on-read-acquire (type $3) (param $shared (ref null $shared-struct)) (result i32)
  ;; CHECK-NEXT:  (local $x i32)
  ;; CHECK-NEXT:  (nop)
  ;; CHECK-NEXT:  (block $l (result i32)
  ;; CHECK-NEXT:   (drop
  ;; CHECK-NEXT:    (br_if $l
  ;; CHECK-NEXT:     (block (result i32)
  ;; CHECK-NEXT:      (drop
  ;; CHECK-NEXT:       (struct.atomic.get acqrel $shared-struct 0
  ;; CHECK-NEXT:        (local.get $shared)
  ;; CHECK-NEXT:       )
  ;; CHECK-NEXT:      )
  ;; CHECK-NEXT:      (i32.const 42)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:     (block (result i32)
  ;; CHECK-NEXT:      (drop
  ;; CHECK-NEXT:       (struct.get $shared-struct 0
  ;; CHECK-NEXT:        (local.get $shared)
  ;; CHECK-NEXT:       )
  ;; CHECK-NEXT:      )
  ;; CHECK-NEXT:      (nop)
  ;; CHECK-NEXT:      (i32.const 1)
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:   (nop)
  ;; CHECK-NEXT:   (i32.const 0)
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT: )
  (func $br-on-read-acquire (param $shared (ref null $shared-struct)) (result i32)
    (local $x i32)
    (block $l
      (br_if $l
        (block (result i32)
          ;; We will remove the local.set below by moving the value,
          ;; including the acquire read, back past this normal read.
          (drop
            (struct.get $shared-struct 0
              (local.get $shared)
            )
          )
          (local.set $x
            (block (result i32)
              (drop
                (struct.atomic.get acqrel $shared-struct 0
                  (local.get $shared)
                )
              )
              (i32.const 42)
            )
          )
          (i32.const 1)
        )
      )
      (local.set $x
        (i32.const 0)
      )
    )
    (local.get $x)
  )

  ;; CHECK:      (func $br-on-acquire-read (type $3) (param $shared (ref null $shared-struct)) (result i32)
  ;; CHECK-NEXT:  (local $x i32)
  ;; CHECK-NEXT:  (block $l
  ;; CHECK-NEXT:   (br_if $l
  ;; CHECK-NEXT:    (block (result i32)
  ;; CHECK-NEXT:     (drop
  ;; CHECK-NEXT:      (struct.atomic.get acqrel $shared-struct 0
  ;; CHECK-NEXT:       (local.get $shared)
  ;; CHECK-NEXT:      )
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:     (local.set $x
  ;; CHECK-NEXT:      (block (result i32)
  ;; CHECK-NEXT:       (drop
  ;; CHECK-NEXT:        (struct.get $shared-struct 0
  ;; CHECK-NEXT:         (local.get $shared)
  ;; CHECK-NEXT:        )
  ;; CHECK-NEXT:       )
  ;; CHECK-NEXT:       (i32.const 42)
  ;; CHECK-NEXT:      )
  ;; CHECK-NEXT:     )
  ;; CHECK-NEXT:     (i32.const 1)
  ;; CHECK-NEXT:    )
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:   (local.set $x
  ;; CHECK-NEXT:    (i32.const 0)
  ;; CHECK-NEXT:   )
  ;; CHECK-NEXT:  )
  ;; CHECK-NEXT:  (local.get $x)
  ;; CHECK-NEXT: )
  (func $br-on-acquire-read (param $shared (ref null $shared-struct)) (result i32)
    (local $x i32)
    (block $l
      (br_if $l
        (block (result i32)
          ;; Now the acquire read comes first, so we cannot reorder.
          (drop
            (struct.atomic.get acqrel $shared-struct 0
              (local.get $shared)
            )
          )
          (local.set $x
            (block (result i32)
              (drop
                (struct.get $shared-struct 0
                  (local.get $shared)
                )
              )
              (i32.const 42)
            )
          )
          (i32.const 1)
        )
      )
      (local.set $x
        (i32.const 0)
      )
    )
    (local.get $x)
  )
)
