https://github.com/HendrikHuebner updated
https://github.com/llvm/llvm-project/pull/168346
From 24e3f1a0c9d41633504bc0270968013336228e39 Mon Sep 17 00:00:00 2001
From: hhuebner
Date: Mon, 17 Nov 2025 10:01:13 +0100
Subject: [PATCH 1/4] [CIR] Add atomic fence op
---
clang/include/clang/CIR/Dialect/IR/CIROps.td | 35
clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp | 28 +++
.../CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp | 22 +++
clang/test/CIR/CodeGen/atomic-thread-fence.c | 181 ++
4 files changed, 266 insertions(+)
create mode 100644 clang/test/CIR/CodeGen/atomic-thread-fence.c
diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td
b/clang/include/clang/CIR/Dialect/IR/CIROps.td
index 3c59a0b2a3144..31adc2bb039f0 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIROps.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td
@@ -5122,6 +5122,41 @@ def CIR_AtomicClearOp : CIR_Op<"atomic.clear"> {
}];
}
+def CIR_SyncScopeKind : CIR_I32EnumAttr<"SyncScopeKind", "sync scope kind", [
+ I32EnumAttrCase<"SingleThread", 0, "single_thread">,
+ I32EnumAttrCase<"System", 1, "system">
+]>;
+
+def CIR_AtomicFence : CIR_Op<"atomic.fence"> {
+ let summary = "Atomic thread fence";
+ let description = [{
+C/C++ Atomic thread fence synchronization primitive. Implements the builtin
+`__atomic_thread_fence` which enforces memory ordering constraints across
+threads within the specified synchronization scope.
+
+This handles all variations including:
+ - `__atomic_thread_fence`
+ - `__atomic_signal_fence`
+ - `__c11_atomic_thread_fence`
+ - `__c11_atomic_signal_fence`
+
+Example:
+```mlir
+ cir.atomic.fence syncscope(system) seq_cst
+ cir.atomic.fence syncscope(single_thread) seq_cst
+```
+ }];
+
+ let arguments = (ins
+Arg:$ordering,
+OptionalAttr:$syncscope
+ );
+
+ let assemblyFormat = [{
+(`syncscope` `(` $syncscope^ `)`)? $ordering attr-dict
+ }];
+}
+
//===--===//
// BlockAddressOp
//===--===//
diff --git a/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp
b/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp
index dee5704c66011..7bb31be1413f6 100644
--- a/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp
@@ -58,6 +58,28 @@ static RValue emitBuiltinBitOp(CIRGenFunction &cgf, const
CallExpr *e,
return RValue::get(result);
}
+static mlir::Value makeAtomicFenceValue(CIRGenFunction &cgf,
+const CallExpr *expr,
+cir::SyncScopeKind syncScope) {
+ auto &builder = cgf.getBuilder();
+ mlir::Value orderingVal = cgf.emitScalarExpr(expr->getArg(0));
+
+ auto constOrdering = orderingVal.getDefiningOp();
+ if (!constOrdering)
+llvm_unreachable("NYI: variable ordering not supported");
+
+ if (auto constOrderingAttr = constOrdering.getValueAttr()) {
+cir::MemOrder ordering =
+static_cast(constOrderingAttr.getUInt());
+
+cir::AtomicFence::create(
+builder, cgf.getLoc(expr->getSourceRange()), ordering,
+cir::SyncScopeKindAttr::get(&cgf.getMLIRContext(), syncScope));
+ }
+
+ return {};
+}
+
RValue CIRGenFunction::emitRotate(const CallExpr *e, bool isRotateLeft) {
mlir::Value input = emitScalarExpr(e->getArg(0));
mlir::Value amount = emitScalarExpr(e->getArg(1));
@@ -612,6 +634,12 @@ RValue CIRGenFunction::emitBuiltinExpr(const GlobalDecl
&gd, unsigned builtinID,
builder.createIsFPClass(loc, v, cir::FPClassTest(test)),
convertType(e->getType(;
}
+ case Builtin::BI__atomic_thread_fence:
+return RValue::get(
+makeAtomicFenceValue(*this, e, cir::SyncScopeKind::System));
+ case Builtin::BI__atomic_signal_fence:
+return RValue::get(
+makeAtomicFenceValue(*this, e, cir::SyncScopeKind::SingleThread));
}
// If this is an alias for a lib function (e.g. __builtin_sin), emit
diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
index 833464824f0e5..ead2803c8582a 100644
--- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
+++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
@@ -750,6 +750,15 @@ getLLVMMemOrder(std::optional memorder) {
llvm_unreachable("unknown memory order");
}
+static std::optional
+getLLVMSyncScope(std::optional syncScope) {
+ if (syncScope.has_value())
+return syncScope.value() == cir::SyncScopeKind::SingleThread
+ ? "singlethread"
+ : "";
+ return std::nullopt;
+}
+
mlir::LogicalResult CIRToLLVMAtomicCmpXchgOpLowering::matchAndRewrite(
cir::AtomicCmpXchgOp op, OpAdaptor adaptor,
mlir::ConversionPatternRewriter &rewriter) const {
@@ -826,6 +835,19 @@ mlir::LogicalResult
CIRToLLVMAtomicClearOpLowering::matchAndRewrite(
return mlir::success();
}