r211467 - Revert r211402 (and r211408, r211410), "CodeGen: Refactor dynamic_cast and typeid" It crashes msvc codegen in clang/test/SemaCXX/undefined-internal.cpp.
David Majnemer
david.majnemer at gmail.com
Sun Jun 22 12:14:30 PDT 2014
Thanks, fixed in r211473.
On Sun, Jun 22, 2014 at 12:42 PM, NAKAMURA Takumi <geek4civic at gmail.com>
wrote:
> Author: chapuni
> Date: Sun Jun 22 07:42:29 2014
> New Revision: 211467
>
> URL: http://llvm.org/viewvc/llvm-project?rev=211467&view=rev
> Log:
> 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
>
> Modified:
> cfe/trunk/lib/CodeGen/CGCXXABI.h
> cfe/trunk/lib/CodeGen/CGExprCXX.cpp
> cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp
> cfe/trunk/lib/CodeGen/MicrosoftCXXABI.cpp
> cfe/trunk/test/CodeGenCXX/microsoft-abi-dynamic-cast.cpp
> cfe/trunk/test/CodeGenCXX/microsoft-abi-typeid.cpp
>
> Modified: cfe/trunk/lib/CodeGen/CGCXXABI.h
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGCXXABI.h?rev=211467&r1=211466&r2=211467&view=diff
>
> ==============================================================================
> --- cfe/trunk/lib/CodeGen/CGCXXABI.h (original)
> +++ cfe/trunk/lib/CodeGen/CGCXXABI.h Sun Jun 22 07:42:29 2014
> @@ -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,
>
> Modified: cfe/trunk/lib/CodeGen/CGExprCXX.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGExprCXX.cpp?rev=211467&r1=211466&r2=211467&view=diff
>
> ==============================================================================
> --- cfe/trunk/lib/CodeGen/CGExprCXX.cpp (original)
> +++ cfe/trunk/lib/CodeGen/CGExprCXX.cpp Sun Jun 22 07:42:29 2014
> @@ -1615,36 +1615,98 @@ void CodeGenFunction::EmitCXXDeleteExpr(
> 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::EmitCXXTyp
> 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 *EmitDynamicCastToNul
>
> /// 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::EmitDynami
> 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);
>
> Modified: cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp?rev=211467&r1=211466&r2=211467&view=diff
>
> ==============================================================================
> --- cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp (original)
> +++ cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp Sun Jun 22 07:42:29 2014
> @@ -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::adjustToComp
> 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,
>
> Modified: cfe/trunk/lib/CodeGen/MicrosoftCXXABI.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/MicrosoftCXXABI.cpp?rev=211467&r1=211466&r2=211467&view=diff
>
> ==============================================================================
> --- cfe/trunk/lib/CodeGen/MicrosoftCXXABI.cpp (original)
> +++ cfe/trunk/lib/CodeGen/MicrosoftCXXABI.cpp Sun Jun 22 07:42:29 2014
> @@ -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::adjustToCo
> 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,
>
> Modified: cfe/trunk/test/CodeGenCXX/microsoft-abi-dynamic-cast.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/microsoft-abi-dynamic-cast.cpp?rev=211467&r1=211466&r2=211467&view=diff
>
> ==============================================================================
> --- cfe/trunk/test/CodeGenCXX/microsoft-abi-dynamic-cast.cpp (original)
> +++ cfe/trunk/test/CodeGenCXX/microsoft-abi-dynamic-cast.cpp Sun Jun 22
> 07:42:29 2014
> @@ -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: }
>
> Modified: cfe/trunk/test/CodeGenCXX/microsoft-abi-typeid.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/microsoft-abi-typeid.cpp?rev=211467&r1=211466&r2=211467&view=diff
>
> ==============================================================================
> --- cfe/trunk/test/CodeGenCXX/microsoft-abi-typeid.cpp (original)
> +++ cfe/trunk/test/CodeGenCXX/microsoft-abi-typeid.cpp Sun Jun 22 07:42:29
> 2014
> @@ -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 at 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 at 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 at 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 at 8" to %struct.type_info*)
> +// CHECK-NEXT: }
>
>
> _______________________________________________
> cfe-commits mailing list
> cfe-commits at cs.uiuc.edu
> http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20140622/4837c02f/attachment.html>
More information about the cfe-commits
mailing list