[clang] 4128b21 - [CIR] Add support for non-compile-time memory order (#168892)
via cfe-commits
cfe-commits at lists.llvm.org
Sat Nov 22 03:36:45 PST 2025
Author: Sirui Mu
Date: 2025-11-22T19:36:40+08:00
New Revision: 4128b213ee93750766c57b5b37d239be53b80c26
URL: https://github.com/llvm/llvm-project/commit/4128b213ee93750766c57b5b37d239be53b80c26
DIFF: https://github.com/llvm/llvm-project/commit/4128b213ee93750766c57b5b37d239be53b80c26.diff
LOG: [CIR] Add support for non-compile-time memory order (#168892)
This patch upstreams CIR support for atomic operations with memory
orders that are not known at compile time.
Added:
Modified:
clang/lib/CIR/CodeGen/CIRGenAtomic.cpp
clang/test/CIR/CodeGen/atomic.c
Removed:
################################################################################
diff --git a/clang/lib/CIR/CodeGen/CIRGenAtomic.cpp b/clang/lib/CIR/CodeGen/CIRGenAtomic.cpp
index cd4c1f0e5b769..48c082d89de18 100644
--- a/clang/lib/CIR/CodeGen/CIRGenAtomic.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenAtomic.cpp
@@ -286,6 +286,31 @@ void AtomicInfo::emitCopyIntoMemory(RValue rvalue) const {
}
}
+static void emitMemOrderDefaultCaseLabel(CIRGenBuilderTy &builder,
+ mlir::Location loc) {
+ mlir::ArrayAttr ordersAttr = builder.getArrayAttr({});
+ mlir::OpBuilder::InsertPoint insertPoint;
+ cir::CaseOp::create(builder, loc, ordersAttr, cir::CaseOpKind::Default,
+ insertPoint);
+ builder.restoreInsertionPoint(insertPoint);
+}
+
+// Create a "case" operation with the given list of orders as its values. Also
+// create the region that will hold the body of the switch-case label.
+static void emitMemOrderCaseLabel(CIRGenBuilderTy &builder, mlir::Location loc,
+ mlir::Type orderType,
+ llvm::ArrayRef<cir::MemOrder> orders) {
+ llvm::SmallVector<mlir::Attribute, 2> orderAttrs;
+ for (cir::MemOrder order : orders)
+ orderAttrs.push_back(cir::IntAttr::get(orderType, static_cast<int>(order)));
+ mlir::ArrayAttr ordersAttr = builder.getArrayAttr(orderAttrs);
+
+ mlir::OpBuilder::InsertPoint insertPoint;
+ cir::CaseOp::create(builder, loc, ordersAttr, cir::CaseOpKind::Anyof,
+ insertPoint);
+ builder.restoreInsertionPoint(insertPoint);
+}
+
static void emitAtomicCmpXchg(CIRGenFunction &cgf, AtomicExpr *e, bool isWeak,
Address dest, Address ptr, Address val1,
Address val2, uint64_t size,
@@ -657,6 +682,70 @@ static bool isMemOrderValid(uint64_t order, bool isStore, bool isLoad) {
return true;
}
+static void emitAtomicExprWithDynamicMemOrder(
+ CIRGenFunction &cgf, mlir::Value order, AtomicExpr *e, Address dest,
+ Address ptr, Address val1, Address val2, Expr *isWeakExpr,
+ Expr *orderFailExpr, uint64_t size, bool isStore, bool isLoad) {
+ // The memory order is not known at compile-time. The atomic operations
+ // can't handle runtime memory orders; the memory order must be hard coded.
+ // Generate a "switch" statement that converts a runtime value into a
+ // compile-time value.
+ CIRGenBuilderTy &builder = cgf.getBuilder();
+ cir::SwitchOp::create(
+ builder, order.getLoc(), order,
+ [&](mlir::OpBuilder &, mlir::Location loc, mlir::OperationState &) {
+ mlir::Block *switchBlock = builder.getBlock();
+
+ auto emitMemOrderCase = [&](llvm::ArrayRef<cir::MemOrder> caseOrders,
+ cir::MemOrder actualOrder) {
+ if (caseOrders.empty())
+ emitMemOrderDefaultCaseLabel(builder, loc);
+ else
+ emitMemOrderCaseLabel(builder, loc, order.getType(), caseOrders);
+ emitAtomicOp(cgf, e, dest, ptr, val1, val2, isWeakExpr, orderFailExpr,
+ size, actualOrder);
+ builder.createBreak(loc);
+ builder.setInsertionPointToEnd(switchBlock);
+ };
+
+ // default:
+ // Use memory_order_relaxed for relaxed operations and for any memory
+ // order value that is not supported. There is no good way to report
+ // an unsupported memory order at runtime, hence the fallback to
+ // memory_order_relaxed.
+ emitMemOrderCase(/*caseOrders=*/{}, cir::MemOrder::Relaxed);
+
+ if (!isStore) {
+ // case consume:
+ // case acquire:
+ // memory_order_consume is not implemented; it is always treated
+ // like memory_order_acquire. These memory orders are not valid for
+ // write-only operations.
+ emitMemOrderCase({cir::MemOrder::Consume, cir::MemOrder::Acquire},
+ cir::MemOrder::Acquire);
+ }
+
+ if (!isLoad) {
+ // case release:
+ // memory_order_release is not valid for read-only operations.
+ emitMemOrderCase({cir::MemOrder::Release}, cir::MemOrder::Release);
+ }
+
+ if (!isLoad && !isStore) {
+ // case acq_rel:
+ // memory_order_acq_rel is only valid for read-write operations.
+ emitMemOrderCase({cir::MemOrder::AcquireRelease},
+ cir::MemOrder::AcquireRelease);
+ }
+
+ // case seq_cst:
+ emitMemOrderCase({cir::MemOrder::SequentiallyConsistent},
+ cir::MemOrder::SequentiallyConsistent);
+
+ builder.createYield(loc);
+ });
+}
+
RValue CIRGenFunction::emitAtomicExpr(AtomicExpr *e) {
QualType atomicTy = e->getPtr()->getType()->getPointeeType();
QualType memTy = atomicTy;
@@ -844,9 +933,9 @@ RValue CIRGenFunction::emitAtomicExpr(AtomicExpr *e) {
emitAtomicOp(*this, e, dest, ptr, val1, val2, isWeakExpr, orderFailExpr,
size, static_cast<cir::MemOrder>(ord));
} else {
- assert(!cir::MissingFeatures::atomicExpr());
- cgm.errorNYI(e->getSourceRange(), "emitAtomicExpr: dynamic memory order");
- return RValue::get(nullptr);
+ emitAtomicExprWithDynamicMemOrder(*this, order, e, dest, ptr, val1, val2,
+ isWeakExpr, orderFailExpr, size, isStore,
+ isLoad);
}
if (resultTy->isVoidType())
diff --git a/clang/test/CIR/CodeGen/atomic.c b/clang/test/CIR/CodeGen/atomic.c
index d5bea8446d730..71cb1f1e164b3 100644
--- a/clang/test/CIR/CodeGen/atomic.c
+++ b/clang/test/CIR/CodeGen/atomic.c
@@ -1133,3 +1133,269 @@ int c11_atomic_fetch_nand(_Atomic(int) *ptr, int value) {
// OGCG: %[[RES:.+]] = atomicrmw nand ptr %{{.+}}, i32 %{{.+}} seq_cst, align 4
// OGCG-NEXT: store i32 %[[RES]], ptr %{{.+}}, align 4
}
+
+int atomic_load_dynamic_order(int *ptr, int order) {
+ // CIR-LABEL: atomic_load_dynamic_order
+ // LLVM-LABEL: atomic_load_dynamic_order
+ // OGCG-LABEL: atomic_load_dynamic_order
+
+ return __atomic_load_n(ptr, order);
+
+ // CIR: %[[PTR:.+]] = cir.load align(8) %{{.+}} : !cir.ptr<!cir.ptr<!s32i>>, !cir.ptr<!s32i>
+ // CIR-NEXT: %[[ORDER:.+]] = cir.load align(4) %{{.+}} : !cir.ptr<!s32i>, !s32i
+ // CIR-NEXT: cir.switch (%[[ORDER]] : !s32i) {
+ // CIR-NEXT: cir.case(default, []) {
+ // CIR-NEXT: %[[RES:.+]] = cir.load align(4) atomic(relaxed) %[[PTR]] : !cir.ptr<!s32i>, !s32i
+ // CIR-NEXT: cir.store align(4) %[[RES]], %[[RES_SLOT:.+]] : !s32i, !cir.ptr<!s32i>
+ // CIR-NEXT: cir.break
+ // CIR-NEXT: }
+ // CIR-NEXT: cir.case(anyof, [#cir.int<1> : !s32i, #cir.int<2> : !s32i]) {
+ // CIR-NEXT: %[[RES:.+]] = cir.load align(4) atomic(acquire) %[[PTR]] : !cir.ptr<!s32i>, !s32i
+ // CIR-NEXT: cir.store align(4) %[[RES]], %[[RES_SLOT]] : !s32i, !cir.ptr<!s32i>
+ // CIR-NEXT: cir.break
+ // CIR-NEXT: }
+ // CIR-NEXT: cir.case(anyof, [#cir.int<5> : !s32i]) {
+ // CIR-NEXT: %[[RES:.+]] = cir.load align(4) atomic(seq_cst) %[[PTR]] : !cir.ptr<!s32i>, !s32i
+ // CIR-NEXT: cir.store align(4) %[[RES]], %[[RES_SLOT]] : !s32i, !cir.ptr<!s32i>
+ // CIR-NEXT: cir.break
+ // CIR-NEXT: }
+ // CIR-NEXT: cir.yield
+ // CIR-NEXT: }
+ // CIR-NEXT: %{{.+}} = cir.load align(4) %[[RES_SLOT]] : !cir.ptr<!s32i>, !s32i
+
+ // LLVM: %[[PTR:.+]] = load ptr, ptr %{{.+}}, align 8
+ // LLVM-NEXT: %[[ORDER:.+]] = load i32, ptr %{{.+}}, align 4
+ // LLVM-NEXT: br label %[[SWITCH_BLK:.+]]
+ // LLVM: [[SWITCH_BLK]]:
+ // LLVM-NEXT: switch i32 %[[ORDER]], label %[[DEFAULT_BLK:.+]] [
+ // LLVM-NEXT: i32 1, label %[[ACQUIRE_BLK:.+]]
+ // LLVM-NEXT: i32 2, label %[[ACQUIRE_BLK]]
+ // LLVM-NEXT: i32 5, label %[[SEQ_CST_BLK:.+]]
+ // LLVM-NEXT: ]
+ // LLVM: [[DEFAULT_BLK]]:
+ // LLVM-NEXT: %[[RES:.+]] = load atomic i32, ptr %[[PTR]] monotonic, align 4
+ // LLVM-NEXT: store i32 %[[RES]], ptr %[[RES_SLOT:.+]], align 4
+ // LLVM-NEXT: br label %[[CONTINUE_BLK:.+]]
+ // LLVM: [[ACQUIRE_BLK]]:
+ // LLVM-NEXT: %[[RES:.+]] = load atomic i32, ptr %[[PTR]] acquire, align 4
+ // LLVM-NEXT: store i32 %[[RES]], ptr %[[RES_SLOT]], align 4
+ // LLVM-NEXT: br label %[[CONTINUE_BLK]]
+ // LLVM: [[SEQ_CST_BLK]]:
+ // LLVM-NEXT: %[[RES:.+]] = load atomic i32, ptr %[[PTR]] seq_cst, align 4
+ // LLVM-NEXT: store i32 %[[RES]], ptr %[[RES_SLOT]], align 4
+ // LLVM-NEXT: br label %[[CONTINUE_BLK]]
+ // LLVM: [[CONTINUE_BLK]]:
+ // LLVM-NEXT: %{{.+}} = load i32, ptr %[[RES_SLOT]], align 4
+
+ // OGCG: %[[PTR:.+]] = load ptr, ptr %{{.+}}, align 8
+ // OGCG-NEXT: %[[ORDER:.+]] = load i32, ptr %{{.+}}, align 4
+ // OGCG-NEXT: switch i32 %[[ORDER]], label %[[DEFAULT_BLK:.+]] [
+ // OGCG-NEXT: i32 1, label %[[ACQUIRE_BLK:.+]]
+ // OGCG-NEXT: i32 2, label %[[ACQUIRE_BLK]]
+ // OGCG-NEXT: i32 5, label %[[SEQ_CST_BLK:.+]]
+ // OGCG-NEXT: ]
+ // OGCG: [[DEFAULT_BLK]]:
+ // OGCG-NEXT: %[[RES:.+]] = load atomic i32, ptr %[[PTR]] monotonic, align 4
+ // OGCG-NEXT: store i32 %[[RES]], ptr %[[RES_SLOT:.+]], align 4
+ // OGCG-NEXT: br label %[[CONTINUE_BLK:.+]]
+ // OGCG: [[ACQUIRE_BLK]]:
+ // OGCG-NEXT: %[[RES:.+]] = load atomic i32, ptr %[[PTR]] acquire, align 4
+ // OGCG-NEXT: store i32 %[[RES]], ptr %[[RES_SLOT]], align 4
+ // OGCG-NEXT: br label %[[CONTINUE_BLK]]
+ // OGCG: [[SEQ_CST_BLK]]:
+ // OGCG-NEXT: %[[RES:.+]] = load atomic i32, ptr %[[PTR]] seq_cst, align 4
+ // OGCG-NEXT: store i32 %[[RES]], ptr %[[RES_SLOT]], align 4
+ // OGCG-NEXT: br label %[[CONTINUE_BLK]]
+ // OGCG: [[CONTINUE_BLK]]:
+ // OGCG-NEXT: %{{.+}} = load i32, ptr %[[RES_SLOT]], align 4
+}
+
+void atomic_store_dynamic_order(int *ptr, int order) {
+ // CIR-LABEL: atomic_store_dynamic_order
+ // LLVM-LABEL: atomic_store_dynamic_order
+ // OGCG-LABEL: atomic_store_dynamic_order
+
+ __atomic_store_n(ptr, 10, order);
+
+ // CIR: %[[PTR:.+]] = cir.load align(8) %{{.+}} : !cir.ptr<!cir.ptr<!s32i>>, !cir.ptr<!s32i>
+ // CIR-NEXT: %[[ORDER:.+]] = cir.load align(4) %{{.+}} : !cir.ptr<!s32i>, !s32i
+ // CIR: cir.switch (%[[ORDER]] : !s32i) {
+ // CIR-NEXT: cir.case(default, []) {
+ // CIR-NEXT: %[[VALUE:.+]] = cir.load align(4) %{{.+}} : !cir.ptr<!s32i>, !s32i
+ // CIR-NEXT: cir.store align(4) atomic(relaxed) %[[VALUE]], %[[PTR]] : !s32i, !cir.ptr<!s32i>
+ // CIR-NEXT: cir.break
+ // CIR-NEXT: }
+ // CIR-NEXT: cir.case(anyof, [#cir.int<3> : !s32i]) {
+ // CIR-NEXT: %[[VALUE:.+]] = cir.load align(4) %{{.+}} : !cir.ptr<!s32i>, !s32i
+ // CIR-NEXT: cir.store align(4) atomic(release) %[[VALUE]], %[[PTR]] : !s32i, !cir.ptr<!s32i>
+ // CIR-NEXT: cir.break
+ // CIR-NEXT: }
+ // CIR-NEXT: cir.case(anyof, [#cir.int<5> : !s32i]) {
+ // CIR-NEXT: %[[VALUE:.+]] = cir.load align(4) %{{.+}} : !cir.ptr<!s32i>, !s32i
+ // CIR-NEXT: cir.store align(4) atomic(seq_cst) %[[VALUE]], %[[PTR]] : !s32i, !cir.ptr<!s32i>
+ // CIR-NEXT: cir.break
+ // CIR-NEXT: }
+ // CIR-NEXT: cir.yield
+ // CIR-NEXT: }
+
+ // LLVM: %[[PTR:.+]] = load ptr, ptr %{{.+}}, align 8
+ // LLVM-NEXT: %[[ORDER:.+]] = load i32, ptr %{{.+}}, align 4
+ // LLVM: br label %[[SWITCH_BLK:.+]]
+ // LLVM: [[SWITCH_BLK]]:
+ // LLVM-NEXT: switch i32 %[[ORDER]], label %[[DEFAULT_BLK:.+]] [
+ // LLVM-NEXT: i32 3, label %[[RELEASE_BLK:.+]]
+ // LLVM-NEXT: i32 5, label %[[SEQ_CST_BLK:.+]]
+ // LLVM-NEXT: ]
+ // LLVM: [[DEFAULT_BLK]]:
+ // LLVM-NEXT: %[[VALUE:.+]] = load i32, ptr %{{.+}}, align 4
+ // LLVM-NEXT: store atomic i32 %[[VALUE]], ptr %[[PTR]] monotonic, align 4
+ // LLVM-NEXT: br label %{{.+}}
+ // LLVM: [[RELEASE_BLK]]:
+ // LLVM-NEXT: %[[VALUE:.+]] = load i32, ptr %{{.+}}, align 4
+ // LLVM-NEXT: store atomic i32 %[[VALUE]], ptr %[[PTR]] release, align 4
+ // LLVM-NEXT: br label %{{.+}}
+ // LLVM: [[SEQ_CST_BLK]]:
+ // LLVM-NEXT: %[[VALUE:.+]] = load i32, ptr %{{.+}}, align 4
+ // LLVM-NEXT: store atomic i32 %[[VALUE]], ptr %[[PTR]] seq_cst, align 4
+ // LLVM-NEXT: br label %{{.+}}
+
+ // OGCG: %[[PTR:.+]] = load ptr, ptr %{{.+}}, align 8
+ // OGCG-NEXT: %[[ORDER:.+]] = load i32, ptr %{{.+}}, align 4
+ // OGCG: switch i32 %[[ORDER]], label %[[DEFAULT_BLK:.+]] [
+ // OGCG-NEXT: i32 3, label %[[RELEASE_BLK:.+]]
+ // OGCG-NEXT: i32 5, label %[[SEQ_CST_BLK:.+]]
+ // OGCG-NEXT: ]
+ // OGCG: [[DEFAULT_BLK]]:
+ // OGCG-NEXT: %[[VALUE:.+]] = load i32, ptr %{{.+}}, align 4
+ // OGCG-NEXT: store atomic i32 %[[VALUE]], ptr %[[PTR]] monotonic, align 4
+ // OGCG-NEXT: br label %{{.+}}
+ // OGCG: [[RELEASE_BLK]]:
+ // OGCG-NEXT: %[[VALUE:.+]] = load i32, ptr %{{.+}}, align 4
+ // OGCG-NEXT: store atomic i32 %[[VALUE]], ptr %[[PTR]] release, align 4
+ // OGCG-NEXT: br label %{{.+}}
+ // OGCG: [[SEQ_CST_BLK]]:
+ // OGCG-NEXT: %[[VALUE:.+]] = load i32, ptr %{{.+}}, align 4
+ // OGCG-NEXT: store atomic i32 %[[VALUE]], ptr %[[PTR]] seq_cst, align 4
+ // OGCG-NEXT: br label %{{.+}}
+}
+
+int atomic_load_and_store_dynamic_order(int *ptr, int order) {
+ // CIR-LABEL: atomic_load_and_store_dynamic_order
+ // LLVM-LABEL: atomic_load_and_store_dynamic_order
+ // OGCG-LABEL: atomic_load_and_store_dynamic_order
+
+ return __atomic_exchange_n(ptr, 20, order);
+
+ // CIR: %[[PTR:.+]] = cir.load align(8) %{{.+}} : !cir.ptr<!cir.ptr<!s32i>>, !cir.ptr<!s32i>
+ // CIR-NEXT: %[[ORDER:.+]] = cir.load align(4) %{{.+}} : !cir.ptr<!s32i>, !s32i
+ // CIR: cir.switch (%[[ORDER]] : !s32i) {
+ // CIR-NEXT: cir.case(default, []) {
+ // CIR-NEXT: %[[LIT:.+]] = cir.load align(4) %{{.+}} : !cir.ptr<!s32i>, !s32i
+ // CIR-NEXT: %[[RES:.+]] = cir.atomic.xchg relaxed %[[PTR]], %[[LIT]] : (!cir.ptr<!s32i>, !s32i) -> !s32i
+ // CIR-NEXT: cir.store align(4) %[[RES]], %[[RES_SLOT:.+]] : !s32i, !cir.ptr<!s32i>
+ // CIR-NEXT: cir.break
+ // CIR-NEXT: }
+ // CIR-NEXT: cir.case(anyof, [#cir.int<1> : !s32i, #cir.int<2> : !s32i]) {
+ // CIR-NEXT: %[[LIT:.+]] = cir.load align(4) %{{.+}} : !cir.ptr<!s32i>, !s32i
+ // CIR-NEXT: %[[RES:.+]] = cir.atomic.xchg acquire %[[PTR]], %[[LIT]] : (!cir.ptr<!s32i>, !s32i) -> !s32i
+ // CIR-NEXT: cir.store align(4) %[[RES]], %[[RES_SLOT]] : !s32i, !cir.ptr<!s32i>
+ // CIR-NEXT: cir.break
+ // CIR-NEXT: }
+ // CIR-NEXT: cir.case(anyof, [#cir.int<3> : !s32i]) {
+ // CIR-NEXT: %[[LIT:.+]] = cir.load align(4) %{{.+}} : !cir.ptr<!s32i>, !s32i
+ // CIR-NEXT: %[[RES:.+]] = cir.atomic.xchg release %[[PTR]], %[[LIT]] : (!cir.ptr<!s32i>, !s32i) -> !s32i
+ // CIR-NEXT: cir.store align(4) %[[RES]], %[[RES_SLOT]] : !s32i, !cir.ptr<!s32i>
+ // CIR-NEXT: cir.break
+ // CIR-NEXT: }
+ // CIR-NEXT: cir.case(anyof, [#cir.int<4> : !s32i]) {
+ // CIR-NEXT: %[[LIT:.+]] = cir.load align(4) %{{.+}} : !cir.ptr<!s32i>, !s32i
+ // CIR-NEXT: %[[RES:.+]] = cir.atomic.xchg acq_rel %[[PTR]], %[[LIT]] : (!cir.ptr<!s32i>, !s32i) -> !s32i
+ // CIR-NEXT: cir.store align(4) %[[RES]], %[[RES_SLOT]] : !s32i, !cir.ptr<!s32i>
+ // CIR-NEXT: cir.break
+ // CIR-NEXT: }
+ // CIR-NEXT: cir.case(anyof, [#cir.int<5> : !s32i]) {
+ // CIR-NEXT: %[[LIT:.+]] = cir.load align(4) %{{.+}} : !cir.ptr<!s32i>, !s32i
+ // CIR-NEXT: %[[RES:.+]] = cir.atomic.xchg seq_cst %[[PTR]], %[[LIT]] : (!cir.ptr<!s32i>, !s32i) -> !s32i
+ // CIR-NEXT: cir.store align(4) %[[RES]], %[[RES_SLOT]] : !s32i, !cir.ptr<!s32i>
+ // CIR-NEXT: cir.break
+ // CIR-NEXT: }
+ // CIR-NEXT: cir.yield
+ // CIR-NEXT: }
+ // CIR-NEXT: %{{.+}} = cir.load align(4) %[[RES_SLOT]] : !cir.ptr<!s32i>, !s32i
+
+ // LLVM: %[[PTR:.+]] = load ptr, ptr %{{.+}}, align 8
+ // LLVM-NEXT: %[[ORDER:.+]] = load i32, ptr %{{.+}}, align 4
+ // LLVM: br label %[[SWITCH_BLK:.+]]
+ // LLVM: [[SWITCH_BLK]]:
+ // LLVM-NEXT: switch i32 %[[ORDER]], label %[[DEFAULT_BLK:.+]] [
+ // LLVM-NEXT: i32 1, label %[[ACQUIRE_BLK:.+]]
+ // LLVM-NEXT: i32 2, label %[[ACQUIRE_BLK]]
+ // LLVM-NEXT: i32 3, label %[[RELEASE_BLK:.+]]
+ // LLVM-NEXT: i32 4, label %[[ACQ_REL_BLK:.+]]
+ // LLVM-NEXT: i32 5, label %[[SEQ_CST_BLK:.+]]
+ // LLVM-NEXT: ]
+ // LLVM: [[DEFAULT_BLK]]:
+ // LLVM-NEXT: %[[VALUE:.+]] = load i32, ptr %{{.+}}, align 4
+ // LLVM-NEXT: %[[RES:.+]] = atomicrmw xchg ptr %[[PTR]], i32 %[[VALUE]] monotonic, align 4
+ // LLVM-NEXT: store i32 %[[RES]], ptr %[[RES_SLOT:.+]], align 4
+ // LLVM-NEXT: br label %[[CONTINUE_BLK:.+]]
+ // LLVM: [[ACQUIRE_BLK]]:
+ // LLVM-NEXT: %[[VALUE:.+]] = load i32, ptr %{{.+}}, align 4
+ // LLVM-NEXT: %[[RES:.+]] = atomicrmw xchg ptr %[[PTR]], i32 %[[VALUE]] acquire, align 4
+ // LLVM-NEXT: store i32 %[[RES]], ptr %[[RES_SLOT]], align 4
+ // LLVM-NEXT: br label %[[CONTINUE_BLK]]
+ // LLVM: [[RELEASE_BLK]]:
+ // LLVM-NEXT: %[[VALUE:.+]] = load i32, ptr %{{.+}}, align 4
+ // LLVM-NEXT: %[[RES:.+]] = atomicrmw xchg ptr %[[PTR]], i32 %[[VALUE]] release, align 4
+ // LLVM-NEXT: store i32 %[[RES]], ptr %[[RES_SLOT]], align 4
+ // LLVM-NEXT: br label %[[CONTINUE_BLK]]
+ // LLVM: [[ACQ_REL_BLK]]:
+ // LLVM-NEXT: %[[VALUE:.+]] = load i32, ptr %{{.+}}, align 4
+ // LLVM-NEXT: %[[RES:.+]] = atomicrmw xchg ptr %[[PTR]], i32 %[[VALUE]] acq_rel, align 4
+ // LLVM-NEXT: store i32 %[[RES]], ptr %[[RES_SLOT]], align 4
+ // LLVM-NEXT: br label %[[CONTINUE_BLK]]
+ // LLVM: [[SEQ_CST_BLK]]:
+ // LLVM-NEXT: %[[VALUE:.+]] = load i32, ptr %{{.+}}, align 4
+ // LLVM-NEXT: %[[RES:.+]] = atomicrmw xchg ptr %[[PTR]], i32 %[[VALUE]] seq_cst, align 4
+ // LLVM-NEXT: store i32 %[[RES]], ptr %[[RES_SLOT]], align 4
+ // LLVM-NEXT: br label %[[CONTINUE_BLK]]
+ // LLVM: [[CONTINUE_BLK]]:
+ // LLVM-NEXT: %{{.+}} = load i32, ptr %[[RES_SLOT]], align 4
+
+ // OGCG: %[[PTR:.+]] = load ptr, ptr %{{.+}}, align 8
+ // OGCG-NEXT: %[[ORDER:.+]] = load i32, ptr %{{.+}}, align 4
+ // OGCG: switch i32 %[[ORDER]], label %[[DEFAULT_BLK:.+]] [
+ // OGCG-NEXT: i32 1, label %[[ACQUIRE_BLK:.+]]
+ // OGCG-NEXT: i32 2, label %[[ACQUIRE_BLK]]
+ // OGCG-NEXT: i32 3, label %[[RELEASE_BLK:.+]]
+ // OGCG-NEXT: i32 4, label %[[ACQ_REL_BLK:.+]]
+ // OGCG-NEXT: i32 5, label %[[SEQ_CST_BLK:.+]]
+ // OGCG-NEXT: ]
+ // OGCG: [[DEFAULT_BLK]]:
+ // OGCG-NEXT: %[[VALUE:.+]] = load i32, ptr %{{.+}}, align 4
+ // OGCG-NEXT: %[[RES:.+]] = atomicrmw xchg ptr %[[PTR]], i32 %[[VALUE]] monotonic, align 4
+ // OGCG-NEXT: store i32 %[[RES]], ptr %[[RES_SLOT:.+]], align 4
+ // OGCG-NEXT: br label %[[CONTINUE_BLK:.+]]
+ // OGCG: [[ACQUIRE_BLK]]:
+ // OGCG-NEXT: %[[VALUE:.+]] = load i32, ptr %{{.+}}, align 4
+ // OGCG-NEXT: %[[RES:.+]] = atomicrmw xchg ptr %[[PTR]], i32 %[[VALUE]] acquire, align 4
+ // OGCG-NEXT: store i32 %[[RES]], ptr %[[RES_SLOT]], align 4
+ // OGCG-NEXT: br label %[[CONTINUE_BLK]]
+ // OGCG: [[RELEASE_BLK]]:
+ // OGCG-NEXT: %[[VALUE:.+]] = load i32, ptr %{{.+}}, align 4
+ // OGCG-NEXT: %[[RES:.+]] = atomicrmw xchg ptr %[[PTR]], i32 %[[VALUE]] release, align 4
+ // OGCG-NEXT: store i32 %[[RES]], ptr %[[RES_SLOT]], align 4
+ // OGCG-NEXT: br label %[[CONTINUE_BLK]]
+ // OGCG: [[ACQ_REL_BLK]]:
+ // OGCG-NEXT: %[[VALUE:.+]] = load i32, ptr %{{.+}}, align 4
+ // OGCG-NEXT: %[[RES:.+]] = atomicrmw xchg ptr %[[PTR]], i32 %[[VALUE]] acq_rel, align 4
+ // OGCG-NEXT: store i32 %[[RES]], ptr %[[RES_SLOT]], align 4
+ // OGCG-NEXT: br label %[[CONTINUE_BLK]]
+ // OGCG: [[SEQ_CST_BLK]]:
+ // OGCG-NEXT: %[[VALUE:.+]] = load i32, ptr %{{.+}}, align 4
+ // OGCG-NEXT: %[[RES:.+]] = atomicrmw xchg ptr %[[PTR]], i32 %[[VALUE]] seq_cst, align 4
+ // OGCG-NEXT: store i32 %[[RES]], ptr %[[RES_SLOT]], align 4
+ // OGCG-NEXT: br label %[[CONTINUE_BLK]]
+ // OGCG: [[CONTINUE_BLK]]:
+ // OGCG-NEXT: %{{.+}} = load i32, ptr %[[RES_SLOT]], align 4
+}
More information about the cfe-commits
mailing list