Repository: bytecodealliance/wasm-tools
Pull request #1563 (2024-05-16 22:50:56)

threads: add `global.atomic.rmw.*` instructions
This change adds support for the various `global.atomic.rmw.*` instructions that are now available as a part of the shared-everything-threads [proposal].

[proposal]: https://github.com/WebAssembly/shared-everything-threads

abrown: @alexcrichton, I'm playing around with generating all of the test cases programmatically for completeness and efficiency. But there's a lot there. Feel free to recommend a different way to organize those tests!

Patch:
diff --git a/README.md b/README.md
index fa0d6ffd..472d3ac3 100644
--- a/README.md
+++ b/README.md
@@ -142,7 +142,7 @@ that can be use programmatically as well:
 | `wasm-tools objdump` |   | Print debugging information about section headers |
 | `wasm-tools strip` |   | Remove custom sections from a WebAssembly file |
 | `wasm-tools demangle` |   | Demangle Rust and C++ symbol names in the `name` section |
-| `wasm-tools compose` | [wasm-compose] | Compose wasm components together |
+| `wasm-tools compose` | [wasm-compose] | Compose wasm components together (*deprecated*) |
 | `wasm-tools component new` | [wit-component] | Create a component from a core wasm binary |
 | `wasm-tools component wit` |  | Extract a `*.wit` interface from a component |
 | `wasm-tools component embed` |  | Embed a `component-type` custom section in a core wasm binary |
diff --git a/crates/wasm-compose/README.md b/crates/wasm-compose/README.md
index acf21ea4..325f287e 100644
--- a/crates/wasm-compose/README.md
+++ b/crates/wasm-compose/README.md
@@ -16,6 +16,8 @@
 
 ## Overview
 
+**IMPORTANT**:  `wasm-compose` has been been deprecated in favor of [`wac`](https://github.com/bytecodealliance/wac).
+
 `wasm-compose` is a library for composing [WebAssembly components](https://github.com/webassembly/component-model)
 from other WebAssembly components.
 
diff --git a/crates/wasm-encoder/src/core/code.rs b/crates/wasm-encoder/src/core/code.rs
index 4834b206..de176686 100644
--- a/crates/wasm-encoder/src/core/code.rs
+++ b/crates/wasm-encoder/src/core/code.rs
@@ -1020,6 +1020,34 @@ pub enum Instruction<'a> {
         ordering: Ordering,
         global_index: u32,
     },
+    GlobalAtomicRmwAdd {
+        ordering: Ordering,
+        global_index: u32,
+    },
+    GlobalAtomicRmwSub {
+        ordering: Ordering,
+        global_index: u32,
+    },
+    GlobalAtomicRmwAnd {
+        ordering: Ordering,
+        global_index: u32,
+    },
+    GlobalAtomicRmwOr {
+        ordering: Ordering,
+        global_index: u32,
+    },
+    GlobalAtomicRmwXor {
+        ordering: Ordering,
+        global_index: u32,
+    },
+    GlobalAtomicRmwXchg {
+        ordering: Ordering,
+        global_index: u32,
+    },
+    GlobalAtomicRmwCmpxchg {
+        ordering: Ordering,
+        global_index: u32,
+    },
 }
 
 impl Encode for Instruction<'_> {
@@ -3183,6 +3211,69 @@ impl Encode for Instruction<'_> {
                 ordering.encode(sink);
                 global_index.encode(sink);
             }
+            Instruction::GlobalAtomicRmwAdd {
+                ordering,
+                global_index,
+            } => {
+                sink.push(0xFE);
+                sink.push(0x51);
+                ordering.encode(sink);
+                global_index.encode(sink);
+            }
+            Instruction::GlobalAtomicRmwSub {
+                ordering,
+                global_index,
+            } => {
+                sink.push(0xFE);
+                sink.push(0x52);
+                ordering.encode(sink);
+                global_index.encode(sink);
+            }
+            Instruction::GlobalAtomicRmwAnd {
+                ordering,
+                global_index,
+            } => {
+                sink.push(0xFE);
+                sink.push(0x53);
+                ordering.encode(sink);
+                global_index.encode(sink);
+            }
+            Instruction::GlobalAtomicRmwOr {
+                ordering,
+                global_index,
+            } => {
+                sink.push(0xFE);
+                sink.push(0x54);
+                ordering.encode(sink);
+                global_index.encode(sink);
+            }
+            Instruction::GlobalAtomicRmwXor {
+                ordering,
+                global_index,
+            } => {
+                sink.push(0xFE);
+                sink.push(0x55);
+                ordering.encode(sink);
+                global_index.encode(sink);
+            }
+            Instruction::GlobalAtomicRmwXchg {
+                ordering,
+                global_index,
+            } => {
+                sink.push(0xFE);
+                sink.push(0x56);
+                ordering.encode(sink);
+                global_index.encode(sink);
+            }
+            Instruction::GlobalAtomicRmwCmpxchg {
+                ordering,
+                global_index,
+            } => {
+                sink.push(0xFE);
+                sink.push(0x57);
+                ordering.encode(sink);
+                global_index.encode(sink);
+            }
         }
     }
 }
diff --git a/crates/wasmparser/src/binary_reader.rs b/crates/wasmparser/src/binary_reader.rs
index cf286946..fe059792 100644
--- a/crates/wasmparser/src/binary_reader.rs
+++ b/crates/wasmparser/src/binary_reader.rs
@@ -1684,6 +1684,25 @@ impl<'a> BinaryReader<'a> {
             // Decode shared-everything-threads proposal.
             0x4f => visitor.visit_global_atomic_get(self.read_ordering()?, self.read_var_u32()?),
             0x50 => visitor.visit_global_atomic_set(self.read_ordering()?, self.read_var_u32()?),
+            0x51 => {
+                visitor.visit_global_atomic_rmw_add(self.read_ordering()?, self.read_var_u32()?)
+            }
+            0x52 => {
+                visitor.visit_global_atomic_rmw_sub(self.read_ordering()?, self.read_var_u32()?)
+            }
+            0x53 => {
+                visitor.visit_global_atomic_rmw_and(self.read_ordering()?, self.read_var_u32()?)
+            }
+            0x54 => visitor.visit_global_atomic_rmw_or(self.read_ordering()?, self.read_var_u32()?),
+            0x55 => {
+                visitor.visit_global_atomic_rmw_xor(self.read_ordering()?, self.read_var_u32()?)
+            }
+            0x56 => {
+                visitor.visit_global_atomic_rmw_xchg(self.read_ordering()?, self.read_var_u32()?)
+            }
+            0x57 => {
+                visitor.visit_global_atomic_rmw_cmpxchg(self.read_ordering()?, self.read_var_u32()?)
+            }
 
             _ => bail!(pos, "unknown 0xfe subopcode: 0x{code:x}"),
         })
