Skip to content

Commit 4128b21

Browse files
authored
[CIR] Add support for non-compile-time memory order (llvm#168892)
This patch upstreams CIR support for atomic operations with memory orders that are not known at compile time.
1 parent b8f8ef5 commit 4128b21

File tree

2 files changed

+358
-3
lines changed

2 files changed

+358
-3
lines changed

clang/lib/CIR/CodeGen/CIRGenAtomic.cpp

Lines changed: 92 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -286,6 +286,31 @@ void AtomicInfo::emitCopyIntoMemory(RValue rvalue) const {
286286
}
287287
}
288288

289+
static void emitMemOrderDefaultCaseLabel(CIRGenBuilderTy &builder,
290+
mlir::Location loc) {
291+
mlir::ArrayAttr ordersAttr = builder.getArrayAttr({});
292+
mlir::OpBuilder::InsertPoint insertPoint;
293+
cir::CaseOp::create(builder, loc, ordersAttr, cir::CaseOpKind::Default,
294+
insertPoint);
295+
builder.restoreInsertionPoint(insertPoint);
296+
}
297+
298+
// Create a "case" operation with the given list of orders as its values. Also
299+
// create the region that will hold the body of the switch-case label.
300+
static void emitMemOrderCaseLabel(CIRGenBuilderTy &builder, mlir::Location loc,
301+
mlir::Type orderType,
302+
llvm::ArrayRef<cir::MemOrder> orders) {
303+
llvm::SmallVector<mlir::Attribute, 2> orderAttrs;
304+
for (cir::MemOrder order : orders)
305+
orderAttrs.push_back(cir::IntAttr::get(orderType, static_cast<int>(order)));
306+
mlir::ArrayAttr ordersAttr = builder.getArrayAttr(orderAttrs);
307+
308+
mlir::OpBuilder::InsertPoint insertPoint;
309+
cir::CaseOp::create(builder, loc, ordersAttr, cir::CaseOpKind::Anyof,
310+
insertPoint);
311+
builder.restoreInsertionPoint(insertPoint);
312+
}
313+
289314
static void emitAtomicCmpXchg(CIRGenFunction &cgf, AtomicExpr *e, bool isWeak,
290315
Address dest, Address ptr, Address val1,
291316
Address val2, uint64_t size,
@@ -657,6 +682,70 @@ static bool isMemOrderValid(uint64_t order, bool isStore, bool isLoad) {
657682
return true;
658683
}
659684

685+
static void emitAtomicExprWithDynamicMemOrder(
686+
CIRGenFunction &cgf, mlir::Value order, AtomicExpr *e, Address dest,
687+
Address ptr, Address val1, Address val2, Expr *isWeakExpr,
688+
Expr *orderFailExpr, uint64_t size, bool isStore, bool isLoad) {
689+
// The memory order is not known at compile-time. The atomic operations
690+
// can't handle runtime memory orders; the memory order must be hard coded.
691+
// Generate a "switch" statement that converts a runtime value into a
692+
// compile-time value.
693+
CIRGenBuilderTy &builder = cgf.getBuilder();
694+
cir::SwitchOp::create(
695+
builder, order.getLoc(), order,
696+
[&](mlir::OpBuilder &, mlir::Location loc, mlir::OperationState &) {
697+
mlir::Block *switchBlock = builder.getBlock();
698+
699+
auto emitMemOrderCase = [&](llvm::ArrayRef<cir::MemOrder> caseOrders,
700+
cir::MemOrder actualOrder) {
701+
if (caseOrders.empty())
702+
emitMemOrderDefaultCaseLabel(builder, loc);
703+
else
704+
emitMemOrderCaseLabel(builder, loc, order.getType(), caseOrders);
705+
emitAtomicOp(cgf, e, dest, ptr, val1, val2, isWeakExpr, orderFailExpr,
706+
size, actualOrder);
707+
builder.createBreak(loc);
708+
builder.setInsertionPointToEnd(switchBlock);
709+
};
710+
711+
// default:
712+
// Use memory_order_relaxed for relaxed operations and for any memory
713+
// order value that is not supported. There is no good way to report
714+
// an unsupported memory order at runtime, hence the fallback to
715+
// memory_order_relaxed.
716+
emitMemOrderCase(/*caseOrders=*/{}, cir::MemOrder::Relaxed);
717+
718+
if (!isStore) {
719+
// case consume:
720+
// case acquire:
721+
// memory_order_consume is not implemented; it is always treated
722+
// like memory_order_acquire. These memory orders are not valid for
723+
// write-only operations.
724+
emitMemOrderCase({cir::MemOrder::Consume, cir::MemOrder::Acquire},
725+
cir::MemOrder::Acquire);
726+
}
727+
728+
if (!isLoad) {
729+
// case release:
730+
// memory_order_release is not valid for read-only operations.
731+
emitMemOrderCase({cir::MemOrder::Release}, cir::MemOrder::Release);
732+
}
733+
734+
if (!isLoad && !isStore) {
735+
// case acq_rel:
736+
// memory_order_acq_rel is only valid for read-write operations.
737+
emitMemOrderCase({cir::MemOrder::AcquireRelease},
738+
cir::MemOrder::AcquireRelease);
739+
}
740+
741+
// case seq_cst:
742+
emitMemOrderCase({cir::MemOrder::SequentiallyConsistent},
743+
cir::MemOrder::SequentiallyConsistent);
744+
745+
builder.createYield(loc);
746+
});
747+
}
748+
660749
RValue CIRGenFunction::emitAtomicExpr(AtomicExpr *e) {
661750
QualType atomicTy = e->getPtr()->getType()->getPointeeType();
662751
QualType memTy = atomicTy;
@@ -844,9 +933,9 @@ RValue CIRGenFunction::emitAtomicExpr(AtomicExpr *e) {
844933
emitAtomicOp(*this, e, dest, ptr, val1, val2, isWeakExpr, orderFailExpr,
845934
size, static_cast<cir::MemOrder>(ord));
846935
} else {
847-
assert(!cir::MissingFeatures::atomicExpr());
848-
cgm.errorNYI(e->getSourceRange(), "emitAtomicExpr: dynamic memory order");
849-
return RValue::get(nullptr);
936+
emitAtomicExprWithDynamicMemOrder(*this, order, e, dest, ptr, val1, val2,
937+
isWeakExpr, orderFailExpr, size, isStore,
938+
isLoad);
850939
}
851940

852941
if (resultTy->isVoidType())

clang/test/CIR/CodeGen/atomic.c

Lines changed: 266 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1133,3 +1133,269 @@ int c11_atomic_fetch_nand(_Atomic(int) *ptr, int value) {
11331133
// OGCG: %[[RES:.+]] = atomicrmw nand ptr %{{.+}}, i32 %{{.+}} seq_cst, align 4
11341134
// OGCG-NEXT: store i32 %[[RES]], ptr %{{.+}}, align 4
11351135
}
1136+
1137+
int atomic_load_dynamic_order(int *ptr, int order) {
1138+
// CIR-LABEL: atomic_load_dynamic_order
1139+
// LLVM-LABEL: atomic_load_dynamic_order
1140+
// OGCG-LABEL: atomic_load_dynamic_order
1141+
1142+
return __atomic_load_n(ptr, order);
1143+
1144+
// CIR: %[[PTR:.+]] = cir.load align(8) %{{.+}} : !cir.ptr<!cir.ptr<!s32i>>, !cir.ptr<!s32i>
1145+
// CIR-NEXT: %[[ORDER:.+]] = cir.load align(4) %{{.+}} : !cir.ptr<!s32i>, !s32i
1146+
// CIR-NEXT: cir.switch (%[[ORDER]] : !s32i) {
1147+
// CIR-NEXT: cir.case(default, []) {
1148+
// CIR-NEXT: %[[RES:.+]] = cir.load align(4) atomic(relaxed) %[[PTR]] : !cir.ptr<!s32i>, !s32i
1149+
// CIR-NEXT: cir.store align(4) %[[RES]], %[[RES_SLOT:.+]] : !s32i, !cir.ptr<!s32i>
1150+
// CIR-NEXT: cir.break
1151+
// CIR-NEXT: }
1152+
// CIR-NEXT: cir.case(anyof, [#cir.int<1> : !s32i, #cir.int<2> : !s32i]) {
1153+
// CIR-NEXT: %[[RES:.+]] = cir.load align(4) atomic(acquire) %[[PTR]] : !cir.ptr<!s32i>, !s32i
1154+
// CIR-NEXT: cir.store align(4) %[[RES]], %[[RES_SLOT]] : !s32i, !cir.ptr<!s32i>
1155+
// CIR-NEXT: cir.break
1156+
// CIR-NEXT: }
1157+
// CIR-NEXT: cir.case(anyof, [#cir.int<5> : !s32i]) {
1158+
// CIR-NEXT: %[[RES:.+]] = cir.load align(4) atomic(seq_cst) %[[PTR]] : !cir.ptr<!s32i>, !s32i
1159+
// CIR-NEXT: cir.store align(4) %[[RES]], %[[RES_SLOT]] : !s32i, !cir.ptr<!s32i>
1160+
// CIR-NEXT: cir.break
1161+
// CIR-NEXT: }
1162+
// CIR-NEXT: cir.yield
1163+
// CIR-NEXT: }
1164+
// CIR-NEXT: %{{.+}} = cir.load align(4) %[[RES_SLOT]] : !cir.ptr<!s32i>, !s32i
1165+
1166+
// LLVM: %[[PTR:.+]] = load ptr, ptr %{{.+}}, align 8
1167+
// LLVM-NEXT: %[[ORDER:.+]] = load i32, ptr %{{.+}}, align 4
1168+
// LLVM-NEXT: br label %[[SWITCH_BLK:.+]]
1169+
// LLVM: [[SWITCH_BLK]]:
1170+
// LLVM-NEXT: switch i32 %[[ORDER]], label %[[DEFAULT_BLK:.+]] [
1171+
// LLVM-NEXT: i32 1, label %[[ACQUIRE_BLK:.+]]
1172+
// LLVM-NEXT: i32 2, label %[[ACQUIRE_BLK]]
1173+
// LLVM-NEXT: i32 5, label %[[SEQ_CST_BLK:.+]]
1174+
// LLVM-NEXT: ]
1175+
// LLVM: [[DEFAULT_BLK]]:
1176+
// LLVM-NEXT: %[[RES:.+]] = load atomic i32, ptr %[[PTR]] monotonic, align 4
1177+
// LLVM-NEXT: store i32 %[[RES]], ptr %[[RES_SLOT:.+]], align 4
1178+
// LLVM-NEXT: br label %[[CONTINUE_BLK:.+]]
1179+
// LLVM: [[ACQUIRE_BLK]]:
1180+
// LLVM-NEXT: %[[RES:.+]] = load atomic i32, ptr %[[PTR]] acquire, align 4
1181+
// LLVM-NEXT: store i32 %[[RES]], ptr %[[RES_SLOT]], align 4
1182+
// LLVM-NEXT: br label %[[CONTINUE_BLK]]
1183+
// LLVM: [[SEQ_CST_BLK]]:
1184+
// LLVM-NEXT: %[[RES:.+]] = load atomic i32, ptr %[[PTR]] seq_cst, align 4
1185+
// LLVM-NEXT: store i32 %[[RES]], ptr %[[RES_SLOT]], align 4
1186+
// LLVM-NEXT: br label %[[CONTINUE_BLK]]
1187+
// LLVM: [[CONTINUE_BLK]]:
1188+
// LLVM-NEXT: %{{.+}} = load i32, ptr %[[RES_SLOT]], align 4
1189+
1190+
// OGCG: %[[PTR:.+]] = load ptr, ptr %{{.+}}, align 8
1191+
// OGCG-NEXT: %[[ORDER:.+]] = load i32, ptr %{{.+}}, align 4
1192+
// OGCG-NEXT: switch i32 %[[ORDER]], label %[[DEFAULT_BLK:.+]] [
1193+
// OGCG-NEXT: i32 1, label %[[ACQUIRE_BLK:.+]]
1194+
// OGCG-NEXT: i32 2, label %[[ACQUIRE_BLK]]
1195+
// OGCG-NEXT: i32 5, label %[[SEQ_CST_BLK:.+]]
1196+
// OGCG-NEXT: ]
1197+
// OGCG: [[DEFAULT_BLK]]:
1198+
// OGCG-NEXT: %[[RES:.+]] = load atomic i32, ptr %[[PTR]] monotonic, align 4
1199+
// OGCG-NEXT: store i32 %[[RES]], ptr %[[RES_SLOT:.+]], align 4
1200+
// OGCG-NEXT: br label %[[CONTINUE_BLK:.+]]
1201+
// OGCG: [[ACQUIRE_BLK]]:
1202+
// OGCG-NEXT: %[[RES:.+]] = load atomic i32, ptr %[[PTR]] acquire, align 4
1203+
// OGCG-NEXT: store i32 %[[RES]], ptr %[[RES_SLOT]], align 4
1204+
// OGCG-NEXT: br label %[[CONTINUE_BLK]]
1205+
// OGCG: [[SEQ_CST_BLK]]:
1206+
// OGCG-NEXT: %[[RES:.+]] = load atomic i32, ptr %[[PTR]] seq_cst, align 4
1207+
// OGCG-NEXT: store i32 %[[RES]], ptr %[[RES_SLOT]], align 4
1208+
// OGCG-NEXT: br label %[[CONTINUE_BLK]]
1209+
// OGCG: [[CONTINUE_BLK]]:
1210+
// OGCG-NEXT: %{{.+}} = load i32, ptr %[[RES_SLOT]], align 4
1211+
}
1212+
1213+
void atomic_store_dynamic_order(int *ptr, int order) {
1214+
// CIR-LABEL: atomic_store_dynamic_order
1215+
// LLVM-LABEL: atomic_store_dynamic_order
1216+
// OGCG-LABEL: atomic_store_dynamic_order
1217+
1218+
__atomic_store_n(ptr, 10, order);
1219+
1220+
// CIR: %[[PTR:.+]] = cir.load align(8) %{{.+}} : !cir.ptr<!cir.ptr<!s32i>>, !cir.ptr<!s32i>
1221+
// CIR-NEXT: %[[ORDER:.+]] = cir.load align(4) %{{.+}} : !cir.ptr<!s32i>, !s32i
1222+
// CIR: cir.switch (%[[ORDER]] : !s32i) {
1223+
// CIR-NEXT: cir.case(default, []) {
1224+
// CIR-NEXT: %[[VALUE:.+]] = cir.load align(4) %{{.+}} : !cir.ptr<!s32i>, !s32i
1225+
// CIR-NEXT: cir.store align(4) atomic(relaxed) %[[VALUE]], %[[PTR]] : !s32i, !cir.ptr<!s32i>
1226+
// CIR-NEXT: cir.break
1227+
// CIR-NEXT: }
1228+
// CIR-NEXT: cir.case(anyof, [#cir.int<3> : !s32i]) {
1229+
// CIR-NEXT: %[[VALUE:.+]] = cir.load align(4) %{{.+}} : !cir.ptr<!s32i>, !s32i
1230+
// CIR-NEXT: cir.store align(4) atomic(release) %[[VALUE]], %[[PTR]] : !s32i, !cir.ptr<!s32i>
1231+
// CIR-NEXT: cir.break
1232+
// CIR-NEXT: }
1233+
// CIR-NEXT: cir.case(anyof, [#cir.int<5> : !s32i]) {
1234+
// CIR-NEXT: %[[VALUE:.+]] = cir.load align(4) %{{.+}} : !cir.ptr<!s32i>, !s32i
1235+
// CIR-NEXT: cir.store align(4) atomic(seq_cst) %[[VALUE]], %[[PTR]] : !s32i, !cir.ptr<!s32i>
1236+
// CIR-NEXT: cir.break
1237+
// CIR-NEXT: }
1238+
// CIR-NEXT: cir.yield
1239+
// CIR-NEXT: }
1240+
1241+
// LLVM: %[[PTR:.+]] = load ptr, ptr %{{.+}}, align 8
1242+
// LLVM-NEXT: %[[ORDER:.+]] = load i32, ptr %{{.+}}, align 4
1243+
// LLVM: br label %[[SWITCH_BLK:.+]]
1244+
// LLVM: [[SWITCH_BLK]]:
1245+
// LLVM-NEXT: switch i32 %[[ORDER]], label %[[DEFAULT_BLK:.+]] [
1246+
// LLVM-NEXT: i32 3, label %[[RELEASE_BLK:.+]]
1247+
// LLVM-NEXT: i32 5, label %[[SEQ_CST_BLK:.+]]
1248+
// LLVM-NEXT: ]
1249+
// LLVM: [[DEFAULT_BLK]]:
1250+
// LLVM-NEXT: %[[VALUE:.+]] = load i32, ptr %{{.+}}, align 4
1251+
// LLVM-NEXT: store atomic i32 %[[VALUE]], ptr %[[PTR]] monotonic, align 4
1252+
// LLVM-NEXT: br label %{{.+}}
1253+
// LLVM: [[RELEASE_BLK]]:
1254+
// LLVM-NEXT: %[[VALUE:.+]] = load i32, ptr %{{.+}}, align 4
1255+
// LLVM-NEXT: store atomic i32 %[[VALUE]], ptr %[[PTR]] release, align 4
1256+
// LLVM-NEXT: br label %{{.+}}
1257+
// LLVM: [[SEQ_CST_BLK]]:
1258+
// LLVM-NEXT: %[[VALUE:.+]] = load i32, ptr %{{.+}}, align 4
1259+
// LLVM-NEXT: store atomic i32 %[[VALUE]], ptr %[[PTR]] seq_cst, align 4
1260+
// LLVM-NEXT: br label %{{.+}}
1261+
1262+
// OGCG: %[[PTR:.+]] = load ptr, ptr %{{.+}}, align 8
1263+
// OGCG-NEXT: %[[ORDER:.+]] = load i32, ptr %{{.+}}, align 4
1264+
// OGCG: switch i32 %[[ORDER]], label %[[DEFAULT_BLK:.+]] [
1265+
// OGCG-NEXT: i32 3, label %[[RELEASE_BLK:.+]]
1266+
// OGCG-NEXT: i32 5, label %[[SEQ_CST_BLK:.+]]
1267+
// OGCG-NEXT: ]
1268+
// OGCG: [[DEFAULT_BLK]]:
1269+
// OGCG-NEXT: %[[VALUE:.+]] = load i32, ptr %{{.+}}, align 4
1270+
// OGCG-NEXT: store atomic i32 %[[VALUE]], ptr %[[PTR]] monotonic, align 4
1271+
// OGCG-NEXT: br label %{{.+}}
1272+
// OGCG: [[RELEASE_BLK]]:
1273+
// OGCG-NEXT: %[[VALUE:.+]] = load i32, ptr %{{.+}}, align 4
1274+
// OGCG-NEXT: store atomic i32 %[[VALUE]], ptr %[[PTR]] release, align 4
1275+
// OGCG-NEXT: br label %{{.+}}
1276+
// OGCG: [[SEQ_CST_BLK]]:
1277+
// OGCG-NEXT: %[[VALUE:.+]] = load i32, ptr %{{.+}}, align 4
1278+
// OGCG-NEXT: store atomic i32 %[[VALUE]], ptr %[[PTR]] seq_cst, align 4
1279+
// OGCG-NEXT: br label %{{.+}}
1280+
}
1281+
1282+
int atomic_load_and_store_dynamic_order(int *ptr, int order) {
1283+
// CIR-LABEL: atomic_load_and_store_dynamic_order
1284+
// LLVM-LABEL: atomic_load_and_store_dynamic_order
1285+
// OGCG-LABEL: atomic_load_and_store_dynamic_order
1286+
1287+
return __atomic_exchange_n(ptr, 20, order);
1288+
1289+
// CIR: %[[PTR:.+]] = cir.load align(8) %{{.+}} : !cir.ptr<!cir.ptr<!s32i>>, !cir.ptr<!s32i>
1290+
// CIR-NEXT: %[[ORDER:.+]] = cir.load align(4) %{{.+}} : !cir.ptr<!s32i>, !s32i
1291+
// CIR: cir.switch (%[[ORDER]] : !s32i) {
1292+
// CIR-NEXT: cir.case(default, []) {
1293+
// CIR-NEXT: %[[LIT:.+]] = cir.load align(4) %{{.+}} : !cir.ptr<!s32i>, !s32i
1294+
// CIR-NEXT: %[[RES:.+]] = cir.atomic.xchg relaxed %[[PTR]], %[[LIT]] : (!cir.ptr<!s32i>, !s32i) -> !s32i
1295+
// CIR-NEXT: cir.store align(4) %[[RES]], %[[RES_SLOT:.+]] : !s32i, !cir.ptr<!s32i>
1296+
// CIR-NEXT: cir.break
1297+
// CIR-NEXT: }
1298+
// CIR-NEXT: cir.case(anyof, [#cir.int<1> : !s32i, #cir.int<2> : !s32i]) {
1299+
// CIR-NEXT: %[[LIT:.+]] = cir.load align(4) %{{.+}} : !cir.ptr<!s32i>, !s32i
1300+
// CIR-NEXT: %[[RES:.+]] = cir.atomic.xchg acquire %[[PTR]], %[[LIT]] : (!cir.ptr<!s32i>, !s32i) -> !s32i
1301+
// CIR-NEXT: cir.store align(4) %[[RES]], %[[RES_SLOT]] : !s32i, !cir.ptr<!s32i>
1302+
// CIR-NEXT: cir.break
1303+
// CIR-NEXT: }
1304+
// CIR-NEXT: cir.case(anyof, [#cir.int<3> : !s32i]) {
1305+
// CIR-NEXT: %[[LIT:.+]] = cir.load align(4) %{{.+}} : !cir.ptr<!s32i>, !s32i
1306+
// CIR-NEXT: %[[RES:.+]] = cir.atomic.xchg release %[[PTR]], %[[LIT]] : (!cir.ptr<!s32i>, !s32i) -> !s32i
1307+
// CIR-NEXT: cir.store align(4) %[[RES]], %[[RES_SLOT]] : !s32i, !cir.ptr<!s32i>
1308+
// CIR-NEXT: cir.break
1309+
// CIR-NEXT: }
1310+
// CIR-NEXT: cir.case(anyof, [#cir.int<4> : !s32i]) {
1311+
// CIR-NEXT: %[[LIT:.+]] = cir.load align(4) %{{.+}} : !cir.ptr<!s32i>, !s32i
1312+
// CIR-NEXT: %[[RES:.+]] = cir.atomic.xchg acq_rel %[[PTR]], %[[LIT]] : (!cir.ptr<!s32i>, !s32i) -> !s32i
1313+
// CIR-NEXT: cir.store align(4) %[[RES]], %[[RES_SLOT]] : !s32i, !cir.ptr<!s32i>
1314+
// CIR-NEXT: cir.break
1315+
// CIR-NEXT: }
1316+
// CIR-NEXT: cir.case(anyof, [#cir.int<5> : !s32i]) {
1317+
// CIR-NEXT: %[[LIT:.+]] = cir.load align(4) %{{.+}} : !cir.ptr<!s32i>, !s32i
1318+
// CIR-NEXT: %[[RES:.+]] = cir.atomic.xchg seq_cst %[[PTR]], %[[LIT]] : (!cir.ptr<!s32i>, !s32i) -> !s32i
1319+
// CIR-NEXT: cir.store align(4) %[[RES]], %[[RES_SLOT]] : !s32i, !cir.ptr<!s32i>
1320+
// CIR-NEXT: cir.break
1321+
// CIR-NEXT: }
1322+
// CIR-NEXT: cir.yield
1323+
// CIR-NEXT: }
1324+
// CIR-NEXT: %{{.+}} = cir.load align(4) %[[RES_SLOT]] : !cir.ptr<!s32i>, !s32i
1325+
1326+
// LLVM: %[[PTR:.+]] = load ptr, ptr %{{.+}}, align 8
1327+
// LLVM-NEXT: %[[ORDER:.+]] = load i32, ptr %{{.+}}, align 4
1328+
// LLVM: br label %[[SWITCH_BLK:.+]]
1329+
// LLVM: [[SWITCH_BLK]]:
1330+
// LLVM-NEXT: switch i32 %[[ORDER]], label %[[DEFAULT_BLK:.+]] [
1331+
// LLVM-NEXT: i32 1, label %[[ACQUIRE_BLK:.+]]
1332+
// LLVM-NEXT: i32 2, label %[[ACQUIRE_BLK]]
1333+
// LLVM-NEXT: i32 3, label %[[RELEASE_BLK:.+]]
1334+
// LLVM-NEXT: i32 4, label %[[ACQ_REL_BLK:.+]]
1335+
// LLVM-NEXT: i32 5, label %[[SEQ_CST_BLK:.+]]
1336+
// LLVM-NEXT: ]
1337+
// LLVM: [[DEFAULT_BLK]]:
1338+
// LLVM-NEXT: %[[VALUE:.+]] = load i32, ptr %{{.+}}, align 4
1339+
// LLVM-NEXT: %[[RES:.+]] = atomicrmw xchg ptr %[[PTR]], i32 %[[VALUE]] monotonic, align 4
1340+
// LLVM-NEXT: store i32 %[[RES]], ptr %[[RES_SLOT:.+]], align 4
1341+
// LLVM-NEXT: br label %[[CONTINUE_BLK:.+]]
1342+
// LLVM: [[ACQUIRE_BLK]]:
1343+
// LLVM-NEXT: %[[VALUE:.+]] = load i32, ptr %{{.+}}, align 4
1344+
// LLVM-NEXT: %[[RES:.+]] = atomicrmw xchg ptr %[[PTR]], i32 %[[VALUE]] acquire, align 4
1345+
// LLVM-NEXT: store i32 %[[RES]], ptr %[[RES_SLOT]], align 4
1346+
// LLVM-NEXT: br label %[[CONTINUE_BLK]]
1347+
// LLVM: [[RELEASE_BLK]]:
1348+
// LLVM-NEXT: %[[VALUE:.+]] = load i32, ptr %{{.+}}, align 4
1349+
// LLVM-NEXT: %[[RES:.+]] = atomicrmw xchg ptr %[[PTR]], i32 %[[VALUE]] release, align 4
1350+
// LLVM-NEXT: store i32 %[[RES]], ptr %[[RES_SLOT]], align 4
1351+
// LLVM-NEXT: br label %[[CONTINUE_BLK]]
1352+
// LLVM: [[ACQ_REL_BLK]]:
1353+
// LLVM-NEXT: %[[VALUE:.+]] = load i32, ptr %{{.+}}, align 4
1354+
// LLVM-NEXT: %[[RES:.+]] = atomicrmw xchg ptr %[[PTR]], i32 %[[VALUE]] acq_rel, align 4
1355+
// LLVM-NEXT: store i32 %[[RES]], ptr %[[RES_SLOT]], align 4
1356+
// LLVM-NEXT: br label %[[CONTINUE_BLK]]
1357+
// LLVM: [[SEQ_CST_BLK]]:
1358+
// LLVM-NEXT: %[[VALUE:.+]] = load i32, ptr %{{.+}}, align 4
1359+
// LLVM-NEXT: %[[RES:.+]] = atomicrmw xchg ptr %[[PTR]], i32 %[[VALUE]] seq_cst, align 4
1360+
// LLVM-NEXT: store i32 %[[RES]], ptr %[[RES_SLOT]], align 4
1361+
// LLVM-NEXT: br label %[[CONTINUE_BLK]]
1362+
// LLVM: [[CONTINUE_BLK]]:
1363+
// LLVM-NEXT: %{{.+}} = load i32, ptr %[[RES_SLOT]], align 4
1364+
1365+
// OGCG: %[[PTR:.+]] = load ptr, ptr %{{.+}}, align 8
1366+
// OGCG-NEXT: %[[ORDER:.+]] = load i32, ptr %{{.+}}, align 4
1367+
// OGCG: switch i32 %[[ORDER]], label %[[DEFAULT_BLK:.+]] [
1368+
// OGCG-NEXT: i32 1, label %[[ACQUIRE_BLK:.+]]
1369+
// OGCG-NEXT: i32 2, label %[[ACQUIRE_BLK]]
1370+
// OGCG-NEXT: i32 3, label %[[RELEASE_BLK:.+]]
1371+
// OGCG-NEXT: i32 4, label %[[ACQ_REL_BLK:.+]]
1372+
// OGCG-NEXT: i32 5, label %[[SEQ_CST_BLK:.+]]
1373+
// OGCG-NEXT: ]
1374+
// OGCG: [[DEFAULT_BLK]]:
1375+
// OGCG-NEXT: %[[VALUE:.+]] = load i32, ptr %{{.+}}, align 4
1376+
// OGCG-NEXT: %[[RES:.+]] = atomicrmw xchg ptr %[[PTR]], i32 %[[VALUE]] monotonic, align 4
1377+
// OGCG-NEXT: store i32 %[[RES]], ptr %[[RES_SLOT:.+]], align 4
1378+
// OGCG-NEXT: br label %[[CONTINUE_BLK:.+]]
1379+
// OGCG: [[ACQUIRE_BLK]]:
1380+
// OGCG-NEXT: %[[VALUE:.+]] = load i32, ptr %{{.+}}, align 4
1381+
// OGCG-NEXT: %[[RES:.+]] = atomicrmw xchg ptr %[[PTR]], i32 %[[VALUE]] acquire, align 4
1382+
// OGCG-NEXT: store i32 %[[RES]], ptr %[[RES_SLOT]], align 4
1383+
// OGCG-NEXT: br label %[[CONTINUE_BLK]]
1384+
// OGCG: [[RELEASE_BLK]]:
1385+
// OGCG-NEXT: %[[VALUE:.+]] = load i32, ptr %{{.+}}, align 4
1386+
// OGCG-NEXT: %[[RES:.+]] = atomicrmw xchg ptr %[[PTR]], i32 %[[VALUE]] release, align 4
1387+
// OGCG-NEXT: store i32 %[[RES]], ptr %[[RES_SLOT]], align 4
1388+
// OGCG-NEXT: br label %[[CONTINUE_BLK]]
1389+
// OGCG: [[ACQ_REL_BLK]]:
1390+
// OGCG-NEXT: %[[VALUE:.+]] = load i32, ptr %{{.+}}, align 4
1391+
// OGCG-NEXT: %[[RES:.+]] = atomicrmw xchg ptr %[[PTR]], i32 %[[VALUE]] acq_rel, align 4
1392+
// OGCG-NEXT: store i32 %[[RES]], ptr %[[RES_SLOT]], align 4
1393+
// OGCG-NEXT: br label %[[CONTINUE_BLK]]
1394+
// OGCG: [[SEQ_CST_BLK]]:
1395+
// OGCG-NEXT: %[[VALUE:.+]] = load i32, ptr %{{.+}}, align 4
1396+
// OGCG-NEXT: %[[RES:.+]] = atomicrmw xchg ptr %[[PTR]], i32 %[[VALUE]] seq_cst, align 4
1397+
// OGCG-NEXT: store i32 %[[RES]], ptr %[[RES_SLOT]], align 4
1398+
// OGCG-NEXT: br label %[[CONTINUE_BLK]]
1399+
// OGCG: [[CONTINUE_BLK]]:
1400+
// OGCG-NEXT: %{{.+}} = load i32, ptr %[[RES_SLOT]], align 4
1401+
}

0 commit comments

Comments
 (0)