[clang] 6855d70 - [CIR] Add support for atomic-to-non-atomic cast (#193784)
via cfe-commits
cfe-commits at lists.llvm.org
Sat Apr 25 09:33:06 PDT 2026
Author: Sirui Mu
Date: 2026-04-26T00:33:01+08:00
New Revision: 6855d70d0153bc1b238a781db0211bdb581cfa4a
URL: https://github.com/llvm/llvm-project/commit/6855d70d0153bc1b238a781db0211bdb581cfa4a
DIFF: https://github.com/llvm/llvm-project/commit/6855d70d0153bc1b238a781db0211bdb581cfa4a.diff
LOG: [CIR] Add support for atomic-to-non-atomic cast (#193784)
This patch adds support for atomic-to-non-atomic casts in CIR.
Related to #192319 .
Assisted-by: Github Copilot / GPT-5.4
Added:
Modified:
clang/lib/CIR/CodeGen/CIRGenAtomic.cpp
clang/lib/CIR/CodeGen/CIRGenExpr.cpp
clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp
clang/lib/CIR/CodeGen/CIRGenFunction.h
clang/test/CIR/CodeGen/atomic.c
Removed:
################################################################################
diff --git a/clang/lib/CIR/CodeGen/CIRGenAtomic.cpp b/clang/lib/CIR/CodeGen/CIRGenAtomic.cpp
index 4b5c5325d0486..e9bf89c91627f 100644
--- a/clang/lib/CIR/CodeGen/CIRGenAtomic.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenAtomic.cpp
@@ -113,6 +113,10 @@ class AtomicInfo {
/// Converts a rvalue to integer value.
mlir::Value convertRValueToInt(RValue rvalue, bool cmpxchg = false) const;
+ RValue convertToValueOrAtomic(mlir::Value intVal, AggValueSlot resultSlot,
+ SourceLocation loc, bool asValue,
+ bool cmpxchg = false) const;
+
/// Copy an atomic r-value into atomic-layout memory.
void emitCopyIntoMemory(RValue rvalue) const;
@@ -128,11 +132,20 @@ class AtomicInfo {
return LValue::makeAddr(addr, getValueType(), lvalue.getBaseInfo());
}
+ /// Emits atomic load.
+ /// \returns Loaded value.
+ RValue emitAtomicLoad(AggValueSlot resultSlot, SourceLocation loc,
+ bool asValue, cir::MemOrder order, bool isVolatile);
+
/// Creates temp alloca for intermediate operations on atomic value.
Address createTempAlloca() const;
private:
bool requiresMemSetZero(mlir::Type ty) const;
+
+ /// Emits atomic load as a CIR operation.
+ mlir::Value emitAtomicLoadOp(cir::MemOrder order, bool isVolatile,
+ bool cmpxchg = false);
};
} // namespace
@@ -189,6 +202,28 @@ Address AtomicInfo::convertToAtomicIntPointer(Address addr) const {
return castToAtomicIntPointer(addr);
}
+RValue AtomicInfo::emitAtomicLoad(AggValueSlot resultSlot, SourceLocation loc,
+ bool asValue, cir::MemOrder order,
+ bool isVolatile) {
+ // Check whether we should use a library call.
+ if (shouldUseLibCall()) {
+ assert(!cir::MissingFeatures::atomicUseLibCall());
+ cgf.cgm.errorNYI(loc, "emitAtomicLoad: emit atomic lib call");
+ return RValue::get(nullptr);
+ }
+
+ // Okay, we're doing this natively.
+ mlir::Value loadOp = emitAtomicLoadOp(order, isVolatile);
+
+ // If we're ignoring an aggregate return, don't do anything.
+ if (getEvaluationKind() == TEK_Aggregate && resultSlot.isIgnored())
+ return RValue::getAggregate(Address::invalid(), false);
+
+ // Okay, turn that back into the original value or atomic (for non-simple
+ // lvalues) type.
+ return convertToValueOrAtomic(loadOp, resultSlot, loc, asValue);
+}
+
Address AtomicInfo::createTempAlloca() const {
Address tempAlloca = cgf.createMemTemp(
(lvalue.isBitField() && valueSizeInBits > atomicSizeInBits) ? valueTy
@@ -240,6 +275,20 @@ static bool shouldCastToInt(mlir::Type valueTy, bool cmpxchg) {
return !isa<cir::IntType>(valueTy) && !isa<cir::PointerType>(valueTy);
}
+mlir::Value AtomicInfo::emitAtomicLoadOp(cir::MemOrder order, bool isVolatile,
+ bool cmpxchg) {
+ Address addr = getAtomicAddress();
+ if (shouldCastToInt(addr.getElementType(), cmpxchg))
+ addr = castToAtomicIntPointer(addr);
+
+ cir::LoadOp op =
+ cgf.getBuilder().createLoad(loc, addr, /*isVolatile=*/isVolatile);
+ op.setMemOrder(order);
+
+ assert(!cir::MissingFeatures::opTBAA());
+ return op;
+}
+
mlir::Value AtomicInfo::convertRValueToInt(RValue rvalue, bool cmpxchg) const {
// If we've got a scalar value of the right size, try to avoid going
// through memory. Floats get casted if needed by AtomicExpandPass.
@@ -257,6 +306,35 @@ mlir::Value AtomicInfo::convertRValueToInt(RValue rvalue, bool cmpxchg) const {
return nullptr;
}
+RValue AtomicInfo::convertToValueOrAtomic(mlir::Value intVal,
+ AggValueSlot resultSlot,
+ SourceLocation loc, bool asValue,
+ bool cmpxchg) const {
+ // Try not to in some easy cases.
+ assert((mlir::isa<cir::IntType, cir::PointerType, cir::FPTypeInterface>(
+ intVal.getType())) &&
+ "Expected integer, pointer or floating point value when converting "
+ "result.");
+ bool isWholeValue =
+ !lvalue.isBitField() || lvalue.getBitFieldInfo().size == valueSizeInBits;
+ if (getEvaluationKind() == TEK_Scalar &&
+ ((isWholeValue && !hasPadding()) || !asValue)) {
+ mlir::Type valTy = asValue ? cgf.convertTypeForMem(valueTy)
+ : getAtomicAddress().getElementType();
+ if (!shouldCastToInt(valTy, cmpxchg)) {
+ assert((!mlir::isa<cir::IntType>(valTy) || intVal.getType() == valTy) &&
+ "Different integer types.");
+ return RValue::get(cgf.emitFromMemory(intVal, valueTy));
+ }
+
+ cgf.cgm.errorNYI("convertToValueOrAtomic: convert through bitcast");
+ return RValue::get(nullptr);
+ }
+
+ cgf.cgm.errorNYI("convertToValueOrAtomic: convert through temp");
+ return RValue::get(nullptr);
+}
+
/// Copy an r-value into memory as part of storing to an atomic type.
/// This needs to create a bit-pattern suitable for atomic operations.
void AtomicInfo::emitCopyIntoMemory(RValue rvalue) const {
@@ -1163,6 +1241,22 @@ RValue CIRGenFunction::emitAtomicExpr(AtomicExpr *e) {
e->getExprLoc());
}
+RValue CIRGenFunction::emitAtomicLoad(LValue lvalue, SourceLocation loc,
+ AggValueSlot slot) {
+ if (lvalue.getType()->isAtomicType())
+ return emitAtomicLoad(lvalue, loc, cir::MemOrder::SequentiallyConsistent,
+ /*isVolatile=*/lvalue.isVolatileQualified(), slot);
+ return emitAtomicLoad(lvalue, loc, cir::MemOrder::Acquire,
+ /*isVolatile=*/true, slot);
+}
+
+RValue CIRGenFunction::emitAtomicLoad(LValue lvalue, SourceLocation loc,
+ cir::MemOrder order, bool isVolatile,
+ AggValueSlot slot) {
+ AtomicInfo info(*this, lvalue, getLoc(loc));
+ return info.emitAtomicLoad(slot, loc, /*asValue=*/true, order, isVolatile);
+}
+
void CIRGenFunction::emitAtomicStore(RValue rvalue, LValue dest, bool isInit) {
bool isVolatile = dest.isVolatileQualified();
auto order = cir::MemOrder::SequentiallyConsistent;
diff --git a/clang/lib/CIR/CodeGen/CIRGenExpr.cpp b/clang/lib/CIR/CodeGen/CIRGenExpr.cpp
index 37f2d030024df..65c218f0f78c7 100644
--- a/clang/lib/CIR/CodeGen/CIRGenExpr.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenExpr.cpp
@@ -676,7 +676,7 @@ mlir::Value CIRGenFunction::emitLoadOfScalar(Address addr, bool isVolatile,
assert(!cir::MissingFeatures::opLoadStoreTbaa());
LValue atomicLValue = LValue::makeAddr(addr, ty, baseInfo);
if (ty->isAtomicType() || isLValueSuitableForInlineAtomic(atomicLValue))
- cgm.errorNYI("emitLoadOfScalar: load atomic");
+ return emitAtomicLoad(atomicLValue, loc).getValue();
if (mlir::isa<cir::VoidType>(eltTy))
cgm.errorNYI(loc, "emitLoadOfScalar: void type");
diff --git a/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp b/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp
index 9c03279352357..aef3decf4d2ae 100644
--- a/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp
@@ -2225,12 +2225,7 @@ mlir::Value ScalarExprEmitter::VisitCastExpr(CastExpr *ce) {
return cgf.performAddrSpaceCast(Visit(subExpr), convertType(destTy));
}
- case CK_AtomicToNonAtomic: {
- cgf.getCIRGenModule().errorNYI(subExpr->getSourceRange(),
- "CastExpr: ", ce->getCastKindName());
- mlir::Location loc = cgf.getLoc(subExpr->getSourceRange());
- return cgf.createDummyValue(loc, destTy);
- }
+ case CK_AtomicToNonAtomic:
case CK_NonAtomicToAtomic:
case CK_UserDefinedConversion:
return Visit(const_cast<Expr *>(subExpr));
diff --git a/clang/lib/CIR/CodeGen/CIRGenFunction.h b/clang/lib/CIR/CodeGen/CIRGenFunction.h
index c5106caa52cb2..f3eb5982c041f 100644
--- a/clang/lib/CIR/CodeGen/CIRGenFunction.h
+++ b/clang/lib/CIR/CodeGen/CIRGenFunction.h
@@ -546,6 +546,12 @@ class CIRGenFunction : public CIRGenTypeCache {
bool isLValueSuitableForInlineAtomic(LValue lv);
+ RValue emitAtomicLoad(LValue lvalue, SourceLocation loc,
+ AggValueSlot slot = AggValueSlot::ignored());
+ RValue emitAtomicLoad(LValue lvalue, SourceLocation loc, cir::MemOrder order,
+ bool isVolatile = false,
+ AggValueSlot slot = AggValueSlot::ignored());
+
/// An abstract representation of regular/ObjC call/message targets.
class AbstractCallee {
/// The function declaration of the callee.
diff --git a/clang/test/CIR/CodeGen/atomic.c b/clang/test/CIR/CodeGen/atomic.c
index 50ed62cc9d7d1..abce1166cf9a2 100644
--- a/clang/test/CIR/CodeGen/atomic.c
+++ b/clang/test/CIR/CodeGen/atomic.c
@@ -72,6 +72,22 @@ void f4(_Atomic(float) *p) {
// OGCG-LABEL: @f4
// OGCG: store atomic float 0x40091EB860000000, ptr %{{.+}} seq_cst, align 4
+void atomic_to_non_atomic(_Atomic int *ptr, _Atomic volatile int *vptr) {
+ // CIR-LABEL: @atomic_to_non_atomic
+ // LLVM-LABEL: @atomic_to_non_atomic
+ // OGCG-LABEL: @atomic_to_non_atomic
+
+ int a = *ptr;
+ // CIR: %{{.+}} = cir.load align(4) atomic(seq_cst) %{{.+}} : !cir.ptr<!s32i>, !s32i
+ // LLVM: %{{.+}} = load atomic i32, ptr %{{.+}} seq_cst, align 4
+ // OGCG: %{{.+}} = load atomic i32, ptr %{{.+}} seq_cst, align 4
+
+ int b = *vptr;
+ // CIR: %{{.+}} = cir.load volatile align(4) atomic(seq_cst) %{{.+}} : !cir.ptr<!s32i>, !s32i
+ // LLVM: %{{.+}} = load atomic volatile i32, ptr %{{.+}} seq_cst, align 4
+ // OGCG: %{{.+}} = load atomic volatile i32, ptr %{{.+}} seq_cst, align 4
+}
+
void load(int *ptr) {
int x;
__atomic_load(ptr, &x, __ATOMIC_RELAXED);
More information about the cfe-commits
mailing list