diff --git a/crates/wasmparser/src/lib.rs b/crates/wasmparser/src/lib.rs
index 28cc15bb..909dbea7 100644
--- a/crates/wasmparser/src/lib.rs
+++ b/crates/wasmparser/src/lib.rs
@@ -498,6 +498,13 @@ macro_rules! for_each_operator {
             // https://github.com/WebAssembly/shared-everything-threads
             @shared_everything_threads GlobalAtomicGet { ordering: $crate::Ordering, global_index: u32 } => visit_global_atomic_get
             @shared_everything_threads GlobalAtomicSet { ordering: $crate::Ordering, global_index: u32 } => visit_global_atomic_set
+            @shared_everything_threads GlobalAtomicRmwAdd { ordering: $crate::Ordering, global_index: u32 } => visit_global_atomic_rmw_add
+            @shared_everything_threads GlobalAtomicRmwSub { ordering: $crate::Ordering, global_index: u32 } => visit_global_atomic_rmw_sub
+            @shared_everything_threads GlobalAtomicRmwAnd { ordering: $crate::Ordering, global_index: u32 } => visit_global_atomic_rmw_and
+            @shared_everything_threads GlobalAtomicRmwOr { ordering: $crate::Ordering, global_index: u32 } => visit_global_atomic_rmw_or
+            @shared_everything_threads GlobalAtomicRmwXor { ordering: $crate::Ordering, global_index: u32 } => visit_global_atomic_rmw_xor
+            @shared_everything_threads GlobalAtomicRmwXchg { ordering: $crate::Ordering, global_index: u32 } => visit_global_atomic_rmw_xchg
+            @shared_everything_threads GlobalAtomicRmwCmpxchg { ordering: $crate::Ordering, global_index: u32 } => visit_global_atomic_rmw_cmpxchg
 
             // 0xFD operators
             // 128-bit SIMD
diff --git a/crates/wasmparser/src/validator/operators.rs b/crates/wasmparser/src/validator/operators.rs
index 8e99b399..a3d1c313 100644
--- a/crates/wasmparser/src/validator/operators.rs
+++ b/crates/wasmparser/src/validator/operators.rs
@@ -22,13 +22,13 @@
 // confusing it's recommended to read over that section to see how it maps to
 // the various methods here.
 
-use crate::prelude::*;
 use crate::{
     limits::MAX_WASM_FUNCTION_LOCALS, ArrayType, BinaryReaderError, BlockType, BrTable, Catch,
     CompositeType, FieldType, FuncType, HeapType, Ieee32, Ieee64, MemArg, RefType, Result,
     StorageType, StructType, SubType, TableType, TryTable, UnpackedIndex, ValType, VisitOperator,
     WasmFeatures, WasmModuleResources, V128,
 };
+use crate::{prelude::*, GlobalType};
 use core::ops::{Deref, DerefMut};
 
 pub(crate) struct OperatorValidator {
@@ -938,8 +938,8 @@ where
         Ok(())
     }
 
-    /// Checks the validity of a common atomic binary operator.
-    fn check_atomic_binary_op(&mut self, memarg: MemArg, op_ty: ValType) -> Result<()> {
+    /// Checks the validity of atomic binary operator on memory.
+    fn check_atomic_binary_memory_op(&mut self, memarg: MemArg, op_ty: ValType) -> Result<()> {
         let ty = self.check_shared_memarg(memarg)?;
         self.pop_operand(Some(op_ty))?;
         self.pop_operand(Some(ty))?;
@@ -947,8 +947,8 @@ where
         Ok(())
     }
 
-    /// Checks the validity of an atomic compare exchange operator.
-    fn check_atomic_binary_cmpxchg(&mut self, memarg: MemArg, op_ty: ValType) -> Result<()> {
+    /// Checks the validity of an atomic compare exchange operator on memories.
+    fn check_atomic_binary_memory_cmpxchg(&mut self, memarg: MemArg, op_ty: ValType) -> Result<()> {
         let ty = self.check_shared_memarg(memarg)?;
         self.pop_operand(Some(op_ty))?;
         self.pop_operand(Some(op_ty))?;
@@ -1073,22 +1073,17 @@ where
         self.push_operand(sub_ty)
     }
 
-    /// Common helper for checking the types of global types accessed
-    /// atomically.
-    fn check_atomic_global_ty(&self, global_index: u32) -> Result<()> {
-        let ty = self
-            .resources
-            .global_at(global_index)
-            .expect("existence should be checked prior to this point");
-        let ty = ty.content_type;
-        let supertype = RefType::ANYREF.into();
-        if !(ty == ValType::I32 || ty == ValType::I64 || self.resources.is_subtype(ty, supertype)) {
+    /// Common helper for checking the types of globals accessed with atomic RMW
+    /// instructions, which only allow `i32` and `i64`.
+    fn check_atomic_global_rmw_ty(&self, global_index: u32) -> Result<ValType> {
+        let ty = self.global_type_at(global_index)?.content_type;
+        if !(ty == ValType::I32 || ty == ValType::I64) {
             bail!(
-                    self.offset,
-                    "invalid type: `global.atomic.get` only allows `i32`, `i64` and subtypes of `anyref`"
-                );
+                self.offset,
+                "invalid type: `global.atomic.rmw.*` only allows `i32` and `i64`"
+            );
         }
-        Ok(())
+        Ok(ty)
     }
 
     fn element_type_at(&self, elem_index: u32) -> Result<RefType> {
@@ -1163,6 +1158,14 @@ where
             .ok_or_else(|| format_err!(self.offset, "unknown tag {}: tag index out of bounds", at))
     }
 
+    fn global_type_at(&self, at: u32) -> Result<GlobalType> {
+        if let Some(ty) = self.resources.global_at(at) {
+            Ok(ty)
+        } else {
+            bail!(self.offset, "unknown global: global index out of bounds");
+        }
+    }
+
     fn params(&self, ty: BlockType) -> Result<impl PreciseIterator<Item = ValType> + 'resources> {
         Ok(match ty {
             BlockType::Empty | BlockType::Type(_) => Either::B(None.into_iter()),
@@ -1631,13 +1634,9 @@ where
         Ok(())
     }
     fn visit_global_get(&mut self, global_index: u32) -> Self::Output {
-        if let Some(ty) = self.resources.global_at(global_index) {
-            let ty = ty.content_type;
-            debug_assert_type_indices_are_ids(ty);
-            self.push_operand(ty)?;
-        } else {
-            bail!(self.offset, "unknown global: global index out of bounds");
-        };
+        let ty = self.global_type_at(global_index)?.content_type;
+        debug_assert_type_indices_are_ids(ty);
+        self.push_operand(ty)?;
         Ok(())
     }
     fn visit_global_atomic_get(
@@ -1647,22 +1646,24 @@ where
     ) -> Self::Output {
         self.visit_global_get(global_index)?;
         // No validation of `ordering` is needed because `global.atomic.get` can
-        // be used on both shared and unshared globals.
-        self.check_atomic_global_ty(global_index)?;
+        // be used on both shared and unshared globals. But we do need to limit
+        // which types can be used with this instruction.
+        let ty = self.global_type_at(global_index)?.content_type;
+        let supertype = RefType::ANYREF.into();
+        if !(ty == ValType::I32 || ty == ValType::I64 || self.resources.is_subtype(ty, supertype)) {
+            bail!(self.offset, "invalid type: `global.atomic.get` only allows `i32`, `i64` and subtypes of `anyref`");
+        }
         Ok(())
     }
     fn visit_global_set(&mut self, global_index: u32) -> Self::Output {
-        if let Some(ty) = self.resources.global_at(global_index) {
-            if !ty.mutable {
-                bail!(
-                    self.offset,
-                    "global is immutable: cannot modify it with `global.set`"
-                );
-            }
-            self.pop_operand(Some(ty.content_type))?;
-        } else {
-            bail!(self.offset, "unknown global: global index out of bounds");
-        };
+        let ty = self.global_type_at(global_index)?;
+        if !ty.mutable {
+            bail!(
+                self.offset,
+                "global is immutable: cannot modify it with `global.set`"
+            );
+        }
+        self.pop_operand(Some(ty.content_type))?;
         Ok(())
     }
     fn visit_global_atomic_set(
@@ -1673,9 +1674,82 @@ where
         self.visit_global_set(global_index)?;
         // No validation of `ordering` is needed because `global.atomic.get` can
         // be used on both shared and unshared globals.
-        self.check_atomic_global_ty(global_index)?;
+        let ty = self.global_type_at(global_index)?.content_type;
+        let supertype = RefType::ANYREF.into();
+        if !(ty == ValType::I32 || ty == ValType::I64 || self.resources.is_subtype(ty, supertype)) {
+            bail!(self.offset, "invalid type: `global.atomic.set` only allows `i32`, `i64` and subtypes of `anyref`");
+        }
         Ok(())
     }
+    fn visit_global_atomic_rmw_add(
+        &mut self,
+        _ordering: crate::Ordering,
+        global_index: u32,
+    ) -> Self::Output {
+        let ty = self.check_atomic_global_rmw_ty(global_index)?;
+        self.check_unary_op(ty)
+    }
+    fn visit_global_atomic_rmw_sub(
+        &mut self,
+        _ordering: crate::Ordering,
+        global_index: u32,
+    ) -> Self::Output {
+        let ty = self.check_atomic_global_rmw_ty(global_index)?;
+        self.check_unary_op(ty)
+    }
+    fn visit_global_atomic_rmw_and(
+        &mut self,
+        _ordering: crate::Ordering,
+        global_index: u32,
+    ) -> Self::Output {
+        let ty = self.check_atomic_global_rmw_ty(global_index)?;
+        self.check_unary_op(ty)
+    }
+    fn visit_global_atomic_rmw_or(
+        &mut self,
+        _ordering: crate::Ordering,
+        global_index: u32,
+    ) -> Self::Output {
+        let ty = self.check_atomic_global_rmw_ty(global_index)?;
+        self.check_unary_op(ty)
+    }
+    fn visit_global_atomic_rmw_xor(
+        &mut self,
+        _ordering: crate::Ordering,
+        global_index: u32,
+    ) -> Self::Output {
+        let ty = self.check_atomic_global_rmw_ty(global_index)?;
+        self.check_unary_op(ty)
+    }
+    fn visit_global_atomic_rmw_xchg(
+        &mut self,
+        _ordering: crate::Ordering,
+        global_index: u32,
+    ) -> Self::Output {
+        let ty = self.global_type_at(global_index)?.content_type;
+        if !(ty == ValType::I32
+            || ty == ValType::I64
+            || self.resources.is_subtype(ty, RefType::ANYREF.into()))
+        {
+            bail!(self.offset, "invalid type: `global.atomic.rmw.xchg` only allows `i32`, `i64` and subtypes of `anyref`");
+        }
+        self.check_unary_op(ty)
+    }
+    fn visit_global_atomic_rmw_cmpxchg(
+        &mut self,
+        _ordering: crate::Ordering,
+        global_index: u32,
+    ) -> Self::Output {
+        let ty = self.global_type_at(global_index)?.content_type;
+        if !(ty == ValType::I32
+            || ty == ValType::I64
+            || self.resources.is_subtype(ty, RefType::EQREF.into()))
+        {
+            bail!(self.offset, "invalid type: `global.atomic.rmw.cmpxchg` only allows `i32`, `i64` and subtypes of `eqref`");
+        }
+        self.check_binary_op(ty)
+    }
+
     fn visit_i32_load(&mut self, memarg: MemArg) -> Self::Output {
         let ty = self.check_memarg(memarg)?;
         self.pop_operand(Some(ty))?;
@@ -2293,154 +2367,154 @@ where
         self.check_atomic_store(memarg, ValType::I64)
     }
     fn visit_i32_atomic_rmw_add(&mut self, memarg: MemArg) -> Self::Output {
-        self.check_atomic_binary_op(memarg, ValType::I32)
+        self.check_atomic_binary_memory_op(memarg, ValType::I32)
     }
     fn visit_i32_atomic_rmw_sub(&mut self, memarg: MemArg) -> Self::Output {
-        self.check_atomic_binary_op(memarg, ValType::I32)
+        self.check_atomic_binary_memory_op(memarg, ValType::I32)
     }
     fn visit_i32_atomic_rmw_and(&mut self, memarg: MemArg) -> Self::Output {
-        self.check_atomic_binary_op(memarg, ValType::I32)
+        self.check_atomic_binary_memory_op(memarg, ValType::I32)
     }
     fn visit_i32_atomic_rmw_or(&mut self, memarg: MemArg) -> Self::Output {
-        self.check_atomic_binary_op(memarg, ValType::I32)
+        self.check_atomic_binary_memory_op(memarg, ValType::I32)
     }
     fn visit_i32_atomic_rmw_xor(&mut self, memarg: MemArg) -> Self::Output {
-        self.check_atomic_binary_op(memarg, ValType::I32)
+        self.check_atomic_binary_memory_op(memarg, ValType::I32)
     }
     fn visit_i32_atomic_rmw16_add_u(&mut self, memarg: MemArg) -> Self::Output {
-        self.check_atomic_binary_op(memarg, ValType::I32)
+        self.check_atomic_binary_memory_op(memarg, ValType::I32)
     }
     fn visit_i32_atomic_rmw16_sub_u(&mut self, memarg: MemArg) -> Self::Output {
-        self.check_atomic_binary_op(memarg, ValType::I32)
+        self.check_atomic_binary_memory_op(memarg, ValType::I32)
     }
     fn visit_i32_atomic_rmw16_and_u(&mut self, memarg: MemArg) -> Self::Output {
-        self.check_atomic_binary_op(memarg, ValType::I32)
+        self.check_atomic_binary_memory_op(memarg, ValType::I32)
     }
     fn visit_i32_atomic_rmw16_or_u(&mut self, memarg: MemArg) -> Self::Output {
-        self.check_atomic_binary_op(memarg, ValType::I32)
+        self.check_atomic_binary_memory_op(memarg, ValType::I32)
     }
     fn visit_i32_atomic_rmw16_xor_u(&mut self, memarg: MemArg) -> Self::Output {
-        self.check_atomic_binary_op(memarg, ValType::I32)
+        self.check_atomic_binary_memory_op(memarg, ValType::I32)
     }
     fn visit_i32_atomic_rmw8_add_u(&mut self, memarg: MemArg) -> Self::Output {
-        self.check_atomic_binary_op(memarg, ValType::I32)
+        self.check_atomic_binary_memory_op(memarg, ValType::I32)
     }
     fn visit_i32_atomic_rmw8_sub_u(&mut self, memarg: MemArg) -> Self::Output {
-        self.check_atomic_binary_op(memarg, ValType::I32)
+        self.check_atomic_binary_memory_op(memarg, ValType::I32)
     }
     fn visit_i32_atomic_rmw8_and_u(&mut self, memarg: MemArg) -> Self::Output {
-        self.check_atomic_binary_op(memarg, ValType::I32)
+        self.check_atomic_binary_memory_op(memarg, ValType::I32)
     }
     fn visit_i32_atomic_rmw8_or_u(&mut self, memarg: MemArg) -> Self::Output {
-        self.check_atomic_binary_op(memarg, ValType::I32)
+        self.check_atomic_binary_memory_op(memarg, ValType::I32)
     }
     fn visit_i32_atomic_rmw8_xor_u(&mut self, memarg: MemArg) -> Self::Output {
-        self.check_atomic_binary_op(memarg, ValType::I32)
+        self.check_atomic_binary_memory_op(memarg, ValType::I32)
     }
     fn visit_i64_atomic_rmw_add(&mut self, memarg: MemArg) -> Self::Output {
-        self.check_atomic_binary_op(memarg, ValType::I64)
+        self.check_atomic_binary_memory_op(memarg, ValType::I64)
     }
     fn visit_i64_atomic_rmw_sub(&mut self, memarg: MemArg) -> Self::Output {
-        self.check_atomic_binary_op(memarg, ValType::I64)
+        self.check_atomic_binary_memory_op(memarg, ValType::I64)
     }
     fn visit_i64_atomic_rmw_and(&mut self, memarg: MemArg) -> Self::Output {
-        self.check_atomic_binary_op(memarg, ValType::I64)
+        self.check_atomic_binary_memory_op(memarg, ValType::I64)
     }
     fn visit_i64_atomic_rmw_or(&mut self, memarg: MemArg) -> Self::Output {
-        self.check_atomic_binary_op(memarg, ValType::I64)
+        self.check_atomic_binary_memory_op(memarg, ValType::I64)
     }
     fn visit_i64_atomic_rmw_xor(&mut self, memarg: MemArg) -> Self::Output {
-        self.check_atomic_binary_op(memarg, ValType::I64)
+        self.check_atomic_binary_memory_op(memarg, ValType::I64)
     }
     fn visit_i64_atomic_rmw32_add_u(&mut self, memarg: MemArg) -> Self::Output {
-        self.check_atomic_binary_op(memarg, ValType::I64)
+        self.check_atomic_binary_memory_op(memarg, ValType::I64)
     }
     fn visit_i64_atomic_rmw32_sub_u(&mut self, memarg: MemArg) -> Self::Output {
-        self.check_atomic_binary_op(memarg, ValType::I64)
+        self.check_atomic_binary_memory_op(memarg, ValType::I64)
     }
     fn visit_i64_atomic_rmw32_and_u(&mut self, memarg: MemArg) -> Self::Output {
-        self.check_atomic_binary_op(memarg, ValType::I64)
+        self.check_atomic_binary_memory_op(memarg, ValType::I64)
     }
     fn visit_i64_atomic_rmw32_or_u(&mut self, memarg: MemArg) -> Self::Output {
-        self.check_atomic_binary_op(memarg, ValType::I64)
+        self.check_atomic_binary_memory_op(memarg, ValType::I64)
     }
     fn visit_i64_atomic_rmw32_xor_u(&mut self, memarg: MemArg) -> Self::Output {
-        self.check_atomic_binary_op(memarg, ValType::I64)
+        self.check_atomic_binary_memory_op(memarg, ValType::I64)
     }
     fn visit_i64_atomic_rmw16_add_u(&mut self, memarg: MemArg) -> Self::Output {
-        self.check_atomic_binary_op(memarg, ValType::I64)
+        self.check_atomic_binary_memory_op(memarg, ValType::I64)
     }
     fn visit_i64_atomic_rmw16_sub_u(&mut self, memarg: MemArg) -> Self::Output {
-        self.check_atomic_binary_op(memarg, ValType::I64)
+        self.check_atomic_binary_memory_op(memarg, ValType::I64)
     }
     fn visit_i64_atomic_rmw16_and_u(&mut self, memarg: MemArg) -> Self::Output {
-        self.check_atomic_binary_op(memarg, ValType::I64)
+        self.check_atomic_binary_memory_op(memarg, ValType::I64)
     }
     fn visit_i64_atomic_rmw16_or_u(&mut self, memarg: MemArg) -> Self::Output {
-        self.check_atomic_binary_op(memarg, ValType::I64)
+        self.check_atomic_binary_memory_op(memarg, ValType::I64)
     }
     fn visit_i64_atomic_rmw16_xor_u(&mut self, memarg: MemArg) -> Self::Output {
-        self.check_atomic_binary_op(memarg, ValType::I64)
+        self.check_atomic_binary_memory_op(memarg, ValType::I64)
     }
     fn visit_i64_atomic_rmw8_add_u(&mut self, memarg: MemArg) -> Self::Output {
-        self.check_atomic_binary_op(memarg, ValType::I64)
+        self.check_atomic_binary_memory_op(memarg, ValType::I64)
     }
     fn visit_i64_atomic_rmw8_sub_u(&mut self, memarg: MemArg) -> Self::Output {
-        self.check_atomic_binary_op(memarg, ValType::I64)
+        self.check_atomic_binary_memory_op(memarg, ValType::I64)
     }
     fn visit_i64_atomic_rmw8_and_u(&mut self, memarg: MemArg) -> Self::Output {
-        self.check_atomic_binary_op(memarg, ValType::I64)
+        self.check_atomic_binary_memory_op(memarg, ValType::I64)
     }
     fn visit_i64_atomic_rmw8_or_u(&mut self, memarg: MemArg) -> Self::Output {
-        self.check_atomic_binary_op(memarg, ValType::I64)
+        self.check_atomic_binary_memory_op(memarg, ValType::I64)
     }
     fn visit_i64_atomic_rmw8_xor_u(&mut self, memarg: MemArg) -> Self::Output {
-        self.check_atomic_binary_op(memarg, ValType::I64)
+        self.check_atomic_binary_memory_op(memarg, ValType::I64)
     }
     fn visit_i32_atomic_rmw_xchg(&mut self, memarg: MemArg) -> Self::Output {
-        self.check_atomic_binary_op(memarg, ValType::I32)
+        self.check_atomic_binary_memory_op(memarg, ValType::I32)
     }
     fn visit_i32_atomic_rmw16_xchg_u(&mut self, memarg: MemArg) -> Self::Output {
-        self.check_atomic_binary_op(memarg, ValType::I32)
+        self.check_atomic_binary_memory_op(memarg, ValType::I32)
     }
     fn visit_i32_atomic_rmw8_xchg_u(&mut self, memarg: MemArg) -> Self::Output {
-        self.check_atomic_binary_op(memarg, ValType::I32)
+        self.check_atomic_binary_memory_op(memarg, ValType::I32)
     }
     fn visit_i32_atomic_rmw_cmpxchg(&mut self, memarg: MemArg) -> Self::Output {
-        self.check_atomic_binary_cmpxchg(memarg, ValType::I32)
+        self.check_atomic_binary_memory_cmpxchg(memarg, ValType::I32)
     }
     fn visit_i32_atomic_rmw16_cmpxchg_u(&mut self, memarg: MemArg) -> Self::Output {
-        self.check_atomic_binary_cmpxchg(memarg, ValType::I32)
+        self.check_atomic_binary_memory_cmpxchg(memarg, ValType::I32)
     }
     fn visit_i32_atomic_rmw8_cmpxchg_u(&mut self, memarg: MemArg) -> Self::Output {
-        self.check_atomic_binary_cmpxchg(memarg, ValType::I32)
+        self.check_atomic_binary_memory_cmpxchg(memarg, ValType::I32)
     }
     fn visit_i64_atomic_rmw_xchg(&mut self, memarg: MemArg) -> Self::Output {
-        self.check_atomic_binary_op(memarg, ValType::I64)
+        self.check_atomic_binary_memory_op(memarg, ValType::I64)
     }
     fn visit_i64_atomic_rmw32_xchg_u(&mut self, memarg: MemArg) -> Self::Output {
-        self.check_atomic_binary_op(memarg, ValType::I64)
+        self.check_atomic_binary_memory_op(memarg, ValType::I64)
     }
     fn visit_i64_atomic_rmw16_xchg_u(&mut self, memarg: MemArg) -> Self::Output {
-        self.check_atomic_binary_op(memarg, ValType::I64)
+        self.check_atomic_binary_memory_op(memarg, ValType::I64)
     }
     fn visit_i64_atomic_rmw8_xchg_u(&mut self, memarg: MemArg) -> Self::Output {
-        self.check_atomic_binary_op(memarg, ValType::I64)
+        self.check_atomic_binary_memory_op(memarg, ValType::I64)
     }
     fn visit_i64_atomic_rmw_cmpxchg(&mut self, memarg: MemArg) -> Self::Output {
-        self.check_atomic_binary_cmpxchg(memarg, ValType::I64)
+        self.check_atomic_binary_memory_cmpxchg(memarg, ValType::I64)
     }
     fn visit_i64_atomic_rmw32_cmpxchg_u(&mut self, memarg: MemArg) -> Self::Output {
-        self.check_atomic_binary_cmpxchg(memarg, ValType::I64)
+        self.check_atomic_binary_memory_cmpxchg(memarg, ValType::I64)
     }
     fn visit_i64_atomic_rmw16_cmpxchg_u(&mut self, memarg: MemArg) -> Self::Output {
-        self.check_atomic_binary_cmpxchg(memarg, ValType::I64)
+        self.check_atomic_binary_memory_cmpxchg(memarg, ValType::I64)
     }
     fn visit_i64_atomic_rmw8_cmpxchg_u(&mut self, memarg: MemArg) -> Self::Output {
-        self.check_atomic_binary_cmpxchg(memarg, ValType::I64)
+        self.check_atomic_binary_memory_cmpxchg(memarg, ValType::I64)
     }
     fn visit_memory_atomic_notify(&mut self, memarg: MemArg) -> Self::Output {
-        self.check_atomic_binary_op(memarg, ValType::I32)
+        self.check_atomic_binary_memory_op(memarg, ValType::I32)
     }
     fn visit_memory_atomic_wait32(&mut self, memarg: MemArg) -> Self::Output {
         let ty = self.check_shared_memarg(memarg)?;
diff --git a/crates/wasmprinter/src/operator.rs b/crates/wasmprinter/src/operator.rs
index fcb3acc5..6b6f6211 100644
--- a/crates/wasmprinter/src/operator.rs
+++ b/crates/wasmprinter/src/operator.rs
@@ -1155,6 +1155,13 @@ macro_rules! define_visit {
     (name Delegate) => ("delegate");
     (name GlobalAtomicGet) => ("global.atomic.get");
     (name GlobalAtomicSet) => ("global.atomic.set");
+    (name GlobalAtomicRmwAdd) => ("global.atomic.rmw.add");
+    (name GlobalAtomicRmwSub) => ("global.atomic.rmw.sub");
+    (name GlobalAtomicRmwAnd) => ("global.atomic.rmw.and");
+    (name GlobalAtomicRmwOr) => ("global.atomic.rmw.or");
+    (name GlobalAtomicRmwXor) => ("global.atomic.rmw.xor");
+    (name GlobalAtomicRmwXchg) => ("global.atomic.rmw.xchg");
+    (name GlobalAtomicRmwCmpxchg) => ("global.atomic.rmw.cmpxchg");
 }
 
 impl<'a> VisitOperator<'a> for PrintOperator<'_, '_> {
diff --git a/crates/wast/src/core/expr.rs b/crates/wast/src/core/expr.rs
index df0abb7c..df585c22 100644
--- a/crates/wast/src/core/expr.rs
+++ b/crates/wast/src/core/expr.rs
@@ -803,6 +803,13 @@ instructions! {
         // proposal: shared-everything-threads
         GlobalAtomicGet(OrderedAccess<'a>) : [0xfe, 0x4f] : "global.atomic.get",
         GlobalAtomicSet(OrderedAccess<'a>) : [0xfe, 0x50] : "global.atomic.set",
+        GlobalAtomicRmwAdd(OrderedAccess<'a>) : [0xfe, 0x51] : "global.atomic.rmw.add",
+        GlobalAtomicRmwSub(OrderedAccess<'a>) : [0xfe, 0x52] : "global.atomic.rmw.sub",
+        GlobalAtomicRmwAnd(OrderedAccess<'a>) : [0xfe, 0x53] : "global.atomic.rmw.and",
+        GlobalAtomicRmwOr(OrderedAccess<'a>) : [0xfe, 0x54] : "global.atomic.rmw.or",
+        GlobalAtomicRmwXor(OrderedAccess<'a>) : [0xfe, 0x55] : "global.atomic.rmw.xor",
+        GlobalAtomicRmwXchg(OrderedAccess<'a>) : [0xfe, 0x56] : "global.atomic.rmw.xchg",
+        GlobalAtomicRmwCmpxchg(OrderedAccess<'a>) : [0xfe, 0x57] : "global.atomic.rmw.cmpxchg",
 
         // proposal: simd
         //
diff --git a/crates/wast/src/core/resolve/names.rs b/crates/wast/src/core/resolve/names.rs
index f17590bb..b73195cb 100644
--- a/crates/wast/src/core/resolve/names.rs
+++ b/crates/wast/src/core/resolve/names.rs
@@ -457,7 +457,15 @@ impl<'a, 'b> ExprResolver<'a, 'b> {
                 self.resolver.resolve(i, Ns::Global)?;
             }
 
-            GlobalAtomicSet(i) | GlobalAtomicGet(i) => {
+            GlobalAtomicSet(i)
+            | GlobalAtomicGet(i)
+            | GlobalAtomicRmwAdd(i)
+            | GlobalAtomicRmwSub(i)
+            | GlobalAtomicRmwAnd(i)
+            | GlobalAtomicRmwOr(i)
+            | GlobalAtomicRmwXor(i)
+            | GlobalAtomicRmwXchg(i)
+            | GlobalAtomicRmwCmpxchg(i) => {
                 self.resolver.resolve(&mut i.index, Ns::Global)?;
             }
 
diff --git a/src/bin/wasm-tools/compose.rs b/src/bin/wasm-tools/compose.rs
index c2fbc89d..6b2516ef 100644
--- a/src/bin/wasm-tools/compose.rs
+++ b/src/bin/wasm-tools/compose.rs
@@ -53,6 +53,9 @@ impl Opts {
     }
 
     pub fn run(self) -> Result<()> {
+        eprintln!("WARNING: `wasm-tools compose` has been deprecated.");
+        eprintln!("");
+        eprintln!("Please use `wac` instead. You can find more information about `wac` at https://github.com/bytecodealliance/wac.");
         let config = self.create_config()?;
         log::debug!("configuration:\n{:#?}", config);
 


Test patch:
diff --git a/tests/local/shared-everything-threads/global.wast b/tests/local/shared-everything-threads/global.wast
index 2281017c..ad33bf2b 100644
--- a/tests/local/shared-everything-threads/global.wast
+++ b/tests/local/shared-everything-threads/global.wast
@@ -1,4 +1,40 @@
-;; Styled after ../../testsuite/global.wast
+;; Check shared attribute.
+
+(module
+  ;; Imported.
+  (global (import "spectest" "global_i32") (shared i32))
+  (global (import "spectest" "global_i32_mut") (shared mut i32))
+  (global (import "spectest" "global_i64") (shared i64))
+  (global (import "spectest" "global_i64_mut") (shared mut i64))
+  (global (import "spectest" "global_f32") (shared i32))
+  (global (import "spectest" "global_f32_mut") (shared mut f32))
+  (global (import "spectest" "global_f64") (shared f64))
+  (global (import "spectest" "global_f64_mut") (shared mut f64))
+  (global (import "spectest" "global_v128") (shared v128))
+  (global (import "spectest" "global_v128_mut") (shared mut v128))
+
+  ;; Initialized.
+  (global (shared i32) (i32.const 0))
+  (global (shared mut i32) (i32.const 0))
+  (global (shared i64) (i64.const 0))
+  (global (shared mut i64) (i64.const 0))
+  (global (shared f32) (f32.const 0))
+  (global (shared mut f32) (f32.const 0))
+  (global (shared f64) (f64.const 0))
+  (global (shared mut f64) (f64.const 0))
+  (global (shared v128) (v128.const i64x2 0 0))
+  (global (shared mut v128) (v128.const i64x2 0 0))
+)
+
+(assert_malformed
+  (module quote "(global (mut shared i64) (i64.const -1))")
+  "unexpected token")
+
+(assert_invalid
+  (module (global $a (import "spectest" "global_ref") (shared funcref)))
+  "shared value type")
+
+;; Check global.atomic.get, global.atomic.set.
 
 (module
   (global $a (import "spectest" "global_i32") (shared i32))
@@ -12,10 +48,6 @@
   (func (export "set-e-acqrel") (global.atomic.set acq_rel $e (i64.const 2)))
 )
 
-(assert_malformed
-  (module quote "(global (mut shared i64) (i64.const -1))")
-  "unexpected token")
-
 (assert_invalid
   (module
     (global $a (shared i32) (i32.const 0))
@@ -23,15 +55,316 @@
   )
   "global is immutable")
 
+(assert_invalid
+  (module
+    (global $a (shared mut f32) (f32.const 0))
+    (func (result f32) (global.atomic.get seq_cst $a))
+  )
+  "invalid type")
+
+(assert_invalid
+  (module
+    (global $a (shared mut f32) (f32.const 0))
+    (func (global.atomic.set seq_cst $a (f32.const 0)))
+  )
+  "invalid type")
+
+(assert_invalid
+  (module
+    (global $a (shared mut f32) (f32.const 0))
+    (func (result f32) (global.atomic.get acq_rel $a))
+  )
+  "invalid type")
+
+(assert_invalid
+  (module
+    (global $a (shared mut f32) (f32.const 0))
+    (func (global.atomic.set acq_rel $a (f32.const 0)))
+  )
+  "invalid type")
+
+(assert_invalid
+  (module
+    (global $a (shared f32) (f32.const 0))
+    (func (result f32) (global.atomic.get seq_cst $a))
+  )
+  "invalid type")
+
+(assert_invalid
+  (module
+    (global $a (shared f32) (f32.const 0))
+    (func (result f32) (global.atomic.get acq_rel $a))
+  )
+  "invalid type")
+
 (assert_invalid
   (module
     (global $a (shared mut f64) (f64.const 0))
-    (func (export "set-shared") (global.atomic.set acq_rel $a (f64.const 1.0)))
+    (func (result f64) (global.atomic.get seq_cst $a))
   )
   "invalid type")
 
 (assert_invalid
   (module
-    (global $a (import "spectest" "global_ref") (shared funcref))
+    (global $a (shared mut f64) (f64.const 0))
+    (func (global.atomic.set seq_cst $a (f64.const 0)))
   )
-  "shared value type")
+  "invalid type")
+
+(assert_invalid
+  (module
+    (global $a (shared mut f64) (f64.const 0))
+    (func (result f64) (global.atomic.get acq_rel $a))
+  )
+  "invalid type")
+
+(assert_invalid
+  (module
+    (global $a (shared mut f64) (f64.const 0))
+    (func (global.atomic.set acq_rel $a (f64.const 0)))
+  )
+  "invalid type")
+
+(assert_invalid
+  (module
+    (global $a (shared f64) (f64.const 0))
+    (func (result f64) (global.atomic.get seq_cst $a))
+  )
+  "invalid type")
+
+(assert_invalid
+  (module
+    (global $a (shared f64) (f64.const 0))
+    (func (result f64) (global.atomic.get acq_rel $a))
+  )
+  "invalid type")
+
+(assert_invalid
+  (module
+    (global $a (shared mut v128) (v128.const i64x2 0 0))
+    (func (result v128) (global.atomic.get seq_cst $a))
+  )
+  "invalid type")
+
+(assert_invalid
+  (module
+    (global $a (shared mut v128) (v128.const i64x2 0 0))
+    (func (global.atomic.set seq_cst $a (v128.const i64x2 0 0)))
+  )
+  "invalid type")
+
+(assert_invalid
+  (module
+    (global $a (shared mut v128) (v128.const i64x2 0 0))
+    (func (result v128) (global.atomic.get acq_rel $a))
+  )
+  "invalid type")
+
+(assert_invalid
+  (module
+    (global $a (shared mut v128) (v128.const i64x2 0 0))
+    (func (global.atomic.set acq_rel $a (v128.const i64x2 0 0)))
+  )
+  "invalid type")
+
+(assert_invalid
+  (module
+    (global $a (shared v128) (v128.const i64x2 0 0))
+    (func (result v128) (global.atomic.get seq_cst $a))
+  )
+  "invalid type")
+
+(assert_invalid
+  (module
+    (global $a (shared v128) (v128.const i64x2 0 0))
+    (func (result v128) (global.atomic.get acq_rel $a))
+  )
+  "invalid type")
+
+;; Check global.atomic.rmw.*.
+(module (;i32;)
+  (global $a (import "spectest" "global_i32") (shared mut i32))
+  (global $b (shared mut i32) (i32.const 0))
+  (func (export "rmw-add-i32-seq_cst-$a") (param $x i32) (result i32)
+    local.get $x
+    global.atomic.rmw.add seq_cst $a)
+  (func (export "rmw-add-i32-seq_cst-$b") (param $x i32) (result i32)
+    local.get $x
+    global.atomic.rmw.add seq_cst $b)
+  (func (export "rmw-add-i32-acq_rel-$a") (param $x i32) (result i32)
+    local.get $x
+    global.atomic.rmw.add acq_rel $a)
+  (func (export "rmw-add-i32-acq_rel-$b") (param $x i32) (result i32)
+    local.get $x
+    global.atomic.rmw.add acq_rel $b)
+  (func (export "rmw-sub-i32-seq_cst-$a") (param $x i32) (result i32)
+    local.get $x
+    global.atomic.rmw.sub seq_cst $a)
+  (func (export "rmw-sub-i32-seq_cst-$b") (param $x i32) (result i32)
+    local.get $x
+    global.atomic.rmw.sub seq_cst $b)
+  (func (export "rmw-sub-i32-acq_rel-$a") (param $x i32) (result i32)
+    local.get $x
+    global.atomic.rmw.sub acq_rel $a)
+  (func (export "rmw-sub-i32-acq_rel-$b") (param $x i32) (result i32)
+    local.get $x
+    global.atomic.rmw.sub acq_rel $b)
+  (func (export "rmw-and-i32-seq_cst-$a") (param $x i32) (result i32)
+    local.get $x
+    global.atomic.rmw.and seq_cst $a)
+  (func (export "rmw-and-i32-seq_cst-$b") (param $x i32) (result i32)
+    local.get $x
+    global.atomic.rmw.and seq_cst $b)
+  (func (export "rmw-and-i32-acq_rel-$a") (param $x i32) (result i32)
+    local.get $x
+    global.atomic.rmw.and acq_rel $a)
+  (func (export "rmw-and-i32-acq_rel-$b") (param $x i32) (result i32)
+    local.get $x
+    global.atomic.rmw.and acq_rel $b)
+  (func (export "rmw-or-i32-seq_cst-$a") (param $x i32) (result i32)
+    local.get $x
+    global.atomic.rmw.or seq_cst $a)
+  (func (export "rmw-or-i32-seq_cst-$b") (param $x i32) (result i32)
+    local.get $x
+    global.atomic.rmw.or seq_cst $b)
+  (func (export "rmw-or-i32-acq_rel-$a") (param $x i32) (result i32)
+    local.get $x
+    global.atomic.rmw.or acq_rel $a)
+  (func (export "rmw-or-i32-acq_rel-$b") (param $x i32) (result i32)
+    local.get $x
+    global.atomic.rmw.or acq_rel $b)
+  (func (export "rmw-xor-i32-seq_cst-$a") (param $x i32) (result i32)
+    local.get $x
+    global.atomic.rmw.xor seq_cst $a)
+  (func (export "rmw-xor-i32-seq_cst-$b") (param $x i32) (result i32)
+    local.get $x
+    global.atomic.rmw.xor seq_cst $b)
+  (func (export "rmw-xor-i32-acq_rel-$a") (param $x i32) (result i32)
+    local.get $x
+    global.atomic.rmw.xor acq_rel $a)
+  (func (export "rmw-xor-i32-acq_rel-$b") (param $x i32) (result i32)
+    local.get $x
+    global.atomic.rmw.xor acq_rel $b)
+  (func (export "rmw-xchg-i32-seq_cst-$a") (param $x i32) (result i32)
+    local.get $x
+    global.atomic.rmw.xchg seq_cst $a)
+  (func (export "rmw-xchg-i32-seq_cst-$b") (param $x i32) (result i32)
+    local.get $x
+    global.atomic.rmw.xchg seq_cst $b)
+  (func (export "rmw-xchg-i32-acq_rel-$a") (param $x i32) (result i32)
+    local.get $x
+    global.atomic.rmw.xchg acq_rel $a)
+  (func (export "rmw-xchg-i32-acq_rel-$b") (param $x i32) (result i32)
+    local.get $x
+    global.atomic.rmw.xchg acq_rel $b)
+  (func (export "rmw-cmpxchg-i32-seq_cst-$a") (param $x i32) (param $y i32) (result i32)
+    local.get $x
+    local.get $y
+    global.atomic.rmw.cmpxchg seq_cst $a)
+  (func (export "rmw-cmpxchg-i32-seq_cst-$b") (param $x i32) (param $y i32) (result i32)
+    local.get $x
+    local.get $y
+    global.atomic.rmw.cmpxchg seq_cst $b)
+  (func (export "rmw-cmpxchg-i32-acq_rel-$a") (param $x i32) (param $y i32) (result i32)
+    local.get $x
+    local.get $y
+    global.atomic.rmw.cmpxchg acq_rel $a)
+  (func (export "rmw-cmpxchg-i32-acq_rel-$b") (param $x i32) (param $y i32) (result i32)
+    local.get $x
+    local.get $y
+    global.atomic.rmw.cmpxchg acq_rel $b)
+)
+
+(module (;i64;)
+  (global $a (import "spectest" "global_i64") (shared mut i64))
+  (global $b (shared mut i64) (i64.const 0))
+  (func (export "rmw-add-i64-seq_cst-$a") (param $x i64) (result i64)
+    local.get $x
+    global.atomic.rmw.add seq_cst $a)
+  (func (export "rmw-add-i64-seq_cst-$b") (param $x i64) (result i64)
+    local.get $x
+    global.atomic.rmw.add seq_cst $b)
+  (func (export "rmw-add-i64-acq_rel-$a") (param $x i64) (result i64)
+    local.get $x
+    global.atomic.rmw.add acq_rel $a)
+  (func (export "rmw-add-i64-acq_rel-$b") (param $x i64) (result i64)
+    local.get $x
+    global.atomic.rmw.add acq_rel $b)
+  (func (export "rmw-sub-i64-seq_cst-$a") (param $x i64) (result i64)
+    local.get $x
+    global.atomic.rmw.sub seq_cst $a)
+  (func (export "rmw-sub-i64-seq_cst-$b") (param $x i64) (result i64)
+    local.get $x
+    global.atomic.rmw.sub seq_cst $b)
+  (func (export "rmw-sub-i64-acq_rel-$a") (param $x i64) (result i64)
+    local.get $x
+    global.atomic.rmw.sub acq_rel $a)
+  (func (export "rmw-sub-i64-acq_rel-$b") (param $x i64) (result i64)
+    local.get $x
+    global.atomic.rmw.sub acq_rel $b)
+  (func (export "rmw-and-i64-seq_cst-$a") (param $x i64) (result i64)
+    local.get $x
+    global.atomic.rmw.and seq_cst $a)
+  (func (export "rmw-and-i64-seq_cst-$b") (param $x i64) (result i64)
+    local.get $x
+    global.atomic.rmw.and seq_cst $b)
+  (func (export "rmw-and-i64-acq_rel-$a") (param $x i64) (result i64)
+    local.get $x
+    global.atomic.rmw.and acq_rel $a)
+  (func (export "rmw-and-i64-acq_rel-$b") (param $x i64) (result i64)
+    local.get $x
+    global.atomic.rmw.and acq_rel $b)
+  (func (export "rmw-or-i64-seq_cst-$a") (param $x i64) (result i64)
+    local.get $x
+    global.atomic.rmw.or seq_cst $a)
+  (func (export "rmw-or-i64-seq_cst-$b") (param $x i64) (result i64)
+    local.get $x
+    global.atomic.rmw.or seq_cst $b)
+  (func (export "rmw-or-i64-acq_rel-$a") (param $x i64) (result i64)
+    local.get $x
+    global.atomic.rmw.or acq_rel $a)
+  (func (export "rmw-or-i64-acq_rel-$b") (param $x i64) (result i64)
+    local.get $x
+    global.atomic.rmw.or acq_rel $b)
+  (func (export "rmw-xor-i64-seq_cst-$a") (param $x i64) (result i64)
+    local.get $x
+    global.atomic.rmw.xor seq_cst $a)
+  (func (export "rmw-xor-i64-seq_cst-$b") (param $x i64) (result i64)
+    local.get $x
+    global.atomic.rmw.xor seq_cst $b)
+  (func (export "rmw-xor-i64-acq_rel-$a") (param $x i64) (result i64)
+    local.get $x
+    global.atomic.rmw.xor acq_rel $a)
+  (func (export "rmw-xor-i64-acq_rel-$b") (param $x i64) (result i64)
+    local.get $x
+    global.atomic.rmw.xor acq_rel $b)
+  (func (export "rmw-xchg-i64-seq_cst-$a") (param $x i64) (result i64)
+    local.get $x
+    global.atomic.rmw.xchg seq_cst $a)
+  (func (export "rmw-xchg-i64-seq_cst-$b") (param $x i64) (result i64)
+    local.get $x
+    global.atomic.rmw.xchg seq_cst $b)
+  (func (export "rmw-xchg-i64-acq_rel-$a") (param $x i64) (result i64)
+    local.get $x
+    global.atomic.rmw.xchg acq_rel $a)
+  (func (export "rmw-xchg-i64-acq_rel-$b") (param $x i64) (result i64)
+    local.get $x
+    global.atomic.rmw.xchg acq_rel $b)
+  (func (export "rmw-cmpxchg-i64-seq_cst-$a") (param $x i64) (param $y i64) (result i64)
+    local.get $x
+    local.get $y
+    global.atomic.rmw.cmpxchg seq_cst $a)
+  (func (export "rmw-cmpxchg-i64-seq_cst-$b") (param $x i64) (param $y i64) (result i64)
+    local.get $x
+    local.get $y
+    global.atomic.rmw.cmpxchg seq_cst $b)
+  (func (export "rmw-cmpxchg-i64-acq_rel-$a") (param $x i64) (param $y i64) (result i64)
+    local.get $x
+    local.get $y
+    global.atomic.rmw.cmpxchg acq_rel $a)
+  (func (export "rmw-cmpxchg-i64-acq_rel-$b") (param $x i64) (param $y i64) (result i64)
+    local.get $x
+    local.get $y
+    global.atomic.rmw.cmpxchg acq_rel $b)
+)
+
diff --git a/tests/snapshots/local/shared-everything-threads/global.wast.json b/tests/snapshots/local/shared-everything-threads/global.wast.json
index 1ff22c67..250e98b1 100644
--- a/tests/snapshots/local/shared-everything-threads/global.wast.json
+++ b/tests/snapshots/local/shared-everything-threads/global.wast.json
@@ -8,31 +8,165 @@
     },
     {
       "type": "assert_malformed",
-      "line": 16,
+      "line": 30,
       "filename": "global.1.wat",
       "text": "unexpected token",
       "module_type": "text"
     },
     {
       "type": "assert_invalid",
-      "line": 20,
+      "line": 34,
       "filename": "global.2.wasm",
+      "text": "shared value type",
+      "module_type": "binary"
+    },
+    {
+      "type": "module",
+      "line": 39,
+      "filename": "global.3.wasm"
+    },
+    {
+      "type": "assert_invalid",
+      "line": 52,
+      "filename": "global.4.wasm",
       "text": "global is immutable",
       "module_type": "binary"
     },
     {
       "type": "assert_invalid",
-      "line": 27,
-      "filename": "global.3.wasm",
+      "line": 59,
+      "filename": "global.5.wasm",
       "text": "invalid type",
       "module_type": "binary"
     },
     {
       "type": "assert_invalid",
-      "line": 34,
-      "filename": "global.4.wasm",
-      "text": "shared value type",
+      "line": 66,
+      "filename": "global.6.wasm",
+      "text": "invalid type",
+      "module_type": "binary"
+    },
+    {
+      "type": "assert_invalid",
+      "line": 73,
+      "filename": "global.7.wasm",
+      "text": "invalid type",
+      "module_type": "binary"
+    },
+    {
+      "type": "assert_invalid",
+      "line": 80,
+      "filename": "global.8.wasm",
+      "text": "invalid type",
+      "module_type": "binary"
+    },
+    {
+      "type": "assert_invalid",
+      "line": 87,
+      "filename": "global.9.wasm",
+      "text": "invalid type",
+      "module_type": "binary"
+    },
+    {
+      "type": "assert_invalid",
+      "line": 94,
+      "filename": "global.10.wasm",
+      "text": "invalid type",
+      "module_type": "binary"
+    },
+    {
+      "type": "assert_invalid",
+      "line": 101,
+      "filename": "global.11.wasm",
+      "text": "invalid type",
+      "module_type": "binary"
+    },
+    {
+      "type": "assert_invalid",
+      "line": 108,
+      "filename": "global.12.wasm",
+      "text": "invalid type",
+      "module_type": "binary"
+    },
+    {
+      "type": "assert_invalid",
+      "line": 115,
+      "filename": "global.13.wasm",
+      "text": "invalid type",
+      "module_type": "binary"
+    },
+    {
+      "type": "assert_invalid",
+      "line": 122,
+      "filename": "global.14.wasm",
+      "text": "invalid type",
+      "module_type": "binary"
+    },
+    {
+      "type": "assert_invalid",
+      "line": 129,
+      "filename": "global.15.wasm",
+      "text": "invalid type",
+      "module_type": "binary"
+    },
+    {
+      "type": "assert_invalid",
+      "line": 136,
+      "filename": "global.16.wasm",
+      "text": "invalid type",
+      "module_type": "binary"
+    },
+    {
+      "type": "assert_invalid",
+      "line": 143,
+      "filename": "global.17.wasm",
+      "text": "invalid type",
+      "module_type": "binary"
+    },
+    {
+      "type": "assert_invalid",
+      "line": 150,
+      "filename": "global.18.wasm",
+      "text": "invalid type",
+      "module_type": "binary"
+    },
+    {
+      "type": "assert_invalid",
+      "line": 157,
+      "filename": "global.19.wasm",
+      "text": "invalid type",
       "module_type": "binary"
+    },
+    {
+      "type": "assert_invalid",
+      "line": 164,
+      "filename": "global.20.wasm",
+      "text": "invalid type",
+      "module_type": "binary"
+    },
+    {
+      "type": "assert_invalid",
+      "line": 171,
+      "filename": "global.21.wasm",
+      "text": "invalid type",
+      "module_type": "binary"
+    },
+    {
+      "type": "assert_invalid",
+      "line": 178,
+      "filename": "global.22.wasm",
+      "text": "invalid type",
+      "module_type": "binary"
+    },
+    {
+      "type": "module",
+      "line": 185,
+      "filename": "global.23.wasm"
+    },
+    {
+      "type": "module",
+      "line": 278,
+      "filename": "global.24.wasm"
     }
   ]
 }
\ No newline at end of file
diff --git a/tests/snapshots/local/shared-everything-threads/global.wast/0.print b/tests/snapshots/local/shared-everything-threads/global.wast/0.print
index 9fddda89..b79452f3 100644
--- a/tests/snapshots/local/shared-everything-threads/global.wast/0.print
+++ b/tests/snapshots/local/shared-everything-threads/global.wast/0.print
@@ -1,26 +1,22 @@
 (module
-  (type (;0;) (func (result i32)))
-  (type (;1;) (func))
-  (import "spectest" "global_i32" (global $a (;0;) (shared i32)))
-  (import "spectest" "global_i64" (global $b (;1;) (shared mut i64)))
-  (func (;0;) (type 0) (result i32)
-    global.atomic.get seq_cst $a
-  )
-  (func (;1;) (type 1)
-    i64.const 1
-    global.atomic.set seq_cst $b
-  )
-  (func (;2;) (type 0) (result i32)
-    global.atomic.get acq_rel $d
-  )
-  (func (;3;) (type 1)
-    i64.const 2
-    global.atomic.set acq_rel $e
-  )
-  (global $d (;2;) (shared i32) i32.const 0)
-  (global $e (;3;) (shared mut i64) i64.const 1)
-  (export "get-a-seqcst" (func 0))
-  (export "set-b-seqcst" (func 1))
-  (export "get-d-acqrel" (func 2))
-  (export "set-e-acqrel" (func 3))
+  (import "spectest" "global_i32" (global (;0;) (shared i32)))
+  (import "spectest" "global_i32_mut" (global (;1;) (shared mut i32)))
+  (import "spectest" "global_i64" (global (;2;) (shared i64)))
+  (import "spectest" "global_i64_mut" (global (;3;) (shared mut i64)))
+  (import "spectest" "global_f32" (global (;4;) (shared i32)))
+  (import "spectest" "global_f32_mut" (global (;5;) (shared mut f32)))
+  (import "spectest" "global_f64" (global (;6;) (shared f64)))
+  (import "spectest" "global_f64_mut" (global (;7;) (shared mut f64)))
+  (import "spectest" "global_v128" (global (;8;) (shared v128)))
+  (import "spectest" "global_v128_mut" (global (;9;) (shared mut v128)))
+  (global (;10;) (shared i32) i32.const 0)
+  (global (;11;) (shared mut i32) i32.const 0)
+  (global (;12;) (shared i64) i64.const 0)
+  (global (;13;) (shared mut i64) i64.const 0)
+  (global (;14;) (shared f32) f32.const 0x0p+0 (;=0;))
+  (global (;15;) (shared mut f32) f32.const 0x0p+0 (;=0;))
+  (global (;16;) (shared f64) f64.const 0x0p+0 (;=0;))
+  (global (;17;) (shared mut f64) f64.const 0x0p+0 (;=0;))
+  (global (;18;) (shared v128) v128.const i32x4 0x00000000 0x00000000 0x00000000 0x00000000)
+  (global (;19;) (shared mut v128) v128.const i32x4 0x00000000 0x00000000 0x00000000 0x00000000)
 )
diff --git a/tests/snapshots/local/shared-everything-threads/global.wast/23.print b/tests/snapshots/local/shared-everything-threads/global.wast/23.print
new file mode 100644
index 00000000..0e052f4e
--- /dev/null
+++ b/tests/snapshots/local/shared-everything-threads/global.wast/23.print
@@ -0,0 +1,150 @@
+(module
+  (type (;0;) (func (param i32) (result i32)))
+  (type (;1;) (func (param i32 i32) (result i32)))
+  (import "spectest" "global_i32" (global $a (;0;) (shared mut i32)))
+  (func (;0;) (type 0) (param $x i32) (result i32)
+    local.get $x
+    global.atomic.rmw.add seq_cst $a
+  )
+  (func (;1;) (type 0) (param $x i32) (result i32)
+    local.get $x
+    global.atomic.rmw.add seq_cst $b
+  )
+  (func (;2;) (type 0) (param $x i32) (result i32)
+    local.get $x
+    global.atomic.rmw.add acq_rel $a
+  )
+  (func (;3;) (type 0) (param $x i32) (result i32)
+    local.get $x
+    global.atomic.rmw.add acq_rel $b
+  )
+  (func (;4;) (type 0) (param $x i32) (result i32)
+    local.get $x
+    global.atomic.rmw.sub seq_cst $a
+  )
+  (func (;5;) (type 0) (param $x i32) (result i32)
+    local.get $x
+    global.atomic.rmw.sub seq_cst $b
+  )
+  (func (;6;) (type 0) (param $x i32) (result i32)
+    local.get $x
+    global.atomic.rmw.sub acq_rel $a
+  )
+  (func (;7;) (type 0) (param $x i32) (result i32)
+    local.get $x
+    global.atomic.rmw.sub acq_rel $b
+  )
+  (func (;8;) (type 0) (param $x i32) (result i32)
+    local.get $x
+    global.atomic.rmw.and seq_cst $a
+  )
+  (func (;9;) (type 0) (param $x i32) (result i32)
+    local.get $x
+    global.atomic.rmw.and seq_cst $b
+  )
+  (func (;10;) (type 0) (param $x i32) (result i32)
+    local.get $x
+    global.atomic.rmw.and acq_rel $a
+  )
+  (func (;11;) (type 0) (param $x i32) (result i32)
+    local.get $x
+    global.atomic.rmw.and acq_rel $b
+  )
+  (func (;12;) (type 0) (param $x i32) (result i32)
+    local.get $x
+    global.atomic.rmw.or seq_cst $a
+  )
+  (func (;13;) (type 0) (param $x i32) (result i32)
+    local.get $x
+    global.atomic.rmw.or seq_cst $b
+  )
+  (func (;14;) (type 0) (param $x i32) (result i32)
+    local.get $x
+    global.atomic.rmw.or acq_rel $a
+  )
+  (func (;15;) (type 0) (param $x i32) (result i32)
+    local.get $x
+    global.atomic.rmw.or acq_rel $b
+  )
+  (func (;16;) (type 0) (param $x i32) (result i32)
+    local.get $x
+    global.atomic.rmw.xor seq_cst $a
+  )
+  (func (;17;) (type 0) (param $x i32) (result i32)
+    local.get $x
+    global.atomic.rmw.xor seq_cst $b
+  )
+  (func (;18;) (type 0) (param $x i32) (result i32)
+    local.get $x
+    global.atomic.rmw.xor acq_rel $a
+  )
+  (func (;19;) (type 0) (param $x i32) (result i32)
+    local.get $x
+    global.atomic.rmw.xor acq_rel $b
+  )
+  (func (;20;) (type 0) (param $x i32) (result i32)
+    local.get $x
+    global.atomic.rmw.xchg seq_cst $a
+  )
+  (func (;21;) (type 0) (param $x i32) (result i32)
+    local.get $x
+    global.atomic.rmw.xchg seq_cst $b
+  )
+  (func (;22;) (type 0) (param $x i32) (result i32)
+    local.get $x
+    global.atomic.rmw.xchg acq_rel $a
+  )
+  (func (;23;) (type 0) (param $x i32) (result i32)
+    local.get $x
+    global.atomic.rmw.xchg acq_rel $b
+  )
+  (func (;24;) (type 1) (param $x i32) (param $y i32) (result i32)
+    local.get $x
+    local.get $y
+    global.atomic.rmw.cmpxchg seq_cst $a
+  )
+  (func (;25;) (type 1) (param $x i32) (param $y i32) (result i32)
+    local.get $x
+    local.get $y
+    global.atomic.rmw.cmpxchg seq_cst $b
+  )
+  (func (;26;) (type 1) (param $x i32) (param $y i32) (result i32)
+    local.get $x
+    local.get $y
+    global.atomic.rmw.cmpxchg acq_rel $a
+  )
+  (func (;27;) (type 1) (param $x i32) (param $y i32) (result i32)
+    local.get $x
+    local.get $y
+    global.atomic.rmw.cmpxchg acq_rel $b
+  )
+  (global $b (;1;) (shared mut i32) i32.const 0)
+  (export "rmw-add-i32-seq_cst-$a" (func 0))
+  (export "rmw-add-i32-seq_cst-$b" (func 1))
+  (export "rmw-add-i32-acq_rel-$a" (func 2))
+  (export "rmw-add-i32-acq_rel-$b" (func 3))
+  (export "rmw-sub-i32-seq_cst-$a" (func 4))
+  (export "rmw-sub-i32-seq_cst-$b" (func 5))
+  (export "rmw-sub-i32-acq_rel-$a" (func 6))
+  (export "rmw-sub-i32-acq_rel-$b" (func 7))
+  (export "rmw-and-i32-seq_cst-$a" (func 8))
+  (export "rmw-and-i32-seq_cst-$b" (func 9))
+  (export "rmw-and-i32-acq_rel-$a" (func 10))
+  (export "rmw-and-i32-acq_rel-$b" (func 11))
+  (export "rmw-or-i32-seq_cst-$a" (func 12))
+  (export "rmw-or-i32-seq_cst-$b" (func 13))
+  (export "rmw-or-i32-acq_rel-$a" (func 14))
+  (export "rmw-or-i32-acq_rel-$b" (func 15))
+  (export "rmw-xor-i32-seq_cst-$a" (func 16))
+  (export "rmw-xor-i32-seq_cst-$b" (func 17))
+  (export "rmw-xor-i32-acq_rel-$a" (func 18))
+  (export "rmw-xor-i32-acq_rel-$b" (func 19))
+  (export "rmw-xchg-i32-seq_cst-$a" (func 20))
+  (export "rmw-xchg-i32-seq_cst-$b" (func 21))
+  (export "rmw-xchg-i32-acq_rel-$a" (func 22))
+  (export "rmw-xchg-i32-acq_rel-$b" (func 23))
+  (export "rmw-cmpxchg-i32-seq_cst-$a" (func 24))
+  (export "rmw-cmpxchg-i32-seq_cst-$b" (func 25))
+  (export "rmw-cmpxchg-i32-acq_rel-$a" (func 26))
+  (export "rmw-cmpxchg-i32-acq_rel-$b" (func 27))
+)
diff --git a/tests/snapshots/local/shared-everything-threads/global.wast/24.print b/tests/snapshots/local/shared-everything-threads/global.wast/24.print
new file mode 100644
index 00000000..1aac4333
--- /dev/null
+++ b/tests/snapshots/local/shared-everything-threads/global.wast/24.print
@@ -0,0 +1,150 @@
+(module
+  (type (;0;) (func (param i64) (result i64)))
+  (type (;1;) (func (param i64 i64) (result i64)))
+  (import "spectest" "global_i64" (global $a (;0;) (shared mut i64)))
+  (func (;0;) (type 0) (param $x i64) (result i64)
+    local.get $x
+    global.atomic.rmw.add seq_cst $a
+  )
+  (func (;1;) (type 0) (param $x i64) (result i64)
+    local.get $x
+    global.atomic.rmw.add seq_cst $b
+  )
+  (func (;2;) (type 0) (param $x i64) (result i64)
+    local.get $x
+    global.atomic.rmw.add acq_rel $a
+  )
+  (func (;3;) (type 0) (param $x i64) (result i64)
+    local.get $x
+    global.atomic.rmw.add acq_rel $b
+  )
+  (func (;4;) (type 0) (param $x i64) (result i64)
+    local.get $x
+    global.atomic.rmw.sub seq_cst $a
+  )
+  (func (;5;) (type 0) (param $x i64) (result i64)
+    local.get $x
+    global.atomic.rmw.sub seq_cst $b
+  )
+  (func (;6;) (type 0) (param $x i64) (result i64)
+    local.get $x
+    global.atomic.rmw.sub acq_rel $a
+  )
+  (func (;7;) (type 0) (param $x i64) (result i64)
+    local.get $x
+    global.atomic.rmw.sub acq_rel $b
+  )
+  (func (;8;) (type 0) (param $x i64) (result i64)
+    local.get $x
+    global.atomic.rmw.and seq_cst $a
+  )
+  (func (;9;) (type 0) (param $x i64) (result i64)
+    local.get $x
+    global.atomic.rmw.and seq_cst $b
+  )
+  (func (;10;) (type 0) (param $x i64) (result i64)
+    local.get $x
+    global.atomic.rmw.and acq_rel $a
+  )
+  (func (;11;) (type 0) (param $x i64) (result i64)
+    local.get $x
+    global.atomic.rmw.and acq_rel $b
+  )
+  (func (;12;) (type 0) (param $x i64) (result i64)
+    local.get $x
+    global.atomic.rmw.or seq_cst $a
+  )
+  (func (;13;) (type 0) (param $x i64) (result i64)
+    local.get $x
+    global.atomic.rmw.or seq_cst $b
+  )
+  (func (;14;) (type 0) (param $x i64) (result i64)
+    local.get $x
+    global.atomic.rmw.or acq_rel $a
+  )
+  (func (;15;) (type 0) (param $x i64) (result i64)
+    local.get $x
+    global.atomic.rmw.or acq_rel $b
+  )
+  (func (;16;) (type 0) (param $x i64) (result i64)
+    local.get $x
+    global.atomic.rmw.xor seq_cst $a
+  )
+  (func (;17;) (type 0) (param $x i64) (result i64)
+    local.get $x
+    global.atomic.rmw.xor seq_cst $b
+  )
+  (func (;18;) (type 0) (param $x i64) (result i64)
+    local.get $x
+    global.atomic.rmw.xor acq_rel $a
+  )
+  (func (;19;) (type 0) (param $x i64) (result i64)
+    local.get $x
+    global.atomic.rmw.xor acq_rel $b
+  )
+  (func (;20;) (type 0) (param $x i64) (result i64)
+    local.get $x
+    global.atomic.rmw.xchg seq_cst $a
+  )
+  (func (;21;) (type 0) (param $x i64) (result i64)
+    local.get $x
+    global.atomic.rmw.xchg seq_cst $b
+  )
+  (func (;22;) (type 0) (param $x i64) (result i64)
+    local.get $x
+    global.atomic.rmw.xchg acq_rel $a
+  )
+  (func (;23;) (type 0) (param $x i64) (result i64)
+    local.get $x
+    global.atomic.rmw.xchg acq_rel $b
+  )
+  (func (;24;) (type 1) (param $x i64) (param $y i64) (result i64)
+    local.get $x
+    local.get $y
+    global.atomic.rmw.cmpxchg seq_cst $a
+  )
+  (func (;25;) (type 1) (param $x i64) (param $y i64) (result i64)
+    local.get $x
+    local.get $y
+    global.atomic.rmw.cmpxchg seq_cst $b
+  )
+  (func (;26;) (type 1) (param $x i64) (param $y i64) (result i64)
+    local.get $x
+    local.get $y
+    global.atomic.rmw.cmpxchg acq_rel $a
+  )
+  (func (;27;) (type 1) (param $x i64) (param $y i64) (result i64)
+    local.get $x
+    local.get $y
+    global.atomic.rmw.cmpxchg acq_rel $b
+  )
+  (global $b (;1;) (shared mut i64) i64.const 0)
+  (export "rmw-add-i64-seq_cst-$a" (func 0))
+  (export "rmw-add-i64-seq_cst-$b" (func 1))
+  (export "rmw-add-i64-acq_rel-$a" (func 2))
+  (export "rmw-add-i64-acq_rel-$b" (func 3))
+  (export "rmw-sub-i64-seq_cst-$a" (func 4))
+  (export "rmw-sub-i64-seq_cst-$b" (func 5))
+  (export "rmw-sub-i64-acq_rel-$a" (func 6))
+  (export "rmw-sub-i64-acq_rel-$b" (func 7))
+  (export "rmw-and-i64-seq_cst-$a" (func 8))
+  (export "rmw-and-i64-seq_cst-$b" (func 9))
+  (export "rmw-and-i64-acq_rel-$a" (func 10))
+  (export "rmw-and-i64-acq_rel-$b" (func 11))
+  (export "rmw-or-i64-seq_cst-$a" (func 12))
+  (export "rmw-or-i64-seq_cst-$b" (func 13))
+  (export "rmw-or-i64-acq_rel-$a" (func 14))
+  (export "rmw-or-i64-acq_rel-$b" (func 15))
+  (export "rmw-xor-i64-seq_cst-$a" (func 16))
+  (export "rmw-xor-i64-seq_cst-$b" (func 17))
+  (export "rmw-xor-i64-acq_rel-$a" (func 18))
+  (export "rmw-xor-i64-acq_rel-$b" (func 19))
+  (export "rmw-xchg-i64-seq_cst-$a" (func 20))
+  (export "rmw-xchg-i64-seq_cst-$b" (func 21))
+  (export "rmw-xchg-i64-acq_rel-$a" (func 22))
+  (export "rmw-xchg-i64-acq_rel-$b" (func 23))
+  (export "rmw-cmpxchg-i64-seq_cst-$a" (func 24))
+  (export "rmw-cmpxchg-i64-seq_cst-$b" (func 25))
+  (export "rmw-cmpxchg-i64-acq_rel-$a" (func 26))
+  (export "rmw-cmpxchg-i64-acq_rel-$b" (func 27))
+)
diff --git a/tests/snapshots/local/shared-everything-threads/global.wast/3.print b/tests/snapshots/local/shared-everything-threads/global.wast/3.print
new file mode 100644
index 00000000..9fddda89
--- /dev/null
+++ b/tests/snapshots/local/shared-everything-threads/global.wast/3.print
@@ -0,0 +1,26 @@
+(module
+  (type (;0;) (func (result i32)))
+  (type (;1;) (func))
+  (import "spectest" "global_i32" (global $a (;0;) (shared i32)))
+  (import "spectest" "global_i64" (global $b (;1;) (shared mut i64)))
+  (func (;0;) (type 0) (result i32)
+    global.atomic.get seq_cst $a
+  )
+  (func (;1;) (type 1)
+    i64.const 1
+    global.atomic.set seq_cst $b
+  )
+  (func (;2;) (type 0) (result i32)
+    global.atomic.get acq_rel $d
+  )
+  (func (;3;) (type 1)
+    i64.const 2
+    global.atomic.set acq_rel $e
+  )
+  (global $d (;2;) (shared i32) i32.const 0)
+  (global $e (;3;) (shared mut i64) i64.const 1)
+  (export "get-a-seqcst" (func 0))
+  (export "set-b-seqcst" (func 1))
+  (export "get-d-acqrel" (func 2))
+  (export "set-e-acqrel" (func 3))
+)