-
Notifications
You must be signed in to change notification settings - Fork 15.1k
[CIR] Add support for storing into _Atomic variables #165872
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
Merged
Merged
+162
−8
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Member
|
@llvm/pr-subscribers-clangir @llvm/pr-subscribers-clang Author: Sirui Mu (Lancern) ChangesThis patch adds support for storing values into lvalues of Full diff: https://github.com/llvm/llvm-project/pull/165872.diff 4 Files Affected:
diff --git a/clang/lib/CIR/CodeGen/CIRGenAtomic.cpp b/clang/lib/CIR/CodeGen/CIRGenAtomic.cpp
index 7db6e283ec0a5..5e4032e09bfcb 100644
--- a/clang/lib/CIR/CodeGen/CIRGenAtomic.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenAtomic.cpp
@@ -27,6 +27,7 @@ class AtomicInfo {
CharUnits atomicAlign;
CharUnits valueAlign;
TypeEvaluationKind evaluationKind = cir::TEK_Scalar;
+ bool useLibCall = true;
LValue lvalue;
mlir::Location loc;
@@ -62,8 +63,8 @@ class AtomicInfo {
assert(!cir::MissingFeatures::atomicInfo());
cgf.cgm.errorNYI(loc, "AtomicInfo: non-simple lvalue");
}
-
- assert(!cir::MissingFeatures::atomicUseLibCall());
+ useLibCall = !ctx.getTargetInfo().hasBuiltinAtomic(
+ atomicSizeInBits, ctx.toBits(lvalue.getAlignment()));
}
QualType getValueType() const { return valueTy; }
@@ -75,6 +76,8 @@ class AtomicInfo {
assert(!cir::MissingFeatures::atomicInfoGetAtomicPointer());
return nullptr;
}
+ bool shouldUseLibCall() const { return useLibCall; }
+ const LValue &getAtomicLValue() const { return lvalue; }
Address getAtomicAddress() const {
mlir::Type elemTy;
if (lvalue.isSimple()) {
@@ -96,6 +99,8 @@ class AtomicInfo {
bool emitMemSetZeroIfNecessary() const;
+ mlir::Value getScalarRValValueOrNull(RValue rvalue) const;
+
/// Cast the given pointer to an integer pointer suitable for atomic
/// operations on the source.
Address castToAtomicIntPointer(Address addr) const;
@@ -105,6 +110,9 @@ class AtomicInfo {
/// copy the value across.
Address convertToAtomicIntPointer(Address addr) const;
+ /// Converts a rvalue to integer value.
+ mlir::Value convertRValueToInt(RValue rvalue, bool cmpxchg = false) const;
+
/// Copy an atomic r-value into atomic-layout memory.
void emitCopyIntoMemory(RValue rvalue) const;
@@ -195,6 +203,12 @@ Address AtomicInfo::createTempAlloca() const {
return tempAlloca;
}
+mlir::Value AtomicInfo::getScalarRValValueOrNull(RValue rvalue) const {
+ if (rvalue.isScalar() && (!hasPadding() || !lvalue.isSimple()))
+ return rvalue.getValue();
+ return nullptr;
+}
+
Address AtomicInfo::castToAtomicIntPointer(Address addr) const {
auto intTy = mlir::dyn_cast<cir::IntType>(addr.getElementType());
// Don't bother with int casts if the integer size is the same.
@@ -215,6 +229,34 @@ bool AtomicInfo::emitMemSetZeroIfNecessary() const {
return false;
}
+/// Return true if \param valueTy is a type that should be casted to integer
+/// around the atomic memory operation. If \param cmpxchg is true, then the
+/// cast of a floating point type is made as that instruction can not have
+/// floating point operands. TODO: Allow compare-and-exchange and FP - see
+/// comment in CIRGenAtomicExpandPass.cpp.
+static bool shouldCastToInt(mlir::Type valueTy, bool cmpxchg) {
+ if (cir::isAnyFloatingPointType(valueTy))
+ return isa<cir::FP80Type>(valueTy) || cmpxchg;
+ return !isa<cir::IntType>(valueTy) && !isa<cir::PointerType>(valueTy);
+}
+
+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.
+ if (mlir::Value value = getScalarRValValueOrNull(rvalue)) {
+ if (!shouldCastToInt(value.getType(), cmpxchg))
+ return cgf.emitToMemory(value, valueTy);
+
+ cgf.cgm.errorNYI(
+ loc, "AtomicInfo::convertRValueToInt: cast scalar rvalue to int");
+ return nullptr;
+ }
+
+ cgf.cgm.errorNYI(
+ loc, "AtomicInfo::convertRValueToInt: cast non-scalar rvalue to int");
+ return 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 {
@@ -815,6 +857,85 @@ RValue CIRGenFunction::emitAtomicExpr(AtomicExpr *e) {
e->getExprLoc());
}
+void CIRGenFunction::emitAtomicStore(RValue rvalue, LValue dest, bool isInit) {
+ bool isVolatile = dest.isVolatileQualified();
+ cir::MemOrder order;
+ if (dest.getType()->isAtomicType()) {
+ order = cir::MemOrder::SequentiallyConsistent;
+ } else {
+ order = cir::MemOrder::Release;
+ isVolatile = true;
+ }
+ return emitAtomicStore(rvalue, dest, order, isVolatile, isInit);
+}
+
+/// Emit a store to an l-value of atomic type.
+///
+/// Note that the r-value is expected to be an r-value of the atomic type; this
+/// means that for aggregate r-values, it should include storage for any padding
+/// that was necessary.
+void CIRGenFunction::emitAtomicStore(RValue rvalue, LValue dest,
+ cir::MemOrder order, bool isVolatile,
+ bool isInit) {
+ // If this is an aggregate r-value, it should agree in type except
+ // maybe for address-space qualification.
+ auto loc = dest.getPointer().getLoc();
+ assert(!rvalue.isAggregate() ||
+ rvalue.getAggregateAddress().getElementType() ==
+ dest.getAddress().getElementType());
+
+ AtomicInfo atomics(*this, dest, loc);
+ LValue lvalue = atomics.getAtomicLValue();
+
+ // If this is an initialization, just put the value there normally.
+ if (lvalue.isSimple()) {
+ if (isInit) {
+ atomics.emitCopyIntoMemory(rvalue);
+ return;
+ }
+
+ // Check whether we should use a library call.
+ if (atomics.shouldUseLibCall()) {
+ assert(!cir::MissingFeatures::atomicUseLibCall());
+ cgm.errorNYI(loc, "emitAtomicStore: atomic store with library call");
+ return;
+ }
+
+ // Okay, we're doing this natively.
+ mlir::Value valueToStore = atomics.convertRValueToInt(rvalue);
+
+ // Do the atomic store.
+ Address addr = atomics.getAtomicAddress();
+ if (mlir::Value value = atomics.getScalarRValValueOrNull(rvalue)) {
+ if (shouldCastToInt(value.getType(), /*CmpXchg=*/false)) {
+ addr = atomics.castToAtomicIntPointer(addr);
+ valueToStore =
+ builder.createIntCast(valueToStore, addr.getElementType());
+ }
+ }
+ cir::StoreOp store = builder.createStore(loc, valueToStore, addr);
+
+ // Initializations don't need to be atomic.
+ if (!isInit) {
+ if (order == cir::MemOrder::Acquire)
+ order = cir::MemOrder::Relaxed; // Monotonic
+ else if (order == cir::MemOrder::AcquireRelease)
+ order = cir::MemOrder::Release;
+ store.setMemOrder(order);
+ }
+
+ // Other decoration.
+ if (isVolatile)
+ store.setIsVolatile(true);
+
+ assert(!cir::MissingFeatures::opLoadStoreTbaa());
+ return;
+ }
+
+ cgm.errorNYI(loc, "emitAtomicStore: non-simple atomic lvalue");
+ assert(!cir::MissingFeatures::opLoadStoreAtomic());
+}
+
void CIRGenFunction::emitAtomicInit(Expr *init, LValue dest) {
AtomicInfo atomics(*this, dest, getLoc(init->getSourceRange()));
diff --git a/clang/lib/CIR/CodeGen/CIRGenExpr.cpp b/clang/lib/CIR/CodeGen/CIRGenExpr.cpp
index 5ccb431e626ae..bb3b895f7f17f 100644
--- a/clang/lib/CIR/CodeGen/CIRGenExpr.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenExpr.cpp
@@ -311,7 +311,8 @@ static LValue emitGlobalVarDeclLValue(CIRGenFunction &cgf, const Expr *e,
void CIRGenFunction::emitStoreOfScalar(mlir::Value value, Address addr,
bool isVolatile, QualType ty,
- bool isInit, bool isNontemporal) {
+ LValueBaseInfo baseInfo, bool isInit,
+ bool isNontemporal) {
assert(!cir::MissingFeatures::opLoadStoreThreadLocal());
if (const auto *clangVecTy = ty->getAs<clang::VectorType>()) {
@@ -333,7 +334,13 @@ void CIRGenFunction::emitStoreOfScalar(mlir::Value value, Address addr,
value = emitToMemory(value, ty);
- assert(!cir::MissingFeatures::opLoadStoreAtomic());
+ assert(!cir::MissingFeatures::opLoadStoreTbaa());
+ LValue atomicLValue = LValue::makeAddr(addr, ty, baseInfo);
+ if (ty->isAtomicType() ||
+ (!isInit && isLValueSuitableForInlineAtomic(atomicLValue))) {
+ emitAtomicStore(RValue::get(value), atomicLValue, isInit);
+ return;
+ }
// Update the alloca with more info on initialization.
assert(addr.getPointer() && "expected pointer to exist");
@@ -550,7 +557,8 @@ void CIRGenFunction::emitStoreOfScalar(mlir::Value value, LValue lvalue,
}
emitStoreOfScalar(value, lvalue.getAddress(), lvalue.isVolatile(),
- lvalue.getType(), isInit, /*isNontemporal=*/false);
+ lvalue.getType(), lvalue.getBaseInfo(), isInit,
+ /*isNontemporal=*/false);
}
mlir::Value CIRGenFunction::emitLoadOfScalar(Address addr, bool isVolatile,
diff --git a/clang/lib/CIR/CodeGen/CIRGenFunction.h b/clang/lib/CIR/CodeGen/CIRGenFunction.h
index c3fcd1a69a88e..ad5e3af8f7a5e 100644
--- a/clang/lib/CIR/CodeGen/CIRGenFunction.h
+++ b/clang/lib/CIR/CodeGen/CIRGenFunction.h
@@ -1246,6 +1246,9 @@ class CIRGenFunction : public CIRGenTypeCache {
RValue emitAtomicExpr(AtomicExpr *e);
void emitAtomicInit(Expr *init, LValue dest);
+ void emitAtomicStore(RValue rvalue, LValue dest, bool isInit);
+ void emitAtomicStore(RValue rvalue, LValue dest, cir::MemOrder order,
+ bool isVolatile, bool isInit);
AutoVarEmission emitAutoVarAlloca(const clang::VarDecl &d,
mlir::OpBuilder::InsertPoint ip = {});
@@ -1654,8 +1657,8 @@ class CIRGenFunction : public CIRGenTypeCache {
bool isInit);
void emitStoreOfScalar(mlir::Value value, Address addr, bool isVolatile,
- clang::QualType ty, bool isInit = false,
- bool isNontemporal = false);
+ clang::QualType ty, LValueBaseInfo baseInfo,
+ bool isInit = false, bool isNontemporal = false);
void emitStoreOfScalar(mlir::Value value, LValue lvalue, bool isInit);
/// Store the specified rvalue into the specified
diff --git a/clang/test/CIR/CodeGen/atomic.c b/clang/test/CIR/CodeGen/atomic.c
index 65799881a0cbe..7e819596f1bab 100644
--- a/clang/test/CIR/CodeGen/atomic.c
+++ b/clang/test/CIR/CodeGen/atomic.c
@@ -46,6 +46,19 @@ void f2(void) {
// OGCG-NEXT: store i32 42, ptr %[[SLOT]], align 4
// OGCG: }
+void f3(_Atomic(int) *p) {
+ *p = 42;
+}
+
+// CIR-LABEL: @f3
+// CIR: cir.store align(4) atomic(seq_cst) %{{.+}}, %{{.+}} : !s32i, !cir.ptr<!s32i>
+
+// LLVM-LABEL: @f3
+// LLVM: store atomic i32 42, ptr %{{.+}} seq_cst, align 4
+
+// OGCG-LABEL: @f3
+// OGCG: store atomic i32 42, ptr %{{.+}} seq_cst, align 4
+
void load(int *ptr) {
int x;
__atomic_load(ptr, &x, __ATOMIC_RELAXED);
|
120fb44 to
33ae461
Compare
andykaylor
approved these changes
Nov 3, 2025
Contributor
andykaylor
left a comment
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 good, just a nit and a test request
33ae461 to
97656c2
Compare
bcardosolopes
approved these changes
Nov 4, 2025
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
This patch adds support for storing values into lvalues of
_Atomictypes.