summaryrefslogtreecommitdiffstats
path: root/clang/lib/CodeGen/CGAtomic.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'clang/lib/CodeGen/CGAtomic.cpp')
-rw-r--r--clang/lib/CodeGen/CGAtomic.cpp144
1 files changed, 103 insertions, 41 deletions
diff --git a/clang/lib/CodeGen/CGAtomic.cpp b/clang/lib/CodeGen/CGAtomic.cpp
index b7222fc1cd6..d51c4fdb596 100644
--- a/clang/lib/CodeGen/CGAtomic.cpp
+++ b/clang/lib/CodeGen/CGAtomic.cpp
@@ -209,7 +209,7 @@ namespace {
/// \param IsWeak true if atomic operation is weak, false otherwise.
/// \returns Pair of values: previous value from storage (value type) and
/// boolean flag (i1 type) with true if success and false otherwise.
- std::pair<llvm::Value *, llvm::Value *> EmitAtomicCompareExchange(
+ std::pair<RValue, llvm::Value *> EmitAtomicCompareExchange(
RValue Expected, RValue Desired,
llvm::AtomicOrdering Success = llvm::SequentiallyConsistent,
llvm::AtomicOrdering Failure = llvm::SequentiallyConsistent,
@@ -235,13 +235,13 @@ namespace {
/// \brief Emits atomic load as LLVM instruction.
llvm::Value *EmitAtomicLoadOp(llvm::AtomicOrdering AO, bool IsVolatile);
/// \brief Emits atomic compare-and-exchange op as a libcall.
- std::pair<llvm::Value *, llvm::Value *> EmitAtomicCompareExchangeLibcall(
- llvm::Value *ExpectedAddr, llvm::Value *DesiredAddr,
+ std::pair<RValue, llvm::Value *> EmitAtomicCompareExchangeLibcall(
+ RValue Expected, RValue DesiredAddr,
llvm::AtomicOrdering Success = llvm::SequentiallyConsistent,
llvm::AtomicOrdering Failure = llvm::SequentiallyConsistent);
/// \brief Emits atomic compare-and-exchange op as LLVM instruction.
- std::pair<llvm::Value *, llvm::Value *> EmitAtomicCompareExchangeOp(
- llvm::Value *Expected, llvm::Value *Desired,
+ std::pair<RValue, llvm::Value *> EmitAtomicCompareExchangeOp(
+ RValue Expected, RValue Desired,
llvm::AtomicOrdering Success = llvm::SequentiallyConsistent,
llvm::AtomicOrdering Failure = llvm::SequentiallyConsistent,
bool IsWeak = false);
@@ -1291,7 +1291,7 @@ llvm::Value *AtomicInfo::convertRValueToInt(RValue RVal) const {
if (RVal.isScalar() && (!hasPadding() || !LVal.isSimple())) {
llvm::Value *Value = RVal.getScalarVal();
if (isa<llvm::IntegerType>(Value->getType()))
- return Value;
+ return CGF.EmitToMemory(Value, ValueTy);
else {
llvm::IntegerType *InputIntTy = llvm::IntegerType::get(
CGF.getLLVMContext(),
@@ -1312,13 +1312,15 @@ llvm::Value *AtomicInfo::convertRValueToInt(RValue RVal) const {
getAtomicAlignment().getQuantity());
}
-std::pair<llvm::Value *, llvm::Value *> AtomicInfo::EmitAtomicCompareExchangeOp(
- llvm::Value *Expected, llvm::Value *Desired, llvm::AtomicOrdering Success,
+std::pair<RValue, llvm::Value *> AtomicInfo::EmitAtomicCompareExchangeOp(
+ RValue Expected, RValue Desired, llvm::AtomicOrdering Success,
llvm::AtomicOrdering Failure, bool IsWeak) {
// Do the atomic store.
+ auto *ExpectedVal = convertRValueToInt(Expected);
+ auto *DesiredVal = convertRValueToInt(Desired);
auto *Addr = emitCastToAtomicIntPointer(getAtomicAddress());
- auto *Inst = CGF.Builder.CreateAtomicCmpXchg(Addr, Expected, Desired, Success,
- Failure);
+ auto *Inst = CGF.Builder.CreateAtomicCmpXchg(Addr, ExpectedVal, DesiredVal,
+ Success, Failure);
// Other decoration.
Inst->setVolatile(LVal.isVolatileQualified());
Inst->setWeak(IsWeak);
@@ -1326,16 +1328,20 @@ std::pair<llvm::Value *, llvm::Value *> AtomicInfo::EmitAtomicCompareExchangeOp(
// Okay, turn that back into the original value type.
auto *PreviousVal = CGF.Builder.CreateExtractValue(Inst, /*Idxs=*/0);
auto *SuccessFailureVal = CGF.Builder.CreateExtractValue(Inst, /*Idxs=*/1);
- return std::make_pair(PreviousVal, SuccessFailureVal);
+ return std::make_pair(
+ ConvertIntToValueOrAtomic(PreviousVal, AggValueSlot::ignored(),
+ SourceLocation(), /*AsValue=*/false),
+ SuccessFailureVal);
}
-std::pair<llvm::Value *, llvm::Value *>
-AtomicInfo::EmitAtomicCompareExchangeLibcall(llvm::Value *ExpectedAddr,
- llvm::Value *DesiredAddr,
+std::pair<RValue, llvm::Value *>
+AtomicInfo::EmitAtomicCompareExchangeLibcall(RValue Expected, RValue Desired,
llvm::AtomicOrdering Success,
llvm::AtomicOrdering Failure) {
// bool __atomic_compare_exchange(size_t size, void *obj, void *expected,
// void *desired, int success, int failure);
+ auto *ExpectedAddr = materializeRValue(Expected);
+ auto *DesiredAddr = materializeRValue(Desired);
CallArgList Args;
Args.add(RValue::get(getAtomicSizeValue()), CGF.getContext().getSizeType());
Args.add(RValue::get(CGF.EmitCastToVoidPtr(getAtomicAddress())),
@@ -1352,12 +1358,14 @@ AtomicInfo::EmitAtomicCompareExchangeLibcall(llvm::Value *ExpectedAddr,
CGF.getContext().IntTy);
auto SuccessFailureRVal = emitAtomicLibcall(CGF, "__atomic_compare_exchange",
CGF.getContext().BoolTy, Args);
- auto *PreviousVal = CGF.Builder.CreateAlignedLoad(
- ExpectedAddr, getValueAlignment().getQuantity());
- return std::make_pair(PreviousVal, SuccessFailureRVal.getScalarVal());
+
+ return std::make_pair(
+ convertTempToRValue(ExpectedAddr, AggValueSlot::ignored(),
+ SourceLocation(), /*AsValue=*/false),
+ SuccessFailureRVal.getScalarVal());
}
-std::pair<llvm::Value *, llvm::Value *> AtomicInfo::EmitAtomicCompareExchange(
+std::pair<RValue, llvm::Value *> AtomicInfo::EmitAtomicCompareExchange(
RValue Expected, RValue Desired, llvm::AtomicOrdering Success,
llvm::AtomicOrdering Failure, bool IsWeak) {
if (Failure >= Success)
@@ -1366,20 +1374,15 @@ std::pair<llvm::Value *, llvm::Value *> AtomicInfo::EmitAtomicCompareExchange(
// Check whether we should use a library call.
if (shouldUseLibcall()) {
- auto *ExpectedAddr = materializeRValue(Expected);
// Produce a source address.
- auto *DesiredAddr = materializeRValue(Desired);
- return EmitAtomicCompareExchangeLibcall(ExpectedAddr, DesiredAddr, Success,
+ return EmitAtomicCompareExchangeLibcall(Expected, Desired, Success,
Failure);
}
// If we've got a scalar value of the right size, try to avoid going
// through memory.
- auto *ExpectedIntVal = convertRValueToInt(Expected);
- auto *DesiredIntVal = convertRValueToInt(Desired);
-
- return EmitAtomicCompareExchangeOp(ExpectedIntVal, DesiredIntVal, Success,
- Failure, IsWeak);
+ return EmitAtomicCompareExchangeOp(Expected, Desired, Success, Failure,
+ IsWeak);
}
void CodeGenFunction::EmitAtomicStore(RValue rvalue, LValue lvalue,
@@ -1498,20 +1501,14 @@ void CodeGenFunction::EmitAtomicStore(RValue rvalue, LValue dest,
atomics.getAtomicType(), SourceLocation()));
// Try to write new value using cmpxchg operation
auto Pair = atomics.EmitAtomicCompareExchange(OriginalRValue, NewRValue, AO);
- llvm::Value *OldValue = Pair.first;
- if (!atomics.shouldUseLibcall())
- // Convert integer value to original atomic type
- OldValue = atomics.ConvertIntToValueOrAtomic(
- OldValue, AggValueSlot::ignored(), SourceLocation(),
- /*AsValue=*/false).getScalarVal();
- PHI->addIncoming(OldValue, ContBB);
+ PHI->addIncoming(Pair.first.getScalarVal(), ContBB);
Builder.CreateCondBr(Pair.second, ExitBB, ContBB);
EmitBlock(ExitBB, /*IsFinished=*/true);
}
/// Emit a compare-and-exchange op for atomic type.
///
-std::pair<RValue, RValue> CodeGenFunction::EmitAtomicCompareExchange(
+std::pair<RValue, llvm::Value *> CodeGenFunction::EmitAtomicCompareExchange(
LValue Obj, RValue Expected, RValue Desired, SourceLocation Loc,
llvm::AtomicOrdering Success, llvm::AtomicOrdering Failure, bool IsWeak,
AggValueSlot Slot) {
@@ -1525,13 +1522,78 @@ std::pair<RValue, RValue> CodeGenFunction::EmitAtomicCompareExchange(
Obj.getAddress()->getType()->getPointerElementType());
AtomicInfo Atomics(*this, Obj);
- auto Pair = Atomics.EmitAtomicCompareExchange(Expected, Desired, Success,
- Failure, IsWeak);
- return std::make_pair(Atomics.shouldUseLibcall()
- ? RValue::get(Pair.first)
- : Atomics.ConvertIntToValueOrAtomic(
- Pair.first, Slot, Loc, /*AsValue=*/true),
- RValue::get(Pair.second));
+ return Atomics.EmitAtomicCompareExchange(Expected, Desired, Success, Failure,
+ IsWeak);
+}
+
+void CodeGenFunction::EmitAtomicUpdate(
+ LValue LVal, llvm::AtomicOrdering AO,
+ const std::function<RValue(RValue)> &UpdateOp, bool IsVolatile) {
+ AtomicInfo Atomics(*this, LVal);
+ LValue AtomicLVal = Atomics.getAtomicLValue();
+
+ // Atomic load of prev value.
+ RValue OldRVal =
+ Atomics.EmitAtomicLoad(AggValueSlot::ignored(), SourceLocation(),
+ /*AsValue=*/false, AO, IsVolatile);
+ bool IsScalar = OldRVal.isScalar();
+ auto *OldVal =
+ IsScalar ? OldRVal.getScalarVal() : Atomics.convertRValueToInt(OldRVal);
+ // For non-simple lvalues perform compare-and-swap procedure.
+ auto *ContBB = createBasicBlock("atomic_cont");
+ auto *ExitBB = createBasicBlock("atomic_exit");
+ auto *CurBB = Builder.GetInsertBlock();
+ EmitBlock(ContBB);
+ llvm::PHINode *PHI = Builder.CreatePHI(OldVal->getType(),
+ /*NumReservedValues=*/2);
+ PHI->addIncoming(OldVal, CurBB);
+ RValue OriginalRValue =
+ IsScalar ? RValue::get(PHI) : Atomics.ConvertIntToValueOrAtomic(
+ PHI, AggValueSlot::ignored(),
+ SourceLocation(), /*AsValue=*/false);
+ // Build new lvalue for temp address
+ LValue UpdateLVal;
+ llvm::Value *Ptr = nullptr;
+ RValue UpRVal;
+ if (AtomicLVal.isSimple()) {
+ UpRVal = OriginalRValue;
+ } else {
+ // Build new lvalue for temp address
+ Ptr = Atomics.materializeRValue(OriginalRValue);
+ if (AtomicLVal.isBitField())
+ UpdateLVal =
+ LValue::MakeBitfield(Ptr, AtomicLVal.getBitFieldInfo(),
+ AtomicLVal.getType(), AtomicLVal.getAlignment());
+ else if (AtomicLVal.isVectorElt())
+ UpdateLVal = LValue::MakeVectorElt(Ptr, AtomicLVal.getVectorIdx(),
+ AtomicLVal.getType(),
+ AtomicLVal.getAlignment());
+ else {
+ assert(AtomicLVal.isExtVectorElt());
+ UpdateLVal = LValue::MakeExtVectorElt(Ptr, AtomicLVal.getExtVectorElts(),
+ AtomicLVal.getType(),
+ AtomicLVal.getAlignment());
+ }
+ UpdateLVal.setTBAAInfo(LVal.getTBAAInfo());
+ UpRVal = EmitLoadOfLValue(UpdateLVal, SourceLocation());
+ }
+ // Store new value in the corresponding memory area
+ RValue NewRVal = UpdateOp(UpRVal);
+ if (!AtomicLVal.isSimple()) {
+ EmitStoreThroughLValue(NewRVal, UpdateLVal);
+ // Load new value
+ NewRVal = RValue::get(
+ EmitLoadOfScalar(Ptr, AtomicLVal.isVolatile(),
+ Atomics.getAtomicAlignment().getQuantity(),
+ Atomics.getAtomicType(), SourceLocation()));
+ }
+ // Try to write new value using cmpxchg operation
+ auto Pair = Atomics.EmitAtomicCompareExchange(OriginalRValue, NewRVal, AO);
+ OldVal = IsScalar ? Pair.first.getScalarVal()
+ : Atomics.convertRValueToInt(Pair.first);
+ PHI->addIncoming(OldVal, ContBB);
+ Builder.CreateCondBr(Pair.second, ExitBB, ContBB);
+ EmitBlock(ExitBB, /*IsFinished=*/true);
}
void CodeGenFunction::EmitAtomicInit(Expr *init, LValue dest) {
OpenPOWER on IntegriCloud