-
Notifications
You must be signed in to change notification settings - Fork 15.5k
[CIR] Add codegen for atomic fence builtin with non-const memory order #172455
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
Luhaocong
wants to merge
2
commits into
llvm:main
Choose a base branch
from
Luhaocong:non-const-atomic-fence
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
+557
−105
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Member
|
@llvm/pr-subscribers-clangir @llvm/pr-subscribers-clang Author: Haocong Lu (Luhaocong) Changes
Patch is 21.71 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/172455.diff 2 Files Affected:
diff --git a/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp b/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp
index b4f02c97f539a..4f732bbb4750c 100644
--- a/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp
@@ -63,25 +63,87 @@ static RValue emitBuiltinBitOp(CIRGenFunction &cgf, const CallExpr *e,
static void emitAtomicFenceOp(CIRGenFunction &cgf, const CallExpr *expr,
cir::SyncScopeKind syncScope) {
CIRGenBuilderTy &builder = cgf.getBuilder();
- mlir::Value orderingVal = cgf.emitScalarExpr(expr->getArg(0));
-
- auto constOrdering = orderingVal.getDefiningOp<cir::ConstantOp>();
-
- if (!constOrdering) {
- // TODO(cir): Emit code to switch on `orderingVal`,
- // and creating the fence op for valid values.
- cgf.cgm.errorNYI("Variable atomic fence ordering");
+ mlir::Location loc = cgf.getLoc(expr->getSourceRange());
+
+ // Convert the memory order specified by user to effective one:
+ // Relaxed -> std::nullopt
+ // Consume/Acquire -> Acquire
+ // Release -> Release
+ // AcquireRelease -> AcquireRelease
+ // SequentiallyConsistent -> SequentiallyConsistent
+ auto getEffectiveMemOrder =
+ [](cir::MemOrder oriOrder) -> std::optional<cir::MemOrder> {
+ if (oriOrder == cir::MemOrder::Relaxed)
+ return std::nullopt;
+ else if (oriOrder == cir::MemOrder::Consume ||
+ oriOrder == cir::MemOrder::Acquire)
+ return cir::MemOrder::Acquire;
+ else
+ return oriOrder;
+ };
+
+ // Handle constant memory ordering.
+ Expr::EvalResult eval;
+ if (expr->getArg(0)->EvaluateAsInt(eval, cgf.getContext())) {
+ uint64_t constOrder = eval.Val.getInt().getZExtValue();
+ // Not emit anything if it's an invalid constant.
+ if (!cir::isValidCIRAtomicOrderingCABI(constOrder))
+ return;
+ cir::MemOrder caseOrder = static_cast<cir::MemOrder>(constOrder);
+ if (std::optional<cir::MemOrder> order = getEffectiveMemOrder(caseOrder))
+ cir::AtomicFenceOp::create(
+ builder, loc, order.value(),
+ cir::SyncScopeKindAttr::get(&cgf.getMLIRContext(), syncScope));
return;
}
- auto constOrderingAttr = constOrdering.getValueAttr<cir::IntAttr>();
- assert(constOrderingAttr && "Expected integer constant for ordering");
-
- auto ordering = static_cast<cir::MemOrder>(constOrderingAttr.getUInt());
-
- cir::AtomicFenceOp::create(
- builder, cgf.getLoc(expr->getSourceRange()), ordering,
- cir::SyncScopeKindAttr::get(&cgf.getMLIRContext(), syncScope));
+ // Otherwise, handle variable memory ordering. Emit `SwitchOp` to convert
+ // dynamic value to static value.
+ mlir::Value varOrder = cgf.emitScalarExpr(expr->getArg(0));
+ cir::SwitchOp::create(
+ builder, loc, varOrder,
+ [&](mlir::OpBuilder &, mlir::Location loc, mlir::OperationState &) {
+ mlir::Block *switchBlock = builder.getBlock();
+
+ auto emitMemOrderCase = [&](llvm::ArrayRef<cir::MemOrder> caseOrders) {
+ if (caseOrders.empty()) {
+ // Creating default case operation
+ mlir::OpBuilder::InsertPoint insertPoint;
+ cir::CaseOp::create(builder, loc, builder.getArrayAttr({}),
+ cir::CaseOpKind::Default, insertPoint);
+ builder.restoreInsertionPoint(insertPoint);
+ } else if (auto actualOrder = getEffectiveMemOrder(caseOrders[0])) {
+ // Creating case operation for effective memory order
+ mlir::OpBuilder::InsertPoint insertPoint;
+ llvm::SmallVector<mlir::Attribute, 2> orderAttrs;
+ for (cir::MemOrder caseOrder : caseOrders)
+ orderAttrs.push_back(cir::IntAttr::get(
+ varOrder.getType(), static_cast<int>(caseOrder)));
+ cir::CaseOp::create(builder, loc, builder.getArrayAttr(orderAttrs),
+ cir::CaseOpKind::Anyof, insertPoint);
+ // Creating atomic fence operation
+ builder.restoreInsertionPoint(insertPoint);
+ cir::AtomicFenceOp::create(
+ builder, loc, actualOrder.value(),
+ cir::SyncScopeKindAttr::get(&cgf.getMLIRContext(), syncScope));
+ } else {
+ // Do nothing if unneccssary (!caseOrders.empty() && !actualOrder)
+ return;
+ }
+ builder.createBreak(loc);
+ builder.setInsertionPointToEnd(switchBlock);
+ return;
+ };
+
+ emitMemOrderCase(/*default:*/ {});
+ emitMemOrderCase({cir::MemOrder::Relaxed}); // Not effective
+ emitMemOrderCase({cir::MemOrder::Consume, cir::MemOrder::Acquire});
+ emitMemOrderCase({cir::MemOrder::Release});
+ emitMemOrderCase({cir::MemOrder::AcquireRelease});
+ emitMemOrderCase({cir::MemOrder::SequentiallyConsistent});
+
+ builder.createYield(loc);
+ });
}
namespace {
@@ -1007,16 +1069,16 @@ RValue CIRGenFunction::emitBuiltinExpr(const GlobalDecl &gd, unsigned builtinID,
case Builtin::BI__atomic_test_and_set:
case Builtin::BI__atomic_clear:
return errorBuiltinNYI(*this, e, builtinID);
- case Builtin::BI__atomic_thread_fence: {
+ case Builtin::BI__atomic_thread_fence:
+ case Builtin::BI__c11_atomic_thread_fence: {
emitAtomicFenceOp(*this, e, cir::SyncScopeKind::System);
return RValue::get(nullptr);
}
- case Builtin::BI__atomic_signal_fence: {
+ case Builtin::BI__atomic_signal_fence:
+ case Builtin::BI__c11_atomic_signal_fence: {
emitAtomicFenceOp(*this, e, cir::SyncScopeKind::SingleThread);
return RValue::get(nullptr);
}
- case Builtin::BI__c11_atomic_thread_fence:
- case Builtin::BI__c11_atomic_signal_fence:
case Builtin::BI__scoped_atomic_thread_fence:
case Builtin::BI__builtin_signbit:
case Builtin::BI__builtin_signbitf:
diff --git a/clang/test/CIR/CodeGen/atomic-thread-fence.c b/clang/test/CIR/CodeGen/atomic-thread-fence.c
index f28bc6808cbfa..69298fb9cd7b0 100644
--- a/clang/test/CIR/CodeGen/atomic-thread-fence.c
+++ b/clang/test/CIR/CodeGen/atomic-thread-fence.c
@@ -179,3 +179,427 @@ void loadWithSignalFence(DataPtr d) {
// OGCG: %[[DATA_TEMP_LOAD]] = load ptr, ptr %[[DATA_TEMP]], align 8
// OGCG: ret void
}
+
+void const_atomic_thread_fence() {
+ __atomic_thread_fence(__ATOMIC_RELAXED);
+ __atomic_thread_fence(__ATOMIC_CONSUME);
+ __atomic_thread_fence(__ATOMIC_ACQUIRE);
+ __atomic_thread_fence(__ATOMIC_RELEASE);
+ __atomic_thread_fence(__ATOMIC_ACQ_REL);
+ __atomic_thread_fence(__ATOMIC_SEQ_CST);
+ // CIR-LABEL: const_atomic_thread_fence
+ // CIR: cir.atomic.fence syncscope(system) acquire
+ // CIR: cir.atomic.fence syncscope(system) acquire
+ // CIR: cir.atomic.fence syncscope(system) release
+ // CIR: cir.atomic.fence syncscope(system) acq_rel
+ // CIR: cir.atomic.fence syncscope(system) seq_cst
+
+ // LLVM-LABEL: const_atomic_thread_fence
+ // LLVM: fence acquire
+ // LLVM: fence acquire
+ // LLVM: fence release
+ // LLVM: fence acq_rel
+ // LLVM: fence seq_cst
+
+ // OGCG-LABEL: const_atomic_thread_fence
+ // OGCG: fence acquire
+ // OGCG: fence acquire
+ // OGCG: fence release
+ // OGCG: fence acq_rel
+ // OGCG: fence seq_cst
+}
+
+void const_c11_atomic_thread_fence() {
+ __c11_atomic_thread_fence(__ATOMIC_RELAXED);
+ __c11_atomic_thread_fence(__ATOMIC_CONSUME);
+ __c11_atomic_thread_fence(__ATOMIC_ACQUIRE);
+ __c11_atomic_thread_fence(__ATOMIC_RELEASE);
+ __c11_atomic_thread_fence(__ATOMIC_ACQ_REL);
+ __c11_atomic_thread_fence(__ATOMIC_SEQ_CST);
+ // CIR-LABEL: const_c11_atomic_thread_fence
+ // CIR: cir.atomic.fence syncscope(system) acquire
+ // CIR: cir.atomic.fence syncscope(system) acquire
+ // CIR: cir.atomic.fence syncscope(system) release
+ // CIR: cir.atomic.fence syncscope(system) acq_rel
+ // CIR: cir.atomic.fence syncscope(system) seq_cst
+
+ // LLVM-LABEL: const_c11_atomic_thread_fence
+ // LLVM: fence acquire
+ // LLVM: fence acquire
+ // LLVM: fence release
+ // LLVM: fence acq_rel
+ // LLVM: fence seq_cst
+
+ // OGCG-LABEL: const_c11_atomic_thread_fence
+ // OGCG: fence acquire
+ // OGCG: fence acquire
+ // OGCG: fence release
+ // OGCG: fence acq_rel
+ // OGCG: fence seq_cst
+}
+
+void const_atomic_signal_fence() {
+ __atomic_signal_fence(__ATOMIC_RELAXED);
+ __atomic_signal_fence(__ATOMIC_CONSUME);
+ __atomic_signal_fence(__ATOMIC_ACQUIRE);
+ __atomic_signal_fence(__ATOMIC_RELEASE);
+ __atomic_signal_fence(__ATOMIC_ACQ_REL);
+ __atomic_signal_fence(__ATOMIC_SEQ_CST);
+ // CIR-LABEL: const_atomic_signal_fence
+ // CIR: cir.atomic.fence syncscope(single_thread) acquire
+ // CIR: cir.atomic.fence syncscope(single_thread) acquire
+ // CIR: cir.atomic.fence syncscope(single_thread) release
+ // CIR: cir.atomic.fence syncscope(single_thread) acq_rel
+ // CIR: cir.atomic.fence syncscope(single_thread) seq_cst
+
+ // LLVM-LABEL: const_atomic_signal_fence
+ // LLVM: fence syncscope("singlethread") acquire
+ // LLVM: fence syncscope("singlethread") acquire
+ // LLVM: fence syncscope("singlethread") release
+ // LLVM: fence syncscope("singlethread") acq_rel
+ // LLVM: fence syncscope("singlethread") seq_cst
+
+ // OGCG--LABEL: const_atomic_signal_fence
+ // OGCG: fence syncscope("singlethread") acquire
+ // OGCG: fence syncscope("singlethread") acquire
+ // OGCG: fence syncscope("singlethread") release
+ // OGCG: fence syncscope("singlethread") acq_rel
+ // OGCG: fence syncscope("singlethread") seq_cst
+}
+
+void const_c11_atomic_signal_fence() {
+ __c11_atomic_signal_fence(__ATOMIC_RELAXED);
+ __c11_atomic_signal_fence(__ATOMIC_CONSUME);
+ __c11_atomic_signal_fence(__ATOMIC_ACQUIRE);
+ __c11_atomic_signal_fence(__ATOMIC_RELEASE);
+ __c11_atomic_signal_fence(__ATOMIC_ACQ_REL);
+ __c11_atomic_signal_fence(__ATOMIC_SEQ_CST);
+ // CIR-LABEL: const_c11_atomic_signal_fence
+ // CIR: cir.atomic.fence syncscope(single_thread) acquire
+ // CIR: cir.atomic.fence syncscope(single_thread) acquire
+ // CIR: cir.atomic.fence syncscope(single_thread) release
+ // CIR: cir.atomic.fence syncscope(single_thread) acq_rel
+ // CIR: cir.atomic.fence syncscope(single_thread) seq_cst
+
+ // LLVM-LABEL: const_c11_atomic_signal_fence
+ // LLVM: fence syncscope("singlethread") acquire
+ // LLVM: fence syncscope("singlethread") acquire
+ // LLVM: fence syncscope("singlethread") release
+ // LLVM: fence syncscope("singlethread") acq_rel
+ // LLVM: fence syncscope("singlethread") seq_cst
+
+ // OGCG-LABEL: const_c11_atomic_signal_fence
+ // OGCG: fence syncscope("singlethread") acquire
+ // OGCG: fence syncscope("singlethread") acquire
+ // OGCG: fence syncscope("singlethread") release
+ // OGCG: fence syncscope("singlethread") acq_rel
+ // OGCG: fence syncscope("singlethread") seq_cst
+}
+
+void variable_atomic_thread_fences(int memorder) {
+ __atomic_thread_fence(memorder);
+ // CIR-LABEL: variable_atomic_thread_fences
+ // CIR: cir.switch
+ // CIR: cir.case(default, []) {
+ // CIR: cir.break
+ // CIR: }
+ // CIR: cir.case(anyof, [#cir.int<1> : !s32i, #cir.int<2> : !s32i]) {
+ // CIR: cir.atomic.fence syncscope(system) acquire
+ // CIR: cir.break
+ // CIR: }
+ // CIR: cir.case(anyof, [#cir.int<3> : !s32i]) {
+ // CIR: cir.atomic.fence syncscope(system) release
+ // CIR: cir.break
+ // CIR: }
+ // CIR: cir.case(anyof, [#cir.int<4> : !s32i]) {
+ // CIR: cir.atomic.fence syncscope(system) acq_rel
+ // CIR: cir.break
+ // CIR: }
+ // CIR: cir.case(anyof, [#cir.int<5> : !s32i]) {
+ // CIR: cir.atomic.fence syncscope(system)
+ // CIR: cir.break
+ // CIR: }
+ // CIR: cir.yield
+ // CIR: }
+
+ // LLVM-LABEL: variable_atomic_thread_fences
+ // LLVM: %[[ORDER:.+]] = load i32, ptr %[[PTR:.+]], align 4
+ // LLVM: br label %[[SWITCH_BLK:.+]]
+ // LLVM: [[SWITCH_BLK]]:
+ // LLVM: switch i32 %[[ORDER]], label %[[DEFAULT_BLK:.+]] [
+ // LLVM: i32 1, label %[[ACQUIRE_BLK:.+]]
+ // LLVM: i32 2, label %[[ACQUIRE_BLK]]
+ // LLVM: i32 3, label %[[RELEASE_BLK:.+]]
+ // LLVM: i32 4, label %[[ACQ_REL_BLK:.+]]
+ // LLVM: i32 5, label %[[SEQ_CST_BLK:.+]]
+ // LLVM: ]
+ // LLVM: [[DEFAULT_BLK]]:
+ // LLVM: br label %{{.+}}
+ // LLVM: [[ACQUIRE_BLK]]:
+ // LLVM: fence acquire
+ // LLVM: br label %{{.+}}
+ // LLVM: [[RELEASE_BLK]]:
+ // LLVM: fence release
+ // LLVM: br label %{{.+}}
+ // LLVM: [[ACQ_REL_BLK]]:
+ // LLVM: fence acq_rel
+ // LLVM: br label %{{.+}}
+ // LLVM: [[SEQ_CST_BLK]]:
+ // LLVM: fence seq_cst
+ // LLVM: br label %{{.+}}
+
+ // OGCG-LABEL: variable_atomic_thread_fences
+ // OGCG: %[[ORDER:.+]] = load i32, ptr %[[PTR:.+]], align 4
+ // OGCG: switch i32 %[[ORDER]], label %[[DEFAULT_BLK:.+]] [
+ // OGCG: i32 1, label %[[ACQUIRE_BLK:.+]]
+ // OGCG: i32 2, label %[[ACQUIRE_BLK]]
+ // OGCG: i32 3, label %[[RELEASE_BLK:.+]]
+ // OGCG: i32 4, label %[[ACQ_REL_BLK:.+]]
+ // OGCG: i32 5, label %[[SEQ_CST_BLK:.+]]
+ // OGCG: ]
+ // OGCG: [[ACQUIRE_BLK]]:
+ // OGCG: fence acquire
+ // OGCG: br label %[[DEFAULT_BLK]]
+ // OGCG: [[RELEASE_BLK]]:
+ // OGCG: fence release
+ // OGCG: br label %[[DEFAULT_BLK]]
+ // OGCG: [[ACQ_REL_BLK]]:
+ // OGCG: fence acq_rel
+ // OGCG: br label %[[DEFAULT_BLK]]
+ // OGCG: [[SEQ_CST_BLK]]:
+ // OGCG: fence seq_cst
+ // OGCG: br label %[[DEFAULT_BLK]]
+ // OGCG: [[DEFAULT_BLK]]:
+ // OGCG: ret void
+}
+
+void variable_c11_atomic_thread_fences(int memorder) {
+ __c11_atomic_thread_fence(memorder);
+ // CIR-LABEL: variable_c11_atomic_thread_fences
+ // CIR: cir.switch
+ // CIR: cir.case(default, []) {
+ // CIR: cir.break
+ // CIR: }
+ // CIR: cir.case(anyof, [#cir.int<1> : !s32i, #cir.int<2> : !s32i]) {
+ // CIR: cir.atomic.fence syncscope(system) acquire
+ // CIR: cir.break
+ // CIR: }
+ // CIR: cir.case(anyof, [#cir.int<3> : !s32i]) {
+ // CIR: cir.atomic.fence syncscope(system) release
+ // CIR: cir.break
+ // CIR: }
+ // CIR: cir.case(anyof, [#cir.int<4> : !s32i]) {
+ // CIR: cir.atomic.fence syncscope(system) acq_rel
+ // CIR: cir.break
+ // CIR: }
+ // CIR: cir.case(anyof, [#cir.int<5> : !s32i]) {
+ // CIR: cir.atomic.fence syncscope(system)
+ // CIR: cir.break
+ // CIR: }
+ // CIR: cir.yield
+ // CIR: }
+
+ // LLVM-LABEL: variable_c11_atomic_thread_fences
+ // LLVM: %[[ORDER:.+]] = load i32, ptr %[[PTR:.+]], align 4
+ // LLVM: br label %[[SWITCH_BLK:.+]]
+ // LLVM: [[SWITCH_BLK]]:
+ // LLVM: switch i32 %[[ORDER]], label %[[DEFAULT_BLK:.+]] [
+ // LLVM: i32 1, label %[[ACQUIRE_BLK:.+]]
+ // LLVM: i32 2, label %[[ACQUIRE_BLK]]
+ // LLVM: i32 3, label %[[RELEASE_BLK:.+]]
+ // LLVM: i32 4, label %[[ACQ_REL_BLK:.+]]
+ // LLVM: i32 5, label %[[SEQ_CST_BLK:.+]]
+ // LLVM: ]
+ // LLVM: [[DEFAULT_BLK]]:
+ // LLVM: br label %{{.+}}
+ // LLVM: [[ACQUIRE_BLK]]:
+ // LLVM: fence acquire
+ // LLVM: br label %{{.+}}
+ // LLVM: [[RELEASE_BLK]]:
+ // LLVM: fence release
+ // LLVM: br label %{{.+}}
+ // LLVM: [[ACQ_REL_BLK]]:
+ // LLVM: fence acq_rel
+ // LLVM: br label %{{.+}}
+ // LLVM: [[SEQ_CST_BLK]]:
+ // LLVM: fence seq_cst
+ // LLVM: br label %{{.+}}
+
+ // OGCG-LABEL: variable_c11_atomic_thread_fences
+ // OGCG: %[[ORDER:.+]] = load i32, ptr %[[PTR:.+]], align 4
+ // OGCG: switch i32 %[[ORDER]], label %[[DEFAULT_BLK:.+]] [
+ // OGCG: i32 1, label %[[ACQUIRE_BLK:.+]]
+ // OGCG: i32 2, label %[[ACQUIRE_BLK]]
+ // OGCG: i32 3, label %[[RELEASE_BLK:.+]]
+ // OGCG: i32 4, label %[[ACQ_REL_BLK:.+]]
+ // OGCG: i32 5, label %[[SEQ_CST_BLK:.+]]
+ // OGCG: ]
+ // OGCG: [[ACQUIRE_BLK]]:
+ // OGCG: fence acquire
+ // OGCG: br label %[[DEFAULT_BLK]]
+ // OGCG: [[RELEASE_BLK]]:
+ // OGCG: fence release
+ // OGCG: br label %[[DEFAULT_BLK]]
+ // OGCG: [[ACQ_REL_BLK]]:
+ // OGCG: fence acq_rel
+ // OGCG: br label %[[DEFAULT_BLK]]
+ // OGCG: [[SEQ_CST_BLK]]:
+ // OGCG: fence seq_cst
+ // OGCG: br label %[[DEFAULT_BLK]]
+ // OGCG: [[DEFAULT_BLK]]:
+ // OGCG: ret void
+}
+
+void variable_atomic_signal_fences(int memorder) {
+ __atomic_signal_fence(memorder);
+ // CIR-LABEL: variable_atomic_signal_fences
+ // CIR: cir.switch
+ // CIR: cir.case(default, []) {
+ // CIR: cir.break
+ // CIR: }
+ // CIR: cir.case(anyof, [#cir.int<1> : !s32i, #cir.int<2> : !s32i]) {
+ // CIR: cir.atomic.fence syncscope(single_thread) acquire
+ // CIR: cir.break
+ // CIR: }
+ // CIR: cir.case(anyof, [#cir.int<3> : !s32i]) {
+ // CIR: cir.atomic.fence syncscope(single_thread) release
+ // CIR: cir.break
+ // CIR: }
+ // CIR: cir.case(anyof, [#cir.int<4> : !s32i]) {
+ // CIR: cir.atomic.fence syncscope(single_thread) acq_rel
+ // CIR: cir.break
+ // CIR: }
+ // CIR: cir.case(anyof, [#cir.int<5> : !s32i]) {
+ // CIR: cir.atomic.fence syncscope(single_thread)
+ // CIR: cir.break
+ // CIR: }
+ // CIR: cir.yield
+ // CIR: }
+
+ // LLVM-LABEL: variable_atomic_signal_fences
+ // LLVM: %[[ORDER:.+]] = load i32, ptr %[[PTR:.+]], align 4
+ // LLVM: br label %[[SWITCH_BLK:.+]]
+ // LLVM: [[SWITCH_BLK]]:
+ // LLVM: switch i32 %[[ORDER]], label %[[DEFAULT_BLK:.+]] [
+ // LLVM: i32 1, label %[[ACQUIRE_BLK:.+]]
+ // LLVM: i32 2, label %[[ACQUIRE_BLK]]
+ // LLVM: i32 3, label %[[RELEASE_BLK:.+]]
+ // LLVM: i32 4, label %[[ACQ_REL_BLK:.+]]
+ // LLVM: i32 5, label %[[SEQ_CST_BLK:.+]]
+ // LLVM: ]
+ // LLVM: [[DEFAULT_BLK]]:
+ // LLVM: br label %{{.+}}
+ // LLVM: [[ACQUIRE_BLK]]:
+ // LLVM: fence syncscope("singlethread") acquire
+ // LLVM: br label %{{.+}}
+ // LLVM: [[RELEASE_BLK]]:
+ // LLVM: fence syncscope("singlethread") release
+ // LLVM: br label %{{.+}}
+ // LLVM: [[ACQ_REL_BLK]]:
+ // LLVM: fence syncscope("singlethread") acq_rel
+ // LLVM: br label %{{.+}}
+ // LLVM: [[SEQ_CST_BLK]]:
+ // LLVM: fence syncscope("singlethread") seq_cst
+ // LLVM: br label %{{.+}}
+
+ // OGCG-LABEL: variable_atomic_signal_fences
+ // OGCG: %[[ORDER:.+]] = load i32, ptr %[[PTR:.+]], align 4
+ // OGCG: switch i32 %[[ORDER]], label %[[DEFAULT_BLK:.+]] [
+ // OGCG: i32 1, label %[[ACQUIRE_BLK:.+]]
+ // OGCG: i32 2, label %[[ACQUIRE_BLK]]
+ // OGCG: i32 3, label %[[RELEASE_BLK:.+]]
+ // OGCG: i32 4, label %[[ACQ_REL_BLK:.+]]
+ // OGCG: i32 5, label %[[SEQ_CST_BLK:.+]]
+ // OGCG: ]
+ // OGCG: [[ACQUIRE_BLK]]:
+ // OGCG: fence syncscope("singlethread") acquire
+ // OGCG: br label %[[DEFAULT_BLK]]
+ // OGCG: [[RELEASE_BLK]]:
+ // OGCG: fence syncscope("singlethread") release
+ // OGCG: br label %[[DEFAULT_BLK]]
+ // OGCG: [[ACQ_REL_BLK]]:
+ // OGCG: fence syncscope("singlethread") acq_rel
+ // OGCG: br label %[[DEFAULT_BLK]]
+ // OGCG: [[SEQ_CST_BLK]]:
+ // OGCG: fence syncscope("singlethread") seq_cst
+ // OGCG: br label %[[DEFAULT_BLK]]
+ // OGCG: [[DEFAULT_BLK]]:
+ // OGCG: ret void
+}
+
+void variable_c11_atomic_signal_fences(int memorder) {
+ __c11_atomic_signal_fence(memorder);
+ // CIR-LABEL: variable_c11_atomic_signal_fences
+ // CIR: cir.switch
+ // CIR: cir.case(default, []) {
+ // CIR: cir.break
+ // CIR: }
+ // CIR: cir.case(anyof, [#cir.int<1> : !s32i, #cir.int<2> : !s32i]) {
+ // CIR: cir.atomic.fence syncscope(single_thread) acquire
+ // CIR: cir.break
+ // CIR: }
+ // CIR: cir.case(anyof, [#cir.int<3> : !s32i]) {
+ // CIR: cir.atomic.fence syncscope(single_thread) release
+ // CIR: cir.break
+ // CIR: }
+ // CIR: cir.case(anyof, [#cir.int<4> : !s32i]) {
+ // CIR: cir.atomic.fence syncscope(single_thread) acq_rel
+ // CIR: cir.break
+ // CIR: }
+ // CIR: cir.case(anyof, [#cir.int<5> : !s32i]) {
+ // CIR: cir.atomic.fence syncscope(single_thread)
+ // CIR: cir.break
+ // CIR: }
+ // CIR: cir.yield
+ // CIR: }
+
+ // LLVM-LABEL: variable_c11_atomic_signal_fences
+ // LLVM: %[[ORDER:.+]] = load i32, ptr %[[PTR:.+]], align 4
+ // LLVM: br label %[[SWITCH_BLK:.+]]
+ // LLVM: [[SWITCH_BLK]]:
+ // LLVM: switch i32 %[[ORDER]], label %[[DEFAULT_BLK:.+]] [
+ // LLVM: i...
[truncated]
|
7e47024 to
1e7e9a6
Compare
…order - Support CIR codegen for follow atomic fence builtin when the memory order is non constant: `__atomic_thread_fence` `__atomic_signal_fence` `__c11_atomic_thread_fence` `__c11_atomic_signal_fence` - Refactor current implementation when the memory order is constant, the argument expression at AST is evaluated as a constant directly. - Add test cases that cover all kinds of memory order.
Lancern
requested changes
Dec 16, 2025
bcardosolopes
approved these changes
Dec 18, 2025
Member
bcardosolopes
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
__atomic_thread_fence__atomic_signal_fence__c11_atomic_thread_fence__c11_atomic_signal_fenceemitAtomicExprWithMemOrder