r211473 - Revert "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 14:43:59 PDT 2014
The diff in my last message is reversed, the correct diff would be:
$ git diff 5d2297..a73161 lib/CodeGen
diff --git a/lib/CodeGen/MicrosoftCXXABI.cpp
b/lib/CodeGen/MicrosoftCXXABI.cpp
index e19904f..f3c79ef 100644
--- a/lib/CodeGen/MicrosoftCXXABI.cpp
+++ b/lib/CodeGen/MicrosoftCXXABI.cpp
@@ -548,13 +548,10 @@ 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));
+ llvm::Value *Offset;
+ std::tie(ThisPtr, Offset) = performBaseAdjustment(CGF, ThisPtr,
SrcRecordTy);
return CGF.Builder.CreateBitCast(
- emitRTtypeidCall(CGF, AdjustedThisPtr).getInstruction(),
- StdTypeInfoPtrTy);
+ emitRTtypeidCall(CGF, ThisPtr).getInstruction(), StdTypeInfoPtrTy);
}
bool MicrosoftCXXABI::shouldDynamicCastCallBeNullChecked(bool SrcIsPtr,
On Sun, Jun 22, 2014 at 9:39 PM, David Majnemer <david.majnemer at gmail.com>
wrote:
> Below is a reconstruction of the delta between the original commit,
> r211402, and the ultimate commit, r211473.
>
> The difference boiled down to whether or not the adjusted 'this' pointer
> was calculated via getPolymorphicOffset or performBaseAdjustment.
> getPolymorphicOffset assumes that there is some base in the most derived
> type which is polymorphic while performBaseAdjustment first checks to see
> if the most derived type has it's own virtual function-table pointer.
>
> $ git diff a73161..5d2297 lib/CodeGen
> diff --git a/lib/CodeGen/MicrosoftCXXABI.cpp
> b/lib/CodeGen/MicrosoftCXXABI.cpp
> index f3c79ef..e19904f 100644
> --- a/lib/CodeGen/MicrosoftCXXABI.cpp
> +++ b/lib/CodeGen/MicrosoftCXXABI.cpp
> @@ -548,10 +548,13 @@ llvm::Value
> *MicrosoftCXXABI::EmitTypeid(CodeGenFunction &CGF,
> QualType SrcRecordTy,
> llvm::Value *ThisPtr,
> llvm::Type *StdTypeInfoPtrTy) {
> - llvm::Value *Offset;
> - std::tie(ThisPtr, Offset) = performBaseAdjustment(CGF, ThisPtr,
> SrcRecordTy);
> + 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, ThisPtr).getInstruction(), StdTypeInfoPtrTy);
> + emitRTtypeidCall(CGF, AdjustedThisPtr).getInstruction(),
> + StdTypeInfoPtrTy);
> }
>
> bool MicrosoftCXXABI::shouldDynamicCastCallBeNullChecked(bool SrcIsPtr,
>
>
> On Sun, Jun 22, 2014 at 8:59 PM, David Blaikie <dblaikie at gmail.com> wrote:
>
>> I'm a little confused about what was reverted/committed here. If this was
>> a recommit after a revert due to breakage it'd be nice to understand how
>> the breakage was addressed, for example.
>> On Jun 22, 2014 12:19 PM, "David Majnemer" <david.majnemer at gmail.com>
>> wrote:
>>
>>> Author: majnemer
>>> Date: Sun Jun 22 14:05:33 2014
>>> New Revision: 211473
>>>
>>> URL: http://llvm.org/viewvc/llvm-project?rev=211473&view=rev
>>> Log:
>>> Revert "Revert r211402 (and r211408,r211410), "CodeGen: Refactor
>>> dynamic_cast and typeid" It crashes msvc codegen in
>>> clang/test/SemaCXX/undefined-internal.cpp."
>>>
>>> This reverts commit r211467 which reverted r211408,r211410, it caused
>>> crashes in test/SemaCXX/undefined-internal.cpp for i686-win32 targets.
>>>
>>> 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=211473&r1=211472&r2=211473&view=diff
>>>
>>> ==============================================================================
>>> --- cfe/trunk/lib/CodeGen/CGCXXABI.h (original)
>>> +++ cfe/trunk/lib/CodeGen/CGCXXABI.h Sun Jun 22 14:05:33 2014
>>> @@ -207,6 +207,28 @@ public:
>>> llvm::Value *ptr,
>>> QualType type) = 0;
>>>
>>> + virtual bool shouldTypeidBeNullChecked(bool IsDeref,
>>> + QualType SrcRecordTy) = 0;
>>> + virtual void EmitBadTypeidCall(CodeGenFunction &CGF) = 0;
>>> + virtual llvm::Value *EmitTypeid(CodeGenFunction &CGF, QualType
>>> SrcRecordTy,
>>> + llvm::Value *ThisPtr,
>>> + llvm::Type *StdTypeInfoPtrTy) = 0;
>>> +
>>> + virtual bool shouldDynamicCastCallBeNullChecked(bool SrcIsPtr,
>>> + QualType SrcRecordTy)
>>> = 0;
>>> +
>>> + virtual llvm::Value *
>>> + EmitDynamicCastCall(CodeGenFunction &CGF, llvm::Value *Value,
>>> + QualType SrcRecordTy, QualType DestTy,
>>> + QualType DestRecordTy, llvm::BasicBlock *CastEnd)
>>> = 0;
>>> +
>>> + virtual llvm::Value *EmitDynamicCastToVoid(CodeGenFunction &CGF,
>>> + llvm::Value *Value,
>>> + QualType SrcRecordTy,
>>> + QualType DestTy) = 0;
>>> +
>>> + virtual bool EmitBadCastCall(CodeGenFunction &CGF) = 0;
>>> +
>>> virtual llvm::Value *GetVirtualBaseClassOffset(CodeGenFunction &CGF,
>>> llvm::Value *This,
>>> const CXXRecordDecl
>>> *ClassDecl,
>>>
>>> Modified: cfe/trunk/lib/CodeGen/CGExprCXX.cpp
>>> URL:
>>> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGExprCXX.cpp?rev=211473&r1=211472&r2=211473&view=diff
>>>
>>> ==============================================================================
>>> --- cfe/trunk/lib/CodeGen/CGExprCXX.cpp (original)
>>> +++ cfe/trunk/lib/CodeGen/CGExprCXX.cpp Sun Jun 22 14:05:33 2014
>>> @@ -1615,98 +1615,36 @@ 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.
>>> - if (const UnaryOperator *UO =
>>> dyn_cast<UnaryOperator>(E->IgnoreParens())) {
>>> - if (UO->getOpcode() == UO_Deref) {
>>> - llvm::BasicBlock *BadTypeidBlock =
>>> + bool IsDeref = false;
>>> + if (const UnaryOperator *UO =
>>> dyn_cast<UnaryOperator>(E->IgnoreParens()))
>>> + if (UO->getOpcode() == UO_Deref)
>>> + IsDeref = true;
>>> +
>>> + QualType SrcRecordTy = E->getType();
>>> + if (CGF.CGM.getCXXABI().shouldTypeidBeNullChecked(IsDeref,
>>> SrcRecordTy)) {
>>> + llvm::BasicBlock *BadTypeidBlock =
>>> CGF.createBasicBlock("typeid.bad_typeid");
>>> - llvm::BasicBlock *EndBlock =
>>> - CGF.createBasicBlock("typeid.end");
>>> + llvm::BasicBlock *EndBlock = CGF.createBasicBlock("typeid.end");
>>>
>>> - llvm::Value *IsNull = CGF.Builder.CreateIsNull(ThisPtr);
>>> - CGF.Builder.CreateCondBr(IsNull, BadTypeidBlock, EndBlock);
>>> + llvm::Value *IsNull = CGF.Builder.CreateIsNull(ThisPtr);
>>> + CGF.Builder.CreateCondBr(IsNull, BadTypeidBlock, EndBlock);
>>>
>>> - CGF.EmitBlock(BadTypeidBlock);
>>> - EmitBadTypeidCall(CGF);
>>> - CGF.EmitBlock(EndBlock);
>>> - }
>>> + CGF.EmitBlock(BadTypeidBlock);
>>> + CGF.CGM.getCXXABI().EmitBadTypeidCall(CGF);
>>> + CGF.EmitBlock(EndBlock);
>>> }
>>>
>>> - llvm::Value *Value = CGF.GetVTablePtr(ThisPtr,
>>> -
>>> StdTypeInfoPtrTy->getPointerTo());
>>> -
>>> - // Load the type info.
>>> - Value = CGF.Builder.CreateConstInBoundsGEP1_64(Value, -1ULL);
>>> - return CGF.Builder.CreateLoad(Value);
>>> + return CGF.CGM.getCXXABI().EmitTypeid(CGF, SrcRecordTy, ThisPtr,
>>> + StdTypeInfoPtrTy);
>>> }
>>>
>>> llvm::Value *CodeGenFunction::EmitCXXTypeidExpr(const CXXTypeidExpr *E)
>>> {
>>> @@ -1733,173 +1671,6 @@ llvm::Value *CodeGenFunction::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);
>>> @@ -1908,142 +1679,49 @@ static llvm::Value *EmitDynamicCastToNul
>>>
>>> /// C++ [expr.dynamic.cast]p9:
>>> /// A failed cast to reference type throws std::bad_cast
>>> - EmitBadCastCall(CGF);
>>> + if (!CGF.CGM.getCXXABI().EmitBadCastCall(CGF))
>>> + return nullptr;
>>>
>>> CGF.EmitBlock(CGF.createBasicBlock("dynamic_cast.end"));
>>> return llvm::UndefValue::get(DestLTy);
>>> }
>>>
>>> -namespace {
>>> -struct MSDynamicCastBuilder {
>>> - MSDynamicCastBuilder(CodeGenFunction &CGF, const CXXDynamicCastExpr
>>> *DCE);
>>> - llvm::Value *emitDynamicCastCall(llvm::Value *Value);
>>> - llvm::Value *emitDynamicCast(llvm::Value *Value);
>>> -
>>> - CodeGenFunction &CGF;
>>> - CGBuilderTy &Builder;
>>> - llvm::PointerType *Int8PtrTy;
>>> - QualType SrcTy, DstTy;
>>> - const CXXRecordDecl *SrcDecl;
>>> - bool IsPtrCast, IsCastToVoid, IsCastOfNull;
>>> -};
>>> -} // namespace
>>> -
>>> -MSDynamicCastBuilder::MSDynamicCastBuilder(CodeGenFunction &CGF,
>>> - const CXXDynamicCastExpr
>>> *DCE)
>>> - : CGF(CGF), Builder(CGF.Builder), Int8PtrTy(CGF.Int8PtrTy),
>>> - SrcDecl(nullptr) {
>>> - DstTy = DCE->getTypeAsWritten();
>>> - IsPtrCast = DstTy->isPointerType();
>>> - // Get the PointeeTypes. After this point the original types are not
>>> used.
>>> - DstTy = IsPtrCast ? DstTy->castAs<PointerType>()->getPointeeType()
>>> - : DstTy->castAs<ReferenceType>()->getPointeeType();
>>> - IsCastToVoid = DstTy->isVoidType();
>>> - IsCastOfNull = DCE->isAlwaysNull();
>>> - if (IsCastOfNull)
>>> - return;
>>> - SrcTy = DCE->getSubExpr()->getType();
>>> - SrcTy = IsPtrCast ? SrcTy->castAs<PointerType>()->getPointeeType() :
>>> SrcTy;
>>> - SrcDecl = SrcTy->getAsCXXRecordDecl();
>>> - // If we don't need a base adjustment, we don't need a SrcDecl so
>>> clear it
>>> - // here. Later we use the existence of the SrcDecl to determine the
>>> need for
>>> - // a base adjustment.
>>> - if (CGF.getContext().getASTRecordLayout(SrcDecl).hasExtendableVFPtr())
>>> - SrcDecl = nullptr;
>>> -}
>>> -
>>> -llvm::Value *MSDynamicCastBuilder::emitDynamicCastCall(llvm::Value
>>> *Value) {
>>> - llvm::IntegerType *Int32Ty = CGF.Int32Ty;
>>> - llvm::Value *Offset = llvm::ConstantInt::get(Int32Ty, 0);
>>> - Value = Builder.CreateBitCast(Value, Int8PtrTy);
>>> - // If we need to perform a base adjustment, do it here.
>>> - if (SrcDecl) {
>>> - Offset = getPolymorphicOffset(CGF, SrcDecl, Value);
>>> - Value = Builder.CreateInBoundsGEP(Value, Offset);
>>> - Offset = Builder.CreateTrunc(Offset, Int32Ty);
>>> - }
>>> - if (IsCastToVoid) {
>>> - // PVOID __RTCastToVoid(
>>> - // PVOID inptr)
>>> - llvm::Type *ArgTypes[] = {Int8PtrTy};
>>> - llvm::Constant *Function = CGF.CGM.CreateRuntimeFunction(
>>> - llvm::FunctionType::get(Int8PtrTy, ArgTypes, false),
>>> "__RTCastToVoid");
>>> - llvm::Value *Args[] = {Value};
>>> - return CGF.EmitRuntimeCall(Function, Args);
>>> - }
>>> - // PVOID __RTDynamicCast(
>>> - // PVOID inptr,
>>> - // LONG VfDelta,
>>> - // PVOID SrcType,
>>> - // PVOID TargetType,
>>> - // BOOL isReference)
>>> - llvm::Type *ArgTypes[] = {Int8PtrTy, Int32Ty, Int8PtrTy, Int8PtrTy,
>>> Int32Ty};
>>> - llvm::Constant *Function = CGF.CGM.CreateRuntimeFunction(
>>> - llvm::FunctionType::get(Int8PtrTy, ArgTypes, false),
>>> "__RTDynamicCast");
>>> - llvm::Value *Args[] = {
>>> - Value, Offset,
>>> - CGF.CGM.GetAddrOfRTTIDescriptor(SrcTy.getUnqualifiedType()),
>>> - CGF.CGM.GetAddrOfRTTIDescriptor(DstTy.getUnqualifiedType()),
>>> - llvm::ConstantInt::get(Int32Ty, IsPtrCast ? 0 : 1)};
>>> - return CGF.EmitRuntimeCall(Function, Args);
>>> -}
>>> -
>>> -llvm::Value *MSDynamicCastBuilder::emitDynamicCast(llvm::Value *Value) {
>>> - // Note about undefined behavior: If the dynamic cast is casting to a
>>> - // reference type and the input is null, we hit a grey area in the
>>> standard.
>>> - // Here we're interpreting the behavior as undefined. The effects
>>> are the
>>> - // following: If the compiler determines that the argument is
>>> statically null
>>> - // or if the argument is dynamically null but does not require base
>>> - // adjustment, __RTDynamicCast will be called with a null argument
>>> and the
>>> - // isreference bit set. In this case __RTDynamicCast will throw
>>> - // std::bad_cast. If the argument is dynamically null and a base
>>> adjustment is
>>> - // required the resulting code will produce an out of bounds memory
>>> reference
>>> - // when trying to read VBTblPtr. In Itanium mode clang also emits a
>>> vtable
>>> - // load that fails at run time.
>>> - llvm::PointerType *DstLTy = CGF.ConvertType(DstTy)->getPointerTo();
>>> - if (IsCastOfNull && IsPtrCast)
>>> - return Builder.CreateBitCast(Value, DstLTy);
>>> - if (IsCastOfNull || !IsPtrCast || !SrcDecl)
>>> - return Builder.CreateBitCast(emitDynamicCastCall(Value), DstLTy);
>>> - // !IsCastOfNull && IsPtrCast && SrcDecl
>>> - // In this case we have a pointer that requires a base adjustment. An
>>> - // adjustment is only required if the pointer is actually valid so
>>> here we
>>> - // perform a null check before doing the base adjustment and calling
>>> - // __RTDynamicCast. In the case that the argument is null we simply
>>> return
>>> - // null without calling __RTDynamicCast.
>>> - llvm::BasicBlock *EntryBlock = Builder.GetInsertBlock();
>>> - llvm::BasicBlock *CallBlock =
>>> CGF.createBasicBlock("dynamic_cast.valid");
>>> - llvm::BasicBlock *ExitBlock =
>>> CGF.createBasicBlock("dynamic_cast.call");
>>> - Builder.CreateCondBr(Builder.CreateIsNull(Value), ExitBlock,
>>> CallBlock);
>>> - // Emit the call block and code for it.
>>> - CGF.EmitBlock(CallBlock);
>>> - Value = emitDynamicCastCall(Value);
>>> - // Emit the call block and the phi nodes for it.
>>> - CGF.EmitBlock(ExitBlock);
>>> - llvm::PHINode *ValuePHI = Builder.CreatePHI(Int8PtrTy, 2);
>>> - ValuePHI->addIncoming(Value, CallBlock);
>>> - ValuePHI->addIncoming(llvm::Constant::getNullValue(Int8PtrTy),
>>> EntryBlock);
>>> - return Builder.CreateBitCast(ValuePHI, DstLTy);
>>> -}
>>> -
>>> llvm::Value *CodeGenFunction::EmitDynamicCast(llvm::Value *Value,
>>> const CXXDynamicCastExpr
>>> *DCE) {
>>> - if (getTarget().getCXXABI().isMicrosoft()) {
>>> - MSDynamicCastBuilder Builder(*this, DCE);
>>> - return Builder.emitDynamicCast(Value);
>>> - }
>>> -
>>> QualType DestTy = DCE->getTypeAsWritten();
>>>
>>> if (DCE->isAlwaysNull())
>>> - return EmitDynamicCastToNull(*this, DestTy);
>>> + if (llvm::Value *T = EmitDynamicCastToNull(*this, DestTy))
>>> + return T;
>>>
>>> QualType SrcTy = DCE->getSubExpr()->getType();
>>>
>>> + // C++ [expr.dynamic.cast]p7:
>>> + // If T is "pointer to cv void," then the result is a pointer to
>>> the most
>>> + // derived object pointed to by v.
>>> + const PointerType *DestPTy = DestTy->getAs<PointerType>();
>>> +
>>> + bool isDynamicCastToVoid;
>>> + QualType SrcRecordTy;
>>> + QualType DestRecordTy;
>>> + if (DestPTy) {
>>> + isDynamicCastToVoid = DestPTy->getPointeeType()->isVoidType();
>>> + SrcRecordTy = SrcTy->castAs<PointerType>()->getPointeeType();
>>> + DestRecordTy = DestPTy->getPointeeType();
>>> + } else {
>>> + isDynamicCastToVoid = false;
>>> + SrcRecordTy = SrcTy;
>>> + DestRecordTy = DestTy->castAs<ReferenceType>()->getPointeeType();
>>> + }
>>> +
>>> + assert(SrcRecordTy->isRecordType() && "source type must be a record
>>> type!");
>>> +
>>> // C++ [expr.dynamic.cast]p4:
>>> // If the value of v is a null pointer value in the pointer case,
>>> the result
>>> // is the null pointer value of type T.
>>> - bool ShouldNullCheckSrcValue = SrcTy->isPointerType();
>>> + bool ShouldNullCheckSrcValue =
>>> +
>>> CGM.getCXXABI().shouldDynamicCastCallBeNullChecked(SrcTy->isPointerType(),
>>> + SrcRecordTy);
>>>
>>> llvm::BasicBlock *CastNull = nullptr;
>>> llvm::BasicBlock *CastNotNull = nullptr;
>>> @@ -2058,7 +1736,15 @@ llvm::Value *CodeGenFunction::EmitDynami
>>> EmitBlock(CastNotNull);
>>> }
>>>
>>> - Value = EmitItaniumDynamicCastCall(*this, Value, SrcTy, DestTy,
>>> CastEnd);
>>> + if (isDynamicCastToVoid) {
>>> + Value = CGM.getCXXABI().EmitDynamicCastToVoid(*this, Value,
>>> SrcRecordTy,
>>> + DestTy);
>>> + } else {
>>> + assert(DestRecordTy->isRecordType() &&
>>> + "destination type must be a record type!");
>>> + Value = CGM.getCXXABI().EmitDynamicCastCall(*this, Value,
>>> SrcRecordTy,
>>> + DestTy, DestRecordTy,
>>> CastEnd);
>>> + }
>>>
>>> if (ShouldNullCheckSrcValue) {
>>> EmitBranch(CastEnd);
>>>
>>> Modified: cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp
>>> URL:
>>> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp?rev=211473&r1=211472&r2=211473&view=diff
>>>
>>> ==============================================================================
>>> --- cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp (original)
>>> +++ cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp Sun Jun 22 14:05:33 2014
>>> @@ -25,6 +25,7 @@
>>> #include "CodeGenModule.h"
>>> #include "clang/AST/Mangle.h"
>>> #include "clang/AST/Type.h"
>>> +#include "llvm/IR/CallSite.h"
>>> #include "llvm/IR/DataLayout.h"
>>> #include "llvm/IR/Intrinsics.h"
>>> #include "llvm/IR/Value.h"
>>> @@ -108,6 +109,26 @@ public:
>>> llvm::Value *adjustToCompleteObject(CodeGenFunction &CGF, llvm::Value
>>> *ptr,
>>> QualType type) override;
>>>
>>> + bool shouldTypeidBeNullChecked(bool IsDeref, QualType SrcRecordTy)
>>> override;
>>> + void EmitBadTypeidCall(CodeGenFunction &CGF) override;
>>> + llvm::Value *EmitTypeid(CodeGenFunction &CGF, QualType SrcRecordTy,
>>> + llvm::Value *ThisPtr,
>>> + llvm::Type *StdTypeInfoPtrTy) override;
>>> +
>>> + bool shouldDynamicCastCallBeNullChecked(bool SrcIsPtr,
>>> + QualType SrcRecordTy)
>>> override;
>>> +
>>> + llvm::Value *EmitDynamicCastCall(CodeGenFunction &CGF, llvm::Value
>>> *Value,
>>> + QualType SrcRecordTy, QualType
>>> DestTy,
>>> + QualType DestRecordTy,
>>> + llvm::BasicBlock *CastEnd) override;
>>> +
>>> + llvm::Value *EmitDynamicCastToVoid(CodeGenFunction &CGF, llvm::Value
>>> *Value,
>>> + QualType SrcRecordTy,
>>> + QualType DestTy) override;
>>> +
>>> + bool EmitBadCastCall(CodeGenFunction &CGF) override;
>>> +
>>> llvm::Value *
>>> GetVirtualBaseClassOffset(CodeGenFunction &CGF, llvm::Value *This,
>>> const CXXRecordDecl *ClassDecl,
>>> @@ -800,6 +821,194 @@ llvm::Value *ItaniumCXXABI::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=211473&r1=211472&r2=211473&view=diff
>>>
>>> ==============================================================================
>>> --- cfe/trunk/lib/CodeGen/MicrosoftCXXABI.cpp (original)
>>> +++ cfe/trunk/lib/CodeGen/MicrosoftCXXABI.cpp Sun Jun 22 14:05:33 2014
>>> @@ -21,6 +21,7 @@
>>> #include "clang/AST/DeclCXX.h"
>>> #include "clang/AST/VTableBuilder.h"
>>> #include "llvm/ADT/StringSet.h"
>>> +#include "llvm/IR/CallSite.h"
>>>
>>> using namespace clang;
>>> using namespace CodeGen;
>>> @@ -56,6 +57,26 @@ public:
>>> llvm::Value *ptr,
>>> QualType type) override;
>>>
>>> + bool shouldTypeidBeNullChecked(bool IsDeref, QualType SrcRecordTy)
>>> override;
>>> + void EmitBadTypeidCall(CodeGenFunction &CGF) override;
>>> + llvm::Value *EmitTypeid(CodeGenFunction &CGF, QualType SrcRecordTy,
>>> + llvm::Value *ThisPtr,
>>> + llvm::Type *StdTypeInfoPtrTy) override;
>>> +
>>> + bool shouldDynamicCastCallBeNullChecked(bool SrcIsPtr,
>>> + QualType SrcRecordTy)
>>> override;
>>> +
>>> + llvm::Value *EmitDynamicCastCall(CodeGenFunction &CGF, llvm::Value
>>> *Value,
>>> + QualType SrcRecordTy, QualType
>>> DestTy,
>>> + QualType DestRecordTy,
>>> + llvm::BasicBlock *CastEnd) override;
>>> +
>>> + llvm::Value *EmitDynamicCastToVoid(CodeGenFunction &CGF, llvm::Value
>>> *Value,
>>> + QualType SrcRecordTy,
>>> + QualType DestTy) override;
>>> +
>>> + bool EmitBadCastCall(CodeGenFunction &CGF) override;
>>> +
>>> llvm::Value *
>>> GetVirtualBaseClassOffset(CodeGenFunction &CGF, llvm::Value *This,
>>> const CXXRecordDecl *ClassDecl,
>>> @@ -469,6 +490,129 @@ llvm::Value *MicrosoftCXXABI::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) {
>>> + llvm::Value *Offset;
>>> + std::tie(ThisPtr, Offset) = performBaseAdjustment(CGF, ThisPtr,
>>> SrcRecordTy);
>>> + return CGF.Builder.CreateBitCast(
>>> + emitRTtypeidCall(CGF, ThisPtr).getInstruction(),
>>> StdTypeInfoPtrTy);
>>> +}
>>> +
>>> +bool MicrosoftCXXABI::shouldDynamicCastCallBeNullChecked(bool SrcIsPtr,
>>> + QualType
>>> SrcRecordTy) {
>>> + const CXXRecordDecl *SrcDecl = SrcRecordTy->getAsCXXRecordDecl();
>>> + return SrcIsPtr &&
>>> +
>>> !CGM.getContext().getASTRecordLayout(SrcDecl).hasExtendableVFPtr();
>>> +}
>>> +
>>> +llvm::Value *MicrosoftCXXABI::EmitDynamicCastCall(
>>> + CodeGenFunction &CGF, llvm::Value *Value, QualType SrcRecordTy,
>>> + QualType DestTy, QualType DestRecordTy, llvm::BasicBlock *CastEnd) {
>>> + llvm::Type *DestLTy = CGF.ConvertType(DestTy);
>>> +
>>> + llvm::Value *SrcRTTI =
>>> + CGF.CGM.GetAddrOfRTTIDescriptor(SrcRecordTy.getUnqualifiedType());
>>> + llvm::Value *DestRTTI =
>>> +
>>> CGF.CGM.GetAddrOfRTTIDescriptor(DestRecordTy.getUnqualifiedType());
>>> +
>>> + llvm::Value *Offset;
>>> + std::tie(Value, Offset) = performBaseAdjustment(CGF, Value,
>>> SrcRecordTy);
>>> +
>>> + // PVOID __RTDynamicCast(
>>> + // PVOID inptr,
>>> + // LONG VfDelta,
>>> + // PVOID SrcType,
>>> + // PVOID TargetType,
>>> + // BOOL isReference)
>>> + llvm::Type *ArgTypes[] = {CGF.Int8PtrTy, CGF.Int32Ty, CGF.Int8PtrTy,
>>> + CGF.Int8PtrTy, CGF.Int32Ty};
>>> + llvm::Constant *Function = CGF.CGM.CreateRuntimeFunction(
>>> + llvm::FunctionType::get(CGF.Int8PtrTy, ArgTypes, false),
>>> + "__RTDynamicCast");
>>> + llvm::Value *Args[] = {
>>> + Value, Offset, SrcRTTI, DestRTTI,
>>> + llvm::ConstantInt::get(CGF.Int32Ty, DestTy->isReferenceType())};
>>> + Value = CGF.EmitRuntimeCallOrInvoke(Function, Args).getInstruction();
>>> + return CGF.Builder.CreateBitCast(Value, DestLTy);
>>> +}
>>> +
>>> +llvm::Value *
>>> +MicrosoftCXXABI::EmitDynamicCastToVoid(CodeGenFunction &CGF,
>>> llvm::Value *Value,
>>> + QualType SrcRecordTy,
>>> + QualType DestTy) {
>>> + llvm::Value *Offset;
>>> + std::tie(Value, Offset) = performBaseAdjustment(CGF, Value,
>>> SrcRecordTy);
>>> +
>>> + // PVOID __RTCastToVoid(
>>> + // PVOID inptr)
>>> + llvm::Type *ArgTypes[] = {CGF.Int8PtrTy};
>>> + llvm::Constant *Function = CGF.CGM.CreateRuntimeFunction(
>>> + llvm::FunctionType::get(CGF.Int8PtrTy, ArgTypes, false),
>>> + "__RTCastToVoid");
>>> + llvm::Value *Args[] = {Value};
>>> + return CGF.EmitRuntimeCall(Function, Args);
>>> +}
>>> +
>>> +bool MicrosoftCXXABI::EmitBadCastCall(CodeGenFunction &CGF) {
>>> + return false;
>>> +}
>>> +
>>> llvm::Value *
>>> MicrosoftCXXABI::GetVirtualBaseClassOffset(CodeGenFunction &CGF,
>>> llvm::Value *This,
>>>
>>> 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=211473&r1=211472&r2=211473&view=diff
>>>
>>> ==============================================================================
>>> --- cfe/trunk/test/CodeGenCXX/microsoft-abi-dynamic-cast.cpp (original)
>>> +++ cfe/trunk/test/CodeGenCXX/microsoft-abi-dynamic-cast.cpp Sun Jun 22
>>> 14:05:33 2014
>>> @@ -1,158 +1,130 @@
>>> -// RUN: %clang_cc1 -emit-llvm -O2 -optzns -o - -triple=i386-pc-win32
>>> 2>/dev/null %s | FileCheck %s
>>> -// REQUIRES: asserts
>>> +// RUN: %clang_cc1 -emit-llvm -O1 -o - -triple=i386-pc-win32 %s |
>>> FileCheck %s
>>>
>>> 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: define noalias %struct.T* @"\01?test0@@YAPAUT@@XZ"() #0 {
>>> -// CHECK-NEXT: entry:
>>> -// CHECK-NEXT: ret %struct.T* null
>>> -// CHECK-NEXT: }
>>> +// CHECK-LABEL: define noalias %struct.T* @"\01?test0@@YAPAUT@@XZ"()
>>> +// CHECK: ret %struct.T* null
>>>
>>> T* test1(V* x) { return &dynamic_cast<T&>(*x); }
>>> -// 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: }
>>> +// 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]]
>>>
>>> T* test2(A* x) { return &dynamic_cast<T&>(*x); }
>>> -// 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: }
>>> +// 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]]
>>>
>>> T* test3(B* x) { return &dynamic_cast<T&>(*x); }
>>> -// 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: }
>>> +// 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]]
>>>
>>> T* test4(V* x) { return dynamic_cast<T*>(x); }
>>> -// 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: }
>>> +// 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]]
>>>
>>> T* test5(A* x) { return dynamic_cast<T*>(x); }
>>> -// 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: }
>>> +// 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]]
>>>
>>> T* test6(B* x) { return dynamic_cast<T*>(x); }
>>> -// 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: }
>>> +// 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]]
>>>
>>> void* test7(V* x) { return dynamic_cast<void*>(x); }
>>> -// 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: }
>>> +// 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]]
>>>
>>> void* test8(A* x) { return dynamic_cast<void*>(x); }
>>> -// 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: }
>>> +// 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]]
>>>
>>> void* test9(B* x) { return dynamic_cast<void*>(x); }
>>> -// 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: }
>>> +// 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]]
>>> +
>>>
>>> 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=211473&r1=211472&r2=211473&view=diff
>>>
>>> ==============================================================================
>>> --- cfe/trunk/test/CodeGenCXX/microsoft-abi-typeid.cpp (original)
>>> +++ cfe/trunk/test/CodeGenCXX/microsoft-abi-typeid.cpp Sun Jun 22
>>> 14:05:33 2014
>>> @@ -1,58 +1,45 @@
>>> -// RUN: %clang_cc1 -emit-llvm -O2 -optzns -o - -triple=i386-pc-win32
>>> 2>/dev/null %s | FileCheck %s
>>> -// REQUIRES: asserts
>>> +// RUN: %clang_cc1 -emit-llvm -O1 -o - -triple=i386-pc-win32 %s |
>>> FileCheck %s
>>>
>>> -struct type_info { const char* raw_name() const; };
>>> +struct type_info;
>>> namespace std { using ::type_info; }
>>>
>>> -struct V { virtual void f() {}; };
>>> -struct A : virtual V {};
>>> +struct V { virtual void f(); };
>>> +struct A : virtual V { A(); };
>>>
>>> -A a;
>>> -int b;
>>> +extern A a;
>>> +extern int b;
>>> A* fn();
>>>
>>> const std::type_info* test0_typeid() { return &typeid(int); }
>>> -// 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: }
>>> +// 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*)
>>>
>>> const std::type_info* test1_typeid() { return &typeid(A); }
>>> -// 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: }
>>> +// 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*)
>>>
>>> const std::type_info* test2_typeid() { return &typeid(&a); }
>>> -// 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: }
>>> +// 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*)
>>>
>>> const std::type_info* test3_typeid() { return &typeid(*fn()); }
>>> -// 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: }
>>> +// 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]]
>>>
>>> const std::type_info* test4_typeid() { return &typeid(b); }
>>> -// 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: }
>>> +// 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*)
>>>
>>>
>>> _______________________________________________
>>> 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/585abf60/attachment.html>
More information about the cfe-commits
mailing list