[clang] [CIR][NFC] Align dynamic dispatch of sync scopes to memory ordering (PR #206054)
Sirui Mu via cfe-commits
cfe-commits at lists.llvm.org
Fri Jun 26 05:52:20 PDT 2026
https://github.com/Lancern created https://github.com/llvm/llvm-project/pull/206054
This patch is a minor refactoring that aligns the dynamic dispatch path of atomic sync scopes to the dynamic dispatch path of atomic memory ordering.
>From e35dbf73fa43f1b966d8f46b90e8f52090d73cd0 Mon Sep 17 00:00:00 2001
From: Sirui Mu <msrlancern at gmail.com>
Date: Fri, 26 Jun 2026 20:37:30 +0800
Subject: [PATCH] [CIR][NFC] Align dynamic dispatch of sync scopes to memory
ordering
This patch is a minor refactoring that aligns the dynamic dispatch path of
atomic sync scopes to the dynamic dispatch path of atomic memory ordering.
---
clang/lib/CIR/CodeGen/CIRGenAtomic.cpp | 161 ++++++++++++-------------
clang/lib/CIR/CodeGen/CIRGenFunction.h | 3 +
2 files changed, 80 insertions(+), 84 deletions(-)
diff --git a/clang/lib/CIR/CodeGen/CIRGenAtomic.cpp b/clang/lib/CIR/CodeGen/CIRGenAtomic.cpp
index 4d774761b975a..41be5c9cc95c3 100644
--- a/clang/lib/CIR/CodeGen/CIRGenAtomic.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenAtomic.cpp
@@ -890,7 +890,6 @@ static void emitAtomicOp(CIRGenFunction &cgf, AtomicExpr *expr, Address dest,
// Map clang sync scope to CIR sync scope.
static cir::SyncScopeKind convertSyncScopeToCIR(CIRGenFunction &cgf,
- SourceRange range,
clang::SyncScope scope) {
switch (scope) {
case clang::SyncScope::SingleScope:
@@ -932,75 +931,6 @@ static cir::SyncScopeKind convertSyncScopeToCIR(CIRGenFunction &cgf,
llvm_unreachable("unhandled sync scope");
}
-static void emitAtomicOp(CIRGenFunction &cgf, AtomicExpr *expr, Address dest,
- Address ptr, Address val1, Address val2,
- Expr *isWeakExpr, Expr *failureOrderExpr, int64_t size,
- cir::MemOrder order,
- const std::optional<Expr::EvalResult> &scopeConst,
- mlir::Value scopeValue) {
- std::unique_ptr<AtomicScopeModel> scopeModel = expr->getScopeModel();
-
- if (!scopeModel) {
- emitAtomicOp(cgf, expr, dest, ptr, val1, val2, isWeakExpr, failureOrderExpr,
- size, order, cir::SyncScopeKind::System);
- return;
- }
-
- if (scopeConst.has_value()) {
- cir::SyncScopeKind mappedScope = convertSyncScopeToCIR(
- cgf, expr->getScope()->getSourceRange(),
- scopeModel->map(scopeConst->Val.getInt().getZExtValue()));
- emitAtomicOp(cgf, expr, dest, ptr, val1, val2, isWeakExpr, failureOrderExpr,
- size, order, mappedScope);
- return;
- }
-
- // The sync scope is not a compile-time constant. Emit a switch statement to
- // handle each possible value of the sync scope.
- CIRGenBuilderTy &builder = cgf.getBuilder();
- mlir::Location loc = cgf.getLoc(expr->getSourceRange());
- llvm::ArrayRef<unsigned> allScopes = scopeModel->getRuntimeValues();
- unsigned fallback = scopeModel->getFallBackValue();
-
- cir::SwitchOp::create(
- builder, loc, scopeValue,
- [&](mlir::OpBuilder &, mlir::Location loc, mlir::OperationState &) {
- mlir::Block *switchBlock = builder.getBlock();
-
- // Default case -- use fallback scope
- cir::SyncScopeKind fallbackScope = convertSyncScopeToCIR(
- cgf, expr->getScope()->getSourceRange(), scopeModel->map(fallback));
- emitDefaultCaseLabel(builder, loc);
- emitAtomicOp(cgf, expr, dest, ptr, val1, val2, isWeakExpr,
- failureOrderExpr, size, order, fallbackScope);
- builder.createBreak(loc);
- builder.setInsertionPointToEnd(switchBlock);
-
- // Emit a switch case for each non-fallback runtime scope value
- for (unsigned scope : allScopes) {
- if (scope == fallback)
- continue;
-
- cir::SyncScopeKind cirScope = convertSyncScopeToCIR(
- cgf, expr->getScope()->getSourceRange(), scopeModel->map(scope));
-
- mlir::ArrayAttr casesAttr = builder.getArrayAttr(
- {cir::IntAttr::get(scopeValue.getType(), scope)});
- mlir::OpBuilder::InsertPoint insertPoint;
- cir::CaseOp::create(builder, loc, casesAttr, cir::CaseOpKind::Equal,
- insertPoint);
-
- builder.restoreInsertionPoint(insertPoint);
- emitAtomicOp(cgf, expr, dest, ptr, val1, val2, isWeakExpr,
- failureOrderExpr, size, order, cirScope);
- builder.createBreak(loc);
- builder.setInsertionPointToEnd(switchBlock);
- }
-
- builder.createYield(loc);
- });
-}
-
static std::optional<cir::MemOrder>
getEffectiveAtomicMemOrder(cir::MemOrder oriOrder, bool isStore, bool isLoad,
bool isFence) {
@@ -1090,6 +1020,50 @@ static void emitAtomicExprWithDynamicMemOrder(
});
}
+static void emitAtomicExprWithDynamicSyncScope(
+ CIRGenFunction &cgf, const AtomicScopeModel *scopeModel, mlir::Value scope,
+ llvm::function_ref<void(cir::SyncScopeKind)> emitAtomicOp) {
+ CIRGenBuilderTy &builder = cgf.getBuilder();
+ llvm::ArrayRef<unsigned> allScopes = scopeModel->getRuntimeValues();
+ unsigned fallback = scopeModel->getFallBackValue();
+
+ cir::SwitchOp::create(
+ builder, scope.getLoc(), scope,
+ [&](mlir::OpBuilder &, mlir::Location loc, mlir::OperationState &) {
+ mlir::Block *switchBlock = builder.getBlock();
+
+ // Default case -- use fallback scope
+ cir::SyncScopeKind fallbackScope =
+ convertSyncScopeToCIR(cgf, scopeModel->map(fallback));
+ emitDefaultCaseLabel(builder, loc);
+ emitAtomicOp(fallbackScope);
+ builder.createBreak(loc);
+ builder.setInsertionPointToEnd(switchBlock);
+
+ // Emit a switch case for each non-fallback runtime scope value
+ for (unsigned runtimeScopeValue : allScopes) {
+ if (runtimeScopeValue == fallback)
+ continue;
+
+ cir::SyncScopeKind cirScope =
+ convertSyncScopeToCIR(cgf, scopeModel->map(runtimeScopeValue));
+
+ mlir::ArrayAttr casesAttr = builder.getArrayAttr(
+ {cir::IntAttr::get(scope.getType(), runtimeScopeValue)});
+ mlir::OpBuilder::InsertPoint insertPoint;
+ cir::CaseOp::create(builder, loc, casesAttr, cir::CaseOpKind::Equal,
+ insertPoint);
+
+ builder.restoreInsertionPoint(insertPoint);
+ emitAtomicOp(cirScope);
+ builder.createBreak(loc);
+ builder.setInsertionPointToEnd(switchBlock);
+ }
+
+ builder.createYield(loc);
+ });
+}
+
void CIRGenFunction::emitAtomicExprWithMemOrder(
const Expr *memOrder, bool isStore, bool isLoad, bool isFence,
llvm::function_ref<void(cir::MemOrder)> emitAtomicOpFn) {
@@ -1115,6 +1089,29 @@ void CIRGenFunction::emitAtomicExprWithMemOrder(
emitAtomicOpFn);
}
+void CIRGenFunction::emitAtomicExprWithSyncScope(
+ const AtomicScopeModel *scopeModel, const Expr *scopeExpr,
+ llvm::function_ref<void(cir::SyncScopeKind)> emitAtomicOp) {
+ if (!scopeModel || !scopeExpr) {
+ emitAtomicOp(cir::SyncScopeKind::System);
+ return;
+ }
+
+ // Try to evaluate the sync scope as a constant.
+ Expr::EvalResult scopeConst;
+ if (scopeExpr->EvaluateAsInt(scopeConst, getContext())) {
+ cir::SyncScopeKind mappedScope = convertSyncScopeToCIR(
+ *this, scopeModel->map(scopeConst.Val.getInt().getZExtValue()));
+ emitAtomicOp(mappedScope);
+ return;
+ }
+
+ // Otherwise, handle variable sync scope. Emit a switch op to match dynamic
+ // sync scope values to static sync scopes.
+ mlir::Value dynScope = emitScalarExpr(scopeExpr);
+ emitAtomicExprWithDynamicSyncScope(*this, scopeModel, dynScope, emitAtomicOp);
+}
+
static RValue emitAtomicLibCall(CIRGenFunction &cgf, llvm::StringRef funcName,
QualType resultType, CallArgList &args) {
const CIRGenFunctionInfo &fnInfo =
@@ -1357,14 +1354,6 @@ RValue CIRGenFunction::emitAtomicExpr(AtomicExpr *e) {
TypeInfoChars typeInfo = getContext().getTypeInfoInChars(atomicTy);
uint64_t size = typeInfo.Width.getQuantity();
- // Emit the sync scope operand, and try to evaluate it as a constant.
- mlir::Value scope =
- e->getScopeModel() ? emitScalarExpr(e->getScope()) : nullptr;
- std::optional<Expr::EvalResult> scopeConst;
- if (Expr::EvalResult eval;
- e->getScopeModel() && e->getScope()->EvaluateAsInt(eval, getContext()))
- scopeConst.emplace(std::move(eval));
-
switch (e->getOp()) {
default:
cgm.errorNYI(e->getSourceRange(), "atomic op NYI");
@@ -1562,12 +1551,16 @@ RValue CIRGenFunction::emitAtomicExpr(AtomicExpr *e) {
e->getOp() == AtomicExpr::AO__scoped_atomic_load ||
e->getOp() == AtomicExpr::AO__scoped_atomic_load_n;
- auto emitAtomicOpCallBackFn = [&](cir::MemOrder memOrder) {
- emitAtomicOp(*this, e, dest, ptr, val1, val2, isWeakExpr, orderFailExpr,
- size, memOrder, scopeConst, scope);
- };
- emitAtomicExprWithMemOrder(e->getOrder(), isStore, isLoad, /*isFence*/ false,
- emitAtomicOpCallBackFn);
+ emitAtomicExprWithMemOrder(
+ e->getOrder(), isStore, isLoad, /*isFence*/ false,
+ [&](cir::MemOrder memOrder) {
+ emitAtomicExprWithSyncScope(
+ e->getScopeModel().get(), e->getScope(),
+ [&](cir::SyncScopeKind scope) {
+ emitAtomicOp(*this, e, dest, ptr, val1, val2, isWeakExpr,
+ orderFailExpr, size, memOrder, scope);
+ });
+ });
if (resultTy->isVoidType())
return RValue::get(nullptr);
diff --git a/clang/lib/CIR/CodeGen/CIRGenFunction.h b/clang/lib/CIR/CodeGen/CIRGenFunction.h
index b6a4a277fab92..0beb5974778f3 100644
--- a/clang/lib/CIR/CodeGen/CIRGenFunction.h
+++ b/clang/lib/CIR/CodeGen/CIRGenFunction.h
@@ -1642,6 +1642,9 @@ class CIRGenFunction : public CIRGenTypeCache {
void emitAtomicExprWithMemOrder(
const Expr *memOrder, bool isStore, bool isLoad, bool isFence,
llvm::function_ref<void(cir::MemOrder)> emitAtomicOp);
+ void emitAtomicExprWithSyncScope(
+ const AtomicScopeModel *scopeModel, const Expr *scopeExpr,
+ llvm::function_ref<void(cir::SyncScopeKind)> emitAtomicOp);
mlir::LogicalResult emitAttributedStmt(const AttributedStmt &s);
More information about the cfe-commits
mailing list