Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions clang/include/clang/CIR/MissingFeatures.h
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,8 @@ struct MissingFeatures {
static bool atomicSyncScopeID() { return false; }
static bool atomicTypes() { return false; }
static bool atomicUseLibCall() { return false; }
static bool atomicMicrosoftVolatile() { return false; }
static bool atomicOpenMP() { return false; }

// Global ctor handling
static bool globalCtorLexOrder() { return false; }
Expand Down
121 changes: 118 additions & 3 deletions clang/lib/CIR/CodeGen/CIRGenAtomic.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ class AtomicInfo {
CharUnits atomicAlign;
CharUnits valueAlign;
TypeEvaluationKind evaluationKind = cir::TEK_Scalar;
bool useLibCall = true;
LValue lvalue;
mlir::Location loc;

Expand Down Expand Up @@ -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; }
Expand All @@ -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()) {
Expand All @@ -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;
Expand All @@ -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;

Expand Down Expand Up @@ -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.
Expand All @@ -211,10 +225,38 @@ bool AtomicInfo::emitMemSetZeroIfNecessary() const {
return false;

cgf.cgm.errorNYI(loc,
"AtomicInfo::emitMemSetZeroIfNecessary: emit memset zero");
"AtomicInfo::emitMemSetZeroIfNecaessary: emit memset zero");
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 {
Expand Down Expand Up @@ -815,6 +857,79 @@ RValue CIRGenFunction::emitAtomicExpr(AtomicExpr *e) {
e->getExprLoc());
}

void CIRGenFunction::emitAtomicStore(RValue rvalue, LValue dest, bool isInit) {
bool isVolatile = dest.isVolatileQualified();
auto order = cir::MemOrder::SequentiallyConsistent;
if (!dest.getType()->isAtomicType()) {
assert(!cir::MissingFeatures::atomicMicrosoftVolatile());
}
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.
mlir::Location loc = dest.getPointer().getLoc();
assert(!rvalue.isAggregate() ||
rvalue.getAggregateAddress().getElementType() ==
dest.getAddress().getElementType());

AtomicInfo atomics(*this, dest, loc);
LValue lvalue = atomics.getAtomicLValue();

if (lvalue.isSimple()) {
// If this is an initialization, just put the value there normally.
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) {
assert(!cir::MissingFeatures::atomicOpenMP());
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()));

Expand Down
14 changes: 11 additions & 3 deletions clang/lib/CIR/CodeGen/CIRGenExpr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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>()) {
Expand All @@ -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");
Expand Down Expand Up @@ -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,
Expand Down
7 changes: 5 additions & 2 deletions clang/lib/CIR/CodeGen/CIRGenFunction.h
Original file line number Diff line number Diff line change
Expand Up @@ -1271,6 +1271,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 = {});
Expand Down Expand Up @@ -1679,8 +1682,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
Expand Down
26 changes: 26 additions & 0 deletions clang/test/CIR/CodeGen/atomic.c
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,32 @@ 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 f4(_Atomic(float) *p) {
*p = 3.14;
}

// CIR-LABEL: @f4
// CIR: cir.store align(4) atomic(seq_cst) %{{.+}}, %{{.+}} : !cir.float, !cir.ptr<!cir.float>

// LLVM-LABEL: @f4
// LLVM: store atomic float 0x40091EB860000000, ptr %{{.+}} seq_cst, align 4

// OGCG-LABEL: @f4
// OGCG: store atomic float 0x40091EB860000000, ptr %{{.+}} seq_cst, align 4

void load(int *ptr) {
int x;
__atomic_load(ptr, &x, __ATOMIC_RELAXED);
Expand Down