https://github.com/HendrikHuebner created https://github.com/llvm/llvm-project/pull/168346
This PR upstreams the AtomicFence operation from the incubator repo. From 2aa5a6d11f5f856f3bf1383cb8bc8637156a2279 Mon Sep 17 00:00:00 2001 From: hhuebner <[email protected]> Date: Mon, 17 Nov 2025 10:01:13 +0100 Subject: [PATCH 1/2] [CIR] Add atomic fence op --- clang/include/clang/CIR/Dialect/IR/CIROps.td | 30 ++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td index 2124b1dc62a81..ee912073d2e0c 100644 --- a/clang/include/clang/CIR/Dialect/IR/CIROps.td +++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td @@ -4845,4 +4845,34 @@ def CIR_AtomicClearOp : CIR_Op<"atomic.clear"> { }]; } +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<CIR_MemOrder, "memory order">:$ordering, + OptionalAttr<CIR_MemScopeKind>:$syncscope + ); + + let assemblyFormat = [{ + (`syncscope` `(` $syncscope^ `)`)? $ordering attr-dict + }]; +} + #endif // CLANG_CIR_DIALECT_IR_CIROPS_TD From 8b845f0527d340aa0ec875919d953474cd84ee29 Mon Sep 17 00:00:00 2001 From: hhuebner <[email protected]> Date: Mon, 17 Nov 2025 12:08:49 +0100 Subject: [PATCH 2/2] Implement fence builtins --- clang/include/clang/CIR/Dialect/IR/CIROps.td | 5 +++ clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp | 39 +++++++++++++++++++ .../CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp | 21 ++++++++++ 3 files changed, 65 insertions(+) diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td index ee912073d2e0c..ee63ac39c5ba4 100644 --- a/clang/include/clang/CIR/Dialect/IR/CIROps.td +++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td @@ -4845,6 +4845,11 @@ def CIR_AtomicClearOp : CIR_Op<"atomic.clear"> { }]; } +def CIR_MemScopeKind : CIR_I32EnumAttr<"MemScopeKind", "memory 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 = [{ diff --git a/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp b/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp index 77f19343653db..1223669a76ab1 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::MemScopeKind syncScope) { + auto &builder = cgf.getBuilder(); + mlir::Value orderingVal = cgf.emitScalarExpr(expr->getArg(0)); + + auto constOrdering = orderingVal.getDefiningOp<cir::ConstantOp>(); + if (!constOrdering) + llvm_unreachable("NYI: variable ordering not supported"); + + if (auto constOrderingAttr = constOrdering.getValueAttr<cir::IntAttr>()) { + cir::MemOrder ordering = + static_cast<cir::MemOrder>(constOrderingAttr.getUInt()); + + cir::AtomicFence::create( + builder, cgf.getLoc(expr->getSourceRange()), ordering, + cir::MemScopeKindAttr::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)); @@ -520,6 +542,23 @@ RValue CIRGenFunction::emitBuiltinExpr(const GlobalDecl &gd, unsigned builtinID, cir::PrefetchOp::create(builder, loc, address, locality, isWrite); return RValue::get(nullptr); } + case Builtin::BI__c11_atomic_is_lock_free: + llvm_unreachable("BI__c11_atomic_is_lock_free NYI"); + case Builtin::BI__atomic_is_lock_free: + llvm_unreachable("BI__atomic_is_lock_free NYI"); + case Builtin::BI__atomic_test_and_set: + llvm_unreachable("BI__atomic_test_and_set NYI"); + case Builtin::BI__atomic_clear: + llvm_unreachable("BI__atomic_clear NYI"); + case Builtin::BI__atomic_thread_fence: + return RValue::get( + makeAtomicFenceValue(*this, e, cir::MemScopeKind::System)); + case Builtin::BI__atomic_signal_fence: + return RValue::get( + makeAtomicFenceValue(*this, e, cir::MemScopeKind::SingleThread)); + case Builtin::BI__c11_atomic_thread_fence: + case Builtin::BI__c11_atomic_signal_fence: + llvm_unreachable("BI__c11_atomic_thread_fence like NYI"); } // 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 d88a4ad76f27b..755a9b572f3ca 100644 --- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp +++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp @@ -732,6 +732,14 @@ getLLVMMemOrder(std::optional<cir::MemOrder> memorder) { llvm_unreachable("unknown memory order"); } +static std::optional<llvm::StringRef> +getLLVMSyncScope(std::optional<cir::MemScopeKind> syncScope) { + if (syncScope.has_value()) + return syncScope.value() == cir::MemScopeKind::SingleThread ? "singlethread" + : ""; + return std::nullopt; +} + mlir::LogicalResult CIRToLLVMAtomicCmpXchgOpLowering::matchAndRewrite( cir::AtomicCmpXchgOp op, OpAdaptor adaptor, mlir::ConversionPatternRewriter &rewriter) const { @@ -808,6 +816,19 @@ mlir::LogicalResult CIRToLLVMAtomicClearOpLowering::matchAndRewrite( return mlir::success(); } +mlir::LogicalResult CIRToLLVMAtomicFenceLowering::matchAndRewrite( + cir::AtomicFence op, OpAdaptor adaptor, + mlir::ConversionPatternRewriter &rewriter) const { + mlir::LLVM::AtomicOrdering llvmOrder = getLLVMMemOrder(adaptor.getOrdering()); + + auto fence = mlir::LLVM::FenceOp::create(rewriter, op.getLoc(), llvmOrder); + fence.setSyncscope(getLLVMSyncScope(adaptor.getSyncscope())); + + rewriter.replaceOp(op, fence); + + return mlir::success(); +} + static mlir::LLVM::AtomicBinOp getLLVMAtomicBinOp(cir::AtomicFetchKind k, bool isInt, bool isSignedInt) { switch (k) { _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
