-
Notifications
You must be signed in to change notification settings - Fork 15.4k
[CIR] Add AtomicFenceOp and signal/thread fence builtins and required helpers #168346
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
[CIR] Add AtomicFenceOp and signal/thread fence builtins and required helpers #168346
Conversation
|
@llvm/pr-subscribers-clang @llvm/pr-subscribers-clangir Author: Hendrik Hübner (HendrikHuebner) ChangesThis PR upstreams the AtomicFence operation from the incubator repo. Full diff: https://github.com/llvm/llvm-project/pull/168346.diff 3 Files Affected:
diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td
index 2124b1dc62a81..ee63ac39c5ba4 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIROps.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td
@@ -4845,4 +4845,39 @@ 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 = [{
+ 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
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) {
|
6756a00 to
24e3f1a
Compare
🐧 Linux x64 Test Results
✅ The build succeeded and all tests passed. |
| }]; | ||
| } | ||
|
|
||
| def CIR_SyncScopeKind : CIR_I32EnumAttr<"SyncScopeKind", "sync scope kind", [ |
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.
Move this attribute closer to CIR_AtomicFetchKind
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.
done
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.
This hasn't been addressed.
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.
Looks I did not push the fix. Thanks for catching this.
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.
Updated
1669d4d to
36ec970
Compare
|
✅ With the latest revision this PR passed the C/C++ code formatter. |
|
@bcardosolopes @Lancern Any more comments or can this be merged? |
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.
Thanks for pinging, LGTM
| }]; | ||
| } | ||
|
|
||
| def CIR_SyncScopeKind : CIR_I32EnumAttr<"SyncScopeKind", "sync scope kind", [ |
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.
This hasn't been addressed.
… helpers (llvm#168346) This PR adds the AtomicFenceOp and signal/thread fence builtins.
This PR upstreams the AtomicFence operation from the incubator repo.