Skip to content

Commit 33ae461

Browse files
committed
[CIR] Add support for storing into _Atomic variables
1 parent 2837a4b commit 33ae461

File tree

4 files changed

+152
-7
lines changed

4 files changed

+152
-7
lines changed

clang/lib/CIR/CodeGen/CIRGenAtomic.cpp

Lines changed: 123 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ class AtomicInfo {
2727
CharUnits atomicAlign;
2828
CharUnits valueAlign;
2929
TypeEvaluationKind evaluationKind = cir::TEK_Scalar;
30+
bool useLibCall = true;
3031
LValue lvalue;
3132
mlir::Location loc;
3233

@@ -62,8 +63,8 @@ class AtomicInfo {
6263
assert(!cir::MissingFeatures::atomicInfo());
6364
cgf.cgm.errorNYI(loc, "AtomicInfo: non-simple lvalue");
6465
}
65-
66-
assert(!cir::MissingFeatures::atomicUseLibCall());
66+
useLibCall = !ctx.getTargetInfo().hasBuiltinAtomic(
67+
atomicSizeInBits, ctx.toBits(lvalue.getAlignment()));
6768
}
6869

6970
QualType getValueType() const { return valueTy; }
@@ -75,6 +76,8 @@ class AtomicInfo {
7576
assert(!cir::MissingFeatures::atomicInfoGetAtomicPointer());
7677
return nullptr;
7778
}
79+
bool shouldUseLibCall() const { return useLibCall; }
80+
const LValue &getAtomicLValue() const { return lvalue; }
7881
Address getAtomicAddress() const {
7982
mlir::Type elemTy;
8083
if (lvalue.isSimple()) {
@@ -96,6 +99,8 @@ class AtomicInfo {
9699

97100
bool emitMemSetZeroIfNecessary() const;
98101

102+
mlir::Value getScalarRValValueOrNull(RValue rvalue) const;
103+
99104
/// Cast the given pointer to an integer pointer suitable for atomic
100105
/// operations on the source.
101106
Address castToAtomicIntPointer(Address addr) const;
@@ -105,6 +110,9 @@ class AtomicInfo {
105110
/// copy the value across.
106111
Address convertToAtomicIntPointer(Address addr) const;
107112

113+
/// Converts a rvalue to integer value.
114+
mlir::Value convertRValueToInt(RValue rvalue, bool cmpxchg = false) const;
115+
108116
/// Copy an atomic r-value into atomic-layout memory.
109117
void emitCopyIntoMemory(RValue rvalue) const;
110118

@@ -195,6 +203,12 @@ Address AtomicInfo::createTempAlloca() const {
195203
return tempAlloca;
196204
}
197205

206+
mlir::Value AtomicInfo::getScalarRValValueOrNull(RValue rvalue) const {
207+
if (rvalue.isScalar() && (!hasPadding() || !lvalue.isSimple()))
208+
return rvalue.getValue();
209+
return nullptr;
210+
}
211+
198212
Address AtomicInfo::castToAtomicIntPointer(Address addr) const {
199213
auto intTy = mlir::dyn_cast<cir::IntType>(addr.getElementType());
200214
// Don't bother with int casts if the integer size is the same.
@@ -215,6 +229,34 @@ bool AtomicInfo::emitMemSetZeroIfNecessary() const {
215229
return false;
216230
}
217231

232+
/// Return true if \param valueTy is a type that should be casted to integer
233+
/// around the atomic memory operation. If \param cmpxchg is true, then the
234+
/// cast of a floating point type is made as that instruction can not have
235+
/// floating point operands. TODO: Allow compare-and-exchange and FP - see
236+
/// comment in CIRGenAtomicExpandPass.cpp.
237+
static bool shouldCastToInt(mlir::Type valueTy, bool cmpxchg) {
238+
if (cir::isAnyFloatingPointType(valueTy))
239+
return isa<cir::FP80Type>(valueTy) || cmpxchg;
240+
return !isa<cir::IntType>(valueTy) && !isa<cir::PointerType>(valueTy);
241+
}
242+
243+
mlir::Value AtomicInfo::convertRValueToInt(RValue rvalue, bool cmpxchg) const {
244+
// If we've got a scalar value of the right size, try to avoid going
245+
// through memory. Floats get casted if needed by AtomicExpandPass.
246+
if (mlir::Value value = getScalarRValValueOrNull(rvalue)) {
247+
if (!shouldCastToInt(value.getType(), cmpxchg))
248+
return cgf.emitToMemory(value, valueTy);
249+
250+
cgf.cgm.errorNYI(
251+
loc, "AtomicInfo::convertRValueToInt: cast scalar rvalue to int");
252+
return nullptr;
253+
}
254+
255+
cgf.cgm.errorNYI(
256+
loc, "AtomicInfo::convertRValueToInt: cast non-scalar rvalue to int");
257+
return nullptr;
258+
}
259+
218260
/// Copy an r-value into memory as part of storing to an atomic type.
219261
/// This needs to create a bit-pattern suitable for atomic operations.
220262
void AtomicInfo::emitCopyIntoMemory(RValue rvalue) const {
@@ -815,6 +857,85 @@ RValue CIRGenFunction::emitAtomicExpr(AtomicExpr *e) {
815857
e->getExprLoc());
816858
}
817859

860+
void CIRGenFunction::emitAtomicStore(RValue rvalue, LValue dest, bool isInit) {
861+
bool isVolatile = dest.isVolatileQualified();
862+
cir::MemOrder order;
863+
if (dest.getType()->isAtomicType()) {
864+
order = cir::MemOrder::SequentiallyConsistent;
865+
} else {
866+
order = cir::MemOrder::Release;
867+
isVolatile = true;
868+
}
869+
return emitAtomicStore(rvalue, dest, order, isVolatile, isInit);
870+
}
871+
872+
/// Emit a store to an l-value of atomic type.
873+
///
874+
/// Note that the r-value is expected to be an r-value of the atomic type; this
875+
/// means that for aggregate r-values, it should include storage for any padding
876+
/// that was necessary.
877+
void CIRGenFunction::emitAtomicStore(RValue rvalue, LValue dest,
878+
cir::MemOrder order, bool isVolatile,
879+
bool isInit) {
880+
// If this is an aggregate r-value, it should agree in type except
881+
// maybe for address-space qualification.
882+
auto loc = dest.getPointer().getLoc();
883+
assert(!rvalue.isAggregate() ||
884+
rvalue.getAggregateAddress().getElementType() ==
885+
dest.getAddress().getElementType());
886+
887+
AtomicInfo atomics(*this, dest, loc);
888+
LValue lvalue = atomics.getAtomicLValue();
889+
890+
// If this is an initialization, just put the value there normally.
891+
if (lvalue.isSimple()) {
892+
if (isInit) {
893+
atomics.emitCopyIntoMemory(rvalue);
894+
return;
895+
}
896+
897+
// Check whether we should use a library call.
898+
if (atomics.shouldUseLibCall()) {
899+
assert(!cir::MissingFeatures::atomicUseLibCall());
900+
cgm.errorNYI(loc, "emitAtomicStore: atomic store with library call");
901+
return;
902+
}
903+
904+
// Okay, we're doing this natively.
905+
mlir::Value valueToStore = atomics.convertRValueToInt(rvalue);
906+
907+
// Do the atomic store.
908+
Address addr = atomics.getAtomicAddress();
909+
if (mlir::Value value = atomics.getScalarRValValueOrNull(rvalue)) {
910+
if (shouldCastToInt(value.getType(), /*CmpXchg=*/false)) {
911+
addr = atomics.castToAtomicIntPointer(addr);
912+
valueToStore =
913+
builder.createIntCast(valueToStore, addr.getElementType());
914+
}
915+
}
916+
cir::StoreOp store = builder.createStore(loc, valueToStore, addr);
917+
918+
// Initializations don't need to be atomic.
919+
if (!isInit) {
920+
if (order == cir::MemOrder::Acquire)
921+
order = cir::MemOrder::Relaxed; // Monotonic
922+
else if (order == cir::MemOrder::AcquireRelease)
923+
order = cir::MemOrder::Release;
924+
store.setMemOrder(order);
925+
}
926+
927+
// Other decoration.
928+
if (isVolatile)
929+
store.setIsVolatile(true);
930+
931+
assert(!cir::MissingFeatures::opLoadStoreTbaa());
932+
return;
933+
}
934+
935+
cgm.errorNYI(loc, "emitAtomicStore: non-simple atomic lvalue");
936+
assert(!cir::MissingFeatures::opLoadStoreAtomic());
937+
}
938+
818939
void CIRGenFunction::emitAtomicInit(Expr *init, LValue dest) {
819940
AtomicInfo atomics(*this, dest, getLoc(init->getSourceRange()));
820941

clang/lib/CIR/CodeGen/CIRGenExpr.cpp

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -311,7 +311,8 @@ static LValue emitGlobalVarDeclLValue(CIRGenFunction &cgf, const Expr *e,
311311

312312
void CIRGenFunction::emitStoreOfScalar(mlir::Value value, Address addr,
313313
bool isVolatile, QualType ty,
314-
bool isInit, bool isNontemporal) {
314+
LValueBaseInfo baseInfo, bool isInit,
315+
bool isNontemporal) {
315316
assert(!cir::MissingFeatures::opLoadStoreThreadLocal());
316317

317318
if (const auto *clangVecTy = ty->getAs<clang::VectorType>()) {
@@ -333,7 +334,13 @@ void CIRGenFunction::emitStoreOfScalar(mlir::Value value, Address addr,
333334

334335
value = emitToMemory(value, ty);
335336

336-
assert(!cir::MissingFeatures::opLoadStoreAtomic());
337+
assert(!cir::MissingFeatures::opLoadStoreTbaa());
338+
LValue atomicLValue = LValue::makeAddr(addr, ty, baseInfo);
339+
if (ty->isAtomicType() ||
340+
(!isInit && isLValueSuitableForInlineAtomic(atomicLValue))) {
341+
emitAtomicStore(RValue::get(value), atomicLValue, isInit);
342+
return;
343+
}
337344

338345
// Update the alloca with more info on initialization.
339346
assert(addr.getPointer() && "expected pointer to exist");
@@ -550,7 +557,8 @@ void CIRGenFunction::emitStoreOfScalar(mlir::Value value, LValue lvalue,
550557
}
551558

552559
emitStoreOfScalar(value, lvalue.getAddress(), lvalue.isVolatile(),
553-
lvalue.getType(), isInit, /*isNontemporal=*/false);
560+
lvalue.getType(), lvalue.getBaseInfo(), isInit,
561+
/*isNontemporal=*/false);
554562
}
555563

556564
mlir::Value CIRGenFunction::emitLoadOfScalar(Address addr, bool isVolatile,

clang/lib/CIR/CodeGen/CIRGenFunction.h

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1271,6 +1271,9 @@ class CIRGenFunction : public CIRGenTypeCache {
12711271

12721272
RValue emitAtomicExpr(AtomicExpr *e);
12731273
void emitAtomicInit(Expr *init, LValue dest);
1274+
void emitAtomicStore(RValue rvalue, LValue dest, bool isInit);
1275+
void emitAtomicStore(RValue rvalue, LValue dest, cir::MemOrder order,
1276+
bool isVolatile, bool isInit);
12741277

12751278
AutoVarEmission emitAutoVarAlloca(const clang::VarDecl &d,
12761279
mlir::OpBuilder::InsertPoint ip = {});
@@ -1679,8 +1682,8 @@ class CIRGenFunction : public CIRGenTypeCache {
16791682
bool isInit);
16801683

16811684
void emitStoreOfScalar(mlir::Value value, Address addr, bool isVolatile,
1682-
clang::QualType ty, bool isInit = false,
1683-
bool isNontemporal = false);
1685+
clang::QualType ty, LValueBaseInfo baseInfo,
1686+
bool isInit = false, bool isNontemporal = false);
16841687
void emitStoreOfScalar(mlir::Value value, LValue lvalue, bool isInit);
16851688

16861689
/// Store the specified rvalue into the specified

clang/test/CIR/CodeGen/atomic.c

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,19 @@ void f2(void) {
4646
// OGCG-NEXT: store i32 42, ptr %[[SLOT]], align 4
4747
// OGCG: }
4848

49+
void f3(_Atomic(int) *p) {
50+
*p = 42;
51+
}
52+
53+
// CIR-LABEL: @f3
54+
// CIR: cir.store align(4) atomic(seq_cst) %{{.+}}, %{{.+}} : !s32i, !cir.ptr<!s32i>
55+
56+
// LLVM-LABEL: @f3
57+
// LLVM: store atomic i32 42, ptr %{{.+}} seq_cst, align 4
58+
59+
// OGCG-LABEL: @f3
60+
// OGCG: store atomic i32 42, ptr %{{.+}} seq_cst, align 4
61+
4962
void load(int *ptr) {
5063
int x;
5164
__atomic_load(ptr, &x, __ATOMIC_RELAXED);

0 commit comments

Comments
 (0)