[clang] [llvm] [WebAssembly] Support acquire-release atomics in CodeGen (PR #184900)

Derek Schuff via cfe-commits cfe-commits at lists.llvm.org
Fri Mar 6 09:57:55 PST 2026


https://github.com/dschuff updated https://github.com/llvm/llvm-project/pull/184900

>From 02407bddfb71b39a7d57caafdcdeb5654accb085 Mon Sep 17 00:00:00 2001
From: Derek Schuff <dschuff at chromium.org>
Date: Thu, 5 Mar 2026 00:47:15 +0000
Subject: [PATCH 1/9] [WebAssembly] Support acquire-release memory orderings in
 CodeGen This commit completes the CodeGen support for matching LLVM IR atomic
 orderings to the newly introduced WebAssembly `MemOrder` immediate operand.
 Instead of duplicating TableGen definitions across the extensive set of
 `PatFrag` combinations in
 [WebAssemblyInstrAtomics.td](cci:7://file:///usr/local/google/home/dschuff/s/llvm-upstream/llvm-project/llvm/lib/Target/WebAssembly/WebAssemblyInstrAtomics.td:0:0-0:0),
 memory ordering constraints are now dynamically computed during ISel and
 MCInst lowering: - Intercepts `WebAssembly::OPERAND_MEMORDER` during MCInst
 lowering (`WebAssemblyMCInstLower::lower`). If the target feature
 `+relaxed-atomics` is enabled, we extract the `MachineMemOperand`'s ordering
 (Acquire, Release, AcquireRelease, or Monotonic) and dynamically map it to
 `acqrel` (1). Fallback logic maps the remaining orderings to `seqcst` (0). -
 Updates `ISD::ATOMIC_FENCE` expansion in `WebAssemblyISelDAGToDAG::Select` to
 natively detect and pass the correct `MemOrder` target constant for
 standalone compiler fences based on their original IR ordering. Adds
 [llvm/test/CodeGen/WebAssembly/atomics-orderings.ll](cci:7://file:///usr/local/google/home/dschuff/s/llvm-upstream/llvm-project/llvm/test/CodeGen/WebAssembly/atomics-orderings.ll:0:0-0:0)
 to verify that `acquire`, `release`, `acq_rel`, and `seq_cst` properly map to
 their target WebAssembly equivalents (load, store, RMW, cmpxchg, and fence).

---
 .../WebAssembly/WebAssemblyISelDAGToDAG.cpp   |  29 +++-
 .../WebAssembly/WebAssemblyMCInstLower.cpp    |  25 +++
 .../CodeGen/WebAssembly/atomics-orderings.ll  | 148 ++++++++++++++++++
 3 files changed, 195 insertions(+), 7 deletions(-)
 create mode 100644 llvm/test/CodeGen/WebAssembly/atomics-orderings.ll

diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyISelDAGToDAG.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyISelDAGToDAG.cpp
index 2541b0433ab59..473546d64d273 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblyISelDAGToDAG.cpp
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyISelDAGToDAG.cpp
@@ -207,17 +207,32 @@ void WebAssemblyDAGToDAGISel::Select(SDNode *Node) {
                                      Node->getOperand(0) // inchain
       );
       break;
-    case SyncScope::System:
-      // Currently wasm only supports sequentially consistent atomics, so we
-      // always set the order to 0 (sequentially consistent).
+    case SyncScope::System: {
+      unsigned Order = 0;
+      if (MF.getSubtarget<WebAssemblySubtarget>().hasRelaxedAtomics()) {
+        auto Ordering =
+            static_cast<AtomicOrdering>(Node->getConstantOperandVal(1));
+        switch (Ordering) {
+        case AtomicOrdering::Acquire:
+        case AtomicOrdering::Release:
+        case AtomicOrdering::AcquireRelease:
+        case AtomicOrdering::Monotonic:
+          Order = 1; // acqrel
+          break;
+        default:
+          Order = 0; // seqcst
+          break;
+        }
+      }
       Fence = CurDAG->getMachineNode(
           WebAssembly::ATOMIC_FENCE,
-          DL,                                         // debug loc
-          MVT::Other,                                 // outchain type
-          CurDAG->getTargetConstant(0, DL, MVT::i32), // order
-          Node->getOperand(0)                         // inchain
+          DL,                                             // debug loc
+          MVT::Other,                                     // outchain type
+          CurDAG->getTargetConstant(Order, DL, MVT::i32), // order
+          Node->getOperand(0)                             // inchain
       );
       break;
+    }
     default:
       llvm_unreachable("Unknown scope!");
     }
diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyMCInstLower.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyMCInstLower.cpp
index e48283aadb437..ac234b7755b5d 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblyMCInstLower.cpp
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyMCInstLower.cpp
@@ -33,6 +33,7 @@
 #include "llvm/MC/MCExpr.h"
 #include "llvm/MC/MCInst.h"
 #include "llvm/MC/MCSymbolWasm.h"
+#include "llvm/Support/AtomicOrdering.h"
 #include "llvm/Support/ErrorHandling.h"
 #include "llvm/Support/raw_ostream.h"
 
@@ -212,6 +213,30 @@ void WebAssemblyMCInstLower::lower(const MachineInstr *MI,
     const MachineOperand &MO = MI->getOperand(I);
 
     MCOperand MCOp;
+
+    if (I < Desc.getNumOperands() &&
+        Desc.operands()[I].OperandType == WebAssembly::OPERAND_MEMORDER &&
+        !MI->memoperands_empty()) {
+      unsigned Order = MO.getImm();
+      auto *MMO = *MI->memoperands_begin();
+      if (MF->getSubtarget<WebAssemblySubtarget>().hasRelaxedAtomics()) {
+        switch (MMO->getMergedOrdering()) {
+        case AtomicOrdering::Acquire:
+        case AtomicOrdering::Release:
+        case AtomicOrdering::AcquireRelease:
+        case AtomicOrdering::Monotonic:
+          Order = 1; // acqrel
+          break;
+        default:
+          Order = 0; // seqcst
+          break;
+        }
+      }
+      MCOp = MCOperand::createImm(Order);
+      OutMI.addOperand(MCOp);
+      continue;
+    }
+
     switch (MO.getType()) {
     default:
       MI->print(errs());
diff --git a/llvm/test/CodeGen/WebAssembly/atomics-orderings.ll b/llvm/test/CodeGen/WebAssembly/atomics-orderings.ll
new file mode 100644
index 0000000000000..95e1930842d56
--- /dev/null
+++ b/llvm/test/CodeGen/WebAssembly/atomics-orderings.ll
@@ -0,0 +1,148 @@
+; RUN: llc < %s --mtriple=wasm32 -mattr=+atomics,+relaxed-atomics | FileCheck %s
+
+; CHECK-LABEL: load_i32_acquire:
+; CHECK: i32.atomic.load acqrel 0
+define i32 @load_i32_acquire(ptr %p) {
+  %v = load atomic i32, ptr %p acquire, align 4
+  ret i32 %v
+}
+
+; CHECK-LABEL: load_i32_seq_cst:
+; CHECK: i32.atomic.load seqcst 0
+define i32 @load_i32_seq_cst(ptr %p) {
+  %v = load atomic i32, ptr %p seq_cst, align 4
+  ret i32 %v
+}
+
+; CHECK-LABEL: store_i32_release:
+; CHECK: i32.atomic.store acqrel 0
+define void @store_i32_release(ptr %p, i32 %v) {
+  store atomic i32 %v, ptr %p release, align 4
+  ret void
+}
+
+; CHECK-LABEL: store_i32_seq_cst:
+; CHECK: i32.atomic.store seqcst 0
+define void @store_i32_seq_cst(ptr %p, i32 %v) {
+  store atomic i32 %v, ptr %p seq_cst, align 4
+  ret void
+}
+
+; CHECK-LABEL: add_i32_acq_rel:
+; CHECK: i32.atomic.rmw.add acqrel 0
+define i32 @add_i32_acq_rel(ptr %p, i32 %v) {
+  %old = atomicrmw add ptr %p, i32 %v acq_rel
+  ret i32 %old
+}
+
+; CHECK-LABEL: add_i32_seq_cst:
+; CHECK: i32.atomic.rmw.add seqcst 0
+define i32 @add_i32_seq_cst(ptr %p, i32 %v) {
+  %old = atomicrmw add ptr %p, i32 %v seq_cst
+  ret i32 %old
+}
+
+; CHECK-LABEL: cmpxchg_i32_acquire_acquire:
+; CHECK: i32.atomic.rmw.cmpxchg acqrel 0
+define i32 @cmpxchg_i32_acquire_acquire(ptr %p, i32 %exp, i32 %new) {
+  %pair = cmpxchg ptr %p, i32 %exp, i32 %new acquire acquire
+  %val = extractvalue { i32, i1 } %pair, 0
+  ret i32 %val
+}
+
+; CHECK-LABEL: cmpxchg_i32_seq_cst_seq_cst:
+; CHECK: i32.atomic.rmw.cmpxchg seqcst 0
+define i32 @cmpxchg_i32_seq_cst_seq_cst(ptr %p, i32 %exp, i32 %new) {
+  %pair = cmpxchg ptr %p, i32 %exp, i32 %new seq_cst seq_cst
+  %val = extractvalue { i32, i1 } %pair, 0
+  ret i32 %val
+}
+
+; CHECK-LABEL: fence_acquire:
+; CHECK: atomic.fence acqrel
+define void @fence_acquire() {
+  fence acquire
+  ret void
+}
+
+; CHECK-LABEL: fence_seq_cst:
+; CHECK: atomic.fence seqcst
+define void @fence_seq_cst() {
+  fence seq_cst
+  ret void
+}
+
+; CHECK-LABEL: load_i32_monotonic:
+; CHECK: i32.atomic.load acqrel 0
+define i32 @load_i32_monotonic(ptr %p) {
+  %v = load atomic i32, ptr %p monotonic, align 4
+  ret i32 %v
+}
+
+; CHECK-LABEL: store_i32_monotonic:
+; CHECK: i32.atomic.store acqrel 0
+define void @store_i32_monotonic(ptr %p, i32 %v) {
+  store atomic i32 %v, ptr %p monotonic, align 4
+  ret void
+}
+
+; CHECK-LABEL: add_i32_release:
+; CHECK: i32.atomic.rmw.add acqrel 0
+define i32 @add_i32_release(ptr %p, i32 %v) {
+  %old = atomicrmw add ptr %p, i32 %v release
+  ret i32 %old
+}
+
+; CHECK-LABEL: add_i32_acquire:
+; CHECK: i32.atomic.rmw.add acqrel 0
+define i32 @add_i32_acquire(ptr %p, i32 %v) {
+  %old = atomicrmw add ptr %p, i32 %v acquire
+  ret i32 %old
+}
+
+; CHECK-LABEL: add_i32_monotonic:
+; CHECK: i32.atomic.rmw.add acqrel 0
+define i32 @add_i32_monotonic(ptr %p, i32 %v) {
+  %old = atomicrmw add ptr %p, i32 %v monotonic
+  ret i32 %old
+}
+
+; CHECK-LABEL: cmpxchg_i32_acq_rel_monotonic:
+; CHECK: i32.atomic.rmw.cmpxchg acqrel 0
+define i32 @cmpxchg_i32_acq_rel_monotonic(ptr %p, i32 %exp, i32 %new) {
+  %pair = cmpxchg ptr %p, i32 %exp, i32 %new acq_rel monotonic
+  %val = extractvalue { i32, i1 } %pair, 0
+  ret i32 %val
+}
+
+; CHECK-LABEL: cmpxchg_i32_release_monotonic:
+; CHECK: i32.atomic.rmw.cmpxchg acqrel 0
+define i32 @cmpxchg_i32_release_monotonic(ptr %p, i32 %exp, i32 %new) {
+  %pair = cmpxchg ptr %p, i32 %exp, i32 %new release monotonic
+  %val = extractvalue { i32, i1 } %pair, 0
+  ret i32 %val
+}
+
+; CHECK-LABEL: cmpxchg_i32_monotonic_monotonic:
+; CHECK: i32.atomic.rmw.cmpxchg acqrel 0
+define i32 @cmpxchg_i32_monotonic_monotonic(ptr %p, i32 %exp, i32 %new) {
+  %pair = cmpxchg ptr %p, i32 %exp, i32 %new monotonic monotonic
+  %val = extractvalue { i32, i1 } %pair, 0
+  ret i32 %val
+}
+
+; CHECK-LABEL: fence_release:
+; CHECK: atomic.fence acqrel
+define void @fence_release() {
+  fence release
+  ret void
+}
+
+; CHECK-LABEL: fence_acq_rel:
+; CHECK: atomic.fence acqrel
+define void @fence_acq_rel() {
+  fence acq_rel
+  ret void
+}
+
+

>From 6c51a93b6d383cc450f95a25a0868a3f87d4bcfe Mon Sep 17 00:00:00 2001
From: Derek Schuff <dschuff at chromium.org>
Date: Thu, 5 Mar 2026 20:36:18 +0000
Subject: [PATCH 2/9] Clang support: feature, flag, and preprocessor
 definitions

---
 clang/include/clang/Options/Options.td         |  2 ++
 clang/lib/Basic/Targets/WebAssembly.cpp        | 11 +++++++++++
 clang/lib/Basic/Targets/WebAssembly.h          |  1 +
 clang/test/Driver/wasm-features.c              |  6 ++++++
 clang/test/Preprocessor/wasm-target-features.c | 11 +++++++++++
 5 files changed, 31 insertions(+)

diff --git a/clang/include/clang/Options/Options.td b/clang/include/clang/Options/Options.td
index fe7169423b6bf..9d3ec8a173472 100644
--- a/clang/include/clang/Options/Options.td
+++ b/clang/include/clang/Options/Options.td
@@ -5688,6 +5688,8 @@ def mnontrapping_fptoint : Flag<["-"], "mnontrapping-fptoint">, Group<m_wasm_Fea
 def mno_nontrapping_fptoint : Flag<["-"], "mno-nontrapping-fptoint">, Group<m_wasm_Features_Group>;
 def mreference_types : Flag<["-"], "mreference-types">, Group<m_wasm_Features_Group>;
 def mno_reference_types : Flag<["-"], "mno-reference-types">, Group<m_wasm_Features_Group>;
+def mrelaxed_atomics : Flag<["-"], "mrelaxed-atomics">, Group<m_wasm_Features_Group>;
+def mno_relaxed_atomics : Flag<["-"], "mno-relaxed-atomics">, Group<m_wasm_Features_Group>;
 def mrelaxed_simd : Flag<["-"], "mrelaxed-simd">, Group<m_wasm_Features_Group>;
 def mno_relaxed_simd : Flag<["-"], "mno-relaxed-simd">, Group<m_wasm_Features_Group>;
 def msign_ext : Flag<["-"], "msign-ext">, Group<m_wasm_Features_Group>;
diff --git a/clang/lib/Basic/Targets/WebAssembly.cpp b/clang/lib/Basic/Targets/WebAssembly.cpp
index daaefd9a1267c..4bb3d521cd9fd 100644
--- a/clang/lib/Basic/Targets/WebAssembly.cpp
+++ b/clang/lib/Basic/Targets/WebAssembly.cpp
@@ -66,6 +66,7 @@ bool WebAssemblyTargetInfo::hasFeature(StringRef Feature) const {
       .Case("mutable-globals", HasMutableGlobals)
       .Case("nontrapping-fptoint", HasNontrappingFPToInt)
       .Case("reference-types", HasReferenceTypes)
+      .Case("relaxed-atomics", HasRelaxedAtomics)
       .Case("relaxed-simd", SIMDLevel >= RelaxedSIMD)
       .Case("sign-ext", HasSignExt)
       .Case("simd128", SIMDLevel >= SIMD128)
@@ -110,6 +111,8 @@ void WebAssemblyTargetInfo::getTargetDefines(const LangOptions &Opts,
     Builder.defineMacro("__wasm_nontrapping_fptoint__");
   if (HasReferenceTypes)
     Builder.defineMacro("__wasm_reference_types__");
+  if (HasRelaxedAtomics)
+    Builder.defineMacro("__wasm_relaxed_atomics__");
   if (SIMDLevel >= RelaxedSIMD)
     Builder.defineMacro("__wasm_relaxed_simd__");
   if (HasSignExt)
@@ -332,6 +335,14 @@ bool WebAssemblyTargetInfo::handleTargetFeatures(
       HasReferenceTypes = false;
       continue;
     }
+    if (Feature == "+relaxed-atomics") {
+      HasRelaxedAtomics = true;
+      continue;
+    }
+    if (Feature == "-relaxed-atomics") {
+      HasRelaxedAtomics = false;
+      continue;
+    }
     if (Feature == "+relaxed-simd") {
       SIMDLevel = std::max(SIMDLevel, RelaxedSIMD);
       continue;
diff --git a/clang/lib/Basic/Targets/WebAssembly.h b/clang/lib/Basic/Targets/WebAssembly.h
index 3a0823bd717d9..8128dd96068a0 100644
--- a/clang/lib/Basic/Targets/WebAssembly.h
+++ b/clang/lib/Basic/Targets/WebAssembly.h
@@ -72,6 +72,7 @@ class LLVM_LIBRARY_VISIBILITY WebAssemblyTargetInfo : public TargetInfo {
   bool HasMutableGlobals = false;
   bool HasNontrappingFPToInt = false;
   bool HasReferenceTypes = false;
+  bool HasRelaxedAtomics = false;
   bool HasSignExt = false;
   bool HasTailCall = false;
   bool HasWideArithmetic = false;
diff --git a/clang/test/Driver/wasm-features.c b/clang/test/Driver/wasm-features.c
index 89ced36eeffab..9e523aa5b53b6 100644
--- a/clang/test/Driver/wasm-features.c
+++ b/clang/test/Driver/wasm-features.c
@@ -77,6 +77,12 @@
 // REFERENCE-TYPES: "-target-feature" "+reference-types"
 // NO-REFERENCE-TYPES: "-target-feature" "-reference-types"
 
+// RUN: %clang --target=wasm32-unknown-unknown -### %s -mrelaxed-atomics 2>&1 | FileCheck %s -check-prefix=RELAXED-ATOMICS
+// RUN: %clang --target=wasm32-unknown-unknown -### %s -mno-relaxed-atomics 2>&1 | FileCheck %s -check-prefix=NO-RELAXED-ATOMICS
+
+// RELAXED-ATOMICS: "-target-feature" "+relaxed-atomics"
+// NO-RELAXED-ATOMICS: "-target-feature" "-relaxed-atomics"
+
 // RUN: %clang --target=wasm32-unknown-unknown -### %s -mrelaxed-simd 2>&1 | FileCheck %s -check-prefix=RELAXED-SIMD
 // RUN: %clang --target=wasm32-unknown-unknown -### %s -mno-relaxed-simd 2>&1 | FileCheck %s -check-prefix=NO-RELAXED-SIMD
 
diff --git a/clang/test/Preprocessor/wasm-target-features.c b/clang/test/Preprocessor/wasm-target-features.c
index 3edaf9e7cd594..aff7442773531 100644
--- a/clang/test/Preprocessor/wasm-target-features.c
+++ b/clang/test/Preprocessor/wasm-target-features.c
@@ -106,6 +106,15 @@
 //
 // REFERENCE-TYPES: #define __wasm_reference_types__ 1{{$}}
 
+// RUN: %clang -E -dM %s -o - 2>&1 \
+// RUN:     -target wasm32-unknown-unknown -mrelaxed-atomics \
+// RUN:   | FileCheck %s -check-prefix=RELAXED-ATOMICS
+// RUN: %clang -E -dM %s -o - 2>&1 \
+// RUN:     -target wasm64-unknown-unknown -mrelaxed-atomics \
+// RUN:   | FileCheck %s -check-prefix=RELAXED-ATOMICS
+//
+// RELAXED-ATOMICS: #define __wasm_relaxed_atomics__ 1{{$}}
+
 // RUN: %clang -E -dM %s -o - 2>&1 \
 // RUN:     -target wasm32-unknown-unknown -mrelaxed-simd \
 // RUN:   | FileCheck %s -check-prefix=RELAXED-SIMD
@@ -160,6 +169,7 @@
 // MVP-NOT: #define __wasm_mutable_globals__ 1{{$}}
 // MVP-NOT: #define __wasm_nontrapping_fptoint__ 1{{$}}
 // MVP-NOT: #define __wasm_reference_types__ 1{{$}}
+// MVP-NOT: #define __wasm_relaxed_atomics__ 1{{$}}
 // MVP-NOT: #define __wasm_relaxed_simd__ 1{{$}}
 // MVP-NOT: #define __wasm_sign_ext__ 1{{$}}
 // MVP-NOT: #define __wasm_simd128__ 1{{$}}
@@ -193,6 +203,7 @@
 // GENERIC-NOT: #define __wasm__fp16__ 1{{$}}
 // GENERIC-NOT: #define __wasm_gc__ 1{{$}}
 // GENERIC-NOT: #define __wasm_multimemory__ 1{{$}}
+// GENERIC-NOT: #define __wasm_relaxed_atomics__ 1{{$}}
 // GENERIC-NOT: #define __wasm_relaxed_simd__ 1{{$}}
 // GENERIC-NOT: #define __wasm_simd128__ 1{{$}}
 // GENERIC-NOT: #define __wasm_tail_call__ 1{{$}}

>From 505892450fbd11a0550a5d8156b88d752930d78c Mon Sep 17 00:00:00 2001
From: Derek Schuff <dschuff at chromium.org>
Date: Thu, 5 Mar 2026 21:08:53 +0000
Subject: [PATCH 3/9] Use a MI pass to set ordering after ISel instead of
 setting it at MC lowering

---
 llvm/lib/Target/WebAssembly/CMakeLists.txt    |  1 +
 llvm/lib/Target/WebAssembly/WebAssembly.h     |  2 +
 .../WebAssembly/WebAssemblyFixupAtomics.cpp   | 89 +++++++++++++++++++
 .../WebAssembly/WebAssemblyMCInstLower.cpp    | 17 +---
 .../WebAssembly/WebAssemblyTargetMachine.cpp  |  4 +-
 5 files changed, 96 insertions(+), 17 deletions(-)
 create mode 100644 llvm/lib/Target/WebAssembly/WebAssemblyFixupAtomics.cpp

diff --git a/llvm/lib/Target/WebAssembly/CMakeLists.txt b/llvm/lib/Target/WebAssembly/CMakeLists.txt
index 1ad99f7e468df..8cbabcd15968c 100644
--- a/llvm/lib/Target/WebAssembly/CMakeLists.txt
+++ b/llvm/lib/Target/WebAssembly/CMakeLists.txt
@@ -67,6 +67,7 @@ add_llvm_target(WebAssemblyCodeGen
   WebAssemblyReplacePhysRegs.cpp
   WebAssemblyRuntimeLibcallSignatures.cpp
   WebAssemblySelectionDAGInfo.cpp
+  WebAssemblyFixupAtomics.cpp
   WebAssemblySetP2AlignOperands.cpp
   WebAssemblySortRegion.cpp
   WebAssemblyMemIntrinsicResults.cpp
diff --git a/llvm/lib/Target/WebAssembly/WebAssembly.h b/llvm/lib/Target/WebAssembly/WebAssembly.h
index 71647974b2843..0c5622f502a5c 100644
--- a/llvm/lib/Target/WebAssembly/WebAssembly.h
+++ b/llvm/lib/Target/WebAssembly/WebAssembly.h
@@ -52,6 +52,7 @@ FunctionPass *createWebAssemblyISelDag(WebAssemblyTargetMachine &TM,
                                        CodeGenOptLevel OptLevel);
 FunctionPass *createWebAssemblyArgumentMove();
 FunctionPass *createWebAssemblySetP2AlignOperands();
+FunctionPass *createWebAssemblyFixupAtomics();
 FunctionPass *createWebAssemblyCleanCodeAfterTrap();
 
 // Late passes.
@@ -103,6 +104,7 @@ void initializeWebAssemblyRegNumberingPass(PassRegistry &);
 void initializeWebAssemblyRegStackifyPass(PassRegistry &);
 void initializeWebAssemblyReplacePhysRegsPass(PassRegistry &);
 void initializeWebAssemblySetP2AlignOperandsPass(PassRegistry &);
+void initializeWebAssemblyFixupAtomicsPass(PassRegistry &);
 
 namespace WebAssembly {
 enum TargetIndex {
diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyFixupAtomics.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyFixupAtomics.cpp
new file mode 100644
index 0000000000000..8f6f40cdcfabd
--- /dev/null
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyFixupAtomics.cpp
@@ -0,0 +1,89 @@
+//===-- WebAssemblyFixupAtomics.cpp - Fixup Atomics -----------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// \brief Fixes memory ordering operands for atomic instructions.
+///
+//===----------------------------------------------------------------------===//
+
+#include "MCTargetDesc/WebAssemblyMCTargetDesc.h"
+#include "WebAssembly.h"
+#include "WebAssemblySubtarget.h"
+#include "llvm/CodeGen/MachineFunctionPass.h"
+#include "llvm/CodeGen/MachineInstrBuilder.h"
+
+using namespace llvm;
+
+#define DEBUG_TYPE "wasm-fixup-atomics"
+
+namespace {
+class WebAssemblyFixupAtomics final : public MachineFunctionPass {
+  StringRef getPassName() const override { return "WebAssembly Fixup Atomics"; }
+
+  void getAnalysisUsage(AnalysisUsage &AU) const override {
+    AU.setPreservesCFG();
+    MachineFunctionPass::getAnalysisUsage(AU);
+  }
+
+  bool runOnMachineFunction(MachineFunction &MF) override;
+
+public:
+  static char ID; // Pass identification, replacement for typeid
+  WebAssemblyFixupAtomics() : MachineFunctionPass(ID) {}
+};
+} // end anonymous namespace
+
+char WebAssemblyFixupAtomics::ID = 0;
+INITIALIZE_PASS(WebAssemblyFixupAtomics, DEBUG_TYPE,
+                "Fixup the memory ordering of atomics", false, false)
+
+FunctionPass *llvm::createWebAssemblyFixupAtomics() {
+  return new WebAssemblyFixupAtomics();
+}
+
+bool WebAssemblyFixupAtomics::runOnMachineFunction(MachineFunction &MF) {
+  LLVM_DEBUG(dbgs() << "********** Fixup Atomics **********\n"
+                    << "********** Function: " << MF.getName() << '\n');
+
+  bool Changed = false;
+  const auto &Subtarget = MF.getSubtarget<WebAssemblySubtarget>();
+  bool HasRelaxedAtomics = Subtarget.hasRelaxedAtomics();
+
+  for (auto &MBB : MF) {
+    for (auto &MI : MBB) {
+      const MCInstrDesc &Desc = MI.getDesc();
+      for (unsigned I = 0, E = MI.getNumExplicitOperands(); I < E; ++I) {
+        if (I < Desc.getNumOperands() &&
+            Desc.operands()[I].OperandType == WebAssembly::OPERAND_MEMORDER) {
+
+          if (HasRelaxedAtomics && !MI.memoperands_empty()) {
+            unsigned Order = 0; // seqcst
+            auto *MMO = *MI.memoperands_begin();
+            switch (MMO->getMergedOrdering()) {
+            case AtomicOrdering::Acquire:
+            case AtomicOrdering::Release:
+            case AtomicOrdering::AcquireRelease:
+            case AtomicOrdering::Monotonic:
+              Order = 1; // acqrel
+              break;
+            default:
+              Order = 0; // seqcst
+              break;
+            }
+            if (MI.getOperand(I).getImm() != Order) {
+              MI.getOperand(I).setImm(Order);
+              Changed = true;
+            }
+          }
+        }
+      }
+    }
+  }
+
+  return Changed;
+}
diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyMCInstLower.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyMCInstLower.cpp
index ac234b7755b5d..4f4cf4d869ed9 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblyMCInstLower.cpp
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyMCInstLower.cpp
@@ -217,22 +217,7 @@ void WebAssemblyMCInstLower::lower(const MachineInstr *MI,
     if (I < Desc.getNumOperands() &&
         Desc.operands()[I].OperandType == WebAssembly::OPERAND_MEMORDER &&
         !MI->memoperands_empty()) {
-      unsigned Order = MO.getImm();
-      auto *MMO = *MI->memoperands_begin();
-      if (MF->getSubtarget<WebAssemblySubtarget>().hasRelaxedAtomics()) {
-        switch (MMO->getMergedOrdering()) {
-        case AtomicOrdering::Acquire:
-        case AtomicOrdering::Release:
-        case AtomicOrdering::AcquireRelease:
-        case AtomicOrdering::Monotonic:
-          Order = 1; // acqrel
-          break;
-        default:
-          Order = 0; // seqcst
-          break;
-        }
-      }
-      MCOp = MCOperand::createImm(Order);
+      MCOp = MCOperand::createImm(MO.getImm());
       OutMI.addOperand(MCOp);
       continue;
     }
diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp
index dce8f54409c41..cb2ea6bf4b6fb 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp
@@ -108,6 +108,7 @@ LLVMInitializeWebAssemblyTarget() {
   initializeWebAssemblyArgumentMovePass(PR);
   initializeWebAssemblyAsmPrinterPass(PR);
   initializeWebAssemblySetP2AlignOperandsPass(PR);
+  initializeWebAssemblyFixupAtomicsPass(PR);
   initializeWebAssemblyReplacePhysRegsPass(PR);
   initializeWebAssemblyOptimizeLiveIntervalsPass(PR);
   initializeWebAssemblyMemIntrinsicResultsPass(PR);
@@ -551,7 +552,7 @@ bool WebAssemblyPassConfig::addInstSelector() {
   // it's inconvenient to collect. Collect it now, and update the immediate
   // operands.
   addPass(createWebAssemblySetP2AlignOperands());
-
+  addPass(createWebAssemblyFixupAtomics());
   // Eliminate range checks and add default targets to br_table instructions.
   addPass(createWebAssemblyFixBrTableDefaults());
 
@@ -713,6 +714,7 @@ bool WebAssemblyPassConfig::addGlobalInstructionSelect() {
   if (isGlobalISelAbortEnabled()) {
     addPass(createWebAssemblyArgumentMove());
     addPass(createWebAssemblySetP2AlignOperands());
+    addPass(createWebAssemblyFixupAtomics());
     addPass(createWebAssemblyFixBrTableDefaults());
     addPass(createWebAssemblyCleanCodeAfterTrap());
   }

>From 2af4d8a081305ec74d32a65378587afb00ea047e Mon Sep 17 00:00:00 2001
From: Derek Schuff <dschuff at chromium.org>
Date: Thu, 5 Mar 2026 21:23:11 +0000
Subject: [PATCH 4/9] add comments, use constants

---
 .../Target/WebAssembly/WebAssemblyFixupAtomics.cpp | 14 +++++++++++---
 .../GlobalISel/gisel-commandline-option.ll         |  2 ++
 2 files changed, 13 insertions(+), 3 deletions(-)

diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyFixupAtomics.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyFixupAtomics.cpp
index 8f6f40cdcfabd..565feb79af9ec 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblyFixupAtomics.cpp
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyFixupAtomics.cpp
@@ -9,11 +9,17 @@
 /// \file
 /// \brief Fixes memory ordering operands for atomic instructions.
 ///
+/// This is used because ISel selects atomics with a default value for the
+/// memory ordering immediate operand. Even though we run this pass early in
+/// the MI pass pipeline, MI passes should still use getMergedOrdering() on
+/// the MachineMemOperand to get the ordering rther than the immediate.
+///
 //===----------------------------------------------------------------------===//
 
 #include "MCTargetDesc/WebAssemblyMCTargetDesc.h"
 #include "WebAssembly.h"
 #include "WebAssemblySubtarget.h"
+#include "llvm/BinaryFormat/Wasm.h"
 #include "llvm/CodeGen/MachineFunctionPass.h"
 #include "llvm/CodeGen/MachineInstrBuilder.h"
 
@@ -62,17 +68,19 @@ bool WebAssemblyFixupAtomics::runOnMachineFunction(MachineFunction &MF) {
             Desc.operands()[I].OperandType == WebAssembly::OPERAND_MEMORDER) {
 
           if (HasRelaxedAtomics && !MI.memoperands_empty()) {
-            unsigned Order = 0; // seqcst
+            assert(MI.getOperand(I).getImm() == wasm::WASM_MEM_ORDER_SEQ_CST &&
+                   "Expected seqcst default atomics from ISel");
+            unsigned Order = wasm::WASM_MEM_ORDER_SEQ_CST;
             auto *MMO = *MI.memoperands_begin();
             switch (MMO->getMergedOrdering()) {
             case AtomicOrdering::Acquire:
             case AtomicOrdering::Release:
             case AtomicOrdering::AcquireRelease:
             case AtomicOrdering::Monotonic:
-              Order = 1; // acqrel
+              Order = wasm::WASM_MEM_ORDER_ACQ_REL;
               break;
             default:
-              Order = 0; // seqcst
+              Order = wasm::WASM_MEM_ORDER_SEQ_CST;
               break;
             }
             if (MI.getOperand(I).getImm() != Order) {
diff --git a/llvm/test/CodeGen/WebAssembly/GlobalISel/gisel-commandline-option.ll b/llvm/test/CodeGen/WebAssembly/GlobalISel/gisel-commandline-option.ll
index 47b05c8160fd1..1389591a34ed6 100644
--- a/llvm/test/CodeGen/WebAssembly/GlobalISel/gisel-commandline-option.ll
+++ b/llvm/test/CodeGen/WebAssembly/GlobalISel/gisel-commandline-option.ll
@@ -31,6 +31,7 @@
 ; ENABLED-NEXT:  InstructionSelect
 ; NOFALLBACK-NEXT:  WebAssembly Argument Move
 ; NOFALLBACK-NEXT:  WebAssembly Set p2align Operands
+; NOFALLBACK-NEXT:  WebAssembly Fixup Atomics
 ; NOFALLBACK-NEXT:  WebAssembly Fix br_table Defaults
 ; NOFALLBACK-NEXT:  WebAssembly Clean Code After Trap
 ; ENABLED-NEXT:  ResetMachineFunction
@@ -38,6 +39,7 @@
 ; FALLBACK:       WebAssembly Instruction Selection
 ; FALLBACK-NEXT:  WebAssembly Argument Move
 ; FALLBACK-NEXT:  WebAssembly Set p2align Operands
+; FALLBACK-NEXT:  WebAssembly Fixup Atomics
 ; FALLBACK-NEXT:  WebAssembly Fix br_table Defaults
 ; FALLBACK-NEXT:  WebAssembly Clean Code After Trap
 

>From db7307f1b230a7f486bed4e72727a810264ae88a Mon Sep 17 00:00:00 2001
From: Derek Schuff <dschuff at chromium.org>
Date: Thu, 5 Mar 2026 21:43:04 +0000
Subject: [PATCH 5/9] cleanups

---
 .../WebAssembly/WebAssemblyISelDAGToDAG.cpp   |   7 +-
 .../WebAssembly/WebAssemblyMCInstLower.cpp    |  10 -
 .../CodeGen/WebAssembly/atomics-orderings.ll  | 177 +++++++++++++-----
 3 files changed, 138 insertions(+), 56 deletions(-)

diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyISelDAGToDAG.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyISelDAGToDAG.cpp
index 473546d64d273..e1f7e51f2af34 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblyISelDAGToDAG.cpp
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyISelDAGToDAG.cpp
@@ -186,7 +186,6 @@ void WebAssemblyDAGToDAGISel::Select(SDNode *Node) {
   auto GlobalGetIns = PtrVT == MVT::i64 ? WebAssembly::GLOBAL_GET_I64
                                         : WebAssembly::GLOBAL_GET_I32;
 
-  // Few custom selection stuff.
   SDLoc DL(Node);
   MachineFunction &MF = CurDAG->getMachineFunction();
   switch (Node->getOpcode()) {
@@ -208,7 +207,7 @@ void WebAssemblyDAGToDAGISel::Select(SDNode *Node) {
       );
       break;
     case SyncScope::System: {
-      unsigned Order = 0;
+      unsigned Order = wasm::WASM_MEM_ORDER_SEQ_CST;
       if (MF.getSubtarget<WebAssemblySubtarget>().hasRelaxedAtomics()) {
         auto Ordering =
             static_cast<AtomicOrdering>(Node->getConstantOperandVal(1));
@@ -217,10 +216,10 @@ void WebAssemblyDAGToDAGISel::Select(SDNode *Node) {
         case AtomicOrdering::Release:
         case AtomicOrdering::AcquireRelease:
         case AtomicOrdering::Monotonic:
-          Order = 1; // acqrel
+          Order = wasm::WASM_MEM_ORDER_ACQ_REL;
           break;
         default:
-          Order = 0; // seqcst
+          Order = wasm::WASM_MEM_ORDER_SEQ_CST;
           break;
         }
       }
diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyMCInstLower.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyMCInstLower.cpp
index 4f4cf4d869ed9..e48283aadb437 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblyMCInstLower.cpp
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyMCInstLower.cpp
@@ -33,7 +33,6 @@
 #include "llvm/MC/MCExpr.h"
 #include "llvm/MC/MCInst.h"
 #include "llvm/MC/MCSymbolWasm.h"
-#include "llvm/Support/AtomicOrdering.h"
 #include "llvm/Support/ErrorHandling.h"
 #include "llvm/Support/raw_ostream.h"
 
@@ -213,15 +212,6 @@ void WebAssemblyMCInstLower::lower(const MachineInstr *MI,
     const MachineOperand &MO = MI->getOperand(I);
 
     MCOperand MCOp;
-
-    if (I < Desc.getNumOperands() &&
-        Desc.operands()[I].OperandType == WebAssembly::OPERAND_MEMORDER &&
-        !MI->memoperands_empty()) {
-      MCOp = MCOperand::createImm(MO.getImm());
-      OutMI.addOperand(MCOp);
-      continue;
-    }
-
     switch (MO.getType()) {
     default:
       MI->print(errs());
diff --git a/llvm/test/CodeGen/WebAssembly/atomics-orderings.ll b/llvm/test/CodeGen/WebAssembly/atomics-orderings.ll
index 95e1930842d56..9095d27493a8e 100644
--- a/llvm/test/CodeGen/WebAssembly/atomics-orderings.ll
+++ b/llvm/test/CodeGen/WebAssembly/atomics-orderings.ll
@@ -1,148 +1,241 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 6
 ; RUN: llc < %s --mtriple=wasm32 -mattr=+atomics,+relaxed-atomics | FileCheck %s
 
-; CHECK-LABEL: load_i32_acquire:
-; CHECK: i32.atomic.load acqrel 0
 define i32 @load_i32_acquire(ptr %p) {
+; CHECK-LABEL: load_i32_acquire:
+; CHECK:         .functype load_i32_acquire (i32) -> (i32)
+; CHECK-NEXT:  # %bb.0:
+; CHECK-NEXT:    local.get 0
+; CHECK-NEXT:    i32.atomic.load acqrel 0
+; CHECK-NEXT:    # fallthrough-return
   %v = load atomic i32, ptr %p acquire, align 4
   ret i32 %v
 }
 
-; CHECK-LABEL: load_i32_seq_cst:
-; CHECK: i32.atomic.load seqcst 0
 define i32 @load_i32_seq_cst(ptr %p) {
+; CHECK-LABEL: load_i32_seq_cst:
+; CHECK:         .functype load_i32_seq_cst (i32) -> (i32)
+; CHECK-NEXT:  # %bb.0:
+; CHECK-NEXT:    local.get 0
+; CHECK-NEXT:    i32.atomic.load seqcst 0
+; CHECK-NEXT:    # fallthrough-return
   %v = load atomic i32, ptr %p seq_cst, align 4
   ret i32 %v
 }
 
-; CHECK-LABEL: store_i32_release:
-; CHECK: i32.atomic.store acqrel 0
 define void @store_i32_release(ptr %p, i32 %v) {
+; CHECK-LABEL: store_i32_release:
+; CHECK:         .functype store_i32_release (i32, i32) -> ()
+; CHECK-NEXT:  # %bb.0:
+; CHECK-NEXT:    local.get 0
+; CHECK-NEXT:    local.get 1
+; CHECK-NEXT:    i32.atomic.store acqrel 0
+; CHECK-NEXT:    # fallthrough-return
   store atomic i32 %v, ptr %p release, align 4
   ret void
 }
 
-; CHECK-LABEL: store_i32_seq_cst:
-; CHECK: i32.atomic.store seqcst 0
 define void @store_i32_seq_cst(ptr %p, i32 %v) {
+; CHECK-LABEL: store_i32_seq_cst:
+; CHECK:         .functype store_i32_seq_cst (i32, i32) -> ()
+; CHECK-NEXT:  # %bb.0:
+; CHECK-NEXT:    local.get 0
+; CHECK-NEXT:    local.get 1
+; CHECK-NEXT:    i32.atomic.store seqcst 0
+; CHECK-NEXT:    # fallthrough-return
   store atomic i32 %v, ptr %p seq_cst, align 4
   ret void
 }
 
-; CHECK-LABEL: add_i32_acq_rel:
-; CHECK: i32.atomic.rmw.add acqrel 0
 define i32 @add_i32_acq_rel(ptr %p, i32 %v) {
+; CHECK-LABEL: add_i32_acq_rel:
+; CHECK:         .functype add_i32_acq_rel (i32, i32) -> (i32)
+; CHECK-NEXT:  # %bb.0:
+; CHECK-NEXT:    local.get 0
+; CHECK-NEXT:    local.get 1
+; CHECK-NEXT:    i32.atomic.rmw.add acqrel 0
+; CHECK-NEXT:    # fallthrough-return
   %old = atomicrmw add ptr %p, i32 %v acq_rel
   ret i32 %old
 }
 
-; CHECK-LABEL: add_i32_seq_cst:
-; CHECK: i32.atomic.rmw.add seqcst 0
 define i32 @add_i32_seq_cst(ptr %p, i32 %v) {
+; CHECK-LABEL: add_i32_seq_cst:
+; CHECK:         .functype add_i32_seq_cst (i32, i32) -> (i32)
+; CHECK-NEXT:  # %bb.0:
+; CHECK-NEXT:    local.get 0
+; CHECK-NEXT:    local.get 1
+; CHECK-NEXT:    i32.atomic.rmw.add seqcst 0
+; CHECK-NEXT:    # fallthrough-return
   %old = atomicrmw add ptr %p, i32 %v seq_cst
   ret i32 %old
 }
 
-; CHECK-LABEL: cmpxchg_i32_acquire_acquire:
-; CHECK: i32.atomic.rmw.cmpxchg acqrel 0
 define i32 @cmpxchg_i32_acquire_acquire(ptr %p, i32 %exp, i32 %new) {
+; CHECK-LABEL: cmpxchg_i32_acquire_acquire:
+; CHECK:         .functype cmpxchg_i32_acquire_acquire (i32, i32, i32) -> (i32)
+; CHECK-NEXT:  # %bb.0:
+; CHECK-NEXT:    local.get 0
+; CHECK-NEXT:    local.get 1
+; CHECK-NEXT:    local.get 2
+; CHECK-NEXT:    i32.atomic.rmw.cmpxchg acqrel 0
+; CHECK-NEXT:    # fallthrough-return
   %pair = cmpxchg ptr %p, i32 %exp, i32 %new acquire acquire
   %val = extractvalue { i32, i1 } %pair, 0
   ret i32 %val
 }
 
-; CHECK-LABEL: cmpxchg_i32_seq_cst_seq_cst:
-; CHECK: i32.atomic.rmw.cmpxchg seqcst 0
 define i32 @cmpxchg_i32_seq_cst_seq_cst(ptr %p, i32 %exp, i32 %new) {
+; CHECK-LABEL: cmpxchg_i32_seq_cst_seq_cst:
+; CHECK:         .functype cmpxchg_i32_seq_cst_seq_cst (i32, i32, i32) -> (i32)
+; CHECK-NEXT:  # %bb.0:
+; CHECK-NEXT:    local.get 0
+; CHECK-NEXT:    local.get 1
+; CHECK-NEXT:    local.get 2
+; CHECK-NEXT:    i32.atomic.rmw.cmpxchg seqcst 0
+; CHECK-NEXT:    # fallthrough-return
   %pair = cmpxchg ptr %p, i32 %exp, i32 %new seq_cst seq_cst
   %val = extractvalue { i32, i1 } %pair, 0
   ret i32 %val
 }
 
-; CHECK-LABEL: fence_acquire:
-; CHECK: atomic.fence acqrel
 define void @fence_acquire() {
+; CHECK-LABEL: fence_acquire:
+; CHECK:         .functype fence_acquire () -> ()
+; CHECK-NEXT:  # %bb.0:
+; CHECK-NEXT:    atomic.fence acqrel
+; CHECK-NEXT:    # fallthrough-return
   fence acquire
   ret void
 }
 
-; CHECK-LABEL: fence_seq_cst:
-; CHECK: atomic.fence seqcst
 define void @fence_seq_cst() {
+; CHECK-LABEL: fence_seq_cst:
+; CHECK:         .functype fence_seq_cst () -> ()
+; CHECK-NEXT:  # %bb.0:
+; CHECK-NEXT:    atomic.fence seqcst
+; CHECK-NEXT:    # fallthrough-return
   fence seq_cst
   ret void
 }
 
-; CHECK-LABEL: load_i32_monotonic:
-; CHECK: i32.atomic.load acqrel 0
 define i32 @load_i32_monotonic(ptr %p) {
+; CHECK-LABEL: load_i32_monotonic:
+; CHECK:         .functype load_i32_monotonic (i32) -> (i32)
+; CHECK-NEXT:  # %bb.0:
+; CHECK-NEXT:    local.get 0
+; CHECK-NEXT:    i32.atomic.load acqrel 0
+; CHECK-NEXT:    # fallthrough-return
   %v = load atomic i32, ptr %p monotonic, align 4
   ret i32 %v
 }
 
-; CHECK-LABEL: store_i32_monotonic:
-; CHECK: i32.atomic.store acqrel 0
 define void @store_i32_monotonic(ptr %p, i32 %v) {
+; CHECK-LABEL: store_i32_monotonic:
+; CHECK:         .functype store_i32_monotonic (i32, i32) -> ()
+; CHECK-NEXT:  # %bb.0:
+; CHECK-NEXT:    local.get 0
+; CHECK-NEXT:    local.get 1
+; CHECK-NEXT:    i32.atomic.store acqrel 0
+; CHECK-NEXT:    # fallthrough-return
   store atomic i32 %v, ptr %p monotonic, align 4
   ret void
 }
 
-; CHECK-LABEL: add_i32_release:
-; CHECK: i32.atomic.rmw.add acqrel 0
 define i32 @add_i32_release(ptr %p, i32 %v) {
+; CHECK-LABEL: add_i32_release:
+; CHECK:         .functype add_i32_release (i32, i32) -> (i32)
+; CHECK-NEXT:  # %bb.0:
+; CHECK-NEXT:    local.get 0
+; CHECK-NEXT:    local.get 1
+; CHECK-NEXT:    i32.atomic.rmw.add acqrel 0
+; CHECK-NEXT:    # fallthrough-return
   %old = atomicrmw add ptr %p, i32 %v release
   ret i32 %old
 }
 
-; CHECK-LABEL: add_i32_acquire:
-; CHECK: i32.atomic.rmw.add acqrel 0
 define i32 @add_i32_acquire(ptr %p, i32 %v) {
+; CHECK-LABEL: add_i32_acquire:
+; CHECK:         .functype add_i32_acquire (i32, i32) -> (i32)
+; CHECK-NEXT:  # %bb.0:
+; CHECK-NEXT:    local.get 0
+; CHECK-NEXT:    local.get 1
+; CHECK-NEXT:    i32.atomic.rmw.add acqrel 0
+; CHECK-NEXT:    # fallthrough-return
   %old = atomicrmw add ptr %p, i32 %v acquire
   ret i32 %old
 }
 
-; CHECK-LABEL: add_i32_monotonic:
-; CHECK: i32.atomic.rmw.add acqrel 0
 define i32 @add_i32_monotonic(ptr %p, i32 %v) {
+; CHECK-LABEL: add_i32_monotonic:
+; CHECK:         .functype add_i32_monotonic (i32, i32) -> (i32)
+; CHECK-NEXT:  # %bb.0:
+; CHECK-NEXT:    local.get 0
+; CHECK-NEXT:    local.get 1
+; CHECK-NEXT:    i32.atomic.rmw.add acqrel 0
+; CHECK-NEXT:    # fallthrough-return
   %old = atomicrmw add ptr %p, i32 %v monotonic
   ret i32 %old
 }
 
-; CHECK-LABEL: cmpxchg_i32_acq_rel_monotonic:
-; CHECK: i32.atomic.rmw.cmpxchg acqrel 0
 define i32 @cmpxchg_i32_acq_rel_monotonic(ptr %p, i32 %exp, i32 %new) {
+; CHECK-LABEL: cmpxchg_i32_acq_rel_monotonic:
+; CHECK:         .functype cmpxchg_i32_acq_rel_monotonic (i32, i32, i32) -> (i32)
+; CHECK-NEXT:  # %bb.0:
+; CHECK-NEXT:    local.get 0
+; CHECK-NEXT:    local.get 1
+; CHECK-NEXT:    local.get 2
+; CHECK-NEXT:    i32.atomic.rmw.cmpxchg acqrel 0
+; CHECK-NEXT:    # fallthrough-return
   %pair = cmpxchg ptr %p, i32 %exp, i32 %new acq_rel monotonic
   %val = extractvalue { i32, i1 } %pair, 0
   ret i32 %val
 }
 
-; CHECK-LABEL: cmpxchg_i32_release_monotonic:
-; CHECK: i32.atomic.rmw.cmpxchg acqrel 0
 define i32 @cmpxchg_i32_release_monotonic(ptr %p, i32 %exp, i32 %new) {
+; CHECK-LABEL: cmpxchg_i32_release_monotonic:
+; CHECK:         .functype cmpxchg_i32_release_monotonic (i32, i32, i32) -> (i32)
+; CHECK-NEXT:  # %bb.0:
+; CHECK-NEXT:    local.get 0
+; CHECK-NEXT:    local.get 1
+; CHECK-NEXT:    local.get 2
+; CHECK-NEXT:    i32.atomic.rmw.cmpxchg acqrel 0
+; CHECK-NEXT:    # fallthrough-return
   %pair = cmpxchg ptr %p, i32 %exp, i32 %new release monotonic
   %val = extractvalue { i32, i1 } %pair, 0
   ret i32 %val
 }
 
-; CHECK-LABEL: cmpxchg_i32_monotonic_monotonic:
-; CHECK: i32.atomic.rmw.cmpxchg acqrel 0
 define i32 @cmpxchg_i32_monotonic_monotonic(ptr %p, i32 %exp, i32 %new) {
+; CHECK-LABEL: cmpxchg_i32_monotonic_monotonic:
+; CHECK:         .functype cmpxchg_i32_monotonic_monotonic (i32, i32, i32) -> (i32)
+; CHECK-NEXT:  # %bb.0:
+; CHECK-NEXT:    local.get 0
+; CHECK-NEXT:    local.get 1
+; CHECK-NEXT:    local.get 2
+; CHECK-NEXT:    i32.atomic.rmw.cmpxchg acqrel 0
+; CHECK-NEXT:    # fallthrough-return
   %pair = cmpxchg ptr %p, i32 %exp, i32 %new monotonic monotonic
   %val = extractvalue { i32, i1 } %pair, 0
   ret i32 %val
 }
 
-; CHECK-LABEL: fence_release:
-; CHECK: atomic.fence acqrel
 define void @fence_release() {
+; CHECK-LABEL: fence_release:
+; CHECK:         .functype fence_release () -> ()
+; CHECK-NEXT:  # %bb.0:
+; CHECK-NEXT:    atomic.fence acqrel
+; CHECK-NEXT:    # fallthrough-return
   fence release
   ret void
 }
 
-; CHECK-LABEL: fence_acq_rel:
-; CHECK: atomic.fence acqrel
 define void @fence_acq_rel() {
+; CHECK-LABEL: fence_acq_rel:
+; CHECK:         .functype fence_acq_rel () -> ()
+; CHECK-NEXT:  # %bb.0:
+; CHECK-NEXT:    atomic.fence acqrel
+; CHECK-NEXT:    # fallthrough-return
   fence acq_rel
   ret void
 }
-
-

>From e52d41267f1a4813d58a6abfc5b014f76e0e37bb Mon Sep 17 00:00:00 2001
From: Derek Schuff <dschuff at chromium.org>
Date: Thu, 5 Mar 2026 21:44:17 +0000
Subject: [PATCH 6/9] add wasm64 test

---
 .../CodeGen/WebAssembly/atomics-orderings.ll  | 425 ++++++++++++------
 1 file changed, 290 insertions(+), 135 deletions(-)

diff --git a/llvm/test/CodeGen/WebAssembly/atomics-orderings.ll b/llvm/test/CodeGen/WebAssembly/atomics-orderings.ll
index 9095d27493a8e..3cc623c8c329d 100644
--- a/llvm/test/CodeGen/WebAssembly/atomics-orderings.ll
+++ b/llvm/test/CodeGen/WebAssembly/atomics-orderings.ll
@@ -1,241 +1,396 @@
 ; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 6
-; RUN: llc < %s --mtriple=wasm32 -mattr=+atomics,+relaxed-atomics | FileCheck %s
+; RUN: llc < %s --mtriple=wasm32 -mattr=+atomics,+relaxed-atomics | FileCheck %s --check-prefixes=WASM32
+; RUN: llc < %s --mtriple=wasm64 -mattr=+atomics,+relaxed-atomics | FileCheck %s --check-prefixes=WASM64
 
 define i32 @load_i32_acquire(ptr %p) {
-; CHECK-LABEL: load_i32_acquire:
-; CHECK:         .functype load_i32_acquire (i32) -> (i32)
-; CHECK-NEXT:  # %bb.0:
-; CHECK-NEXT:    local.get 0
-; CHECK-NEXT:    i32.atomic.load acqrel 0
-; CHECK-NEXT:    # fallthrough-return
+; WASM32-LABEL: load_i32_acquire:
+; WASM32:         .functype load_i32_acquire (i32) -> (i32)
+; WASM32-NEXT:  # %bb.0:
+; WASM32-NEXT:    local.get 0
+; WASM32-NEXT:    i32.atomic.load acqrel 0
+; WASM32-NEXT:    # fallthrough-return
+;
+; WASM64-LABEL: load_i32_acquire:
+; WASM64:         .functype load_i32_acquire (i64) -> (i32)
+; WASM64-NEXT:  # %bb.0:
+; WASM64-NEXT:    local.get 0
+; WASM64-NEXT:    i32.atomic.load acqrel 0
+; WASM64-NEXT:    # fallthrough-return
   %v = load atomic i32, ptr %p acquire, align 4
   ret i32 %v
 }
 
 define i32 @load_i32_seq_cst(ptr %p) {
-; CHECK-LABEL: load_i32_seq_cst:
-; CHECK:         .functype load_i32_seq_cst (i32) -> (i32)
-; CHECK-NEXT:  # %bb.0:
-; CHECK-NEXT:    local.get 0
-; CHECK-NEXT:    i32.atomic.load seqcst 0
-; CHECK-NEXT:    # fallthrough-return
+; WASM32-LABEL: load_i32_seq_cst:
+; WASM32:         .functype load_i32_seq_cst (i32) -> (i32)
+; WASM32-NEXT:  # %bb.0:
+; WASM32-NEXT:    local.get 0
+; WASM32-NEXT:    i32.atomic.load seqcst 0
+; WASM32-NEXT:    # fallthrough-return
+;
+; WASM64-LABEL: load_i32_seq_cst:
+; WASM64:         .functype load_i32_seq_cst (i64) -> (i32)
+; WASM64-NEXT:  # %bb.0:
+; WASM64-NEXT:    local.get 0
+; WASM64-NEXT:    i32.atomic.load seqcst 0
+; WASM64-NEXT:    # fallthrough-return
   %v = load atomic i32, ptr %p seq_cst, align 4
   ret i32 %v
 }
 
 define void @store_i32_release(ptr %p, i32 %v) {
-; CHECK-LABEL: store_i32_release:
-; CHECK:         .functype store_i32_release (i32, i32) -> ()
-; CHECK-NEXT:  # %bb.0:
-; CHECK-NEXT:    local.get 0
-; CHECK-NEXT:    local.get 1
-; CHECK-NEXT:    i32.atomic.store acqrel 0
-; CHECK-NEXT:    # fallthrough-return
+; WASM32-LABEL: store_i32_release:
+; WASM32:         .functype store_i32_release (i32, i32) -> ()
+; WASM32-NEXT:  # %bb.0:
+; WASM32-NEXT:    local.get 0
+; WASM32-NEXT:    local.get 1
+; WASM32-NEXT:    i32.atomic.store acqrel 0
+; WASM32-NEXT:    # fallthrough-return
+;
+; WASM64-LABEL: store_i32_release:
+; WASM64:         .functype store_i32_release (i64, i32) -> ()
+; WASM64-NEXT:  # %bb.0:
+; WASM64-NEXT:    local.get 0
+; WASM64-NEXT:    local.get 1
+; WASM64-NEXT:    i32.atomic.store acqrel 0
+; WASM64-NEXT:    # fallthrough-return
   store atomic i32 %v, ptr %p release, align 4
   ret void
 }
 
 define void @store_i32_seq_cst(ptr %p, i32 %v) {
-; CHECK-LABEL: store_i32_seq_cst:
-; CHECK:         .functype store_i32_seq_cst (i32, i32) -> ()
-; CHECK-NEXT:  # %bb.0:
-; CHECK-NEXT:    local.get 0
-; CHECK-NEXT:    local.get 1
-; CHECK-NEXT:    i32.atomic.store seqcst 0
-; CHECK-NEXT:    # fallthrough-return
+; WASM32-LABEL: store_i32_seq_cst:
+; WASM32:         .functype store_i32_seq_cst (i32, i32) -> ()
+; WASM32-NEXT:  # %bb.0:
+; WASM32-NEXT:    local.get 0
+; WASM32-NEXT:    local.get 1
+; WASM32-NEXT:    i32.atomic.store seqcst 0
+; WASM32-NEXT:    # fallthrough-return
+;
+; WASM64-LABEL: store_i32_seq_cst:
+; WASM64:         .functype store_i32_seq_cst (i64, i32) -> ()
+; WASM64-NEXT:  # %bb.0:
+; WASM64-NEXT:    local.get 0
+; WASM64-NEXT:    local.get 1
+; WASM64-NEXT:    i32.atomic.store seqcst 0
+; WASM64-NEXT:    # fallthrough-return
   store atomic i32 %v, ptr %p seq_cst, align 4
   ret void
 }
 
 define i32 @add_i32_acq_rel(ptr %p, i32 %v) {
-; CHECK-LABEL: add_i32_acq_rel:
-; CHECK:         .functype add_i32_acq_rel (i32, i32) -> (i32)
-; CHECK-NEXT:  # %bb.0:
-; CHECK-NEXT:    local.get 0
-; CHECK-NEXT:    local.get 1
-; CHECK-NEXT:    i32.atomic.rmw.add acqrel 0
-; CHECK-NEXT:    # fallthrough-return
+; WASM32-LABEL: add_i32_acq_rel:
+; WASM32:         .functype add_i32_acq_rel (i32, i32) -> (i32)
+; WASM32-NEXT:  # %bb.0:
+; WASM32-NEXT:    local.get 0
+; WASM32-NEXT:    local.get 1
+; WASM32-NEXT:    i32.atomic.rmw.add acqrel 0
+; WASM32-NEXT:    # fallthrough-return
+;
+; WASM64-LABEL: add_i32_acq_rel:
+; WASM64:         .functype add_i32_acq_rel (i64, i32) -> (i32)
+; WASM64-NEXT:  # %bb.0:
+; WASM64-NEXT:    local.get 0
+; WASM64-NEXT:    local.get 1
+; WASM64-NEXT:    i32.atomic.rmw.add acqrel 0
+; WASM64-NEXT:    # fallthrough-return
   %old = atomicrmw add ptr %p, i32 %v acq_rel
   ret i32 %old
 }
 
 define i32 @add_i32_seq_cst(ptr %p, i32 %v) {
-; CHECK-LABEL: add_i32_seq_cst:
-; CHECK:         .functype add_i32_seq_cst (i32, i32) -> (i32)
-; CHECK-NEXT:  # %bb.0:
-; CHECK-NEXT:    local.get 0
-; CHECK-NEXT:    local.get 1
-; CHECK-NEXT:    i32.atomic.rmw.add seqcst 0
-; CHECK-NEXT:    # fallthrough-return
+; WASM32-LABEL: add_i32_seq_cst:
+; WASM32:         .functype add_i32_seq_cst (i32, i32) -> (i32)
+; WASM32-NEXT:  # %bb.0:
+; WASM32-NEXT:    local.get 0
+; WASM32-NEXT:    local.get 1
+; WASM32-NEXT:    i32.atomic.rmw.add seqcst 0
+; WASM32-NEXT:    # fallthrough-return
+;
+; WASM64-LABEL: add_i32_seq_cst:
+; WASM64:         .functype add_i32_seq_cst (i64, i32) -> (i32)
+; WASM64-NEXT:  # %bb.0:
+; WASM64-NEXT:    local.get 0
+; WASM64-NEXT:    local.get 1
+; WASM64-NEXT:    i32.atomic.rmw.add seqcst 0
+; WASM64-NEXT:    # fallthrough-return
   %old = atomicrmw add ptr %p, i32 %v seq_cst
   ret i32 %old
 }
 
 define i32 @cmpxchg_i32_acquire_acquire(ptr %p, i32 %exp, i32 %new) {
-; CHECK-LABEL: cmpxchg_i32_acquire_acquire:
-; CHECK:         .functype cmpxchg_i32_acquire_acquire (i32, i32, i32) -> (i32)
-; CHECK-NEXT:  # %bb.0:
-; CHECK-NEXT:    local.get 0
-; CHECK-NEXT:    local.get 1
-; CHECK-NEXT:    local.get 2
-; CHECK-NEXT:    i32.atomic.rmw.cmpxchg acqrel 0
-; CHECK-NEXT:    # fallthrough-return
+; WASM32-LABEL: cmpxchg_i32_acquire_acquire:
+; WASM32:         .functype cmpxchg_i32_acquire_acquire (i32, i32, i32) -> (i32)
+; WASM32-NEXT:  # %bb.0:
+; WASM32-NEXT:    local.get 0
+; WASM32-NEXT:    local.get 1
+; WASM32-NEXT:    local.get 2
+; WASM32-NEXT:    i32.atomic.rmw.cmpxchg acqrel 0
+; WASM32-NEXT:    # fallthrough-return
+;
+; WASM64-LABEL: cmpxchg_i32_acquire_acquire:
+; WASM64:         .functype cmpxchg_i32_acquire_acquire (i64, i32, i32) -> (i32)
+; WASM64-NEXT:  # %bb.0:
+; WASM64-NEXT:    local.get 0
+; WASM64-NEXT:    local.get 1
+; WASM64-NEXT:    local.get 2
+; WASM64-NEXT:    i32.atomic.rmw.cmpxchg acqrel 0
+; WASM64-NEXT:    # fallthrough-return
   %pair = cmpxchg ptr %p, i32 %exp, i32 %new acquire acquire
   %val = extractvalue { i32, i1 } %pair, 0
   ret i32 %val
 }
 
 define i32 @cmpxchg_i32_seq_cst_seq_cst(ptr %p, i32 %exp, i32 %new) {
-; CHECK-LABEL: cmpxchg_i32_seq_cst_seq_cst:
-; CHECK:         .functype cmpxchg_i32_seq_cst_seq_cst (i32, i32, i32) -> (i32)
-; CHECK-NEXT:  # %bb.0:
-; CHECK-NEXT:    local.get 0
-; CHECK-NEXT:    local.get 1
-; CHECK-NEXT:    local.get 2
-; CHECK-NEXT:    i32.atomic.rmw.cmpxchg seqcst 0
-; CHECK-NEXT:    # fallthrough-return
+; WASM32-LABEL: cmpxchg_i32_seq_cst_seq_cst:
+; WASM32:         .functype cmpxchg_i32_seq_cst_seq_cst (i32, i32, i32) -> (i32)
+; WASM32-NEXT:  # %bb.0:
+; WASM32-NEXT:    local.get 0
+; WASM32-NEXT:    local.get 1
+; WASM32-NEXT:    local.get 2
+; WASM32-NEXT:    i32.atomic.rmw.cmpxchg seqcst 0
+; WASM32-NEXT:    # fallthrough-return
+;
+; WASM64-LABEL: cmpxchg_i32_seq_cst_seq_cst:
+; WASM64:         .functype cmpxchg_i32_seq_cst_seq_cst (i64, i32, i32) -> (i32)
+; WASM64-NEXT:  # %bb.0:
+; WASM64-NEXT:    local.get 0
+; WASM64-NEXT:    local.get 1
+; WASM64-NEXT:    local.get 2
+; WASM64-NEXT:    i32.atomic.rmw.cmpxchg seqcst 0
+; WASM64-NEXT:    # fallthrough-return
   %pair = cmpxchg ptr %p, i32 %exp, i32 %new seq_cst seq_cst
   %val = extractvalue { i32, i1 } %pair, 0
   ret i32 %val
 }
 
 define void @fence_acquire() {
-; CHECK-LABEL: fence_acquire:
-; CHECK:         .functype fence_acquire () -> ()
-; CHECK-NEXT:  # %bb.0:
-; CHECK-NEXT:    atomic.fence acqrel
-; CHECK-NEXT:    # fallthrough-return
+; WASM32-LABEL: fence_acquire:
+; WASM32:         .functype fence_acquire () -> ()
+; WASM32-NEXT:  # %bb.0:
+; WASM32-NEXT:    atomic.fence acqrel
+; WASM32-NEXT:    # fallthrough-return
+;
+; WASM64-LABEL: fence_acquire:
+; WASM64:         .functype fence_acquire () -> ()
+; WASM64-NEXT:  # %bb.0:
+; WASM64-NEXT:    atomic.fence acqrel
+; WASM64-NEXT:    # fallthrough-return
   fence acquire
   ret void
 }
 
 define void @fence_seq_cst() {
-; CHECK-LABEL: fence_seq_cst:
-; CHECK:         .functype fence_seq_cst () -> ()
-; CHECK-NEXT:  # %bb.0:
-; CHECK-NEXT:    atomic.fence seqcst
-; CHECK-NEXT:    # fallthrough-return
+; WASM32-LABEL: fence_seq_cst:
+; WASM32:         .functype fence_seq_cst () -> ()
+; WASM32-NEXT:  # %bb.0:
+; WASM32-NEXT:    atomic.fence seqcst
+; WASM32-NEXT:    # fallthrough-return
+;
+; WASM64-LABEL: fence_seq_cst:
+; WASM64:         .functype fence_seq_cst () -> ()
+; WASM64-NEXT:  # %bb.0:
+; WASM64-NEXT:    atomic.fence seqcst
+; WASM64-NEXT:    # fallthrough-return
   fence seq_cst
   ret void
 }
 
 define i32 @load_i32_monotonic(ptr %p) {
-; CHECK-LABEL: load_i32_monotonic:
-; CHECK:         .functype load_i32_monotonic (i32) -> (i32)
-; CHECK-NEXT:  # %bb.0:
-; CHECK-NEXT:    local.get 0
-; CHECK-NEXT:    i32.atomic.load acqrel 0
-; CHECK-NEXT:    # fallthrough-return
+; WASM32-LABEL: load_i32_monotonic:
+; WASM32:         .functype load_i32_monotonic (i32) -> (i32)
+; WASM32-NEXT:  # %bb.0:
+; WASM32-NEXT:    local.get 0
+; WASM32-NEXT:    i32.atomic.load acqrel 0
+; WASM32-NEXT:    # fallthrough-return
+;
+; WASM64-LABEL: load_i32_monotonic:
+; WASM64:         .functype load_i32_monotonic (i64) -> (i32)
+; WASM64-NEXT:  # %bb.0:
+; WASM64-NEXT:    local.get 0
+; WASM64-NEXT:    i32.atomic.load acqrel 0
+; WASM64-NEXT:    # fallthrough-return
   %v = load atomic i32, ptr %p monotonic, align 4
   ret i32 %v
 }
 
 define void @store_i32_monotonic(ptr %p, i32 %v) {
-; CHECK-LABEL: store_i32_monotonic:
-; CHECK:         .functype store_i32_monotonic (i32, i32) -> ()
-; CHECK-NEXT:  # %bb.0:
-; CHECK-NEXT:    local.get 0
-; CHECK-NEXT:    local.get 1
-; CHECK-NEXT:    i32.atomic.store acqrel 0
-; CHECK-NEXT:    # fallthrough-return
+; WASM32-LABEL: store_i32_monotonic:
+; WASM32:         .functype store_i32_monotonic (i32, i32) -> ()
+; WASM32-NEXT:  # %bb.0:
+; WASM32-NEXT:    local.get 0
+; WASM32-NEXT:    local.get 1
+; WASM32-NEXT:    i32.atomic.store acqrel 0
+; WASM32-NEXT:    # fallthrough-return
+;
+; WASM64-LABEL: store_i32_monotonic:
+; WASM64:         .functype store_i32_monotonic (i64, i32) -> ()
+; WASM64-NEXT:  # %bb.0:
+; WASM64-NEXT:    local.get 0
+; WASM64-NEXT:    local.get 1
+; WASM64-NEXT:    i32.atomic.store acqrel 0
+; WASM64-NEXT:    # fallthrough-return
   store atomic i32 %v, ptr %p monotonic, align 4
   ret void
 }
 
 define i32 @add_i32_release(ptr %p, i32 %v) {
-; CHECK-LABEL: add_i32_release:
-; CHECK:         .functype add_i32_release (i32, i32) -> (i32)
-; CHECK-NEXT:  # %bb.0:
-; CHECK-NEXT:    local.get 0
-; CHECK-NEXT:    local.get 1
-; CHECK-NEXT:    i32.atomic.rmw.add acqrel 0
-; CHECK-NEXT:    # fallthrough-return
+; WASM32-LABEL: add_i32_release:
+; WASM32:         .functype add_i32_release (i32, i32) -> (i32)
+; WASM32-NEXT:  # %bb.0:
+; WASM32-NEXT:    local.get 0
+; WASM32-NEXT:    local.get 1
+; WASM32-NEXT:    i32.atomic.rmw.add acqrel 0
+; WASM32-NEXT:    # fallthrough-return
+;
+; WASM64-LABEL: add_i32_release:
+; WASM64:         .functype add_i32_release (i64, i32) -> (i32)
+; WASM64-NEXT:  # %bb.0:
+; WASM64-NEXT:    local.get 0
+; WASM64-NEXT:    local.get 1
+; WASM64-NEXT:    i32.atomic.rmw.add acqrel 0
+; WASM64-NEXT:    # fallthrough-return
   %old = atomicrmw add ptr %p, i32 %v release
   ret i32 %old
 }
 
 define i32 @add_i32_acquire(ptr %p, i32 %v) {
-; CHECK-LABEL: add_i32_acquire:
-; CHECK:         .functype add_i32_acquire (i32, i32) -> (i32)
-; CHECK-NEXT:  # %bb.0:
-; CHECK-NEXT:    local.get 0
-; CHECK-NEXT:    local.get 1
-; CHECK-NEXT:    i32.atomic.rmw.add acqrel 0
-; CHECK-NEXT:    # fallthrough-return
+; WASM32-LABEL: add_i32_acquire:
+; WASM32:         .functype add_i32_acquire (i32, i32) -> (i32)
+; WASM32-NEXT:  # %bb.0:
+; WASM32-NEXT:    local.get 0
+; WASM32-NEXT:    local.get 1
+; WASM32-NEXT:    i32.atomic.rmw.add acqrel 0
+; WASM32-NEXT:    # fallthrough-return
+;
+; WASM64-LABEL: add_i32_acquire:
+; WASM64:         .functype add_i32_acquire (i64, i32) -> (i32)
+; WASM64-NEXT:  # %bb.0:
+; WASM64-NEXT:    local.get 0
+; WASM64-NEXT:    local.get 1
+; WASM64-NEXT:    i32.atomic.rmw.add acqrel 0
+; WASM64-NEXT:    # fallthrough-return
   %old = atomicrmw add ptr %p, i32 %v acquire
   ret i32 %old
 }
 
 define i32 @add_i32_monotonic(ptr %p, i32 %v) {
-; CHECK-LABEL: add_i32_monotonic:
-; CHECK:         .functype add_i32_monotonic (i32, i32) -> (i32)
-; CHECK-NEXT:  # %bb.0:
-; CHECK-NEXT:    local.get 0
-; CHECK-NEXT:    local.get 1
-; CHECK-NEXT:    i32.atomic.rmw.add acqrel 0
-; CHECK-NEXT:    # fallthrough-return
+; WASM32-LABEL: add_i32_monotonic:
+; WASM32:         .functype add_i32_monotonic (i32, i32) -> (i32)
+; WASM32-NEXT:  # %bb.0:
+; WASM32-NEXT:    local.get 0
+; WASM32-NEXT:    local.get 1
+; WASM32-NEXT:    i32.atomic.rmw.add acqrel 0
+; WASM32-NEXT:    # fallthrough-return
+;
+; WASM64-LABEL: add_i32_monotonic:
+; WASM64:         .functype add_i32_monotonic (i64, i32) -> (i32)
+; WASM64-NEXT:  # %bb.0:
+; WASM64-NEXT:    local.get 0
+; WASM64-NEXT:    local.get 1
+; WASM64-NEXT:    i32.atomic.rmw.add acqrel 0
+; WASM64-NEXT:    # fallthrough-return
   %old = atomicrmw add ptr %p, i32 %v monotonic
   ret i32 %old
 }
 
 define i32 @cmpxchg_i32_acq_rel_monotonic(ptr %p, i32 %exp, i32 %new) {
-; CHECK-LABEL: cmpxchg_i32_acq_rel_monotonic:
-; CHECK:         .functype cmpxchg_i32_acq_rel_monotonic (i32, i32, i32) -> (i32)
-; CHECK-NEXT:  # %bb.0:
-; CHECK-NEXT:    local.get 0
-; CHECK-NEXT:    local.get 1
-; CHECK-NEXT:    local.get 2
-; CHECK-NEXT:    i32.atomic.rmw.cmpxchg acqrel 0
-; CHECK-NEXT:    # fallthrough-return
+; WASM32-LABEL: cmpxchg_i32_acq_rel_monotonic:
+; WASM32:         .functype cmpxchg_i32_acq_rel_monotonic (i32, i32, i32) -> (i32)
+; WASM32-NEXT:  # %bb.0:
+; WASM32-NEXT:    local.get 0
+; WASM32-NEXT:    local.get 1
+; WASM32-NEXT:    local.get 2
+; WASM32-NEXT:    i32.atomic.rmw.cmpxchg acqrel 0
+; WASM32-NEXT:    # fallthrough-return
+;
+; WASM64-LABEL: cmpxchg_i32_acq_rel_monotonic:
+; WASM64:         .functype cmpxchg_i32_acq_rel_monotonic (i64, i32, i32) -> (i32)
+; WASM64-NEXT:  # %bb.0:
+; WASM64-NEXT:    local.get 0
+; WASM64-NEXT:    local.get 1
+; WASM64-NEXT:    local.get 2
+; WASM64-NEXT:    i32.atomic.rmw.cmpxchg acqrel 0
+; WASM64-NEXT:    # fallthrough-return
   %pair = cmpxchg ptr %p, i32 %exp, i32 %new acq_rel monotonic
   %val = extractvalue { i32, i1 } %pair, 0
   ret i32 %val
 }
 
 define i32 @cmpxchg_i32_release_monotonic(ptr %p, i32 %exp, i32 %new) {
-; CHECK-LABEL: cmpxchg_i32_release_monotonic:
-; CHECK:         .functype cmpxchg_i32_release_monotonic (i32, i32, i32) -> (i32)
-; CHECK-NEXT:  # %bb.0:
-; CHECK-NEXT:    local.get 0
-; CHECK-NEXT:    local.get 1
-; CHECK-NEXT:    local.get 2
-; CHECK-NEXT:    i32.atomic.rmw.cmpxchg acqrel 0
-; CHECK-NEXT:    # fallthrough-return
+; WASM32-LABEL: cmpxchg_i32_release_monotonic:
+; WASM32:         .functype cmpxchg_i32_release_monotonic (i32, i32, i32) -> (i32)
+; WASM32-NEXT:  # %bb.0:
+; WASM32-NEXT:    local.get 0
+; WASM32-NEXT:    local.get 1
+; WASM32-NEXT:    local.get 2
+; WASM32-NEXT:    i32.atomic.rmw.cmpxchg acqrel 0
+; WASM32-NEXT:    # fallthrough-return
+;
+; WASM64-LABEL: cmpxchg_i32_release_monotonic:
+; WASM64:         .functype cmpxchg_i32_release_monotonic (i64, i32, i32) -> (i32)
+; WASM64-NEXT:  # %bb.0:
+; WASM64-NEXT:    local.get 0
+; WASM64-NEXT:    local.get 1
+; WASM64-NEXT:    local.get 2
+; WASM64-NEXT:    i32.atomic.rmw.cmpxchg acqrel 0
+; WASM64-NEXT:    # fallthrough-return
   %pair = cmpxchg ptr %p, i32 %exp, i32 %new release monotonic
   %val = extractvalue { i32, i1 } %pair, 0
   ret i32 %val
 }
 
 define i32 @cmpxchg_i32_monotonic_monotonic(ptr %p, i32 %exp, i32 %new) {
-; CHECK-LABEL: cmpxchg_i32_monotonic_monotonic:
-; CHECK:         .functype cmpxchg_i32_monotonic_monotonic (i32, i32, i32) -> (i32)
-; CHECK-NEXT:  # %bb.0:
-; CHECK-NEXT:    local.get 0
-; CHECK-NEXT:    local.get 1
-; CHECK-NEXT:    local.get 2
-; CHECK-NEXT:    i32.atomic.rmw.cmpxchg acqrel 0
-; CHECK-NEXT:    # fallthrough-return
+; WASM32-LABEL: cmpxchg_i32_monotonic_monotonic:
+; WASM32:         .functype cmpxchg_i32_monotonic_monotonic (i32, i32, i32) -> (i32)
+; WASM32-NEXT:  # %bb.0:
+; WASM32-NEXT:    local.get 0
+; WASM32-NEXT:    local.get 1
+; WASM32-NEXT:    local.get 2
+; WASM32-NEXT:    i32.atomic.rmw.cmpxchg acqrel 0
+; WASM32-NEXT:    # fallthrough-return
+;
+; WASM64-LABEL: cmpxchg_i32_monotonic_monotonic:
+; WASM64:         .functype cmpxchg_i32_monotonic_monotonic (i64, i32, i32) -> (i32)
+; WASM64-NEXT:  # %bb.0:
+; WASM64-NEXT:    local.get 0
+; WASM64-NEXT:    local.get 1
+; WASM64-NEXT:    local.get 2
+; WASM64-NEXT:    i32.atomic.rmw.cmpxchg acqrel 0
+; WASM64-NEXT:    # fallthrough-return
   %pair = cmpxchg ptr %p, i32 %exp, i32 %new monotonic monotonic
   %val = extractvalue { i32, i1 } %pair, 0
   ret i32 %val
 }
 
 define void @fence_release() {
-; CHECK-LABEL: fence_release:
-; CHECK:         .functype fence_release () -> ()
-; CHECK-NEXT:  # %bb.0:
-; CHECK-NEXT:    atomic.fence acqrel
-; CHECK-NEXT:    # fallthrough-return
+; WASM32-LABEL: fence_release:
+; WASM32:         .functype fence_release () -> ()
+; WASM32-NEXT:  # %bb.0:
+; WASM32-NEXT:    atomic.fence acqrel
+; WASM32-NEXT:    # fallthrough-return
+;
+; WASM64-LABEL: fence_release:
+; WASM64:         .functype fence_release () -> ()
+; WASM64-NEXT:  # %bb.0:
+; WASM64-NEXT:    atomic.fence acqrel
+; WASM64-NEXT:    # fallthrough-return
   fence release
   ret void
 }
 
 define void @fence_acq_rel() {
-; CHECK-LABEL: fence_acq_rel:
-; CHECK:         .functype fence_acq_rel () -> ()
-; CHECK-NEXT:  # %bb.0:
-; CHECK-NEXT:    atomic.fence acqrel
-; CHECK-NEXT:    # fallthrough-return
+; WASM32-LABEL: fence_acq_rel:
+; WASM32:         .functype fence_acq_rel () -> ()
+; WASM32-NEXT:  # %bb.0:
+; WASM32-NEXT:    atomic.fence acqrel
+; WASM32-NEXT:    # fallthrough-return
+;
+; WASM64-LABEL: fence_acq_rel:
+; WASM64:         .functype fence_acq_rel () -> ()
+; WASM64-NEXT:  # %bb.0:
+; WASM64-NEXT:    atomic.fence acqrel
+; WASM64-NEXT:    # fallthrough-return
   fence acq_rel
   ret void
 }

>From cd9e18078acb1201d41f1b2b4cc3a99edd154a67 Mon Sep 17 00:00:00 2001
From: Derek Schuff <dschuff at chromium.org>
Date: Thu, 5 Mar 2026 21:46:00 +0000
Subject: [PATCH 7/9] split clang change out from this one

---
 clang/include/clang/Options/Options.td         |  2 --
 clang/lib/Basic/Targets/WebAssembly.cpp        | 11 -----------
 clang/lib/Basic/Targets/WebAssembly.h          |  1 -
 clang/test/Driver/wasm-features.c              |  6 ------
 clang/test/Preprocessor/wasm-target-features.c | 11 -----------
 5 files changed, 31 deletions(-)

diff --git a/clang/include/clang/Options/Options.td b/clang/include/clang/Options/Options.td
index 9d3ec8a173472..fe7169423b6bf 100644
--- a/clang/include/clang/Options/Options.td
+++ b/clang/include/clang/Options/Options.td
@@ -5688,8 +5688,6 @@ def mnontrapping_fptoint : Flag<["-"], "mnontrapping-fptoint">, Group<m_wasm_Fea
 def mno_nontrapping_fptoint : Flag<["-"], "mno-nontrapping-fptoint">, Group<m_wasm_Features_Group>;
 def mreference_types : Flag<["-"], "mreference-types">, Group<m_wasm_Features_Group>;
 def mno_reference_types : Flag<["-"], "mno-reference-types">, Group<m_wasm_Features_Group>;
-def mrelaxed_atomics : Flag<["-"], "mrelaxed-atomics">, Group<m_wasm_Features_Group>;
-def mno_relaxed_atomics : Flag<["-"], "mno-relaxed-atomics">, Group<m_wasm_Features_Group>;
 def mrelaxed_simd : Flag<["-"], "mrelaxed-simd">, Group<m_wasm_Features_Group>;
 def mno_relaxed_simd : Flag<["-"], "mno-relaxed-simd">, Group<m_wasm_Features_Group>;
 def msign_ext : Flag<["-"], "msign-ext">, Group<m_wasm_Features_Group>;
diff --git a/clang/lib/Basic/Targets/WebAssembly.cpp b/clang/lib/Basic/Targets/WebAssembly.cpp
index 4bb3d521cd9fd..daaefd9a1267c 100644
--- a/clang/lib/Basic/Targets/WebAssembly.cpp
+++ b/clang/lib/Basic/Targets/WebAssembly.cpp
@@ -66,7 +66,6 @@ bool WebAssemblyTargetInfo::hasFeature(StringRef Feature) const {
       .Case("mutable-globals", HasMutableGlobals)
       .Case("nontrapping-fptoint", HasNontrappingFPToInt)
       .Case("reference-types", HasReferenceTypes)
-      .Case("relaxed-atomics", HasRelaxedAtomics)
       .Case("relaxed-simd", SIMDLevel >= RelaxedSIMD)
       .Case("sign-ext", HasSignExt)
       .Case("simd128", SIMDLevel >= SIMD128)
@@ -111,8 +110,6 @@ void WebAssemblyTargetInfo::getTargetDefines(const LangOptions &Opts,
     Builder.defineMacro("__wasm_nontrapping_fptoint__");
   if (HasReferenceTypes)
     Builder.defineMacro("__wasm_reference_types__");
-  if (HasRelaxedAtomics)
-    Builder.defineMacro("__wasm_relaxed_atomics__");
   if (SIMDLevel >= RelaxedSIMD)
     Builder.defineMacro("__wasm_relaxed_simd__");
   if (HasSignExt)
@@ -335,14 +332,6 @@ bool WebAssemblyTargetInfo::handleTargetFeatures(
       HasReferenceTypes = false;
       continue;
     }
-    if (Feature == "+relaxed-atomics") {
-      HasRelaxedAtomics = true;
-      continue;
-    }
-    if (Feature == "-relaxed-atomics") {
-      HasRelaxedAtomics = false;
-      continue;
-    }
     if (Feature == "+relaxed-simd") {
       SIMDLevel = std::max(SIMDLevel, RelaxedSIMD);
       continue;
diff --git a/clang/lib/Basic/Targets/WebAssembly.h b/clang/lib/Basic/Targets/WebAssembly.h
index 8128dd96068a0..3a0823bd717d9 100644
--- a/clang/lib/Basic/Targets/WebAssembly.h
+++ b/clang/lib/Basic/Targets/WebAssembly.h
@@ -72,7 +72,6 @@ class LLVM_LIBRARY_VISIBILITY WebAssemblyTargetInfo : public TargetInfo {
   bool HasMutableGlobals = false;
   bool HasNontrappingFPToInt = false;
   bool HasReferenceTypes = false;
-  bool HasRelaxedAtomics = false;
   bool HasSignExt = false;
   bool HasTailCall = false;
   bool HasWideArithmetic = false;
diff --git a/clang/test/Driver/wasm-features.c b/clang/test/Driver/wasm-features.c
index 9e523aa5b53b6..89ced36eeffab 100644
--- a/clang/test/Driver/wasm-features.c
+++ b/clang/test/Driver/wasm-features.c
@@ -77,12 +77,6 @@
 // REFERENCE-TYPES: "-target-feature" "+reference-types"
 // NO-REFERENCE-TYPES: "-target-feature" "-reference-types"
 
-// RUN: %clang --target=wasm32-unknown-unknown -### %s -mrelaxed-atomics 2>&1 | FileCheck %s -check-prefix=RELAXED-ATOMICS
-// RUN: %clang --target=wasm32-unknown-unknown -### %s -mno-relaxed-atomics 2>&1 | FileCheck %s -check-prefix=NO-RELAXED-ATOMICS
-
-// RELAXED-ATOMICS: "-target-feature" "+relaxed-atomics"
-// NO-RELAXED-ATOMICS: "-target-feature" "-relaxed-atomics"
-
 // RUN: %clang --target=wasm32-unknown-unknown -### %s -mrelaxed-simd 2>&1 | FileCheck %s -check-prefix=RELAXED-SIMD
 // RUN: %clang --target=wasm32-unknown-unknown -### %s -mno-relaxed-simd 2>&1 | FileCheck %s -check-prefix=NO-RELAXED-SIMD
 
diff --git a/clang/test/Preprocessor/wasm-target-features.c b/clang/test/Preprocessor/wasm-target-features.c
index aff7442773531..3edaf9e7cd594 100644
--- a/clang/test/Preprocessor/wasm-target-features.c
+++ b/clang/test/Preprocessor/wasm-target-features.c
@@ -106,15 +106,6 @@
 //
 // REFERENCE-TYPES: #define __wasm_reference_types__ 1{{$}}
 
-// RUN: %clang -E -dM %s -o - 2>&1 \
-// RUN:     -target wasm32-unknown-unknown -mrelaxed-atomics \
-// RUN:   | FileCheck %s -check-prefix=RELAXED-ATOMICS
-// RUN: %clang -E -dM %s -o - 2>&1 \
-// RUN:     -target wasm64-unknown-unknown -mrelaxed-atomics \
-// RUN:   | FileCheck %s -check-prefix=RELAXED-ATOMICS
-//
-// RELAXED-ATOMICS: #define __wasm_relaxed_atomics__ 1{{$}}
-
 // RUN: %clang -E -dM %s -o - 2>&1 \
 // RUN:     -target wasm32-unknown-unknown -mrelaxed-simd \
 // RUN:   | FileCheck %s -check-prefix=RELAXED-SIMD
@@ -169,7 +160,6 @@
 // MVP-NOT: #define __wasm_mutable_globals__ 1{{$}}
 // MVP-NOT: #define __wasm_nontrapping_fptoint__ 1{{$}}
 // MVP-NOT: #define __wasm_reference_types__ 1{{$}}
-// MVP-NOT: #define __wasm_relaxed_atomics__ 1{{$}}
 // MVP-NOT: #define __wasm_relaxed_simd__ 1{{$}}
 // MVP-NOT: #define __wasm_sign_ext__ 1{{$}}
 // MVP-NOT: #define __wasm_simd128__ 1{{$}}
@@ -203,7 +193,6 @@
 // GENERIC-NOT: #define __wasm__fp16__ 1{{$}}
 // GENERIC-NOT: #define __wasm_gc__ 1{{$}}
 // GENERIC-NOT: #define __wasm_multimemory__ 1{{$}}
-// GENERIC-NOT: #define __wasm_relaxed_atomics__ 1{{$}}
 // GENERIC-NOT: #define __wasm_relaxed_simd__ 1{{$}}
 // GENERIC-NOT: #define __wasm_simd128__ 1{{$}}
 // GENERIC-NOT: #define __wasm_tail_call__ 1{{$}}

>From 74fa381b9b9bcafc73818ea2b62c50f8c03dd132 Mon Sep 17 00:00:00 2001
From: Derek Schuff <dschuff at chromium.org>
Date: Thu, 5 Mar 2026 21:56:31 +0000
Subject: [PATCH 8/9] clean up FixupAtomics

---
 .../WebAssembly/WebAssemblyFixupAtomics.cpp   | 48 +++++++++----------
 1 file changed, 24 insertions(+), 24 deletions(-)

diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyFixupAtomics.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyFixupAtomics.cpp
index 565feb79af9ec..cf00e5f88733b 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblyFixupAtomics.cpp
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyFixupAtomics.cpp
@@ -57,36 +57,36 @@ bool WebAssemblyFixupAtomics::runOnMachineFunction(MachineFunction &MF) {
                     << "********** Function: " << MF.getName() << '\n');
 
   bool Changed = false;
-  const auto &Subtarget = MF.getSubtarget<WebAssemblySubtarget>();
-  bool HasRelaxedAtomics = Subtarget.hasRelaxedAtomics();
+  if (!MF.getSubtarget<WebAssemblySubtarget>().hasRelaxedAtomics())
+    return Changed;
 
   for (auto &MBB : MF) {
     for (auto &MI : MBB) {
       const MCInstrDesc &Desc = MI.getDesc();
       for (unsigned I = 0, E = MI.getNumExplicitOperands(); I < E; ++I) {
         if (I < Desc.getNumOperands() &&
-            Desc.operands()[I].OperandType == WebAssembly::OPERAND_MEMORDER) {
-
-          if (HasRelaxedAtomics && !MI.memoperands_empty()) {
-            assert(MI.getOperand(I).getImm() == wasm::WASM_MEM_ORDER_SEQ_CST &&
-                   "Expected seqcst default atomics from ISel");
-            unsigned Order = wasm::WASM_MEM_ORDER_SEQ_CST;
-            auto *MMO = *MI.memoperands_begin();
-            switch (MMO->getMergedOrdering()) {
-            case AtomicOrdering::Acquire:
-            case AtomicOrdering::Release:
-            case AtomicOrdering::AcquireRelease:
-            case AtomicOrdering::Monotonic:
-              Order = wasm::WASM_MEM_ORDER_ACQ_REL;
-              break;
-            default:
-              Order = wasm::WASM_MEM_ORDER_SEQ_CST;
-              break;
-            }
-            if (MI.getOperand(I).getImm() != Order) {
-              MI.getOperand(I).setImm(Order);
-              Changed = true;
-            }
+            Desc.operands()[I].OperandType == WebAssembly::OPERAND_MEMORDER &&
+            // Fences are already selected with the correct ordering.
+            MI.getOpcode() != WebAssembly::ATOMIC_FENCE) {
+          assert(MI.getOperand(I).getImm() == wasm::WASM_MEM_ORDER_SEQ_CST &&
+                 "Expected seqcst default atomics from ISel");
+          assert(!MI.memoperands_empty());
+          unsigned Order = wasm::WASM_MEM_ORDER_SEQ_CST;
+          auto *MMO = *MI.memoperands_begin();
+          switch (MMO->getMergedOrdering()) {
+          case AtomicOrdering::Acquire:
+          case AtomicOrdering::Release:
+          case AtomicOrdering::AcquireRelease:
+          case AtomicOrdering::Monotonic:
+            Order = wasm::WASM_MEM_ORDER_ACQ_REL;
+            break;
+          default:
+            Order = wasm::WASM_MEM_ORDER_SEQ_CST;
+            break;
+          }
+          if (MI.getOperand(I).getImm() != Order) {
+            MI.getOperand(I).setImm(Order);
+            Changed = true;
           }
         }
       }

>From 737f2e60978ce091406a77cae648593d29dd2d52 Mon Sep 17 00:00:00 2001
From: Derek Schuff <dschuff at chromium.org>
Date: Fri, 6 Mar 2026 17:57:37 +0000
Subject: [PATCH 9/9] Apply suggestions; merge atomics-orderings.ll with
 atomic-mem-consistency.ll and atomic-fence.ll

---
 .../WebAssembly/WebAssemblyFixupAtomics.cpp   |  11 +-
 .../WebAssembly/WebAssemblyISelDAGToDAG.cpp   |   5 +-
 llvm/test/CodeGen/WebAssembly/atomic-fence.ll | 144 ++-
 .../WebAssembly/atomic-mem-consistency.ll     | 945 ++++++++++++++++--
 .../CodeGen/WebAssembly/atomics-orderings.ll  | 396 --------
 5 files changed, 990 insertions(+), 511 deletions(-)
 delete mode 100644 llvm/test/CodeGen/WebAssembly/atomics-orderings.ll

diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyFixupAtomics.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyFixupAtomics.cpp
index cf00e5f88733b..7730175d1b185 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblyFixupAtomics.cpp
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyFixupAtomics.cpp
@@ -11,8 +11,8 @@
 ///
 /// This is used because ISel selects atomics with a default value for the
 /// memory ordering immediate operand. Even though we run this pass early in
-/// the MI pass pipeline, MI passes should still use getMergedOrdering() on
-/// the MachineMemOperand to get the ordering rther than the immediate.
+/// the MI pass pipeline, later MI passes should still use getMergedOrdering()
+/// on the MachineMemOperand to get the ordering rather than the immediate.
 ///
 //===----------------------------------------------------------------------===//
 
@@ -74,15 +74,18 @@ bool WebAssemblyFixupAtomics::runOnMachineFunction(MachineFunction &MF) {
           unsigned Order = wasm::WASM_MEM_ORDER_SEQ_CST;
           auto *MMO = *MI.memoperands_begin();
           switch (MMO->getMergedOrdering()) {
+          case AtomicOrdering::Unordered:
+          case AtomicOrdering::Monotonic:
           case AtomicOrdering::Acquire:
           case AtomicOrdering::Release:
           case AtomicOrdering::AcquireRelease:
-          case AtomicOrdering::Monotonic:
             Order = wasm::WASM_MEM_ORDER_ACQ_REL;
             break;
-          default:
+          case AtomicOrdering::SequentiallyConsistent:
             Order = wasm::WASM_MEM_ORDER_SEQ_CST;
             break;
+          default:
+           report_fatal_error("Atomic instructions cannot have NotAtomic ordering");
           }
           if (MI.getOperand(I).getImm() != Order) {
             MI.getOperand(I).setImm(Order);
diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyISelDAGToDAG.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyISelDAGToDAG.cpp
index e1f7e51f2af34..e7c8e1776a7de 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblyISelDAGToDAG.cpp
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyISelDAGToDAG.cpp
@@ -215,12 +215,13 @@ void WebAssemblyDAGToDAGISel::Select(SDNode *Node) {
         case AtomicOrdering::Acquire:
         case AtomicOrdering::Release:
         case AtomicOrdering::AcquireRelease:
-        case AtomicOrdering::Monotonic:
           Order = wasm::WASM_MEM_ORDER_ACQ_REL;
           break;
-        default:
+        case AtomicOrdering::SequentiallyConsistent:
           Order = wasm::WASM_MEM_ORDER_SEQ_CST;
           break;
+        default:
+          llvm_unreachable("Invalid ordering for atomic fence");
         }
       }
       Fence = CurDAG->getMachineNode(
diff --git a/llvm/test/CodeGen/WebAssembly/atomic-fence.ll b/llvm/test/CodeGen/WebAssembly/atomic-fence.ll
index 8fed309bcce00..5df28f2cdcd8d 100644
--- a/llvm/test/CodeGen/WebAssembly/atomic-fence.ll
+++ b/llvm/test/CodeGen/WebAssembly/atomic-fence.ll
@@ -1,36 +1,140 @@
-; RUN: llc < %s | FileCheck %s --check-prefix NOATOMIC
-; RUN: llc < %s -asm-verbose=false -wasm-disable-explicit-locals -wasm-keep-registers -mattr=+atomics | FileCheck %s
-
-target triple = "wasm32-unknown-unknown"
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 6
+; RUN: llc < %s --mtriple=wasm32 | FileCheck %s --check-prefixes=NO-ATOMICS
+; RUN: llc < %s --mtriple=wasm32 -mattr=+atomics | FileCheck %s --check-prefixes=ATOMICS
+; RUN: llc < %s --mtriple=wasm32 -mattr=+atomics,+relaxed-atomics | FileCheck %s --check-prefixes=RELAXED32
+; RUN: llc < %s --mtriple=wasm64 -mattr=+atomics,+relaxed-atomics | FileCheck %s --check-prefixes=RELAXED64
 
 ; A multithread fence is lowered to an atomic.fence instruction.
-; CHECK-LABEL: multithread_fence:
-; CHECK:  atomic.fence
-; NOATOMIC-NOT: i32.atomic.rmw.or
-define void @multithread_fence() {
-  fence seq_cst
+define void @fence_acquire() {
+; NO-ATOMICS-LABEL: fence_acquire:
+; NO-ATOMICS:         .functype fence_acquire () -> ()
+; NO-ATOMICS-NEXT:  # %bb.0:
+; NO-ATOMICS-NEXT:    # fallthrough-return
+;
+; ATOMICS-LABEL: fence_acquire:
+; ATOMICS:         .functype fence_acquire () -> ()
+; ATOMICS-NEXT:  # %bb.0:
+; ATOMICS-NEXT:    atomic.fence
+; ATOMICS-NEXT:    # fallthrough-return
+;
+; RELAXED32-LABEL: fence_acquire:
+; RELAXED32:         .functype fence_acquire () -> ()
+; RELAXED32-NEXT:  # %bb.0:
+; RELAXED32-NEXT:    atomic.fence acqrel
+; RELAXED32-NEXT:    # fallthrough-return
+;
+; RELAXED64-LABEL: fence_acquire:
+; RELAXED64:         .functype fence_acquire () -> ()
+; RELAXED64-NEXT:  # %bb.0:
+; RELAXED64-NEXT:    atomic.fence acqrel
+; RELAXED64-NEXT:    # fallthrough-return
+  fence acquire
   ret void
 }
 
-; Fences with weaker memory orderings than seq_cst should be treated the same
-; because atomic memory access in wasm are sequentially consistent.
-; CHECK-LABEL: multithread_weak_fence:
-; CHECK:       atomic.fence
-; CHECK-NEXT:  atomic.fence
-; CHECK-NEXT:  atomic.fence
-define void @multithread_weak_fence() {
-  fence acquire
+define void @fence_release() {
+; NO-ATOMICS-LABEL: fence_release:
+; NO-ATOMICS:         .functype fence_release () -> ()
+; NO-ATOMICS-NEXT:  # %bb.0:
+; NO-ATOMICS-NEXT:    # fallthrough-return
+;
+; ATOMICS-LABEL: fence_release:
+; ATOMICS:         .functype fence_release () -> ()
+; ATOMICS-NEXT:  # %bb.0:
+; ATOMICS-NEXT:    atomic.fence
+; ATOMICS-NEXT:    # fallthrough-return
+;
+; RELAXED32-LABEL: fence_release:
+; RELAXED32:         .functype fence_release () -> ()
+; RELAXED32-NEXT:  # %bb.0:
+; RELAXED32-NEXT:    atomic.fence acqrel
+; RELAXED32-NEXT:    # fallthrough-return
+;
+; RELAXED64-LABEL: fence_release:
+; RELAXED64:         .functype fence_release () -> ()
+; RELAXED64-NEXT:  # %bb.0:
+; RELAXED64-NEXT:    atomic.fence acqrel
+; RELAXED64-NEXT:    # fallthrough-return
   fence release
+  ret void
+}
+
+define void @fence_acq_rel() {
+; NO-ATOMICS-LABEL: fence_acq_rel:
+; NO-ATOMICS:         .functype fence_acq_rel () -> ()
+; NO-ATOMICS-NEXT:  # %bb.0:
+; NO-ATOMICS-NEXT:    # fallthrough-return
+;
+; ATOMICS-LABEL: fence_acq_rel:
+; ATOMICS:         .functype fence_acq_rel () -> ()
+; ATOMICS-NEXT:  # %bb.0:
+; ATOMICS-NEXT:    atomic.fence
+; ATOMICS-NEXT:    # fallthrough-return
+;
+; RELAXED32-LABEL: fence_acq_rel:
+; RELAXED32:         .functype fence_acq_rel () -> ()
+; RELAXED32-NEXT:  # %bb.0:
+; RELAXED32-NEXT:    atomic.fence acqrel
+; RELAXED32-NEXT:    # fallthrough-return
+;
+; RELAXED64-LABEL: fence_acq_rel:
+; RELAXED64:         .functype fence_acq_rel () -> ()
+; RELAXED64-NEXT:  # %bb.0:
+; RELAXED64-NEXT:    atomic.fence acqrel
+; RELAXED64-NEXT:    # fallthrough-return
   fence acq_rel
   ret void
 }
 
+define void @fence_seq_cst() {
+; NO-ATOMICS-LABEL: fence_seq_cst:
+; NO-ATOMICS:         .functype fence_seq_cst () -> ()
+; NO-ATOMICS-NEXT:  # %bb.0:
+; NO-ATOMICS-NEXT:    # fallthrough-return
+;
+; ATOMICS-LABEL: fence_seq_cst:
+; ATOMICS:         .functype fence_seq_cst () -> ()
+; ATOMICS-NEXT:  # %bb.0:
+; ATOMICS-NEXT:    atomic.fence
+; ATOMICS-NEXT:    # fallthrough-return
+;
+; RELAXED32-LABEL: fence_seq_cst:
+; RELAXED32:         .functype fence_seq_cst () -> ()
+; RELAXED32-NEXT:  # %bb.0:
+; RELAXED32-NEXT:    atomic.fence seqcst
+; RELAXED32-NEXT:    # fallthrough-return
+;
+; RELAXED64-LABEL: fence_seq_cst:
+; RELAXED64:         .functype fence_seq_cst () -> ()
+; RELAXED64-NEXT:  # %bb.0:
+; RELAXED64-NEXT:    atomic.fence seqcst
+; RELAXED64-NEXT:    # fallthrough-return
+  fence seq_cst
+  ret void
+}
+
 ; A singlethread fence becomes compiler_fence instruction, a pseudo instruction
 ; that acts as a compiler barrier. The barrier should not be emitted to .s file.
-; CHECK-LABEL: singlethread_fence:
-; CHECK-NOT: compiler_fence
-; CHECK-NOT: atomic_fence
 define void @singlethread_fence() {
+; NO-ATOMICS-LABEL: singlethread_fence:
+; NO-ATOMICS:         .functype singlethread_fence () -> ()
+; NO-ATOMICS-NEXT:  # %bb.0:
+; NO-ATOMICS-NEXT:    # fallthrough-return
+;
+; ATOMICS-LABEL: singlethread_fence:
+; ATOMICS:         .functype singlethread_fence () -> ()
+; ATOMICS-NEXT:  # %bb.0:
+; ATOMICS-NEXT:    # fallthrough-return
+;
+; RELAXED32-LABEL: singlethread_fence:
+; RELAXED32:         .functype singlethread_fence () -> ()
+; RELAXED32-NEXT:  # %bb.0:
+; RELAXED32-NEXT:    # fallthrough-return
+;
+; RELAXED64-LABEL: singlethread_fence:
+; RELAXED64:         .functype singlethread_fence () -> ()
+; RELAXED64-NEXT:  # %bb.0:
+; RELAXED64-NEXT:    # fallthrough-return
   fence syncscope("singlethread") seq_cst
   fence syncscope("singlethread") acquire
   fence syncscope("singlethread") release
diff --git a/llvm/test/CodeGen/WebAssembly/atomic-mem-consistency.ll b/llvm/test/CodeGen/WebAssembly/atomic-mem-consistency.ll
index 5e9a0060c6ece..116c5fbba34d9 100644
--- a/llvm/test/CodeGen/WebAssembly/atomic-mem-consistency.ll
+++ b/llvm/test/CodeGen/WebAssembly/atomic-mem-consistency.ll
@@ -1,9 +1,13 @@
-; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt
-; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -wasm-disable-explicit-locals -wasm-keep-registers -mattr=+atomics,+sign-ext | FileCheck %s
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 6
+; RUN: llc < %s --mtriple=wasm32 | FileCheck %s --check-prefixes=NO-ATOMICS
+; RUN: llc < %s --mtriple=wasm32 -mattr=+atomics | FileCheck %s --check-prefixes=ATOMICS
+; RUN: llc < %s --mtriple=wasm32 -mattr=+atomics,+relaxed-atomics | FileCheck %s --check-prefixes=RELAXED32
+; RUN: llc < %s --mtriple=wasm64 -mattr=+atomics,+relaxed-atomics | FileCheck %s --check-prefixes=RELAXED64
 
-; Currently all wasm atomic memory access instructions are sequentially
-; consistent, so even if LLVM IR specifies weaker orderings than that, we
-; should upgrade them to sequential ordering and treat them in the same way.
+; Currently Wasm supports a constrained set of atomic memory orderings.
+; Originally it supported only sequential consistency, but now it also
+; supports relaxed atomics. Weaker orderings in LLVM IR are "upgraded" to
+; the next supported ordering.
 
 target triple = "wasm32-unknown-unknown"
 
@@ -13,34 +17,130 @@ target triple = "wasm32-unknown-unknown"
 
 ; The 'release' and 'acq_rel' orderings are not valid on load instructions.
 
-; CHECK-LABEL: load_i32_unordered:
-; CHECK: i32.atomic.load $push0=, 0($0){{$}}
-; CHECK-NEXT: return $pop0{{$}}
 define i32 @load_i32_unordered(ptr %p) {
+; NO-ATOMICS-LABEL: load_i32_unordered:
+; NO-ATOMICS:         .functype load_i32_unordered (i32) -> (i32)
+; NO-ATOMICS-NEXT:  # %bb.0:
+; NO-ATOMICS-NEXT:    local.get 0
+; NO-ATOMICS-NEXT:    i32.load 0
+; NO-ATOMICS-NEXT:    # fallthrough-return
+;
+; ATOMICS-LABEL: load_i32_unordered:
+; ATOMICS:         .functype load_i32_unordered (i32) -> (i32)
+; ATOMICS-NEXT:  # %bb.0:
+; ATOMICS-NEXT:    local.get 0
+; ATOMICS-NEXT:    i32.atomic.load 0
+; ATOMICS-NEXT:    # fallthrough-return
+;
+; RELAXED32-LABEL: load_i32_unordered:
+; RELAXED32:         .functype load_i32_unordered (i32) -> (i32)
+; RELAXED32-NEXT:  # %bb.0:
+; RELAXED32-NEXT:    local.get 0
+; RELAXED32-NEXT:    i32.atomic.load acqrel 0
+; RELAXED32-NEXT:    # fallthrough-return
+;
+; RELAXED64-LABEL: load_i32_unordered:
+; RELAXED64:         .functype load_i32_unordered (i64) -> (i32)
+; RELAXED64-NEXT:  # %bb.0:
+; RELAXED64-NEXT:    local.get 0
+; RELAXED64-NEXT:    i32.atomic.load acqrel 0
+; RELAXED64-NEXT:    # fallthrough-return
   %v = load atomic i32, ptr %p unordered, align 4
   ret i32 %v
 }
 
-; CHECK-LABEL: load_i32_monotonic:
-; CHECK: i32.atomic.load $push0=, 0($0){{$}}
-; CHECK-NEXT: return $pop0{{$}}
 define i32 @load_i32_monotonic(ptr %p) {
+; NO-ATOMICS-LABEL: load_i32_monotonic:
+; NO-ATOMICS:         .functype load_i32_monotonic (i32) -> (i32)
+; NO-ATOMICS-NEXT:  # %bb.0:
+; NO-ATOMICS-NEXT:    local.get 0
+; NO-ATOMICS-NEXT:    i32.load 0
+; NO-ATOMICS-NEXT:    # fallthrough-return
+;
+; ATOMICS-LABEL: load_i32_monotonic:
+; ATOMICS:         .functype load_i32_monotonic (i32) -> (i32)
+; ATOMICS-NEXT:  # %bb.0:
+; ATOMICS-NEXT:    local.get 0
+; ATOMICS-NEXT:    i32.atomic.load 0
+; ATOMICS-NEXT:    # fallthrough-return
+;
+; RELAXED32-LABEL: load_i32_monotonic:
+; RELAXED32:         .functype load_i32_monotonic (i32) -> (i32)
+; RELAXED32-NEXT:  # %bb.0:
+; RELAXED32-NEXT:    local.get 0
+; RELAXED32-NEXT:    i32.atomic.load acqrel 0
+; RELAXED32-NEXT:    # fallthrough-return
+;
+; RELAXED64-LABEL: load_i32_monotonic:
+; RELAXED64:         .functype load_i32_monotonic (i64) -> (i32)
+; RELAXED64-NEXT:  # %bb.0:
+; RELAXED64-NEXT:    local.get 0
+; RELAXED64-NEXT:    i32.atomic.load acqrel 0
+; RELAXED64-NEXT:    # fallthrough-return
   %v = load atomic i32, ptr %p monotonic, align 4
   ret i32 %v
 }
 
-; CHECK-LABEL: load_i32_acquire:
-; CHECK: i32.atomic.load $push0=, 0($0){{$}}
-; CHECK-NEXT: return $pop0{{$}}
 define i32 @load_i32_acquire(ptr %p) {
+; NO-ATOMICS-LABEL: load_i32_acquire:
+; NO-ATOMICS:         .functype load_i32_acquire (i32) -> (i32)
+; NO-ATOMICS-NEXT:  # %bb.0:
+; NO-ATOMICS-NEXT:    local.get 0
+; NO-ATOMICS-NEXT:    i32.load 0
+; NO-ATOMICS-NEXT:    # fallthrough-return
+;
+; ATOMICS-LABEL: load_i32_acquire:
+; ATOMICS:         .functype load_i32_acquire (i32) -> (i32)
+; ATOMICS-NEXT:  # %bb.0:
+; ATOMICS-NEXT:    local.get 0
+; ATOMICS-NEXT:    i32.atomic.load 0
+; ATOMICS-NEXT:    # fallthrough-return
+;
+; RELAXED32-LABEL: load_i32_acquire:
+; RELAXED32:         .functype load_i32_acquire (i32) -> (i32)
+; RELAXED32-NEXT:  # %bb.0:
+; RELAXED32-NEXT:    local.get 0
+; RELAXED32-NEXT:    i32.atomic.load acqrel 0
+; RELAXED32-NEXT:    # fallthrough-return
+;
+; RELAXED64-LABEL: load_i32_acquire:
+; RELAXED64:         .functype load_i32_acquire (i64) -> (i32)
+; RELAXED64-NEXT:  # %bb.0:
+; RELAXED64-NEXT:    local.get 0
+; RELAXED64-NEXT:    i32.atomic.load acqrel 0
+; RELAXED64-NEXT:    # fallthrough-return
   %v = load atomic i32, ptr %p acquire, align 4
   ret i32 %v
 }
 
-; CHECK-LABEL: load_i32_seq_cst:
-; CHECK: i32.atomic.load $push0=, 0($0){{$}}
-; CHECK-NEXT: return $pop0{{$}}
 define i32 @load_i32_seq_cst(ptr %p) {
+; NO-ATOMICS-LABEL: load_i32_seq_cst:
+; NO-ATOMICS:         .functype load_i32_seq_cst (i32) -> (i32)
+; NO-ATOMICS-NEXT:  # %bb.0:
+; NO-ATOMICS-NEXT:    local.get 0
+; NO-ATOMICS-NEXT:    i32.load 0
+; NO-ATOMICS-NEXT:    # fallthrough-return
+;
+; ATOMICS-LABEL: load_i32_seq_cst:
+; ATOMICS:         .functype load_i32_seq_cst (i32) -> (i32)
+; ATOMICS-NEXT:  # %bb.0:
+; ATOMICS-NEXT:    local.get 0
+; ATOMICS-NEXT:    i32.atomic.load 0
+; ATOMICS-NEXT:    # fallthrough-return
+;
+; RELAXED32-LABEL: load_i32_seq_cst:
+; RELAXED32:         .functype load_i32_seq_cst (i32) -> (i32)
+; RELAXED32-NEXT:  # %bb.0:
+; RELAXED32-NEXT:    local.get 0
+; RELAXED32-NEXT:    i32.atomic.load seqcst 0
+; RELAXED32-NEXT:    # fallthrough-return
+;
+; RELAXED64-LABEL: load_i32_seq_cst:
+; RELAXED64:         .functype load_i32_seq_cst (i64) -> (i32)
+; RELAXED64-NEXT:  # %bb.0:
+; RELAXED64-NEXT:    local.get 0
+; RELAXED64-NEXT:    i32.atomic.load seqcst 0
+; RELAXED64-NEXT:    # fallthrough-return
   %v = load atomic i32, ptr %p seq_cst, align 4
   ret i32 %v
 }
@@ -51,38 +151,146 @@ define i32 @load_i32_seq_cst(ptr %p) {
 
 ; The 'acquire' and 'acq_rel' orderings aren’t valid on store instructions.
 
-; CHECK-LABEL: store_i32_unordered:
-; CHECK-NEXT: .functype store_i32_unordered (i32, i32) -> (){{$}}
-; CHECK-NEXT: i32.atomic.store 0($0), $1{{$}}
-; CHECK-NEXT: return{{$}}
 define void @store_i32_unordered(ptr %p, i32 %v) {
+; NO-ATOMICS-LABEL: store_i32_unordered:
+; NO-ATOMICS:         .functype store_i32_unordered (i32, i32) -> ()
+; NO-ATOMICS-NEXT:  # %bb.0:
+; NO-ATOMICS-NEXT:    local.get 0
+; NO-ATOMICS-NEXT:    local.get 1
+; NO-ATOMICS-NEXT:    i32.store 0
+; NO-ATOMICS-NEXT:    # fallthrough-return
+;
+; ATOMICS-LABEL: store_i32_unordered:
+; ATOMICS:         .functype store_i32_unordered (i32, i32) -> ()
+; ATOMICS-NEXT:  # %bb.0:
+; ATOMICS-NEXT:    local.get 0
+; ATOMICS-NEXT:    local.get 1
+; ATOMICS-NEXT:    i32.atomic.store 0
+; ATOMICS-NEXT:    # fallthrough-return
+;
+; RELAXED32-LABEL: store_i32_unordered:
+; RELAXED32:         .functype store_i32_unordered (i32, i32) -> ()
+; RELAXED32-NEXT:  # %bb.0:
+; RELAXED32-NEXT:    local.get 0
+; RELAXED32-NEXT:    local.get 1
+; RELAXED32-NEXT:    i32.atomic.store acqrel 0
+; RELAXED32-NEXT:    # fallthrough-return
+;
+; RELAXED64-LABEL: store_i32_unordered:
+; RELAXED64:         .functype store_i32_unordered (i64, i32) -> ()
+; RELAXED64-NEXT:  # %bb.0:
+; RELAXED64-NEXT:    local.get 0
+; RELAXED64-NEXT:    local.get 1
+; RELAXED64-NEXT:    i32.atomic.store acqrel 0
+; RELAXED64-NEXT:    # fallthrough-return
   store atomic i32 %v, ptr %p unordered, align 4
   ret void
 }
 
-; CHECK-LABEL: store_i32_monotonic:
-; CHECK-NEXT: .functype store_i32_monotonic (i32, i32) -> (){{$}}
-; CHECK-NEXT: i32.atomic.store 0($0), $1{{$}}
-; CHECK-NEXT: return{{$}}
 define void @store_i32_monotonic(ptr %p, i32 %v) {
+; NO-ATOMICS-LABEL: store_i32_monotonic:
+; NO-ATOMICS:         .functype store_i32_monotonic (i32, i32) -> ()
+; NO-ATOMICS-NEXT:  # %bb.0:
+; NO-ATOMICS-NEXT:    local.get 0
+; NO-ATOMICS-NEXT:    local.get 1
+; NO-ATOMICS-NEXT:    i32.store 0
+; NO-ATOMICS-NEXT:    # fallthrough-return
+;
+; ATOMICS-LABEL: store_i32_monotonic:
+; ATOMICS:         .functype store_i32_monotonic (i32, i32) -> ()
+; ATOMICS-NEXT:  # %bb.0:
+; ATOMICS-NEXT:    local.get 0
+; ATOMICS-NEXT:    local.get 1
+; ATOMICS-NEXT:    i32.atomic.store 0
+; ATOMICS-NEXT:    # fallthrough-return
+;
+; RELAXED32-LABEL: store_i32_monotonic:
+; RELAXED32:         .functype store_i32_monotonic (i32, i32) -> ()
+; RELAXED32-NEXT:  # %bb.0:
+; RELAXED32-NEXT:    local.get 0
+; RELAXED32-NEXT:    local.get 1
+; RELAXED32-NEXT:    i32.atomic.store acqrel 0
+; RELAXED32-NEXT:    # fallthrough-return
+;
+; RELAXED64-LABEL: store_i32_monotonic:
+; RELAXED64:         .functype store_i32_monotonic (i64, i32) -> ()
+; RELAXED64-NEXT:  # %bb.0:
+; RELAXED64-NEXT:    local.get 0
+; RELAXED64-NEXT:    local.get 1
+; RELAXED64-NEXT:    i32.atomic.store acqrel 0
+; RELAXED64-NEXT:    # fallthrough-return
   store atomic i32 %v, ptr %p monotonic, align 4
   ret void
 }
 
-; CHECK-LABEL: store_i32_release:
-; CHECK-NEXT: .functype store_i32_release (i32, i32) -> (){{$}}
-; CHECK-NEXT: i32.atomic.store 0($0), $1{{$}}
-; CHECK-NEXT: return{{$}}
 define void @store_i32_release(ptr %p, i32 %v) {
+; NO-ATOMICS-LABEL: store_i32_release:
+; NO-ATOMICS:         .functype store_i32_release (i32, i32) -> ()
+; NO-ATOMICS-NEXT:  # %bb.0:
+; NO-ATOMICS-NEXT:    local.get 0
+; NO-ATOMICS-NEXT:    local.get 1
+; NO-ATOMICS-NEXT:    i32.store 0
+; NO-ATOMICS-NEXT:    # fallthrough-return
+;
+; ATOMICS-LABEL: store_i32_release:
+; ATOMICS:         .functype store_i32_release (i32, i32) -> ()
+; ATOMICS-NEXT:  # %bb.0:
+; ATOMICS-NEXT:    local.get 0
+; ATOMICS-NEXT:    local.get 1
+; ATOMICS-NEXT:    i32.atomic.store 0
+; ATOMICS-NEXT:    # fallthrough-return
+;
+; RELAXED32-LABEL: store_i32_release:
+; RELAXED32:         .functype store_i32_release (i32, i32) -> ()
+; RELAXED32-NEXT:  # %bb.0:
+; RELAXED32-NEXT:    local.get 0
+; RELAXED32-NEXT:    local.get 1
+; RELAXED32-NEXT:    i32.atomic.store acqrel 0
+; RELAXED32-NEXT:    # fallthrough-return
+;
+; RELAXED64-LABEL: store_i32_release:
+; RELAXED64:         .functype store_i32_release (i64, i32) -> ()
+; RELAXED64-NEXT:  # %bb.0:
+; RELAXED64-NEXT:    local.get 0
+; RELAXED64-NEXT:    local.get 1
+; RELAXED64-NEXT:    i32.atomic.store acqrel 0
+; RELAXED64-NEXT:    # fallthrough-return
   store atomic i32 %v, ptr %p release, align 4
   ret void
 }
 
-; CHECK-LABEL: store_i32_seq_cst:
-; CHECK-NEXT: .functype store_i32_seq_cst (i32, i32) -> (){{$}}
-; CHECK-NEXT: i32.atomic.store 0($0), $1{{$}}
-; CHECK-NEXT: return{{$}}
 define void @store_i32_seq_cst(ptr %p, i32 %v) {
+; NO-ATOMICS-LABEL: store_i32_seq_cst:
+; NO-ATOMICS:         .functype store_i32_seq_cst (i32, i32) -> ()
+; NO-ATOMICS-NEXT:  # %bb.0:
+; NO-ATOMICS-NEXT:    local.get 0
+; NO-ATOMICS-NEXT:    local.get 1
+; NO-ATOMICS-NEXT:    i32.store 0
+; NO-ATOMICS-NEXT:    # fallthrough-return
+;
+; ATOMICS-LABEL: store_i32_seq_cst:
+; ATOMICS:         .functype store_i32_seq_cst (i32, i32) -> ()
+; ATOMICS-NEXT:  # %bb.0:
+; ATOMICS-NEXT:    local.get 0
+; ATOMICS-NEXT:    local.get 1
+; ATOMICS-NEXT:    i32.atomic.store 0
+; ATOMICS-NEXT:    # fallthrough-return
+;
+; RELAXED32-LABEL: store_i32_seq_cst:
+; RELAXED32:         .functype store_i32_seq_cst (i32, i32) -> ()
+; RELAXED32-NEXT:  # %bb.0:
+; RELAXED32-NEXT:    local.get 0
+; RELAXED32-NEXT:    local.get 1
+; RELAXED32-NEXT:    i32.atomic.store seqcst 0
+; RELAXED32-NEXT:    # fallthrough-return
+;
+; RELAXED64-LABEL: store_i32_seq_cst:
+; RELAXED64:         .functype store_i32_seq_cst (i64, i32) -> ()
+; RELAXED64-NEXT:  # %bb.0:
+; RELAXED64-NEXT:    local.get 0
+; RELAXED64-NEXT:    local.get 1
+; RELAXED64-NEXT:    i32.atomic.store seqcst 0
+; RELAXED64-NEXT:    # fallthrough-return
   store atomic i32 %v, ptr %p seq_cst, align 4
   ret void
 }
@@ -94,47 +302,212 @@ define void @store_i32_seq_cst(ptr %p, i32 %v) {
 ; Out of several binary RMW instructions, here we test 'add' as an example.
 ; The 'unordered' ordering is not valid on atomicrmw instructions.
 
-; CHECK-LABEL: add_i32_monotonic:
-; CHECK-NEXT: .functype add_i32_monotonic (i32, i32) -> (i32){{$}}
-; CHECK: i32.atomic.rmw.add $push0=, 0($0), $1{{$}}
-; CHECK-NEXT: return $pop0{{$}}
 define i32 @add_i32_monotonic(ptr %p, i32 %v) {
+; NO-ATOMICS-LABEL: add_i32_monotonic:
+; NO-ATOMICS:         .functype add_i32_monotonic (i32, i32) -> (i32)
+; NO-ATOMICS-NEXT:    .local i32
+; NO-ATOMICS-NEXT:  # %bb.0:
+; NO-ATOMICS-NEXT:    local.get 0
+; NO-ATOMICS-NEXT:    local.get 0
+; NO-ATOMICS-NEXT:    i32.load 0
+; NO-ATOMICS-NEXT:    local.tee 2
+; NO-ATOMICS-NEXT:    local.get 1
+; NO-ATOMICS-NEXT:    i32.add
+; NO-ATOMICS-NEXT:    i32.store 0
+; NO-ATOMICS-NEXT:    local.get 2
+; NO-ATOMICS-NEXT:    # fallthrough-return
+;
+; ATOMICS-LABEL: add_i32_monotonic:
+; ATOMICS:         .functype add_i32_monotonic (i32, i32) -> (i32)
+; ATOMICS-NEXT:  # %bb.0:
+; ATOMICS-NEXT:    local.get 0
+; ATOMICS-NEXT:    local.get 1
+; ATOMICS-NEXT:    i32.atomic.rmw.add 0
+; ATOMICS-NEXT:    # fallthrough-return
+;
+; RELAXED32-LABEL: add_i32_monotonic:
+; RELAXED32:         .functype add_i32_monotonic (i32, i32) -> (i32)
+; RELAXED32-NEXT:  # %bb.0:
+; RELAXED32-NEXT:    local.get 0
+; RELAXED32-NEXT:    local.get 1
+; RELAXED32-NEXT:    i32.atomic.rmw.add acqrel 0
+; RELAXED32-NEXT:    # fallthrough-return
+;
+; RELAXED64-LABEL: add_i32_monotonic:
+; RELAXED64:         .functype add_i32_monotonic (i64, i32) -> (i32)
+; RELAXED64-NEXT:  # %bb.0:
+; RELAXED64-NEXT:    local.get 0
+; RELAXED64-NEXT:    local.get 1
+; RELAXED64-NEXT:    i32.atomic.rmw.add acqrel 0
+; RELAXED64-NEXT:    # fallthrough-return
   %old = atomicrmw add ptr %p, i32 %v monotonic
   ret i32 %old
 }
 
-; CHECK-LABEL: add_i32_acquire:
-; CHECK-NEXT: .functype add_i32_acquire (i32, i32) -> (i32){{$}}
-; CHECK: i32.atomic.rmw.add $push0=, 0($0), $1{{$}}
-; CHECK-NEXT: return $pop0{{$}}
 define i32 @add_i32_acquire(ptr %p, i32 %v) {
+; NO-ATOMICS-LABEL: add_i32_acquire:
+; NO-ATOMICS:         .functype add_i32_acquire (i32, i32) -> (i32)
+; NO-ATOMICS-NEXT:    .local i32
+; NO-ATOMICS-NEXT:  # %bb.0:
+; NO-ATOMICS-NEXT:    local.get 0
+; NO-ATOMICS-NEXT:    local.get 0
+; NO-ATOMICS-NEXT:    i32.load 0
+; NO-ATOMICS-NEXT:    local.tee 2
+; NO-ATOMICS-NEXT:    local.get 1
+; NO-ATOMICS-NEXT:    i32.add
+; NO-ATOMICS-NEXT:    i32.store 0
+; NO-ATOMICS-NEXT:    local.get 2
+; NO-ATOMICS-NEXT:    # fallthrough-return
+;
+; ATOMICS-LABEL: add_i32_acquire:
+; ATOMICS:         .functype add_i32_acquire (i32, i32) -> (i32)
+; ATOMICS-NEXT:  # %bb.0:
+; ATOMICS-NEXT:    local.get 0
+; ATOMICS-NEXT:    local.get 1
+; ATOMICS-NEXT:    i32.atomic.rmw.add 0
+; ATOMICS-NEXT:    # fallthrough-return
+;
+; RELAXED32-LABEL: add_i32_acquire:
+; RELAXED32:         .functype add_i32_acquire (i32, i32) -> (i32)
+; RELAXED32-NEXT:  # %bb.0:
+; RELAXED32-NEXT:    local.get 0
+; RELAXED32-NEXT:    local.get 1
+; RELAXED32-NEXT:    i32.atomic.rmw.add acqrel 0
+; RELAXED32-NEXT:    # fallthrough-return
+;
+; RELAXED64-LABEL: add_i32_acquire:
+; RELAXED64:         .functype add_i32_acquire (i64, i32) -> (i32)
+; RELAXED64-NEXT:  # %bb.0:
+; RELAXED64-NEXT:    local.get 0
+; RELAXED64-NEXT:    local.get 1
+; RELAXED64-NEXT:    i32.atomic.rmw.add acqrel 0
+; RELAXED64-NEXT:    # fallthrough-return
   %old = atomicrmw add ptr %p, i32 %v acquire
   ret i32 %old
 }
 
-; CHECK-LABEL: add_i32_release:
-; CHECK-NEXT: .functype add_i32_release (i32, i32) -> (i32){{$}}
-; CHECK: i32.atomic.rmw.add $push0=, 0($0), $1{{$}}
-; CHECK-NEXT: return $pop0{{$}}
 define i32 @add_i32_release(ptr %p, i32 %v) {
+; NO-ATOMICS-LABEL: add_i32_release:
+; NO-ATOMICS:         .functype add_i32_release (i32, i32) -> (i32)
+; NO-ATOMICS-NEXT:    .local i32
+; NO-ATOMICS-NEXT:  # %bb.0:
+; NO-ATOMICS-NEXT:    local.get 0
+; NO-ATOMICS-NEXT:    local.get 0
+; NO-ATOMICS-NEXT:    i32.load 0
+; NO-ATOMICS-NEXT:    local.tee 2
+; NO-ATOMICS-NEXT:    local.get 1
+; NO-ATOMICS-NEXT:    i32.add
+; NO-ATOMICS-NEXT:    i32.store 0
+; NO-ATOMICS-NEXT:    local.get 2
+; NO-ATOMICS-NEXT:    # fallthrough-return
+;
+; ATOMICS-LABEL: add_i32_release:
+; ATOMICS:         .functype add_i32_release (i32, i32) -> (i32)
+; ATOMICS-NEXT:  # %bb.0:
+; ATOMICS-NEXT:    local.get 0
+; ATOMICS-NEXT:    local.get 1
+; ATOMICS-NEXT:    i32.atomic.rmw.add 0
+; ATOMICS-NEXT:    # fallthrough-return
+;
+; RELAXED32-LABEL: add_i32_release:
+; RELAXED32:         .functype add_i32_release (i32, i32) -> (i32)
+; RELAXED32-NEXT:  # %bb.0:
+; RELAXED32-NEXT:    local.get 0
+; RELAXED32-NEXT:    local.get 1
+; RELAXED32-NEXT:    i32.atomic.rmw.add acqrel 0
+; RELAXED32-NEXT:    # fallthrough-return
+;
+; RELAXED64-LABEL: add_i32_release:
+; RELAXED64:         .functype add_i32_release (i64, i32) -> (i32)
+; RELAXED64-NEXT:  # %bb.0:
+; RELAXED64-NEXT:    local.get 0
+; RELAXED64-NEXT:    local.get 1
+; RELAXED64-NEXT:    i32.atomic.rmw.add acqrel 0
+; RELAXED64-NEXT:    # fallthrough-return
   %old = atomicrmw add ptr %p, i32 %v release
   ret i32 %old
 }
 
-; CHECK-LABEL: add_i32_acq_rel:
-; CHECK-NEXT: .functype add_i32_acq_rel (i32, i32) -> (i32){{$}}
-; CHECK: i32.atomic.rmw.add $push0=, 0($0), $1{{$}}
-; CHECK-NEXT: return $pop0{{$}}
 define i32 @add_i32_acq_rel(ptr %p, i32 %v) {
+; NO-ATOMICS-LABEL: add_i32_acq_rel:
+; NO-ATOMICS:         .functype add_i32_acq_rel (i32, i32) -> (i32)
+; NO-ATOMICS-NEXT:    .local i32
+; NO-ATOMICS-NEXT:  # %bb.0:
+; NO-ATOMICS-NEXT:    local.get 0
+; NO-ATOMICS-NEXT:    local.get 0
+; NO-ATOMICS-NEXT:    i32.load 0
+; NO-ATOMICS-NEXT:    local.tee 2
+; NO-ATOMICS-NEXT:    local.get 1
+; NO-ATOMICS-NEXT:    i32.add
+; NO-ATOMICS-NEXT:    i32.store 0
+; NO-ATOMICS-NEXT:    local.get 2
+; NO-ATOMICS-NEXT:    # fallthrough-return
+;
+; ATOMICS-LABEL: add_i32_acq_rel:
+; ATOMICS:         .functype add_i32_acq_rel (i32, i32) -> (i32)
+; ATOMICS-NEXT:  # %bb.0:
+; ATOMICS-NEXT:    local.get 0
+; ATOMICS-NEXT:    local.get 1
+; ATOMICS-NEXT:    i32.atomic.rmw.add 0
+; ATOMICS-NEXT:    # fallthrough-return
+;
+; RELAXED32-LABEL: add_i32_acq_rel:
+; RELAXED32:         .functype add_i32_acq_rel (i32, i32) -> (i32)
+; RELAXED32-NEXT:  # %bb.0:
+; RELAXED32-NEXT:    local.get 0
+; RELAXED32-NEXT:    local.get 1
+; RELAXED32-NEXT:    i32.atomic.rmw.add acqrel 0
+; RELAXED32-NEXT:    # fallthrough-return
+;
+; RELAXED64-LABEL: add_i32_acq_rel:
+; RELAXED64:         .functype add_i32_acq_rel (i64, i32) -> (i32)
+; RELAXED64-NEXT:  # %bb.0:
+; RELAXED64-NEXT:    local.get 0
+; RELAXED64-NEXT:    local.get 1
+; RELAXED64-NEXT:    i32.atomic.rmw.add acqrel 0
+; RELAXED64-NEXT:    # fallthrough-return
   %old = atomicrmw add ptr %p, i32 %v acq_rel
   ret i32 %old
 }
 
-; CHECK-LABEL: add_i32_seq_cst:
-; CHECK-NEXT: .functype add_i32_seq_cst (i32, i32) -> (i32){{$}}
-; CHECK: i32.atomic.rmw.add $push0=, 0($0), $1{{$}}
-; CHECK-NEXT: return $pop0{{$}}
 define i32 @add_i32_seq_cst(ptr %p, i32 %v) {
+; NO-ATOMICS-LABEL: add_i32_seq_cst:
+; NO-ATOMICS:         .functype add_i32_seq_cst (i32, i32) -> (i32)
+; NO-ATOMICS-NEXT:    .local i32
+; NO-ATOMICS-NEXT:  # %bb.0:
+; NO-ATOMICS-NEXT:    local.get 0
+; NO-ATOMICS-NEXT:    local.get 0
+; NO-ATOMICS-NEXT:    i32.load 0
+; NO-ATOMICS-NEXT:    local.tee 2
+; NO-ATOMICS-NEXT:    local.get 1
+; NO-ATOMICS-NEXT:    i32.add
+; NO-ATOMICS-NEXT:    i32.store 0
+; NO-ATOMICS-NEXT:    local.get 2
+; NO-ATOMICS-NEXT:    # fallthrough-return
+;
+; ATOMICS-LABEL: add_i32_seq_cst:
+; ATOMICS:         .functype add_i32_seq_cst (i32, i32) -> (i32)
+; ATOMICS-NEXT:  # %bb.0:
+; ATOMICS-NEXT:    local.get 0
+; ATOMICS-NEXT:    local.get 1
+; ATOMICS-NEXT:    i32.atomic.rmw.add 0
+; ATOMICS-NEXT:    # fallthrough-return
+;
+; RELAXED32-LABEL: add_i32_seq_cst:
+; RELAXED32:         .functype add_i32_seq_cst (i32, i32) -> (i32)
+; RELAXED32-NEXT:  # %bb.0:
+; RELAXED32-NEXT:    local.get 0
+; RELAXED32-NEXT:    local.get 1
+; RELAXED32-NEXT:    i32.atomic.rmw.add seqcst 0
+; RELAXED32-NEXT:    # fallthrough-return
+;
+; RELAXED64-LABEL: add_i32_seq_cst:
+; RELAXED64:         .functype add_i32_seq_cst (i64, i32) -> (i32)
+; RELAXED64-NEXT:  # %bb.0:
+; RELAXED64-NEXT:    local.get 0
+; RELAXED64-NEXT:    local.get 1
+; RELAXED64-NEXT:    i32.atomic.rmw.add seqcst 0
+; RELAXED64-NEXT:    # fallthrough-return
   %old = atomicrmw add ptr %p, i32 %v seq_cst
   ret i32 %old
 }
@@ -145,81 +518,393 @@ define i32 @add_i32_seq_cst(ptr %p, i32 %v) {
 ; least monotonic, the ordering constraint on failure must be no stronger than
 ; that on success, and the failure ordering cannot be either release or acq_rel.
 
-; CHECK-LABEL: cmpxchg_i32_monotonic_monotonic:
-; CHECK-NEXT: .functype cmpxchg_i32_monotonic_monotonic (i32, i32, i32) -> (i32){{$}}
-; CHECK: i32.atomic.rmw.cmpxchg $push0=, 0($0), $1, $2{{$}}
-; CHECK-NEXT: return $pop0{{$}}
 define i32 @cmpxchg_i32_monotonic_monotonic(ptr %p, i32 %exp, i32 %new) {
+; NO-ATOMICS-LABEL: cmpxchg_i32_monotonic_monotonic:
+; NO-ATOMICS:         .functype cmpxchg_i32_monotonic_monotonic (i32, i32, i32) -> (i32)
+; NO-ATOMICS-NEXT:    .local i32
+; NO-ATOMICS-NEXT:  # %bb.0:
+; NO-ATOMICS-NEXT:    local.get 0
+; NO-ATOMICS-NEXT:    local.get 2
+; NO-ATOMICS-NEXT:    local.get 0
+; NO-ATOMICS-NEXT:    i32.load 0
+; NO-ATOMICS-NEXT:    local.tee 3
+; NO-ATOMICS-NEXT:    local.get 3
+; NO-ATOMICS-NEXT:    local.get 1
+; NO-ATOMICS-NEXT:    i32.eq
+; NO-ATOMICS-NEXT:    i32.select
+; NO-ATOMICS-NEXT:    i32.store 0
+; NO-ATOMICS-NEXT:    local.get 3
+; NO-ATOMICS-NEXT:    # fallthrough-return
+;
+; ATOMICS-LABEL: cmpxchg_i32_monotonic_monotonic:
+; ATOMICS:         .functype cmpxchg_i32_monotonic_monotonic (i32, i32, i32) -> (i32)
+; ATOMICS-NEXT:  # %bb.0:
+; ATOMICS-NEXT:    local.get 0
+; ATOMICS-NEXT:    local.get 1
+; ATOMICS-NEXT:    local.get 2
+; ATOMICS-NEXT:    i32.atomic.rmw.cmpxchg 0
+; ATOMICS-NEXT:    # fallthrough-return
+;
+; RELAXED32-LABEL: cmpxchg_i32_monotonic_monotonic:
+; RELAXED32:         .functype cmpxchg_i32_monotonic_monotonic (i32, i32, i32) -> (i32)
+; RELAXED32-NEXT:  # %bb.0:
+; RELAXED32-NEXT:    local.get 0
+; RELAXED32-NEXT:    local.get 1
+; RELAXED32-NEXT:    local.get 2
+; RELAXED32-NEXT:    i32.atomic.rmw.cmpxchg acqrel 0
+; RELAXED32-NEXT:    # fallthrough-return
+;
+; RELAXED64-LABEL: cmpxchg_i32_monotonic_monotonic:
+; RELAXED64:         .functype cmpxchg_i32_monotonic_monotonic (i64, i32, i32) -> (i32)
+; RELAXED64-NEXT:  # %bb.0:
+; RELAXED64-NEXT:    local.get 0
+; RELAXED64-NEXT:    local.get 1
+; RELAXED64-NEXT:    local.get 2
+; RELAXED64-NEXT:    i32.atomic.rmw.cmpxchg acqrel 0
+; RELAXED64-NEXT:    # fallthrough-return
   %pair = cmpxchg ptr %p, i32 %exp, i32 %new monotonic monotonic
   %old = extractvalue { i32, i1 } %pair, 0
   ret i32 %old
 }
 
-; CHECK-LABEL: cmpxchg_i32_acquire_monotonic:
-; CHECK-NEXT: .functype cmpxchg_i32_acquire_monotonic (i32, i32, i32) -> (i32){{$}}
-; CHECK: i32.atomic.rmw.cmpxchg $push0=, 0($0), $1, $2{{$}}
-; CHECK-NEXT: return $pop0{{$}}
 define i32 @cmpxchg_i32_acquire_monotonic(ptr %p, i32 %exp, i32 %new) {
+; NO-ATOMICS-LABEL: cmpxchg_i32_acquire_monotonic:
+; NO-ATOMICS:         .functype cmpxchg_i32_acquire_monotonic (i32, i32, i32) -> (i32)
+; NO-ATOMICS-NEXT:    .local i32
+; NO-ATOMICS-NEXT:  # %bb.0:
+; NO-ATOMICS-NEXT:    local.get 0
+; NO-ATOMICS-NEXT:    local.get 2
+; NO-ATOMICS-NEXT:    local.get 0
+; NO-ATOMICS-NEXT:    i32.load 0
+; NO-ATOMICS-NEXT:    local.tee 3
+; NO-ATOMICS-NEXT:    local.get 3
+; NO-ATOMICS-NEXT:    local.get 1
+; NO-ATOMICS-NEXT:    i32.eq
+; NO-ATOMICS-NEXT:    i32.select
+; NO-ATOMICS-NEXT:    i32.store 0
+; NO-ATOMICS-NEXT:    local.get 3
+; NO-ATOMICS-NEXT:    # fallthrough-return
+;
+; ATOMICS-LABEL: cmpxchg_i32_acquire_monotonic:
+; ATOMICS:         .functype cmpxchg_i32_acquire_monotonic (i32, i32, i32) -> (i32)
+; ATOMICS-NEXT:  # %bb.0:
+; ATOMICS-NEXT:    local.get 0
+; ATOMICS-NEXT:    local.get 1
+; ATOMICS-NEXT:    local.get 2
+; ATOMICS-NEXT:    i32.atomic.rmw.cmpxchg 0
+; ATOMICS-NEXT:    # fallthrough-return
+;
+; RELAXED32-LABEL: cmpxchg_i32_acquire_monotonic:
+; RELAXED32:         .functype cmpxchg_i32_acquire_monotonic (i32, i32, i32) -> (i32)
+; RELAXED32-NEXT:  # %bb.0:
+; RELAXED32-NEXT:    local.get 0
+; RELAXED32-NEXT:    local.get 1
+; RELAXED32-NEXT:    local.get 2
+; RELAXED32-NEXT:    i32.atomic.rmw.cmpxchg acqrel 0
+; RELAXED32-NEXT:    # fallthrough-return
+;
+; RELAXED64-LABEL: cmpxchg_i32_acquire_monotonic:
+; RELAXED64:         .functype cmpxchg_i32_acquire_monotonic (i64, i32, i32) -> (i32)
+; RELAXED64-NEXT:  # %bb.0:
+; RELAXED64-NEXT:    local.get 0
+; RELAXED64-NEXT:    local.get 1
+; RELAXED64-NEXT:    local.get 2
+; RELAXED64-NEXT:    i32.atomic.rmw.cmpxchg acqrel 0
+; RELAXED64-NEXT:    # fallthrough-return
   %pair = cmpxchg ptr %p, i32 %exp, i32 %new acquire monotonic
   %old = extractvalue { i32, i1 } %pair, 0
   ret i32 %old
 }
 
-; CHECK-LABEL: cmpxchg_i32_release_monotonic:
-; CHECK-NEXT: .functype cmpxchg_i32_release_monotonic (i32, i32, i32) -> (i32){{$}}
-; CHECK: i32.atomic.rmw.cmpxchg $push0=, 0($0), $1, $2{{$}}
-; CHECK-NEXT: return $pop0{{$}}
 define i32 @cmpxchg_i32_release_monotonic(ptr %p, i32 %exp, i32 %new) {
+; NO-ATOMICS-LABEL: cmpxchg_i32_release_monotonic:
+; NO-ATOMICS:         .functype cmpxchg_i32_release_monotonic (i32, i32, i32) -> (i32)
+; NO-ATOMICS-NEXT:    .local i32
+; NO-ATOMICS-NEXT:  # %bb.0:
+; NO-ATOMICS-NEXT:    local.get 0
+; NO-ATOMICS-NEXT:    local.get 2
+; NO-ATOMICS-NEXT:    local.get 0
+; NO-ATOMICS-NEXT:    i32.load 0
+; NO-ATOMICS-NEXT:    local.tee 3
+; NO-ATOMICS-NEXT:    local.get 3
+; NO-ATOMICS-NEXT:    local.get 1
+; NO-ATOMICS-NEXT:    i32.eq
+; NO-ATOMICS-NEXT:    i32.select
+; NO-ATOMICS-NEXT:    i32.store 0
+; NO-ATOMICS-NEXT:    local.get 3
+; NO-ATOMICS-NEXT:    # fallthrough-return
+;
+; ATOMICS-LABEL: cmpxchg_i32_release_monotonic:
+; ATOMICS:         .functype cmpxchg_i32_release_monotonic (i32, i32, i32) -> (i32)
+; ATOMICS-NEXT:  # %bb.0:
+; ATOMICS-NEXT:    local.get 0
+; ATOMICS-NEXT:    local.get 1
+; ATOMICS-NEXT:    local.get 2
+; ATOMICS-NEXT:    i32.atomic.rmw.cmpxchg 0
+; ATOMICS-NEXT:    # fallthrough-return
+;
+; RELAXED32-LABEL: cmpxchg_i32_release_monotonic:
+; RELAXED32:         .functype cmpxchg_i32_release_monotonic (i32, i32, i32) -> (i32)
+; RELAXED32-NEXT:  # %bb.0:
+; RELAXED32-NEXT:    local.get 0
+; RELAXED32-NEXT:    local.get 1
+; RELAXED32-NEXT:    local.get 2
+; RELAXED32-NEXT:    i32.atomic.rmw.cmpxchg acqrel 0
+; RELAXED32-NEXT:    # fallthrough-return
+;
+; RELAXED64-LABEL: cmpxchg_i32_release_monotonic:
+; RELAXED64:         .functype cmpxchg_i32_release_monotonic (i64, i32, i32) -> (i32)
+; RELAXED64-NEXT:  # %bb.0:
+; RELAXED64-NEXT:    local.get 0
+; RELAXED64-NEXT:    local.get 1
+; RELAXED64-NEXT:    local.get 2
+; RELAXED64-NEXT:    i32.atomic.rmw.cmpxchg acqrel 0
+; RELAXED64-NEXT:    # fallthrough-return
   %pair = cmpxchg ptr %p, i32 %exp, i32 %new release monotonic
   %old = extractvalue { i32, i1 } %pair, 0
   ret i32 %old
 }
 
-; CHECK-LABEL: cmpxchg_i32_acq_rel_monotonic:
-; CHECK-NEXT: .functype cmpxchg_i32_acq_rel_monotonic (i32, i32, i32) -> (i32){{$}}
-; CHECK: i32.atomic.rmw.cmpxchg $push0=, 0($0), $1, $2{{$}}
-; CHECK-NEXT: return $pop0{{$}}
 define i32 @cmpxchg_i32_acq_rel_monotonic(ptr %p, i32 %exp, i32 %new) {
+; NO-ATOMICS-LABEL: cmpxchg_i32_acq_rel_monotonic:
+; NO-ATOMICS:         .functype cmpxchg_i32_acq_rel_monotonic (i32, i32, i32) -> (i32)
+; NO-ATOMICS-NEXT:    .local i32
+; NO-ATOMICS-NEXT:  # %bb.0:
+; NO-ATOMICS-NEXT:    local.get 0
+; NO-ATOMICS-NEXT:    local.get 2
+; NO-ATOMICS-NEXT:    local.get 0
+; NO-ATOMICS-NEXT:    i32.load 0
+; NO-ATOMICS-NEXT:    local.tee 3
+; NO-ATOMICS-NEXT:    local.get 3
+; NO-ATOMICS-NEXT:    local.get 1
+; NO-ATOMICS-NEXT:    i32.eq
+; NO-ATOMICS-NEXT:    i32.select
+; NO-ATOMICS-NEXT:    i32.store 0
+; NO-ATOMICS-NEXT:    local.get 3
+; NO-ATOMICS-NEXT:    # fallthrough-return
+;
+; ATOMICS-LABEL: cmpxchg_i32_acq_rel_monotonic:
+; ATOMICS:         .functype cmpxchg_i32_acq_rel_monotonic (i32, i32, i32) -> (i32)
+; ATOMICS-NEXT:  # %bb.0:
+; ATOMICS-NEXT:    local.get 0
+; ATOMICS-NEXT:    local.get 1
+; ATOMICS-NEXT:    local.get 2
+; ATOMICS-NEXT:    i32.atomic.rmw.cmpxchg 0
+; ATOMICS-NEXT:    # fallthrough-return
+;
+; RELAXED32-LABEL: cmpxchg_i32_acq_rel_monotonic:
+; RELAXED32:         .functype cmpxchg_i32_acq_rel_monotonic (i32, i32, i32) -> (i32)
+; RELAXED32-NEXT:  # %bb.0:
+; RELAXED32-NEXT:    local.get 0
+; RELAXED32-NEXT:    local.get 1
+; RELAXED32-NEXT:    local.get 2
+; RELAXED32-NEXT:    i32.atomic.rmw.cmpxchg acqrel 0
+; RELAXED32-NEXT:    # fallthrough-return
+;
+; RELAXED64-LABEL: cmpxchg_i32_acq_rel_monotonic:
+; RELAXED64:         .functype cmpxchg_i32_acq_rel_monotonic (i64, i32, i32) -> (i32)
+; RELAXED64-NEXT:  # %bb.0:
+; RELAXED64-NEXT:    local.get 0
+; RELAXED64-NEXT:    local.get 1
+; RELAXED64-NEXT:    local.get 2
+; RELAXED64-NEXT:    i32.atomic.rmw.cmpxchg acqrel 0
+; RELAXED64-NEXT:    # fallthrough-return
   %pair = cmpxchg ptr %p, i32 %exp, i32 %new acq_rel monotonic
   %old = extractvalue { i32, i1 } %pair, 0
   ret i32 %old
 }
 
-; CHECK-LABEL: cmpxchg_i32_seq_cst_monotonic:
-; CHECK-NEXT: .functype cmpxchg_i32_seq_cst_monotonic (i32, i32, i32) -> (i32){{$}}
-; CHECK: i32.atomic.rmw.cmpxchg $push0=, 0($0), $1, $2{{$}}
-; CHECK-NEXT: return $pop0{{$}}
 define i32 @cmpxchg_i32_seq_cst_monotonic(ptr %p, i32 %exp, i32 %new) {
+; NO-ATOMICS-LABEL: cmpxchg_i32_seq_cst_monotonic:
+; NO-ATOMICS:         .functype cmpxchg_i32_seq_cst_monotonic (i32, i32, i32) -> (i32)
+; NO-ATOMICS-NEXT:    .local i32
+; NO-ATOMICS-NEXT:  # %bb.0:
+; NO-ATOMICS-NEXT:    local.get 0
+; NO-ATOMICS-NEXT:    local.get 2
+; NO-ATOMICS-NEXT:    local.get 0
+; NO-ATOMICS-NEXT:    i32.load 0
+; NO-ATOMICS-NEXT:    local.tee 3
+; NO-ATOMICS-NEXT:    local.get 3
+; NO-ATOMICS-NEXT:    local.get 1
+; NO-ATOMICS-NEXT:    i32.eq
+; NO-ATOMICS-NEXT:    i32.select
+; NO-ATOMICS-NEXT:    i32.store 0
+; NO-ATOMICS-NEXT:    local.get 3
+; NO-ATOMICS-NEXT:    # fallthrough-return
+;
+; ATOMICS-LABEL: cmpxchg_i32_seq_cst_monotonic:
+; ATOMICS:         .functype cmpxchg_i32_seq_cst_monotonic (i32, i32, i32) -> (i32)
+; ATOMICS-NEXT:  # %bb.0:
+; ATOMICS-NEXT:    local.get 0
+; ATOMICS-NEXT:    local.get 1
+; ATOMICS-NEXT:    local.get 2
+; ATOMICS-NEXT:    i32.atomic.rmw.cmpxchg 0
+; ATOMICS-NEXT:    # fallthrough-return
+;
+; RELAXED32-LABEL: cmpxchg_i32_seq_cst_monotonic:
+; RELAXED32:         .functype cmpxchg_i32_seq_cst_monotonic (i32, i32, i32) -> (i32)
+; RELAXED32-NEXT:  # %bb.0:
+; RELAXED32-NEXT:    local.get 0
+; RELAXED32-NEXT:    local.get 1
+; RELAXED32-NEXT:    local.get 2
+; RELAXED32-NEXT:    i32.atomic.rmw.cmpxchg seqcst 0
+; RELAXED32-NEXT:    # fallthrough-return
+;
+; RELAXED64-LABEL: cmpxchg_i32_seq_cst_monotonic:
+; RELAXED64:         .functype cmpxchg_i32_seq_cst_monotonic (i64, i32, i32) -> (i32)
+; RELAXED64-NEXT:  # %bb.0:
+; RELAXED64-NEXT:    local.get 0
+; RELAXED64-NEXT:    local.get 1
+; RELAXED64-NEXT:    local.get 2
+; RELAXED64-NEXT:    i32.atomic.rmw.cmpxchg seqcst 0
+; RELAXED64-NEXT:    # fallthrough-return
   %pair = cmpxchg ptr %p, i32 %exp, i32 %new seq_cst monotonic
   %old = extractvalue { i32, i1 } %pair, 0
   ret i32 %old
 }
 
-; CHECK-LABEL: cmpxchg_i32_acquire_acquire:
-; CHECK-NEXT: .functype cmpxchg_i32_acquire_acquire (i32, i32, i32) -> (i32){{$}}
-; CHECK: i32.atomic.rmw.cmpxchg $push0=, 0($0), $1, $2{{$}}
-; CHECK-NEXT: return $pop0{{$}}
 define i32 @cmpxchg_i32_acquire_acquire(ptr %p, i32 %exp, i32 %new) {
+; NO-ATOMICS-LABEL: cmpxchg_i32_acquire_acquire:
+; NO-ATOMICS:         .functype cmpxchg_i32_acquire_acquire (i32, i32, i32) -> (i32)
+; NO-ATOMICS-NEXT:    .local i32
+; NO-ATOMICS-NEXT:  # %bb.0:
+; NO-ATOMICS-NEXT:    local.get 0
+; NO-ATOMICS-NEXT:    local.get 2
+; NO-ATOMICS-NEXT:    local.get 0
+; NO-ATOMICS-NEXT:    i32.load 0
+; NO-ATOMICS-NEXT:    local.tee 3
+; NO-ATOMICS-NEXT:    local.get 3
+; NO-ATOMICS-NEXT:    local.get 1
+; NO-ATOMICS-NEXT:    i32.eq
+; NO-ATOMICS-NEXT:    i32.select
+; NO-ATOMICS-NEXT:    i32.store 0
+; NO-ATOMICS-NEXT:    local.get 3
+; NO-ATOMICS-NEXT:    # fallthrough-return
+;
+; ATOMICS-LABEL: cmpxchg_i32_acquire_acquire:
+; ATOMICS:         .functype cmpxchg_i32_acquire_acquire (i32, i32, i32) -> (i32)
+; ATOMICS-NEXT:  # %bb.0:
+; ATOMICS-NEXT:    local.get 0
+; ATOMICS-NEXT:    local.get 1
+; ATOMICS-NEXT:    local.get 2
+; ATOMICS-NEXT:    i32.atomic.rmw.cmpxchg 0
+; ATOMICS-NEXT:    # fallthrough-return
+;
+; RELAXED32-LABEL: cmpxchg_i32_acquire_acquire:
+; RELAXED32:         .functype cmpxchg_i32_acquire_acquire (i32, i32, i32) -> (i32)
+; RELAXED32-NEXT:  # %bb.0:
+; RELAXED32-NEXT:    local.get 0
+; RELAXED32-NEXT:    local.get 1
+; RELAXED32-NEXT:    local.get 2
+; RELAXED32-NEXT:    i32.atomic.rmw.cmpxchg acqrel 0
+; RELAXED32-NEXT:    # fallthrough-return
+;
+; RELAXED64-LABEL: cmpxchg_i32_acquire_acquire:
+; RELAXED64:         .functype cmpxchg_i32_acquire_acquire (i64, i32, i32) -> (i32)
+; RELAXED64-NEXT:  # %bb.0:
+; RELAXED64-NEXT:    local.get 0
+; RELAXED64-NEXT:    local.get 1
+; RELAXED64-NEXT:    local.get 2
+; RELAXED64-NEXT:    i32.atomic.rmw.cmpxchg acqrel 0
+; RELAXED64-NEXT:    # fallthrough-return
   %pair = cmpxchg ptr %p, i32 %exp, i32 %new acquire acquire
   %old = extractvalue { i32, i1 } %pair, 0
   ret i32 %old
 }
 
-; CHECK-LABEL: cmpxchg_i32_release_acquire:
-; CHECK-NEXT: .functype cmpxchg_i32_release_acquire (i32, i32, i32) -> (i32){{$}}
-; CHECK: i32.atomic.rmw.cmpxchg $push0=, 0($0), $1, $2{{$}}
-; CHECK-NEXT: return $pop0{{$}}
 define i32 @cmpxchg_i32_release_acquire(ptr %p, i32 %exp, i32 %new) {
+; NO-ATOMICS-LABEL: cmpxchg_i32_release_acquire:
+; NO-ATOMICS:         .functype cmpxchg_i32_release_acquire (i32, i32, i32) -> (i32)
+; NO-ATOMICS-NEXT:    .local i32
+; NO-ATOMICS-NEXT:  # %bb.0:
+; NO-ATOMICS-NEXT:    local.get 0
+; NO-ATOMICS-NEXT:    local.get 2
+; NO-ATOMICS-NEXT:    local.get 0
+; NO-ATOMICS-NEXT:    i32.load 0
+; NO-ATOMICS-NEXT:    local.tee 3
+; NO-ATOMICS-NEXT:    local.get 3
+; NO-ATOMICS-NEXT:    local.get 1
+; NO-ATOMICS-NEXT:    i32.eq
+; NO-ATOMICS-NEXT:    i32.select
+; NO-ATOMICS-NEXT:    i32.store 0
+; NO-ATOMICS-NEXT:    local.get 3
+; NO-ATOMICS-NEXT:    # fallthrough-return
+;
+; ATOMICS-LABEL: cmpxchg_i32_release_acquire:
+; ATOMICS:         .functype cmpxchg_i32_release_acquire (i32, i32, i32) -> (i32)
+; ATOMICS-NEXT:  # %bb.0:
+; ATOMICS-NEXT:    local.get 0
+; ATOMICS-NEXT:    local.get 1
+; ATOMICS-NEXT:    local.get 2
+; ATOMICS-NEXT:    i32.atomic.rmw.cmpxchg 0
+; ATOMICS-NEXT:    # fallthrough-return
+;
+; RELAXED32-LABEL: cmpxchg_i32_release_acquire:
+; RELAXED32:         .functype cmpxchg_i32_release_acquire (i32, i32, i32) -> (i32)
+; RELAXED32-NEXT:  # %bb.0:
+; RELAXED32-NEXT:    local.get 0
+; RELAXED32-NEXT:    local.get 1
+; RELAXED32-NEXT:    local.get 2
+; RELAXED32-NEXT:    i32.atomic.rmw.cmpxchg acqrel 0
+; RELAXED32-NEXT:    # fallthrough-return
+;
+; RELAXED64-LABEL: cmpxchg_i32_release_acquire:
+; RELAXED64:         .functype cmpxchg_i32_release_acquire (i64, i32, i32) -> (i32)
+; RELAXED64-NEXT:  # %bb.0:
+; RELAXED64-NEXT:    local.get 0
+; RELAXED64-NEXT:    local.get 1
+; RELAXED64-NEXT:    local.get 2
+; RELAXED64-NEXT:    i32.atomic.rmw.cmpxchg acqrel 0
+; RELAXED64-NEXT:    # fallthrough-return
   %pair = cmpxchg ptr %p, i32 %exp, i32 %new release acquire
   %old = extractvalue { i32, i1 } %pair, 0
   ret i32 %old
 }
 
-; CHECK-LABEL: cmpxchg_i32_acq_rel_acquire:
-; CHECK-NEXT: .functype cmpxchg_i32_acq_rel_acquire (i32, i32, i32) -> (i32){{$}}
-; CHECK: i32.atomic.rmw.cmpxchg $push0=, 0($0), $1, $2{{$}}
-; CHECK-NEXT: return $pop0{{$}}
 define i32 @cmpxchg_i32_acq_rel_acquire(ptr %p, i32 %exp, i32 %new) {
+; NO-ATOMICS-LABEL: cmpxchg_i32_acq_rel_acquire:
+; NO-ATOMICS:         .functype cmpxchg_i32_acq_rel_acquire (i32, i32, i32) -> (i32)
+; NO-ATOMICS-NEXT:    .local i32
+; NO-ATOMICS-NEXT:  # %bb.0:
+; NO-ATOMICS-NEXT:    local.get 0
+; NO-ATOMICS-NEXT:    local.get 2
+; NO-ATOMICS-NEXT:    local.get 0
+; NO-ATOMICS-NEXT:    i32.load 0
+; NO-ATOMICS-NEXT:    local.tee 3
+; NO-ATOMICS-NEXT:    local.get 3
+; NO-ATOMICS-NEXT:    local.get 1
+; NO-ATOMICS-NEXT:    i32.eq
+; NO-ATOMICS-NEXT:    i32.select
+; NO-ATOMICS-NEXT:    i32.store 0
+; NO-ATOMICS-NEXT:    local.get 3
+; NO-ATOMICS-NEXT:    # fallthrough-return
+;
+; ATOMICS-LABEL: cmpxchg_i32_acq_rel_acquire:
+; ATOMICS:         .functype cmpxchg_i32_acq_rel_acquire (i32, i32, i32) -> (i32)
+; ATOMICS-NEXT:  # %bb.0:
+; ATOMICS-NEXT:    local.get 0
+; ATOMICS-NEXT:    local.get 1
+; ATOMICS-NEXT:    local.get 2
+; ATOMICS-NEXT:    i32.atomic.rmw.cmpxchg 0
+; ATOMICS-NEXT:    # fallthrough-return
+;
+; RELAXED32-LABEL: cmpxchg_i32_acq_rel_acquire:
+; RELAXED32:         .functype cmpxchg_i32_acq_rel_acquire (i32, i32, i32) -> (i32)
+; RELAXED32-NEXT:  # %bb.0:
+; RELAXED32-NEXT:    local.get 0
+; RELAXED32-NEXT:    local.get 1
+; RELAXED32-NEXT:    local.get 2
+; RELAXED32-NEXT:    i32.atomic.rmw.cmpxchg acqrel 0
+; RELAXED32-NEXT:    # fallthrough-return
+;
+; RELAXED64-LABEL: cmpxchg_i32_acq_rel_acquire:
+; RELAXED64:         .functype cmpxchg_i32_acq_rel_acquire (i64, i32, i32) -> (i32)
+; RELAXED64-NEXT:  # %bb.0:
+; RELAXED64-NEXT:    local.get 0
+; RELAXED64-NEXT:    local.get 1
+; RELAXED64-NEXT:    local.get 2
+; RELAXED64-NEXT:    i32.atomic.rmw.cmpxchg acqrel 0
+; RELAXED64-NEXT:    # fallthrough-return
   %pair = cmpxchg ptr %p, i32 %exp, i32 %new acq_rel acquire
   %old = extractvalue { i32, i1 } %pair, 0
   ret i32 %old
@@ -230,16 +915,98 @@ define i32 @cmpxchg_i32_acq_rel_acquire(ptr %p, i32 %exp, i32 %new) {
 ; CHECK: i32.atomic.rmw.cmpxchg $push0=, 0($0), $1, $2{{$}}
 ; CHECK-NEXT: return $pop0{{$}}
 define i32 @cmpxchg_i32_seq_cst_acquire(ptr %p, i32 %exp, i32 %new) {
+; NO-ATOMICS-LABEL: cmpxchg_i32_seq_cst_acquire:
+; NO-ATOMICS:         .functype cmpxchg_i32_seq_cst_acquire (i32, i32, i32) -> (i32)
+; NO-ATOMICS-NEXT:    .local i32
+; NO-ATOMICS-NEXT:  # %bb.0:
+; NO-ATOMICS-NEXT:    local.get 0
+; NO-ATOMICS-NEXT:    local.get 2
+; NO-ATOMICS-NEXT:    local.get 0
+; NO-ATOMICS-NEXT:    i32.load 0
+; NO-ATOMICS-NEXT:    local.tee 3
+; NO-ATOMICS-NEXT:    local.get 3
+; NO-ATOMICS-NEXT:    local.get 1
+; NO-ATOMICS-NEXT:    i32.eq
+; NO-ATOMICS-NEXT:    i32.select
+; NO-ATOMICS-NEXT:    i32.store 0
+; NO-ATOMICS-NEXT:    local.get 3
+; NO-ATOMICS-NEXT:    # fallthrough-return
+;
+; ATOMICS-LABEL: cmpxchg_i32_seq_cst_acquire:
+; ATOMICS:         .functype cmpxchg_i32_seq_cst_acquire (i32, i32, i32) -> (i32)
+; ATOMICS-NEXT:  # %bb.0:
+; ATOMICS-NEXT:    local.get 0
+; ATOMICS-NEXT:    local.get 1
+; ATOMICS-NEXT:    local.get 2
+; ATOMICS-NEXT:    i32.atomic.rmw.cmpxchg 0
+; ATOMICS-NEXT:    # fallthrough-return
+;
+; RELAXED32-LABEL: cmpxchg_i32_seq_cst_acquire:
+; RELAXED32:         .functype cmpxchg_i32_seq_cst_acquire (i32, i32, i32) -> (i32)
+; RELAXED32-NEXT:  # %bb.0:
+; RELAXED32-NEXT:    local.get 0
+; RELAXED32-NEXT:    local.get 1
+; RELAXED32-NEXT:    local.get 2
+; RELAXED32-NEXT:    i32.atomic.rmw.cmpxchg seqcst 0
+; RELAXED32-NEXT:    # fallthrough-return
+;
+; RELAXED64-LABEL: cmpxchg_i32_seq_cst_acquire:
+; RELAXED64:         .functype cmpxchg_i32_seq_cst_acquire (i64, i32, i32) -> (i32)
+; RELAXED64-NEXT:  # %bb.0:
+; RELAXED64-NEXT:    local.get 0
+; RELAXED64-NEXT:    local.get 1
+; RELAXED64-NEXT:    local.get 2
+; RELAXED64-NEXT:    i32.atomic.rmw.cmpxchg seqcst 0
+; RELAXED64-NEXT:    # fallthrough-return
   %pair = cmpxchg ptr %p, i32 %exp, i32 %new seq_cst acquire
   %old = extractvalue { i32, i1 } %pair, 0
   ret i32 %old
 }
 
-; CHECK-LABEL: cmpxchg_i32_seq_cst_seq_cst:
-; CHECK-NEXT: .functype cmpxchg_i32_seq_cst_seq_cst (i32, i32, i32) -> (i32){{$}}
-; CHECK: i32.atomic.rmw.cmpxchg $push0=, 0($0), $1, $2{{$}}
-; CHECK-NEXT: return $pop0{{$}}
 define i32 @cmpxchg_i32_seq_cst_seq_cst(ptr %p, i32 %exp, i32 %new) {
+; NO-ATOMICS-LABEL: cmpxchg_i32_seq_cst_seq_cst:
+; NO-ATOMICS:         .functype cmpxchg_i32_seq_cst_seq_cst (i32, i32, i32) -> (i32)
+; NO-ATOMICS-NEXT:    .local i32
+; NO-ATOMICS-NEXT:  # %bb.0:
+; NO-ATOMICS-NEXT:    local.get 0
+; NO-ATOMICS-NEXT:    local.get 2
+; NO-ATOMICS-NEXT:    local.get 0
+; NO-ATOMICS-NEXT:    i32.load 0
+; NO-ATOMICS-NEXT:    local.tee 3
+; NO-ATOMICS-NEXT:    local.get 3
+; NO-ATOMICS-NEXT:    local.get 1
+; NO-ATOMICS-NEXT:    i32.eq
+; NO-ATOMICS-NEXT:    i32.select
+; NO-ATOMICS-NEXT:    i32.store 0
+; NO-ATOMICS-NEXT:    local.get 3
+; NO-ATOMICS-NEXT:    # fallthrough-return
+;
+; ATOMICS-LABEL: cmpxchg_i32_seq_cst_seq_cst:
+; ATOMICS:         .functype cmpxchg_i32_seq_cst_seq_cst (i32, i32, i32) -> (i32)
+; ATOMICS-NEXT:  # %bb.0:
+; ATOMICS-NEXT:    local.get 0
+; ATOMICS-NEXT:    local.get 1
+; ATOMICS-NEXT:    local.get 2
+; ATOMICS-NEXT:    i32.atomic.rmw.cmpxchg 0
+; ATOMICS-NEXT:    # fallthrough-return
+;
+; RELAXED32-LABEL: cmpxchg_i32_seq_cst_seq_cst:
+; RELAXED32:         .functype cmpxchg_i32_seq_cst_seq_cst (i32, i32, i32) -> (i32)
+; RELAXED32-NEXT:  # %bb.0:
+; RELAXED32-NEXT:    local.get 0
+; RELAXED32-NEXT:    local.get 1
+; RELAXED32-NEXT:    local.get 2
+; RELAXED32-NEXT:    i32.atomic.rmw.cmpxchg seqcst 0
+; RELAXED32-NEXT:    # fallthrough-return
+;
+; RELAXED64-LABEL: cmpxchg_i32_seq_cst_seq_cst:
+; RELAXED64:         .functype cmpxchg_i32_seq_cst_seq_cst (i64, i32, i32) -> (i32)
+; RELAXED64-NEXT:  # %bb.0:
+; RELAXED64-NEXT:    local.get 0
+; RELAXED64-NEXT:    local.get 1
+; RELAXED64-NEXT:    local.get 2
+; RELAXED64-NEXT:    i32.atomic.rmw.cmpxchg seqcst 0
+; RELAXED64-NEXT:    # fallthrough-return
   %pair = cmpxchg ptr %p, i32 %exp, i32 %new seq_cst seq_cst
   %old = extractvalue { i32, i1 } %pair, 0
   ret i32 %old
diff --git a/llvm/test/CodeGen/WebAssembly/atomics-orderings.ll b/llvm/test/CodeGen/WebAssembly/atomics-orderings.ll
deleted file mode 100644
index 3cc623c8c329d..0000000000000
--- a/llvm/test/CodeGen/WebAssembly/atomics-orderings.ll
+++ /dev/null
@@ -1,396 +0,0 @@
-; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 6
-; RUN: llc < %s --mtriple=wasm32 -mattr=+atomics,+relaxed-atomics | FileCheck %s --check-prefixes=WASM32
-; RUN: llc < %s --mtriple=wasm64 -mattr=+atomics,+relaxed-atomics | FileCheck %s --check-prefixes=WASM64
-
-define i32 @load_i32_acquire(ptr %p) {
-; WASM32-LABEL: load_i32_acquire:
-; WASM32:         .functype load_i32_acquire (i32) -> (i32)
-; WASM32-NEXT:  # %bb.0:
-; WASM32-NEXT:    local.get 0
-; WASM32-NEXT:    i32.atomic.load acqrel 0
-; WASM32-NEXT:    # fallthrough-return
-;
-; WASM64-LABEL: load_i32_acquire:
-; WASM64:         .functype load_i32_acquire (i64) -> (i32)
-; WASM64-NEXT:  # %bb.0:
-; WASM64-NEXT:    local.get 0
-; WASM64-NEXT:    i32.atomic.load acqrel 0
-; WASM64-NEXT:    # fallthrough-return
-  %v = load atomic i32, ptr %p acquire, align 4
-  ret i32 %v
-}
-
-define i32 @load_i32_seq_cst(ptr %p) {
-; WASM32-LABEL: load_i32_seq_cst:
-; WASM32:         .functype load_i32_seq_cst (i32) -> (i32)
-; WASM32-NEXT:  # %bb.0:
-; WASM32-NEXT:    local.get 0
-; WASM32-NEXT:    i32.atomic.load seqcst 0
-; WASM32-NEXT:    # fallthrough-return
-;
-; WASM64-LABEL: load_i32_seq_cst:
-; WASM64:         .functype load_i32_seq_cst (i64) -> (i32)
-; WASM64-NEXT:  # %bb.0:
-; WASM64-NEXT:    local.get 0
-; WASM64-NEXT:    i32.atomic.load seqcst 0
-; WASM64-NEXT:    # fallthrough-return
-  %v = load atomic i32, ptr %p seq_cst, align 4
-  ret i32 %v
-}
-
-define void @store_i32_release(ptr %p, i32 %v) {
-; WASM32-LABEL: store_i32_release:
-; WASM32:         .functype store_i32_release (i32, i32) -> ()
-; WASM32-NEXT:  # %bb.0:
-; WASM32-NEXT:    local.get 0
-; WASM32-NEXT:    local.get 1
-; WASM32-NEXT:    i32.atomic.store acqrel 0
-; WASM32-NEXT:    # fallthrough-return
-;
-; WASM64-LABEL: store_i32_release:
-; WASM64:         .functype store_i32_release (i64, i32) -> ()
-; WASM64-NEXT:  # %bb.0:
-; WASM64-NEXT:    local.get 0
-; WASM64-NEXT:    local.get 1
-; WASM64-NEXT:    i32.atomic.store acqrel 0
-; WASM64-NEXT:    # fallthrough-return
-  store atomic i32 %v, ptr %p release, align 4
-  ret void
-}
-
-define void @store_i32_seq_cst(ptr %p, i32 %v) {
-; WASM32-LABEL: store_i32_seq_cst:
-; WASM32:         .functype store_i32_seq_cst (i32, i32) -> ()
-; WASM32-NEXT:  # %bb.0:
-; WASM32-NEXT:    local.get 0
-; WASM32-NEXT:    local.get 1
-; WASM32-NEXT:    i32.atomic.store seqcst 0
-; WASM32-NEXT:    # fallthrough-return
-;
-; WASM64-LABEL: store_i32_seq_cst:
-; WASM64:         .functype store_i32_seq_cst (i64, i32) -> ()
-; WASM64-NEXT:  # %bb.0:
-; WASM64-NEXT:    local.get 0
-; WASM64-NEXT:    local.get 1
-; WASM64-NEXT:    i32.atomic.store seqcst 0
-; WASM64-NEXT:    # fallthrough-return
-  store atomic i32 %v, ptr %p seq_cst, align 4
-  ret void
-}
-
-define i32 @add_i32_acq_rel(ptr %p, i32 %v) {
-; WASM32-LABEL: add_i32_acq_rel:
-; WASM32:         .functype add_i32_acq_rel (i32, i32) -> (i32)
-; WASM32-NEXT:  # %bb.0:
-; WASM32-NEXT:    local.get 0
-; WASM32-NEXT:    local.get 1
-; WASM32-NEXT:    i32.atomic.rmw.add acqrel 0
-; WASM32-NEXT:    # fallthrough-return
-;
-; WASM64-LABEL: add_i32_acq_rel:
-; WASM64:         .functype add_i32_acq_rel (i64, i32) -> (i32)
-; WASM64-NEXT:  # %bb.0:
-; WASM64-NEXT:    local.get 0
-; WASM64-NEXT:    local.get 1
-; WASM64-NEXT:    i32.atomic.rmw.add acqrel 0
-; WASM64-NEXT:    # fallthrough-return
-  %old = atomicrmw add ptr %p, i32 %v acq_rel
-  ret i32 %old
-}
-
-define i32 @add_i32_seq_cst(ptr %p, i32 %v) {
-; WASM32-LABEL: add_i32_seq_cst:
-; WASM32:         .functype add_i32_seq_cst (i32, i32) -> (i32)
-; WASM32-NEXT:  # %bb.0:
-; WASM32-NEXT:    local.get 0
-; WASM32-NEXT:    local.get 1
-; WASM32-NEXT:    i32.atomic.rmw.add seqcst 0
-; WASM32-NEXT:    # fallthrough-return
-;
-; WASM64-LABEL: add_i32_seq_cst:
-; WASM64:         .functype add_i32_seq_cst (i64, i32) -> (i32)
-; WASM64-NEXT:  # %bb.0:
-; WASM64-NEXT:    local.get 0
-; WASM64-NEXT:    local.get 1
-; WASM64-NEXT:    i32.atomic.rmw.add seqcst 0
-; WASM64-NEXT:    # fallthrough-return
-  %old = atomicrmw add ptr %p, i32 %v seq_cst
-  ret i32 %old
-}
-
-define i32 @cmpxchg_i32_acquire_acquire(ptr %p, i32 %exp, i32 %new) {
-; WASM32-LABEL: cmpxchg_i32_acquire_acquire:
-; WASM32:         .functype cmpxchg_i32_acquire_acquire (i32, i32, i32) -> (i32)
-; WASM32-NEXT:  # %bb.0:
-; WASM32-NEXT:    local.get 0
-; WASM32-NEXT:    local.get 1
-; WASM32-NEXT:    local.get 2
-; WASM32-NEXT:    i32.atomic.rmw.cmpxchg acqrel 0
-; WASM32-NEXT:    # fallthrough-return
-;
-; WASM64-LABEL: cmpxchg_i32_acquire_acquire:
-; WASM64:         .functype cmpxchg_i32_acquire_acquire (i64, i32, i32) -> (i32)
-; WASM64-NEXT:  # %bb.0:
-; WASM64-NEXT:    local.get 0
-; WASM64-NEXT:    local.get 1
-; WASM64-NEXT:    local.get 2
-; WASM64-NEXT:    i32.atomic.rmw.cmpxchg acqrel 0
-; WASM64-NEXT:    # fallthrough-return
-  %pair = cmpxchg ptr %p, i32 %exp, i32 %new acquire acquire
-  %val = extractvalue { i32, i1 } %pair, 0
-  ret i32 %val
-}
-
-define i32 @cmpxchg_i32_seq_cst_seq_cst(ptr %p, i32 %exp, i32 %new) {
-; WASM32-LABEL: cmpxchg_i32_seq_cst_seq_cst:
-; WASM32:         .functype cmpxchg_i32_seq_cst_seq_cst (i32, i32, i32) -> (i32)
-; WASM32-NEXT:  # %bb.0:
-; WASM32-NEXT:    local.get 0
-; WASM32-NEXT:    local.get 1
-; WASM32-NEXT:    local.get 2
-; WASM32-NEXT:    i32.atomic.rmw.cmpxchg seqcst 0
-; WASM32-NEXT:    # fallthrough-return
-;
-; WASM64-LABEL: cmpxchg_i32_seq_cst_seq_cst:
-; WASM64:         .functype cmpxchg_i32_seq_cst_seq_cst (i64, i32, i32) -> (i32)
-; WASM64-NEXT:  # %bb.0:
-; WASM64-NEXT:    local.get 0
-; WASM64-NEXT:    local.get 1
-; WASM64-NEXT:    local.get 2
-; WASM64-NEXT:    i32.atomic.rmw.cmpxchg seqcst 0
-; WASM64-NEXT:    # fallthrough-return
-  %pair = cmpxchg ptr %p, i32 %exp, i32 %new seq_cst seq_cst
-  %val = extractvalue { i32, i1 } %pair, 0
-  ret i32 %val
-}
-
-define void @fence_acquire() {
-; WASM32-LABEL: fence_acquire:
-; WASM32:         .functype fence_acquire () -> ()
-; WASM32-NEXT:  # %bb.0:
-; WASM32-NEXT:    atomic.fence acqrel
-; WASM32-NEXT:    # fallthrough-return
-;
-; WASM64-LABEL: fence_acquire:
-; WASM64:         .functype fence_acquire () -> ()
-; WASM64-NEXT:  # %bb.0:
-; WASM64-NEXT:    atomic.fence acqrel
-; WASM64-NEXT:    # fallthrough-return
-  fence acquire
-  ret void
-}
-
-define void @fence_seq_cst() {
-; WASM32-LABEL: fence_seq_cst:
-; WASM32:         .functype fence_seq_cst () -> ()
-; WASM32-NEXT:  # %bb.0:
-; WASM32-NEXT:    atomic.fence seqcst
-; WASM32-NEXT:    # fallthrough-return
-;
-; WASM64-LABEL: fence_seq_cst:
-; WASM64:         .functype fence_seq_cst () -> ()
-; WASM64-NEXT:  # %bb.0:
-; WASM64-NEXT:    atomic.fence seqcst
-; WASM64-NEXT:    # fallthrough-return
-  fence seq_cst
-  ret void
-}
-
-define i32 @load_i32_monotonic(ptr %p) {
-; WASM32-LABEL: load_i32_monotonic:
-; WASM32:         .functype load_i32_monotonic (i32) -> (i32)
-; WASM32-NEXT:  # %bb.0:
-; WASM32-NEXT:    local.get 0
-; WASM32-NEXT:    i32.atomic.load acqrel 0
-; WASM32-NEXT:    # fallthrough-return
-;
-; WASM64-LABEL: load_i32_monotonic:
-; WASM64:         .functype load_i32_monotonic (i64) -> (i32)
-; WASM64-NEXT:  # %bb.0:
-; WASM64-NEXT:    local.get 0
-; WASM64-NEXT:    i32.atomic.load acqrel 0
-; WASM64-NEXT:    # fallthrough-return
-  %v = load atomic i32, ptr %p monotonic, align 4
-  ret i32 %v
-}
-
-define void @store_i32_monotonic(ptr %p, i32 %v) {
-; WASM32-LABEL: store_i32_monotonic:
-; WASM32:         .functype store_i32_monotonic (i32, i32) -> ()
-; WASM32-NEXT:  # %bb.0:
-; WASM32-NEXT:    local.get 0
-; WASM32-NEXT:    local.get 1
-; WASM32-NEXT:    i32.atomic.store acqrel 0
-; WASM32-NEXT:    # fallthrough-return
-;
-; WASM64-LABEL: store_i32_monotonic:
-; WASM64:         .functype store_i32_monotonic (i64, i32) -> ()
-; WASM64-NEXT:  # %bb.0:
-; WASM64-NEXT:    local.get 0
-; WASM64-NEXT:    local.get 1
-; WASM64-NEXT:    i32.atomic.store acqrel 0
-; WASM64-NEXT:    # fallthrough-return
-  store atomic i32 %v, ptr %p monotonic, align 4
-  ret void
-}
-
-define i32 @add_i32_release(ptr %p, i32 %v) {
-; WASM32-LABEL: add_i32_release:
-; WASM32:         .functype add_i32_release (i32, i32) -> (i32)
-; WASM32-NEXT:  # %bb.0:
-; WASM32-NEXT:    local.get 0
-; WASM32-NEXT:    local.get 1
-; WASM32-NEXT:    i32.atomic.rmw.add acqrel 0
-; WASM32-NEXT:    # fallthrough-return
-;
-; WASM64-LABEL: add_i32_release:
-; WASM64:         .functype add_i32_release (i64, i32) -> (i32)
-; WASM64-NEXT:  # %bb.0:
-; WASM64-NEXT:    local.get 0
-; WASM64-NEXT:    local.get 1
-; WASM64-NEXT:    i32.atomic.rmw.add acqrel 0
-; WASM64-NEXT:    # fallthrough-return
-  %old = atomicrmw add ptr %p, i32 %v release
-  ret i32 %old
-}
-
-define i32 @add_i32_acquire(ptr %p, i32 %v) {
-; WASM32-LABEL: add_i32_acquire:
-; WASM32:         .functype add_i32_acquire (i32, i32) -> (i32)
-; WASM32-NEXT:  # %bb.0:
-; WASM32-NEXT:    local.get 0
-; WASM32-NEXT:    local.get 1
-; WASM32-NEXT:    i32.atomic.rmw.add acqrel 0
-; WASM32-NEXT:    # fallthrough-return
-;
-; WASM64-LABEL: add_i32_acquire:
-; WASM64:         .functype add_i32_acquire (i64, i32) -> (i32)
-; WASM64-NEXT:  # %bb.0:
-; WASM64-NEXT:    local.get 0
-; WASM64-NEXT:    local.get 1
-; WASM64-NEXT:    i32.atomic.rmw.add acqrel 0
-; WASM64-NEXT:    # fallthrough-return
-  %old = atomicrmw add ptr %p, i32 %v acquire
-  ret i32 %old
-}
-
-define i32 @add_i32_monotonic(ptr %p, i32 %v) {
-; WASM32-LABEL: add_i32_monotonic:
-; WASM32:         .functype add_i32_monotonic (i32, i32) -> (i32)
-; WASM32-NEXT:  # %bb.0:
-; WASM32-NEXT:    local.get 0
-; WASM32-NEXT:    local.get 1
-; WASM32-NEXT:    i32.atomic.rmw.add acqrel 0
-; WASM32-NEXT:    # fallthrough-return
-;
-; WASM64-LABEL: add_i32_monotonic:
-; WASM64:         .functype add_i32_monotonic (i64, i32) -> (i32)
-; WASM64-NEXT:  # %bb.0:
-; WASM64-NEXT:    local.get 0
-; WASM64-NEXT:    local.get 1
-; WASM64-NEXT:    i32.atomic.rmw.add acqrel 0
-; WASM64-NEXT:    # fallthrough-return
-  %old = atomicrmw add ptr %p, i32 %v monotonic
-  ret i32 %old
-}
-
-define i32 @cmpxchg_i32_acq_rel_monotonic(ptr %p, i32 %exp, i32 %new) {
-; WASM32-LABEL: cmpxchg_i32_acq_rel_monotonic:
-; WASM32:         .functype cmpxchg_i32_acq_rel_monotonic (i32, i32, i32) -> (i32)
-; WASM32-NEXT:  # %bb.0:
-; WASM32-NEXT:    local.get 0
-; WASM32-NEXT:    local.get 1
-; WASM32-NEXT:    local.get 2
-; WASM32-NEXT:    i32.atomic.rmw.cmpxchg acqrel 0
-; WASM32-NEXT:    # fallthrough-return
-;
-; WASM64-LABEL: cmpxchg_i32_acq_rel_monotonic:
-; WASM64:         .functype cmpxchg_i32_acq_rel_monotonic (i64, i32, i32) -> (i32)
-; WASM64-NEXT:  # %bb.0:
-; WASM64-NEXT:    local.get 0
-; WASM64-NEXT:    local.get 1
-; WASM64-NEXT:    local.get 2
-; WASM64-NEXT:    i32.atomic.rmw.cmpxchg acqrel 0
-; WASM64-NEXT:    # fallthrough-return
-  %pair = cmpxchg ptr %p, i32 %exp, i32 %new acq_rel monotonic
-  %val = extractvalue { i32, i1 } %pair, 0
-  ret i32 %val
-}
-
-define i32 @cmpxchg_i32_release_monotonic(ptr %p, i32 %exp, i32 %new) {
-; WASM32-LABEL: cmpxchg_i32_release_monotonic:
-; WASM32:         .functype cmpxchg_i32_release_monotonic (i32, i32, i32) -> (i32)
-; WASM32-NEXT:  # %bb.0:
-; WASM32-NEXT:    local.get 0
-; WASM32-NEXT:    local.get 1
-; WASM32-NEXT:    local.get 2
-; WASM32-NEXT:    i32.atomic.rmw.cmpxchg acqrel 0
-; WASM32-NEXT:    # fallthrough-return
-;
-; WASM64-LABEL: cmpxchg_i32_release_monotonic:
-; WASM64:         .functype cmpxchg_i32_release_monotonic (i64, i32, i32) -> (i32)
-; WASM64-NEXT:  # %bb.0:
-; WASM64-NEXT:    local.get 0
-; WASM64-NEXT:    local.get 1
-; WASM64-NEXT:    local.get 2
-; WASM64-NEXT:    i32.atomic.rmw.cmpxchg acqrel 0
-; WASM64-NEXT:    # fallthrough-return
-  %pair = cmpxchg ptr %p, i32 %exp, i32 %new release monotonic
-  %val = extractvalue { i32, i1 } %pair, 0
-  ret i32 %val
-}
-
-define i32 @cmpxchg_i32_monotonic_monotonic(ptr %p, i32 %exp, i32 %new) {
-; WASM32-LABEL: cmpxchg_i32_monotonic_monotonic:
-; WASM32:         .functype cmpxchg_i32_monotonic_monotonic (i32, i32, i32) -> (i32)
-; WASM32-NEXT:  # %bb.0:
-; WASM32-NEXT:    local.get 0
-; WASM32-NEXT:    local.get 1
-; WASM32-NEXT:    local.get 2
-; WASM32-NEXT:    i32.atomic.rmw.cmpxchg acqrel 0
-; WASM32-NEXT:    # fallthrough-return
-;
-; WASM64-LABEL: cmpxchg_i32_monotonic_monotonic:
-; WASM64:         .functype cmpxchg_i32_monotonic_monotonic (i64, i32, i32) -> (i32)
-; WASM64-NEXT:  # %bb.0:
-; WASM64-NEXT:    local.get 0
-; WASM64-NEXT:    local.get 1
-; WASM64-NEXT:    local.get 2
-; WASM64-NEXT:    i32.atomic.rmw.cmpxchg acqrel 0
-; WASM64-NEXT:    # fallthrough-return
-  %pair = cmpxchg ptr %p, i32 %exp, i32 %new monotonic monotonic
-  %val = extractvalue { i32, i1 } %pair, 0
-  ret i32 %val
-}
-
-define void @fence_release() {
-; WASM32-LABEL: fence_release:
-; WASM32:         .functype fence_release () -> ()
-; WASM32-NEXT:  # %bb.0:
-; WASM32-NEXT:    atomic.fence acqrel
-; WASM32-NEXT:    # fallthrough-return
-;
-; WASM64-LABEL: fence_release:
-; WASM64:         .functype fence_release () -> ()
-; WASM64-NEXT:  # %bb.0:
-; WASM64-NEXT:    atomic.fence acqrel
-; WASM64-NEXT:    # fallthrough-return
-  fence release
-  ret void
-}
-
-define void @fence_acq_rel() {
-; WASM32-LABEL: fence_acq_rel:
-; WASM32:         .functype fence_acq_rel () -> ()
-; WASM32-NEXT:  # %bb.0:
-; WASM32-NEXT:    atomic.fence acqrel
-; WASM32-NEXT:    # fallthrough-return
-;
-; WASM64-LABEL: fence_acq_rel:
-; WASM64:         .functype fence_acq_rel () -> ()
-; WASM64-NEXT:  # %bb.0:
-; WASM64-NEXT:    atomic.fence acqrel
-; WASM64-NEXT:    # fallthrough-return
-  fence acq_rel
-  ret void
-}



More information about the cfe-commits mailing list