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

Derek Schuff via cfe-commits cfe-commits at lists.llvm.org
Wed Mar 11 09:47:29 PDT 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 01/11] [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 02/11] 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 03/11] 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 04/11] 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 05/11] 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 06/11] 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 07/11] 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 08/11] 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 09/11] 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
-}

>From 4cb5c14210964928121e3986076bf87d98026279 Mon Sep 17 00:00:00 2001
From: Derek Schuff <dschuff at chromium.org>
Date: Fri, 6 Mar 2026 22:55:35 +0000
Subject: [PATCH 10/11] Switch to DAG selection for ordering

Add some missing atomic offset tests
---
 llvm/lib/Target/WebAssembly/CMakeLists.txt    |   1 -
 llvm/lib/Target/WebAssembly/WebAssembly.h     |   2 -
 .../WebAssembly/WebAssemblyFixupAtomics.cpp   | 100 ------------------
 .../WebAssembly/WebAssemblyISelDAGToDAG.cpp   |  98 ++++++++++++++---
 .../WebAssembly/WebAssemblyInstrAtomics.td    |  45 ++++----
 .../WebAssembly/WebAssemblyTargetMachine.cpp  |   4 +-
 .../GlobalISel/gisel-commandline-option.ll    |   2 -
 .../CodeGen/WebAssembly/offset-atomics.ll     |  33 ++++++
 8 files changed, 143 insertions(+), 142 deletions(-)
 delete 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 8cbabcd15968c..1ad99f7e468df 100644
--- a/llvm/lib/Target/WebAssembly/CMakeLists.txt
+++ b/llvm/lib/Target/WebAssembly/CMakeLists.txt
@@ -67,7 +67,6 @@ 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 0c5622f502a5c..71647974b2843 100644
--- a/llvm/lib/Target/WebAssembly/WebAssembly.h
+++ b/llvm/lib/Target/WebAssembly/WebAssembly.h
@@ -52,7 +52,6 @@ FunctionPass *createWebAssemblyISelDag(WebAssemblyTargetMachine &TM,
                                        CodeGenOptLevel OptLevel);
 FunctionPass *createWebAssemblyArgumentMove();
 FunctionPass *createWebAssemblySetP2AlignOperands();
-FunctionPass *createWebAssemblyFixupAtomics();
 FunctionPass *createWebAssemblyCleanCodeAfterTrap();
 
 // Late passes.
@@ -104,7 +103,6 @@ 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
deleted file mode 100644
index 7730175d1b185..0000000000000
--- a/llvm/lib/Target/WebAssembly/WebAssemblyFixupAtomics.cpp
+++ /dev/null
@@ -1,100 +0,0 @@
-//===-- 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.
-///
-/// 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, later MI passes should still use getMergedOrdering()
-/// on the MachineMemOperand to get the ordering rather 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"
-
-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;
-  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 &&
-            // 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::Unordered:
-          case AtomicOrdering::Monotonic:
-          case AtomicOrdering::Acquire:
-          case AtomicOrdering::Release:
-          case AtomicOrdering::AcquireRelease:
-            Order = wasm::WASM_MEM_ORDER_ACQ_REL;
-            break;
-          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);
-            Changed = true;
-          }
-        }
-      }
-    }
-  }
-
-  return Changed;
-}
diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyISelDAGToDAG.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyISelDAGToDAG.cpp
index e7c8e1776a7de..4a63be7ce9e34 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblyISelDAGToDAG.cpp
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyISelDAGToDAG.cpp
@@ -16,6 +16,7 @@
 #include "WebAssemblyISelLowering.h"
 #include "WebAssemblyTargetMachine.h"
 #include "WebAssemblyUtilities.h"
+#include "llvm/BinaryFormat/Wasm.h"
 #include "llvm/CodeGen/MachineFrameInfo.h"
 #include "llvm/CodeGen/SelectionDAGISel.h"
 #include "llvm/CodeGen/WasmEHFuncInfo.h"
