Revert r211402 (and r211408,r211410), "CodeGen: Refactor dynamic_cast and typeid" It crashes msvc codegen in clang/test/SemaCXX/undefined-internal.cpp.
It is reproducible with: $ clang -cc1 -triple i686-win32 -emit-llvm-only clang/test/SemaCXX/undefined-internal.cpp llvm-svn: 211467
This commit is contained in:
parent
e80af7f3eb
commit
0a6c5e2fb5
|
@ -207,28 +207,6 @@ 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,
|
||||
|
|
|
@ -1615,36 +1615,98 @@ 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.
|
||||
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 =
|
||||
if (const UnaryOperator *UO = dyn_cast<UnaryOperator>(E->IgnoreParens())) {
|
||||
if (UO->getOpcode() == UO_Deref) {
|
||||
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);
|
||||
CGF.CGM.getCXXABI().EmitBadTypeidCall(CGF);
|
||||
CGF.EmitBlock(EndBlock);
|
||||
CGF.EmitBlock(BadTypeidBlock);
|
||||
EmitBadTypeidCall(CGF);
|
||||
CGF.EmitBlock(EndBlock);
|
||||
}
|
||||
}
|
||||
|
||||
return CGF.CGM.getCXXABI().EmitTypeid(CGF, SrcRecordTy, ThisPtr,
|
||||
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);
|
||||
}
|
||||
|
||||
llvm::Value *CodeGenFunction::EmitCXXTypeidExpr(const CXXTypeidExpr *E) {
|
||||
|
@ -1671,6 +1733,173 @@ 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);
|
||||
|
@ -1679,49 +1908,142 @@ static llvm::Value *EmitDynamicCastToNull(CodeGenFunction &CGF,
|
|||
|
||||
/// C++ [expr.dynamic.cast]p9:
|
||||
/// A failed cast to reference type throws std::bad_cast
|
||||
if (!CGF.CGM.getCXXABI().EmitBadCastCall(CGF))
|
||||
return nullptr;
|
||||
EmitBadCastCall(CGF);
|
||||
|
||||
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())
|
||||
if (llvm::Value *T = EmitDynamicCastToNull(*this, DestTy))
|
||||
return T;
|
||||
return EmitDynamicCastToNull(*this, DestTy);
|
||||
|
||||
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 =
|
||||
CGM.getCXXABI().shouldDynamicCastCallBeNullChecked(SrcTy->isPointerType(),
|
||||
SrcRecordTy);
|
||||
bool ShouldNullCheckSrcValue = SrcTy->isPointerType();
|
||||
|
||||
llvm::BasicBlock *CastNull = nullptr;
|
||||
llvm::BasicBlock *CastNotNull = nullptr;
|
||||
|
@ -1736,15 +2058,7 @@ llvm::Value *CodeGenFunction::EmitDynamicCast(llvm::Value *Value,
|
|||
EmitBlock(CastNotNull);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
Value = EmitItaniumDynamicCastCall(*this, Value, SrcTy, DestTy, CastEnd);
|
||||
|
||||
if (ShouldNullCheckSrcValue) {
|
||||
EmitBranch(CastEnd);
|
||||
|
|
|
@ -25,7 +25,6 @@
|
|||
#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"
|
||||
|
@ -109,26 +108,6 @@ 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,
|
||||
|
@ -821,194 +800,6 @@ 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,
|
||||
|
|
|
@ -21,7 +21,6 @@
|
|||
#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;
|
||||
|
@ -57,26 +56,6 @@ 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,
|
||||
|
@ -490,132 +469,6 @@ 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) {
|
||||
const CXXRecordDecl *RD = SrcRecordTy->getAsCXXRecordDecl();
|
||||
llvm::Value *CastPtr = CGF.Builder.CreateBitCast(ThisPtr, CGF.Int8PtrTy);
|
||||
llvm::Value *AdjustedThisPtr = CGF.Builder.CreateInBoundsGEP(
|
||||
CastPtr, getPolymorphicOffset(CGF, RD, CastPtr));
|
||||
return CGF.Builder.CreateBitCast(
|
||||
emitRTtypeidCall(CGF, AdjustedThisPtr).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,
|
||||
|
|
|
@ -1,130 +1,158 @@
|
|||
// RUN: %clang_cc1 -emit-llvm -O1 -o - -triple=i386-pc-win32 %s | FileCheck %s
|
||||
// RUN: %clang_cc1 -emit-llvm -O2 -optzns -o - -triple=i386-pc-win32 2>/dev/null %s | FileCheck %s
|
||||
// REQUIRES: asserts
|
||||
|
||||
struct S { char a; };
|
||||
struct V { virtual void f(); };
|
||||
struct V { virtual void f(){} };
|
||||
struct A : virtual V {};
|
||||
struct B : S, virtual V {};
|
||||
struct T {};
|
||||
|
||||
T* test0() { return dynamic_cast<T*>((B*)0); }
|
||||
// CHECK-LABEL: define noalias %struct.T* @"\01?test0@@YAPAUT@@XZ"()
|
||||
// CHECK: ret %struct.T* null
|
||||
// CHECK: define noalias %struct.T* @"\01?test0@@YAPAUT@@XZ"() #0 {
|
||||
// CHECK-NEXT: entry:
|
||||
// CHECK-NEXT: ret %struct.T* null
|
||||
// CHECK-NEXT: }
|
||||
|
||||
T* test1(V* x) { return &dynamic_cast<T&>(*x); }
|
||||
// CHECK-LABEL: define %struct.T* @"\01?test1@@YAPAUT@@PAUV@@@Z"(%struct.V* %x)
|
||||
// CHECK: [[CAST:%.*]] = bitcast %struct.V* %x to i8*
|
||||
// CHECK-NEXT: [[CALL:%.*]] = tail call i8* @__RTDynamicCast(i8* [[CAST]], i32 0, i8* bitcast (%"MSRTTITypeDescriptor\07"* @"\01??_R0?AUV@@@8" to i8*), i8* bitcast (%"MSRTTITypeDescriptor\07"* @"\01??_R0?AUT@@@8" to i8*), i32 1)
|
||||
// CHECK-NEXT: [[RET:%.*]] = bitcast i8* [[CALL]] to %struct.T*
|
||||
// CHECK-NEXT: ret %struct.T* [[RET]]
|
||||
// CHECK: define %struct.T* @"\01?test1@@YAPAUT@@PAUV@@@Z"(%struct.V* %x) #1 {
|
||||
// CHECK-NEXT: entry:
|
||||
// CHECK-NEXT: %0 = bitcast %struct.V* %x to i8*
|
||||
// CHECK-NEXT: %1 = tail call i8* @__RTDynamicCast(i8* %0, i32 0, i8* bitcast (%"MSRTTITypeDescriptor\07"* @"\01??_R0?AUV@@@8" to i8*), i8* bitcast (%"MSRTTITypeDescriptor\07"* @"\01??_R0?AUT@@@8" to i8*), i32 1) #2
|
||||
// CHECK-NEXT: %2 = bitcast i8* %1 to %struct.T*
|
||||
// CHECK-NEXT: ret %struct.T* %2
|
||||
// CHECK-NEXT: }
|
||||
|
||||
T* test2(A* x) { return &dynamic_cast<T&>(*x); }
|
||||
// CHECK-LABEL: define %struct.T* @"\01?test2@@YAPAUT@@PAUA@@@Z"(%struct.A* %x)
|
||||
// CHECK: [[CAST:%.*]] = bitcast %struct.A* %x to i8*
|
||||
// CHECK-NEXT: [[BITCAST:%.*]] = bitcast %struct.A* %x to i8**
|
||||
// CHECK-NEXT: [[VBTBL:%.*]] = load i8** [[BITCAST]], align 4
|
||||
// CHECK-NEXT: [[VBOFFP:%.*]] = getelementptr inbounds i8* [[VBTBL]], i32 4
|
||||
// CHECK-NEXT: [[VBOFFPCAST:%.*]] = bitcast i8* [[VBOFFP]] to i32*
|
||||
// CHECK-NEXT: [[VBOFFS:%.*]] = load i32* [[VBOFFPCAST]], align 4
|
||||
// CHECK-NEXT: [[ADJ:%.*]] = getelementptr inbounds i8* [[CAST]], i32 [[VBOFFS]]
|
||||
// CHECK-NEXT: [[CALL:%.*]] = tail call i8* @__RTDynamicCast(i8* [[ADJ]], i32 [[VBOFFS]], i8* bitcast (%"MSRTTITypeDescriptor\07"* @"\01??_R0?AUA@@@8" to i8*), i8* bitcast (%"MSRTTITypeDescriptor\07"* @"\01??_R0?AUT@@@8" to i8*), i32 1)
|
||||
// CHECK-NEXT: [[RET:%.*]] = bitcast i8* [[CALL]] to %struct.T*
|
||||
// CHECK-NEXT: ret %struct.T* [[RET]]
|
||||
// CHECK: define %struct.T* @"\01?test2@@YAPAUT@@PAUA@@@Z"(%struct.A* %x) #1 {
|
||||
// CHECK-NEXT: entry:
|
||||
// CHECK-NEXT: %0 = bitcast %struct.A* %x to i8*
|
||||
// CHECK-NEXT: %1 = bitcast %struct.A* %x to i8**
|
||||
// CHECK-NEXT: %vbtable = load i8** %1, align 4
|
||||
// CHECK-NEXT: %2 = getelementptr inbounds i8* %vbtable, i32 4
|
||||
// CHECK-NEXT: %3 = bitcast i8* %2 to i32*
|
||||
// CHECK-NEXT: %vbase_offs = load i32* %3, align 4
|
||||
// CHECK-NEXT: %4 = getelementptr inbounds i8* %0, i32 %vbase_offs
|
||||
// CHECK-NEXT: %5 = tail call i8* @__RTDynamicCast(i8* %4, i32 %vbase_offs, i8* bitcast (%"MSRTTITypeDescriptor\07"* @"\01??_R0?AUA@@@8" to i8*), i8* bitcast (%"MSRTTITypeDescriptor\07"* @"\01??_R0?AUT@@@8" to i8*), i32 1) #2
|
||||
// CHECK-NEXT: %6 = bitcast i8* %5 to %struct.T*
|
||||
// CHECK-NEXT: ret %struct.T* %6
|
||||
// CHECK-NEXT: }
|
||||
|
||||
T* test3(B* x) { return &dynamic_cast<T&>(*x); }
|
||||
// CHECK-LABEL: define %struct.T* @"\01?test3@@YAPAUT@@PAUB@@@Z"(%struct.B* %x)
|
||||
// CHECK: [[VOIDP:%.*]] = getelementptr inbounds %struct.B* %x, i32 0, i32 0, i32 0
|
||||
// CHECK-NEXT: [[VBPTR:%.*]] = getelementptr inbounds i8* [[VOIDP]], i32 4
|
||||
// CHECK-NEXT: [[BITCAST:%.*]] = bitcast i8* [[VBPTR:%.*]] to i8**
|
||||
// CHECK-NEXT: [[VBTBL:%.*]] = load i8** [[BITCAST]], align 4
|
||||
// CHECK-NEXT: [[VBOFFP:%.*]] = getelementptr inbounds i8* [[VBTBL]], i32 4
|
||||
// CHECK-NEXT: [[VBOFFPCAST:%.*]] = bitcast i8* [[VBOFFP]] to i32*
|
||||
// CHECK-NEXT: [[VBOFFS:%.*]] = load i32* [[VBOFFPCAST]], align 4
|
||||
// CHECK-NEXT: [[DELTA:%.*]] = add nsw i32 [[VBOFFS]], 4
|
||||
// CHECK-NEXT: [[ADJ:%.*]] = getelementptr inbounds i8* [[VOIDP]], i32 [[DELTA]]
|
||||
// CHECK-NEXT: [[CALL:%.*]] = tail call i8* @__RTDynamicCast(i8* [[ADJ]], i32 [[DELTA]], i8* bitcast (%"MSRTTITypeDescriptor\07"* @"\01??_R0?AUB@@@8" to i8*), i8* bitcast (%"MSRTTITypeDescriptor\07"* @"\01??_R0?AUT@@@8" to i8*), i32 1)
|
||||
// CHECK-NEXT: [[RET:%.*]] = bitcast i8* [[CALL]] to %struct.T*
|
||||
// CHECK-NEXT: ret %struct.T* [[RET]]
|
||||
// CHECK: define %struct.T* @"\01?test3@@YAPAUT@@PAUB@@@Z"(%struct.B* %x) #1 {
|
||||
// CHECK-NEXT: entry:
|
||||
// CHECK-NEXT: %0 = getelementptr inbounds %struct.B* %x, i32 0, i32 0, i32 0
|
||||
// CHECK-NEXT: %vbptr = getelementptr inbounds i8* %0, i32 4
|
||||
// CHECK-NEXT: %1 = bitcast i8* %vbptr to i8**
|
||||
// CHECK-NEXT: %vbtable = load i8** %1, align 4
|
||||
// CHECK-NEXT: %2 = getelementptr inbounds i8* %vbtable, i32 4
|
||||
// CHECK-NEXT: %3 = bitcast i8* %2 to i32*
|
||||
// CHECK-NEXT: %vbase_offs = load i32* %3, align 4
|
||||
// CHECK-NEXT: %4 = add nsw i32 %vbase_offs, 4
|
||||
// CHECK-NEXT: %5 = getelementptr inbounds i8* %0, i32 %4
|
||||
// CHECK-NEXT: %6 = tail call i8* @__RTDynamicCast(i8* %5, i32 %4, i8* bitcast (%"MSRTTITypeDescriptor\07"* @"\01??_R0?AUB@@@8" to i8*), i8* bitcast (%"MSRTTITypeDescriptor\07"* @"\01??_R0?AUT@@@8" to i8*), i32 1) #2
|
||||
// CHECK-NEXT: %7 = bitcast i8* %6 to %struct.T*
|
||||
// CHECK-NEXT: ret %struct.T* %7
|
||||
// CHECK-NEXT: }
|
||||
|
||||
T* test4(V* x) { return dynamic_cast<T*>(x); }
|
||||
// CHECK-LABEL: define %struct.T* @"\01?test4@@YAPAUT@@PAUV@@@Z"(%struct.V* %x)
|
||||
// CHECK: [[CAST:%.*]] = bitcast %struct.V* %x to i8*
|
||||
// CHECK-NEXT: [[CALL:%.*]] = tail call i8* @__RTDynamicCast(i8* [[CAST]], i32 0, i8* bitcast (%"MSRTTITypeDescriptor\07"* @"\01??_R0?AUV@@@8" to i8*), i8* bitcast (%"MSRTTITypeDescriptor\07"* @"\01??_R0?AUT@@@8" to i8*), i32 0)
|
||||
// CHECK-NEXT: [[RET:%.*]] = bitcast i8* [[CALL]] to %struct.T*
|
||||
// CHECK-NEXT: ret %struct.T* [[RET]]
|
||||
// CHECK: define %struct.T* @"\01?test4@@YAPAUT@@PAUV@@@Z"(%struct.V* %x) #1 {
|
||||
// CHECK-NEXT: entry:
|
||||
// CHECK-NEXT: %0 = bitcast %struct.V* %x to i8*
|
||||
// CHECK-NEXT: %1 = tail call i8* @__RTDynamicCast(i8* %0, i32 0, i8* bitcast (%"MSRTTITypeDescriptor\07"* @"\01??_R0?AUV@@@8" to i8*), i8* bitcast (%"MSRTTITypeDescriptor\07"* @"\01??_R0?AUT@@@8" to i8*), i32 0) #2
|
||||
// CHECK-NEXT: %2 = bitcast i8* %1 to %struct.T*
|
||||
// CHECK-NEXT: ret %struct.T* %2
|
||||
// CHECK-NEXT: }
|
||||
|
||||
T* test5(A* x) { return dynamic_cast<T*>(x); }
|
||||
// CHECK-LABEL: define %struct.T* @"\01?test5@@YAPAUT@@PAUA@@@Z"(%struct.A* %x)
|
||||
// CHECK: [[CHECK:%.*]] = icmp eq %struct.A* %x, null
|
||||
// CHECK-NEXT: br i1 [[CHECK]]
|
||||
// CHECK: [[VOIDP:%.*]] = bitcast %struct.A* %x to i8*
|
||||
// CHECK-NEXT: [[BITCAST:%.*]] = bitcast %struct.A* %x to i8**
|
||||
// CHECK-NEXT: [[VBTBL:%.*]] = load i8** [[BITCAST]], align 4
|
||||
// CHECK-NEXT: [[VBOFFP:%.*]] = getelementptr inbounds i8* [[VBTBL]], i32 4
|
||||
// CHECK-NEXT: [[VBOFFPCAST:%.*]] = bitcast i8* [[VBOFFP]] to i32*
|
||||
// CHECK-NEXT: [[VBOFFS:%.*]] = load i32* [[VBOFFPCAST:%.*]], align 4
|
||||
// CHECK-NEXT: [[ADJ:%.*]] = getelementptr inbounds i8* [[VOIDP]], i32 [[VBOFFS]]
|
||||
// CHECK-NEXT: [[CALL:%.*]] = tail call i8* @__RTDynamicCast(i8* [[ADJ]], i32 [[VBOFFS]], i8* bitcast (%"MSRTTITypeDescriptor\07"* @"\01??_R0?AUA@@@8" to i8*), i8* bitcast (%"MSRTTITypeDescriptor\07"* @"\01??_R0?AUT@@@8" to i8*), i32 0)
|
||||
// CHECK-NEXT: [[RES:%.*]] = bitcast i8* [[CALL]] to %struct.T*
|
||||
// CHECK-NEXT: br label
|
||||
// CHECK: [[RET:%.*]] = phi %struct.T*
|
||||
// CHECK-NEXT: ret %struct.T* [[RET]]
|
||||
// CHECK: define %struct.T* @"\01?test5@@YAPAUT@@PAUA@@@Z"(%struct.A* %x) #1 {
|
||||
// CHECK-NEXT: entry:
|
||||
// CHECK-NEXT: %0 = icmp eq %struct.A* %x, null
|
||||
// CHECK-NEXT: br i1 %0, label %dynamic_cast.call, label %dynamic_cast.valid
|
||||
// CHECK: dynamic_cast.valid: ; preds = %entry
|
||||
// CHECK-NEXT: %1 = bitcast %struct.A* %x to i8*
|
||||
// CHECK-NEXT: %2 = bitcast %struct.A* %x to i8**
|
||||
// CHECK-NEXT: %vbtable = load i8** %2, align 4
|
||||
// CHECK-NEXT: %3 = getelementptr inbounds i8* %vbtable, i32 4
|
||||
// CHECK-NEXT: %4 = bitcast i8* %3 to i32*
|
||||
// CHECK-NEXT: %vbase_offs = load i32* %4, align 4
|
||||
// CHECK-NEXT: %5 = getelementptr inbounds i8* %1, i32 %vbase_offs
|
||||
// CHECK-NEXT: %6 = tail call i8* @__RTDynamicCast(i8* %5, i32 %vbase_offs, i8* bitcast (%"MSRTTITypeDescriptor\07"* @"\01??_R0?AUA@@@8" to i8*), i8* bitcast (%"MSRTTITypeDescriptor\07"* @"\01??_R0?AUT@@@8" to i8*), i32 0) #2
|
||||
// CHECK-NEXT: %phitmp = bitcast i8* %6 to %struct.T*
|
||||
// CHECK-NEXT: br label %dynamic_cast.call
|
||||
// CHECK: dynamic_cast.call: ; preds = %dynamic_cast.valid, %entry
|
||||
// CHECK-NEXT: %7 = phi %struct.T* [ %phitmp, %dynamic_cast.valid ], [ null, %entry ]
|
||||
// CHECK-NEXT: ret %struct.T* %7
|
||||
// CHECK-NEXT: }
|
||||
|
||||
T* test6(B* x) { return dynamic_cast<T*>(x); }
|
||||
// CHECK-LABEL: define %struct.T* @"\01?test6@@YAPAUT@@PAUB@@@Z"(%struct.B* %x)
|
||||
// CHECK: [[CHECK:%.*]] = icmp eq %struct.B* %x, null
|
||||
// CHECK-NEXT: br i1 [[CHECK]]
|
||||
// CHECK: [[CAST:%.*]] = getelementptr inbounds %struct.B* %x, i32 0, i32 0, i32 0
|
||||
// CHECK-NEXT: [[VBPTR:%.*]] = getelementptr inbounds i8* [[CAST]], i32 4
|
||||
// CHECK-NEXT: [[BITCAST:%.*]] = bitcast i8* [[VBPTR]] to i8**
|
||||
// CHECK-NEXT: [[VBTBL:%.*]] = load i8** [[BITCAST]], align 4
|
||||
// CHECK-NEXT: [[VBOFFP:%.*]] = getelementptr inbounds i8* [[VBTBL]], i32 4
|
||||
// CHECK-NEXT: [[VBOFFPCAST:%.*]] = bitcast i8* [[VBOFFP]] to i32*
|
||||
// CHECK-NEXT: [[VBOFFS:%.*]] = load i32* [[VBOFFPCAST:%.*]], align 4
|
||||
// CHECK-NEXT: [[DELTA:%.*]] = add nsw i32 [[VBOFFS]], 4
|
||||
// CHECK-NEXT: [[ADJ:%.*]] = getelementptr inbounds i8* [[CAST]], i32 [[DELTA]]
|
||||
// CHECK-NEXT: [[CALL:%.*]] = tail call i8* @__RTDynamicCast(i8* [[ADJ]], i32 [[DELTA]], i8* bitcast (%"MSRTTITypeDescriptor\07"* @"\01??_R0?AUB@@@8" to i8*), i8* bitcast (%"MSRTTITypeDescriptor\07"* @"\01??_R0?AUT@@@8" to i8*), i32 0)
|
||||
// CHECK-NEXT: [[RES:%.*]] = bitcast i8* [[CALL]] to %struct.T*
|
||||
// CHECK-NEXT: br label
|
||||
// CHECK: [[RET:%.*]] = phi %struct.T*
|
||||
// CHECK-NEXT: ret %struct.T* [[RET]]
|
||||
// CHECK: define %struct.T* @"\01?test6@@YAPAUT@@PAUB@@@Z"(%struct.B* %x) #1 {
|
||||
// CHECK-NEXT: entry:
|
||||
// CHECK-NEXT: %0 = icmp eq %struct.B* %x, null
|
||||
// CHECK-NEXT: br i1 %0, label %dynamic_cast.call, label %dynamic_cast.valid
|
||||
// CHECK: dynamic_cast.valid: ; preds = %entry
|
||||
// CHECK-NEXT: %1 = getelementptr inbounds %struct.B* %x, i32 0, i32 0, i32 0
|
||||
// CHECK-NEXT: %vbptr = getelementptr inbounds i8* %1, i32 4
|
||||
// CHECK-NEXT: %2 = bitcast i8* %vbptr to i8**
|
||||
// CHECK-NEXT: %vbtable = load i8** %2, align 4
|
||||
// CHECK-NEXT: %3 = getelementptr inbounds i8* %vbtable, i32 4
|
||||
// CHECK-NEXT: %4 = bitcast i8* %3 to i32*
|
||||
// CHECK-NEXT: %vbase_offs = load i32* %4, align 4
|
||||
// CHECK-NEXT: %5 = add nsw i32 %vbase_offs, 4
|
||||
// CHECK-NEXT: %6 = getelementptr inbounds i8* %1, i32 %5
|
||||
// CHECK-NEXT: %7 = tail call i8* @__RTDynamicCast(i8* %6, i32 %5, i8* bitcast (%"MSRTTITypeDescriptor\07"* @"\01??_R0?AUB@@@8" to i8*), i8* bitcast (%"MSRTTITypeDescriptor\07"* @"\01??_R0?AUT@@@8" to i8*), i32 0) #2
|
||||
// CHECK-NEXT: %phitmp = bitcast i8* %7 to %struct.T*
|
||||
// CHECK-NEXT: br label %dynamic_cast.call
|
||||
// CHECK: dynamic_cast.call: ; preds = %dynamic_cast.valid, %entry
|
||||
// CHECK-NEXT: %8 = phi %struct.T* [ %phitmp, %dynamic_cast.valid ], [ null, %entry ]
|
||||
// CHECK-NEXT: ret %struct.T* %8
|
||||
// CHECK-NEXT: }
|
||||
|
||||
void* test7(V* x) { return dynamic_cast<void*>(x); }
|
||||
// CHECK-LABEL: define i8* @"\01?test7@@YAPAXPAUV@@@Z"(%struct.V* %x)
|
||||
// CHECK: [[CAST:%.*]] = bitcast %struct.V* %x to i8*
|
||||
// CHECK-NEXT: [[RET:%.*]] = tail call i8* @__RTCastToVoid(i8* [[CAST]])
|
||||
// CHECK-NEXT: ret i8* [[RET]]
|
||||
// CHECK: define i8* @"\01?test7@@YAPAXPAUV@@@Z"(%struct.V* %x) #1 {
|
||||
// CHECK-NEXT: entry:
|
||||
// CHECK-NEXT: %0 = bitcast %struct.V* %x to i8*
|
||||
// CHECK-NEXT: %1 = tail call i8* @__RTCastToVoid(i8* %0) #2
|
||||
// CHECK-NEXT: ret i8* %1
|
||||
// CHECK-NEXT: }
|
||||
|
||||
void* test8(A* x) { return dynamic_cast<void*>(x); }
|
||||
// CHECK-LABEL: define i8* @"\01?test8@@YAPAXPAUA@@@Z"(%struct.A* %x)
|
||||
// CHECK: [[CHECK:%.*]] = icmp eq %struct.A* %x, null
|
||||
// CHECK-NEXT: br i1 [[CHECK]]
|
||||
// CHECK: [[VOIDP:%.*]] = bitcast %struct.A* %x to i8*
|
||||
// CHECK-NEXT: [[BITCAST:%.*]] = bitcast %struct.A* %x to i8**
|
||||
// CHECK-NEXT: [[VBTBL:%.*]] = load i8** [[BITCAST]], align 4
|
||||
// CHECK-NEXT: [[VBOFFP:%.*]] = getelementptr inbounds i8* [[VBTBL]], i32 4
|
||||
// CHECK-NEXT: [[VBOFFPCAST:%.*]] = bitcast i8* [[VBOFFP]] to i32*
|
||||
// CHECK-NEXT: [[VBOFFS:%.*]] = load i32* [[VBOFFPCAST:%.*]], align 4
|
||||
// CHECK-NEXT: [[ADJ:%.*]] = getelementptr inbounds i8* [[VOIDP]], i32 [[VBOFFS]]
|
||||
// CHECK-NEXT: [[RES:%.*]] = tail call i8* @__RTCastToVoid(i8* [[ADJ]])
|
||||
// CHECK-NEXT: br label
|
||||
// CHECK: [[RET:%.*]] = phi i8*
|
||||
// CHECK-NEXT: ret i8* [[RET]]
|
||||
// CHECK: define i8* @"\01?test8@@YAPAXPAUA@@@Z"(%struct.A* %x) #1 {
|
||||
// CHECK-NEXT: entry:
|
||||
// CHECK-NEXT: %0 = icmp eq %struct.A* %x, null
|
||||
// CHECK-NEXT: br i1 %0, label %dynamic_cast.call, label %dynamic_cast.valid
|
||||
// CHECK: dynamic_cast.valid: ; preds = %entry
|
||||
// CHECK-NEXT: %1 = bitcast %struct.A* %x to i8*
|
||||
// CHECK-NEXT: %2 = bitcast %struct.A* %x to i8**
|
||||
// CHECK-NEXT: %vbtable = load i8** %2, align 4
|
||||
// CHECK-NEXT: %3 = getelementptr inbounds i8* %vbtable, i32 4
|
||||
// CHECK-NEXT: %4 = bitcast i8* %3 to i32*
|
||||
// CHECK-NEXT: %vbase_offs = load i32* %4, align 4
|
||||
// CHECK-NEXT: %5 = getelementptr inbounds i8* %1, i32 %vbase_offs
|
||||
// CHECK-NEXT: %6 = tail call i8* @__RTCastToVoid(i8* %5) #2
|
||||
// CHECK-NEXT: br label %dynamic_cast.call
|
||||
// CHECK: dynamic_cast.call: ; preds = %dynamic_cast.valid, %entry
|
||||
// CHECK-NEXT: %7 = phi i8* [ %6, %dynamic_cast.valid ], [ null, %entry ]
|
||||
// CHECK-NEXT: ret i8* %7
|
||||
// CHECK-NEXT: }
|
||||
|
||||
void* test9(B* x) { return dynamic_cast<void*>(x); }
|
||||
// CHECK-LABEL: define i8* @"\01?test9@@YAPAXPAUB@@@Z"(%struct.B* %x)
|
||||
// CHECK: [[CHECK:%.*]] = icmp eq %struct.B* %x, null
|
||||
// CHECK-NEXT: br i1 [[CHECK]]
|
||||
// CHECK: [[CAST:%.*]] = getelementptr inbounds %struct.B* %x, i32 0, i32 0, i32 0
|
||||
// CHECK-NEXT: [[VBPTR:%.*]] = getelementptr inbounds i8* [[CAST]], i32 4
|
||||
// CHECK-NEXT: [[BITCAST:%.*]] = bitcast i8* [[VBPTR]] to i8**
|
||||
// CHECK-NEXT: [[VBTBL:%.*]] = load i8** [[BITCAST]], align 4
|
||||
// CHECK-NEXT: [[VBOFFP:%.*]] = getelementptr inbounds i8* [[VBTBL]], i32 4
|
||||
// CHECK-NEXT: [[VBOFFPCAST:%.*]] = bitcast i8* [[VBOFFP]] to i32*
|
||||
// CHECK-NEXT: [[VBOFFS:%.*]] = load i32* [[VBOFFPCAST:%.*]], align 4
|
||||
// CHECK-NEXT: [[DELTA:%.*]] = add nsw i32 [[VBOFFS]], 4
|
||||
// CHECK-NEXT: [[ADJ:%.*]] = getelementptr inbounds i8* [[CAST]], i32 [[DELTA]]
|
||||
// CHECK-NEXT: [[CALL:%.*]] = tail call i8* @__RTCastToVoid(i8* [[ADJ]])
|
||||
// CHECK-NEXT: br label
|
||||
// CHECK: [[RET:%.*]] = phi i8*
|
||||
// CHECK-NEXT: ret i8* [[RET]]
|
||||
|
||||
// CHECK: define i8* @"\01?test9@@YAPAXPAUB@@@Z"(%struct.B* %x) #1 {
|
||||
// CHECK-NEXT: entry:
|
||||
// CHECK-NEXT: %0 = icmp eq %struct.B* %x, null
|
||||
// CHECK-NEXT: br i1 %0, label %dynamic_cast.call, label %dynamic_cast.valid
|
||||
// CHECK: dynamic_cast.valid: ; preds = %entry
|
||||
// CHECK-NEXT: %1 = getelementptr inbounds %struct.B* %x, i32 0, i32 0, i32 0
|
||||
// CHECK-NEXT: %vbptr = getelementptr inbounds i8* %1, i32 4
|
||||
// CHECK-NEXT: %2 = bitcast i8* %vbptr to i8**
|
||||
// CHECK-NEXT: %vbtable = load i8** %2, align 4
|
||||
// CHECK-NEXT: %3 = getelementptr inbounds i8* %vbtable, i32 4
|
||||
// CHECK-NEXT: %4 = bitcast i8* %3 to i32*
|
||||
// CHECK-NEXT: %vbase_offs = load i32* %4, align 4
|
||||
// CHECK-NEXT: %5 = add nsw i32 %vbase_offs, 4
|
||||
// CHECK-NEXT: %6 = getelementptr inbounds i8* %1, i32 %5
|
||||
// CHECK-NEXT: %7 = tail call i8* @__RTCastToVoid(i8* %6) #2
|
||||
// CHECK-NEXT: br label %dynamic_cast.call
|
||||
// CHECK: dynamic_cast.call: ; preds = %dynamic_cast.valid, %entry
|
||||
// CHECK-NEXT: %8 = phi i8* [ %7, %dynamic_cast.valid ], [ null, %entry ]
|
||||
// CHECK-NEXT: ret i8* %8
|
||||
// CHECK-NEXT: }
|
||||
|
|
|
@ -1,45 +1,58 @@
|
|||
// RUN: %clang_cc1 -emit-llvm -O1 -o - -triple=i386-pc-win32 %s | FileCheck %s
|
||||
// RUN: %clang_cc1 -emit-llvm -O2 -optzns -o - -triple=i386-pc-win32 2>/dev/null %s | FileCheck %s
|
||||
// REQUIRES: asserts
|
||||
|
||||
struct type_info;
|
||||
struct type_info { const char* raw_name() const; };
|
||||
namespace std { using ::type_info; }
|
||||
|
||||
struct V { virtual void f(); };
|
||||
struct A : virtual V { A(); };
|
||||
struct V { virtual void f() {}; };
|
||||
struct A : virtual V {};
|
||||
|
||||
extern A a;
|
||||
extern int b;
|
||||
A a;
|
||||
int b;
|
||||
A* fn();
|
||||
|
||||
const std::type_info* test0_typeid() { return &typeid(int); }
|
||||
// CHECK-LABEL: define %struct.type_info* @"\01?test0_typeid@@YAPBUtype_info@@XZ"()
|
||||
// CHECK: ret %struct.type_info* bitcast (%"MSRTTITypeDescriptor\02"* @"\01??_R0H@8" to %struct.type_info*)
|
||||
// CHECK: define %struct.type_info* @"\01?test0_typeid@@YAPBUtype_info@@XZ"() #0 {
|
||||
// CHECK-NEXT: entry:
|
||||
// CHECK-NEXT: ret %struct.type_info* bitcast (%"MSRTTITypeDescriptor\02"* @"\01??_R0H@8" to %struct.type_info*)
|
||||
// CHECK-NEXT: }
|
||||
|
||||
const std::type_info* test1_typeid() { return &typeid(A); }
|
||||
// CHECK-LABEL: define %struct.type_info* @"\01?test1_typeid@@YAPBUtype_info@@XZ"()
|
||||
// CHECK: ret %struct.type_info* bitcast (%"MSRTTITypeDescriptor\07"* @"\01??_R0?AUA@@@8" to %struct.type_info*)
|
||||
// CHECK: define %struct.type_info* @"\01?test1_typeid@@YAPBUtype_info@@XZ"() #0 {
|
||||
// CHECK-NEXT: entry:
|
||||
// CHECK-NEXT: ret %struct.type_info* bitcast (%"MSRTTITypeDescriptor\07"* @"\01??_R0?AUA@@@8" to %struct.type_info*)
|
||||
// CHECK-NEXT: }
|
||||
|
||||
const std::type_info* test2_typeid() { return &typeid(&a); }
|
||||
// CHECK-LABEL: define %struct.type_info* @"\01?test2_typeid@@YAPBUtype_info@@XZ"()
|
||||
// CHECK: ret %struct.type_info* bitcast (%"MSRTTITypeDescriptor\07"* @"\01??_R0PAUA@@@8" to %struct.type_info*)
|
||||
// CHECK: define %struct.type_info* @"\01?test2_typeid@@YAPBUtype_info@@XZ"() #0 {
|
||||
// CHECK-NEXT: entry:
|
||||
// CHECK-NEXT: ret %struct.type_info* bitcast (%"MSRTTITypeDescriptor\07"* @"\01??_R0PAUA@@@8" to %struct.type_info*)
|
||||
// CHECK-NEXT: }
|
||||
|
||||
const std::type_info* test3_typeid() { return &typeid(*fn()); }
|
||||
// CHECK-LABEL: define %struct.type_info* @"\01?test3_typeid@@YAPBUtype_info@@XZ"()
|
||||
// CHECK: [[CALL:%.*]] = tail call %struct.A* @"\01?fn@@YAPAUA@@XZ"()
|
||||
// CHECK-NEXT: [[CMP:%.*]] = icmp eq %struct.A* [[CALL]], null
|
||||
// CHECK-NEXT: br i1 [[CMP]]
|
||||
// CHECK: tail call i8* @__RTtypeid(i8* null)
|
||||
// CHECK-NEXT: unreachable
|
||||
// CHECK: [[THIS:%.*]] = bitcast %struct.A* [[CALL]] to i8*
|
||||
// CHECK-NEXT: [[VBTBLP:%.*]] = bitcast %struct.A* [[CALL]] to i8**
|
||||
// CHECK-NEXT: [[VBTBL:%.*]] = load i8** [[VBTBLP]], align 4
|
||||
// CHECK-NEXT: [[VBSLOT:%.*]] = getelementptr inbounds i8* [[VBTBL]], i32 4
|
||||
// CHECK-NEXT: [[VBITCST:%.*]] = bitcast i8* [[VBSLOT]] to i32*
|
||||
// CHECK-NEXT: [[VBASE_OFFS:%.*]] = load i32* [[VBITCST]], align 4
|
||||
// CHECK-NEXT: [[ADJ:%.*]] = getelementptr inbounds i8* [[THIS]], i32 [[VBASE_OFFS]]
|
||||
// CHECK-NEXT: [[RT:%.*]] = tail call i8* @__RTtypeid(i8* [[ADJ]])
|
||||
// CHECK-NEXT: [[RET:%.*]] = bitcast i8* [[RT]] to %struct.type_info*
|
||||
// CHECK-NEXT: ret %struct.type_info* [[RET]]
|
||||
// CHECK: define %struct.type_info* @"\01?test3_typeid@@YAPBUtype_info@@XZ"() #1 {
|
||||
// CHECK-NEXT: entry:
|
||||
// CHECK-NEXT: %call = tail call %struct.A* @"\01?fn@@YAPAUA@@XZ"() #3
|
||||
// CHECK-NEXT: %0 = icmp eq %struct.A* %call, null
|
||||
// CHECK-NEXT: br i1 %0, label %type_id.call, label %type_id.valid
|
||||
// CHECK: type_id.valid: ; preds = %entry
|
||||
// CHECK-NEXT: %1 = bitcast %struct.A* %call to i8*
|
||||
// CHECK-NEXT: %2 = bitcast %struct.A* %call to i8**
|
||||
// CHECK-NEXT: %vbtable = load i8** %2, align 4
|
||||
// CHECK-NEXT: %3 = getelementptr inbounds i8* %vbtable, i32 4
|
||||
// CHECK-NEXT: %4 = bitcast i8* %3 to i32*
|
||||
// CHECK-NEXT: %vbase_offs = load i32* %4, align 4
|
||||
// CHECK-NEXT: %5 = getelementptr inbounds i8* %1, i32 %vbase_offs
|
||||
// CHECK-NEXT: br label %type_id.call
|
||||
// CHECK: type_id.call: ; preds = %type_id.valid, %entry
|
||||
// CHECK-NEXT: %6 = phi i8* [ %5, %type_id.valid ], [ null, %entry ]
|
||||
// CHECK-NEXT: %7 = tail call i8* @__RTtypeid(i8* %6) #3
|
||||
// CHECK-NEXT: %8 = bitcast i8* %7 to %struct.type_info*
|
||||
// CHECK-NEXT: ret %struct.type_info* %8
|
||||
// CHECK-NEXT: }
|
||||
|
||||
const std::type_info* test4_typeid() { return &typeid(b); }
|
||||
// CHECK: define %struct.type_info* @"\01?test4_typeid@@YAPBUtype_info@@XZ"()
|
||||
// CHECK: ret %struct.type_info* bitcast (%"MSRTTITypeDescriptor\02"* @"\01??_R0H@8" to %struct.type_info*)
|
||||
// CHECK: define %struct.type_info* @"\01?test4_typeid@@YAPBUtype_info@@XZ"() #0 {
|
||||
// CHECK-NEXT: entry:
|
||||
// CHECK-NEXT: ret %struct.type_info* bitcast (%"MSRTTITypeDescriptor\02"* @"\01??_R0H@8" to %struct.type_info*)
|
||||
// CHECK-NEXT: }
|
||||
|
|
Loading…
Reference in New Issue