summaryrefslogtreecommitdiffstats
path: root/clang/lib
diff options
context:
space:
mode:
authorAlexey Bataev <a.bataev@hotmail.com>2014-12-15 05:25:25 +0000
committerAlexey Bataev <a.bataev@hotmail.com>2014-12-15 05:25:25 +0000
commit452d8e1133766f2ace44563918b7deba4d614385 (patch)
tree34dae9bae23db47887409fee1e964db16c76785b /clang/lib
parent48be28ef1a85f82b95e76313f5b8555d8dcf15ab (diff)
downloadbcm5719-llvm-452d8e1133766f2ace44563918b7deba4d614385.tar.gz
bcm5719-llvm-452d8e1133766f2ace44563918b7deba4d614385.zip
Bugfix for Codegen of atomic load/store/other ops.
Currently clang fires assertions on x86-64 on any atomic operations for long double operands. Patch fixes codegen for such operations. Differential Revision: http://reviews.llvm.org/D6499 llvm-svn: 224230
Diffstat (limited to 'clang/lib')
-rw-r--r--clang/lib/CodeGen/CGAtomic.cpp217
-rw-r--r--clang/lib/CodeGen/CGExprScalar.cpp20
-rw-r--r--clang/lib/CodeGen/CodeGenFunction.h6
3 files changed, 161 insertions, 82 deletions
diff --git a/clang/lib/CodeGen/CGAtomic.cpp b/clang/lib/CodeGen/CGAtomic.cpp
index 49f98b2a07a..daac174c8e0 100644
--- a/clang/lib/CodeGen/CGAtomic.cpp
+++ b/clang/lib/CodeGen/CGAtomic.cpp
@@ -64,9 +64,8 @@ namespace {
if (lvalue.getAlignment().isZero())
lvalue.setAlignment(AtomicAlign);
- UseLibcall =
- (AtomicSizeInBits > uint64_t(C.toBits(lvalue.getAlignment())) ||
- AtomicSizeInBits > C.getTargetInfo().getMaxAtomicInlineWidth());
+ UseLibcall = !C.getTargetInfo().hasBuiltinAtomic(
+ AtomicSizeInBits, C.toBits(lvalue.getAlignment()));
}
QualType getAtomicType() const { return AtomicTy; }
@@ -74,7 +73,7 @@ namespace {
CharUnits getAtomicAlignment() const { return AtomicAlign; }
CharUnits getValueAlignment() const { return ValueAlign; }
uint64_t getAtomicSizeInBits() const { return AtomicSizeInBits; }
- uint64_t getValueSizeInBits() const { return AtomicSizeInBits; }
+ uint64_t getValueSizeInBits() const { return ValueSizeInBits; }
TypeEvaluationKind getEvaluationKind() const { return EvaluationKind; }
bool shouldUseLibcall() const { return UseLibcall; }
@@ -104,6 +103,12 @@ namespace {
AggValueSlot resultSlot,
SourceLocation loc) const;
+ /// \brief Converts a rvalue to integer value.
+ llvm::Value *convertRValueToInt(RValue RVal) const;
+
+ RValue convertIntToValue(llvm::Value *IntVal, AggValueSlot ResultSlot,
+ SourceLocation Loc) const;
+
/// Copy an atomic r-value into atomic-layout memory.
void emitCopyIntoMemory(RValue rvalue, LValue lvalue) const;
@@ -909,6 +914,45 @@ RValue AtomicInfo::convertTempToRValue(llvm::Value *addr,
return CGF.convertTempToRValue(addr, getValueType(), loc);
}
+RValue AtomicInfo::convertIntToValue(llvm::Value *IntVal,
+ AggValueSlot ResultSlot,
+ SourceLocation Loc) const {
+ // Try not to in some easy cases.
+ assert(IntVal->getType()->isIntegerTy() && "Expected integer value");
+ if (getEvaluationKind() == TEK_Scalar && !hasPadding()) {
+ auto *ValTy = CGF.ConvertTypeForMem(ValueTy);
+ if (ValTy->isIntegerTy()) {
+ assert(IntVal->getType() == ValTy && "Different integer types.");
+ return RValue::get(IntVal);
+ } else if (ValTy->isPointerTy())
+ return RValue::get(CGF.Builder.CreateIntToPtr(IntVal, ValTy));
+ else if (llvm::CastInst::isBitCastable(IntVal->getType(), ValTy))
+ return RValue::get(CGF.Builder.CreateBitCast(IntVal, ValTy));
+ }
+
+ // Create a temporary. This needs to be big enough to hold the
+ // atomic integer.
+ llvm::Value *Temp;
+ bool TempIsVolatile = false;
+ CharUnits TempAlignment;
+ if (getEvaluationKind() == TEK_Aggregate) {
+ assert(!ResultSlot.isIgnored());
+ Temp = ResultSlot.getAddr();
+ TempAlignment = getValueAlignment();
+ TempIsVolatile = ResultSlot.isVolatile();
+ } else {
+ Temp = CGF.CreateMemTemp(getAtomicType(), "atomic-temp");
+ TempAlignment = getAtomicAlignment();
+ }
+
+ // Slam the integer into the temporary.
+ llvm::Value *CastTemp = emitCastToAtomicIntPointer(Temp);
+ CGF.Builder.CreateAlignedStore(IntVal, CastTemp, TempAlignment.getQuantity())
+ ->setVolatile(TempIsVolatile);
+
+ return convertTempToRValue(Temp, ResultSlot, Loc);
+}
+
/// Emit a load from an l-value of atomic type. Note that the r-value
/// we produce is an r-value of the atomic *value* type.
RValue CodeGenFunction::EmitAtomicLoad(LValue src, SourceLocation loc,
@@ -954,50 +998,12 @@ RValue CodeGenFunction::EmitAtomicLoad(LValue src, SourceLocation loc,
if (src.getTBAAInfo())
CGM.DecorateInstruction(load, src.getTBAAInfo());
- // Okay, turn that back into the original value type.
- QualType valueType = atomics.getValueType();
- llvm::Value *result = load;
-
// If we're ignoring an aggregate return, don't do anything.
if (atomics.getEvaluationKind() == TEK_Aggregate && resultSlot.isIgnored())
return RValue::getAggregate(nullptr, false);
- // The easiest way to do this this is to go through memory, but we
- // try not to in some easy cases.
- if (atomics.getEvaluationKind() == TEK_Scalar && !atomics.hasPadding()) {
- llvm::Type *resultTy = CGM.getTypes().ConvertTypeForMem(valueType);
- if (isa<llvm::IntegerType>(resultTy)) {
- assert(result->getType() == resultTy);
- result = EmitFromMemory(result, valueType);
- } else if (isa<llvm::PointerType>(resultTy)) {
- result = Builder.CreateIntToPtr(result, resultTy);
- } else {
- result = Builder.CreateBitCast(result, resultTy);
- }
- return RValue::get(result);
- }
-
- // Create a temporary. This needs to be big enough to hold the
- // atomic integer.
- llvm::Value *temp;
- bool tempIsVolatile = false;
- CharUnits tempAlignment;
- if (atomics.getEvaluationKind() == TEK_Aggregate) {
- assert(!resultSlot.isIgnored());
- temp = resultSlot.getAddr();
- tempAlignment = atomics.getValueAlignment();
- tempIsVolatile = resultSlot.isVolatile();
- } else {
- temp = CreateMemTemp(atomics.getAtomicType(), "atomic-load-temp");
- tempAlignment = atomics.getAtomicAlignment();
- }
-
- // Slam the integer into the temporary.
- llvm::Value *castTemp = atomics.emitCastToAtomicIntPointer(temp);
- Builder.CreateAlignedStore(result, castTemp, tempAlignment.getQuantity())
- ->setVolatile(tempIsVolatile);
-
- return atomics.convertTempToRValue(temp, resultSlot, loc);
+ // Okay, turn that back into the original value type.
+ return atomics.convertIntToValue(load, resultSlot, loc);
}
@@ -1050,6 +1056,32 @@ llvm::Value *AtomicInfo::materializeRValue(RValue rvalue) const {
return temp;
}
+llvm::Value *AtomicInfo::convertRValueToInt(RValue RVal) const {
+ // If we've got a scalar value of the right size, try to avoid going
+ // through memory.
+ if (RVal.isScalar() && !hasPadding()) {
+ llvm::Value *Value = RVal.getScalarVal();
+ if (isa<llvm::IntegerType>(Value->getType()))
+ return Value;
+ else {
+ llvm::IntegerType *InputIntTy =
+ llvm::IntegerType::get(CGF.getLLVMContext(), getValueSizeInBits());
+ if (isa<llvm::PointerType>(Value->getType()))
+ return CGF.Builder.CreatePtrToInt(Value, InputIntTy);
+ else if (llvm::BitCastInst::isBitCastable(Value->getType(), InputIntTy))
+ return CGF.Builder.CreateBitCast(Value, InputIntTy);
+ }
+ }
+ // Otherwise, we need to go through memory.
+ // Put the r-value in memory.
+ llvm::Value *Addr = materializeRValue(RVal);
+
+ // Cast the temporary to the atomic int type and pull a value out.
+ Addr = emitCastToAtomicIntPointer(Addr);
+ return CGF.Builder.CreateAlignedLoad(Addr,
+ getAtomicAlignment().getQuantity());
+}
+
/// 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
@@ -1091,34 +1123,7 @@ void CodeGenFunction::EmitAtomicStore(RValue rvalue, LValue dest, bool isInit) {
}
// Okay, we're doing this natively.
- llvm::Value *intValue;
-
- // If we've got a scalar value of the right size, try to avoid going
- // through memory.
- if (rvalue.isScalar() && !atomics.hasPadding()) {
- llvm::Value *value = rvalue.getScalarVal();
- if (isa<llvm::IntegerType>(value->getType())) {
- intValue = value;
- } else {
- llvm::IntegerType *inputIntTy =
- llvm::IntegerType::get(getLLVMContext(), atomics.getValueSizeInBits());
- if (isa<llvm::PointerType>(value->getType())) {
- intValue = Builder.CreatePtrToInt(value, inputIntTy);
- } else {
- intValue = Builder.CreateBitCast(value, inputIntTy);
- }
- }
-
- // Otherwise, we need to go through memory.
- } else {
- // Put the r-value in memory.
- llvm::Value *addr = atomics.materializeRValue(rvalue);
-
- // Cast the temporary to the atomic int type and pull a value out.
- addr = atomics.emitCastToAtomicIntPointer(addr);
- intValue = Builder.CreateAlignedLoad(addr,
- atomics.getAtomicAlignment().getQuantity());
- }
+ llvm::Value *intValue = atomics.convertRValueToInt(rvalue);
// Do the atomic store.
llvm::Value *addr = atomics.emitCastToAtomicIntPointer(dest.getAddress());
@@ -1135,6 +1140,74 @@ void CodeGenFunction::EmitAtomicStore(RValue rvalue, LValue dest, bool isInit) {
CGM.DecorateInstruction(store, dest.getTBAAInfo());
}
+/// Emit a compare-and-exchange op for atomic type.
+///
+std::pair<RValue, RValue> CodeGenFunction::EmitAtomicCompareExchange(
+ LValue Obj, RValue Expected, RValue Desired, SourceLocation Loc,
+ llvm::AtomicOrdering Success, llvm::AtomicOrdering Failure, bool IsWeak,
+ AggValueSlot Slot) {
+ // If this is an aggregate r-value, it should agree in type except
+ // maybe for address-space qualification.
+ assert(!Expected.isAggregate() ||
+ Expected.getAggregateAddr()->getType()->getPointerElementType() ==
+ Obj.getAddress()->getType()->getPointerElementType());
+ assert(!Desired.isAggregate() ||
+ Desired.getAggregateAddr()->getType()->getPointerElementType() ==
+ Obj.getAddress()->getType()->getPointerElementType());
+ AtomicInfo Atomics(*this, Obj);
+
+ if (Failure >= Success)
+ // Don't assert on undefined behavior.
+ Failure = llvm::AtomicCmpXchgInst::getStrongestFailureOrdering(Success);
+
+ auto Alignment = Atomics.getValueAlignment();
+ // Check whether we should use a library call.
+ if (Atomics.shouldUseLibcall()) {
+ auto *ExpectedAddr = Atomics.materializeRValue(Expected);
+ // Produce a source address.
+ auto *DesiredAddr = Atomics.materializeRValue(Desired);
+ // bool __atomic_compare_exchange(size_t size, void *obj, void *expected,
+ // void *desired, int success, int failure);
+ CallArgList Args;
+ Args.add(RValue::get(Atomics.getAtomicSizeValue()),
+ getContext().getSizeType());
+ Args.add(RValue::get(EmitCastToVoidPtr(Obj.getAddress())),
+ getContext().VoidPtrTy);
+ Args.add(RValue::get(EmitCastToVoidPtr(ExpectedAddr)),
+ getContext().VoidPtrTy);
+ Args.add(RValue::get(EmitCastToVoidPtr(DesiredAddr)),
+ getContext().VoidPtrTy);
+ Args.add(RValue::get(llvm::ConstantInt::get(IntTy, Success)),
+ getContext().IntTy);
+ Args.add(RValue::get(llvm::ConstantInt::get(IntTy, Failure)),
+ getContext().IntTy);
+ auto SuccessFailureRVal = emitAtomicLibcall(
+ *this, "__atomic_compare_exchange", getContext().BoolTy, Args);
+ auto *PreviousVal =
+ Builder.CreateAlignedLoad(ExpectedAddr, Alignment.getQuantity());
+ return std::make_pair(RValue::get(PreviousVal), SuccessFailureRVal);
+ }
+
+ // If we've got a scalar value of the right size, try to avoid going
+ // through memory.
+ auto *ExpectedIntVal = Atomics.convertRValueToInt(Expected);
+ auto *DesiredIntVal = Atomics.convertRValueToInt(Desired);
+
+ // Do the atomic store.
+ auto *Addr = Atomics.emitCastToAtomicIntPointer(Obj.getAddress());
+ auto *Inst = Builder.CreateAtomicCmpXchg(Addr, ExpectedIntVal, DesiredIntVal,
+ Success, Failure);
+ // Other decoration.
+ Inst->setVolatile(Obj.isVolatileQualified());
+ Inst->setWeak(IsWeak);
+
+ // Okay, turn that back into the original value type.
+ auto *PreviousVal = Builder.CreateExtractValue(Inst, /*Idxs=*/0);
+ auto *SuccessFailureVal = Builder.CreateExtractValue(Inst, /*Idxs=*/1);
+ return std::make_pair(Atomics.convertIntToValue(PreviousVal, Slot, Loc),
+ RValue::get(SuccessFailureVal));
+}
+
void CodeGenFunction::EmitAtomicInit(Expr *init, LValue dest) {
AtomicInfo atomics(*this, dest);
diff --git a/clang/lib/CodeGen/CGExprScalar.cpp b/clang/lib/CodeGen/CGExprScalar.cpp
index 7e3c5b5a326..a4430dffb05 100644
--- a/clang/lib/CodeGen/CGExprScalar.cpp
+++ b/clang/lib/CodeGen/CGExprScalar.cpp
@@ -1791,11 +1791,11 @@ ScalarExprEmitter::EmitScalarPrePostIncDec(const UnaryOperator *E, LValue LV,
if (atomicPHI) {
llvm::BasicBlock *opBB = Builder.GetInsertBlock();
llvm::BasicBlock *contBB = CGF.createBasicBlock("atomic_cont", CGF.CurFn);
- llvm::Value *pair = Builder.CreateAtomicCmpXchg(
- LV.getAddress(), atomicPHI, CGF.EmitToMemory(value, type),
- llvm::SequentiallyConsistent, llvm::SequentiallyConsistent);
- llvm::Value *old = Builder.CreateExtractValue(pair, 0);
- llvm::Value *success = Builder.CreateExtractValue(pair, 1);
+ auto Pair = CGF.EmitAtomicCompareExchange(
+ LV, RValue::get(atomicPHI), RValue::get(CGF.EmitToMemory(value, type)),
+ E->getExprLoc());
+ llvm::Value *old = Pair.first.getScalarVal();
+ llvm::Value *success = Pair.second.getScalarVal();
atomicPHI->addIncoming(old, opBB);
Builder.CreateCondBr(success, contBB, opBB);
Builder.SetInsertPoint(contBB);
@@ -2135,11 +2135,11 @@ LValue ScalarExprEmitter::EmitCompoundAssignLValue(
if (atomicPHI) {
llvm::BasicBlock *opBB = Builder.GetInsertBlock();
llvm::BasicBlock *contBB = CGF.createBasicBlock("atomic_cont", CGF.CurFn);
- llvm::Value *pair = Builder.CreateAtomicCmpXchg(
- LHSLV.getAddress(), atomicPHI, CGF.EmitToMemory(Result, LHSTy),
- llvm::SequentiallyConsistent, llvm::SequentiallyConsistent);
- llvm::Value *old = Builder.CreateExtractValue(pair, 0);
- llvm::Value *success = Builder.CreateExtractValue(pair, 1);
+ auto Pair = CGF.EmitAtomicCompareExchange(
+ LHSLV, RValue::get(atomicPHI),
+ RValue::get(CGF.EmitToMemory(Result, LHSTy)), E->getExprLoc());
+ llvm::Value *old = Pair.first.getScalarVal();
+ llvm::Value *success = Pair.second.getScalarVal();
atomicPHI->addIncoming(old, opBB);
Builder.CreateCondBr(success, contBB, opBB);
Builder.SetInsertPoint(contBB);
diff --git a/clang/lib/CodeGen/CodeGenFunction.h b/clang/lib/CodeGen/CodeGenFunction.h
index 80f43e5cbfc..6c61df78bdf 100644
--- a/clang/lib/CodeGen/CodeGenFunction.h
+++ b/clang/lib/CodeGen/CodeGenFunction.h
@@ -2101,6 +2101,12 @@ public:
void EmitAtomicStore(RValue rvalue, LValue lvalue, bool isInit);
+ std::pair<RValue, RValue> EmitAtomicCompareExchange(
+ LValue Obj, RValue Expected, RValue Desired, SourceLocation Loc,
+ llvm::AtomicOrdering Success = llvm::SequentiallyConsistent,
+ llvm::AtomicOrdering Failure = llvm::SequentiallyConsistent,
+ bool IsWeak = false, AggValueSlot Slot = AggValueSlot::ignored());
+
/// EmitToMemory - Change a scalar value from its value
/// representation to its in-memory representation.
llvm::Value *EmitToMemory(llvm::Value *Value, QualType Ty);
OpenPOWER on IntegriCloud