@@ -69,6 +70,12 @@ class WebAssemblyDAGToDAGISel final : public SelectionDAGISel {
 
   bool SelectAddrOperands32(SDValue Op, SDValue &Offset, SDValue &Addr);
   bool SelectAddrOperands64(SDValue Op, SDValue &Offset, SDValue &Addr);
+  bool SelectAtomicAddrOperands(SDNode *Op, SDValue N, SDValue &Offset,
+                                SDValue &Addr, SDValue &Order, bool Is64);
+  bool SelectAtomicAddrOperands32(SDNode *Op, SDValue N, SDValue &Offset,
+                                  SDValue &Addr, SDValue &Order);
+  bool SelectAtomicAddrOperands64(SDNode *Op, SDValue N, SDValue &Offset,
+                                  SDValue &Addr, SDValue &Order);
 
 // Include the pieces autogenerated from the target description.
 #include "WebAssemblyGenDAGISel.inc"
@@ -174,6 +181,25 @@ static APInt encodeFunctionSignature(SelectionDAG *DAG, SDLoc &DL,
   return Sig;
 }
 
+static unsigned getWebAssemblyMemoryOrder(AtomicOrdering Ordering) {
+  unsigned OrderVal = wasm::WASM_MEM_ORDER_SEQ_CST;
+  switch (Ordering) {
+  case AtomicOrdering::Unordered:
+  case AtomicOrdering::Monotonic:
+  case AtomicOrdering::Acquire:
+  case AtomicOrdering::Release:
+  case AtomicOrdering::AcquireRelease:
+    OrderVal = wasm::WASM_MEM_ORDER_ACQ_REL;
+    break;
+  case AtomicOrdering::SequentiallyConsistent:
+    OrderVal = wasm::WASM_MEM_ORDER_SEQ_CST;
+    break;
+  default:
+    llvm_unreachable("Invalid atomic ordering");
+  }
+  return OrderVal;
+}
+
 void WebAssemblyDAGToDAGISel::Select(SDNode *Node) {
   // If we have a custom node, we already have selected!
   if (Node->isMachineOpcode()) {
@@ -211,18 +237,7 @@ void WebAssemblyDAGToDAGISel::Select(SDNode *Node) {
       if (MF.getSubtarget<WebAssemblySubtarget>().hasRelaxedAtomics()) {
         auto Ordering =
             static_cast<AtomicOrdering>(Node->getConstantOperandVal(1));
-        switch (Ordering) {
-        case AtomicOrdering::Acquire:
-        case AtomicOrdering::Release:
-        case AtomicOrdering::AcquireRelease:
-          Order = wasm::WASM_MEM_ORDER_ACQ_REL;
-          break;
-        case AtomicOrdering::SequentiallyConsistent:
-          Order = wasm::WASM_MEM_ORDER_SEQ_CST;
-          break;
-        default:
-          llvm_unreachable("Invalid ordering for atomic fence");
-        }
+        Order = getWebAssemblyMemoryOrder(Ordering);
       }
       Fence = CurDAG->getMachineNode(
           WebAssembly::ATOMIC_FENCE,
@@ -563,6 +578,65 @@ bool WebAssemblyDAGToDAGISel::SelectAddrOperands64(SDValue Op, SDValue &Offset,
   return SelectAddrOperands(MVT::i64, WebAssembly::CONST_I64, Op, Offset, Addr);
 }
 
+static MemSDNode *findMemSDNode(SDNode *N) {
+  while (N) {
+    if (auto *MemNode = dyn_cast<MemSDNode>(N))
+      return MemNode;
+    switch (N->getOpcode()) {
+    case ISD::ZERO_EXTEND:
+    case ISD::SIGN_EXTEND:
+    case ISD::ANY_EXTEND:
+    case ISD::SIGN_EXTEND_INREG:
+    case ISD::AssertZext:
+    case ISD::AssertSext:
+    case ISD::TRUNCATE:
+    case ISD::BITCAST:
+    case ISD::AND:
+      N = N->getOperand(0).getNode();
+      break;
+    default:
+      return nullptr;
+    }
+  }
+  return nullptr;
+}
+
+bool WebAssemblyDAGToDAGISel::SelectAtomicAddrOperands(SDNode *Op, SDValue N,
+                                                       SDValue &Offset,
+                                                       SDValue &Addr,
+                                                       SDValue &Order,
+                                                       bool Is64) {
+  auto *MemNode = findMemSDNode(Op);
+  if (!MemNode)
+    return false;
+
+  bool Match = Is64 ? SelectAddrOperands64(N, Offset, Addr)
+                    : SelectAddrOperands32(N, Offset, Addr);
+  if (!Match)
+    return false;
+
+  auto Ordering = MemNode->getMergedOrdering();
+  unsigned OrderVal = wasm::WASM_MEM_ORDER_SEQ_CST;
+  if (Subtarget->hasRelaxedAtomics())
+    OrderVal = getWebAssemblyMemoryOrder(Ordering);
+  Order = CurDAG->getTargetConstant(OrderVal, SDLoc(Op), MVT::i32);
+  return true;
+}
+
+bool WebAssemblyDAGToDAGISel::SelectAtomicAddrOperands32(SDNode *Op, SDValue N,
+                                                         SDValue &Offset,
+                                                         SDValue &Addr,
+                                                         SDValue &Order) {
+  return SelectAtomicAddrOperands(Op, N, Offset, Addr, Order, /*Is64=*/false);
+}
+
+bool WebAssemblyDAGToDAGISel::SelectAtomicAddrOperands64(SDNode *Op, SDValue N,
+                                                         SDValue &Offset,
+                                                         SDValue &Addr,
+                                                         SDValue &Order) {
+  return SelectAtomicAddrOperands(Op, N, Offset, Addr, Order, /*Is64=*/true);
+}
+
 /// This pass converts a legalized DAG into a WebAssembly-specific DAG, ready
 /// for instruction scheduling.
 FunctionPass *llvm::createWebAssemblyISelDag(WebAssemblyTargetMachine &TM,
diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyInstrAtomics.td b/llvm/lib/Target/WebAssembly/WebAssemblyInstrAtomics.td
index c10c8805f8c54..4e47abd733778 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblyInstrAtomics.td
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyInstrAtomics.td
@@ -11,6 +11,13 @@
 ///
 //===----------------------------------------------------------------------===//
 
+def AtomicAddrOps32 : ComplexPattern<i32, 3, "SelectAtomicAddrOperands32"> {
+  let WantsRoot = 1;
+}
+def AtomicAddrOps64 : ComplexPattern<i64, 3, "SelectAtomicAddrOperands64"> {
+  let WantsRoot = 1;
+}
+
 let UseNamedOperandTable = 1 in
 multiclass ATOMIC_I<dag oops_r, dag iops_r, dag oops_s, dag iops_s,
                     list<dag> pattern_r, string asmstr_r,
@@ -150,11 +157,11 @@ multiclass AtomicLoad<WebAssemblyRegClass rc, string name, int atomic_op> {
 }
 
 multiclass AtomicLoadPat<ValueType ty, SDPatternOperator kind, string Name> {
-  def : Pat<(ty (kind (AddrOps32 offset32_op:$offset, I32:$addr))),
-            (!cast<NI>(Name # "_A32") 0, 0, offset32_op:$offset, I32:$addr)>,
+  def : Pat<(ty (kind (AtomicAddrOps32 offset32_op:$offset, I32:$addr, i32imm:$order))),
+            (!cast<NI>(Name # "_A32") $order, 0, offset32_op:$offset, I32:$addr)>,
         Requires<[HasAddr32, HasAtomics]>;
-  def : Pat<(ty (kind (AddrOps64 offset64_op:$offset, I64:$addr))),
-            (!cast<NI>(Name # "_A64") 0, 0, offset64_op:$offset, I64:$addr)>,
+  def : Pat<(ty (kind (AtomicAddrOps64 offset64_op:$offset, I64:$addr, i32imm:$order))),
+            (!cast<NI>(Name # "_A64") $order, 0, offset64_op:$offset, I64:$addr)>,
         Requires<[HasAddr64, HasAtomics]>;
 }
 
@@ -245,18 +252,12 @@ multiclass AtomicStore<WebAssemblyRegClass rc, string name, int atomic_op> {
 defm ATOMIC_STORE_I32 : AtomicStore<I32, "i32.atomic.store", 0x17>;
 defm ATOMIC_STORE_I64 : AtomicStore<I64, "i64.atomic.store", 0x18>;
 
-// We used to need an 'atomic' version of store patterns because store and atomic_store
-// nodes have different operand orders.
-//
-// TODO: This is no longer true and atomic_store and store patterns
-// can be unified.
-
 multiclass AStorePat<ValueType ty, PatFrag kind, string inst> {
-  def : Pat<(kind ty:$val, (AddrOps32 offset32_op:$offset, I32:$addr)),
-            (!cast<NI>(inst#_A32) 0, 0, $offset, $addr, $val)>,
+  def : Pat<(kind ty:$val, (AtomicAddrOps32 offset32_op:$offset, I32:$addr, i32imm:$order)),
+            (!cast<NI>(inst#_A32) $order, 0, $offset, $addr, $val)>,
         Requires<[HasAddr32, HasAtomics]>;
-  def : Pat<(kind ty:$val, (AddrOps64 offset64_op:$offset, I64:$addr)),
-            (!cast<NI>(inst#_A64) 0, 0, $offset, $addr, $val)>,
+  def : Pat<(kind ty:$val, (AtomicAddrOps64 offset64_op:$offset, I64:$addr, i32imm:$order)),
+            (!cast<NI>(inst#_A64) $order, 0, $offset, $addr, $val)>,
         Requires<[HasAddr64, HasAtomics]>;
 }
 defm : AStorePat<i32, atomic_store_32, "ATOMIC_STORE_I32">;
@@ -393,11 +394,11 @@ defm ATOMIC_RMW32_U_XCHG_I64 :
   WebAssemblyBinRMW<I64, "i64.atomic.rmw32.xchg_u", 0x47>;
 
 multiclass BinRMWPat<ValueType ty, PatFrag kind, string inst> {
-  def : Pat<(ty (kind (AddrOps32 offset32_op:$offset, I32:$addr), ty:$val)),
-            (!cast<NI>(inst#_A32) 0, 0, $offset, $addr, $val)>,
+  def : Pat<(ty (kind (AtomicAddrOps32 offset32_op:$offset, I32:$addr, i32imm:$order), ty:$val)),
+            (!cast<NI>(inst#_A32) $order, 0, $offset, $addr, $val)>,
         Requires<[HasAddr32, HasAtomics]>;
-  def : Pat<(ty (kind (AddrOps64 offset64_op:$offset, I64:$addr), ty:$val)),
-            (!cast<NI>(inst#_A64) 0, 0, $offset, $addr, $val)>,
+  def : Pat<(ty (kind (AtomicAddrOps64 offset64_op:$offset, I64:$addr, i32imm:$order), ty:$val)),
+            (!cast<NI>(inst#_A64) $order, 0, $offset, $addr, $val)>,
         Requires<[HasAddr64, HasAtomics]>;
 }
 
@@ -536,11 +537,11 @@ defm ATOMIC_RMW32_U_CMPXCHG_I64 :
   WebAssemblyTerRMW<I64, "i64.atomic.rmw32.cmpxchg_u", 0x4e>;
 
 multiclass TerRMWPat<ValueType ty, PatFrag kind, string inst> {
-  def : Pat<(ty (kind (AddrOps32 offset32_op:$offset, I32:$addr), ty:$exp, ty:$new)),
-            (!cast<NI>(inst#_A32) 0, 0, $offset, $addr, $exp, $new)>,
+  def : Pat<(ty (kind (AtomicAddrOps32 offset32_op:$offset, I32:$addr, i32imm:$order), ty:$exp, ty:$new)),
+            (!cast<NI>(inst#_A32) $order, 0, $offset, $addr, $exp, $new)>,
         Requires<[HasAddr32, HasAtomics]>;
-  def : Pat<(ty (kind (AddrOps64 offset64_op:$offset, I64:$addr), ty:$exp, ty:$new)),
-            (!cast<NI>(inst#_A64) 0, 0, $offset, $addr, $exp, $new)>,
+  def : Pat<(ty (kind (AtomicAddrOps64 offset64_op:$offset, I64:$addr, i32imm:$order), ty:$exp, ty:$new)),
+            (!cast<NI>(inst#_A64) $order, 0, $offset, $addr, $exp, $new)>,
         Requires<[HasAddr64, HasAtomics]>;
 }
 
diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp
index cb2ea6bf4b6fb..dce8f54409c41 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp
@@ -108,7 +108,6 @@ LLVMInitializeWebAssemblyTarget() {
   initializeWebAssemblyArgumentMovePass(PR);
   initializeWebAssemblyAsmPrinterPass(PR);
   initializeWebAssemblySetP2AlignOperandsPass(PR);
-  initializeWebAssemblyFixupAtomicsPass(PR);
   initializeWebAssemblyReplacePhysRegsPass(PR);
   initializeWebAssemblyOptimizeLiveIntervalsPass(PR);
   initializeWebAssemblyMemIntrinsicResultsPass(PR);
@@ -552,7 +551,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());
 
@@ -714,7 +713,6 @@ bool WebAssemblyPassConfig::addGlobalInstructionSelect() {
   if (isGlobalISelAbortEnabled()) {
     addPass(createWebAssemblyArgumentMove());
     addPass(createWebAssemblySetP2AlignOperands());
-    addPass(createWebAssemblyFixupAtomics());
     addPass(createWebAssemblyFixBrTableDefaults());
     addPass(createWebAssemblyCleanCodeAfterTrap());
   }
diff --git a/llvm/test/CodeGen/WebAssembly/GlobalISel/gisel-commandline-option.ll b/llvm/test/CodeGen/WebAssembly/GlobalISel/gisel-commandline-option.ll
index 1389591a34ed6..47b05c8160fd1 100644
--- a/llvm/test/CodeGen/WebAssembly/GlobalISel/gisel-commandline-option.ll
+++ b/llvm/test/CodeGen/WebAssembly/GlobalISel/gisel-commandline-option.ll
@@ -31,7 +31,6 @@
 ; 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
@@ -39,7 +38,6 @@
 ; 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
 
diff --git a/llvm/test/CodeGen/WebAssembly/offset-atomics.ll b/llvm/test/CodeGen/WebAssembly/offset-atomics.ll
index 466b82e982c30..c391138d9b0a2 100644
--- a/llvm/test/CodeGen/WebAssembly/offset-atomics.ll
+++ b/llvm/test/CodeGen/WebAssembly/offset-atomics.ll
@@ -41,6 +41,26 @@ define i32 @load_i32_with_folded_gep_offset(ptr %p) {
   ret i32 %t
 }
 
+; Same for nusw.
+
+; CHECK-LABEL: load_i32_with_folded_gep_offset_nusw:
+; CHECK: i32.atomic.load  $push0=, 24($0){{$}}
+define i32 @load_i32_with_folded_gep_offset_nusw(ptr %p) {
+  %s = getelementptr nusw i32, ptr %p, i32 6
+  %t = load atomic i32, ptr %s seq_cst, align 4
+  ret i32 %t
+}
+
+; For nuw we don't need the offset to be positive.
+
+; CHECK-LABEL: load_i32_with_folded_gep_offset_nuw:
+; CHECK: i32.atomic.load  $push0=, -24($0){{$}}
+define i32 @load_i32_with_folded_gep_offset_nuw(ptr %p) {
+  %s = getelementptr nuw i32, ptr %p, i32 -6
+  %t = load atomic i32, ptr %s seq_cst, align 4
+  ret i32 %t
+}
+
 ; We can't fold a negative offset though, even with an inbounds gep.
 
 ; CHECK-LABEL: load_i32_with_unfolded_gep_negative_offset:
@@ -99,8 +119,19 @@ define i32 @load_i32_from_global_address() {
   ret i32 %t
 }
 
+define i32 @load_i32_global_with_folded_gep_offset_nonconst_nuw(i32 %idx) {
+; CHECK-LABEL: load_i32_global_with_folded_gep_offset_nonconst_nuw:
+; CHECK: i32.const $push0=, 2
+; CHECK: i32.shl $push1=, $0, $pop0
+; CHECK: i32.atomic.load $push2=, gv($pop1)
+  %s = getelementptr nuw i32, ptr @gv, i32 %idx
+  %t = load atomic i32, ptr %s seq_cst, align 4
+  ret i32 %t
+}
+
 ;===----------------------------------------------------------------------------
 ; Atomic loads: 64-bit
+
 ;===----------------------------------------------------------------------------
 
 ; Basic load.
@@ -1790,3 +1821,5 @@ define i32 @notify_from_global_address(i32 %notify_count) {
   %t = call i32 @llvm.wasm.memory.atomic.notify(ptr @gv, i32 %notify_count)
   ret i32 %t
 }
+;; NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line:
+; CHECK: {{.*}}

>From 227426372ab34ec09fc11940eb64b1c264d5771d Mon Sep 17 00:00:00 2001
From: Derek Schuff <dschuff at chromium.org>
Date: Wed, 11 Mar 2026 16:46:40 +0000
Subject: [PATCH 11/11] review comments

---
 llvm/lib/Target/WebAssembly/WebAssemblyInstrAtomics.td | 6 ++++--
 llvm/test/CodeGen/WebAssembly/offset-atomics.ll        | 2 --
 2 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyInstrAtomics.td b/llvm/lib/Target/WebAssembly/WebAssemblyInstrAtomics.td
index 4e47abd733778..90b8506fdba8d 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblyInstrAtomics.td
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyInstrAtomics.td
@@ -394,10 +394,12 @@ defm ATOMIC_RMW32_U_XCHG_I64 :
   WebAssemblyBinRMW<I64, "i64.atomic.rmw32.xchg_u", 0x47>;
 
 multiclass BinRMWPat<ValueType ty, PatFrag kind, string inst> {
-  def : Pat<(ty (kind (AtomicAddrOps32 offset32_op:$offset, I32:$addr, i32imm:$order), ty:$val)),
+  def : Pat<(ty (kind (AtomicAddrOps32 offset32_op:$offset, I32:$addr,
+                       i32imm:$order), ty:$val)),
             (!cast<NI>(inst#_A32) $order, 0, $offset, $addr, $val)>,
         Requires<[HasAddr32, HasAtomics]>;
-  def : Pat<(ty (kind (AtomicAddrOps64 offset64_op:$offset, I64:$addr, i32imm:$order), ty:$val)),
+  def : Pat<(ty (kind (AtomicAddrOps64 offset64_op:$offset, I64:$addr,
+                       i32imm:$order), ty:$val)),
             (!cast<NI>(inst#_A64) $order, 0, $offset, $addr, $val)>,
         Requires<[HasAddr64, HasAtomics]>;
 }
diff --git a/llvm/test/CodeGen/WebAssembly/offset-atomics.ll b/llvm/test/CodeGen/WebAssembly/offset-atomics.ll
index c391138d9b0a2..c1475955f83da 100644
--- a/llvm/test/CodeGen/WebAssembly/offset-atomics.ll
+++ b/llvm/test/CodeGen/WebAssembly/offset-atomics.ll
@@ -1821,5 +1821,3 @@ define i32 @notify_from_global_address(i32 %notify_count) {
   %t = call i32 @llvm.wasm.memory.atomic.notify(ptr @gv, i32 %notify_count)
   ret i32 %t
 }
-;; NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line:
-; CHECK: {{.*}}



More information about the cfe-commits mailing list