summaryrefslogtreecommitdiffstats
path: root/clang/lib/CodeGen
diff options
context:
space:
mode:
authorDavid Majnemer <david.majnemer@gmail.com>2014-06-22 19:05:33 +0000
committerDavid Majnemer <david.majnemer@gmail.com>2014-06-22 19:05:33 +0000
commit1162d25c1b5e98aeb91813a4de6080568507a6ef (patch)
tree33be26e934b9729febd7744b8bf985b616664775 /clang/lib/CodeGen
parent1af2dfd2744e04b4c85137f85c2a9d26e25533e8 (diff)
downloadbcm5719-llvm-1162d25c1b5e98aeb91813a4de6080568507a6ef.tar.gz
bcm5719-llvm-1162d25c1b5e98aeb91813a4de6080568507a6ef.zip
Revert "Revert r211402 (and r211408,r211410), "CodeGen: Refactor dynamic_cast and typeid" It crashes msvc codegen in clang/test/SemaCXX/undefined-internal.cpp."
This reverts commit r211467 which reverted r211408,r211410, it caused crashes in test/SemaCXX/undefined-internal.cpp for i686-win32 targets. llvm-svn: 211473
Diffstat (limited to 'clang/lib/CodeGen')
-rw-r--r--clang/lib/CodeGen/CGCXXABI.h22
-rw-r--r--clang/lib/CodeGen/CGExprCXX.cpp418
-rw-r--r--clang/lib/CodeGen/ItaniumCXXABI.cpp209
-rw-r--r--clang/lib/CodeGen/MicrosoftCXXABI.cpp144
4 files changed, 427 insertions, 366 deletions
diff --git a/clang/lib/CodeGen/CGCXXABI.h b/clang/lib/CodeGen/CGCXXABI.h
index 82687746eda..82b4e883974 100644
--- a/clang/lib/CodeGen/CGCXXABI.h
+++ b/clang/lib/CodeGen/CGCXXABI.h
@@ -207,6 +207,28 @@ public:
llvm::Value *ptr,
QualType type) = 0;
+ virtual bool shouldTypeidBeNullChecked(bool IsDeref,
+ QualType SrcRecordTy) = 0;
+ virtual void EmitBadTypeidCall(CodeGenFunction &CGF) = 0;
+ virtual llvm::Value *EmitTypeid(CodeGenFunction &CGF, QualType SrcRecordTy,
+ llvm::Value *ThisPtr,
+ llvm::Type *StdTypeInfoPtrTy) = 0;
+
+ virtual bool shouldDynamicCastCallBeNullChecked(bool SrcIsPtr,
+ QualType SrcRecordTy) = 0;
+
+ virtual llvm::Value *
+ EmitDynamicCastCall(CodeGenFunction &CGF, llvm::Value *Value,
+ QualType SrcRecordTy, QualType DestTy,
+ QualType DestRecordTy, llvm::BasicBlock *CastEnd) = 0;
+
+ virtual llvm::Value *EmitDynamicCastToVoid(CodeGenFunction &CGF,
+ llvm::Value *Value,
+ QualType SrcRecordTy,
+ QualType DestTy) = 0;
+
+ virtual bool EmitBadCastCall(CodeGenFunction &CGF) = 0;
+
virtual llvm::Value *GetVirtualBaseClassOffset(CodeGenFunction &CGF,
llvm::Value *This,
const CXXRecordDecl *ClassDecl,
diff --git a/clang/lib/CodeGen/CGExprCXX.cpp b/clang/lib/CodeGen/CGExprCXX.cpp
index 0b5a415a0ea..47dc9fbbc73 100644
--- a/clang/lib/CodeGen/CGExprCXX.cpp
+++ b/clang/lib/CodeGen/CGExprCXX.cpp
@@ -1615,98 +1615,36 @@ void CodeGenFunction::EmitCXXDeleteExpr(const CXXDeleteExpr *E) {
EmitBlock(DeleteEnd);
}
-static llvm::Constant *getBadTypeidFn(CodeGenFunction &CGF) {
- // void __cxa_bad_typeid();
- llvm::FunctionType *FTy = llvm::FunctionType::get(CGF.VoidTy, false);
-
- return CGF.CGM.CreateRuntimeFunction(FTy, "__cxa_bad_typeid");
-}
-
-static void EmitBadTypeidCall(CodeGenFunction &CGF) {
- llvm::Value *Fn = getBadTypeidFn(CGF);
- CGF.EmitRuntimeCallOrInvoke(Fn).setDoesNotReturn();
- CGF.Builder.CreateUnreachable();
-}
-
-/// \brief Gets the offset to the virtual base that contains the vfptr for
-/// MS-ABI polymorphic types.
-static llvm::Value *getPolymorphicOffset(CodeGenFunction &CGF,
- const CXXRecordDecl *RD,
- llvm::Value *Value) {
- const ASTContext &Context = RD->getASTContext();
- for (const CXXBaseSpecifier &Base : RD->vbases())
- if (Context.getASTRecordLayout(Base.getType()->getAsCXXRecordDecl())
- .hasExtendableVFPtr())
- return CGF.CGM.getCXXABI().GetVirtualBaseClassOffset(
- CGF, Value, RD, Base.getType()->getAsCXXRecordDecl());
- llvm_unreachable("One of our vbases should be polymorphic.");
-}
-
-static llvm::Value *emitRTtypeidCall(CodeGenFunction &CGF,
- llvm::Value *Argument) {
- llvm::Type *ArgTypes[] = {CGF.Int8PtrTy};
- llvm::Constant *Function = CGF.CGM.CreateRuntimeFunction(
- llvm::FunctionType::get(CGF.Int8PtrTy, ArgTypes, false), "__RTtypeid");
- llvm::Value *Args[] = {Argument};
- return CGF.EmitRuntimeCall(Function, Args);
-}
-
static llvm::Value *EmitTypeidFromVTable(CodeGenFunction &CGF, const Expr *E,
llvm::Type *StdTypeInfoPtrTy) {
// Get the vtable pointer.
llvm::Value *ThisPtr = CGF.EmitLValue(E).getAddress();
- if (CGF.getTarget().getCXXABI().isMicrosoft()) {
- llvm::Value *CastPtr = CGF.Builder.CreateBitCast(ThisPtr, CGF.Int8PtrTy);
- const CXXRecordDecl *RD = E->getType()->getAsCXXRecordDecl();
- if (CGF.getContext().getASTRecordLayout(RD).hasExtendableVFPtr())
- return CGF.Builder.CreateBitCast(emitRTtypeidCall(CGF, CastPtr),
- StdTypeInfoPtrTy);
- llvm::BasicBlock *EntryBlock = CGF.Builder.GetInsertBlock();
- llvm::BasicBlock *AdjustBlock = CGF.createBasicBlock("type_id.valid");
- llvm::BasicBlock *ExitBlock = CGF.createBasicBlock("type_id.call");
- CGF.Builder.CreateCondBr(CGF.Builder.CreateIsNull(CastPtr), ExitBlock,
- AdjustBlock);
- // Emit the call block and code for it.
- CGF.EmitBlock(AdjustBlock);
- llvm::Value *AdjustedThisPtr = CGF.Builder.CreateInBoundsGEP(
- CastPtr, getPolymorphicOffset(CGF, RD, CastPtr));
- // Emit the call block and the phi nodes for it.
- CGF.EmitBlock(ExitBlock);
- llvm::PHINode *ValuePHI = CGF.Builder.CreatePHI(CGF.Int8PtrTy, 2);
- ValuePHI->addIncoming(AdjustedThisPtr, AdjustBlock);
- ValuePHI->addIncoming(llvm::Constant::getNullValue(CGF.Int8PtrTy),
- EntryBlock);
- return CGF.Builder.CreateBitCast(emitRTtypeidCall(CGF, ValuePHI),
- StdTypeInfoPtrTy);
- }
-
// C++ [expr.typeid]p2:
// If the glvalue expression is obtained by applying the unary * operator to
// a pointer and the pointer is a null pointer value, the typeid expression
// throws the std::bad_typeid exception.
- if (const UnaryOperator *UO = dyn_cast<UnaryOperator>(E->IgnoreParens())) {
- if (UO->getOpcode() == UO_Deref) {
- llvm::BasicBlock *BadTypeidBlock =
+ bool IsDeref = false;
+ if (const UnaryOperator *UO = dyn_cast<UnaryOperator>(E->IgnoreParens()))
+ if (UO->getOpcode() == UO_Deref)
+ IsDeref = true;
+
+ QualType SrcRecordTy = E->getType();
+ if (CGF.CGM.getCXXABI().shouldTypeidBeNullChecked(IsDeref, SrcRecordTy)) {
+ llvm::BasicBlock *BadTypeidBlock =
CGF.createBasicBlock("typeid.bad_typeid");
- llvm::BasicBlock *EndBlock =
- CGF.createBasicBlock("typeid.end");
+ llvm::BasicBlock *EndBlock = CGF.createBasicBlock("typeid.end");
- llvm::Value *IsNull = CGF.Builder.CreateIsNull(ThisPtr);
- CGF.Builder.CreateCondBr(IsNull, BadTypeidBlock, EndBlock);
+ llvm::Value *IsNull = CGF.Builder.CreateIsNull(ThisPtr);
+ CGF.Builder.CreateCondBr(IsNull, BadTypeidBlock, EndBlock);
- CGF.EmitBlock(BadTypeidBlock);
- EmitBadTypeidCall(CGF);
- CGF.EmitBlock(EndBlock);
- }
+ CGF.EmitBlock(BadTypeidBlock);
+ CGF.CGM.getCXXABI().EmitBadTypeidCall(CGF);
+ CGF.EmitBlock(EndBlock);
}
- llvm::Value *Value = CGF.GetVTablePtr(ThisPtr,
- StdTypeInfoPtrTy->getPointerTo());
-
- // Load the type info.
- Value = CGF.Builder.CreateConstInBoundsGEP1_64(Value, -1ULL);
- return CGF.Builder.CreateLoad(Value);
+ return CGF.CGM.getCXXABI().EmitTypeid(CGF, SrcRecordTy, ThisPtr,
+ StdTypeInfoPtrTy);
}
llvm::Value *CodeGenFunction::EmitCXXTypeidExpr(const CXXTypeidExpr *E) {
@@ -1733,173 +1671,6 @@ llvm::Value *CodeGenFunction::EmitCXXTypeidExpr(const CXXTypeidExpr *E) {
StdTypeInfoPtrTy);
}
-static llvm::Constant *getItaniumDynamicCastFn(CodeGenFunction &CGF) {
- // void *__dynamic_cast(const void *sub,
- // const abi::__class_type_info *src,
- // const abi::__class_type_info *dst,
- // std::ptrdiff_t src2dst_offset);
-
- llvm::Type *Int8PtrTy = CGF.Int8PtrTy;
- llvm::Type *PtrDiffTy =
- CGF.ConvertType(CGF.getContext().getPointerDiffType());
-
- llvm::Type *Args[4] = { Int8PtrTy, Int8PtrTy, Int8PtrTy, PtrDiffTy };
-
- llvm::FunctionType *FTy = llvm::FunctionType::get(Int8PtrTy, Args, false);
-
- // Mark the function as nounwind readonly.
- llvm::Attribute::AttrKind FuncAttrs[] = { llvm::Attribute::NoUnwind,
- llvm::Attribute::ReadOnly };
- llvm::AttributeSet Attrs = llvm::AttributeSet::get(
- CGF.getLLVMContext(), llvm::AttributeSet::FunctionIndex, FuncAttrs);
-
- return CGF.CGM.CreateRuntimeFunction(FTy, "__dynamic_cast", Attrs);
-}
-
-static llvm::Constant *getBadCastFn(CodeGenFunction &CGF) {
- // void __cxa_bad_cast();
- llvm::FunctionType *FTy = llvm::FunctionType::get(CGF.VoidTy, false);
- return CGF.CGM.CreateRuntimeFunction(FTy, "__cxa_bad_cast");
-}
-
-static void EmitBadCastCall(CodeGenFunction &CGF) {
- llvm::Value *Fn = getBadCastFn(CGF);
- CGF.EmitRuntimeCallOrInvoke(Fn).setDoesNotReturn();
- CGF.Builder.CreateUnreachable();
-}
-
-/// \brief Compute the src2dst_offset hint as described in the
-/// Itanium C++ ABI [2.9.7]
-static CharUnits computeOffsetHint(ASTContext &Context,
- const CXXRecordDecl *Src,
- const CXXRecordDecl *Dst) {
- CXXBasePaths Paths(/*FindAmbiguities=*/true, /*RecordPaths=*/true,
- /*DetectVirtual=*/false);
-
- // If Dst is not derived from Src we can skip the whole computation below and
- // return that Src is not a public base of Dst. Record all inheritance paths.
- if (!Dst->isDerivedFrom(Src, Paths))
- return CharUnits::fromQuantity(-2ULL);
-
- unsigned NumPublicPaths = 0;
- CharUnits Offset;
-
- // Now walk all possible inheritance paths.
- for (CXXBasePaths::paths_iterator I = Paths.begin(), E = Paths.end();
- I != E; ++I) {
- if (I->Access != AS_public) // Ignore non-public inheritance.
- continue;
-
- ++NumPublicPaths;
-
- for (CXXBasePath::iterator J = I->begin(), JE = I->end(); J != JE; ++J) {
- // If the path contains a virtual base class we can't give any hint.
- // -1: no hint.
- if (J->Base->isVirtual())
- return CharUnits::fromQuantity(-1ULL);
-
- if (NumPublicPaths > 1) // Won't use offsets, skip computation.
- continue;
-
- // Accumulate the base class offsets.
- const ASTRecordLayout &L = Context.getASTRecordLayout(J->Class);
- Offset += L.getBaseClassOffset(J->Base->getType()->getAsCXXRecordDecl());
- }
- }
-
- // -2: Src is not a public base of Dst.
- if (NumPublicPaths == 0)
- return CharUnits::fromQuantity(-2ULL);
-
- // -3: Src is a multiple public base type but never a virtual base type.
- if (NumPublicPaths > 1)
- return CharUnits::fromQuantity(-3ULL);
-
- // Otherwise, the Src type is a unique public nonvirtual base type of Dst.
- // Return the offset of Src from the origin of Dst.
- return Offset;
-}
-
-static llvm::Value *
-EmitItaniumDynamicCastCall(CodeGenFunction &CGF, llvm::Value *Value,
- QualType SrcTy, QualType DestTy,
- llvm::BasicBlock *CastEnd) {
- llvm::Type *PtrDiffLTy =
- CGF.ConvertType(CGF.getContext().getPointerDiffType());
- llvm::Type *DestLTy = CGF.ConvertType(DestTy);
-
- if (const PointerType *PTy = DestTy->getAs<PointerType>()) {
- if (PTy->getPointeeType()->isVoidType()) {
- // C++ [expr.dynamic.cast]p7:
- // If T is "pointer to cv void," then the result is a pointer to the
- // most derived object pointed to by v.
-
- // Get the vtable pointer.
- llvm::Value *VTable = CGF.GetVTablePtr(Value, PtrDiffLTy->getPointerTo());
-
- // Get the offset-to-top from the vtable.
- llvm::Value *OffsetToTop =
- CGF.Builder.CreateConstInBoundsGEP1_64(VTable, -2ULL);
- OffsetToTop = CGF.Builder.CreateLoad(OffsetToTop, "offset.to.top");
-
- // Finally, add the offset to the pointer.
- Value = CGF.EmitCastToVoidPtr(Value);
- Value = CGF.Builder.CreateInBoundsGEP(Value, OffsetToTop);
-
- return CGF.Builder.CreateBitCast(Value, DestLTy);
- }
- }
-
- QualType SrcRecordTy;
- QualType DestRecordTy;
-
- if (const PointerType *DestPTy = DestTy->getAs<PointerType>()) {
- SrcRecordTy = SrcTy->castAs<PointerType>()->getPointeeType();
- DestRecordTy = DestPTy->getPointeeType();
- } else {
- SrcRecordTy = SrcTy;
- DestRecordTy = DestTy->castAs<ReferenceType>()->getPointeeType();
- }
-
- assert(SrcRecordTy->isRecordType() && "source type must be a record type!");
- assert(DestRecordTy->isRecordType() && "dest type must be a record type!");
-
- llvm::Value *SrcRTTI =
- CGF.CGM.GetAddrOfRTTIDescriptor(SrcRecordTy.getUnqualifiedType());
- llvm::Value *DestRTTI =
- CGF.CGM.GetAddrOfRTTIDescriptor(DestRecordTy.getUnqualifiedType());
-
- // Compute the offset hint.
- const CXXRecordDecl *SrcDecl = SrcRecordTy->getAsCXXRecordDecl();
- const CXXRecordDecl *DestDecl = DestRecordTy->getAsCXXRecordDecl();
- llvm::Value *OffsetHint =
- llvm::ConstantInt::get(PtrDiffLTy,
- computeOffsetHint(CGF.getContext(), SrcDecl,
- DestDecl).getQuantity());
-
- // Emit the call to __dynamic_cast.
- Value = CGF.EmitCastToVoidPtr(Value);
-
- llvm::Value *args[] = { Value, SrcRTTI, DestRTTI, OffsetHint };
- Value = CGF.EmitNounwindRuntimeCall(getItaniumDynamicCastFn(CGF), args);
- Value = CGF.Builder.CreateBitCast(Value, DestLTy);
-
- /// C++ [expr.dynamic.cast]p9:
- /// A failed cast to reference type throws std::bad_cast
- if (DestTy->isReferenceType()) {
- llvm::BasicBlock *BadCastBlock =
- CGF.createBasicBlock("dynamic_cast.bad_cast");
-
- llvm::Value *IsNull = CGF.Builder.CreateIsNull(Value);
- CGF.Builder.CreateCondBr(IsNull, BadCastBlock, CastEnd);
-
- CGF.EmitBlock(BadCastBlock);
- EmitBadCastCall(CGF);
- }
-
- return Value;
-}
-
static llvm::Value *EmitDynamicCastToNull(CodeGenFunction &CGF,
QualType DestTy) {
llvm::Type *DestLTy = CGF.ConvertType(DestTy);
@@ -1908,142 +1679,49 @@ static llvm::Value *EmitDynamicCastToNull(CodeGenFunction &CGF,
/// C++ [expr.dynamic.cast]p9:
/// A failed cast to reference type throws std::bad_cast
- EmitBadCastCall(CGF);
+ if (!CGF.CGM.getCXXABI().EmitBadCastCall(CGF))
+ return nullptr;
CGF.EmitBlock(CGF.createBasicBlock("dynamic_cast.end"));
return llvm::UndefValue::get(DestLTy);
}
-namespace {
-struct MSDynamicCastBuilder {
- MSDynamicCastBuilder(CodeGenFunction &CGF, const CXXDynamicCastExpr *DCE);
- llvm::Value *emitDynamicCastCall(llvm::Value *Value);
- llvm::Value *emitDynamicCast(llvm::Value *Value);
-
- CodeGenFunction &CGF;
- CGBuilderTy &Builder;
- llvm::PointerType *Int8PtrTy;
- QualType SrcTy, DstTy;
- const CXXRecordDecl *SrcDecl;
- bool IsPtrCast, IsCastToVoid, IsCastOfNull;
-};
-} // namespace
-
-MSDynamicCastBuilder::MSDynamicCastBuilder(CodeGenFunction &CGF,
- const CXXDynamicCastExpr *DCE)
- : CGF(CGF), Builder(CGF.Builder), Int8PtrTy(CGF.Int8PtrTy),
- SrcDecl(nullptr) {
- DstTy = DCE->getTypeAsWritten();
- IsPtrCast = DstTy->isPointerType();
- // Get the PointeeTypes. After this point the original types are not used.
- DstTy = IsPtrCast ? DstTy->castAs<PointerType>()->getPointeeType()
- : DstTy->castAs<ReferenceType>()->getPointeeType();
- IsCastToVoid = DstTy->isVoidType();
- IsCastOfNull = DCE->isAlwaysNull();
- if (IsCastOfNull)
- return;
- SrcTy = DCE->getSubExpr()->getType();
- SrcTy = IsPtrCast ? SrcTy->castAs<PointerType>()->getPointeeType() : SrcTy;
- SrcDecl = SrcTy->getAsCXXRecordDecl();
- // If we don't need a base adjustment, we don't need a SrcDecl so clear it
- // here. Later we use the existence of the SrcDecl to determine the need for
- // a base adjustment.
- if (CGF.getContext().getASTRecordLayout(SrcDecl).hasExtendableVFPtr())
- SrcDecl = nullptr;
-}
-
-llvm::Value *MSDynamicCastBuilder::emitDynamicCastCall(llvm::Value *Value) {
- llvm::IntegerType *Int32Ty = CGF.Int32Ty;
- llvm::Value *Offset = llvm::ConstantInt::get(Int32Ty, 0);
- Value = Builder.CreateBitCast(Value, Int8PtrTy);
- // If we need to perform a base adjustment, do it here.
- if (SrcDecl) {
- Offset = getPolymorphicOffset(CGF, SrcDecl, Value);
- Value = Builder.CreateInBoundsGEP(Value, Offset);
- Offset = Builder.CreateTrunc(Offset, Int32Ty);
- }
- if (IsCastToVoid) {
- // PVOID __RTCastToVoid(
- // PVOID inptr)
- llvm::Type *ArgTypes[] = {Int8PtrTy};
- llvm::Constant *Function = CGF.CGM.CreateRuntimeFunction(
- llvm::FunctionType::get(Int8PtrTy, ArgTypes, false), "__RTCastToVoid");
- llvm::Value *Args[] = {Value};
- return CGF.EmitRuntimeCall(Function, Args);
- }
- // PVOID __RTDynamicCast(
- // PVOID inptr,
- // LONG VfDelta,
- // PVOID SrcType,
- // PVOID TargetType,
- // BOOL isReference)
- llvm::Type *ArgTypes[] = {Int8PtrTy, Int32Ty, Int8PtrTy, Int8PtrTy, Int32Ty};
- llvm::Constant *Function = CGF.CGM.CreateRuntimeFunction(
- llvm::FunctionType::get(Int8PtrTy, ArgTypes, false), "__RTDynamicCast");
- llvm::Value *Args[] = {
- Value, Offset,
- CGF.CGM.GetAddrOfRTTIDescriptor(SrcTy.getUnqualifiedType()),
- CGF.CGM.GetAddrOfRTTIDescriptor(DstTy.getUnqualifiedType()),
- llvm::ConstantInt::get(Int32Ty, IsPtrCast ? 0 : 1)};
- return CGF.EmitRuntimeCall(Function, Args);
-}
-
-llvm::Value *MSDynamicCastBuilder::emitDynamicCast(llvm::Value *Value) {
- // Note about undefined behavior: If the dynamic cast is casting to a
- // reference type and the input is null, we hit a grey area in the standard.
- // Here we're interpreting the behavior as undefined. The effects are the
- // following: If the compiler determines that the argument is statically null
- // or if the argument is dynamically null but does not require base
- // adjustment, __RTDynamicCast will be called with a null argument and the
- // isreference bit set. In this case __RTDynamicCast will throw
- // std::bad_cast. If the argument is dynamically null and a base adjustment is
- // required the resulting code will produce an out of bounds memory reference
- // when trying to read VBTblPtr. In Itanium mode clang also emits a vtable
- // load that fails at run time.
- llvm::PointerType *DstLTy = CGF.ConvertType(DstTy)->getPointerTo();
- if (IsCastOfNull && IsPtrCast)
- return Builder.CreateBitCast(Value, DstLTy);
- if (IsCastOfNull || !IsPtrCast || !SrcDecl)
- return Builder.CreateBitCast(emitDynamicCastCall(Value), DstLTy);
- // !IsCastOfNull && IsPtrCast && SrcDecl
- // In this case we have a pointer that requires a base adjustment. An
- // adjustment is only required if the pointer is actually valid so here we
- // perform a null check before doing the base adjustment and calling
- // __RTDynamicCast. In the case that the argument is null we simply return
- // null without calling __RTDynamicCast.
- llvm::BasicBlock *EntryBlock = Builder.GetInsertBlock();
- llvm::BasicBlock *CallBlock = CGF.createBasicBlock("dynamic_cast.valid");
- llvm::BasicBlock *ExitBlock = CGF.createBasicBlock("dynamic_cast.call");
- Builder.CreateCondBr(Builder.CreateIsNull(Value), ExitBlock, CallBlock);
- // Emit the call block and code for it.
- CGF.EmitBlock(CallBlock);
- Value = emitDynamicCastCall(Value);
- // Emit the call block and the phi nodes for it.
- CGF.EmitBlock(ExitBlock);
- llvm::PHINode *ValuePHI = Builder.CreatePHI(Int8PtrTy, 2);
- ValuePHI->addIncoming(Value, CallBlock);
- ValuePHI->addIncoming(llvm::Constant::getNullValue(Int8PtrTy), EntryBlock);
- return Builder.CreateBitCast(ValuePHI, DstLTy);
-}
-
llvm::Value *CodeGenFunction::EmitDynamicCast(llvm::Value *Value,
const CXXDynamicCastExpr *DCE) {
- if (getTarget().getCXXABI().isMicrosoft()) {
- MSDynamicCastBuilder Builder(*this, DCE);
- return Builder.emitDynamicCast(Value);
- }
-
QualType DestTy = DCE->getTypeAsWritten();
if (DCE->isAlwaysNull())
- return EmitDynamicCastToNull(*this, DestTy);
+ if (llvm::Value *T = EmitDynamicCastToNull(*this, DestTy))
+ return T;
QualType SrcTy = DCE->getSubExpr()->getType();
+ // C++ [expr.dynamic.cast]p7:
+ // If T is "pointer to cv void," then the result is a pointer to the most
+ // derived object pointed to by v.
+ const PointerType *DestPTy = DestTy->getAs<PointerType>();
+
+ bool isDynamicCastToVoid;
+ QualType SrcRecordTy;
+ QualType DestRecordTy;
+ if (DestPTy) {
+ isDynamicCastToVoid = DestPTy->getPointeeType()->isVoidType();
+ SrcRecordTy = SrcTy->castAs<PointerType>()->getPointeeType();
+ DestRecordTy = DestPTy->getPointeeType();
+ } else {
+ isDynamicCastToVoid = false;
+ SrcRecordTy = SrcTy;
+ DestRecordTy = DestTy->castAs<ReferenceType>()->getPointeeType();
+ }
+
+ assert(SrcRecordTy->isRecordType() && "source type must be a record type!");
+
// C++ [expr.dynamic.cast]p4:
// If the value of v is a null pointer value in the pointer case, the result
// is the null pointer value of type T.
- bool ShouldNullCheckSrcValue = SrcTy->isPointerType();
+ bool ShouldNullCheckSrcValue =
+ CGM.getCXXABI().shouldDynamicCastCallBeNullChecked(SrcTy->isPointerType(),
+ SrcRecordTy);
llvm::BasicBlock *CastNull = nullptr;
llvm::BasicBlock *CastNotNull = nullptr;
@@ -2058,7 +1736,15 @@ llvm::Value *CodeGenFunction::EmitDynamicCast(llvm::Value *Value,
EmitBlock(CastNotNull);
}
- Value = EmitItaniumDynamicCastCall(*this, Value, SrcTy, DestTy, CastEnd);
+ if (isDynamicCastToVoid) {
+ Value = CGM.getCXXABI().EmitDynamicCastToVoid(*this, Value, SrcRecordTy,
+ DestTy);
+ } else {
+ assert(DestRecordTy->isRecordType() &&
+ "destination type must be a record type!");
+ Value = CGM.getCXXABI().EmitDynamicCastCall(*this, Value, SrcRecordTy,
+ DestTy, DestRecordTy, CastEnd);
+ }
if (ShouldNullCheckSrcValue) {
EmitBranch(CastEnd);
diff --git a/clang/lib/CodeGen/ItaniumCXXABI.cpp b/clang/lib/CodeGen/ItaniumCXXABI.cpp
index be8dac140ed..38d49d134e9 100644
--- a/clang/lib/CodeGen/ItaniumCXXABI.cpp
+++ b/clang/lib/CodeGen/ItaniumCXXABI.cpp
@@ -25,6 +25,7 @@
#include "CodeGenModule.h"
#include "clang/AST/Mangle.h"
#include "clang/AST/Type.h"
+#include "llvm/IR/CallSite.h"
#include "llvm/IR/DataLayout.h"
#include "llvm/IR/Intrinsics.h"
#include "llvm/IR/Value.h"
@@ -108,6 +109,26 @@ public:
llvm::Value *adjustToCompleteObject(CodeGenFunction &CGF, llvm::Value *ptr,
QualType type) override;
+ bool shouldTypeidBeNullChecked(bool IsDeref, QualType SrcRecordTy) override;
+ void EmitBadTypeidCall(CodeGenFunction &CGF) override;
+ llvm::Value *EmitTypeid(CodeGenFunction &CGF, QualType SrcRecordTy,
+ llvm::Value *ThisPtr,
+ llvm::Type *StdTypeInfoPtrTy) override;
+
+ bool shouldDynamicCastCallBeNullChecked(bool SrcIsPtr,
+ QualType SrcRecordTy) override;
+
+ llvm::Value *EmitDynamicCastCall(CodeGenFunction &CGF, llvm::Value *Value,
+ QualType SrcRecordTy, QualType DestTy,
+ QualType DestRecordTy,
+ llvm::BasicBlock *CastEnd) override;
+
+ llvm::Value *EmitDynamicCastToVoid(CodeGenFunction &CGF, llvm::Value *Value,
+ QualType SrcRecordTy,
+ QualType DestTy) override;
+
+ bool EmitBadCastCall(CodeGenFunction &CGF) override;
+
llvm::Value *
GetVirtualBaseClassOffset(CodeGenFunction &CGF, llvm::Value *This,
const CXXRecordDecl *ClassDecl,
@@ -800,6 +821,194 @@ llvm::Value *ItaniumCXXABI::adjustToCompleteObject(CodeGenFunction &CGF,
return CGF.Builder.CreateInBoundsGEP(ptr, offset);
}
+static llvm::Constant *getItaniumDynamicCastFn(CodeGenFunction &CGF) {
+ // void *__dynamic_cast(const void *sub,
+ // const abi::__class_type_info *src,
+ // const abi::__class_type_info *dst,
+ // std::ptrdiff_t src2dst_offset);
+
+ llvm::Type *Int8PtrTy = CGF.Int8PtrTy;
+ llvm::Type *PtrDiffTy =
+ CGF.ConvertType(CGF.getContext().getPointerDiffType());
+
+ llvm::Type *Args[4] = { Int8PtrTy, Int8PtrTy, Int8PtrTy, PtrDiffTy };
+
+ llvm::FunctionType *FTy = llvm::FunctionType::get(Int8PtrTy, Args, false);
+
+ // Mark the function as nounwind readonly.
+ llvm::Attribute::AttrKind FuncAttrs[] = { llvm::Attribute::NoUnwind,
+ llvm::Attribute::ReadOnly };
+ llvm::AttributeSet Attrs = llvm::AttributeSet::get(
+ CGF.getLLVMContext(), llvm::AttributeSet::FunctionIndex, FuncAttrs);
+
+ return CGF.CGM.CreateRuntimeFunction(FTy, "__dynamic_cast", Attrs);
+}
+
+static llvm::Constant *getBadCastFn(CodeGenFunction &CGF) {
+ // void __cxa_bad_cast();
+ llvm::FunctionType *FTy = llvm::FunctionType::get(CGF.VoidTy, false);
+ return CGF.CGM.CreateRuntimeFunction(FTy, "__cxa_bad_cast");
+}
+
+/// \brief Compute the src2dst_offset hint as described in the
+/// Itanium C++ ABI [2.9.7]
+static CharUnits computeOffsetHint(ASTContext &Context,
+ const CXXRecordDecl *Src,
+ const CXXRecordDecl *Dst) {
+ CXXBasePaths Paths(/*FindAmbiguities=*/true, /*RecordPaths=*/true,
+ /*DetectVirtual=*/false);
+
+ // If Dst is not derived from Src we can skip the whole computation below and
+ // return that Src is not a public base of Dst. Record all inheritance paths.
+ if (!Dst->isDerivedFrom(Src, Paths))
+ return CharUnits::fromQuantity(-2ULL);
+
+ unsigned NumPublicPaths = 0;
+ CharUnits Offset;
+
+ // Now walk all possible inheritance paths.
+ for (CXXBasePaths::paths_iterator I = Paths.begin(), E = Paths.end(); I != E;
+ ++I) {
+ if (I->Access != AS_public) // Ignore non-public inheritance.
+ continue;
+
+ ++NumPublicPaths;
+
+ for (CXXBasePath::iterator J = I->begin(), JE = I->end(); J != JE; ++J) {
+ // If the path contains a virtual base class we can't give any hint.
+ // -1: no hint.
+ if (J->Base->isVirtual())
+ return CharUnits::fromQuantity(-1ULL);
+
+ if (NumPublicPaths > 1) // Won't use offsets, skip computation.
+ continue;
+
+ // Accumulate the base class offsets.
+ const ASTRecordLayout &L = Context.getASTRecordLayout(J->Class);
+ Offset += L.getBaseClassOffset(J->Base->getType()->getAsCXXRecordDecl());
+ }
+ }
+
+ // -2: Src is not a public base of Dst.
+ if (NumPublicPaths == 0)
+ return CharUnits::fromQuantity(-2ULL);
+
+ // -3: Src is a multiple public base type but never a virtual base type.
+ if (NumPublicPaths > 1)
+ return CharUnits::fromQuantity(-3ULL);
+
+ // Otherwise, the Src type is a unique public nonvirtual base type of Dst.
+ // Return the offset of Src from the origin of Dst.
+ return Offset;
+}
+
+static llvm::Constant *getBadTypeidFn(CodeGenFunction &CGF) {
+ // void __cxa_bad_typeid();
+ llvm::FunctionType *FTy = llvm::FunctionType::get(CGF.VoidTy, false);
+
+ return CGF.CGM.CreateRuntimeFunction(FTy, "__cxa_bad_typeid");
+}
+
+bool ItaniumCXXABI::shouldTypeidBeNullChecked(bool IsDeref,
+ QualType SrcRecordTy) {
+ return IsDeref;
+}
+
+void ItaniumCXXABI::EmitBadTypeidCall(CodeGenFunction &CGF) {
+ llvm::Value *Fn = getBadTypeidFn(CGF);
+ CGF.EmitRuntimeCallOrInvoke(Fn).setDoesNotReturn();
+ CGF.Builder.CreateUnreachable();
+}
+
+llvm::Value *ItaniumCXXABI::EmitTypeid(CodeGenFunction &CGF,
+ QualType SrcRecordTy,
+ llvm::Value *ThisPtr,
+ llvm::Type *StdTypeInfoPtrTy) {
+ llvm::Value *Value =
+ CGF.GetVTablePtr(ThisPtr, StdTypeInfoPtrTy->getPointerTo());
+
+ // Load the type info.
+ Value = CGF.Builder.CreateConstInBoundsGEP1_64(Value, -1ULL);
+ return CGF.Builder.CreateLoad(Value);
+}
+
+bool ItaniumCXXABI::shouldDynamicCastCallBeNullChecked(bool SrcIsPtr,
+ QualType SrcRecordTy) {
+ return SrcIsPtr;
+}
+
+llvm::Value *ItaniumCXXABI::EmitDynamicCastCall(
+ CodeGenFunction &CGF, llvm::Value *Value, QualType SrcRecordTy,
+ QualType DestTy, QualType DestRecordTy, llvm::BasicBlock *CastEnd) {
+ llvm::Type *PtrDiffLTy =
+ CGF.ConvertType(CGF.getContext().getPointerDiffType());
+ llvm::Type *DestLTy = CGF.ConvertType(DestTy);
+
+ llvm::Value *SrcRTTI =
+ CGF.CGM.GetAddrOfRTTIDescriptor(SrcRecordTy.getUnqualifiedType());
+ llvm::Value *DestRTTI =
+ CGF.CGM.GetAddrOfRTTIDescriptor(DestRecordTy.getUnqualifiedType());
+
+ // Compute the offset hint.
+ const CXXRecordDecl *SrcDecl = SrcRecordTy->getAsCXXRecordDecl();
+ const CXXRecordDecl *DestDecl = DestRecordTy->getAsCXXRecordDecl();
+ llvm::Value *OffsetHint = llvm::ConstantInt::get(
+ PtrDiffLTy,
+ computeOffsetHint(CGF.getContext(), SrcDecl, DestDecl).getQuantity());
+
+ // Emit the call to __dynamic_cast.
+ Value = CGF.EmitCastToVoidPtr(Value);
+
+ llvm::Value *args[] = {Value, SrcRTTI, DestRTTI, OffsetHint};
+ Value = CGF.EmitNounwindRuntimeCall(getItaniumDynamicCastFn(CGF), args);
+ Value = CGF.Builder.CreateBitCast(Value, DestLTy);
+
+ /// C++ [expr.dynamic.cast]p9:
+ /// A failed cast to reference type throws std::bad_cast
+ if (DestTy->isReferenceType()) {
+ llvm::BasicBlock *BadCastBlock =
+ CGF.createBasicBlock("dynamic_cast.bad_cast");
+
+ llvm::Value *IsNull = CGF.Builder.CreateIsNull(Value);
+ CGF.Builder.CreateCondBr(IsNull, BadCastBlock, CastEnd);
+
+ CGF.EmitBlock(BadCastBlock);
+ EmitBadCastCall(CGF);
+ }
+
+ return Value;
+}
+
+llvm::Value *ItaniumCXXABI::EmitDynamicCastToVoid(CodeGenFunction &CGF,
+ llvm::Value *Value,
+ QualType SrcRecordTy,
+ QualType DestTy) {
+ llvm::Type *PtrDiffLTy =
+ CGF.ConvertType(CGF.getContext().getPointerDiffType());
+ llvm::Type *DestLTy = CGF.ConvertType(DestTy);
+
+ // Get the vtable pointer.
+ llvm::Value *VTable = CGF.GetVTablePtr(Value, PtrDiffLTy->getPointerTo());
+
+ // Get the offset-to-top from the vtable.
+ llvm::Value *OffsetToTop =
+ CGF.Builder.CreateConstInBoundsGEP1_64(VTable, -2ULL);
+ OffsetToTop = CGF.Builder.CreateLoad(OffsetToTop, "offset.to.top");
+
+ // Finally, add the offset to the pointer.
+ Value = CGF.EmitCastToVoidPtr(Value);
+ Value = CGF.Builder.CreateInBoundsGEP(Value, OffsetToTop);
+
+ return CGF.Builder.CreateBitCast(Value, DestLTy);
+}
+
+bool ItaniumCXXABI::EmitBadCastCall(CodeGenFunction &CGF) {
+ llvm::Value *Fn = getBadCastFn(CGF);
+ CGF.EmitRuntimeCallOrInvoke(Fn).setDoesNotReturn();
+ CGF.Builder.CreateUnreachable();
+ return true;
+}
+
llvm::Value *
ItaniumCXXABI::GetVirtualBaseClassOffset(CodeGenFunction &CGF,
llvm::Value *This,
diff --git a/clang/lib/CodeGen/MicrosoftCXXABI.cpp b/clang/lib/CodeGen/MicrosoftCXXABI.cpp
index ca2aaa2edf1..f3c79ef967a 100644
--- a/clang/lib/CodeGen/MicrosoftCXXABI.cpp
+++ b/clang/lib/CodeGen/MicrosoftCXXABI.cpp
@@ -21,6 +21,7 @@
#include "clang/AST/DeclCXX.h"
#include "clang/AST/VTableBuilder.h"
#include "llvm/ADT/StringSet.h"
+#include "llvm/IR/CallSite.h"
using namespace clang;
using namespace CodeGen;
@@ -56,6 +57,26 @@ public:
llvm::Value *ptr,
QualType type) override;
+ bool shouldTypeidBeNullChecked(bool IsDeref, QualType SrcRecordTy) override;
+ void EmitBadTypeidCall(CodeGenFunction &CGF) override;
+ llvm::Value *EmitTypeid(CodeGenFunction &CGF, QualType SrcRecordTy,
+ llvm::Value *ThisPtr,
+ llvm::Type *StdTypeInfoPtrTy) override;
+
+ bool shouldDynamicCastCallBeNullChecked(bool SrcIsPtr,
+ QualType SrcRecordTy) override;
+
+ llvm::Value *EmitDynamicCastCall(CodeGenFunction &CGF, llvm::Value *Value,
+ QualType SrcRecordTy, QualType DestTy,
+ QualType DestRecordTy,
+ llvm::BasicBlock *CastEnd) override;
+
+ llvm::Value *EmitDynamicCastToVoid(CodeGenFunction &CGF, llvm::Value *Value,
+ QualType SrcRecordTy,
+ QualType DestTy) override;
+
+ bool EmitBadCastCall(CodeGenFunction &CGF) override;
+
llvm::Value *
GetVirtualBaseClassOffset(CodeGenFunction &CGF, llvm::Value *This,
const CXXRecordDecl *ClassDecl,
@@ -469,6 +490,129 @@ llvm::Value *MicrosoftCXXABI::adjustToCompleteObject(CodeGenFunction &CGF,
return ptr;
}
+/// \brief Gets the offset to the virtual base that contains the vfptr for
+/// MS-ABI polymorphic types.
+static llvm::Value *getPolymorphicOffset(CodeGenFunction &CGF,
+ const CXXRecordDecl *RD,
+ llvm::Value *Value) {
+ const ASTContext &Context = RD->getASTContext();
+ for (const CXXBaseSpecifier &Base : RD->vbases())
+ if (Context.getASTRecordLayout(Base.getType()->getAsCXXRecordDecl())
+ .hasExtendableVFPtr())
+ return CGF.CGM.getCXXABI().GetVirtualBaseClassOffset(
+ CGF, Value, RD, Base.getType()->getAsCXXRecordDecl());
+ llvm_unreachable("One of our vbases should be polymorphic.");
+}
+
+static std::pair<llvm::Value *, llvm::Value *>
+performBaseAdjustment(CodeGenFunction &CGF, llvm::Value *Value,
+ QualType SrcRecordTy) {
+ Value = CGF.Builder.CreateBitCast(Value, CGF.Int8PtrTy);
+ const CXXRecordDecl *SrcDecl = SrcRecordTy->getAsCXXRecordDecl();
+
+ if (CGF.getContext().getASTRecordLayout(SrcDecl).hasExtendableVFPtr())
+ return std::make_pair(Value, llvm::ConstantInt::get(CGF.Int32Ty, 0));
+
+ // Perform a base adjustment.
+ llvm::Value *Offset = getPolymorphicOffset(CGF, SrcDecl, Value);
+ Value = CGF.Builder.CreateInBoundsGEP(Value, Offset);
+ Offset = CGF.Builder.CreateTrunc(Offset, CGF.Int32Ty);
+ return std::make_pair(Value, Offset);
+}
+
+bool MicrosoftCXXABI::shouldTypeidBeNullChecked(bool IsDeref,
+ QualType SrcRecordTy) {
+ const CXXRecordDecl *SrcDecl = SrcRecordTy->getAsCXXRecordDecl();
+ return IsDeref &&
+ !CGM.getContext().getASTRecordLayout(SrcDecl).hasExtendableVFPtr();
+}
+
+static llvm::CallSite emitRTtypeidCall(CodeGenFunction &CGF,
+ llvm::Value *Argument) {
+ llvm::Type *ArgTypes[] = {CGF.Int8PtrTy};
+ llvm::FunctionType *FTy =
+ llvm::FunctionType::get(CGF.Int8PtrTy, ArgTypes, false);
+ llvm::Value *Args[] = {Argument};
+ llvm::Constant *Fn = CGF.CGM.CreateRuntimeFunction(FTy, "__RTtypeid");
+ return CGF.EmitRuntimeCallOrInvoke(Fn, Args);
+}
+
+void MicrosoftCXXABI::EmitBadTypeidCall(CodeGenFunction &CGF) {
+ llvm::CallSite Call =
+ emitRTtypeidCall(CGF, llvm::Constant::getNullValue(CGM.VoidPtrTy));
+ Call.setDoesNotReturn();
+ CGF.Builder.CreateUnreachable();
+}
+
+llvm::Value *MicrosoftCXXABI::EmitTypeid(CodeGenFunction &CGF,
+ QualType SrcRecordTy,
+ llvm::Value *ThisPtr,
+ llvm::Type *StdTypeInfoPtrTy) {
+ llvm::Value *Offset;
+ std::tie(ThisPtr, Offset) = performBaseAdjustment(CGF, ThisPtr, SrcRecordTy);
+ return CGF.Builder.CreateBitCast(
+ emitRTtypeidCall(CGF, ThisPtr).getInstruction(), StdTypeInfoPtrTy);
+}
+
+bool MicrosoftCXXABI::shouldDynamicCastCallBeNullChecked(bool SrcIsPtr,
+ QualType SrcRecordTy) {
+ const CXXRecordDecl *SrcDecl = SrcRecordTy->getAsCXXRecordDecl();
+ return SrcIsPtr &&
+ !CGM.getContext().getASTRecordLayout(SrcDecl).hasExtendableVFPtr();
+}
+
+llvm::Value *MicrosoftCXXABI::EmitDynamicCastCall(
+ CodeGenFunction &CGF, llvm::Value *Value, QualType SrcRecordTy,
+ QualType DestTy, QualType DestRecordTy, llvm::BasicBlock *CastEnd) {
+ llvm::Type *DestLTy = CGF.ConvertType(DestTy);
+
+ llvm::Value *SrcRTTI =
+ CGF.CGM.GetAddrOfRTTIDescriptor(SrcRecordTy.getUnqualifiedType());
+ llvm::Value *DestRTTI =
+ CGF.CGM.GetAddrOfRTTIDescriptor(DestRecordTy.getUnqualifiedType());
+
+ llvm::Value *Offset;
+ std::tie(Value, Offset) = performBaseAdjustment(CGF, Value, SrcRecordTy);
+
+ // PVOID __RTDynamicCast(
+ // PVOID inptr,
+ // LONG VfDelta,
+ // PVOID SrcType,
+ // PVOID TargetType,
+ // BOOL isReference)
+ llvm::Type *ArgTypes[] = {CGF.Int8PtrTy, CGF.Int32Ty, CGF.Int8PtrTy,
+ CGF.Int8PtrTy, CGF.Int32Ty};
+ llvm::Constant *Function = CGF.CGM.CreateRuntimeFunction(
+ llvm::FunctionType::get(CGF.Int8PtrTy, ArgTypes, false),
+ "__RTDynamicCast");
+ llvm::Value *Args[] = {
+ Value, Offset, SrcRTTI, DestRTTI,
+ llvm::ConstantInt::get(CGF.Int32Ty, DestTy->isReferenceType())};
+ Value = CGF.EmitRuntimeCallOrInvoke(Function, Args).getInstruction();
+ return CGF.Builder.CreateBitCast(Value, DestLTy);
+}
+
+llvm::Value *
+MicrosoftCXXABI::EmitDynamicCastToVoid(CodeGenFunction &CGF, llvm::Value *Value,
+ QualType SrcRecordTy,
+ QualType DestTy) {
+ llvm::Value *Offset;
+ std::tie(Value, Offset) = performBaseAdjustment(CGF, Value, SrcRecordTy);
+
+ // PVOID __RTCastToVoid(
+ // PVOID inptr)
+ llvm::Type *ArgTypes[] = {CGF.Int8PtrTy};
+ llvm::Constant *Function = CGF.CGM.CreateRuntimeFunction(
+ llvm::FunctionType::get(CGF.Int8PtrTy, ArgTypes, false),
+ "__RTCastToVoid");
+ llvm::Value *Args[] = {Value};
+ return CGF.EmitRuntimeCall(Function, Args);
+}
+
+bool MicrosoftCXXABI::EmitBadCastCall(CodeGenFunction &CGF) {
+ return false;
+}
+
llvm::Value *
MicrosoftCXXABI::GetVirtualBaseClassOffset(CodeGenFunction &CGF,
llvm::Value *This,
OpenPOWER on IntegriCloud