[clang] [llvm] [WebAssembly] Support acquire-release atomics in CodeGen (PR #184900)
Derek Schuff via cfe-commits
cfe-commits at lists.llvm.org
Fri Mar 6 09:57:55 PST 2026
https://github.com/dschuff updated https://github.com/llvm/llvm-project/pull/184900
>From 02407bddfb71b39a7d57caafdcdeb5654accb085 Mon Sep 17 00:00:00 2001
From: Derek Schuff <dschuff at chromium.org>
Date: Thu, 5 Mar 2026 00:47:15 +0000
Subject: [PATCH 1/9] [WebAssembly] Support acquire-release memory orderings in
CodeGen This commit completes the CodeGen support for matching LLVM IR atomic
orderings to the newly introduced WebAssembly `MemOrder` immediate operand.
Instead of duplicating TableGen definitions across the extensive set of
`PatFrag` combinations in
[WebAssemblyInstrAtomics.td](cci:7://file:///usr/local/google/home/dschuff/s/llvm-upstream/llvm-project/llvm/lib/Target/WebAssembly/WebAssemblyInstrAtomics.td:0:0-0:0),
memory ordering constraints are now dynamically computed during ISel and
MCInst lowering: - Intercepts `WebAssembly::OPERAND_MEMORDER` during MCInst
lowering (`WebAssemblyMCInstLower::lower`). If the target feature
`+relaxed-atomics` is enabled, we extract the `MachineMemOperand`'s ordering
(Acquire, Release, AcquireRelease, or Monotonic) and dynamically map it to
`acqrel` (1). Fallback logic maps the remaining orderings to `seqcst` (0). -
Updates `ISD::ATOMIC_FENCE` expansion in `WebAssemblyISelDAGToDAG::Select` to
natively detect and pass the correct `MemOrder` target constant for
standalone compiler fences based on their original IR ordering. Adds
[llvm/test/CodeGen/WebAssembly/atomics-orderings.ll](cci:7://file:///usr/local/google/home/dschuff/s/llvm-upstream/llvm-project/llvm/test/CodeGen/WebAssembly/atomics-orderings.ll:0:0-0:0)
to verify that `acquire`, `release`, `acq_rel`, and `seq_cst` properly map to
their target WebAssembly equivalents (load, store, RMW, cmpxchg, and fence).
---
.../WebAssembly/WebAssemblyISelDAGToDAG.cpp | 29 +++-
.../WebAssembly/WebAssemblyMCInstLower.cpp | 25 +++
.../CodeGen/WebAssembly/atomics-orderings.ll | 148 ++++++++++++++++++
3 files changed, 195 insertions(+), 7 deletions(-)
create mode 100644 llvm/test/CodeGen/WebAssembly/atomics-orderings.ll
diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyISelDAGToDAG.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyISelDAGToDAG.cpp
index 2541b0433ab59..473546d64d273 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblyISelDAGToDAG.cpp
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyISelDAGToDAG.cpp
@@ -207,17 +207,32 @@ void WebAssemblyDAGToDAGISel::Select(SDNode *Node) {
Node->getOperand(0) // inchain
);
break;
- case SyncScope::System:
- // Currently wasm only supports sequentially consistent atomics, so we
- // always set the order to 0 (sequentially consistent).
+ case SyncScope::System: {
+ unsigned Order = 0;
+ if (MF.getSubtarget<WebAssemblySubtarget>().hasRelaxedAtomics()) {
+ auto Ordering =
+ static_cast<AtomicOrdering>(Node->getConstantOperandVal(1));
+ switch (Ordering) {
+ case AtomicOrdering::Acquire:
+ case AtomicOrdering::Release:
+ case AtomicOrdering::AcquireRelease:
+ case AtomicOrdering::Monotonic:
+ Order = 1; // acqrel
+ break;
+ default:
+ Order = 0; // seqcst
+ break;
+ }
+ }
Fence = CurDAG->getMachineNode(
WebAssembly::ATOMIC_FENCE,
- DL, // debug loc
- MVT::Other, // outchain type
- CurDAG->getTargetConstant(0, DL, MVT::i32), // order
- Node->getOperand(0) // inchain
+ DL, // debug loc
+ MVT::Other, // outchain type
+ CurDAG->getTargetConstant(Order, DL, MVT::i32), // order
+ Node->getOperand(0) // inchain
);
break;
+ }
default:
llvm_unreachable("Unknown scope!");
}
diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyMCInstLower.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyMCInstLower.cpp
index e48283aadb437..ac234b7755b5d 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblyMCInstLower.cpp
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyMCInstLower.cpp
@@ -33,6 +33,7 @@
#include "llvm/MC/MCExpr.h"
#include "llvm/MC/MCInst.h"
#include "llvm/MC/MCSymbolWasm.h"
+#include "llvm/Support/AtomicOrdering.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/raw_ostream.h"
@@ -212,6 +213,30 @@ void WebAssemblyMCInstLower::lower(const MachineInstr *MI,
const MachineOperand &MO = MI->getOperand(I);
MCOperand MCOp;
+
+ if (I < Desc.getNumOperands() &&
+ Desc.operands()[I].OperandType == WebAssembly::OPERAND_MEMORDER &&
+ !MI->memoperands_empty()) {
+ unsigned Order = MO.getImm();
+ auto *MMO = *MI->memoperands_begin();
+ if (MF->getSubtarget<WebAssemblySubtarget>().hasRelaxedAtomics()) {
+ switch (MMO->getMergedOrdering()) {
+ case AtomicOrdering::Acquire:
+ case AtomicOrdering::Release:
+ case AtomicOrdering::AcquireRelease:
+ case AtomicOrdering::Monotonic:
+ Order = 1; // acqrel
+ break;
+ default:
+ Order = 0; // seqcst
+ break;
+ }
+ }
+ MCOp = MCOperand::createImm(Order);
+ OutMI.addOperand(MCOp);
+ continue;
+ }
+
switch (MO.getType()) {
default:
MI->print(errs());
diff --git a/llvm/test/CodeGen/WebAssembly/atomics-orderings.ll b/llvm/test/CodeGen/WebAssembly/atomics-orderings.ll
new file mode 100644
index 0000000000000..95e1930842d56
--- /dev/null
+++ b/llvm/test/CodeGen/WebAssembly/atomics-orderings.ll
@@ -0,0 +1,148 @@
+; RUN: llc < %s --mtriple=wasm32 -mattr=+atomics,+relaxed-atomics | FileCheck %s
+
+; CHECK-LABEL: load_i32_acquire:
+; CHECK: i32.atomic.load acqrel 0
+define i32 @load_i32_acquire(ptr %p) {
+ %v = load atomic i32, ptr %p acquire, align 4
+ ret i32 %v
+}
+
+; CHECK-LABEL: load_i32_seq_cst:
+; CHECK: i32.atomic.load seqcst 0
+define i32 @load_i32_seq_cst(ptr %p) {
+ %v = load atomic i32, ptr %p seq_cst, align 4
+ ret i32 %v
+}
+
+; CHECK-LABEL: store_i32_release:
+; CHECK: i32.atomic.store acqrel 0
+define void @store_i32_release(ptr %p, i32 %v) {
+ store atomic i32 %v, ptr %p release, align 4
+ ret void
+}
+
+; CHECK-LABEL: store_i32_seq_cst:
+; CHECK: i32.atomic.store seqcst 0
+define void @store_i32_seq_cst(ptr %p, i32 %v) {
+ store atomic i32 %v, ptr %p seq_cst, align 4
+ ret void
+}
+
+; CHECK-LABEL: add_i32_acq_rel:
+; CHECK: i32.atomic.rmw.add acqrel 0
+define i32 @add_i32_acq_rel(ptr %p, i32 %v) {
+ %old = atomicrmw add ptr %p, i32 %v acq_rel
+ ret i32 %old
+}
+
+; CHECK-LABEL: add_i32_seq_cst:
+; CHECK: i32.atomic.rmw.add seqcst 0
+define i32 @add_i32_seq_cst(ptr %p, i32 %v) {
+ %old = atomicrmw add ptr %p, i32 %v seq_cst
+ ret i32 %old
+}
+
+; CHECK-LABEL: cmpxchg_i32_acquire_acquire:
+; CHECK: i32.atomic.rmw.cmpxchg acqrel 0
+define i32 @cmpxchg_i32_acquire_acquire(ptr %p, i32 %exp, i32 %new) {
+ %pair = cmpxchg ptr %p, i32 %exp, i32 %new acquire acquire
+ %val = extractvalue { i32, i1 } %pair, 0
+ ret i32 %val
+}
+
+; CHECK-LABEL: cmpxchg_i32_seq_cst_seq_cst:
+; CHECK: i32.atomic.rmw.cmpxchg seqcst 0
+define i32 @cmpxchg_i32_seq_cst_seq_cst(ptr %p, i32 %exp, i32 %new) {
+ %pair = cmpxchg ptr %p, i32 %exp, i32 %new seq_cst seq_cst
+ %val = extractvalue { i32, i1 } %pair, 0
+ ret i32 %val
+}
+
+; CHECK-LABEL: fence_acquire:
+; CHECK: atomic.fence acqrel
+define void @fence_acquire() {
+ fence acquire
+ ret void
+}
+
+; CHECK-LABEL: fence_seq_cst:
+; CHECK: atomic.fence seqcst
+define void @fence_seq_cst() {
+ fence seq_cst
+ ret void
+}
+
+; CHECK-LABEL: load_i32_monotonic:
+; CHECK: i32.atomic.load acqrel 0
+define i32 @load_i32_monotonic(ptr %p) {
+ %v = load atomic i32, ptr %p monotonic, align 4
+ ret i32 %v
+}
+
+; CHECK-LABEL: store_i32_monotonic:
+; CHECK: i32.atomic.store acqrel 0
+define void @store_i32_monotonic(ptr %p, i32 %v) {
+ store atomic i32 %v, ptr %p monotonic, align 4
+ ret void
+}
+
+; CHECK-LABEL: add_i32_release:
+; CHECK: i32.atomic.rmw.add acqrel 0
+define i32 @add_i32_release(ptr %p, i32 %v) {
+ %old = atomicrmw add ptr %p, i32 %v release
+ ret i32 %old
+}
+
+; CHECK-LABEL: add_i32_acquire:
+; CHECK: i32.atomic.rmw.add acqrel 0
+define i32 @add_i32_acquire(ptr %p, i32 %v) {
+ %old = atomicrmw add ptr %p, i32 %v acquire
+ ret i32 %old
+}
+
+; CHECK-LABEL: add_i32_monotonic:
+; CHECK: i32.atomic.rmw.add acqrel 0
+define i32 @add_i32_monotonic(ptr %p, i32 %v) {
+ %old = atomicrmw add ptr %p, i32 %v monotonic
+ ret i32 %old
+}
+
+; CHECK-LABEL: cmpxchg_i32_acq_rel_monotonic:
+; CHECK: i32.atomic.rmw.cmpxchg acqrel 0
+define i32 @cmpxchg_i32_acq_rel_monotonic(ptr %p, i32 %exp, i32 %new) {
+ %pair = cmpxchg ptr %p, i32 %exp, i32 %new acq_rel monotonic
+ %val = extractvalue { i32, i1 } %pair, 0
+ ret i32 %val
+}
+
+; CHECK-LABEL: cmpxchg_i32_release_monotonic:
+; CHECK: i32.atomic.rmw.cmpxchg acqrel 0
+define i32 @cmpxchg_i32_release_monotonic(ptr %p, i32 %exp, i32 %new) {
+ %pair = cmpxchg ptr %p, i32 %exp, i32 %new release monotonic
+ %val = extractvalue { i32, i1 } %pair, 0
+ ret i32 %val
+}
+
+; CHECK-LABEL: cmpxchg_i32_monotonic_monotonic:
+; CHECK: i32.atomic.rmw.cmpxchg acqrel 0
+define i32 @cmpxchg_i32_monotonic_monotonic(ptr %p, i32 %exp, i32 %new) {
+ %pair = cmpxchg ptr %p, i32 %exp, i32 %new monotonic monotonic
+ %val = extractvalue { i32, i1 } %pair, 0
+ ret i32 %val
+}
+
+; CHECK-LABEL: fence_release:
+; CHECK: atomic.fence acqrel
+define void @fence_release() {
+ fence release
+ ret void
+}
+
+; CHECK-LABEL: fence_acq_rel:
+; CHECK: atomic.fence acqrel
+define void @fence_acq_rel() {
+ fence acq_rel
+ ret void
+}
+
+
>From 6c51a93b6d383cc450f95a25a0868a3f87d4bcfe Mon Sep 17 00:00:00 2001
From: Derek Schuff <dschuff at chromium.org>
Date: Thu, 5 Mar 2026 20:36:18 +0000
Subject: [PATCH 2/9] Clang support: feature, flag, and preprocessor
definitions
---
clang/include/clang/Options/Options.td | 2 ++
clang/lib/Basic/Targets/WebAssembly.cpp | 11 +++++++++++
clang/lib/Basic/Targets/WebAssembly.h | 1 +
clang/test/Driver/wasm-features.c | 6 ++++++
clang/test/Preprocessor/wasm-target-features.c | 11 +++++++++++
5 files changed, 31 insertions(+)
diff --git a/clang/include/clang/Options/Options.td b/clang/include/clang/Options/Options.td
index fe7169423b6bf..9d3ec8a173472 100644
--- a/clang/include/clang/Options/Options.td
+++ b/clang/include/clang/Options/Options.td
@@ -5688,6 +5688,8 @@ def mnontrapping_fptoint : Flag<["-"], "mnontrapping-fptoint">, Group<m_wasm_Fea
def mno_nontrapping_fptoint : Flag<["-"], "mno-nontrapping-fptoint">, Group<m_wasm_Features_Group>;
def mreference_types : Flag<["-"], "mreference-types">, Group<m_wasm_Features_Group>;
def mno_reference_types : Flag<["-"], "mno-reference-types">, Group<m_wasm_Features_Group>;
+def mrelaxed_atomics : Flag<["-"], "mrelaxed-atomics">, Group<m_wasm_Features_Group>;
+def mno_relaxed_atomics : Flag<["-"], "mno-relaxed-atomics">, Group<m_wasm_Features_Group>;
def mrelaxed_simd : Flag<["-"], "mrelaxed-simd">, Group<m_wasm_Features_Group>;
def mno_relaxed_simd : Flag<["-"], "mno-relaxed-simd">, Group<m_wasm_Features_Group>;
def msign_ext : Flag<["-"], "msign-ext">, Group<m_wasm_Features_Group>;
diff --git a/clang/lib/Basic/Targets/WebAssembly.cpp b/clang/lib/Basic/Targets/WebAssembly.cpp
index daaefd9a1267c..4bb3d521cd9fd 100644
--- a/clang/lib/Basic/Targets/WebAssembly.cpp
+++ b/clang/lib/Basic/Targets/WebAssembly.cpp
@@ -66,6 +66,7 @@ bool WebAssemblyTargetInfo::hasFeature(StringRef Feature) const {
.Case("mutable-globals", HasMutableGlobals)
.Case("nontrapping-fptoint", HasNontrappingFPToInt)
.Case("reference-types", HasReferenceTypes)
+ .Case("relaxed-atomics", HasRelaxedAtomics)
.Case("relaxed-simd", SIMDLevel >= RelaxedSIMD)
.Case("sign-ext", HasSignExt)
.Case("simd128", SIMDLevel >= SIMD128)
@@ -110,6 +111,8 @@ void WebAssemblyTargetInfo::getTargetDefines(const LangOptions &Opts,
Builder.defineMacro("__wasm_nontrapping_fptoint__");
if (HasReferenceTypes)
Builder.defineMacro("__wasm_reference_types__");
+ if (HasRelaxedAtomics)
+ Builder.defineMacro("__wasm_relaxed_atomics__");
if (SIMDLevel >= RelaxedSIMD)
Builder.defineMacro("__wasm_relaxed_simd__");
if (HasSignExt)
@@ -332,6 +335,14 @@ bool WebAssemblyTargetInfo::handleTargetFeatures(
HasReferenceTypes = false;
continue;
}
+ if (Feature == "+relaxed-atomics") {
+ HasRelaxedAtomics = true;
+ continue;
+ }
+ if (Feature == "-relaxed-atomics") {
+ HasRelaxedAtomics = false;
+ continue;
+ }
if (Feature == "+relaxed-simd") {
SIMDLevel = std::max(SIMDLevel, RelaxedSIMD);
continue;
diff --git a/clang/lib/Basic/Targets/WebAssembly.h b/clang/lib/Basic/Targets/WebAssembly.h
index 3a0823bd717d9..8128dd96068a0 100644
--- a/clang/lib/Basic/Targets/WebAssembly.h
+++ b/clang/lib/Basic/Targets/WebAssembly.h
@@ -72,6 +72,7 @@ class LLVM_LIBRARY_VISIBILITY WebAssemblyTargetInfo : public TargetInfo {
bool HasMutableGlobals = false;
bool HasNontrappingFPToInt = false;
bool HasReferenceTypes = false;
+ bool HasRelaxedAtomics = false;
bool HasSignExt = false;
bool HasTailCall = false;
bool HasWideArithmetic = false;
diff --git a/clang/test/Driver/wasm-features.c b/clang/test/Driver/wasm-features.c
index 89ced36eeffab..9e523aa5b53b6 100644
--- a/clang/test/Driver/wasm-features.c
+++ b/clang/test/Driver/wasm-features.c
@@ -77,6 +77,12 @@
// REFERENCE-TYPES: "-target-feature" "+reference-types"
// NO-REFERENCE-TYPES: "-target-feature" "-reference-types"
+// RUN: %clang --target=wasm32-unknown-unknown -### %s -mrelaxed-atomics 2>&1 | FileCheck %s -check-prefix=RELAXED-ATOMICS
+// RUN: %clang --target=wasm32-unknown-unknown -### %s -mno-relaxed-atomics 2>&1 | FileCheck %s -check-prefix=NO-RELAXED-ATOMICS
+
+// RELAXED-ATOMICS: "-target-feature" "+relaxed-atomics"
+// NO-RELAXED-ATOMICS: "-target-feature" "-relaxed-atomics"
+
// RUN: %clang --target=wasm32-unknown-unknown -### %s -mrelaxed-simd 2>&1 | FileCheck %s -check-prefix=RELAXED-SIMD
// RUN: %clang --target=wasm32-unknown-unknown -### %s -mno-relaxed-simd 2>&1 | FileCheck %s -check-prefix=NO-RELAXED-SIMD
diff --git a/clang/test/Preprocessor/wasm-target-features.c b/clang/test/Preprocessor/wasm-target-features.c
index 3edaf9e7cd594..aff7442773531 100644
--- a/clang/test/Preprocessor/wasm-target-features.c
+++ b/clang/test/Preprocessor/wasm-target-features.c
@@ -106,6 +106,15 @@
//
// REFERENCE-TYPES: #define __wasm_reference_types__ 1{{$}}
+// RUN: %clang -E -dM %s -o - 2>&1 \
+// RUN: -target wasm32-unknown-unknown -mrelaxed-atomics \
+// RUN: | FileCheck %s -check-prefix=RELAXED-ATOMICS
+// RUN: %clang -E -dM %s -o - 2>&1 \
+// RUN: -target wasm64-unknown-unknown -mrelaxed-atomics \
+// RUN: | FileCheck %s -check-prefix=RELAXED-ATOMICS
+//
+// RELAXED-ATOMICS: #define __wasm_relaxed_atomics__ 1{{$}}
+
// RUN: %clang -E -dM %s -o - 2>&1 \
// RUN: -target wasm32-unknown-unknown -mrelaxed-simd \
// RUN: | FileCheck %s -check-prefix=RELAXED-SIMD
@@ -160,6 +169,7 @@
// MVP-NOT: #define __wasm_mutable_globals__ 1{{$}}
// MVP-NOT: #define __wasm_nontrapping_fptoint__ 1{{$}}
// MVP-NOT: #define __wasm_reference_types__ 1{{$}}
+// MVP-NOT: #define __wasm_relaxed_atomics__ 1{{$}}
// MVP-NOT: #define __wasm_relaxed_simd__ 1{{$}}
// MVP-NOT: #define __wasm_sign_ext__ 1{{$}}
// MVP-NOT: #define __wasm_simd128__ 1{{$}}
@@ -193,6 +203,7 @@
// GENERIC-NOT: #define __wasm__fp16__ 1{{$}}
// GENERIC-NOT: #define __wasm_gc__ 1{{$}}
// GENERIC-NOT: #define __wasm_multimemory__ 1{{$}}
+// GENERIC-NOT: #define __wasm_relaxed_atomics__ 1{{$}}
// GENERIC-NOT: #define __wasm_relaxed_simd__ 1{{$}}
// GENERIC-NOT: #define __wasm_simd128__ 1{{$}}
// GENERIC-NOT: #define __wasm_tail_call__ 1{{$}}
>From 505892450fbd11a0550a5d8156b88d752930d78c Mon Sep 17 00:00:00 2001
From: Derek Schuff <dschuff at chromium.org>
Date: Thu, 5 Mar 2026 21:08:53 +0000
Subject: [PATCH 3/9] Use a MI pass to set ordering after ISel instead of
setting it at MC lowering
---
llvm/lib/Target/WebAssembly/CMakeLists.txt | 1 +
llvm/lib/Target/WebAssembly/WebAssembly.h | 2 +
.../WebAssembly/WebAssemblyFixupAtomics.cpp | 89 +++++++++++++++++++
.../WebAssembly/WebAssemblyMCInstLower.cpp | 17 +---
.../WebAssembly/WebAssemblyTargetMachine.cpp | 4 +-
5 files changed, 96 insertions(+), 17 deletions(-)
create mode 100644 llvm/lib/Target/WebAssembly/WebAssemblyFixupAtomics.cpp
diff --git a/llvm/lib/Target/WebAssembly/CMakeLists.txt b/llvm/lib/Target/WebAssembly/CMakeLists.txt
index 1ad99f7e468df..8cbabcd15968c 100644
--- a/llvm/lib/Target/WebAssembly/CMakeLists.txt
+++ b/llvm/lib/Target/WebAssembly/CMakeLists.txt
@@ -67,6 +67,7 @@ add_llvm_target(WebAssemblyCodeGen
WebAssemblyReplacePhysRegs.cpp
WebAssemblyRuntimeLibcallSignatures.cpp
WebAssemblySelectionDAGInfo.cpp
+ WebAssemblyFixupAtomics.cpp
WebAssemblySetP2AlignOperands.cpp
WebAssemblySortRegion.cpp
WebAssemblyMemIntrinsicResults.cpp
diff --git a/llvm/lib/Target/WebAssembly/WebAssembly.h b/llvm/lib/Target/WebAssembly/WebAssembly.h
index 71647974b2843..0c5622f502a5c 100644
--- a/llvm/lib/Target/WebAssembly/WebAssembly.h
+++ b/llvm/lib/Target/WebAssembly/WebAssembly.h
@@ -52,6 +52,7 @@ FunctionPass *createWebAssemblyISelDag(WebAssemblyTargetMachine &TM,
CodeGenOptLevel OptLevel);
FunctionPass *createWebAssemblyArgumentMove();
FunctionPass *createWebAssemblySetP2AlignOperands();
+FunctionPass *createWebAssemblyFixupAtomics();
FunctionPass *createWebAssemblyCleanCodeAfterTrap();
// Late passes.
@@ -103,6 +104,7 @@ void initializeWebAssemblyRegNumberingPass(PassRegistry &);
void initializeWebAssemblyRegStackifyPass(PassRegistry &);
void initializeWebAssemblyReplacePhysRegsPass(PassRegistry &);
void initializeWebAssemblySetP2AlignOperandsPass(PassRegistry &);
+void initializeWebAssemblyFixupAtomicsPass(PassRegistry &);
namespace WebAssembly {
enum TargetIndex {
diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyFixupAtomics.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyFixupAtomics.cpp
new file mode 100644
index 0000000000000..8f6f40cdcfabd
--- /dev/null
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyFixupAtomics.cpp
@@ -0,0 +1,89 @@
+//===-- WebAssemblyFixupAtomics.cpp - Fixup Atomics -----------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// \brief Fixes memory ordering operands for atomic instructions.
+///
+//===----------------------------------------------------------------------===//
+
+#include "MCTargetDesc/WebAssemblyMCTargetDesc.h"
+#include "WebAssembly.h"
+#include "WebAssemblySubtarget.h"
+#include "llvm/CodeGen/MachineFunctionPass.h"
+#include "llvm/CodeGen/MachineInstrBuilder.h"
+
+using namespace llvm;
+
+#define DEBUG_TYPE "wasm-fixup-atomics"
+
+namespace {
+class WebAssemblyFixupAtomics final : public MachineFunctionPass {
+ StringRef getPassName() const override { return "WebAssembly Fixup Atomics"; }
+
+ void getAnalysisUsage(AnalysisUsage &AU) const override {
+ AU.setPreservesCFG();
+ MachineFunctionPass::getAnalysisUsage(AU);
+ }
+
+ bool runOnMachineFunction(MachineFunction &MF) override;
+
+public:
+ static char ID; // Pass identification, replacement for typeid
+ WebAssemblyFixupAtomics() : MachineFunctionPass(ID) {}
+};
+} // end anonymous namespace
+
+char WebAssemblyFixupAtomics::ID = 0;
+INITIALIZE_PASS(WebAssemblyFixupAtomics, DEBUG_TYPE,
+ "Fixup the memory ordering of atomics", false, false)
+
+FunctionPass *llvm::createWebAssemblyFixupAtomics() {
+ return new WebAssemblyFixupAtomics();
+}
+
+bool WebAssemblyFixupAtomics::runOnMachineFunction(MachineFunction &MF) {
+ LLVM_DEBUG(dbgs() << "********** Fixup Atomics **********\n"
+ << "********** Function: " << MF.getName() << '\n');
+
+ bool Changed = false;
+ const auto &Subtarget = MF.getSubtarget<WebAssemblySubtarget>();
+ bool HasRelaxedAtomics = Subtarget.hasRelaxedAtomics();
+
+ for (auto &MBB : MF) {
+ for (auto &MI : MBB) {
+ const MCInstrDesc &Desc = MI.getDesc();
+ for (unsigned I = 0, E = MI.getNumExplicitOperands(); I < E; ++I) {
+ if (I < Desc.getNumOperands() &&
+ Desc.operands()[I].OperandType == WebAssembly::OPERAND_MEMORDER) {
+
+ if (HasRelaxedAtomics && !MI.memoperands_empty()) {
+ unsigned Order = 0; // seqcst
+ auto *MMO = *MI.memoperands_begin();
+ switch (MMO->getMergedOrdering()) {
+ case AtomicOrdering::Acquire:
+ case AtomicOrdering::Release:
+ case AtomicOrdering::AcquireRelease:
+ case AtomicOrdering::Monotonic:
+ Order = 1; // acqrel
+ break;
+ default:
+ Order = 0; // seqcst
+ break;
+ }
+ if (MI.getOperand(I).getImm() != Order) {
+ MI.getOperand(I).setImm(Order);
+ Changed = true;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ return Changed;
+}
diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyMCInstLower.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyMCInstLower.cpp
index ac234b7755b5d..4f4cf4d869ed9 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblyMCInstLower.cpp
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyMCInstLower.cpp
@@ -217,22 +217,7 @@ void WebAssemblyMCInstLower::lower(const MachineInstr *MI,
if (I < Desc.getNumOperands() &&
Desc.operands()[I].OperandType == WebAssembly::OPERAND_MEMORDER &&
!MI->memoperands_empty()) {
- unsigned Order = MO.getImm();
- auto *MMO = *MI->memoperands_begin();
- if (MF->getSubtarget<WebAssemblySubtarget>().hasRelaxedAtomics()) {
- switch (MMO->getMergedOrdering()) {
- case AtomicOrdering::Acquire:
- case AtomicOrdering::Release:
- case AtomicOrdering::AcquireRelease:
- case AtomicOrdering::Monotonic:
- Order = 1; // acqrel
- break;
- default:
- Order = 0; // seqcst
- break;
- }
- }
- MCOp = MCOperand::createImm(Order);
+ MCOp = MCOperand::createImm(MO.getImm());
OutMI.addOperand(MCOp);
continue;
}
diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp
index dce8f54409c41..cb2ea6bf4b6fb 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp
@@ -108,6 +108,7 @@ LLVMInitializeWebAssemblyTarget() {
initializeWebAssemblyArgumentMovePass(PR);
initializeWebAssemblyAsmPrinterPass(PR);
initializeWebAssemblySetP2AlignOperandsPass(PR);
+ initializeWebAssemblyFixupAtomicsPass(PR);
initializeWebAssemblyReplacePhysRegsPass(PR);
initializeWebAssemblyOptimizeLiveIntervalsPass(PR);
initializeWebAssemblyMemIntrinsicResultsPass(PR);
@@ -551,7 +552,7 @@ bool WebAssemblyPassConfig::addInstSelector() {
// it's inconvenient to collect. Collect it now, and update the immediate
// operands.
addPass(createWebAssemblySetP2AlignOperands());
-
+ addPass(createWebAssemblyFixupAtomics());
// Eliminate range checks and add default targets to br_table instructions.
addPass(createWebAssemblyFixBrTableDefaults());
@@ -713,6 +714,7 @@ bool WebAssemblyPassConfig::addGlobalInstructionSelect() {
if (isGlobalISelAbortEnabled()) {
addPass(createWebAssemblyArgumentMove());
addPass(createWebAssemblySetP2AlignOperands());
+ addPass(createWebAssemblyFixupAtomics());
addPass(createWebAssemblyFixBrTableDefaults());
addPass(createWebAssemblyCleanCodeAfterTrap());
}
>From 2af4d8a081305ec74d32a65378587afb00ea047e Mon Sep 17 00:00:00 2001
From: Derek Schuff <dschuff at chromium.org>
Date: Thu, 5 Mar 2026 21:23:11 +0000
Subject: [PATCH 4/9] add comments, use constants
---
.../Target/WebAssembly/WebAssemblyFixupAtomics.cpp | 14 +++++++++++---
.../GlobalISel/gisel-commandline-option.ll | 2 ++
2 files changed, 13 insertions(+), 3 deletions(-)
diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyFixupAtomics.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyFixupAtomics.cpp
index 8f6f40cdcfabd..565feb79af9ec 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblyFixupAtomics.cpp
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyFixupAtomics.cpp
@@ -9,11 +9,17 @@
/// \file
/// \brief Fixes memory ordering operands for atomic instructions.
///
+/// This is used because ISel selects atomics with a default value for the
+/// memory ordering immediate operand. Even though we run this pass early in
+/// the MI pass pipeline, MI passes should still use getMergedOrdering() on
+/// the MachineMemOperand to get the ordering rther than the immediate.
+///
//===----------------------------------------------------------------------===//
#include "MCTargetDesc/WebAssemblyMCTargetDesc.h"
#include "WebAssembly.h"
#include "WebAssemblySubtarget.h"
+#include "llvm/BinaryFormat/Wasm.h"
#include "llvm/CodeGen/MachineFunctionPass.h"
#include "llvm/CodeGen/MachineInstrBuilder.h"
@@ -62,17 +68,19 @@ bool WebAssemblyFixupAtomics::runOnMachineFunction(MachineFunction &MF) {
Desc.operands()[I].OperandType == WebAssembly::OPERAND_MEMORDER) {
if (HasRelaxedAtomics && !MI.memoperands_empty()) {
- unsigned Order = 0; // seqcst
+ assert(MI.getOperand(I).getImm() == wasm::WASM_MEM_ORDER_SEQ_CST &&
+ "Expected seqcst default atomics from ISel");
+ unsigned Order = wasm::WASM_MEM_ORDER_SEQ_CST;
auto *MMO = *MI.memoperands_begin();
switch (MMO->getMergedOrdering()) {
case AtomicOrdering::Acquire:
case AtomicOrdering::Release:
case AtomicOrdering::AcquireRelease:
case AtomicOrdering::Monotonic:
- Order = 1; // acqrel
+ Order = wasm::WASM_MEM_ORDER_ACQ_REL;
break;
default:
- Order = 0; // seqcst
+ Order = wasm::WASM_MEM_ORDER_SEQ_CST;
break;
}
if (MI.getOperand(I).getImm() != Order) {
diff --git a/llvm/test/CodeGen/WebAssembly/GlobalISel/gisel-commandline-option.ll b/llvm/test/CodeGen/WebAssembly/GlobalISel/gisel-commandline-option.ll
index 47b05c8160fd1..1389591a34ed6 100644
--- a/llvm/test/CodeGen/WebAssembly/GlobalISel/gisel-commandline-option.ll
+++ b/llvm/test/CodeGen/WebAssembly/GlobalISel/gisel-commandline-option.ll
@@ -31,6 +31,7 @@
; ENABLED-NEXT: InstructionSelect
; NOFALLBACK-NEXT: WebAssembly Argument Move
; NOFALLBACK-NEXT: WebAssembly Set p2align Operands
+; NOFALLBACK-NEXT: WebAssembly Fixup Atomics
; NOFALLBACK-NEXT: WebAssembly Fix br_table Defaults
; NOFALLBACK-NEXT: WebAssembly Clean Code After Trap
; ENABLED-NEXT: ResetMachineFunction
@@ -38,6 +39,7 @@
; FALLBACK: WebAssembly Instruction Selection
; FALLBACK-NEXT: WebAssembly Argument Move
; FALLBACK-NEXT: WebAssembly Set p2align Operands
+; FALLBACK-NEXT: WebAssembly Fixup Atomics
; FALLBACK-NEXT: WebAssembly Fix br_table Defaults
; FALLBACK-NEXT: WebAssembly Clean Code After Trap
>From db7307f1b230a7f486bed4e72727a810264ae88a Mon Sep 17 00:00:00 2001
From: Derek Schuff <dschuff at chromium.org>
Date: Thu, 5 Mar 2026 21:43:04 +0000
Subject: [PATCH 5/9] cleanups
---
.../WebAssembly/WebAssemblyISelDAGToDAG.cpp | 7 +-
.../WebAssembly/WebAssemblyMCInstLower.cpp | 10 -
.../CodeGen/WebAssembly/atomics-orderings.ll | 177 +++++++++++++-----
3 files changed, 138 insertions(+), 56 deletions(-)
diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyISelDAGToDAG.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyISelDAGToDAG.cpp
index 473546d64d273..e1f7e51f2af34 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblyISelDAGToDAG.cpp
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyISelDAGToDAG.cpp
@@ -186,7 +186,6 @@ void WebAssemblyDAGToDAGISel::Select(SDNode *Node) {
auto GlobalGetIns = PtrVT == MVT::i64 ? WebAssembly::GLOBAL_GET_I64
: WebAssembly::GLOBAL_GET_I32;
- // Few custom selection stuff.
SDLoc DL(Node);
MachineFunction &MF = CurDAG->getMachineFunction();
switch (Node->getOpcode()) {
@@ -208,7 +207,7 @@ void WebAssemblyDAGToDAGISel::Select(SDNode *Node) {
);
break;
case SyncScope::System: {
- unsigned Order = 0;
+ unsigned Order = wasm::WASM_MEM_ORDER_SEQ_CST;
if (MF.getSubtarget<WebAssemblySubtarget>().hasRelaxedAtomics()) {
auto Ordering =
static_cast<AtomicOrdering>(Node->getConstantOperandVal(1));
@@ -217,10 +216,10 @@ void WebAssemblyDAGToDAGISel::Select(SDNode *Node) {
case AtomicOrdering::Release:
case AtomicOrdering::AcquireRelease:
case AtomicOrdering::Monotonic:
- Order = 1; // acqrel
+ Order = wasm::WASM_MEM_ORDER_ACQ_REL;
break;
default:
- Order = 0; // seqcst
+ Order = wasm::WASM_MEM_ORDER_SEQ_CST;
break;
}
}
diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyMCInstLower.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyMCInstLower.cpp
index 4f4cf4d869ed9..e48283aadb437 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblyMCInstLower.cpp
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyMCInstLower.cpp
@@ -33,7 +33,6 @@
#include "llvm/MC/MCExpr.h"
#include "llvm/MC/MCInst.h"
#include "llvm/MC/MCSymbolWasm.h"
-#include "llvm/Support/AtomicOrdering.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/raw_ostream.h"
@@ -213,15 +212,6 @@ void WebAssemblyMCInstLower::lower(const MachineInstr *MI,
const MachineOperand &MO = MI->getOperand(I);
MCOperand MCOp;
-
- if (I < Desc.getNumOperands() &&
- Desc.operands()[I].OperandType == WebAssembly::OPERAND_MEMORDER &&
- !MI->memoperands_empty()) {
- MCOp = MCOperand::createImm(MO.getImm());
- OutMI.addOperand(MCOp);
- continue;
- }
-
switch (MO.getType()) {
default:
MI->print(errs());
diff --git a/llvm/test/CodeGen/WebAssembly/atomics-orderings.ll b/llvm/test/CodeGen/WebAssembly/atomics-orderings.ll
index 95e1930842d56..9095d27493a8e 100644
--- a/llvm/test/CodeGen/WebAssembly/atomics-orderings.ll
+++ b/llvm/test/CodeGen/WebAssembly/atomics-orderings.ll
@@ -1,148 +1,241 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 6
; RUN: llc < %s --mtriple=wasm32 -mattr=+atomics,+relaxed-atomics | FileCheck %s
-; CHECK-LABEL: load_i32_acquire:
-; CHECK: i32.atomic.load acqrel 0
define i32 @load_i32_acquire(ptr %p) {
+; CHECK-LABEL: load_i32_acquire:
+; CHECK: .functype load_i32_acquire (i32) -> (i32)
+; CHECK-NEXT: # %bb.0:
+; CHECK-NEXT: local.get 0
+; CHECK-NEXT: i32.atomic.load acqrel 0
+; CHECK-NEXT: # fallthrough-return
%v = load atomic i32, ptr %p acquire, align 4
ret i32 %v
}
-; CHECK-LABEL: load_i32_seq_cst:
-; CHECK: i32.atomic.load seqcst 0
define i32 @load_i32_seq_cst(ptr %p) {
+; CHECK-LABEL: load_i32_seq_cst:
+; CHECK: .functype load_i32_seq_cst (i32) -> (i32)
+; CHECK-NEXT: # %bb.0:
+; CHECK-NEXT: local.get 0
+; CHECK-NEXT: i32.atomic.load seqcst 0
+; CHECK-NEXT: # fallthrough-return
%v = load atomic i32, ptr %p seq_cst, align 4
ret i32 %v
}
-; CHECK-LABEL: store_i32_release:
-; CHECK: i32.atomic.store acqrel 0
define void @store_i32_release(ptr %p, i32 %v) {
+; CHECK-LABEL: store_i32_release:
+; CHECK: .functype store_i32_release (i32, i32) -> ()
+; CHECK-NEXT: # %bb.0:
+; CHECK-NEXT: local.get 0
+; CHECK-NEXT: local.get 1
+; CHECK-NEXT: i32.atomic.store acqrel 0
+; CHECK-NEXT: # fallthrough-return
store atomic i32 %v, ptr %p release, align 4
ret void
}
-; CHECK-LABEL: store_i32_seq_cst:
-; CHECK: i32.atomic.store seqcst 0
define void @store_i32_seq_cst(ptr %p, i32 %v) {
+; CHECK-LABEL: store_i32_seq_cst:
+; CHECK: .functype store_i32_seq_cst (i32, i32) -> ()
+; CHECK-NEXT: # %bb.0:
+; CHECK-NEXT: local.get 0
+; CHECK-NEXT: local.get 1
+; CHECK-NEXT: i32.atomic.store seqcst 0
+; CHECK-NEXT: # fallthrough-return
store atomic i32 %v, ptr %p seq_cst, align 4
ret void
}
-; CHECK-LABEL: add_i32_acq_rel:
-; CHECK: i32.atomic.rmw.add acqrel 0
define i32 @add_i32_acq_rel(ptr %p, i32 %v) {
+; CHECK-LABEL: add_i32_acq_rel:
+; CHECK: .functype add_i32_acq_rel (i32, i32) -> (i32)
+; CHECK-NEXT: # %bb.0:
+; CHECK-NEXT: local.get 0
+; CHECK-NEXT: local.get 1
+; CHECK-NEXT: i32.atomic.rmw.add acqrel 0
+; CHECK-NEXT: # fallthrough-return
%old = atomicrmw add ptr %p, i32 %v acq_rel
ret i32 %old
}
-; CHECK-LABEL: add_i32_seq_cst:
-; CHECK: i32.atomic.rmw.add seqcst 0
define i32 @add_i32_seq_cst(ptr %p, i32 %v) {
+; CHECK-LABEL: add_i32_seq_cst:
+; CHECK: .functype add_i32_seq_cst (i32, i32) -> (i32)
+; CHECK-NEXT: # %bb.0:
+; CHECK-NEXT: local.get 0
+; CHECK-NEXT: local.get 1
+; CHECK-NEXT: i32.atomic.rmw.add seqcst 0
+; CHECK-NEXT: # fallthrough-return
%old = atomicrmw add ptr %p, i32 %v seq_cst
ret i32 %old
}
-; CHECK-LABEL: cmpxchg_i32_acquire_acquire:
-; CHECK: i32.atomic.rmw.cmpxchg acqrel 0
define i32 @cmpxchg_i32_acquire_acquire(ptr %p, i32 %exp, i32 %new) {
+; CHECK-LABEL: cmpxchg_i32_acquire_acquire:
+; CHECK: .functype cmpxchg_i32_acquire_acquire (i32, i32, i32) -> (i32)
+; CHECK-NEXT: # %bb.0:
+; CHECK-NEXT: local.get 0
+; CHECK-NEXT: local.get 1
+; CHECK-NEXT: local.get 2
+; CHECK-NEXT: i32.atomic.rmw.cmpxchg acqrel 0
+; CHECK-NEXT: # fallthrough-return
%pair = cmpxchg ptr %p, i32 %exp, i32 %new acquire acquire
%val = extractvalue { i32, i1 } %pair, 0
ret i32 %val
}
-; CHECK-LABEL: cmpxchg_i32_seq_cst_seq_cst:
-; CHECK: i32.atomic.rmw.cmpxchg seqcst 0
define i32 @cmpxchg_i32_seq_cst_seq_cst(ptr %p, i32 %exp, i32 %new) {
+; CHECK-LABEL: cmpxchg_i32_seq_cst_seq_cst:
+; CHECK: .functype cmpxchg_i32_seq_cst_seq_cst (i32, i32, i32) -> (i32)
+; CHECK-NEXT: # %bb.0:
+; CHECK-NEXT: local.get 0
+; CHECK-NEXT: local.get 1
+; CHECK-NEXT: local.get 2
+; CHECK-NEXT: i32.atomic.rmw.cmpxchg seqcst 0
+; CHECK-NEXT: # fallthrough-return
%pair = cmpxchg ptr %p, i32 %exp, i32 %new seq_cst seq_cst
%val = extractvalue { i32, i1 } %pair, 0
ret i32 %val
}
-; CHECK-LABEL: fence_acquire:
-; CHECK: atomic.fence acqrel
define void @fence_acquire() {
+; CHECK-LABEL: fence_acquire:
+; CHECK: .functype fence_acquire () -> ()
+; CHECK-NEXT: # %bb.0:
+; CHECK-NEXT: atomic.fence acqrel
+; CHECK-NEXT: # fallthrough-return
fence acquire
ret void
}
-; CHECK-LABEL: fence_seq_cst:
-; CHECK: atomic.fence seqcst
define void @fence_seq_cst() {
+; CHECK-LABEL: fence_seq_cst:
+; CHECK: .functype fence_seq_cst () -> ()
+; CHECK-NEXT: # %bb.0:
+; CHECK-NEXT: atomic.fence seqcst
+; CHECK-NEXT: # fallthrough-return
fence seq_cst
ret void
}
-; CHECK-LABEL: load_i32_monotonic:
-; CHECK: i32.atomic.load acqrel 0
define i32 @load_i32_monotonic(ptr %p) {
+; CHECK-LABEL: load_i32_monotonic:
+; CHECK: .functype load_i32_monotonic (i32) -> (i32)
+; CHECK-NEXT: # %bb.0:
+; CHECK-NEXT: local.get 0
+; CHECK-NEXT: i32.atomic.load acqrel 0
+; CHECK-NEXT: # fallthrough-return
%v = load atomic i32, ptr %p monotonic, align 4
ret i32 %v
}
-; CHECK-LABEL: store_i32_monotonic:
-; CHECK: i32.atomic.store acqrel 0
define void @store_i32_monotonic(ptr %p, i32 %v) {
+; CHECK-LABEL: store_i32_monotonic:
+; CHECK: .functype store_i32_monotonic (i32, i32) -> ()
+; CHECK-NEXT: # %bb.0:
+; CHECK-NEXT: local.get 0
+; CHECK-NEXT: local.get 1
+; CHECK-NEXT: i32.atomic.store acqrel 0
+; CHECK-NEXT: # fallthrough-return
store atomic i32 %v, ptr %p monotonic, align 4
ret void
}
-; CHECK-LABEL: add_i32_release:
-; CHECK: i32.atomic.rmw.add acqrel 0
define i32 @add_i32_release(ptr %p, i32 %v) {
+; CHECK-LABEL: add_i32_release:
+; CHECK: .functype add_i32_release (i32, i32) -> (i32)
+; CHECK-NEXT: # %bb.0:
+; CHECK-NEXT: local.get 0
+; CHECK-NEXT: local.get 1
+; CHECK-NEXT: i32.atomic.rmw.add acqrel 0
+; CHECK-NEXT: # fallthrough-return
%old = atomicrmw add ptr %p, i32 %v release
ret i32 %old
}
-; CHECK-LABEL: add_i32_acquire:
-; CHECK: i32.atomic.rmw.add acqrel 0
define i32 @add_i32_acquire(ptr %p, i32 %v) {
+; CHECK-LABEL: add_i32_acquire:
+; CHECK: .functype add_i32_acquire (i32, i32) -> (i32)
+; CHECK-NEXT: # %bb.0:
+; CHECK-NEXT: local.get 0
+; CHECK-NEXT: local.get 1
+; CHECK-NEXT: i32.atomic.rmw.add acqrel 0
+; CHECK-NEXT: # fallthrough-return
%old = atomicrmw add ptr %p, i32 %v acquire
ret i32 %old
}
-; CHECK-LABEL: add_i32_monotonic:
-; CHECK: i32.atomic.rmw.add acqrel 0
define i32 @add_i32_monotonic(ptr %p, i32 %v) {
+; CHECK-LABEL: add_i32_monotonic:
+; CHECK: .functype add_i32_monotonic (i32, i32) -> (i32)
+; CHECK-NEXT: # %bb.0:
+; CHECK-NEXT: local.get 0
+; CHECK-NEXT: local.get 1
+; CHECK-NEXT: i32.atomic.rmw.add acqrel 0
+; CHECK-NEXT: # fallthrough-return
%old = atomicrmw add ptr %p, i32 %v monotonic
ret i32 %old
}
-; CHECK-LABEL: cmpxchg_i32_acq_rel_monotonic:
-; CHECK: i32.atomic.rmw.cmpxchg acqrel 0
define i32 @cmpxchg_i32_acq_rel_monotonic(ptr %p, i32 %exp, i32 %new) {
+; CHECK-LABEL: cmpxchg_i32_acq_rel_monotonic:
+; CHECK: .functype cmpxchg_i32_acq_rel_monotonic (i32, i32, i32) -> (i32)
+; CHECK-NEXT: # %bb.0:
+; CHECK-NEXT: local.get 0
+; CHECK-NEXT: local.get 1
+; CHECK-NEXT: local.get 2
+; CHECK-NEXT: i32.atomic.rmw.cmpxchg acqrel 0
+; CHECK-NEXT: # fallthrough-return
%pair = cmpxchg ptr %p, i32 %exp, i32 %new acq_rel monotonic
%val = extractvalue { i32, i1 } %pair, 0
ret i32 %val
}
-; CHECK-LABEL: cmpxchg_i32_release_monotonic:
-; CHECK: i32.atomic.rmw.cmpxchg acqrel 0
define i32 @cmpxchg_i32_release_monotonic(ptr %p, i32 %exp, i32 %new) {
+; CHECK-LABEL: cmpxchg_i32_release_monotonic:
+; CHECK: .functype cmpxchg_i32_release_monotonic (i32, i32, i32) -> (i32)
+; CHECK-NEXT: # %bb.0:
+; CHECK-NEXT: local.get 0
+; CHECK-NEXT: local.get 1
+; CHECK-NEXT: local.get 2
+; CHECK-NEXT: i32.atomic.rmw.cmpxchg acqrel 0
+; CHECK-NEXT: # fallthrough-return
%pair = cmpxchg ptr %p, i32 %exp, i32 %new release monotonic
%val = extractvalue { i32, i1 } %pair, 0
ret i32 %val
}
-; CHECK-LABEL: cmpxchg_i32_monotonic_monotonic:
-; CHECK: i32.atomic.rmw.cmpxchg acqrel 0
define i32 @cmpxchg_i32_monotonic_monotonic(ptr %p, i32 %exp, i32 %new) {
+; CHECK-LABEL: cmpxchg_i32_monotonic_monotonic:
+; CHECK: .functype cmpxchg_i32_monotonic_monotonic (i32, i32, i32) -> (i32)
+; CHECK-NEXT: # %bb.0:
+; CHECK-NEXT: local.get 0
+; CHECK-NEXT: local.get 1
+; CHECK-NEXT: local.get 2
+; CHECK-NEXT: i32.atomic.rmw.cmpxchg acqrel 0
+; CHECK-NEXT: # fallthrough-return
%pair = cmpxchg ptr %p, i32 %exp, i32 %new monotonic monotonic
%val = extractvalue { i32, i1 } %pair, 0
ret i32 %val
}
-; CHECK-LABEL: fence_release:
-; CHECK: atomic.fence acqrel
define void @fence_release() {
+; CHECK-LABEL: fence_release:
+; CHECK: .functype fence_release () -> ()
+; CHECK-NEXT: # %bb.0:
+; CHECK-NEXT: atomic.fence acqrel
+; CHECK-NEXT: # fallthrough-return
fence release
ret void
}
-; CHECK-LABEL: fence_acq_rel:
-; CHECK: atomic.fence acqrel
define void @fence_acq_rel() {
+; CHECK-LABEL: fence_acq_rel:
+; CHECK: .functype fence_acq_rel () -> ()
+; CHECK-NEXT: # %bb.0:
+; CHECK-NEXT: atomic.fence acqrel
+; CHECK-NEXT: # fallthrough-return
fence acq_rel
ret void
}
-
-
>From e52d41267f1a4813d58a6abfc5b014f76e0e37bb Mon Sep 17 00:00:00 2001
From: Derek Schuff <dschuff at chromium.org>
Date: Thu, 5 Mar 2026 21:44:17 +0000
Subject: [PATCH 6/9] add wasm64 test
---
.../CodeGen/WebAssembly/atomics-orderings.ll | 425 ++++++++++++------
1 file changed, 290 insertions(+), 135 deletions(-)
diff --git a/llvm/test/CodeGen/WebAssembly/atomics-orderings.ll b/llvm/test/CodeGen/WebAssembly/atomics-orderings.ll
index 9095d27493a8e..3cc623c8c329d 100644
--- a/llvm/test/CodeGen/WebAssembly/atomics-orderings.ll
+++ b/llvm/test/CodeGen/WebAssembly/atomics-orderings.ll
@@ -1,241 +1,396 @@
; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 6
-; RUN: llc < %s --mtriple=wasm32 -mattr=+atomics,+relaxed-atomics | FileCheck %s
+; RUN: llc < %s --mtriple=wasm32 -mattr=+atomics,+relaxed-atomics | FileCheck %s --check-prefixes=WASM32
+; RUN: llc < %s --mtriple=wasm64 -mattr=+atomics,+relaxed-atomics | FileCheck %s --check-prefixes=WASM64
define i32 @load_i32_acquire(ptr %p) {
-; CHECK-LABEL: load_i32_acquire:
-; CHECK: .functype load_i32_acquire (i32) -> (i32)
-; CHECK-NEXT: # %bb.0:
-; CHECK-NEXT: local.get 0
-; CHECK-NEXT: i32.atomic.load acqrel 0
-; CHECK-NEXT: # fallthrough-return
+; WASM32-LABEL: load_i32_acquire:
+; WASM32: .functype load_i32_acquire (i32) -> (i32)
+; WASM32-NEXT: # %bb.0:
+; WASM32-NEXT: local.get 0
+; WASM32-NEXT: i32.atomic.load acqrel 0
+; WASM32-NEXT: # fallthrough-return
+;
+; WASM64-LABEL: load_i32_acquire:
+; WASM64: .functype load_i32_acquire (i64) -> (i32)
+; WASM64-NEXT: # %bb.0:
+; WASM64-NEXT: local.get 0
+; WASM64-NEXT: i32.atomic.load acqrel 0
+; WASM64-NEXT: # fallthrough-return
%v = load atomic i32, ptr %p acquire, align 4
ret i32 %v
}
define i32 @load_i32_seq_cst(ptr %p) {
-; CHECK-LABEL: load_i32_seq_cst:
-; CHECK: .functype load_i32_seq_cst (i32) -> (i32)
-; CHECK-NEXT: # %bb.0:
-; CHECK-NEXT: local.get 0
-; CHECK-NEXT: i32.atomic.load seqcst 0
-; CHECK-NEXT: # fallthrough-return
+; WASM32-LABEL: load_i32_seq_cst:
+; WASM32: .functype load_i32_seq_cst (i32) -> (i32)
+; WASM32-NEXT: # %bb.0:
+; WASM32-NEXT: local.get 0
+; WASM32-NEXT: i32.atomic.load seqcst 0
+; WASM32-NEXT: # fallthrough-return
+;
+; WASM64-LABEL: load_i32_seq_cst:
+; WASM64: .functype load_i32_seq_cst (i64) -> (i32)
+; WASM64-NEXT: # %bb.0:
+; WASM64-NEXT: local.get 0
+; WASM64-NEXT: i32.atomic.load seqcst 0
+; WASM64-NEXT: # fallthrough-return
%v = load atomic i32, ptr %p seq_cst, align 4
ret i32 %v
}
define void @store_i32_release(ptr %p, i32 %v) {
-; CHECK-LABEL: store_i32_release:
-; CHECK: .functype store_i32_release (i32, i32) -> ()
-; CHECK-NEXT: # %bb.0:
-; CHECK-NEXT: local.get 0
-; CHECK-NEXT: local.get 1
-; CHECK-NEXT: i32.atomic.store acqrel 0
-; CHECK-NEXT: # fallthrough-return
+; WASM32-LABEL: store_i32_release:
+; WASM32: .functype store_i32_release (i32, i32) -> ()
+; WASM32-NEXT: # %bb.0:
+; WASM32-NEXT: local.get 0
+; WASM32-NEXT: local.get 1
+; WASM32-NEXT: i32.atomic.store acqrel 0
+; WASM32-NEXT: # fallthrough-return
+;
+; WASM64-LABEL: store_i32_release:
+; WASM64: .functype store_i32_release (i64, i32) -> ()
+; WASM64-NEXT: # %bb.0:
+; WASM64-NEXT: local.get 0
+; WASM64-NEXT: local.get 1
+; WASM64-NEXT: i32.atomic.store acqrel 0
+; WASM64-NEXT: # fallthrough-return
store atomic i32 %v, ptr %p release, align 4
ret void
}
define void @store_i32_seq_cst(ptr %p, i32 %v) {
-; CHECK-LABEL: store_i32_seq_cst:
-; CHECK: .functype store_i32_seq_cst (i32, i32) -> ()
-; CHECK-NEXT: # %bb.0:
-; CHECK-NEXT: local.get 0
-; CHECK-NEXT: local.get 1
-; CHECK-NEXT: i32.atomic.store seqcst 0
-; CHECK-NEXT: # fallthrough-return
+; WASM32-LABEL: store_i32_seq_cst:
+; WASM32: .functype store_i32_seq_cst (i32, i32) -> ()
+; WASM32-NEXT: # %bb.0:
+; WASM32-NEXT: local.get 0
+; WASM32-NEXT: local.get 1
+; WASM32-NEXT: i32.atomic.store seqcst 0
+; WASM32-NEXT: # fallthrough-return
+;
+; WASM64-LABEL: store_i32_seq_cst:
+; WASM64: .functype store_i32_seq_cst (i64, i32) -> ()
+; WASM64-NEXT: # %bb.0:
+; WASM64-NEXT: local.get 0
+; WASM64-NEXT: local.get 1
+; WASM64-NEXT: i32.atomic.store seqcst 0
+; WASM64-NEXT: # fallthrough-return
store atomic i32 %v, ptr %p seq_cst, align 4
ret void
}
define i32 @add_i32_acq_rel(ptr %p, i32 %v) {
-; CHECK-LABEL: add_i32_acq_rel:
-; CHECK: .functype add_i32_acq_rel (i32, i32) -> (i32)
-; CHECK-NEXT: # %bb.0:
-; CHECK-NEXT: local.get 0
-; CHECK-NEXT: local.get 1
-; CHECK-NEXT: i32.atomic.rmw.add acqrel 0
-; CHECK-NEXT: # fallthrough-return
+; WASM32-LABEL: add_i32_acq_rel:
+; WASM32: .functype add_i32_acq_rel (i32, i32) -> (i32)
+; WASM32-NEXT: # %bb.0:
+; WASM32-NEXT: local.get 0
+; WASM32-NEXT: local.get 1
+; WASM32-NEXT: i32.atomic.rmw.add acqrel 0
+; WASM32-NEXT: # fallthrough-return
+;
+; WASM64-LABEL: add_i32_acq_rel:
+; WASM64: .functype add_i32_acq_rel (i64, i32) -> (i32)
+; WASM64-NEXT: # %bb.0:
+; WASM64-NEXT: local.get 0
+; WASM64-NEXT: local.get 1
+; WASM64-NEXT: i32.atomic.rmw.add acqrel 0
+; WASM64-NEXT: # fallthrough-return
%old = atomicrmw add ptr %p, i32 %v acq_rel
ret i32 %old
}
define i32 @add_i32_seq_cst(ptr %p, i32 %v) {
-; CHECK-LABEL: add_i32_seq_cst:
-; CHECK: .functype add_i32_seq_cst (i32, i32) -> (i32)
-; CHECK-NEXT: # %bb.0:
-; CHECK-NEXT: local.get 0
-; CHECK-NEXT: local.get 1
-; CHECK-NEXT: i32.atomic.rmw.add seqcst 0
-; CHECK-NEXT: # fallthrough-return
+; WASM32-LABEL: add_i32_seq_cst:
+; WASM32: .functype add_i32_seq_cst (i32, i32) -> (i32)
+; WASM32-NEXT: # %bb.0:
+; WASM32-NEXT: local.get 0
+; WASM32-NEXT: local.get 1
+; WASM32-NEXT: i32.atomic.rmw.add seqcst 0
+; WASM32-NEXT: # fallthrough-return
+;
+; WASM64-LABEL: add_i32_seq_cst:
+; WASM64: .functype add_i32_seq_cst (i64, i32) -> (i32)
+; WASM64-NEXT: # %bb.0:
+; WASM64-NEXT: local.get 0
+; WASM64-NEXT: local.get 1
+; WASM64-NEXT: i32.atomic.rmw.add seqcst 0
+; WASM64-NEXT: # fallthrough-return
%old = atomicrmw add ptr %p, i32 %v seq_cst
ret i32 %old
}
define i32 @cmpxchg_i32_acquire_acquire(ptr %p, i32 %exp, i32 %new) {
-; CHECK-LABEL: cmpxchg_i32_acquire_acquire:
-; CHECK: .functype cmpxchg_i32_acquire_acquire (i32, i32, i32) -> (i32)
-; CHECK-NEXT: # %bb.0:
-; CHECK-NEXT: local.get 0
-; CHECK-NEXT: local.get 1
-; CHECK-NEXT: local.get 2
-; CHECK-NEXT: i32.atomic.rmw.cmpxchg acqrel 0
-; CHECK-NEXT: # fallthrough-return
+; WASM32-LABEL: cmpxchg_i32_acquire_acquire:
+; WASM32: .functype cmpxchg_i32_acquire_acquire (i32, i32, i32) -> (i32)
+; WASM32-NEXT: # %bb.0:
+; WASM32-NEXT: local.get 0
+; WASM32-NEXT: local.get 1
+; WASM32-NEXT: local.get 2
+; WASM32-NEXT: i32.atomic.rmw.cmpxchg acqrel 0
+; WASM32-NEXT: # fallthrough-return
+;
+; WASM64-LABEL: cmpxchg_i32_acquire_acquire:
+; WASM64: .functype cmpxchg_i32_acquire_acquire (i64, i32, i32) -> (i32)
+; WASM64-NEXT: # %bb.0:
+; WASM64-NEXT: local.get 0
+; WASM64-NEXT: local.get 1
+; WASM64-NEXT: local.get 2
+; WASM64-NEXT: i32.atomic.rmw.cmpxchg acqrel 0
+; WASM64-NEXT: # fallthrough-return
%pair = cmpxchg ptr %p, i32 %exp, i32 %new acquire acquire
%val = extractvalue { i32, i1 } %pair, 0
ret i32 %val
}
define i32 @cmpxchg_i32_seq_cst_seq_cst(ptr %p, i32 %exp, i32 %new) {
-; CHECK-LABEL: cmpxchg_i32_seq_cst_seq_cst:
-; CHECK: .functype cmpxchg_i32_seq_cst_seq_cst (i32, i32, i32) -> (i32)
-; CHECK-NEXT: # %bb.0:
-; CHECK-NEXT: local.get 0
-; CHECK-NEXT: local.get 1
-; CHECK-NEXT: local.get 2
-; CHECK-NEXT: i32.atomic.rmw.cmpxchg seqcst 0
-; CHECK-NEXT: # fallthrough-return
+; WASM32-LABEL: cmpxchg_i32_seq_cst_seq_cst:
+; WASM32: .functype cmpxchg_i32_seq_cst_seq_cst (i32, i32, i32) -> (i32)
+; WASM32-NEXT: # %bb.0:
+; WASM32-NEXT: local.get 0
+; WASM32-NEXT: local.get 1
+; WASM32-NEXT: local.get 2
+; WASM32-NEXT: i32.atomic.rmw.cmpxchg seqcst 0
+; WASM32-NEXT: # fallthrough-return
+;
+; WASM64-LABEL: cmpxchg_i32_seq_cst_seq_cst:
+; WASM64: .functype cmpxchg_i32_seq_cst_seq_cst (i64, i32, i32) -> (i32)
+; WASM64-NEXT: # %bb.0:
+; WASM64-NEXT: local.get 0
+; WASM64-NEXT: local.get 1
+; WASM64-NEXT: local.get 2
+; WASM64-NEXT: i32.atomic.rmw.cmpxchg seqcst 0
+; WASM64-NEXT: # fallthrough-return
%pair = cmpxchg ptr %p, i32 %exp, i32 %new seq_cst seq_cst
%val = extractvalue { i32, i1 } %pair, 0
ret i32 %val
}
define void @fence_acquire() {
-; CHECK-LABEL: fence_acquire:
-; CHECK: .functype fence_acquire () -> ()
-; CHECK-NEXT: # %bb.0:
-; CHECK-NEXT: atomic.fence acqrel
-; CHECK-NEXT: # fallthrough-return
+; WASM32-LABEL: fence_acquire:
+; WASM32: .functype fence_acquire () -> ()
+; WASM32-NEXT: # %bb.0:
+; WASM32-NEXT: atomic.fence acqrel
+; WASM32-NEXT: # fallthrough-return
+;
+; WASM64-LABEL: fence_acquire:
+; WASM64: .functype fence_acquire () -> ()
+; WASM64-NEXT: # %bb.0:
+; WASM64-NEXT: atomic.fence acqrel
+; WASM64-NEXT: # fallthrough-return
fence acquire
ret void
}
define void @fence_seq_cst() {
-; CHECK-LABEL: fence_seq_cst:
-; CHECK: .functype fence_seq_cst () -> ()
-; CHECK-NEXT: # %bb.0:
-; CHECK-NEXT: atomic.fence seqcst
-; CHECK-NEXT: # fallthrough-return
+; WASM32-LABEL: fence_seq_cst:
+; WASM32: .functype fence_seq_cst () -> ()
+; WASM32-NEXT: # %bb.0:
+; WASM32-NEXT: atomic.fence seqcst
+; WASM32-NEXT: # fallthrough-return
+;
+; WASM64-LABEL: fence_seq_cst:
+; WASM64: .functype fence_seq_cst () -> ()
+; WASM64-NEXT: # %bb.0:
+; WASM64-NEXT: atomic.fence seqcst
+; WASM64-NEXT: # fallthrough-return
fence seq_cst
ret void
}
define i32 @load_i32_monotonic(ptr %p) {
-; CHECK-LABEL: load_i32_monotonic:
-; CHECK: .functype load_i32_monotonic (i32) -> (i32)
-; CHECK-NEXT: # %bb.0:
-; CHECK-NEXT: local.get 0
-; CHECK-NEXT: i32.atomic.load acqrel 0
-; CHECK-NEXT: # fallthrough-return
+; WASM32-LABEL: load_i32_monotonic:
+; WASM32: .functype load_i32_monotonic (i32) -> (i32)
+; WASM32-NEXT: # %bb.0:
+; WASM32-NEXT: local.get 0
+; WASM32-NEXT: i32.atomic.load acqrel 0
+; WASM32-NEXT: # fallthrough-return
+;
+; WASM64-LABEL: load_i32_monotonic:
+; WASM64: .functype load_i32_monotonic (i64) -> (i32)
+; WASM64-NEXT: # %bb.0:
+; WASM64-NEXT: local.get 0
+; WASM64-NEXT: i32.atomic.load acqrel 0
+; WASM64-NEXT: # fallthrough-return
%v = load atomic i32, ptr %p monotonic, align 4
ret i32 %v
}
define void @store_i32_monotonic(ptr %p, i32 %v) {
-; CHECK-LABEL: store_i32_monotonic:
-; CHECK: .functype store_i32_monotonic (i32, i32) -> ()
-; CHECK-NEXT: # %bb.0:
-; CHECK-NEXT: local.get 0
-; CHECK-NEXT: local.get 1
-; CHECK-NEXT: i32.atomic.store acqrel 0
-; CHECK-NEXT: # fallthrough-return
+; WASM32-LABEL: store_i32_monotonic:
+; WASM32: .functype store_i32_monotonic (i32, i32) -> ()
+; WASM32-NEXT: # %bb.0:
+; WASM32-NEXT: local.get 0
+; WASM32-NEXT: local.get 1
+; WASM32-NEXT: i32.atomic.store acqrel 0
+; WASM32-NEXT: # fallthrough-return
+;
+; WASM64-LABEL: store_i32_monotonic:
+; WASM64: .functype store_i32_monotonic (i64, i32) -> ()
+; WASM64-NEXT: # %bb.0:
+; WASM64-NEXT: local.get 0
+; WASM64-NEXT: local.get 1
+; WASM64-NEXT: i32.atomic.store acqrel 0
+; WASM64-NEXT: # fallthrough-return
store atomic i32 %v, ptr %p monotonic, align 4
ret void
}
define i32 @add_i32_release(ptr %p, i32 %v) {
-; CHECK-LABEL: add_i32_release:
-; CHECK: .functype add_i32_release (i32, i32) -> (i32)
-; CHECK-NEXT: # %bb.0:
-; CHECK-NEXT: local.get 0
-; CHECK-NEXT: local.get 1
-; CHECK-NEXT: i32.atomic.rmw.add acqrel 0
-; CHECK-NEXT: # fallthrough-return
+; WASM32-LABEL: add_i32_release:
+; WASM32: .functype add_i32_release (i32, i32) -> (i32)
+; WASM32-NEXT: # %bb.0:
+; WASM32-NEXT: local.get 0
+; WASM32-NEXT: local.get 1
+; WASM32-NEXT: i32.atomic.rmw.add acqrel 0
+; WASM32-NEXT: # fallthrough-return
+;
+; WASM64-LABEL: add_i32_release:
+; WASM64: .functype add_i32_release (i64, i32) -> (i32)
+; WASM64-NEXT: # %bb.0:
+; WASM64-NEXT: local.get 0
+; WASM64-NEXT: local.get 1
+; WASM64-NEXT: i32.atomic.rmw.add acqrel 0
+; WASM64-NEXT: # fallthrough-return
%old = atomicrmw add ptr %p, i32 %v release
ret i32 %old
}
define i32 @add_i32_acquire(ptr %p, i32 %v) {
-; CHECK-LABEL: add_i32_acquire:
-; CHECK: .functype add_i32_acquire (i32, i32) -> (i32)
-; CHECK-NEXT: # %bb.0:
-; CHECK-NEXT: local.get 0
-; CHECK-NEXT: local.get 1
-; CHECK-NEXT: i32.atomic.rmw.add acqrel 0
-; CHECK-NEXT: # fallthrough-return
+; WASM32-LABEL: add_i32_acquire:
+; WASM32: .functype add_i32_acquire (i32, i32) -> (i32)
+; WASM32-NEXT: # %bb.0:
+; WASM32-NEXT: local.get 0
+; WASM32-NEXT: local.get 1
+; WASM32-NEXT: i32.atomic.rmw.add acqrel 0
+; WASM32-NEXT: # fallthrough-return
+;
+; WASM64-LABEL: add_i32_acquire:
+; WASM64: .functype add_i32_acquire (i64, i32) -> (i32)
+; WASM64-NEXT: # %bb.0:
+; WASM64-NEXT: local.get 0
+; WASM64-NEXT: local.get 1
+; WASM64-NEXT: i32.atomic.rmw.add acqrel 0
+; WASM64-NEXT: # fallthrough-return
%old = atomicrmw add ptr %p, i32 %v acquire
ret i32 %old
}
define i32 @add_i32_monotonic(ptr %p, i32 %v) {
-; CHECK-LABEL: add_i32_monotonic:
-; CHECK: .functype add_i32_monotonic (i32, i32) -> (i32)
-; CHECK-NEXT: # %bb.0:
-; CHECK-NEXT: local.get 0
-; CHECK-NEXT: local.get 1
-; CHECK-NEXT: i32.atomic.rmw.add acqrel 0
-; CHECK-NEXT: # fallthrough-return
+; WASM32-LABEL: add_i32_monotonic:
+; WASM32: .functype add_i32_monotonic (i32, i32) -> (i32)
+; WASM32-NEXT: # %bb.0:
+; WASM32-NEXT: local.get 0
+; WASM32-NEXT: local.get 1
+; WASM32-NEXT: i32.atomic.rmw.add acqrel 0
+; WASM32-NEXT: # fallthrough-return
+;
+; WASM64-LABEL: add_i32_monotonic:
+; WASM64: .functype add_i32_monotonic (i64, i32) -> (i32)
+; WASM64-NEXT: # %bb.0:
+; WASM64-NEXT: local.get 0
+; WASM64-NEXT: local.get 1
+; WASM64-NEXT: i32.atomic.rmw.add acqrel 0
+; WASM64-NEXT: # fallthrough-return
%old = atomicrmw add ptr %p, i32 %v monotonic
ret i32 %old
}
define i32 @cmpxchg_i32_acq_rel_monotonic(ptr %p, i32 %exp, i32 %new) {
-; CHECK-LABEL: cmpxchg_i32_acq_rel_monotonic:
-; CHECK: .functype cmpxchg_i32_acq_rel_monotonic (i32, i32, i32) -> (i32)
-; CHECK-NEXT: # %bb.0:
-; CHECK-NEXT: local.get 0
-; CHECK-NEXT: local.get 1
-; CHECK-NEXT: local.get 2
-; CHECK-NEXT: i32.atomic.rmw.cmpxchg acqrel 0
-; CHECK-NEXT: # fallthrough-return
+; WASM32-LABEL: cmpxchg_i32_acq_rel_monotonic:
+; WASM32: .functype cmpxchg_i32_acq_rel_monotonic (i32, i32, i32) -> (i32)
+; WASM32-NEXT: # %bb.0:
+; WASM32-NEXT: local.get 0
+; WASM32-NEXT: local.get 1
+; WASM32-NEXT: local.get 2
+; WASM32-NEXT: i32.atomic.rmw.cmpxchg acqrel 0
+; WASM32-NEXT: # fallthrough-return
+;
+; WASM64-LABEL: cmpxchg_i32_acq_rel_monotonic:
+; WASM64: .functype cmpxchg_i32_acq_rel_monotonic (i64, i32, i32) -> (i32)
+; WASM64-NEXT: # %bb.0:
+; WASM64-NEXT: local.get 0
+; WASM64-NEXT: local.get 1
+; WASM64-NEXT: local.get 2
+; WASM64-NEXT: i32.atomic.rmw.cmpxchg acqrel 0
+; WASM64-NEXT: # fallthrough-return
%pair = cmpxchg ptr %p, i32 %exp, i32 %new acq_rel monotonic
%val = extractvalue { i32, i1 } %pair, 0
ret i32 %val
}
define i32 @cmpxchg_i32_release_monotonic(ptr %p, i32 %exp, i32 %new) {
-; CHECK-LABEL: cmpxchg_i32_release_monotonic:
-; CHECK: .functype cmpxchg_i32_release_monotonic (i32, i32, i32) -> (i32)
-; CHECK-NEXT: # %bb.0:
-; CHECK-NEXT: local.get 0
-; CHECK-NEXT: local.get 1
-; CHECK-NEXT: local.get 2
-; CHECK-NEXT: i32.atomic.rmw.cmpxchg acqrel 0
-; CHECK-NEXT: # fallthrough-return
+; WASM32-LABEL: cmpxchg_i32_release_monotonic:
+; WASM32: .functype cmpxchg_i32_release_monotonic (i32, i32, i32) -> (i32)
+; WASM32-NEXT: # %bb.0:
+; WASM32-NEXT: local.get 0
+; WASM32-NEXT: local.get 1
+; WASM32-NEXT: local.get 2
+; WASM32-NEXT: i32.atomic.rmw.cmpxchg acqrel 0
+; WASM32-NEXT: # fallthrough-return
+;
+; WASM64-LABEL: cmpxchg_i32_release_monotonic:
+; WASM64: .functype cmpxchg_i32_release_monotonic (i64, i32, i32) -> (i32)
+; WASM64-NEXT: # %bb.0:
+; WASM64-NEXT: local.get 0
+; WASM64-NEXT: local.get 1
+; WASM64-NEXT: local.get 2
+; WASM64-NEXT: i32.atomic.rmw.cmpxchg acqrel 0
+; WASM64-NEXT: # fallthrough-return
%pair = cmpxchg ptr %p, i32 %exp, i32 %new release monotonic
%val = extractvalue { i32, i1 } %pair, 0
ret i32 %val
}
define i32 @cmpxchg_i32_monotonic_monotonic(ptr %p, i32 %exp, i32 %new) {
-; CHECK-LABEL: cmpxchg_i32_monotonic_monotonic:
-; CHECK: .functype cmpxchg_i32_monotonic_monotonic (i32, i32, i32) -> (i32)
-; CHECK-NEXT: # %bb.0:
-; CHECK-NEXT: local.get 0
-; CHECK-NEXT: local.get 1
-; CHECK-NEXT: local.get 2
-; CHECK-NEXT: i32.atomic.rmw.cmpxchg acqrel 0
-; CHECK-NEXT: # fallthrough-return
+; WASM32-LABEL: cmpxchg_i32_monotonic_monotonic:
+; WASM32: .functype cmpxchg_i32_monotonic_monotonic (i32, i32, i32) -> (i32)
+; WASM32-NEXT: # %bb.0:
+; WASM32-NEXT: local.get 0
+; WASM32-NEXT: local.get 1
+; WASM32-NEXT: local.get 2
+; WASM32-NEXT: i32.atomic.rmw.cmpxchg acqrel 0
+; WASM32-NEXT: # fallthrough-return
+;
+; WASM64-LABEL: cmpxchg_i32_monotonic_monotonic:
+; WASM64: .functype cmpxchg_i32_monotonic_monotonic (i64, i32, i32) -> (i32)
+; WASM64-NEXT: # %bb.0:
+; WASM64-NEXT: local.get 0
+; WASM64-NEXT: local.get 1
+; WASM64-NEXT: local.get 2
+; WASM64-NEXT: i32.atomic.rmw.cmpxchg acqrel 0
+; WASM64-NEXT: # fallthrough-return
%pair = cmpxchg ptr %p, i32 %exp, i32 %new monotonic monotonic
%val = extractvalue { i32, i1 } %pair, 0
ret i32 %val
}
define void @fence_release() {
-; CHECK-LABEL: fence_release:
-; CHECK: .functype fence_release () -> ()
-; CHECK-NEXT: # %bb.0:
-; CHECK-NEXT: atomic.fence acqrel
-; CHECK-NEXT: # fallthrough-return
+; WASM32-LABEL: fence_release:
+; WASM32: .functype fence_release () -> ()
+; WASM32-NEXT: # %bb.0:
+; WASM32-NEXT: atomic.fence acqrel
+; WASM32-NEXT: # fallthrough-return
+;
+; WASM64-LABEL: fence_release:
+; WASM64: .functype fence_release () -> ()
+; WASM64-NEXT: # %bb.0:
+; WASM64-NEXT: atomic.fence acqrel
+; WASM64-NEXT: # fallthrough-return
fence release
ret void
}
define void @fence_acq_rel() {
-; CHECK-LABEL: fence_acq_rel:
-; CHECK: .functype fence_acq_rel () -> ()
-; CHECK-NEXT: # %bb.0:
-; CHECK-NEXT: atomic.fence acqrel
-; CHECK-NEXT: # fallthrough-return
+; WASM32-LABEL: fence_acq_rel:
+; WASM32: .functype fence_acq_rel () -> ()
+; WASM32-NEXT: # %bb.0:
+; WASM32-NEXT: atomic.fence acqrel
+; WASM32-NEXT: # fallthrough-return
+;
+; WASM64-LABEL: fence_acq_rel:
+; WASM64: .functype fence_acq_rel () -> ()
+; WASM64-NEXT: # %bb.0:
+; WASM64-NEXT: atomic.fence acqrel
+; WASM64-NEXT: # fallthrough-return
fence acq_rel
ret void
}
>From cd9e18078acb1201d41f1b2b4cc3a99edd154a67 Mon Sep 17 00:00:00 2001
From: Derek Schuff <dschuff at chromium.org>
Date: Thu, 5 Mar 2026 21:46:00 +0000
Subject: [PATCH 7/9] split clang change out from this one
---
clang/include/clang/Options/Options.td | 2 --
clang/lib/Basic/Targets/WebAssembly.cpp | 11 -----------
clang/lib/Basic/Targets/WebAssembly.h | 1 -
clang/test/Driver/wasm-features.c | 6 ------
clang/test/Preprocessor/wasm-target-features.c | 11 -----------
5 files changed, 31 deletions(-)
diff --git a/clang/include/clang/Options/Options.td b/clang/include/clang/Options/Options.td
index 9d3ec8a173472..fe7169423b6bf 100644
--- a/clang/include/clang/Options/Options.td
+++ b/clang/include/clang/Options/Options.td
@@ -5688,8 +5688,6 @@ def mnontrapping_fptoint : Flag<["-"], "mnontrapping-fptoint">, Group<m_wasm_Fea
def mno_nontrapping_fptoint : Flag<["-"], "mno-nontrapping-fptoint">, Group<m_wasm_Features_Group>;
def mreference_types : Flag<["-"], "mreference-types">, Group<m_wasm_Features_Group>;
def mno_reference_types : Flag<["-"], "mno-reference-types">, Group<m_wasm_Features_Group>;
-def mrelaxed_atomics : Flag<["-"], "mrelaxed-atomics">, Group<m_wasm_Features_Group>;
-def mno_relaxed_atomics : Flag<["-"], "mno-relaxed-atomics">, Group<m_wasm_Features_Group>;
def mrelaxed_simd : Flag<["-"], "mrelaxed-simd">, Group<m_wasm_Features_Group>;
def mno_relaxed_simd : Flag<["-"], "mno-relaxed-simd">, Group<m_wasm_Features_Group>;
def msign_ext : Flag<["-"], "msign-ext">, Group<m_wasm_Features_Group>;
diff --git a/clang/lib/Basic/Targets/WebAssembly.cpp b/clang/lib/Basic/Targets/WebAssembly.cpp
index 4bb3d521cd9fd..daaefd9a1267c 100644
--- a/clang/lib/Basic/Targets/WebAssembly.cpp
+++ b/clang/lib/Basic/Targets/WebAssembly.cpp
@@ -66,7 +66,6 @@ bool WebAssemblyTargetInfo::hasFeature(StringRef Feature) const {
.Case("mutable-globals", HasMutableGlobals)
.Case("nontrapping-fptoint", HasNontrappingFPToInt)
.Case("reference-types", HasReferenceTypes)
- .Case("relaxed-atomics", HasRelaxedAtomics)
.Case("relaxed-simd", SIMDLevel >= RelaxedSIMD)
.Case("sign-ext", HasSignExt)
.Case("simd128", SIMDLevel >= SIMD128)
@@ -111,8 +110,6 @@ void WebAssemblyTargetInfo::getTargetDefines(const LangOptions &Opts,
Builder.defineMacro("__wasm_nontrapping_fptoint__");
if (HasReferenceTypes)
Builder.defineMacro("__wasm_reference_types__");
- if (HasRelaxedAtomics)
- Builder.defineMacro("__wasm_relaxed_atomics__");
if (SIMDLevel >= RelaxedSIMD)
Builder.defineMacro("__wasm_relaxed_simd__");
if (HasSignExt)
@@ -335,14 +332,6 @@ bool WebAssemblyTargetInfo::handleTargetFeatures(
HasReferenceTypes = false;
continue;
}
- if (Feature == "+relaxed-atomics") {
- HasRelaxedAtomics = true;
- continue;
- }
- if (Feature == "-relaxed-atomics") {
- HasRelaxedAtomics = false;
- continue;
- }
if (Feature == "+relaxed-simd") {
SIMDLevel = std::max(SIMDLevel, RelaxedSIMD);
continue;
diff --git a/clang/lib/Basic/Targets/WebAssembly.h b/clang/lib/Basic/Targets/WebAssembly.h
index 8128dd96068a0..3a0823bd717d9 100644
--- a/clang/lib/Basic/Targets/WebAssembly.h
+++ b/clang/lib/Basic/Targets/WebAssembly.h
@@ -72,7 +72,6 @@ class LLVM_LIBRARY_VISIBILITY WebAssemblyTargetInfo : public TargetInfo {
bool HasMutableGlobals = false;
bool HasNontrappingFPToInt = false;
bool HasReferenceTypes = false;
- bool HasRelaxedAtomics = false;
bool HasSignExt = false;
bool HasTailCall = false;
bool HasWideArithmetic = false;
diff --git a/clang/test/Driver/wasm-features.c b/clang/test/Driver/wasm-features.c
index 9e523aa5b53b6..89ced36eeffab 100644
--- a/clang/test/Driver/wasm-features.c
+++ b/clang/test/Driver/wasm-features.c
@@ -77,12 +77,6 @@
// REFERENCE-TYPES: "-target-feature" "+reference-types"
// NO-REFERENCE-TYPES: "-target-feature" "-reference-types"
-// RUN: %clang --target=wasm32-unknown-unknown -### %s -mrelaxed-atomics 2>&1 | FileCheck %s -check-prefix=RELAXED-ATOMICS
-// RUN: %clang --target=wasm32-unknown-unknown -### %s -mno-relaxed-atomics 2>&1 | FileCheck %s -check-prefix=NO-RELAXED-ATOMICS
-
-// RELAXED-ATOMICS: "-target-feature" "+relaxed-atomics"
-// NO-RELAXED-ATOMICS: "-target-feature" "-relaxed-atomics"
-
// RUN: %clang --target=wasm32-unknown-unknown -### %s -mrelaxed-simd 2>&1 | FileCheck %s -check-prefix=RELAXED-SIMD
// RUN: %clang --target=wasm32-unknown-unknown -### %s -mno-relaxed-simd 2>&1 | FileCheck %s -check-prefix=NO-RELAXED-SIMD
diff --git a/clang/test/Preprocessor/wasm-target-features.c b/clang/test/Preprocessor/wasm-target-features.c
index aff7442773531..3edaf9e7cd594 100644
--- a/clang/test/Preprocessor/wasm-target-features.c
+++ b/clang/test/Preprocessor/wasm-target-features.c
@@ -106,15 +106,6 @@
//
// REFERENCE-TYPES: #define __wasm_reference_types__ 1{{$}}
-// RUN: %clang -E -dM %s -o - 2>&1 \
-// RUN: -target wasm32-unknown-unknown -mrelaxed-atomics \
-// RUN: | FileCheck %s -check-prefix=RELAXED-ATOMICS
-// RUN: %clang -E -dM %s -o - 2>&1 \
-// RUN: -target wasm64-unknown-unknown -mrelaxed-atomics \
-// RUN: | FileCheck %s -check-prefix=RELAXED-ATOMICS
-//
-// RELAXED-ATOMICS: #define __wasm_relaxed_atomics__ 1{{$}}
-
// RUN: %clang -E -dM %s -o - 2>&1 \
// RUN: -target wasm32-unknown-unknown -mrelaxed-simd \
// RUN: | FileCheck %s -check-prefix=RELAXED-SIMD
@@ -169,7 +160,6 @@
// MVP-NOT: #define __wasm_mutable_globals__ 1{{$}}
// MVP-NOT: #define __wasm_nontrapping_fptoint__ 1{{$}}
// MVP-NOT: #define __wasm_reference_types__ 1{{$}}
-// MVP-NOT: #define __wasm_relaxed_atomics__ 1{{$}}
// MVP-NOT: #define __wasm_relaxed_simd__ 1{{$}}
// MVP-NOT: #define __wasm_sign_ext__ 1{{$}}
// MVP-NOT: #define __wasm_simd128__ 1{{$}}
@@ -203,7 +193,6 @@
// GENERIC-NOT: #define __wasm__fp16__ 1{{$}}
// GENERIC-NOT: #define __wasm_gc__ 1{{$}}
// GENERIC-NOT: #define __wasm_multimemory__ 1{{$}}
-// GENERIC-NOT: #define __wasm_relaxed_atomics__ 1{{$}}
// GENERIC-NOT: #define __wasm_relaxed_simd__ 1{{$}}
// GENERIC-NOT: #define __wasm_simd128__ 1{{$}}
// GENERIC-NOT: #define __wasm_tail_call__ 1{{$}}
>From 74fa381b9b9bcafc73818ea2b62c50f8c03dd132 Mon Sep 17 00:00:00 2001
From: Derek Schuff <dschuff at chromium.org>
Date: Thu, 5 Mar 2026 21:56:31 +0000
Subject: [PATCH 8/9] clean up FixupAtomics
---
.../WebAssembly/WebAssemblyFixupAtomics.cpp | 48 +++++++++----------
1 file changed, 24 insertions(+), 24 deletions(-)
diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyFixupAtomics.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyFixupAtomics.cpp
index 565feb79af9ec..cf00e5f88733b 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblyFixupAtomics.cpp
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyFixupAtomics.cpp
@@ -57,36 +57,36 @@ bool WebAssemblyFixupAtomics::runOnMachineFunction(MachineFunction &MF) {
<< "********** Function: " << MF.getName() << '\n');
bool Changed = false;
- const auto &Subtarget = MF.getSubtarget<WebAssemblySubtarget>();
- bool HasRelaxedAtomics = Subtarget.hasRelaxedAtomics();
+ if (!MF.getSubtarget<WebAssemblySubtarget>().hasRelaxedAtomics())
+ return Changed;
for (auto &MBB : MF) {
for (auto &MI : MBB) {
const MCInstrDesc &Desc = MI.getDesc();
for (unsigned I = 0, E = MI.getNumExplicitOperands(); I < E; ++I) {
if (I < Desc.getNumOperands() &&
- Desc.operands()[I].OperandType == WebAssembly::OPERAND_MEMORDER) {
-
- if (HasRelaxedAtomics && !MI.memoperands_empty()) {
- assert(MI.getOperand(I).getImm() == wasm::WASM_MEM_ORDER_SEQ_CST &&
- "Expected seqcst default atomics from ISel");
- unsigned Order = wasm::WASM_MEM_ORDER_SEQ_CST;
- auto *MMO = *MI.memoperands_begin();
- switch (MMO->getMergedOrdering()) {
- case AtomicOrdering::Acquire:
- case AtomicOrdering::Release:
- case AtomicOrdering::AcquireRelease:
- case AtomicOrdering::Monotonic:
- Order = wasm::WASM_MEM_ORDER_ACQ_REL;
- break;
- default:
- Order = wasm::WASM_MEM_ORDER_SEQ_CST;
- break;
- }
- if (MI.getOperand(I).getImm() != Order) {
- MI.getOperand(I).setImm(Order);
- Changed = true;
- }
+ Desc.operands()[I].OperandType == WebAssembly::OPERAND_MEMORDER &&
+ // Fences are already selected with the correct ordering.
+ MI.getOpcode() != WebAssembly::ATOMIC_FENCE) {
+ assert(MI.getOperand(I).getImm() == wasm::WASM_MEM_ORDER_SEQ_CST &&
+ "Expected seqcst default atomics from ISel");
+ assert(!MI.memoperands_empty());
+ unsigned Order = wasm::WASM_MEM_ORDER_SEQ_CST;
+ auto *MMO = *MI.memoperands_begin();
+ switch (MMO->getMergedOrdering()) {
+ case AtomicOrdering::Acquire:
+ case AtomicOrdering::Release:
+ case AtomicOrdering::AcquireRelease:
+ case AtomicOrdering::Monotonic:
+ Order = wasm::WASM_MEM_ORDER_ACQ_REL;
+ break;
+ default:
+ Order = wasm::WASM_MEM_ORDER_SEQ_CST;
+ break;
+ }
+ if (MI.getOperand(I).getImm() != Order) {
+ MI.getOperand(I).setImm(Order);
+ Changed = true;
}
}
}
>From 737f2e60978ce091406a77cae648593d29dd2d52 Mon Sep 17 00:00:00 2001
From: Derek Schuff <dschuff at chromium.org>
Date: Fri, 6 Mar 2026 17:57:37 +0000
Subject: [PATCH 9/9] Apply suggestions; merge atomics-orderings.ll with
atomic-mem-consistency.ll and atomic-fence.ll
---
.../WebAssembly/WebAssemblyFixupAtomics.cpp | 11 +-
.../WebAssembly/WebAssemblyISelDAGToDAG.cpp | 5 +-
llvm/test/CodeGen/WebAssembly/atomic-fence.ll | 144 ++-
.../WebAssembly/atomic-mem-consistency.ll | 945 ++++++++++++++++--
.../CodeGen/WebAssembly/atomics-orderings.ll | 396 --------
5 files changed, 990 insertions(+), 511 deletions(-)
delete mode 100644 llvm/test/CodeGen/WebAssembly/atomics-orderings.ll
diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyFixupAtomics.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyFixupAtomics.cpp
index cf00e5f88733b..7730175d1b185 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblyFixupAtomics.cpp
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyFixupAtomics.cpp
@@ -11,8 +11,8 @@
///
/// This is used because ISel selects atomics with a default value for the
/// memory ordering immediate operand. Even though we run this pass early in
-/// the MI pass pipeline, MI passes should still use getMergedOrdering() on
-/// the MachineMemOperand to get the ordering rther than the immediate.
+/// the MI pass pipeline, later MI passes should still use getMergedOrdering()
+/// on the MachineMemOperand to get the ordering rather than the immediate.
///
//===----------------------------------------------------------------------===//
@@ -74,15 +74,18 @@ bool WebAssemblyFixupAtomics::runOnMachineFunction(MachineFunction &MF) {
unsigned Order = wasm::WASM_MEM_ORDER_SEQ_CST;
auto *MMO = *MI.memoperands_begin();
switch (MMO->getMergedOrdering()) {
+ case AtomicOrdering::Unordered:
+ case AtomicOrdering::Monotonic:
case AtomicOrdering::Acquire:
case AtomicOrdering::Release:
case AtomicOrdering::AcquireRelease:
- case AtomicOrdering::Monotonic:
Order = wasm::WASM_MEM_ORDER_ACQ_REL;
break;
- default:
+ case AtomicOrdering::SequentiallyConsistent:
Order = wasm::WASM_MEM_ORDER_SEQ_CST;
break;
+ default:
+ report_fatal_error("Atomic instructions cannot have NotAtomic ordering");
}
if (MI.getOperand(I).getImm() != Order) {
MI.getOperand(I).setImm(Order);
diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyISelDAGToDAG.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyISelDAGToDAG.cpp
index e1f7e51f2af34..e7c8e1776a7de 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblyISelDAGToDAG.cpp
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyISelDAGToDAG.cpp
@@ -215,12 +215,13 @@ void WebAssemblyDAGToDAGISel::Select(SDNode *Node) {
case AtomicOrdering::Acquire:
case AtomicOrdering::Release:
case AtomicOrdering::AcquireRelease:
- case AtomicOrdering::Monotonic:
Order = wasm::WASM_MEM_ORDER_ACQ_REL;
break;
- default:
+ case AtomicOrdering::SequentiallyConsistent:
Order = wasm::WASM_MEM_ORDER_SEQ_CST;
break;
+ default:
+ llvm_unreachable("Invalid ordering for atomic fence");
}
}
Fence = CurDAG->getMachineNode(
diff --git a/llvm/test/CodeGen/WebAssembly/atomic-fence.ll b/llvm/test/CodeGen/WebAssembly/atomic-fence.ll
index 8fed309bcce00..5df28f2cdcd8d 100644
--- a/llvm/test/CodeGen/WebAssembly/atomic-fence.ll
+++ b/llvm/test/CodeGen/WebAssembly/atomic-fence.ll
@@ -1,36 +1,140 @@
-; RUN: llc < %s | FileCheck %s --check-prefix NOATOMIC
-; RUN: llc < %s -asm-verbose=false -wasm-disable-explicit-locals -wasm-keep-registers -mattr=+atomics | FileCheck %s
-
-target triple = "wasm32-unknown-unknown"
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 6
+; RUN: llc < %s --mtriple=wasm32 | FileCheck %s --check-prefixes=NO-ATOMICS
+; RUN: llc < %s --mtriple=wasm32 -mattr=+atomics | FileCheck %s --check-prefixes=ATOMICS
+; RUN: llc < %s --mtriple=wasm32 -mattr=+atomics,+relaxed-atomics | FileCheck %s --check-prefixes=RELAXED32
+; RUN: llc < %s --mtriple=wasm64 -mattr=+atomics,+relaxed-atomics | FileCheck %s --check-prefixes=RELAXED64
; A multithread fence is lowered to an atomic.fence instruction.
-; CHECK-LABEL: multithread_fence:
-; CHECK: atomic.fence
-; NOATOMIC-NOT: i32.atomic.rmw.or
-define void @multithread_fence() {
- fence seq_cst
+define void @fence_acquire() {
+; NO-ATOMICS-LABEL: fence_acquire:
+; NO-ATOMICS: .functype fence_acquire () -> ()
+; NO-ATOMICS-NEXT: # %bb.0:
+; NO-ATOMICS-NEXT: # fallthrough-return
+;
+; ATOMICS-LABEL: fence_acquire:
+; ATOMICS: .functype fence_acquire () -> ()
+; ATOMICS-NEXT: # %bb.0:
+; ATOMICS-NEXT: atomic.fence
+; ATOMICS-NEXT: # fallthrough-return
+;
+; RELAXED32-LABEL: fence_acquire:
+; RELAXED32: .functype fence_acquire () -> ()
+; RELAXED32-NEXT: # %bb.0:
+; RELAXED32-NEXT: atomic.fence acqrel
+; RELAXED32-NEXT: # fallthrough-return
+;
+; RELAXED64-LABEL: fence_acquire:
+; RELAXED64: .functype fence_acquire () -> ()
+; RELAXED64-NEXT: # %bb.0:
+; RELAXED64-NEXT: atomic.fence acqrel
+; RELAXED64-NEXT: # fallthrough-return
+ fence acquire
ret void
}
-; Fences with weaker memory orderings than seq_cst should be treated the same
-; because atomic memory access in wasm are sequentially consistent.
-; CHECK-LABEL: multithread_weak_fence:
-; CHECK: atomic.fence
-; CHECK-NEXT: atomic.fence
-; CHECK-NEXT: atomic.fence
-define void @multithread_weak_fence() {
- fence acquire
+define void @fence_release() {
+; NO-ATOMICS-LABEL: fence_release:
+; NO-ATOMICS: .functype fence_release () -> ()
+; NO-ATOMICS-NEXT: # %bb.0:
+; NO-ATOMICS-NEXT: # fallthrough-return
+;
+; ATOMICS-LABEL: fence_release:
+; ATOMICS: .functype fence_release () -> ()
+; ATOMICS-NEXT: # %bb.0:
+; ATOMICS-NEXT: atomic.fence
+; ATOMICS-NEXT: # fallthrough-return
+;
+; RELAXED32-LABEL: fence_release:
+; RELAXED32: .functype fence_release () -> ()
+; RELAXED32-NEXT: # %bb.0:
+; RELAXED32-NEXT: atomic.fence acqrel
+; RELAXED32-NEXT: # fallthrough-return
+;
+; RELAXED64-LABEL: fence_release:
+; RELAXED64: .functype fence_release () -> ()
+; RELAXED64-NEXT: # %bb.0:
+; RELAXED64-NEXT: atomic.fence acqrel
+; RELAXED64-NEXT: # fallthrough-return
fence release
+ ret void
+}
+
+define void @fence_acq_rel() {
+; NO-ATOMICS-LABEL: fence_acq_rel:
+; NO-ATOMICS: .functype fence_acq_rel () -> ()
+; NO-ATOMICS-NEXT: # %bb.0:
+; NO-ATOMICS-NEXT: # fallthrough-return
+;
+; ATOMICS-LABEL: fence_acq_rel:
+; ATOMICS: .functype fence_acq_rel () -> ()
+; ATOMICS-NEXT: # %bb.0:
+; ATOMICS-NEXT: atomic.fence
+; ATOMICS-NEXT: # fallthrough-return
+;
+; RELAXED32-LABEL: fence_acq_rel:
+; RELAXED32: .functype fence_acq_rel () -> ()
+; RELAXED32-NEXT: # %bb.0:
+; RELAXED32-NEXT: atomic.fence acqrel
+; RELAXED32-NEXT: # fallthrough-return
+;
+; RELAXED64-LABEL: fence_acq_rel:
+; RELAXED64: .functype fence_acq_rel () -> ()
+; RELAXED64-NEXT: # %bb.0:
+; RELAXED64-NEXT: atomic.fence acqrel
+; RELAXED64-NEXT: # fallthrough-return
fence acq_rel
ret void
}
+define void @fence_seq_cst() {
+; NO-ATOMICS-LABEL: fence_seq_cst:
+; NO-ATOMICS: .functype fence_seq_cst () -> ()
+; NO-ATOMICS-NEXT: # %bb.0:
+; NO-ATOMICS-NEXT: # fallthrough-return
+;
+; ATOMICS-LABEL: fence_seq_cst:
+; ATOMICS: .functype fence_seq_cst () -> ()
+; ATOMICS-NEXT: # %bb.0:
+; ATOMICS-NEXT: atomic.fence
+; ATOMICS-NEXT: # fallthrough-return
+;
+; RELAXED32-LABEL: fence_seq_cst:
+; RELAXED32: .functype fence_seq_cst () -> ()
+; RELAXED32-NEXT: # %bb.0:
+; RELAXED32-NEXT: atomic.fence seqcst
+; RELAXED32-NEXT: # fallthrough-return
+;
+; RELAXED64-LABEL: fence_seq_cst:
+; RELAXED64: .functype fence_seq_cst () -> ()
+; RELAXED64-NEXT: # %bb.0:
+; RELAXED64-NEXT: atomic.fence seqcst
+; RELAXED64-NEXT: # fallthrough-return
+ fence seq_cst
+ ret void
+}
+
; A singlethread fence becomes compiler_fence instruction, a pseudo instruction
; that acts as a compiler barrier. The barrier should not be emitted to .s file.
-; CHECK-LABEL: singlethread_fence:
-; CHECK-NOT: compiler_fence
-; CHECK-NOT: atomic_fence
define void @singlethread_fence() {
+; NO-ATOMICS-LABEL: singlethread_fence:
+; NO-ATOMICS: .functype singlethread_fence () -> ()
+; NO-ATOMICS-NEXT: # %bb.0:
+; NO-ATOMICS-NEXT: # fallthrough-return
+;
+; ATOMICS-LABEL: singlethread_fence:
+; ATOMICS: .functype singlethread_fence () -> ()
+; ATOMICS-NEXT: # %bb.0:
+; ATOMICS-NEXT: # fallthrough-return
+;
+; RELAXED32-LABEL: singlethread_fence:
+; RELAXED32: .functype singlethread_fence () -> ()
+; RELAXED32-NEXT: # %bb.0:
+; RELAXED32-NEXT: # fallthrough-return
+;
+; RELAXED64-LABEL: singlethread_fence:
+; RELAXED64: .functype singlethread_fence () -> ()
+; RELAXED64-NEXT: # %bb.0:
+; RELAXED64-NEXT: # fallthrough-return
fence syncscope("singlethread") seq_cst
fence syncscope("singlethread") acquire
fence syncscope("singlethread") release
diff --git a/llvm/test/CodeGen/WebAssembly/atomic-mem-consistency.ll b/llvm/test/CodeGen/WebAssembly/atomic-mem-consistency.ll
index 5e9a0060c6ece..116c5fbba34d9 100644
--- a/llvm/test/CodeGen/WebAssembly/atomic-mem-consistency.ll
+++ b/llvm/test/CodeGen/WebAssembly/atomic-mem-consistency.ll
@@ -1,9 +1,13 @@
-; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt
-; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -wasm-disable-explicit-locals -wasm-keep-registers -mattr=+atomics,+sign-ext | FileCheck %s
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 6
+; RUN: llc < %s --mtriple=wasm32 | FileCheck %s --check-prefixes=NO-ATOMICS
+; RUN: llc < %s --mtriple=wasm32 -mattr=+atomics | FileCheck %s --check-prefixes=ATOMICS
+; RUN: llc < %s --mtriple=wasm32 -mattr=+atomics,+relaxed-atomics | FileCheck %s --check-prefixes=RELAXED32
+; RUN: llc < %s --mtriple=wasm64 -mattr=+atomics,+relaxed-atomics | FileCheck %s --check-prefixes=RELAXED64
-; Currently all wasm atomic memory access instructions are sequentially
-; consistent, so even if LLVM IR specifies weaker orderings than that, we
-; should upgrade them to sequential ordering and treat them in the same way.
+; Currently Wasm supports a constrained set of atomic memory orderings.
+; Originally it supported only sequential consistency, but now it also
+; supports relaxed atomics. Weaker orderings in LLVM IR are "upgraded" to
+; the next supported ordering.
target triple = "wasm32-unknown-unknown"
@@ -13,34 +17,130 @@ target triple = "wasm32-unknown-unknown"
; The 'release' and 'acq_rel' orderings are not valid on load instructions.
-; CHECK-LABEL: load_i32_unordered:
-; CHECK: i32.atomic.load $push0=, 0($0){{$}}
-; CHECK-NEXT: return $pop0{{$}}
define i32 @load_i32_unordered(ptr %p) {
+; NO-ATOMICS-LABEL: load_i32_unordered:
+; NO-ATOMICS: .functype load_i32_unordered (i32) -> (i32)
+; NO-ATOMICS-NEXT: # %bb.0:
+; NO-ATOMICS-NEXT: local.get 0
+; NO-ATOMICS-NEXT: i32.load 0
+; NO-ATOMICS-NEXT: # fallthrough-return
+;
+; ATOMICS-LABEL: load_i32_unordered:
+; ATOMICS: .functype load_i32_unordered (i32) -> (i32)
+; ATOMICS-NEXT: # %bb.0:
+; ATOMICS-NEXT: local.get 0
+; ATOMICS-NEXT: i32.atomic.load 0
+; ATOMICS-NEXT: # fallthrough-return
+;
+; RELAXED32-LABEL: load_i32_unordered:
+; RELAXED32: .functype load_i32_unordered (i32) -> (i32)
+; RELAXED32-NEXT: # %bb.0:
+; RELAXED32-NEXT: local.get 0
+; RELAXED32-NEXT: i32.atomic.load acqrel 0
+; RELAXED32-NEXT: # fallthrough-return
+;
+; RELAXED64-LABEL: load_i32_unordered:
+; RELAXED64: .functype load_i32_unordered (i64) -> (i32)
+; RELAXED64-NEXT: # %bb.0:
+; RELAXED64-NEXT: local.get 0
+; RELAXED64-NEXT: i32.atomic.load acqrel 0
+; RELAXED64-NEXT: # fallthrough-return
%v = load atomic i32, ptr %p unordered, align 4
ret i32 %v
}
-; CHECK-LABEL: load_i32_monotonic:
-; CHECK: i32.atomic.load $push0=, 0($0){{$}}
-; CHECK-NEXT: return $pop0{{$}}
define i32 @load_i32_monotonic(ptr %p) {
+; NO-ATOMICS-LABEL: load_i32_monotonic:
+; NO-ATOMICS: .functype load_i32_monotonic (i32) -> (i32)
+; NO-ATOMICS-NEXT: # %bb.0:
+; NO-ATOMICS-NEXT: local.get 0
+; NO-ATOMICS-NEXT: i32.load 0
+; NO-ATOMICS-NEXT: # fallthrough-return
+;
+; ATOMICS-LABEL: load_i32_monotonic:
+; ATOMICS: .functype load_i32_monotonic (i32) -> (i32)
+; ATOMICS-NEXT: # %bb.0:
+; ATOMICS-NEXT: local.get 0
+; ATOMICS-NEXT: i32.atomic.load 0
+; ATOMICS-NEXT: # fallthrough-return
+;
+; RELAXED32-LABEL: load_i32_monotonic:
+; RELAXED32: .functype load_i32_monotonic (i32) -> (i32)
+; RELAXED32-NEXT: # %bb.0:
+; RELAXED32-NEXT: local.get 0
+; RELAXED32-NEXT: i32.atomic.load acqrel 0
+; RELAXED32-NEXT: # fallthrough-return
+;
+; RELAXED64-LABEL: load_i32_monotonic:
+; RELAXED64: .functype load_i32_monotonic (i64) -> (i32)
+; RELAXED64-NEXT: # %bb.0:
+; RELAXED64-NEXT: local.get 0
+; RELAXED64-NEXT: i32.atomic.load acqrel 0
+; RELAXED64-NEXT: # fallthrough-return
%v = load atomic i32, ptr %p monotonic, align 4
ret i32 %v
}
-; CHECK-LABEL: load_i32_acquire:
-; CHECK: i32.atomic.load $push0=, 0($0){{$}}
-; CHECK-NEXT: return $pop0{{$}}
define i32 @load_i32_acquire(ptr %p) {
+; NO-ATOMICS-LABEL: load_i32_acquire:
+; NO-ATOMICS: .functype load_i32_acquire (i32) -> (i32)
+; NO-ATOMICS-NEXT: # %bb.0:
+; NO-ATOMICS-NEXT: local.get 0
+; NO-ATOMICS-NEXT: i32.load 0
+; NO-ATOMICS-NEXT: # fallthrough-return
+;
+; ATOMICS-LABEL: load_i32_acquire:
+; ATOMICS: .functype load_i32_acquire (i32) -> (i32)
+; ATOMICS-NEXT: # %bb.0:
+; ATOMICS-NEXT: local.get 0
+; ATOMICS-NEXT: i32.atomic.load 0
+; ATOMICS-NEXT: # fallthrough-return
+;
+; RELAXED32-LABEL: load_i32_acquire:
+; RELAXED32: .functype load_i32_acquire (i32) -> (i32)
+; RELAXED32-NEXT: # %bb.0:
+; RELAXED32-NEXT: local.get 0
+; RELAXED32-NEXT: i32.atomic.load acqrel 0
+; RELAXED32-NEXT: # fallthrough-return
+;
+; RELAXED64-LABEL: load_i32_acquire:
+; RELAXED64: .functype load_i32_acquire (i64) -> (i32)
+; RELAXED64-NEXT: # %bb.0:
+; RELAXED64-NEXT: local.get 0
+; RELAXED64-NEXT: i32.atomic.load acqrel 0
+; RELAXED64-NEXT: # fallthrough-return
%v = load atomic i32, ptr %p acquire, align 4
ret i32 %v
}
-; CHECK-LABEL: load_i32_seq_cst:
-; CHECK: i32.atomic.load $push0=, 0($0){{$}}
-; CHECK-NEXT: return $pop0{{$}}
define i32 @load_i32_seq_cst(ptr %p) {
+; NO-ATOMICS-LABEL: load_i32_seq_cst:
+; NO-ATOMICS: .functype load_i32_seq_cst (i32) -> (i32)
+; NO-ATOMICS-NEXT: # %bb.0:
+; NO-ATOMICS-NEXT: local.get 0
+; NO-ATOMICS-NEXT: i32.load 0
+; NO-ATOMICS-NEXT: # fallthrough-return
+;
+; ATOMICS-LABEL: load_i32_seq_cst:
+; ATOMICS: .functype load_i32_seq_cst (i32) -> (i32)
+; ATOMICS-NEXT: # %bb.0:
+; ATOMICS-NEXT: local.get 0
+; ATOMICS-NEXT: i32.atomic.load 0
+; ATOMICS-NEXT: # fallthrough-return
+;
+; RELAXED32-LABEL: load_i32_seq_cst:
+; RELAXED32: .functype load_i32_seq_cst (i32) -> (i32)
+; RELAXED32-NEXT: # %bb.0:
+; RELAXED32-NEXT: local.get 0
+; RELAXED32-NEXT: i32.atomic.load seqcst 0
+; RELAXED32-NEXT: # fallthrough-return
+;
+; RELAXED64-LABEL: load_i32_seq_cst:
+; RELAXED64: .functype load_i32_seq_cst (i64) -> (i32)
+; RELAXED64-NEXT: # %bb.0:
+; RELAXED64-NEXT: local.get 0
+; RELAXED64-NEXT: i32.atomic.load seqcst 0
+; RELAXED64-NEXT: # fallthrough-return
%v = load atomic i32, ptr %p seq_cst, align 4
ret i32 %v
}
@@ -51,38 +151,146 @@ define i32 @load_i32_seq_cst(ptr %p) {
; The 'acquire' and 'acq_rel' orderings aren’t valid on store instructions.
-; CHECK-LABEL: store_i32_unordered:
-; CHECK-NEXT: .functype store_i32_unordered (i32, i32) -> (){{$}}
-; CHECK-NEXT: i32.atomic.store 0($0), $1{{$}}
-; CHECK-NEXT: return{{$}}
define void @store_i32_unordered(ptr %p, i32 %v) {
+; NO-ATOMICS-LABEL: store_i32_unordered:
+; NO-ATOMICS: .functype store_i32_unordered (i32, i32) -> ()
+; NO-ATOMICS-NEXT: # %bb.0:
+; NO-ATOMICS-NEXT: local.get 0
+; NO-ATOMICS-NEXT: local.get 1
+; NO-ATOMICS-NEXT: i32.store 0
+; NO-ATOMICS-NEXT: # fallthrough-return
+;
+; ATOMICS-LABEL: store_i32_unordered:
+; ATOMICS: .functype store_i32_unordered (i32, i32) -> ()
+; ATOMICS-NEXT: # %bb.0:
+; ATOMICS-NEXT: local.get 0
+; ATOMICS-NEXT: local.get 1
+; ATOMICS-NEXT: i32.atomic.store 0
+; ATOMICS-NEXT: # fallthrough-return
+;
+; RELAXED32-LABEL: store_i32_unordered:
+; RELAXED32: .functype store_i32_unordered (i32, i32) -> ()
+; RELAXED32-NEXT: # %bb.0:
+; RELAXED32-NEXT: local.get 0
+; RELAXED32-NEXT: local.get 1
+; RELAXED32-NEXT: i32.atomic.store acqrel 0
+; RELAXED32-NEXT: # fallthrough-return
+;
+; RELAXED64-LABEL: store_i32_unordered:
+; RELAXED64: .functype store_i32_unordered (i64, i32) -> ()
+; RELAXED64-NEXT: # %bb.0:
+; RELAXED64-NEXT: local.get 0
+; RELAXED64-NEXT: local.get 1
+; RELAXED64-NEXT: i32.atomic.store acqrel 0
+; RELAXED64-NEXT: # fallthrough-return
store atomic i32 %v, ptr %p unordered, align 4
ret void
}
-; CHECK-LABEL: store_i32_monotonic:
-; CHECK-NEXT: .functype store_i32_monotonic (i32, i32) -> (){{$}}
-; CHECK-NEXT: i32.atomic.store 0($0), $1{{$}}
-; CHECK-NEXT: return{{$}}
define void @store_i32_monotonic(ptr %p, i32 %v) {
+; NO-ATOMICS-LABEL: store_i32_monotonic:
+; NO-ATOMICS: .functype store_i32_monotonic (i32, i32) -> ()
+; NO-ATOMICS-NEXT: # %bb.0:
+; NO-ATOMICS-NEXT: local.get 0
+; NO-ATOMICS-NEXT: local.get 1
+; NO-ATOMICS-NEXT: i32.store 0
+; NO-ATOMICS-NEXT: # fallthrough-return
+;
+; ATOMICS-LABEL: store_i32_monotonic:
+; ATOMICS: .functype store_i32_monotonic (i32, i32) -> ()
+; ATOMICS-NEXT: # %bb.0:
+; ATOMICS-NEXT: local.get 0
+; ATOMICS-NEXT: local.get 1
+; ATOMICS-NEXT: i32.atomic.store 0
+; ATOMICS-NEXT: # fallthrough-return
+;
+; RELAXED32-LABEL: store_i32_monotonic:
+; RELAXED32: .functype store_i32_monotonic (i32, i32) -> ()
+; RELAXED32-NEXT: # %bb.0:
+; RELAXED32-NEXT: local.get 0
+; RELAXED32-NEXT: local.get 1
+; RELAXED32-NEXT: i32.atomic.store acqrel 0
+; RELAXED32-NEXT: # fallthrough-return
+;
+; RELAXED64-LABEL: store_i32_monotonic:
+; RELAXED64: .functype store_i32_monotonic (i64, i32) -> ()
+; RELAXED64-NEXT: # %bb.0:
+; RELAXED64-NEXT: local.get 0
+; RELAXED64-NEXT: local.get 1
+; RELAXED64-NEXT: i32.atomic.store acqrel 0
+; RELAXED64-NEXT: # fallthrough-return
store atomic i32 %v, ptr %p monotonic, align 4
ret void
}
-; CHECK-LABEL: store_i32_release:
-; CHECK-NEXT: .functype store_i32_release (i32, i32) -> (){{$}}
-; CHECK-NEXT: i32.atomic.store 0($0), $1{{$}}
-; CHECK-NEXT: return{{$}}
define void @store_i32_release(ptr %p, i32 %v) {
+; NO-ATOMICS-LABEL: store_i32_release:
+; NO-ATOMICS: .functype store_i32_release (i32, i32) -> ()
+; NO-ATOMICS-NEXT: # %bb.0:
+; NO-ATOMICS-NEXT: local.get 0
+; NO-ATOMICS-NEXT: local.get 1
+; NO-ATOMICS-NEXT: i32.store 0
+; NO-ATOMICS-NEXT: # fallthrough-return
+;
+; ATOMICS-LABEL: store_i32_release:
+; ATOMICS: .functype store_i32_release (i32, i32) -> ()
+; ATOMICS-NEXT: # %bb.0:
+; ATOMICS-NEXT: local.get 0
+; ATOMICS-NEXT: local.get 1
+; ATOMICS-NEXT: i32.atomic.store 0
+; ATOMICS-NEXT: # fallthrough-return
+;
+; RELAXED32-LABEL: store_i32_release:
+; RELAXED32: .functype store_i32_release (i32, i32) -> ()
+; RELAXED32-NEXT: # %bb.0:
+; RELAXED32-NEXT: local.get 0
+; RELAXED32-NEXT: local.get 1
+; RELAXED32-NEXT: i32.atomic.store acqrel 0
+; RELAXED32-NEXT: # fallthrough-return
+;
+; RELAXED64-LABEL: store_i32_release:
+; RELAXED64: .functype store_i32_release (i64, i32) -> ()
+; RELAXED64-NEXT: # %bb.0:
+; RELAXED64-NEXT: local.get 0
+; RELAXED64-NEXT: local.get 1
+; RELAXED64-NEXT: i32.atomic.store acqrel 0
+; RELAXED64-NEXT: # fallthrough-return
store atomic i32 %v, ptr %p release, align 4
ret void
}
-; CHECK-LABEL: store_i32_seq_cst:
-; CHECK-NEXT: .functype store_i32_seq_cst (i32, i32) -> (){{$}}
-; CHECK-NEXT: i32.atomic.store 0($0), $1{{$}}
-; CHECK-NEXT: return{{$}}
define void @store_i32_seq_cst(ptr %p, i32 %v) {
+; NO-ATOMICS-LABEL: store_i32_seq_cst:
+; NO-ATOMICS: .functype store_i32_seq_cst (i32, i32) -> ()
+; NO-ATOMICS-NEXT: # %bb.0:
+; NO-ATOMICS-NEXT: local.get 0
+; NO-ATOMICS-NEXT: local.get 1
+; NO-ATOMICS-NEXT: i32.store 0
+; NO-ATOMICS-NEXT: # fallthrough-return
+;
+; ATOMICS-LABEL: store_i32_seq_cst:
+; ATOMICS: .functype store_i32_seq_cst (i32, i32) -> ()
+; ATOMICS-NEXT: # %bb.0:
+; ATOMICS-NEXT: local.get 0
+; ATOMICS-NEXT: local.get 1
+; ATOMICS-NEXT: i32.atomic.store 0
+; ATOMICS-NEXT: # fallthrough-return
+;
+; RELAXED32-LABEL: store_i32_seq_cst:
+; RELAXED32: .functype store_i32_seq_cst (i32, i32) -> ()
+; RELAXED32-NEXT: # %bb.0:
+; RELAXED32-NEXT: local.get 0
+; RELAXED32-NEXT: local.get 1
+; RELAXED32-NEXT: i32.atomic.store seqcst 0
+; RELAXED32-NEXT: # fallthrough-return
+;
+; RELAXED64-LABEL: store_i32_seq_cst:
+; RELAXED64: .functype store_i32_seq_cst (i64, i32) -> ()
+; RELAXED64-NEXT: # %bb.0:
+; RELAXED64-NEXT: local.get 0
+; RELAXED64-NEXT: local.get 1
+; RELAXED64-NEXT: i32.atomic.store seqcst 0
+; RELAXED64-NEXT: # fallthrough-return
store atomic i32 %v, ptr %p seq_cst, align 4
ret void
}
@@ -94,47 +302,212 @@ define void @store_i32_seq_cst(ptr %p, i32 %v) {
; Out of several binary RMW instructions, here we test 'add' as an example.
; The 'unordered' ordering is not valid on atomicrmw instructions.
-; CHECK-LABEL: add_i32_monotonic:
-; CHECK-NEXT: .functype add_i32_monotonic (i32, i32) -> (i32){{$}}
-; CHECK: i32.atomic.rmw.add $push0=, 0($0), $1{{$}}
-; CHECK-NEXT: return $pop0{{$}}
define i32 @add_i32_monotonic(ptr %p, i32 %v) {
+; NO-ATOMICS-LABEL: add_i32_monotonic:
+; NO-ATOMICS: .functype add_i32_monotonic (i32, i32) -> (i32)
+; NO-ATOMICS-NEXT: .local i32
+; NO-ATOMICS-NEXT: # %bb.0:
+; NO-ATOMICS-NEXT: local.get 0
+; NO-ATOMICS-NEXT: local.get 0
+; NO-ATOMICS-NEXT: i32.load 0
+; NO-ATOMICS-NEXT: local.tee 2
+; NO-ATOMICS-NEXT: local.get 1
+; NO-ATOMICS-NEXT: i32.add
+; NO-ATOMICS-NEXT: i32.store 0
+; NO-ATOMICS-NEXT: local.get 2
+; NO-ATOMICS-NEXT: # fallthrough-return
+;
+; ATOMICS-LABEL: add_i32_monotonic:
+; ATOMICS: .functype add_i32_monotonic (i32, i32) -> (i32)
+; ATOMICS-NEXT: # %bb.0:
+; ATOMICS-NEXT: local.get 0
+; ATOMICS-NEXT: local.get 1
+; ATOMICS-NEXT: i32.atomic.rmw.add 0
+; ATOMICS-NEXT: # fallthrough-return
+;
+; RELAXED32-LABEL: add_i32_monotonic:
+; RELAXED32: .functype add_i32_monotonic (i32, i32) -> (i32)
+; RELAXED32-NEXT: # %bb.0:
+; RELAXED32-NEXT: local.get 0
+; RELAXED32-NEXT: local.get 1
+; RELAXED32-NEXT: i32.atomic.rmw.add acqrel 0
+; RELAXED32-NEXT: # fallthrough-return
+;
+; RELAXED64-LABEL: add_i32_monotonic:
+; RELAXED64: .functype add_i32_monotonic (i64, i32) -> (i32)
+; RELAXED64-NEXT: # %bb.0:
+; RELAXED64-NEXT: local.get 0
+; RELAXED64-NEXT: local.get 1
+; RELAXED64-NEXT: i32.atomic.rmw.add acqrel 0
+; RELAXED64-NEXT: # fallthrough-return
%old = atomicrmw add ptr %p, i32 %v monotonic
ret i32 %old
}
-; CHECK-LABEL: add_i32_acquire:
-; CHECK-NEXT: .functype add_i32_acquire (i32, i32) -> (i32){{$}}
-; CHECK: i32.atomic.rmw.add $push0=, 0($0), $1{{$}}
-; CHECK-NEXT: return $pop0{{$}}
define i32 @add_i32_acquire(ptr %p, i32 %v) {
+; NO-ATOMICS-LABEL: add_i32_acquire:
+; NO-ATOMICS: .functype add_i32_acquire (i32, i32) -> (i32)
+; NO-ATOMICS-NEXT: .local i32
+; NO-ATOMICS-NEXT: # %bb.0:
+; NO-ATOMICS-NEXT: local.get 0
+; NO-ATOMICS-NEXT: local.get 0
+; NO-ATOMICS-NEXT: i32.load 0
+; NO-ATOMICS-NEXT: local.tee 2
+; NO-ATOMICS-NEXT: local.get 1
+; NO-ATOMICS-NEXT: i32.add
+; NO-ATOMICS-NEXT: i32.store 0
+; NO-ATOMICS-NEXT: local.get 2
+; NO-ATOMICS-NEXT: # fallthrough-return
+;
+; ATOMICS-LABEL: add_i32_acquire:
+; ATOMICS: .functype add_i32_acquire (i32, i32) -> (i32)
+; ATOMICS-NEXT: # %bb.0:
+; ATOMICS-NEXT: local.get 0
+; ATOMICS-NEXT: local.get 1
+; ATOMICS-NEXT: i32.atomic.rmw.add 0
+; ATOMICS-NEXT: # fallthrough-return
+;
+; RELAXED32-LABEL: add_i32_acquire:
+; RELAXED32: .functype add_i32_acquire (i32, i32) -> (i32)
+; RELAXED32-NEXT: # %bb.0:
+; RELAXED32-NEXT: local.get 0
+; RELAXED32-NEXT: local.get 1
+; RELAXED32-NEXT: i32.atomic.rmw.add acqrel 0
+; RELAXED32-NEXT: # fallthrough-return
+;
+; RELAXED64-LABEL: add_i32_acquire:
+; RELAXED64: .functype add_i32_acquire (i64, i32) -> (i32)
+; RELAXED64-NEXT: # %bb.0:
+; RELAXED64-NEXT: local.get 0
+; RELAXED64-NEXT: local.get 1
+; RELAXED64-NEXT: i32.atomic.rmw.add acqrel 0
+; RELAXED64-NEXT: # fallthrough-return
%old = atomicrmw add ptr %p, i32 %v acquire
ret i32 %old
}
-; CHECK-LABEL: add_i32_release:
-; CHECK-NEXT: .functype add_i32_release (i32, i32) -> (i32){{$}}
-; CHECK: i32.atomic.rmw.add $push0=, 0($0), $1{{$}}
-; CHECK-NEXT: return $pop0{{$}}
define i32 @add_i32_release(ptr %p, i32 %v) {
+; NO-ATOMICS-LABEL: add_i32_release:
+; NO-ATOMICS: .functype add_i32_release (i32, i32) -> (i32)
+; NO-ATOMICS-NEXT: .local i32
+; NO-ATOMICS-NEXT: # %bb.0:
+; NO-ATOMICS-NEXT: local.get 0
+; NO-ATOMICS-NEXT: local.get 0
+; NO-ATOMICS-NEXT: i32.load 0
+; NO-ATOMICS-NEXT: local.tee 2
+; NO-ATOMICS-NEXT: local.get 1
+; NO-ATOMICS-NEXT: i32.add
+; NO-ATOMICS-NEXT: i32.store 0
+; NO-ATOMICS-NEXT: local.get 2
+; NO-ATOMICS-NEXT: # fallthrough-return
+;
+; ATOMICS-LABEL: add_i32_release:
+; ATOMICS: .functype add_i32_release (i32, i32) -> (i32)
+; ATOMICS-NEXT: # %bb.0:
+; ATOMICS-NEXT: local.get 0
+; ATOMICS-NEXT: local.get 1
+; ATOMICS-NEXT: i32.atomic.rmw.add 0
+; ATOMICS-NEXT: # fallthrough-return
+;
+; RELAXED32-LABEL: add_i32_release:
+; RELAXED32: .functype add_i32_release (i32, i32) -> (i32)
+; RELAXED32-NEXT: # %bb.0:
+; RELAXED32-NEXT: local.get 0
+; RELAXED32-NEXT: local.get 1
+; RELAXED32-NEXT: i32.atomic.rmw.add acqrel 0
+; RELAXED32-NEXT: # fallthrough-return
+;
+; RELAXED64-LABEL: add_i32_release:
+; RELAXED64: .functype add_i32_release (i64, i32) -> (i32)
+; RELAXED64-NEXT: # %bb.0:
+; RELAXED64-NEXT: local.get 0
+; RELAXED64-NEXT: local.get 1
+; RELAXED64-NEXT: i32.atomic.rmw.add acqrel 0
+; RELAXED64-NEXT: # fallthrough-return
%old = atomicrmw add ptr %p, i32 %v release
ret i32 %old
}
-; CHECK-LABEL: add_i32_acq_rel:
-; CHECK-NEXT: .functype add_i32_acq_rel (i32, i32) -> (i32){{$}}
-; CHECK: i32.atomic.rmw.add $push0=, 0($0), $1{{$}}
-; CHECK-NEXT: return $pop0{{$}}
define i32 @add_i32_acq_rel(ptr %p, i32 %v) {
+; NO-ATOMICS-LABEL: add_i32_acq_rel:
+; NO-ATOMICS: .functype add_i32_acq_rel (i32, i32) -> (i32)
+; NO-ATOMICS-NEXT: .local i32
+; NO-ATOMICS-NEXT: # %bb.0:
+; NO-ATOMICS-NEXT: local.get 0
+; NO-ATOMICS-NEXT: local.get 0
+; NO-ATOMICS-NEXT: i32.load 0
+; NO-ATOMICS-NEXT: local.tee 2
+; NO-ATOMICS-NEXT: local.get 1
+; NO-ATOMICS-NEXT: i32.add
+; NO-ATOMICS-NEXT: i32.store 0
+; NO-ATOMICS-NEXT: local.get 2
+; NO-ATOMICS-NEXT: # fallthrough-return
+;
+; ATOMICS-LABEL: add_i32_acq_rel:
+; ATOMICS: .functype add_i32_acq_rel (i32, i32) -> (i32)
+; ATOMICS-NEXT: # %bb.0:
+; ATOMICS-NEXT: local.get 0
+; ATOMICS-NEXT: local.get 1
+; ATOMICS-NEXT: i32.atomic.rmw.add 0
+; ATOMICS-NEXT: # fallthrough-return
+;
+; RELAXED32-LABEL: add_i32_acq_rel:
+; RELAXED32: .functype add_i32_acq_rel (i32, i32) -> (i32)
+; RELAXED32-NEXT: # %bb.0:
+; RELAXED32-NEXT: local.get 0
+; RELAXED32-NEXT: local.get 1
+; RELAXED32-NEXT: i32.atomic.rmw.add acqrel 0
+; RELAXED32-NEXT: # fallthrough-return
+;
+; RELAXED64-LABEL: add_i32_acq_rel:
+; RELAXED64: .functype add_i32_acq_rel (i64, i32) -> (i32)
+; RELAXED64-NEXT: # %bb.0:
+; RELAXED64-NEXT: local.get 0
+; RELAXED64-NEXT: local.get 1
+; RELAXED64-NEXT: i32.atomic.rmw.add acqrel 0
+; RELAXED64-NEXT: # fallthrough-return
%old = atomicrmw add ptr %p, i32 %v acq_rel
ret i32 %old
}
-; CHECK-LABEL: add_i32_seq_cst:
-; CHECK-NEXT: .functype add_i32_seq_cst (i32, i32) -> (i32){{$}}
-; CHECK: i32.atomic.rmw.add $push0=, 0($0), $1{{$}}
-; CHECK-NEXT: return $pop0{{$}}
define i32 @add_i32_seq_cst(ptr %p, i32 %v) {
+; NO-ATOMICS-LABEL: add_i32_seq_cst:
+; NO-ATOMICS: .functype add_i32_seq_cst (i32, i32) -> (i32)
+; NO-ATOMICS-NEXT: .local i32
+; NO-ATOMICS-NEXT: # %bb.0:
+; NO-ATOMICS-NEXT: local.get 0
+; NO-ATOMICS-NEXT: local.get 0
+; NO-ATOMICS-NEXT: i32.load 0
+; NO-ATOMICS-NEXT: local.tee 2
+; NO-ATOMICS-NEXT: local.get 1
+; NO-ATOMICS-NEXT: i32.add
+; NO-ATOMICS-NEXT: i32.store 0
+; NO-ATOMICS-NEXT: local.get 2
+; NO-ATOMICS-NEXT: # fallthrough-return
+;
+; ATOMICS-LABEL: add_i32_seq_cst:
+; ATOMICS: .functype add_i32_seq_cst (i32, i32) -> (i32)
+; ATOMICS-NEXT: # %bb.0:
+; ATOMICS-NEXT: local.get 0
+; ATOMICS-NEXT: local.get 1
+; ATOMICS-NEXT: i32.atomic.rmw.add 0
+; ATOMICS-NEXT: # fallthrough-return
+;
+; RELAXED32-LABEL: add_i32_seq_cst:
+; RELAXED32: .functype add_i32_seq_cst (i32, i32) -> (i32)
+; RELAXED32-NEXT: # %bb.0:
+; RELAXED32-NEXT: local.get 0
+; RELAXED32-NEXT: local.get 1
+; RELAXED32-NEXT: i32.atomic.rmw.add seqcst 0
+; RELAXED32-NEXT: # fallthrough-return
+;
+; RELAXED64-LABEL: add_i32_seq_cst:
+; RELAXED64: .functype add_i32_seq_cst (i64, i32) -> (i32)
+; RELAXED64-NEXT: # %bb.0:
+; RELAXED64-NEXT: local.get 0
+; RELAXED64-NEXT: local.get 1
+; RELAXED64-NEXT: i32.atomic.rmw.add seqcst 0
+; RELAXED64-NEXT: # fallthrough-return
%old = atomicrmw add ptr %p, i32 %v seq_cst
ret i32 %old
}
@@ -145,81 +518,393 @@ define i32 @add_i32_seq_cst(ptr %p, i32 %v) {
; least monotonic, the ordering constraint on failure must be no stronger than
; that on success, and the failure ordering cannot be either release or acq_rel.
-; CHECK-LABEL: cmpxchg_i32_monotonic_monotonic:
-; CHECK-NEXT: .functype cmpxchg_i32_monotonic_monotonic (i32, i32, i32) -> (i32){{$}}
-; CHECK: i32.atomic.rmw.cmpxchg $push0=, 0($0), $1, $2{{$}}
-; CHECK-NEXT: return $pop0{{$}}
define i32 @cmpxchg_i32_monotonic_monotonic(ptr %p, i32 %exp, i32 %new) {
+; NO-ATOMICS-LABEL: cmpxchg_i32_monotonic_monotonic:
+; NO-ATOMICS: .functype cmpxchg_i32_monotonic_monotonic (i32, i32, i32) -> (i32)
+; NO-ATOMICS-NEXT: .local i32
+; NO-ATOMICS-NEXT: # %bb.0:
+; NO-ATOMICS-NEXT: local.get 0
+; NO-ATOMICS-NEXT: local.get 2
+; NO-ATOMICS-NEXT: local.get 0
+; NO-ATOMICS-NEXT: i32.load 0
+; NO-ATOMICS-NEXT: local.tee 3
+; NO-ATOMICS-NEXT: local.get 3
+; NO-ATOMICS-NEXT: local.get 1
+; NO-ATOMICS-NEXT: i32.eq
+; NO-ATOMICS-NEXT: i32.select
+; NO-ATOMICS-NEXT: i32.store 0
+; NO-ATOMICS-NEXT: local.get 3
+; NO-ATOMICS-NEXT: # fallthrough-return
+;
+; ATOMICS-LABEL: cmpxchg_i32_monotonic_monotonic:
+; ATOMICS: .functype cmpxchg_i32_monotonic_monotonic (i32, i32, i32) -> (i32)
+; ATOMICS-NEXT: # %bb.0:
+; ATOMICS-NEXT: local.get 0
+; ATOMICS-NEXT: local.get 1
+; ATOMICS-NEXT: local.get 2
+; ATOMICS-NEXT: i32.atomic.rmw.cmpxchg 0
+; ATOMICS-NEXT: # fallthrough-return
+;
+; RELAXED32-LABEL: cmpxchg_i32_monotonic_monotonic:
+; RELAXED32: .functype cmpxchg_i32_monotonic_monotonic (i32, i32, i32) -> (i32)
+; RELAXED32-NEXT: # %bb.0:
+; RELAXED32-NEXT: local.get 0
+; RELAXED32-NEXT: local.get 1
+; RELAXED32-NEXT: local.get 2
+; RELAXED32-NEXT: i32.atomic.rmw.cmpxchg acqrel 0
+; RELAXED32-NEXT: # fallthrough-return
+;
+; RELAXED64-LABEL: cmpxchg_i32_monotonic_monotonic:
+; RELAXED64: .functype cmpxchg_i32_monotonic_monotonic (i64, i32, i32) -> (i32)
+; RELAXED64-NEXT: # %bb.0:
+; RELAXED64-NEXT: local.get 0
+; RELAXED64-NEXT: local.get 1
+; RELAXED64-NEXT: local.get 2
+; RELAXED64-NEXT: i32.atomic.rmw.cmpxchg acqrel 0
+; RELAXED64-NEXT: # fallthrough-return
%pair = cmpxchg ptr %p, i32 %exp, i32 %new monotonic monotonic
%old = extractvalue { i32, i1 } %pair, 0
ret i32 %old
}
-; CHECK-LABEL: cmpxchg_i32_acquire_monotonic:
-; CHECK-NEXT: .functype cmpxchg_i32_acquire_monotonic (i32, i32, i32) -> (i32){{$}}
-; CHECK: i32.atomic.rmw.cmpxchg $push0=, 0($0), $1, $2{{$}}
-; CHECK-NEXT: return $pop0{{$}}
define i32 @cmpxchg_i32_acquire_monotonic(ptr %p, i32 %exp, i32 %new) {
+; NO-ATOMICS-LABEL: cmpxchg_i32_acquire_monotonic:
+; NO-ATOMICS: .functype cmpxchg_i32_acquire_monotonic (i32, i32, i32) -> (i32)
+; NO-ATOMICS-NEXT: .local i32
+; NO-ATOMICS-NEXT: # %bb.0:
+; NO-ATOMICS-NEXT: local.get 0
+; NO-ATOMICS-NEXT: local.get 2
+; NO-ATOMICS-NEXT: local.get 0
+; NO-ATOMICS-NEXT: i32.load 0
+; NO-ATOMICS-NEXT: local.tee 3
+; NO-ATOMICS-NEXT: local.get 3
+; NO-ATOMICS-NEXT: local.get 1
+; NO-ATOMICS-NEXT: i32.eq
+; NO-ATOMICS-NEXT: i32.select
+; NO-ATOMICS-NEXT: i32.store 0
+; NO-ATOMICS-NEXT: local.get 3
+; NO-ATOMICS-NEXT: # fallthrough-return
+;
+; ATOMICS-LABEL: cmpxchg_i32_acquire_monotonic:
+; ATOMICS: .functype cmpxchg_i32_acquire_monotonic (i32, i32, i32) -> (i32)
+; ATOMICS-NEXT: # %bb.0:
+; ATOMICS-NEXT: local.get 0
+; ATOMICS-NEXT: local.get 1
+; ATOMICS-NEXT: local.get 2
+; ATOMICS-NEXT: i32.atomic.rmw.cmpxchg 0
+; ATOMICS-NEXT: # fallthrough-return
+;
+; RELAXED32-LABEL: cmpxchg_i32_acquire_monotonic:
+; RELAXED32: .functype cmpxchg_i32_acquire_monotonic (i32, i32, i32) -> (i32)
+; RELAXED32-NEXT: # %bb.0:
+; RELAXED32-NEXT: local.get 0
+; RELAXED32-NEXT: local.get 1
+; RELAXED32-NEXT: local.get 2
+; RELAXED32-NEXT: i32.atomic.rmw.cmpxchg acqrel 0
+; RELAXED32-NEXT: # fallthrough-return
+;
+; RELAXED64-LABEL: cmpxchg_i32_acquire_monotonic:
+; RELAXED64: .functype cmpxchg_i32_acquire_monotonic (i64, i32, i32) -> (i32)
+; RELAXED64-NEXT: # %bb.0:
+; RELAXED64-NEXT: local.get 0
+; RELAXED64-NEXT: local.get 1
+; RELAXED64-NEXT: local.get 2
+; RELAXED64-NEXT: i32.atomic.rmw.cmpxchg acqrel 0
+; RELAXED64-NEXT: # fallthrough-return
%pair = cmpxchg ptr %p, i32 %exp, i32 %new acquire monotonic
%old = extractvalue { i32, i1 } %pair, 0
ret i32 %old
}
-; CHECK-LABEL: cmpxchg_i32_release_monotonic:
-; CHECK-NEXT: .functype cmpxchg_i32_release_monotonic (i32, i32, i32) -> (i32){{$}}
-; CHECK: i32.atomic.rmw.cmpxchg $push0=, 0($0), $1, $2{{$}}
-; CHECK-NEXT: return $pop0{{$}}
define i32 @cmpxchg_i32_release_monotonic(ptr %p, i32 %exp, i32 %new) {
+; NO-ATOMICS-LABEL: cmpxchg_i32_release_monotonic:
+; NO-ATOMICS: .functype cmpxchg_i32_release_monotonic (i32, i32, i32) -> (i32)
+; NO-ATOMICS-NEXT: .local i32
+; NO-ATOMICS-NEXT: # %bb.0:
+; NO-ATOMICS-NEXT: local.get 0
+; NO-ATOMICS-NEXT: local.get 2
+; NO-ATOMICS-NEXT: local.get 0
+; NO-ATOMICS-NEXT: i32.load 0
+; NO-ATOMICS-NEXT: local.tee 3
+; NO-ATOMICS-NEXT: local.get 3
+; NO-ATOMICS-NEXT: local.get 1
+; NO-ATOMICS-NEXT: i32.eq
+; NO-ATOMICS-NEXT: i32.select
+; NO-ATOMICS-NEXT: i32.store 0
+; NO-ATOMICS-NEXT: local.get 3
+; NO-ATOMICS-NEXT: # fallthrough-return
+;
+; ATOMICS-LABEL: cmpxchg_i32_release_monotonic:
+; ATOMICS: .functype cmpxchg_i32_release_monotonic (i32, i32, i32) -> (i32)
+; ATOMICS-NEXT: # %bb.0:
+; ATOMICS-NEXT: local.get 0
+; ATOMICS-NEXT: local.get 1
+; ATOMICS-NEXT: local.get 2
+; ATOMICS-NEXT: i32.atomic.rmw.cmpxchg 0
+; ATOMICS-NEXT: # fallthrough-return
+;
+; RELAXED32-LABEL: cmpxchg_i32_release_monotonic:
+; RELAXED32: .functype cmpxchg_i32_release_monotonic (i32, i32, i32) -> (i32)
+; RELAXED32-NEXT: # %bb.0:
+; RELAXED32-NEXT: local.get 0
+; RELAXED32-NEXT: local.get 1
+; RELAXED32-NEXT: local.get 2
+; RELAXED32-NEXT: i32.atomic.rmw.cmpxchg acqrel 0
+; RELAXED32-NEXT: # fallthrough-return
+;
+; RELAXED64-LABEL: cmpxchg_i32_release_monotonic:
+; RELAXED64: .functype cmpxchg_i32_release_monotonic (i64, i32, i32) -> (i32)
+; RELAXED64-NEXT: # %bb.0:
+; RELAXED64-NEXT: local.get 0
+; RELAXED64-NEXT: local.get 1
+; RELAXED64-NEXT: local.get 2
+; RELAXED64-NEXT: i32.atomic.rmw.cmpxchg acqrel 0
+; RELAXED64-NEXT: # fallthrough-return
%pair = cmpxchg ptr %p, i32 %exp, i32 %new release monotonic
%old = extractvalue { i32, i1 } %pair, 0
ret i32 %old
}
-; CHECK-LABEL: cmpxchg_i32_acq_rel_monotonic:
-; CHECK-NEXT: .functype cmpxchg_i32_acq_rel_monotonic (i32, i32, i32) -> (i32){{$}}
-; CHECK: i32.atomic.rmw.cmpxchg $push0=, 0($0), $1, $2{{$}}
-; CHECK-NEXT: return $pop0{{$}}
define i32 @cmpxchg_i32_acq_rel_monotonic(ptr %p, i32 %exp, i32 %new) {
+; NO-ATOMICS-LABEL: cmpxchg_i32_acq_rel_monotonic:
+; NO-ATOMICS: .functype cmpxchg_i32_acq_rel_monotonic (i32, i32, i32) -> (i32)
+; NO-ATOMICS-NEXT: .local i32
+; NO-ATOMICS-NEXT: # %bb.0:
+; NO-ATOMICS-NEXT: local.get 0
+; NO-ATOMICS-NEXT: local.get 2
+; NO-ATOMICS-NEXT: local.get 0
+; NO-ATOMICS-NEXT: i32.load 0
+; NO-ATOMICS-NEXT: local.tee 3
+; NO-ATOMICS-NEXT: local.get 3
+; NO-ATOMICS-NEXT: local.get 1
+; NO-ATOMICS-NEXT: i32.eq
+; NO-ATOMICS-NEXT: i32.select
+; NO-ATOMICS-NEXT: i32.store 0
+; NO-ATOMICS-NEXT: local.get 3
+; NO-ATOMICS-NEXT: # fallthrough-return
+;
+; ATOMICS-LABEL: cmpxchg_i32_acq_rel_monotonic:
+; ATOMICS: .functype cmpxchg_i32_acq_rel_monotonic (i32, i32, i32) -> (i32)
+; ATOMICS-NEXT: # %bb.0:
+; ATOMICS-NEXT: local.get 0
+; ATOMICS-NEXT: local.get 1
+; ATOMICS-NEXT: local.get 2
+; ATOMICS-NEXT: i32.atomic.rmw.cmpxchg 0
+; ATOMICS-NEXT: # fallthrough-return
+;
+; RELAXED32-LABEL: cmpxchg_i32_acq_rel_monotonic:
+; RELAXED32: .functype cmpxchg_i32_acq_rel_monotonic (i32, i32, i32) -> (i32)
+; RELAXED32-NEXT: # %bb.0:
+; RELAXED32-NEXT: local.get 0
+; RELAXED32-NEXT: local.get 1
+; RELAXED32-NEXT: local.get 2
+; RELAXED32-NEXT: i32.atomic.rmw.cmpxchg acqrel 0
+; RELAXED32-NEXT: # fallthrough-return
+;
+; RELAXED64-LABEL: cmpxchg_i32_acq_rel_monotonic:
+; RELAXED64: .functype cmpxchg_i32_acq_rel_monotonic (i64, i32, i32) -> (i32)
+; RELAXED64-NEXT: # %bb.0:
+; RELAXED64-NEXT: local.get 0
+; RELAXED64-NEXT: local.get 1
+; RELAXED64-NEXT: local.get 2
+; RELAXED64-NEXT: i32.atomic.rmw.cmpxchg acqrel 0
+; RELAXED64-NEXT: # fallthrough-return
%pair = cmpxchg ptr %p, i32 %exp, i32 %new acq_rel monotonic
%old = extractvalue { i32, i1 } %pair, 0
ret i32 %old
}
-; CHECK-LABEL: cmpxchg_i32_seq_cst_monotonic:
-; CHECK-NEXT: .functype cmpxchg_i32_seq_cst_monotonic (i32, i32, i32) -> (i32){{$}}
-; CHECK: i32.atomic.rmw.cmpxchg $push0=, 0($0), $1, $2{{$}}
-; CHECK-NEXT: return $pop0{{$}}
define i32 @cmpxchg_i32_seq_cst_monotonic(ptr %p, i32 %exp, i32 %new) {
+; NO-ATOMICS-LABEL: cmpxchg_i32_seq_cst_monotonic:
+; NO-ATOMICS: .functype cmpxchg_i32_seq_cst_monotonic (i32, i32, i32) -> (i32)
+; NO-ATOMICS-NEXT: .local i32
+; NO-ATOMICS-NEXT: # %bb.0:
+; NO-ATOMICS-NEXT: local.get 0
+; NO-ATOMICS-NEXT: local.get 2
+; NO-ATOMICS-NEXT: local.get 0
+; NO-ATOMICS-NEXT: i32.load 0
+; NO-ATOMICS-NEXT: local.tee 3
+; NO-ATOMICS-NEXT: local.get 3
+; NO-ATOMICS-NEXT: local.get 1
+; NO-ATOMICS-NEXT: i32.eq
+; NO-ATOMICS-NEXT: i32.select
+; NO-ATOMICS-NEXT: i32.store 0
+; NO-ATOMICS-NEXT: local.get 3
+; NO-ATOMICS-NEXT: # fallthrough-return
+;
+; ATOMICS-LABEL: cmpxchg_i32_seq_cst_monotonic:
+; ATOMICS: .functype cmpxchg_i32_seq_cst_monotonic (i32, i32, i32) -> (i32)
+; ATOMICS-NEXT: # %bb.0:
+; ATOMICS-NEXT: local.get 0
+; ATOMICS-NEXT: local.get 1
+; ATOMICS-NEXT: local.get 2
+; ATOMICS-NEXT: i32.atomic.rmw.cmpxchg 0
+; ATOMICS-NEXT: # fallthrough-return
+;
+; RELAXED32-LABEL: cmpxchg_i32_seq_cst_monotonic:
+; RELAXED32: .functype cmpxchg_i32_seq_cst_monotonic (i32, i32, i32) -> (i32)
+; RELAXED32-NEXT: # %bb.0:
+; RELAXED32-NEXT: local.get 0
+; RELAXED32-NEXT: local.get 1
+; RELAXED32-NEXT: local.get 2
+; RELAXED32-NEXT: i32.atomic.rmw.cmpxchg seqcst 0
+; RELAXED32-NEXT: # fallthrough-return
+;
+; RELAXED64-LABEL: cmpxchg_i32_seq_cst_monotonic:
+; RELAXED64: .functype cmpxchg_i32_seq_cst_monotonic (i64, i32, i32) -> (i32)
+; RELAXED64-NEXT: # %bb.0:
+; RELAXED64-NEXT: local.get 0
+; RELAXED64-NEXT: local.get 1
+; RELAXED64-NEXT: local.get 2
+; RELAXED64-NEXT: i32.atomic.rmw.cmpxchg seqcst 0
+; RELAXED64-NEXT: # fallthrough-return
%pair = cmpxchg ptr %p, i32 %exp, i32 %new seq_cst monotonic
%old = extractvalue { i32, i1 } %pair, 0
ret i32 %old
}
-; CHECK-LABEL: cmpxchg_i32_acquire_acquire:
-; CHECK-NEXT: .functype cmpxchg_i32_acquire_acquire (i32, i32, i32) -> (i32){{$}}
-; CHECK: i32.atomic.rmw.cmpxchg $push0=, 0($0), $1, $2{{$}}
-; CHECK-NEXT: return $pop0{{$}}
define i32 @cmpxchg_i32_acquire_acquire(ptr %p, i32 %exp, i32 %new) {
+; NO-ATOMICS-LABEL: cmpxchg_i32_acquire_acquire:
+; NO-ATOMICS: .functype cmpxchg_i32_acquire_acquire (i32, i32, i32) -> (i32)
+; NO-ATOMICS-NEXT: .local i32
+; NO-ATOMICS-NEXT: # %bb.0:
+; NO-ATOMICS-NEXT: local.get 0
+; NO-ATOMICS-NEXT: local.get 2
+; NO-ATOMICS-NEXT: local.get 0
+; NO-ATOMICS-NEXT: i32.load 0
+; NO-ATOMICS-NEXT: local.tee 3
+; NO-ATOMICS-NEXT: local.get 3
+; NO-ATOMICS-NEXT: local.get 1
+; NO-ATOMICS-NEXT: i32.eq
+; NO-ATOMICS-NEXT: i32.select
+; NO-ATOMICS-NEXT: i32.store 0
+; NO-ATOMICS-NEXT: local.get 3
+; NO-ATOMICS-NEXT: # fallthrough-return
+;
+; ATOMICS-LABEL: cmpxchg_i32_acquire_acquire:
+; ATOMICS: .functype cmpxchg_i32_acquire_acquire (i32, i32, i32) -> (i32)
+; ATOMICS-NEXT: # %bb.0:
+; ATOMICS-NEXT: local.get 0
+; ATOMICS-NEXT: local.get 1
+; ATOMICS-NEXT: local.get 2
+; ATOMICS-NEXT: i32.atomic.rmw.cmpxchg 0
+; ATOMICS-NEXT: # fallthrough-return
+;
+; RELAXED32-LABEL: cmpxchg_i32_acquire_acquire:
+; RELAXED32: .functype cmpxchg_i32_acquire_acquire (i32, i32, i32) -> (i32)
+; RELAXED32-NEXT: # %bb.0:
+; RELAXED32-NEXT: local.get 0
+; RELAXED32-NEXT: local.get 1
+; RELAXED32-NEXT: local.get 2
+; RELAXED32-NEXT: i32.atomic.rmw.cmpxchg acqrel 0
+; RELAXED32-NEXT: # fallthrough-return
+;
+; RELAXED64-LABEL: cmpxchg_i32_acquire_acquire:
+; RELAXED64: .functype cmpxchg_i32_acquire_acquire (i64, i32, i32) -> (i32)
+; RELAXED64-NEXT: # %bb.0:
+; RELAXED64-NEXT: local.get 0
+; RELAXED64-NEXT: local.get 1
+; RELAXED64-NEXT: local.get 2
+; RELAXED64-NEXT: i32.atomic.rmw.cmpxchg acqrel 0
+; RELAXED64-NEXT: # fallthrough-return
%pair = cmpxchg ptr %p, i32 %exp, i32 %new acquire acquire
%old = extractvalue { i32, i1 } %pair, 0
ret i32 %old
}
-; CHECK-LABEL: cmpxchg_i32_release_acquire:
-; CHECK-NEXT: .functype cmpxchg_i32_release_acquire (i32, i32, i32) -> (i32){{$}}
-; CHECK: i32.atomic.rmw.cmpxchg $push0=, 0($0), $1, $2{{$}}
-; CHECK-NEXT: return $pop0{{$}}
define i32 @cmpxchg_i32_release_acquire(ptr %p, i32 %exp, i32 %new) {
+; NO-ATOMICS-LABEL: cmpxchg_i32_release_acquire:
+; NO-ATOMICS: .functype cmpxchg_i32_release_acquire (i32, i32, i32) -> (i32)
+; NO-ATOMICS-NEXT: .local i32
+; NO-ATOMICS-NEXT: # %bb.0:
+; NO-ATOMICS-NEXT: local.get 0
+; NO-ATOMICS-NEXT: local.get 2
+; NO-ATOMICS-NEXT: local.get 0
+; NO-ATOMICS-NEXT: i32.load 0
+; NO-ATOMICS-NEXT: local.tee 3
+; NO-ATOMICS-NEXT: local.get 3
+; NO-ATOMICS-NEXT: local.get 1
+; NO-ATOMICS-NEXT: i32.eq
+; NO-ATOMICS-NEXT: i32.select
+; NO-ATOMICS-NEXT: i32.store 0
+; NO-ATOMICS-NEXT: local.get 3
+; NO-ATOMICS-NEXT: # fallthrough-return
+;
+; ATOMICS-LABEL: cmpxchg_i32_release_acquire:
+; ATOMICS: .functype cmpxchg_i32_release_acquire (i32, i32, i32) -> (i32)
+; ATOMICS-NEXT: # %bb.0:
+; ATOMICS-NEXT: local.get 0
+; ATOMICS-NEXT: local.get 1
+; ATOMICS-NEXT: local.get 2
+; ATOMICS-NEXT: i32.atomic.rmw.cmpxchg 0
+; ATOMICS-NEXT: # fallthrough-return
+;
+; RELAXED32-LABEL: cmpxchg_i32_release_acquire:
+; RELAXED32: .functype cmpxchg_i32_release_acquire (i32, i32, i32) -> (i32)
+; RELAXED32-NEXT: # %bb.0:
+; RELAXED32-NEXT: local.get 0
+; RELAXED32-NEXT: local.get 1
+; RELAXED32-NEXT: local.get 2
+; RELAXED32-NEXT: i32.atomic.rmw.cmpxchg acqrel 0
+; RELAXED32-NEXT: # fallthrough-return
+;
+; RELAXED64-LABEL: cmpxchg_i32_release_acquire:
+; RELAXED64: .functype cmpxchg_i32_release_acquire (i64, i32, i32) -> (i32)
+; RELAXED64-NEXT: # %bb.0:
+; RELAXED64-NEXT: local.get 0
+; RELAXED64-NEXT: local.get 1
+; RELAXED64-NEXT: local.get 2
+; RELAXED64-NEXT: i32.atomic.rmw.cmpxchg acqrel 0
+; RELAXED64-NEXT: # fallthrough-return
%pair = cmpxchg ptr %p, i32 %exp, i32 %new release acquire
%old = extractvalue { i32, i1 } %pair, 0
ret i32 %old
}
-; CHECK-LABEL: cmpxchg_i32_acq_rel_acquire:
-; CHECK-NEXT: .functype cmpxchg_i32_acq_rel_acquire (i32, i32, i32) -> (i32){{$}}
-; CHECK: i32.atomic.rmw.cmpxchg $push0=, 0($0), $1, $2{{$}}
-; CHECK-NEXT: return $pop0{{$}}
define i32 @cmpxchg_i32_acq_rel_acquire(ptr %p, i32 %exp, i32 %new) {
+; NO-ATOMICS-LABEL: cmpxchg_i32_acq_rel_acquire:
+; NO-ATOMICS: .functype cmpxchg_i32_acq_rel_acquire (i32, i32, i32) -> (i32)
+; NO-ATOMICS-NEXT: .local i32
+; NO-ATOMICS-NEXT: # %bb.0:
+; NO-ATOMICS-NEXT: local.get 0
+; NO-ATOMICS-NEXT: local.get 2
+; NO-ATOMICS-NEXT: local.get 0
+; NO-ATOMICS-NEXT: i32.load 0
+; NO-ATOMICS-NEXT: local.tee 3
+; NO-ATOMICS-NEXT: local.get 3
+; NO-ATOMICS-NEXT: local.get 1
+; NO-ATOMICS-NEXT: i32.eq
+; NO-ATOMICS-NEXT: i32.select
+; NO-ATOMICS-NEXT: i32.store 0
+; NO-ATOMICS-NEXT: local.get 3
+; NO-ATOMICS-NEXT: # fallthrough-return
+;
+; ATOMICS-LABEL: cmpxchg_i32_acq_rel_acquire:
+; ATOMICS: .functype cmpxchg_i32_acq_rel_acquire (i32, i32, i32) -> (i32)
+; ATOMICS-NEXT: # %bb.0:
+; ATOMICS-NEXT: local.get 0
+; ATOMICS-NEXT: local.get 1
+; ATOMICS-NEXT: local.get 2
+; ATOMICS-NEXT: i32.atomic.rmw.cmpxchg 0
+; ATOMICS-NEXT: # fallthrough-return
+;
+; RELAXED32-LABEL: cmpxchg_i32_acq_rel_acquire:
+; RELAXED32: .functype cmpxchg_i32_acq_rel_acquire (i32, i32, i32) -> (i32)
+; RELAXED32-NEXT: # %bb.0:
+; RELAXED32-NEXT: local.get 0
+; RELAXED32-NEXT: local.get 1
+; RELAXED32-NEXT: local.get 2
+; RELAXED32-NEXT: i32.atomic.rmw.cmpxchg acqrel 0
+; RELAXED32-NEXT: # fallthrough-return
+;
+; RELAXED64-LABEL: cmpxchg_i32_acq_rel_acquire:
+; RELAXED64: .functype cmpxchg_i32_acq_rel_acquire (i64, i32, i32) -> (i32)
+; RELAXED64-NEXT: # %bb.0:
+; RELAXED64-NEXT: local.get 0
+; RELAXED64-NEXT: local.get 1
+; RELAXED64-NEXT: local.get 2
+; RELAXED64-NEXT: i32.atomic.rmw.cmpxchg acqrel 0
+; RELAXED64-NEXT: # fallthrough-return
%pair = cmpxchg ptr %p, i32 %exp, i32 %new acq_rel acquire
%old = extractvalue { i32, i1 } %pair, 0
ret i32 %old
@@ -230,16 +915,98 @@ define i32 @cmpxchg_i32_acq_rel_acquire(ptr %p, i32 %exp, i32 %new) {
; CHECK: i32.atomic.rmw.cmpxchg $push0=, 0($0), $1, $2{{$}}
; CHECK-NEXT: return $pop0{{$}}
define i32 @cmpxchg_i32_seq_cst_acquire(ptr %p, i32 %exp, i32 %new) {
+; NO-ATOMICS-LABEL: cmpxchg_i32_seq_cst_acquire:
+; NO-ATOMICS: .functype cmpxchg_i32_seq_cst_acquire (i32, i32, i32) -> (i32)
+; NO-ATOMICS-NEXT: .local i32
+; NO-ATOMICS-NEXT: # %bb.0:
+; NO-ATOMICS-NEXT: local.get 0
+; NO-ATOMICS-NEXT: local.get 2
+; NO-ATOMICS-NEXT: local.get 0
+; NO-ATOMICS-NEXT: i32.load 0
+; NO-ATOMICS-NEXT: local.tee 3
+; NO-ATOMICS-NEXT: local.get 3
+; NO-ATOMICS-NEXT: local.get 1
+; NO-ATOMICS-NEXT: i32.eq
+; NO-ATOMICS-NEXT: i32.select
+; NO-ATOMICS-NEXT: i32.store 0
+; NO-ATOMICS-NEXT: local.get 3
+; NO-ATOMICS-NEXT: # fallthrough-return
+;
+; ATOMICS-LABEL: cmpxchg_i32_seq_cst_acquire:
+; ATOMICS: .functype cmpxchg_i32_seq_cst_acquire (i32, i32, i32) -> (i32)
+; ATOMICS-NEXT: # %bb.0:
+; ATOMICS-NEXT: local.get 0
+; ATOMICS-NEXT: local.get 1
+; ATOMICS-NEXT: local.get 2
+; ATOMICS-NEXT: i32.atomic.rmw.cmpxchg 0
+; ATOMICS-NEXT: # fallthrough-return
+;
+; RELAXED32-LABEL: cmpxchg_i32_seq_cst_acquire:
+; RELAXED32: .functype cmpxchg_i32_seq_cst_acquire (i32, i32, i32) -> (i32)
+; RELAXED32-NEXT: # %bb.0:
+; RELAXED32-NEXT: local.get 0
+; RELAXED32-NEXT: local.get 1
+; RELAXED32-NEXT: local.get 2
+; RELAXED32-NEXT: i32.atomic.rmw.cmpxchg seqcst 0
+; RELAXED32-NEXT: # fallthrough-return
+;
+; RELAXED64-LABEL: cmpxchg_i32_seq_cst_acquire:
+; RELAXED64: .functype cmpxchg_i32_seq_cst_acquire (i64, i32, i32) -> (i32)
+; RELAXED64-NEXT: # %bb.0:
+; RELAXED64-NEXT: local.get 0
+; RELAXED64-NEXT: local.get 1
+; RELAXED64-NEXT: local.get 2
+; RELAXED64-NEXT: i32.atomic.rmw.cmpxchg seqcst 0
+; RELAXED64-NEXT: # fallthrough-return
%pair = cmpxchg ptr %p, i32 %exp, i32 %new seq_cst acquire
%old = extractvalue { i32, i1 } %pair, 0
ret i32 %old
}
-; CHECK-LABEL: cmpxchg_i32_seq_cst_seq_cst:
-; CHECK-NEXT: .functype cmpxchg_i32_seq_cst_seq_cst (i32, i32, i32) -> (i32){{$}}
-; CHECK: i32.atomic.rmw.cmpxchg $push0=, 0($0), $1, $2{{$}}
-; CHECK-NEXT: return $pop0{{$}}
define i32 @cmpxchg_i32_seq_cst_seq_cst(ptr %p, i32 %exp, i32 %new) {
+; NO-ATOMICS-LABEL: cmpxchg_i32_seq_cst_seq_cst:
+; NO-ATOMICS: .functype cmpxchg_i32_seq_cst_seq_cst (i32, i32, i32) -> (i32)
+; NO-ATOMICS-NEXT: .local i32
+; NO-ATOMICS-NEXT: # %bb.0:
+; NO-ATOMICS-NEXT: local.get 0
+; NO-ATOMICS-NEXT: local.get 2
+; NO-ATOMICS-NEXT: local.get 0
+; NO-ATOMICS-NEXT: i32.load 0
+; NO-ATOMICS-NEXT: local.tee 3
+; NO-ATOMICS-NEXT: local.get 3
+; NO-ATOMICS-NEXT: local.get 1
+; NO-ATOMICS-NEXT: i32.eq
+; NO-ATOMICS-NEXT: i32.select
+; NO-ATOMICS-NEXT: i32.store 0
+; NO-ATOMICS-NEXT: local.get 3
+; NO-ATOMICS-NEXT: # fallthrough-return
+;
+; ATOMICS-LABEL: cmpxchg_i32_seq_cst_seq_cst:
+; ATOMICS: .functype cmpxchg_i32_seq_cst_seq_cst (i32, i32, i32) -> (i32)
+; ATOMICS-NEXT: # %bb.0:
+; ATOMICS-NEXT: local.get 0
+; ATOMICS-NEXT: local.get 1
+; ATOMICS-NEXT: local.get 2
+; ATOMICS-NEXT: i32.atomic.rmw.cmpxchg 0
+; ATOMICS-NEXT: # fallthrough-return
+;
+; RELAXED32-LABEL: cmpxchg_i32_seq_cst_seq_cst:
+; RELAXED32: .functype cmpxchg_i32_seq_cst_seq_cst (i32, i32, i32) -> (i32)
+; RELAXED32-NEXT: # %bb.0:
+; RELAXED32-NEXT: local.get 0
+; RELAXED32-NEXT: local.get 1
+; RELAXED32-NEXT: local.get 2
+; RELAXED32-NEXT: i32.atomic.rmw.cmpxchg seqcst 0
+; RELAXED32-NEXT: # fallthrough-return
+;
+; RELAXED64-LABEL: cmpxchg_i32_seq_cst_seq_cst:
+; RELAXED64: .functype cmpxchg_i32_seq_cst_seq_cst (i64, i32, i32) -> (i32)
+; RELAXED64-NEXT: # %bb.0:
+; RELAXED64-NEXT: local.get 0
+; RELAXED64-NEXT: local.get 1
+; RELAXED64-NEXT: local.get 2
+; RELAXED64-NEXT: i32.atomic.rmw.cmpxchg seqcst 0
+; RELAXED64-NEXT: # fallthrough-return
%pair = cmpxchg ptr %p, i32 %exp, i32 %new seq_cst seq_cst
%old = extractvalue { i32, i1 } %pair, 0
ret i32 %old
diff --git a/llvm/test/CodeGen/WebAssembly/atomics-orderings.ll b/llvm/test/CodeGen/WebAssembly/atomics-orderings.ll
deleted file mode 100644
index 3cc623c8c329d..0000000000000
--- a/llvm/test/CodeGen/WebAssembly/atomics-orderings.ll
+++ /dev/null
@@ -1,396 +0,0 @@
-; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 6
-; RUN: llc < %s --mtriple=wasm32 -mattr=+atomics,+relaxed-atomics | FileCheck %s --check-prefixes=WASM32
-; RUN: llc < %s --mtriple=wasm64 -mattr=+atomics,+relaxed-atomics | FileCheck %s --check-prefixes=WASM64
-
-define i32 @load_i32_acquire(ptr %p) {
-; WASM32-LABEL: load_i32_acquire:
-; WASM32: .functype load_i32_acquire (i32) -> (i32)
-; WASM32-NEXT: # %bb.0:
-; WASM32-NEXT: local.get 0
-; WASM32-NEXT: i32.atomic.load acqrel 0
-; WASM32-NEXT: # fallthrough-return
-;
-; WASM64-LABEL: load_i32_acquire:
-; WASM64: .functype load_i32_acquire (i64) -> (i32)
-; WASM64-NEXT: # %bb.0:
-; WASM64-NEXT: local.get 0
-; WASM64-NEXT: i32.atomic.load acqrel 0
-; WASM64-NEXT: # fallthrough-return
- %v = load atomic i32, ptr %p acquire, align 4
- ret i32 %v
-}
-
-define i32 @load_i32_seq_cst(ptr %p) {
-; WASM32-LABEL: load_i32_seq_cst:
-; WASM32: .functype load_i32_seq_cst (i32) -> (i32)
-; WASM32-NEXT: # %bb.0:
-; WASM32-NEXT: local.get 0
-; WASM32-NEXT: i32.atomic.load seqcst 0
-; WASM32-NEXT: # fallthrough-return
-;
-; WASM64-LABEL: load_i32_seq_cst:
-; WASM64: .functype load_i32_seq_cst (i64) -> (i32)
-; WASM64-NEXT: # %bb.0:
-; WASM64-NEXT: local.get 0
-; WASM64-NEXT: i32.atomic.load seqcst 0
-; WASM64-NEXT: # fallthrough-return
- %v = load atomic i32, ptr %p seq_cst, align 4
- ret i32 %v
-}
-
-define void @store_i32_release(ptr %p, i32 %v) {
-; WASM32-LABEL: store_i32_release:
-; WASM32: .functype store_i32_release (i32, i32) -> ()
-; WASM32-NEXT: # %bb.0:
-; WASM32-NEXT: local.get 0
-; WASM32-NEXT: local.get 1
-; WASM32-NEXT: i32.atomic.store acqrel 0
-; WASM32-NEXT: # fallthrough-return
-;
-; WASM64-LABEL: store_i32_release:
-; WASM64: .functype store_i32_release (i64, i32) -> ()
-; WASM64-NEXT: # %bb.0:
-; WASM64-NEXT: local.get 0
-; WASM64-NEXT: local.get 1
-; WASM64-NEXT: i32.atomic.store acqrel 0
-; WASM64-NEXT: # fallthrough-return
- store atomic i32 %v, ptr %p release, align 4
- ret void
-}
-
-define void @store_i32_seq_cst(ptr %p, i32 %v) {
-; WASM32-LABEL: store_i32_seq_cst:
-; WASM32: .functype store_i32_seq_cst (i32, i32) -> ()
-; WASM32-NEXT: # %bb.0:
-; WASM32-NEXT: local.get 0
-; WASM32-NEXT: local.get 1
-; WASM32-NEXT: i32.atomic.store seqcst 0
-; WASM32-NEXT: # fallthrough-return
-;
-; WASM64-LABEL: store_i32_seq_cst:
-; WASM64: .functype store_i32_seq_cst (i64, i32) -> ()
-; WASM64-NEXT: # %bb.0:
-; WASM64-NEXT: local.get 0
-; WASM64-NEXT: local.get 1
-; WASM64-NEXT: i32.atomic.store seqcst 0
-; WASM64-NEXT: # fallthrough-return
- store atomic i32 %v, ptr %p seq_cst, align 4
- ret void
-}
-
-define i32 @add_i32_acq_rel(ptr %p, i32 %v) {
-; WASM32-LABEL: add_i32_acq_rel:
-; WASM32: .functype add_i32_acq_rel (i32, i32) -> (i32)
-; WASM32-NEXT: # %bb.0:
-; WASM32-NEXT: local.get 0
-; WASM32-NEXT: local.get 1
-; WASM32-NEXT: i32.atomic.rmw.add acqrel 0
-; WASM32-NEXT: # fallthrough-return
-;
-; WASM64-LABEL: add_i32_acq_rel:
-; WASM64: .functype add_i32_acq_rel (i64, i32) -> (i32)
-; WASM64-NEXT: # %bb.0:
-; WASM64-NEXT: local.get 0
-; WASM64-NEXT: local.get 1
-; WASM64-NEXT: i32.atomic.rmw.add acqrel 0
-; WASM64-NEXT: # fallthrough-return
- %old = atomicrmw add ptr %p, i32 %v acq_rel
- ret i32 %old
-}
-
-define i32 @add_i32_seq_cst(ptr %p, i32 %v) {
-; WASM32-LABEL: add_i32_seq_cst:
-; WASM32: .functype add_i32_seq_cst (i32, i32) -> (i32)
-; WASM32-NEXT: # %bb.0:
-; WASM32-NEXT: local.get 0
-; WASM32-NEXT: local.get 1
-; WASM32-NEXT: i32.atomic.rmw.add seqcst 0
-; WASM32-NEXT: # fallthrough-return
-;
-; WASM64-LABEL: add_i32_seq_cst:
-; WASM64: .functype add_i32_seq_cst (i64, i32) -> (i32)
-; WASM64-NEXT: # %bb.0:
-; WASM64-NEXT: local.get 0
-; WASM64-NEXT: local.get 1
-; WASM64-NEXT: i32.atomic.rmw.add seqcst 0
-; WASM64-NEXT: # fallthrough-return
- %old = atomicrmw add ptr %p, i32 %v seq_cst
- ret i32 %old
-}
-
-define i32 @cmpxchg_i32_acquire_acquire(ptr %p, i32 %exp, i32 %new) {
-; WASM32-LABEL: cmpxchg_i32_acquire_acquire:
-; WASM32: .functype cmpxchg_i32_acquire_acquire (i32, i32, i32) -> (i32)
-; WASM32-NEXT: # %bb.0:
-; WASM32-NEXT: local.get 0
-; WASM32-NEXT: local.get 1
-; WASM32-NEXT: local.get 2
-; WASM32-NEXT: i32.atomic.rmw.cmpxchg acqrel 0
-; WASM32-NEXT: # fallthrough-return
-;
-; WASM64-LABEL: cmpxchg_i32_acquire_acquire:
-; WASM64: .functype cmpxchg_i32_acquire_acquire (i64, i32, i32) -> (i32)
-; WASM64-NEXT: # %bb.0:
-; WASM64-NEXT: local.get 0
-; WASM64-NEXT: local.get 1
-; WASM64-NEXT: local.get 2
-; WASM64-NEXT: i32.atomic.rmw.cmpxchg acqrel 0
-; WASM64-NEXT: # fallthrough-return
- %pair = cmpxchg ptr %p, i32 %exp, i32 %new acquire acquire
- %val = extractvalue { i32, i1 } %pair, 0
- ret i32 %val
-}
-
-define i32 @cmpxchg_i32_seq_cst_seq_cst(ptr %p, i32 %exp, i32 %new) {
-; WASM32-LABEL: cmpxchg_i32_seq_cst_seq_cst:
-; WASM32: .functype cmpxchg_i32_seq_cst_seq_cst (i32, i32, i32) -> (i32)
-; WASM32-NEXT: # %bb.0:
-; WASM32-NEXT: local.get 0
-; WASM32-NEXT: local.get 1
-; WASM32-NEXT: local.get 2
-; WASM32-NEXT: i32.atomic.rmw.cmpxchg seqcst 0
-; WASM32-NEXT: # fallthrough-return
-;
-; WASM64-LABEL: cmpxchg_i32_seq_cst_seq_cst:
-; WASM64: .functype cmpxchg_i32_seq_cst_seq_cst (i64, i32, i32) -> (i32)
-; WASM64-NEXT: # %bb.0:
-; WASM64-NEXT: local.get 0
-; WASM64-NEXT: local.get 1
-; WASM64-NEXT: local.get 2
-; WASM64-NEXT: i32.atomic.rmw.cmpxchg seqcst 0
-; WASM64-NEXT: # fallthrough-return
- %pair = cmpxchg ptr %p, i32 %exp, i32 %new seq_cst seq_cst
- %val = extractvalue { i32, i1 } %pair, 0
- ret i32 %val
-}
-
-define void @fence_acquire() {
-; WASM32-LABEL: fence_acquire:
-; WASM32: .functype fence_acquire () -> ()
-; WASM32-NEXT: # %bb.0:
-; WASM32-NEXT: atomic.fence acqrel
-; WASM32-NEXT: # fallthrough-return
-;
-; WASM64-LABEL: fence_acquire:
-; WASM64: .functype fence_acquire () -> ()
-; WASM64-NEXT: # %bb.0:
-; WASM64-NEXT: atomic.fence acqrel
-; WASM64-NEXT: # fallthrough-return
- fence acquire
- ret void
-}
-
-define void @fence_seq_cst() {
-; WASM32-LABEL: fence_seq_cst:
-; WASM32: .functype fence_seq_cst () -> ()
-; WASM32-NEXT: # %bb.0:
-; WASM32-NEXT: atomic.fence seqcst
-; WASM32-NEXT: # fallthrough-return
-;
-; WASM64-LABEL: fence_seq_cst:
-; WASM64: .functype fence_seq_cst () -> ()
-; WASM64-NEXT: # %bb.0:
-; WASM64-NEXT: atomic.fence seqcst
-; WASM64-NEXT: # fallthrough-return
- fence seq_cst
- ret void
-}
-
-define i32 @load_i32_monotonic(ptr %p) {
-; WASM32-LABEL: load_i32_monotonic:
-; WASM32: .functype load_i32_monotonic (i32) -> (i32)
-; WASM32-NEXT: # %bb.0:
-; WASM32-NEXT: local.get 0
-; WASM32-NEXT: i32.atomic.load acqrel 0
-; WASM32-NEXT: # fallthrough-return
-;
-; WASM64-LABEL: load_i32_monotonic:
-; WASM64: .functype load_i32_monotonic (i64) -> (i32)
-; WASM64-NEXT: # %bb.0:
-; WASM64-NEXT: local.get 0
-; WASM64-NEXT: i32.atomic.load acqrel 0
-; WASM64-NEXT: # fallthrough-return
- %v = load atomic i32, ptr %p monotonic, align 4
- ret i32 %v
-}
-
-define void @store_i32_monotonic(ptr %p, i32 %v) {
-; WASM32-LABEL: store_i32_monotonic:
-; WASM32: .functype store_i32_monotonic (i32, i32) -> ()
-; WASM32-NEXT: # %bb.0:
-; WASM32-NEXT: local.get 0
-; WASM32-NEXT: local.get 1
-; WASM32-NEXT: i32.atomic.store acqrel 0
-; WASM32-NEXT: # fallthrough-return
-;
-; WASM64-LABEL: store_i32_monotonic:
-; WASM64: .functype store_i32_monotonic (i64, i32) -> ()
-; WASM64-NEXT: # %bb.0:
-; WASM64-NEXT: local.get 0
-; WASM64-NEXT: local.get 1
-; WASM64-NEXT: i32.atomic.store acqrel 0
-; WASM64-NEXT: # fallthrough-return
- store atomic i32 %v, ptr %p monotonic, align 4
- ret void
-}
-
-define i32 @add_i32_release(ptr %p, i32 %v) {
-; WASM32-LABEL: add_i32_release:
-; WASM32: .functype add_i32_release (i32, i32) -> (i32)
-; WASM32-NEXT: # %bb.0:
-; WASM32-NEXT: local.get 0
-; WASM32-NEXT: local.get 1
-; WASM32-NEXT: i32.atomic.rmw.add acqrel 0
-; WASM32-NEXT: # fallthrough-return
-;
-; WASM64-LABEL: add_i32_release:
-; WASM64: .functype add_i32_release (i64, i32) -> (i32)
-; WASM64-NEXT: # %bb.0:
-; WASM64-NEXT: local.get 0
-; WASM64-NEXT: local.get 1
-; WASM64-NEXT: i32.atomic.rmw.add acqrel 0
-; WASM64-NEXT: # fallthrough-return
- %old = atomicrmw add ptr %p, i32 %v release
- ret i32 %old
-}
-
-define i32 @add_i32_acquire(ptr %p, i32 %v) {
-; WASM32-LABEL: add_i32_acquire:
-; WASM32: .functype add_i32_acquire (i32, i32) -> (i32)
-; WASM32-NEXT: # %bb.0:
-; WASM32-NEXT: local.get 0
-; WASM32-NEXT: local.get 1
-; WASM32-NEXT: i32.atomic.rmw.add acqrel 0
-; WASM32-NEXT: # fallthrough-return
-;
-; WASM64-LABEL: add_i32_acquire:
-; WASM64: .functype add_i32_acquire (i64, i32) -> (i32)
-; WASM64-NEXT: # %bb.0:
-; WASM64-NEXT: local.get 0
-; WASM64-NEXT: local.get 1
-; WASM64-NEXT: i32.atomic.rmw.add acqrel 0
-; WASM64-NEXT: # fallthrough-return
- %old = atomicrmw add ptr %p, i32 %v acquire
- ret i32 %old
-}
-
-define i32 @add_i32_monotonic(ptr %p, i32 %v) {
-; WASM32-LABEL: add_i32_monotonic:
-; WASM32: .functype add_i32_monotonic (i32, i32) -> (i32)
-; WASM32-NEXT: # %bb.0:
-; WASM32-NEXT: local.get 0
-; WASM32-NEXT: local.get 1
-; WASM32-NEXT: i32.atomic.rmw.add acqrel 0
-; WASM32-NEXT: # fallthrough-return
-;
-; WASM64-LABEL: add_i32_monotonic:
-; WASM64: .functype add_i32_monotonic (i64, i32) -> (i32)
-; WASM64-NEXT: # %bb.0:
-; WASM64-NEXT: local.get 0
-; WASM64-NEXT: local.get 1
-; WASM64-NEXT: i32.atomic.rmw.add acqrel 0
-; WASM64-NEXT: # fallthrough-return
- %old = atomicrmw add ptr %p, i32 %v monotonic
- ret i32 %old
-}
-
-define i32 @cmpxchg_i32_acq_rel_monotonic(ptr %p, i32 %exp, i32 %new) {
-; WASM32-LABEL: cmpxchg_i32_acq_rel_monotonic:
-; WASM32: .functype cmpxchg_i32_acq_rel_monotonic (i32, i32, i32) -> (i32)
-; WASM32-NEXT: # %bb.0:
-; WASM32-NEXT: local.get 0
-; WASM32-NEXT: local.get 1
-; WASM32-NEXT: local.get 2
-; WASM32-NEXT: i32.atomic.rmw.cmpxchg acqrel 0
-; WASM32-NEXT: # fallthrough-return
-;
-; WASM64-LABEL: cmpxchg_i32_acq_rel_monotonic:
-; WASM64: .functype cmpxchg_i32_acq_rel_monotonic (i64, i32, i32) -> (i32)
-; WASM64-NEXT: # %bb.0:
-; WASM64-NEXT: local.get 0
-; WASM64-NEXT: local.get 1
-; WASM64-NEXT: local.get 2
-; WASM64-NEXT: i32.atomic.rmw.cmpxchg acqrel 0
-; WASM64-NEXT: # fallthrough-return
- %pair = cmpxchg ptr %p, i32 %exp, i32 %new acq_rel monotonic
- %val = extractvalue { i32, i1 } %pair, 0
- ret i32 %val
-}
-
-define i32 @cmpxchg_i32_release_monotonic(ptr %p, i32 %exp, i32 %new) {
-; WASM32-LABEL: cmpxchg_i32_release_monotonic:
-; WASM32: .functype cmpxchg_i32_release_monotonic (i32, i32, i32) -> (i32)
-; WASM32-NEXT: # %bb.0:
-; WASM32-NEXT: local.get 0
-; WASM32-NEXT: local.get 1
-; WASM32-NEXT: local.get 2
-; WASM32-NEXT: i32.atomic.rmw.cmpxchg acqrel 0
-; WASM32-NEXT: # fallthrough-return
-;
-; WASM64-LABEL: cmpxchg_i32_release_monotonic:
-; WASM64: .functype cmpxchg_i32_release_monotonic (i64, i32, i32) -> (i32)
-; WASM64-NEXT: # %bb.0:
-; WASM64-NEXT: local.get 0
-; WASM64-NEXT: local.get 1
-; WASM64-NEXT: local.get 2
-; WASM64-NEXT: i32.atomic.rmw.cmpxchg acqrel 0
-; WASM64-NEXT: # fallthrough-return
- %pair = cmpxchg ptr %p, i32 %exp, i32 %new release monotonic
- %val = extractvalue { i32, i1 } %pair, 0
- ret i32 %val
-}
-
-define i32 @cmpxchg_i32_monotonic_monotonic(ptr %p, i32 %exp, i32 %new) {
-; WASM32-LABEL: cmpxchg_i32_monotonic_monotonic:
-; WASM32: .functype cmpxchg_i32_monotonic_monotonic (i32, i32, i32) -> (i32)
-; WASM32-NEXT: # %bb.0:
-; WASM32-NEXT: local.get 0
-; WASM32-NEXT: local.get 1
-; WASM32-NEXT: local.get 2
-; WASM32-NEXT: i32.atomic.rmw.cmpxchg acqrel 0
-; WASM32-NEXT: # fallthrough-return
-;
-; WASM64-LABEL: cmpxchg_i32_monotonic_monotonic:
-; WASM64: .functype cmpxchg_i32_monotonic_monotonic (i64, i32, i32) -> (i32)
-; WASM64-NEXT: # %bb.0:
-; WASM64-NEXT: local.get 0
-; WASM64-NEXT: local.get 1
-; WASM64-NEXT: local.get 2
-; WASM64-NEXT: i32.atomic.rmw.cmpxchg acqrel 0
-; WASM64-NEXT: # fallthrough-return
- %pair = cmpxchg ptr %p, i32 %exp, i32 %new monotonic monotonic
- %val = extractvalue { i32, i1 } %pair, 0
- ret i32 %val
-}
-
-define void @fence_release() {
-; WASM32-LABEL: fence_release:
-; WASM32: .functype fence_release () -> ()
-; WASM32-NEXT: # %bb.0:
-; WASM32-NEXT: atomic.fence acqrel
-; WASM32-NEXT: # fallthrough-return
-;
-; WASM64-LABEL: fence_release:
-; WASM64: .functype fence_release () -> ()
-; WASM64-NEXT: # %bb.0:
-; WASM64-NEXT: atomic.fence acqrel
-; WASM64-NEXT: # fallthrough-return
- fence release
- ret void
-}
-
-define void @fence_acq_rel() {
-; WASM32-LABEL: fence_acq_rel:
-; WASM32: .functype fence_acq_rel () -> ()
-; WASM32-NEXT: # %bb.0:
-; WASM32-NEXT: atomic.fence acqrel
-; WASM32-NEXT: # fallthrough-return
-;
-; WASM64-LABEL: fence_acq_rel:
-; WASM64: .functype fence_acq_rel () -> ()
-; WASM64-NEXT: # %bb.0:
-; WASM64-NEXT: atomic.fence acqrel
-; WASM64-NEXT: # fallthrough-return
- fence acq_rel
- ret void
-}
More information about the cfe-commits
mailing list