<div dir="ltr"><div class="gmail_extra"><div class="gmail_quote">On Sun, Jun 22, 2014 at 10:17 PM, David Blaikie <span dir="ltr"><<a href="mailto:dblaikie@gmail.com" target="_blank">dblaikie@gmail.com</a>></span> wrote:<br>
<blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex"><div class="">On Sun, Jun 22, 2014 at 2:39 PM, David Majnemer<br>
<<a href="mailto:david.majnemer@gmail.com">david.majnemer@gmail.com</a>> wrote:<br>
> Below is a reconstruction of the delta between the original commit, r211402,<br>
> and the ultimate commit, r211473.<br>
><br>
> The difference boiled down to whether or not the adjusted 'this' pointer was<br>
> calculated via getPolymorphicOffset or performBaseAdjustment.<br>
> getPolymorphicOffset assumes that there is some base in the most derived<br>
> type which is polymorphic while performBaseAdjustment first checks to see if<br>
> the most derived type has it's own virtual function-table pointer.<br>
<br>
</div>Thanks for the details - nice to include this in the commit message next time.<br>
<br>
Did you add portable test coverage for this? (so that the test would<br>
fail for any developer on any platform (ie: a test with a fixed triple<br>
for the problematic platform - and that does more than "does not<br>
crash" in whatever way is relevant for this test - since the original<br>
test that failed was in SemaCXX and the other tests for this code were<br>
in CodeGenCXX, I guess there might be some missing result coverage for<br>
the particular functionality this patch implements that was only being<br>
incidentally covered by the SemaCXX test case?)<br></blockquote><div><br></div><div>Done in r<font color="#000000"><span style="white-space:pre-wrap">211505.</span></font></div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex">
<div class=""><div class="h5"><br>
><br>
> $ git diff a73161..5d2297 lib/CodeGen<br>
> diff --git a/lib/CodeGen/MicrosoftCXXABI.cpp<br>
> b/lib/CodeGen/MicrosoftCXXABI.cpp<br>
> index f3c79ef..e19904f 100644<br>
> --- a/lib/CodeGen/MicrosoftCXXABI.cpp<br>
> +++ b/lib/CodeGen/MicrosoftCXXABI.cpp<br>
> @@ -548,10 +548,13 @@ llvm::Value<br>
> *MicrosoftCXXABI::EmitTypeid(CodeGenFunction &CGF,<br>
> QualType SrcRecordTy,<br>
> llvm::Value *ThisPtr,<br>
> llvm::Type *StdTypeInfoPtrTy) {<br>
> - llvm::Value *Offset;<br>
> - std::tie(ThisPtr, Offset) = performBaseAdjustment(CGF, ThisPtr,<br>
> SrcRecordTy);<br>
> + const CXXRecordDecl *RD = SrcRecordTy->getAsCXXRecordDecl();<br>
> + llvm::Value *CastPtr = CGF.Builder.CreateBitCast(ThisPtr, CGF.Int8PtrTy);<br>
> + llvm::Value *AdjustedThisPtr = CGF.Builder.CreateInBoundsGEP(<br>
> + CastPtr, getPolymorphicOffset(CGF, RD, CastPtr));<br>
> return CGF.Builder.CreateBitCast(<br>
> - emitRTtypeidCall(CGF, ThisPtr).getInstruction(), StdTypeInfoPtrTy);<br>
> + emitRTtypeidCall(CGF, AdjustedThisPtr).getInstruction(),<br>
> + StdTypeInfoPtrTy);<br>
> }<br>
><br>
> bool MicrosoftCXXABI::shouldDynamicCastCallBeNullChecked(bool SrcIsPtr,<br>
><br>
><br>
> On Sun, Jun 22, 2014 at 8:59 PM, David Blaikie <<a href="mailto:dblaikie@gmail.com">dblaikie@gmail.com</a>> wrote:<br>
>><br>
>> I'm a little confused about what was reverted/committed here. If this was<br>
>> a recommit after a revert due to breakage it'd be nice to understand how the<br>
>> breakage was addressed, for example.<br>
>><br>
>> On Jun 22, 2014 12:19 PM, "David Majnemer" <<a href="mailto:david.majnemer@gmail.com">david.majnemer@gmail.com</a>><br>
>> wrote:<br>
>>><br>
>>> Author: majnemer<br>
>>> Date: Sun Jun 22 14:05:33 2014<br>
>>> New Revision: 211473<br>
>>><br>
>>> URL: <a href="http://llvm.org/viewvc/llvm-project?rev=211473&view=rev" target="_blank">http://llvm.org/viewvc/llvm-project?rev=211473&view=rev</a><br>
>>> Log:<br>
>>> Revert "Revert r211402 (and r211408,r211410), "CodeGen: Refactor<br>
>>> dynamic_cast and typeid" It crashes msvc codegen in<br>
>>> clang/test/SemaCXX/undefined-internal.cpp."<br>
>>><br>
>>> This reverts commit r211467 which reverted r211408,r211410, it caused<br>
>>> crashes in test/SemaCXX/undefined-internal.cpp for i686-win32 targets.<br>
>>><br>
>>> Modified:<br>
>>> cfe/trunk/lib/CodeGen/CGCXXABI.h<br>
>>> cfe/trunk/lib/CodeGen/CGExprCXX.cpp<br>
>>> cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp<br>
>>> cfe/trunk/lib/CodeGen/MicrosoftCXXABI.cpp<br>
>>> cfe/trunk/test/CodeGenCXX/microsoft-abi-dynamic-cast.cpp<br>
>>> cfe/trunk/test/CodeGenCXX/microsoft-abi-typeid.cpp<br>
>>><br>
>>> Modified: cfe/trunk/lib/CodeGen/CGCXXABI.h<br>
>>> URL:<br>
>>> <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGCXXABI.h?rev=211473&r1=211472&r2=211473&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGCXXABI.h?rev=211473&r1=211472&r2=211473&view=diff</a><br>
>>><br>
>>> ==============================================================================<br>
>>> --- cfe/trunk/lib/CodeGen/CGCXXABI.h (original)<br>
>>> +++ cfe/trunk/lib/CodeGen/CGCXXABI.h Sun Jun 22 14:05:33 2014<br>
>>> @@ -207,6 +207,28 @@ public:<br>
>>> llvm::Value *ptr,<br>
>>> QualType type) = 0;<br>
>>><br>
>>> + virtual bool shouldTypeidBeNullChecked(bool IsDeref,<br>
>>> + QualType SrcRecordTy) = 0;<br>
>>> + virtual void EmitBadTypeidCall(CodeGenFunction &CGF) = 0;<br>
>>> + virtual llvm::Value *EmitTypeid(CodeGenFunction &CGF, QualType<br>
>>> SrcRecordTy,<br>
>>> + llvm::Value *ThisPtr,<br>
>>> + llvm::Type *StdTypeInfoPtrTy) = 0;<br>
>>> +<br>
>>> + virtual bool shouldDynamicCastCallBeNullChecked(bool SrcIsPtr,<br>
>>> + QualType SrcRecordTy)<br>
>>> = 0;<br>
>>> +<br>
>>> + virtual llvm::Value *<br>
>>> + EmitDynamicCastCall(CodeGenFunction &CGF, llvm::Value *Value,<br>
>>> + QualType SrcRecordTy, QualType DestTy,<br>
>>> + QualType DestRecordTy, llvm::BasicBlock *CastEnd)<br>
>>> = 0;<br>
>>> +<br>
>>> + virtual llvm::Value *EmitDynamicCastToVoid(CodeGenFunction &CGF,<br>
>>> + llvm::Value *Value,<br>
>>> + QualType SrcRecordTy,<br>
>>> + QualType DestTy) = 0;<br>
>>> +<br>
>>> + virtual bool EmitBadCastCall(CodeGenFunction &CGF) = 0;<br>
>>> +<br>
>>> virtual llvm::Value *GetVirtualBaseClassOffset(CodeGenFunction &CGF,<br>
>>> llvm::Value *This,<br>
>>> const CXXRecordDecl<br>
>>> *ClassDecl,<br>
>>><br>
>>> Modified: cfe/trunk/lib/CodeGen/CGExprCXX.cpp<br>
>>> URL:<br>
>>> <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGExprCXX.cpp?rev=211473&r1=211472&r2=211473&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGExprCXX.cpp?rev=211473&r1=211472&r2=211473&view=diff</a><br>
>>><br>
>>> ==============================================================================<br>
>>> --- cfe/trunk/lib/CodeGen/CGExprCXX.cpp (original)<br>
>>> +++ cfe/trunk/lib/CodeGen/CGExprCXX.cpp Sun Jun 22 14:05:33 2014<br>
>>> @@ -1615,98 +1615,36 @@ void CodeGenFunction::EmitCXXDeleteExpr(<br>
>>> EmitBlock(DeleteEnd);<br>
>>> }<br>
>>><br>
>>> -static llvm::Constant *getBadTypeidFn(CodeGenFunction &CGF) {<br>
>>> - // void __cxa_bad_typeid();<br>
>>> - llvm::FunctionType *FTy = llvm::FunctionType::get(CGF.VoidTy, false);<br>
>>> -<br>
>>> - return CGF.CGM.CreateRuntimeFunction(FTy, "__cxa_bad_typeid");<br>
>>> -}<br>
>>> -<br>
>>> -static void EmitBadTypeidCall(CodeGenFunction &CGF) {<br>
>>> - llvm::Value *Fn = getBadTypeidFn(CGF);<br>
>>> - CGF.EmitRuntimeCallOrInvoke(Fn).setDoesNotReturn();<br>
>>> - CGF.Builder.CreateUnreachable();<br>
>>> -}<br>
>>> -<br>
>>> -/// \brief Gets the offset to the virtual base that contains the vfptr<br>
>>> for<br>
>>> -/// MS-ABI polymorphic types.<br>
>>> -static llvm::Value *getPolymorphicOffset(CodeGenFunction &CGF,<br>
>>> - const CXXRecordDecl *RD,<br>
>>> - llvm::Value *Value) {<br>
>>> - const ASTContext &Context = RD->getASTContext();<br>
>>> - for (const CXXBaseSpecifier &Base : RD->vbases())<br>
>>> - if (Context.getASTRecordLayout(Base.getType()->getAsCXXRecordDecl())<br>
>>> - .hasExtendableVFPtr())<br>
>>> - return CGF.CGM.getCXXABI().GetVirtualBaseClassOffset(<br>
>>> - CGF, Value, RD, Base.getType()->getAsCXXRecordDecl());<br>
>>> - llvm_unreachable("One of our vbases should be polymorphic.");<br>
>>> -}<br>
>>> -<br>
>>> -static llvm::Value *emitRTtypeidCall(CodeGenFunction &CGF,<br>
>>> - llvm::Value *Argument) {<br>
>>> - llvm::Type *ArgTypes[] = {CGF.Int8PtrTy};<br>
>>> - llvm::Constant *Function = CGF.CGM.CreateRuntimeFunction(<br>
>>> - llvm::FunctionType::get(CGF.Int8PtrTy, ArgTypes, false),<br>
>>> "__RTtypeid");<br>
>>> - llvm::Value *Args[] = {Argument};<br>
>>> - return CGF.EmitRuntimeCall(Function, Args);<br>
>>> -}<br>
>>> -<br>
>>> static llvm::Value *EmitTypeidFromVTable(CodeGenFunction &CGF, const<br>
>>> Expr *E,<br>
>>> llvm::Type *StdTypeInfoPtrTy) {<br>
>>> // Get the vtable pointer.<br>
>>> llvm::Value *ThisPtr = CGF.EmitLValue(E).getAddress();<br>
>>><br>
>>> - if (CGF.getTarget().getCXXABI().isMicrosoft()) {<br>
>>> - llvm::Value *CastPtr = CGF.Builder.CreateBitCast(ThisPtr,<br>
>>> CGF.Int8PtrTy);<br>
>>> - const CXXRecordDecl *RD = E->getType()->getAsCXXRecordDecl();<br>
>>> - if (CGF.getContext().getASTRecordLayout(RD).hasExtendableVFPtr())<br>
>>> - return CGF.Builder.CreateBitCast(emitRTtypeidCall(CGF, CastPtr),<br>
>>> - StdTypeInfoPtrTy);<br>
>>> - llvm::BasicBlock *EntryBlock = CGF.Builder.GetInsertBlock();<br>
>>> - llvm::BasicBlock *AdjustBlock =<br>
>>> CGF.createBasicBlock("type_id.valid");<br>
>>> - llvm::BasicBlock *ExitBlock = CGF.createBasicBlock("type_id.call");<br>
>>> - CGF.Builder.CreateCondBr(CGF.Builder.CreateIsNull(CastPtr),<br>
>>> ExitBlock,<br>
>>> - AdjustBlock);<br>
>>> - // Emit the call block and code for it.<br>
>>> - CGF.EmitBlock(AdjustBlock);<br>
>>> - llvm::Value *AdjustedThisPtr = CGF.Builder.CreateInBoundsGEP(<br>
>>> - CastPtr, getPolymorphicOffset(CGF, RD, CastPtr));<br>
>>> - // Emit the call block and the phi nodes for it.<br>
>>> - CGF.EmitBlock(ExitBlock);<br>
>>> - llvm::PHINode *ValuePHI = CGF.Builder.CreatePHI(CGF.Int8PtrTy, 2);<br>
>>> - ValuePHI->addIncoming(AdjustedThisPtr, AdjustBlock);<br>
>>> - ValuePHI->addIncoming(llvm::Constant::getNullValue(CGF.Int8PtrTy),<br>
>>> - EntryBlock);<br>
>>> - return CGF.Builder.CreateBitCast(emitRTtypeidCall(CGF, ValuePHI),<br>
>>> - StdTypeInfoPtrTy);<br>
>>> - }<br>
>>> -<br>
>>> // C++ [expr.typeid]p2:<br>
>>> // If the glvalue expression is obtained by applying the unary *<br>
>>> operator to<br>
>>> // a pointer and the pointer is a null pointer value, the typeid<br>
>>> expression<br>
>>> // throws the std::bad_typeid exception.<br>
>>> - if (const UnaryOperator *UO =<br>
>>> dyn_cast<UnaryOperator>(E->IgnoreParens())) {<br>
>>> - if (UO->getOpcode() == UO_Deref) {<br>
>>> - llvm::BasicBlock *BadTypeidBlock =<br>
>>> + bool IsDeref = false;<br>
>>> + if (const UnaryOperator *UO =<br>
>>> dyn_cast<UnaryOperator>(E->IgnoreParens()))<br>
>>> + if (UO->getOpcode() == UO_Deref)<br>
>>> + IsDeref = true;<br>
>>> +<br>
>>> + QualType SrcRecordTy = E->getType();<br>
>>> + if (CGF.CGM.getCXXABI().shouldTypeidBeNullChecked(IsDeref,<br>
>>> SrcRecordTy)) {<br>
>>> + llvm::BasicBlock *BadTypeidBlock =<br>
>>> CGF.createBasicBlock("typeid.bad_typeid");<br>
>>> - llvm::BasicBlock *EndBlock =<br>
>>> - CGF.createBasicBlock("typeid.end");<br>
>>> + llvm::BasicBlock *EndBlock = CGF.createBasicBlock("typeid.end");<br>
>>><br>
>>> - llvm::Value *IsNull = CGF.Builder.CreateIsNull(ThisPtr);<br>
>>> - CGF.Builder.CreateCondBr(IsNull, BadTypeidBlock, EndBlock);<br>
>>> + llvm::Value *IsNull = CGF.Builder.CreateIsNull(ThisPtr);<br>
>>> + CGF.Builder.CreateCondBr(IsNull, BadTypeidBlock, EndBlock);<br>
>>><br>
>>> - CGF.EmitBlock(BadTypeidBlock);<br>
>>> - EmitBadTypeidCall(CGF);<br>
>>> - CGF.EmitBlock(EndBlock);<br>
>>> - }<br>
>>> + CGF.EmitBlock(BadTypeidBlock);<br>
>>> + CGF.CGM.getCXXABI().EmitBadTypeidCall(CGF);<br>
>>> + CGF.EmitBlock(EndBlock);<br>
>>> }<br>
>>><br>
>>> - llvm::Value *Value = CGF.GetVTablePtr(ThisPtr,<br>
>>> -<br>
>>> StdTypeInfoPtrTy->getPointerTo());<br>
>>> -<br>
>>> - // Load the type info.<br>
>>> - Value = CGF.Builder.CreateConstInBoundsGEP1_64(Value, -1ULL);<br>
>>> - return CGF.Builder.CreateLoad(Value);<br>
>>> + return CGF.CGM.getCXXABI().EmitTypeid(CGF, SrcRecordTy, ThisPtr,<br>
>>> + StdTypeInfoPtrTy);<br>
>>> }<br>
>>><br>
>>> llvm::Value *CodeGenFunction::EmitCXXTypeidExpr(const CXXTypeidExpr *E)<br>
>>> {<br>
>>> @@ -1733,173 +1671,6 @@ llvm::Value *CodeGenFunction::EmitCXXTyp<br>
>>> StdTypeInfoPtrTy);<br>
>>> }<br>
>>><br>
>>> -static llvm::Constant *getItaniumDynamicCastFn(CodeGenFunction &CGF) {<br>
>>> - // void *__dynamic_cast(const void *sub,<br>
>>> - // const abi::__class_type_info *src,<br>
>>> - // const abi::__class_type_info *dst,<br>
>>> - // std::ptrdiff_t src2dst_offset);<br>
>>> -<br>
>>> - llvm::Type *Int8PtrTy = CGF.Int8PtrTy;<br>
>>> - llvm::Type *PtrDiffTy =<br>
>>> - CGF.ConvertType(CGF.getContext().getPointerDiffType());<br>
>>> -<br>
>>> - llvm::Type *Args[4] = { Int8PtrTy, Int8PtrTy, Int8PtrTy, PtrDiffTy };<br>
>>> -<br>
>>> - llvm::FunctionType *FTy = llvm::FunctionType::get(Int8PtrTy, Args,<br>
>>> false);<br>
>>> -<br>
>>> - // Mark the function as nounwind readonly.<br>
>>> - llvm::Attribute::AttrKind FuncAttrs[] = { llvm::Attribute::NoUnwind,<br>
>>> - llvm::Attribute::ReadOnly };<br>
>>> - llvm::AttributeSet Attrs = llvm::AttributeSet::get(<br>
>>> - CGF.getLLVMContext(), llvm::AttributeSet::FunctionIndex,<br>
>>> FuncAttrs);<br>
>>> -<br>
>>> - return CGF.CGM.CreateRuntimeFunction(FTy, "__dynamic_cast", Attrs);<br>
>>> -}<br>
>>> -<br>
>>> -static llvm::Constant *getBadCastFn(CodeGenFunction &CGF) {<br>
>>> - // void __cxa_bad_cast();<br>
>>> - llvm::FunctionType *FTy = llvm::FunctionType::get(CGF.VoidTy, false);<br>
>>> - return CGF.CGM.CreateRuntimeFunction(FTy, "__cxa_bad_cast");<br>
>>> -}<br>
>>> -<br>
>>> -static void EmitBadCastCall(CodeGenFunction &CGF) {<br>
>>> - llvm::Value *Fn = getBadCastFn(CGF);<br>
>>> - CGF.EmitRuntimeCallOrInvoke(Fn).setDoesNotReturn();<br>
>>> - CGF.Builder.CreateUnreachable();<br>
>>> -}<br>
>>> -<br>
>>> -/// \brief Compute the src2dst_offset hint as described in the<br>
>>> -/// Itanium C++ ABI [2.9.7]<br>
>>> -static CharUnits computeOffsetHint(ASTContext &Context,<br>
>>> - const CXXRecordDecl *Src,<br>
>>> - const CXXRecordDecl *Dst) {<br>
>>> - CXXBasePaths Paths(/*FindAmbiguities=*/true, /*RecordPaths=*/true,<br>
>>> - /*DetectVirtual=*/false);<br>
>>> -<br>
>>> - // If Dst is not derived from Src we can skip the whole computation<br>
>>> below and<br>
>>> - // return that Src is not a public base of Dst. Record all<br>
>>> inheritance paths.<br>
>>> - if (!Dst->isDerivedFrom(Src, Paths))<br>
>>> - return CharUnits::fromQuantity(-2ULL);<br>
>>> -<br>
>>> - unsigned NumPublicPaths = 0;<br>
>>> - CharUnits Offset;<br>
>>> -<br>
>>> - // Now walk all possible inheritance paths.<br>
>>> - for (CXXBasePaths::paths_iterator I = Paths.begin(), E = Paths.end();<br>
>>> - I != E; ++I) {<br>
>>> - if (I->Access != AS_public) // Ignore non-public inheritance.<br>
>>> - continue;<br>
>>> -<br>
>>> - ++NumPublicPaths;<br>
>>> -<br>
>>> - for (CXXBasePath::iterator J = I->begin(), JE = I->end(); J != JE;<br>
>>> ++J) {<br>
>>> - // If the path contains a virtual base class we can't give any<br>
>>> hint.<br>
>>> - // -1: no hint.<br>
>>> - if (J->Base->isVirtual())<br>
>>> - return CharUnits::fromQuantity(-1ULL);<br>
>>> -<br>
>>> - if (NumPublicPaths > 1) // Won't use offsets, skip computation.<br>
>>> - continue;<br>
>>> -<br>
>>> - // Accumulate the base class offsets.<br>
>>> - const ASTRecordLayout &L = Context.getASTRecordLayout(J->Class);<br>
>>> - Offset +=<br>
>>> L.getBaseClassOffset(J->Base->getType()->getAsCXXRecordDecl());<br>
>>> - }<br>
>>> - }<br>
>>> -<br>
>>> - // -2: Src is not a public base of Dst.<br>
>>> - if (NumPublicPaths == 0)<br>
>>> - return CharUnits::fromQuantity(-2ULL);<br>
>>> -<br>
>>> - // -3: Src is a multiple public base type but never a virtual base<br>
>>> type.<br>
>>> - if (NumPublicPaths > 1)<br>
>>> - return CharUnits::fromQuantity(-3ULL);<br>
>>> -<br>
>>> - // Otherwise, the Src type is a unique public nonvirtual base type of<br>
>>> Dst.<br>
>>> - // Return the offset of Src from the origin of Dst.<br>
>>> - return Offset;<br>
>>> -}<br>
>>> -<br>
>>> -static llvm::Value *<br>
>>> -EmitItaniumDynamicCastCall(CodeGenFunction &CGF, llvm::Value *Value,<br>
>>> - QualType SrcTy, QualType DestTy,<br>
>>> - llvm::BasicBlock *CastEnd) {<br>
>>> - llvm::Type *PtrDiffLTy =<br>
>>> - CGF.ConvertType(CGF.getContext().getPointerDiffType());<br>
>>> - llvm::Type *DestLTy = CGF.ConvertType(DestTy);<br>
>>> -<br>
>>> - if (const PointerType *PTy = DestTy->getAs<PointerType>()) {<br>
>>> - if (PTy->getPointeeType()->isVoidType()) {<br>
>>> - // C++ [expr.dynamic.cast]p7:<br>
>>> - // If T is "pointer to cv void," then the result is a pointer to<br>
>>> the<br>
>>> - // most derived object pointed to by v.<br>
>>> -<br>
>>> - // Get the vtable pointer.<br>
>>> - llvm::Value *VTable = CGF.GetVTablePtr(Value,<br>
>>> PtrDiffLTy->getPointerTo());<br>
>>> -<br>
>>> - // Get the offset-to-top from the vtable.<br>
>>> - llvm::Value *OffsetToTop =<br>
>>> - CGF.Builder.CreateConstInBoundsGEP1_64(VTable, -2ULL);<br>
>>> - OffsetToTop = CGF.Builder.CreateLoad(OffsetToTop,<br>
>>> "offset.to.top");<br>
>>> -<br>
>>> - // Finally, add the offset to the pointer.<br>
>>> - Value = CGF.EmitCastToVoidPtr(Value);<br>
>>> - Value = CGF.Builder.CreateInBoundsGEP(Value, OffsetToTop);<br>
>>> -<br>
>>> - return CGF.Builder.CreateBitCast(Value, DestLTy);<br>
>>> - }<br>
>>> - }<br>
>>> -<br>
>>> - QualType SrcRecordTy;<br>
>>> - QualType DestRecordTy;<br>
>>> -<br>
>>> - if (const PointerType *DestPTy = DestTy->getAs<PointerType>()) {<br>
>>> - SrcRecordTy = SrcTy->castAs<PointerType>()->getPointeeType();<br>
>>> - DestRecordTy = DestPTy->getPointeeType();<br>
>>> - } else {<br>
>>> - SrcRecordTy = SrcTy;<br>
>>> - DestRecordTy = DestTy->castAs<ReferenceType>()->getPointeeType();<br>
>>> - }<br>
>>> -<br>
>>> - assert(SrcRecordTy->isRecordType() && "source type must be a record<br>
>>> type!");<br>
>>> - assert(DestRecordTy->isRecordType() && "dest type must be a record<br>
>>> type!");<br>
>>> -<br>
>>> - llvm::Value *SrcRTTI =<br>
>>> - CGF.CGM.GetAddrOfRTTIDescriptor(SrcRecordTy.getUnqualifiedType());<br>
>>> - llvm::Value *DestRTTI =<br>
>>> - CGF.CGM.GetAddrOfRTTIDescriptor(DestRecordTy.getUnqualifiedType());<br>
>>> -<br>
>>> - // Compute the offset hint.<br>
>>> - const CXXRecordDecl *SrcDecl = SrcRecordTy->getAsCXXRecordDecl();<br>
>>> - const CXXRecordDecl *DestDecl = DestRecordTy->getAsCXXRecordDecl();<br>
>>> - llvm::Value *OffsetHint =<br>
>>> - llvm::ConstantInt::get(PtrDiffLTy,<br>
>>> - computeOffsetHint(CGF.getContext(), SrcDecl,<br>
>>> - DestDecl).getQuantity());<br>
>>> -<br>
>>> - // Emit the call to __dynamic_cast.<br>
>>> - Value = CGF.EmitCastToVoidPtr(Value);<br>
>>> -<br>
>>> - llvm::Value *args[] = { Value, SrcRTTI, DestRTTI, OffsetHint };<br>
>>> - Value = CGF.EmitNounwindRuntimeCall(getItaniumDynamicCastFn(CGF),<br>
>>> args);<br>
>>> - Value = CGF.Builder.CreateBitCast(Value, DestLTy);<br>
>>> -<br>
>>> - /// C++ [expr.dynamic.cast]p9:<br>
>>> - /// A failed cast to reference type throws std::bad_cast<br>
>>> - if (DestTy->isReferenceType()) {<br>
>>> - llvm::BasicBlock *BadCastBlock =<br>
>>> - CGF.createBasicBlock("dynamic_cast.bad_cast");<br>
>>> -<br>
>>> - llvm::Value *IsNull = CGF.Builder.CreateIsNull(Value);<br>
>>> - CGF.Builder.CreateCondBr(IsNull, BadCastBlock, CastEnd);<br>
>>> -<br>
>>> - CGF.EmitBlock(BadCastBlock);<br>
>>> - EmitBadCastCall(CGF);<br>
>>> - }<br>
>>> -<br>
>>> - return Value;<br>
>>> -}<br>
>>> -<br>
>>> static llvm::Value *EmitDynamicCastToNull(CodeGenFunction &CGF,<br>
>>> QualType DestTy) {<br>
>>> llvm::Type *DestLTy = CGF.ConvertType(DestTy);<br>
>>> @@ -1908,142 +1679,49 @@ static llvm::Value *EmitDynamicCastToNul<br>
>>><br>
>>> /// C++ [expr.dynamic.cast]p9:<br>
>>> /// A failed cast to reference type throws std::bad_cast<br>
>>> - EmitBadCastCall(CGF);<br>
>>> + if (!CGF.CGM.getCXXABI().EmitBadCastCall(CGF))<br>
>>> + return nullptr;<br>
>>><br>
>>> CGF.EmitBlock(CGF.createBasicBlock("dynamic_cast.end"));<br>
>>> return llvm::UndefValue::get(DestLTy);<br>
>>> }<br>
>>><br>
>>> -namespace {<br>
>>> -struct MSDynamicCastBuilder {<br>
>>> - MSDynamicCastBuilder(CodeGenFunction &CGF, const CXXDynamicCastExpr<br>
>>> *DCE);<br>
>>> - llvm::Value *emitDynamicCastCall(llvm::Value *Value);<br>
>>> - llvm::Value *emitDynamicCast(llvm::Value *Value);<br>
>>> -<br>
>>> - CodeGenFunction &CGF;<br>
>>> - CGBuilderTy &Builder;<br>
>>> - llvm::PointerType *Int8PtrTy;<br>
>>> - QualType SrcTy, DstTy;<br>
>>> - const CXXRecordDecl *SrcDecl;<br>
>>> - bool IsPtrCast, IsCastToVoid, IsCastOfNull;<br>
>>> -};<br>
>>> -} // namespace<br>
>>> -<br>
>>> -MSDynamicCastBuilder::MSDynamicCastBuilder(CodeGenFunction &CGF,<br>
>>> - const CXXDynamicCastExpr<br>
>>> *DCE)<br>
>>> - : CGF(CGF), Builder(CGF.Builder), Int8PtrTy(CGF.Int8PtrTy),<br>
>>> - SrcDecl(nullptr) {<br>
>>> - DstTy = DCE->getTypeAsWritten();<br>
>>> - IsPtrCast = DstTy->isPointerType();<br>
>>> - // Get the PointeeTypes. After this point the original types are not<br>
>>> used.<br>
>>> - DstTy = IsPtrCast ? DstTy->castAs<PointerType>()->getPointeeType()<br>
>>> - : DstTy->castAs<ReferenceType>()->getPointeeType();<br>
>>> - IsCastToVoid = DstTy->isVoidType();<br>
>>> - IsCastOfNull = DCE->isAlwaysNull();<br>
>>> - if (IsCastOfNull)<br>
>>> - return;<br>
>>> - SrcTy = DCE->getSubExpr()->getType();<br>
>>> - SrcTy = IsPtrCast ? SrcTy->castAs<PointerType>()->getPointeeType() :<br>
>>> SrcTy;<br>
>>> - SrcDecl = SrcTy->getAsCXXRecordDecl();<br>
>>> - // If we don't need a base adjustment, we don't need a SrcDecl so<br>
>>> clear it<br>
>>> - // here. Later we use the existence of the SrcDecl to determine the<br>
>>> need for<br>
>>> - // a base adjustment.<br>
>>> - if (CGF.getContext().getASTRecordLayout(SrcDecl).hasExtendableVFPtr())<br>
>>> - SrcDecl = nullptr;<br>
>>> -}<br>
>>> -<br>
>>> -llvm::Value *MSDynamicCastBuilder::emitDynamicCastCall(llvm::Value<br>
>>> *Value) {<br>
>>> - llvm::IntegerType *Int32Ty = CGF.Int32Ty;<br>
>>> - llvm::Value *Offset = llvm::ConstantInt::get(Int32Ty, 0);<br>
>>> - Value = Builder.CreateBitCast(Value, Int8PtrTy);<br>
>>> - // If we need to perform a base adjustment, do it here.<br>
>>> - if (SrcDecl) {<br>
>>> - Offset = getPolymorphicOffset(CGF, SrcDecl, Value);<br>
>>> - Value = Builder.CreateInBoundsGEP(Value, Offset);<br>
>>> - Offset = Builder.CreateTrunc(Offset, Int32Ty);<br>
>>> - }<br>
>>> - if (IsCastToVoid) {<br>
>>> - // PVOID __RTCastToVoid(<br>
>>> - // PVOID inptr)<br>
>>> - llvm::Type *ArgTypes[] = {Int8PtrTy};<br>
>>> - llvm::Constant *Function = CGF.CGM.CreateRuntimeFunction(<br>
>>> - llvm::FunctionType::get(Int8PtrTy, ArgTypes, false),<br>
>>> "__RTCastToVoid");<br>
>>> - llvm::Value *Args[] = {Value};<br>
>>> - return CGF.EmitRuntimeCall(Function, Args);<br>
>>> - }<br>
>>> - // PVOID __RTDynamicCast(<br>
>>> - // PVOID inptr,<br>
>>> - // LONG VfDelta,<br>
>>> - // PVOID SrcType,<br>
>>> - // PVOID TargetType,<br>
>>> - // BOOL isReference)<br>
>>> - llvm::Type *ArgTypes[] = {Int8PtrTy, Int32Ty, Int8PtrTy, Int8PtrTy,<br>
>>> Int32Ty};<br>
>>> - llvm::Constant *Function = CGF.CGM.CreateRuntimeFunction(<br>
>>> - llvm::FunctionType::get(Int8PtrTy, ArgTypes, false),<br>
>>> "__RTDynamicCast");<br>
>>> - llvm::Value *Args[] = {<br>
>>> - Value, Offset,<br>
>>> - CGF.CGM.GetAddrOfRTTIDescriptor(SrcTy.getUnqualifiedType()),<br>
>>> - CGF.CGM.GetAddrOfRTTIDescriptor(DstTy.getUnqualifiedType()),<br>
>>> - llvm::ConstantInt::get(Int32Ty, IsPtrCast ? 0 : 1)};<br>
>>> - return CGF.EmitRuntimeCall(Function, Args);<br>
>>> -}<br>
>>> -<br>
>>> -llvm::Value *MSDynamicCastBuilder::emitDynamicCast(llvm::Value *Value) {<br>
>>> - // Note about undefined behavior: If the dynamic cast is casting to a<br>
>>> - // reference type and the input is null, we hit a grey area in the<br>
>>> standard.<br>
>>> - // Here we're interpreting the behavior as undefined. The effects are<br>
>>> the<br>
>>> - // following: If the compiler determines that the argument is<br>
>>> statically null<br>
>>> - // or if the argument is dynamically null but does not require base<br>
>>> - // adjustment, __RTDynamicCast will be called with a null argument and<br>
>>> the<br>
>>> - // isreference bit set. In this case __RTDynamicCast will throw<br>
>>> - // std::bad_cast. If the argument is dynamically null and a base<br>
>>> adjustment is<br>
>>> - // required the resulting code will produce an out of bounds memory<br>
>>> reference<br>
>>> - // when trying to read VBTblPtr. In Itanium mode clang also emits a<br>
>>> vtable<br>
>>> - // load that fails at run time.<br>
>>> - llvm::PointerType *DstLTy = CGF.ConvertType(DstTy)->getPointerTo();<br>
>>> - if (IsCastOfNull && IsPtrCast)<br>
>>> - return Builder.CreateBitCast(Value, DstLTy);<br>
>>> - if (IsCastOfNull || !IsPtrCast || !SrcDecl)<br>
>>> - return Builder.CreateBitCast(emitDynamicCastCall(Value), DstLTy);<br>
>>> - // !IsCastOfNull && IsPtrCast && SrcDecl<br>
>>> - // In this case we have a pointer that requires a base adjustment. An<br>
>>> - // adjustment is only required if the pointer is actually valid so<br>
>>> here we<br>
>>> - // perform a null check before doing the base adjustment and calling<br>
>>> - // __RTDynamicCast. In the case that the argument is null we simply<br>
>>> return<br>
>>> - // null without calling __RTDynamicCast.<br>
>>> - llvm::BasicBlock *EntryBlock = Builder.GetInsertBlock();<br>
>>> - llvm::BasicBlock *CallBlock =<br>
>>> CGF.createBasicBlock("dynamic_cast.valid");<br>
>>> - llvm::BasicBlock *ExitBlock =<br>
>>> CGF.createBasicBlock("dynamic_cast.call");<br>
>>> - Builder.CreateCondBr(Builder.CreateIsNull(Value), ExitBlock,<br>
>>> CallBlock);<br>
>>> - // Emit the call block and code for it.<br>
>>> - CGF.EmitBlock(CallBlock);<br>
>>> - Value = emitDynamicCastCall(Value);<br>
>>> - // Emit the call block and the phi nodes for it.<br>
>>> - CGF.EmitBlock(ExitBlock);<br>
>>> - llvm::PHINode *ValuePHI = Builder.CreatePHI(Int8PtrTy, 2);<br>
>>> - ValuePHI->addIncoming(Value, CallBlock);<br>
>>> - ValuePHI->addIncoming(llvm::Constant::getNullValue(Int8PtrTy),<br>
>>> EntryBlock);<br>
>>> - return Builder.CreateBitCast(ValuePHI, DstLTy);<br>
>>> -}<br>
>>> -<br>
>>> llvm::Value *CodeGenFunction::EmitDynamicCast(llvm::Value *Value,<br>
>>> const CXXDynamicCastExpr<br>
>>> *DCE) {<br>
>>> - if (getTarget().getCXXABI().isMicrosoft()) {<br>
>>> - MSDynamicCastBuilder Builder(*this, DCE);<br>
>>> - return Builder.emitDynamicCast(Value);<br>
>>> - }<br>
>>> -<br>
>>> QualType DestTy = DCE->getTypeAsWritten();<br>
>>><br>
>>> if (DCE->isAlwaysNull())<br>
>>> - return EmitDynamicCastToNull(*this, DestTy);<br>
>>> + if (llvm::Value *T = EmitDynamicCastToNull(*this, DestTy))<br>
>>> + return T;<br>
>>><br>
>>> QualType SrcTy = DCE->getSubExpr()->getType();<br>
>>><br>
>>> + // C++ [expr.dynamic.cast]p7:<br>
>>> + // If T is "pointer to cv void," then the result is a pointer to the<br>
>>> most<br>
>>> + // derived object pointed to by v.<br>
>>> + const PointerType *DestPTy = DestTy->getAs<PointerType>();<br>
>>> +<br>
>>> + bool isDynamicCastToVoid;<br>
>>> + QualType SrcRecordTy;<br>
>>> + QualType DestRecordTy;<br>
>>> + if (DestPTy) {<br>
>>> + isDynamicCastToVoid = DestPTy->getPointeeType()->isVoidType();<br>
>>> + SrcRecordTy = SrcTy->castAs<PointerType>()->getPointeeType();<br>
>>> + DestRecordTy = DestPTy->getPointeeType();<br>
>>> + } else {<br>
>>> + isDynamicCastToVoid = false;<br>
>>> + SrcRecordTy = SrcTy;<br>
>>> + DestRecordTy = DestTy->castAs<ReferenceType>()->getPointeeType();<br>
>>> + }<br>
>>> +<br>
>>> + assert(SrcRecordTy->isRecordType() && "source type must be a record<br>
>>> type!");<br>
>>> +<br>
>>> // C++ [expr.dynamic.cast]p4:<br>
>>> // If the value of v is a null pointer value in the pointer case,<br>
>>> the result<br>
>>> // is the null pointer value of type T.<br>
>>> - bool ShouldNullCheckSrcValue = SrcTy->isPointerType();<br>
>>> + bool ShouldNullCheckSrcValue =<br>
>>> +<br>
>>> CGM.getCXXABI().shouldDynamicCastCallBeNullChecked(SrcTy->isPointerType(),<br>
>>> + SrcRecordTy);<br>
>>><br>
>>> llvm::BasicBlock *CastNull = nullptr;<br>
>>> llvm::BasicBlock *CastNotNull = nullptr;<br>
>>> @@ -2058,7 +1736,15 @@ llvm::Value *CodeGenFunction::EmitDynami<br>
>>> EmitBlock(CastNotNull);<br>
>>> }<br>
>>><br>
>>> - Value = EmitItaniumDynamicCastCall(*this, Value, SrcTy, DestTy,<br>
>>> CastEnd);<br>
>>> + if (isDynamicCastToVoid) {<br>
>>> + Value = CGM.getCXXABI().EmitDynamicCastToVoid(*this, Value,<br>
>>> SrcRecordTy,<br>
>>> + DestTy);<br>
>>> + } else {<br>
>>> + assert(DestRecordTy->isRecordType() &&<br>
>>> + "destination type must be a record type!");<br>
>>> + Value = CGM.getCXXABI().EmitDynamicCastCall(*this, Value,<br>
>>> SrcRecordTy,<br>
>>> + DestTy, DestRecordTy,<br>
>>> CastEnd);<br>
>>> + }<br>
>>><br>
>>> if (ShouldNullCheckSrcValue) {<br>
>>> EmitBranch(CastEnd);<br>
>>><br>
>>> Modified: cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp<br>
>>> URL:<br>
>>> <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp?rev=211473&r1=211472&r2=211473&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp?rev=211473&r1=211472&r2=211473&view=diff</a><br>
>>><br>
>>> ==============================================================================<br>
>>> --- cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp (original)<br>
>>> +++ cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp Sun Jun 22 14:05:33 2014<br>
>>> @@ -25,6 +25,7 @@<br>
>>> #include "CodeGenModule.h"<br>
>>> #include "clang/AST/Mangle.h"<br>
>>> #include "clang/AST/Type.h"<br>
>>> +#include "llvm/IR/CallSite.h"<br>
>>> #include "llvm/IR/DataLayout.h"<br>
>>> #include "llvm/IR/Intrinsics.h"<br>
>>> #include "llvm/IR/Value.h"<br>
>>> @@ -108,6 +109,26 @@ public:<br>
>>> llvm::Value *adjustToCompleteObject(CodeGenFunction &CGF, llvm::Value<br>
>>> *ptr,<br>
>>> QualType type) override;<br>
>>><br>
>>> + bool shouldTypeidBeNullChecked(bool IsDeref, QualType SrcRecordTy)<br>
>>> override;<br>
>>> + void EmitBadTypeidCall(CodeGenFunction &CGF) override;<br>
>>> + llvm::Value *EmitTypeid(CodeGenFunction &CGF, QualType SrcRecordTy,<br>
>>> + llvm::Value *ThisPtr,<br>
>>> + llvm::Type *StdTypeInfoPtrTy) override;<br>
>>> +<br>
>>> + bool shouldDynamicCastCallBeNullChecked(bool SrcIsPtr,<br>
>>> + QualType SrcRecordTy)<br>
>>> override;<br>
>>> +<br>
>>> + llvm::Value *EmitDynamicCastCall(CodeGenFunction &CGF, llvm::Value<br>
>>> *Value,<br>
>>> + QualType SrcRecordTy, QualType<br>
>>> DestTy,<br>
>>> + QualType DestRecordTy,<br>
>>> + llvm::BasicBlock *CastEnd) override;<br>
>>> +<br>
>>> + llvm::Value *EmitDynamicCastToVoid(CodeGenFunction &CGF, llvm::Value<br>
>>> *Value,<br>
>>> + QualType SrcRecordTy,<br>
>>> + QualType DestTy) override;<br>
>>> +<br>
>>> + bool EmitBadCastCall(CodeGenFunction &CGF) override;<br>
>>> +<br>
>>> llvm::Value *<br>
>>> GetVirtualBaseClassOffset(CodeGenFunction &CGF, llvm::Value *This,<br>
>>> const CXXRecordDecl *ClassDecl,<br>
>>> @@ -800,6 +821,194 @@ llvm::Value *ItaniumCXXABI::adjustToComp<br>
>>> return CGF.Builder.CreateInBoundsGEP(ptr, offset);<br>
>>> }<br>
>>><br>
>>> +static llvm::Constant *getItaniumDynamicCastFn(CodeGenFunction &CGF) {<br>
>>> + // void *__dynamic_cast(const void *sub,<br>
>>> + // const abi::__class_type_info *src,<br>
>>> + // const abi::__class_type_info *dst,<br>
>>> + // std::ptrdiff_t src2dst_offset);<br>
>>> +<br>
>>> + llvm::Type *Int8PtrTy = CGF.Int8PtrTy;<br>
>>> + llvm::Type *PtrDiffTy =<br>
>>> + CGF.ConvertType(CGF.getContext().getPointerDiffType());<br>
>>> +<br>
>>> + llvm::Type *Args[4] = { Int8PtrTy, Int8PtrTy, Int8PtrTy, PtrDiffTy };<br>
>>> +<br>
>>> + llvm::FunctionType *FTy = llvm::FunctionType::get(Int8PtrTy, Args,<br>
>>> false);<br>
>>> +<br>
>>> + // Mark the function as nounwind readonly.<br>
>>> + llvm::Attribute::AttrKind FuncAttrs[] = { llvm::Attribute::NoUnwind,<br>
>>> + llvm::Attribute::ReadOnly };<br>
>>> + llvm::AttributeSet Attrs = llvm::AttributeSet::get(<br>
>>> + CGF.getLLVMContext(), llvm::AttributeSet::FunctionIndex,<br>
>>> FuncAttrs);<br>
>>> +<br>
>>> + return CGF.CGM.CreateRuntimeFunction(FTy, "__dynamic_cast", Attrs);<br>
>>> +}<br>
>>> +<br>
>>> +static llvm::Constant *getBadCastFn(CodeGenFunction &CGF) {<br>
>>> + // void __cxa_bad_cast();<br>
>>> + llvm::FunctionType *FTy = llvm::FunctionType::get(CGF.VoidTy, false);<br>
>>> + return CGF.CGM.CreateRuntimeFunction(FTy, "__cxa_bad_cast");<br>
>>> +}<br>
>>> +<br>
>>> +/// \brief Compute the src2dst_offset hint as described in the<br>
>>> +/// Itanium C++ ABI [2.9.7]<br>
>>> +static CharUnits computeOffsetHint(ASTContext &Context,<br>
>>> + const CXXRecordDecl *Src,<br>
>>> + const CXXRecordDecl *Dst) {<br>
>>> + CXXBasePaths Paths(/*FindAmbiguities=*/true, /*RecordPaths=*/true,<br>
>>> + /*DetectVirtual=*/false);<br>
>>> +<br>
>>> + // If Dst is not derived from Src we can skip the whole computation<br>
>>> below and<br>
>>> + // return that Src is not a public base of Dst. Record all<br>
>>> inheritance paths.<br>
>>> + if (!Dst->isDerivedFrom(Src, Paths))<br>
>>> + return CharUnits::fromQuantity(-2ULL);<br>
>>> +<br>
>>> + unsigned NumPublicPaths = 0;<br>
>>> + CharUnits Offset;<br>
>>> +<br>
>>> + // Now walk all possible inheritance paths.<br>
>>> + for (CXXBasePaths::paths_iterator I = Paths.begin(), E = Paths.end();<br>
>>> I != E;<br>
>>> + ++I) {<br>
>>> + if (I->Access != AS_public) // Ignore non-public inheritance.<br>
>>> + continue;<br>
>>> +<br>
>>> + ++NumPublicPaths;<br>
>>> +<br>
>>> + for (CXXBasePath::iterator J = I->begin(), JE = I->end(); J != JE;<br>
>>> ++J) {<br>
>>> + // If the path contains a virtual base class we can't give any<br>
>>> hint.<br>
>>> + // -1: no hint.<br>
>>> + if (J->Base->isVirtual())<br>
>>> + return CharUnits::fromQuantity(-1ULL);<br>
>>> +<br>
>>> + if (NumPublicPaths > 1) // Won't use offsets, skip computation.<br>
>>> + continue;<br>
>>> +<br>
>>> + // Accumulate the base class offsets.<br>
>>> + const ASTRecordLayout &L = Context.getASTRecordLayout(J->Class);<br>
>>> + Offset +=<br>
>>> L.getBaseClassOffset(J->Base->getType()->getAsCXXRecordDecl());<br>
>>> + }<br>
>>> + }<br>
>>> +<br>
>>> + // -2: Src is not a public base of Dst.<br>
>>> + if (NumPublicPaths == 0)<br>
>>> + return CharUnits::fromQuantity(-2ULL);<br>
>>> +<br>
>>> + // -3: Src is a multiple public base type but never a virtual base<br>
>>> type.<br>
>>> + if (NumPublicPaths > 1)<br>
>>> + return CharUnits::fromQuantity(-3ULL);<br>
>>> +<br>
>>> + // Otherwise, the Src type is a unique public nonvirtual base type of<br>
>>> Dst.<br>
>>> + // Return the offset of Src from the origin of Dst.<br>
>>> + return Offset;<br>
>>> +}<br>
>>> +<br>
>>> +static llvm::Constant *getBadTypeidFn(CodeGenFunction &CGF) {<br>
>>> + // void __cxa_bad_typeid();<br>
>>> + llvm::FunctionType *FTy = llvm::FunctionType::get(CGF.VoidTy, false);<br>
>>> +<br>
>>> + return CGF.CGM.CreateRuntimeFunction(FTy, "__cxa_bad_typeid");<br>
>>> +}<br>
>>> +<br>
>>> +bool ItaniumCXXABI::shouldTypeidBeNullChecked(bool IsDeref,<br>
>>> + QualType SrcRecordTy) {<br>
>>> + return IsDeref;<br>
>>> +}<br>
>>> +<br>
>>> +void ItaniumCXXABI::EmitBadTypeidCall(CodeGenFunction &CGF) {<br>
>>> + llvm::Value *Fn = getBadTypeidFn(CGF);<br>
>>> + CGF.EmitRuntimeCallOrInvoke(Fn).setDoesNotReturn();<br>
>>> + CGF.Builder.CreateUnreachable();<br>
>>> +}<br>
>>> +<br>
>>> +llvm::Value *ItaniumCXXABI::EmitTypeid(CodeGenFunction &CGF,<br>
>>> + QualType SrcRecordTy,<br>
>>> + llvm::Value *ThisPtr,<br>
>>> + llvm::Type *StdTypeInfoPtrTy) {<br>
>>> + llvm::Value *Value =<br>
>>> + CGF.GetVTablePtr(ThisPtr, StdTypeInfoPtrTy->getPointerTo());<br>
>>> +<br>
>>> + // Load the type info.<br>
>>> + Value = CGF.Builder.CreateConstInBoundsGEP1_64(Value, -1ULL);<br>
>>> + return CGF.Builder.CreateLoad(Value);<br>
>>> +}<br>
>>> +<br>
>>> +bool ItaniumCXXABI::shouldDynamicCastCallBeNullChecked(bool SrcIsPtr,<br>
>>> + QualType<br>
>>> SrcRecordTy) {<br>
>>> + return SrcIsPtr;<br>
>>> +}<br>
>>> +<br>
>>> +llvm::Value *ItaniumCXXABI::EmitDynamicCastCall(<br>
>>> + CodeGenFunction &CGF, llvm::Value *Value, QualType SrcRecordTy,<br>
>>> + QualType DestTy, QualType DestRecordTy, llvm::BasicBlock *CastEnd) {<br>
>>> + llvm::Type *PtrDiffLTy =<br>
>>> + CGF.ConvertType(CGF.getContext().getPointerDiffType());<br>
>>> + llvm::Type *DestLTy = CGF.ConvertType(DestTy);<br>
>>> +<br>
>>> + llvm::Value *SrcRTTI =<br>
>>> + CGF.CGM.GetAddrOfRTTIDescriptor(SrcRecordTy.getUnqualifiedType());<br>
>>> + llvm::Value *DestRTTI =<br>
>>> +<br>
>>> CGF.CGM.GetAddrOfRTTIDescriptor(DestRecordTy.getUnqualifiedType());<br>
>>> +<br>
>>> + // Compute the offset hint.<br>
>>> + const CXXRecordDecl *SrcDecl = SrcRecordTy->getAsCXXRecordDecl();<br>
>>> + const CXXRecordDecl *DestDecl = DestRecordTy->getAsCXXRecordDecl();<br>
>>> + llvm::Value *OffsetHint = llvm::ConstantInt::get(<br>
>>> + PtrDiffLTy,<br>
>>> + computeOffsetHint(CGF.getContext(), SrcDecl,<br>
>>> DestDecl).getQuantity());<br>
>>> +<br>
>>> + // Emit the call to __dynamic_cast.<br>
>>> + Value = CGF.EmitCastToVoidPtr(Value);<br>
>>> +<br>
>>> + llvm::Value *args[] = {Value, SrcRTTI, DestRTTI, OffsetHint};<br>
>>> + Value = CGF.EmitNounwindRuntimeCall(getItaniumDynamicCastFn(CGF),<br>
>>> args);<br>
>>> + Value = CGF.Builder.CreateBitCast(Value, DestLTy);<br>
>>> +<br>
>>> + /// C++ [expr.dynamic.cast]p9:<br>
>>> + /// A failed cast to reference type throws std::bad_cast<br>
>>> + if (DestTy->isReferenceType()) {<br>
>>> + llvm::BasicBlock *BadCastBlock =<br>
>>> + CGF.createBasicBlock("dynamic_cast.bad_cast");<br>
>>> +<br>
>>> + llvm::Value *IsNull = CGF.Builder.CreateIsNull(Value);<br>
>>> + CGF.Builder.CreateCondBr(IsNull, BadCastBlock, CastEnd);<br>
>>> +<br>
>>> + CGF.EmitBlock(BadCastBlock);<br>
>>> + EmitBadCastCall(CGF);<br>
>>> + }<br>
>>> +<br>
>>> + return Value;<br>
>>> +}<br>
>>> +<br>
>>> +llvm::Value *ItaniumCXXABI::EmitDynamicCastToVoid(CodeGenFunction &CGF,<br>
>>> + llvm::Value *Value,<br>
>>> + QualType SrcRecordTy,<br>
>>> + QualType DestTy) {<br>
>>> + llvm::Type *PtrDiffLTy =<br>
>>> + CGF.ConvertType(CGF.getContext().getPointerDiffType());<br>
>>> + llvm::Type *DestLTy = CGF.ConvertType(DestTy);<br>
>>> +<br>
>>> + // Get the vtable pointer.<br>
>>> + llvm::Value *VTable = CGF.GetVTablePtr(Value,<br>
>>> PtrDiffLTy->getPointerTo());<br>
>>> +<br>
>>> + // Get the offset-to-top from the vtable.<br>
>>> + llvm::Value *OffsetToTop =<br>
>>> + CGF.Builder.CreateConstInBoundsGEP1_64(VTable, -2ULL);<br>
>>> + OffsetToTop = CGF.Builder.CreateLoad(OffsetToTop, "offset.to.top");<br>
>>> +<br>
>>> + // Finally, add the offset to the pointer.<br>
>>> + Value = CGF.EmitCastToVoidPtr(Value);<br>
>>> + Value = CGF.Builder.CreateInBoundsGEP(Value, OffsetToTop);<br>
>>> +<br>
>>> + return CGF.Builder.CreateBitCast(Value, DestLTy);<br>
>>> +}<br>
>>> +<br>
>>> +bool ItaniumCXXABI::EmitBadCastCall(CodeGenFunction &CGF) {<br>
>>> + llvm::Value *Fn = getBadCastFn(CGF);<br>
>>> + CGF.EmitRuntimeCallOrInvoke(Fn).setDoesNotReturn();<br>
>>> + CGF.Builder.CreateUnreachable();<br>
>>> + return true;<br>
>>> +}<br>
>>> +<br>
>>> llvm::Value *<br>
>>> ItaniumCXXABI::GetVirtualBaseClassOffset(CodeGenFunction &CGF,<br>
>>> llvm::Value *This,<br>
>>><br>
>>> Modified: cfe/trunk/lib/CodeGen/MicrosoftCXXABI.cpp<br>
>>> URL:<br>
>>> <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/MicrosoftCXXABI.cpp?rev=211473&r1=211472&r2=211473&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/MicrosoftCXXABI.cpp?rev=211473&r1=211472&r2=211473&view=diff</a><br>
>>><br>
>>> ==============================================================================<br>
>>> --- cfe/trunk/lib/CodeGen/MicrosoftCXXABI.cpp (original)<br>
>>> +++ cfe/trunk/lib/CodeGen/MicrosoftCXXABI.cpp Sun Jun 22 14:05:33 2014<br>
>>> @@ -21,6 +21,7 @@<br>
>>> #include "clang/AST/DeclCXX.h"<br>
>>> #include "clang/AST/VTableBuilder.h"<br>
>>> #include "llvm/ADT/StringSet.h"<br>
>>> +#include "llvm/IR/CallSite.h"<br>
>>><br>
>>> using namespace clang;<br>
>>> using namespace CodeGen;<br>
>>> @@ -56,6 +57,26 @@ public:<br>
>>> llvm::Value *ptr,<br>
>>> QualType type) override;<br>
>>><br>
>>> + bool shouldTypeidBeNullChecked(bool IsDeref, QualType SrcRecordTy)<br>
>>> override;<br>
>>> + void EmitBadTypeidCall(CodeGenFunction &CGF) override;<br>
>>> + llvm::Value *EmitTypeid(CodeGenFunction &CGF, QualType SrcRecordTy,<br>
>>> + llvm::Value *ThisPtr,<br>
>>> + llvm::Type *StdTypeInfoPtrTy) override;<br>
>>> +<br>
>>> + bool shouldDynamicCastCallBeNullChecked(bool SrcIsPtr,<br>
>>> + QualType SrcRecordTy)<br>
>>> override;<br>
>>> +<br>
>>> + llvm::Value *EmitDynamicCastCall(CodeGenFunction &CGF, llvm::Value<br>
>>> *Value,<br>
>>> + QualType SrcRecordTy, QualType<br>
>>> DestTy,<br>
>>> + QualType DestRecordTy,<br>
>>> + llvm::BasicBlock *CastEnd) override;<br>
>>> +<br>
>>> + llvm::Value *EmitDynamicCastToVoid(CodeGenFunction &CGF, llvm::Value<br>
>>> *Value,<br>
>>> + QualType SrcRecordTy,<br>
>>> + QualType DestTy) override;<br>
>>> +<br>
>>> + bool EmitBadCastCall(CodeGenFunction &CGF) override;<br>
>>> +<br>
>>> llvm::Value *<br>
>>> GetVirtualBaseClassOffset(CodeGenFunction &CGF, llvm::Value *This,<br>
>>> const CXXRecordDecl *ClassDecl,<br>
>>> @@ -469,6 +490,129 @@ llvm::Value *MicrosoftCXXABI::adjustToCo<br>
>>> return ptr;<br>
>>> }<br>
>>><br>
>>> +/// \brief Gets the offset to the virtual base that contains the vfptr<br>
>>> for<br>
>>> +/// MS-ABI polymorphic types.<br>
>>> +static llvm::Value *getPolymorphicOffset(CodeGenFunction &CGF,<br>
>>> + const CXXRecordDecl *RD,<br>
>>> + llvm::Value *Value) {<br>
>>> + const ASTContext &Context = RD->getASTContext();<br>
>>> + for (const CXXBaseSpecifier &Base : RD->vbases())<br>
>>> + if (Context.getASTRecordLayout(Base.getType()->getAsCXXRecordDecl())<br>
>>> + .hasExtendableVFPtr())<br>
>>> + return CGF.CGM.getCXXABI().GetVirtualBaseClassOffset(<br>
>>> + CGF, Value, RD, Base.getType()->getAsCXXRecordDecl());<br>
>>> + llvm_unreachable("One of our vbases should be polymorphic.");<br>
>>> +}<br>
>>> +<br>
>>> +static std::pair<llvm::Value *, llvm::Value *><br>
>>> +performBaseAdjustment(CodeGenFunction &CGF, llvm::Value *Value,<br>
>>> + QualType SrcRecordTy) {<br>
>>> + Value = CGF.Builder.CreateBitCast(Value, CGF.Int8PtrTy);<br>
>>> + const CXXRecordDecl *SrcDecl = SrcRecordTy->getAsCXXRecordDecl();<br>
>>> +<br>
>>> + if (CGF.getContext().getASTRecordLayout(SrcDecl).hasExtendableVFPtr())<br>
>>> + return std::make_pair(Value, llvm::ConstantInt::get(CGF.Int32Ty,<br>
>>> 0));<br>
>>> +<br>
>>> + // Perform a base adjustment.<br>
>>> + llvm::Value *Offset = getPolymorphicOffset(CGF, SrcDecl, Value);<br>
>>> + Value = CGF.Builder.CreateInBoundsGEP(Value, Offset);<br>
>>> + Offset = CGF.Builder.CreateTrunc(Offset, CGF.Int32Ty);<br>
>>> + return std::make_pair(Value, Offset);<br>
>>> +}<br>
>>> +<br>
>>> +bool MicrosoftCXXABI::shouldTypeidBeNullChecked(bool IsDeref,<br>
>>> + QualType SrcRecordTy) {<br>
>>> + const CXXRecordDecl *SrcDecl = SrcRecordTy->getAsCXXRecordDecl();<br>
>>> + return IsDeref &&<br>
>>> +<br>
>>> !CGM.getContext().getASTRecordLayout(SrcDecl).hasExtendableVFPtr();<br>
>>> +}<br>
>>> +<br>
>>> +static llvm::CallSite emitRTtypeidCall(CodeGenFunction &CGF,<br>
>>> + llvm::Value *Argument) {<br>
>>> + llvm::Type *ArgTypes[] = {CGF.Int8PtrTy};<br>
>>> + llvm::FunctionType *FTy =<br>
>>> + llvm::FunctionType::get(CGF.Int8PtrTy, ArgTypes, false);<br>
>>> + llvm::Value *Args[] = {Argument};<br>
>>> + llvm::Constant *Fn = CGF.CGM.CreateRuntimeFunction(FTy, "__RTtypeid");<br>
>>> + return CGF.EmitRuntimeCallOrInvoke(Fn, Args);<br>
>>> +}<br>
>>> +<br>
>>> +void MicrosoftCXXABI::EmitBadTypeidCall(CodeGenFunction &CGF) {<br>
>>> + llvm::CallSite Call =<br>
>>> + emitRTtypeidCall(CGF,<br>
>>> llvm::Constant::getNullValue(CGM.VoidPtrTy));<br>
>>> + Call.setDoesNotReturn();<br>
>>> + CGF.Builder.CreateUnreachable();<br>
>>> +}<br>
>>> +<br>
>>> +llvm::Value *MicrosoftCXXABI::EmitTypeid(CodeGenFunction &CGF,<br>
>>> + QualType SrcRecordTy,<br>
>>> + llvm::Value *ThisPtr,<br>
>>> + llvm::Type *StdTypeInfoPtrTy) {<br>
>>> + llvm::Value *Offset;<br>
>>> + std::tie(ThisPtr, Offset) = performBaseAdjustment(CGF, ThisPtr,<br>
>>> SrcRecordTy);<br>
>>> + return CGF.Builder.CreateBitCast(<br>
>>> + emitRTtypeidCall(CGF, ThisPtr).getInstruction(),<br>
>>> StdTypeInfoPtrTy);<br>
>>> +}<br>
>>> +<br>
>>> +bool MicrosoftCXXABI::shouldDynamicCastCallBeNullChecked(bool SrcIsPtr,<br>
>>> + QualType<br>
>>> SrcRecordTy) {<br>
>>> + const CXXRecordDecl *SrcDecl = SrcRecordTy->getAsCXXRecordDecl();<br>
>>> + return SrcIsPtr &&<br>
>>> +<br>
>>> !CGM.getContext().getASTRecordLayout(SrcDecl).hasExtendableVFPtr();<br>
>>> +}<br>
>>> +<br>
>>> +llvm::Value *MicrosoftCXXABI::EmitDynamicCastCall(<br>
>>> + CodeGenFunction &CGF, llvm::Value *Value, QualType SrcRecordTy,<br>
>>> + QualType DestTy, QualType DestRecordTy, llvm::BasicBlock *CastEnd) {<br>
>>> + llvm::Type *DestLTy = CGF.ConvertType(DestTy);<br>
>>> +<br>
>>> + llvm::Value *SrcRTTI =<br>
>>> + CGF.CGM.GetAddrOfRTTIDescriptor(SrcRecordTy.getUnqualifiedType());<br>
>>> + llvm::Value *DestRTTI =<br>
>>> +<br>
>>> CGF.CGM.GetAddrOfRTTIDescriptor(DestRecordTy.getUnqualifiedType());<br>
>>> +<br>
>>> + llvm::Value *Offset;<br>
>>> + std::tie(Value, Offset) = performBaseAdjustment(CGF, Value,<br>
>>> SrcRecordTy);<br>
>>> +<br>
>>> + // PVOID __RTDynamicCast(<br>
>>> + // PVOID inptr,<br>
>>> + // LONG VfDelta,<br>
>>> + // PVOID SrcType,<br>
>>> + // PVOID TargetType,<br>
>>> + // BOOL isReference)<br>
>>> + llvm::Type *ArgTypes[] = {CGF.Int8PtrTy, CGF.Int32Ty, CGF.Int8PtrTy,<br>
>>> + CGF.Int8PtrTy, CGF.Int32Ty};<br>
>>> + llvm::Constant *Function = CGF.CGM.CreateRuntimeFunction(<br>
>>> + llvm::FunctionType::get(CGF.Int8PtrTy, ArgTypes, false),<br>
>>> + "__RTDynamicCast");<br>
>>> + llvm::Value *Args[] = {<br>
>>> + Value, Offset, SrcRTTI, DestRTTI,<br>
>>> + llvm::ConstantInt::get(CGF.Int32Ty, DestTy->isReferenceType())};<br>
>>> + Value = CGF.EmitRuntimeCallOrInvoke(Function, Args).getInstruction();<br>
>>> + return CGF.Builder.CreateBitCast(Value, DestLTy);<br>
>>> +}<br>
>>> +<br>
>>> +llvm::Value *<br>
>>> +MicrosoftCXXABI::EmitDynamicCastToVoid(CodeGenFunction &CGF, llvm::Value<br>
>>> *Value,<br>
>>> + QualType SrcRecordTy,<br>
>>> + QualType DestTy) {<br>
>>> + llvm::Value *Offset;<br>
>>> + std::tie(Value, Offset) = performBaseAdjustment(CGF, Value,<br>
>>> SrcRecordTy);<br>
>>> +<br>
>>> + // PVOID __RTCastToVoid(<br>
>>> + // PVOID inptr)<br>
>>> + llvm::Type *ArgTypes[] = {CGF.Int8PtrTy};<br>
>>> + llvm::Constant *Function = CGF.CGM.CreateRuntimeFunction(<br>
>>> + llvm::FunctionType::get(CGF.Int8PtrTy, ArgTypes, false),<br>
>>> + "__RTCastToVoid");<br>
>>> + llvm::Value *Args[] = {Value};<br>
>>> + return CGF.EmitRuntimeCall(Function, Args);<br>
>>> +}<br>
>>> +<br>
>>> +bool MicrosoftCXXABI::EmitBadCastCall(CodeGenFunction &CGF) {<br>
>>> + return false;<br>
>>> +}<br>
>>> +<br>
>>> llvm::Value *<br>
>>> MicrosoftCXXABI::GetVirtualBaseClassOffset(CodeGenFunction &CGF,<br>
>>> llvm::Value *This,<br>
>>><br>
>>> Modified: cfe/trunk/test/CodeGenCXX/microsoft-abi-dynamic-cast.cpp<br>
>>> URL:<br>
>>> <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/microsoft-abi-dynamic-cast.cpp?rev=211473&r1=211472&r2=211473&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/microsoft-abi-dynamic-cast.cpp?rev=211473&r1=211472&r2=211473&view=diff</a><br>
>>><br>
>>> ==============================================================================<br>
>>> --- cfe/trunk/test/CodeGenCXX/microsoft-abi-dynamic-cast.cpp (original)<br>
>>> +++ cfe/trunk/test/CodeGenCXX/microsoft-abi-dynamic-cast.cpp Sun Jun 22<br>
>>> 14:05:33 2014<br>
>>> @@ -1,158 +1,130 @@<br>
>>> -// RUN: %clang_cc1 -emit-llvm -O2 -optzns -o - -triple=i386-pc-win32<br>
>>> 2>/dev/null %s | FileCheck %s<br>
>>> -// REQUIRES: asserts<br>
>>> +// RUN: %clang_cc1 -emit-llvm -O1 -o - -triple=i386-pc-win32 %s |<br>
>>> FileCheck %s<br>
>>><br>
>>> struct S { char a; };<br>
>>> -struct V { virtual void f(){} };<br>
>>> +struct V { virtual void f(); };<br>
>>> struct A : virtual V {};<br>
>>> struct B : S, virtual V {};<br>
>>> struct T {};<br>
>>><br>
>>> T* test0() { return dynamic_cast<T*>((B*)0); }<br>
>>> -// CHECK: define noalias %struct.T* @"\01?test0@@YAPAUT@@XZ"() #0 {<br>
>>> -// CHECK-NEXT: entry:<br>
>>> -// CHECK-NEXT: ret %struct.T* null<br>
>>> -// CHECK-NEXT: }<br>
>>> +// CHECK-LABEL: define noalias %struct.T* @"\01?test0@@YAPAUT@@XZ"()<br>
>>> +// CHECK: ret %struct.T* null<br>
>>><br>
>>> T* test1(V* x) { return &dynamic_cast<T&>(*x); }<br>
>>> -// CHECK: define %struct.T* @"\01?test1@@YAPAUT@@PAUV@@@Z"(%struct.V*<br>
>>> %x) #1 {<br>
>>> -// CHECK-NEXT: entry:<br>
>>> -// CHECK-NEXT: %0 = bitcast %struct.V* %x to i8*<br>
>>> -// CHECK-NEXT: %1 = tail call i8* @__RTDynamicCast(i8* %0, i32 0, i8*<br>
>>> bitcast (%"MSRTTITypeDescriptor\07"* @"\01??_R0?AUV@@@8" to i8*), i8*<br>
>>> bitcast (%"MSRTTITypeDescriptor\07"* @"\01??_R0?AUT@@@8" to i8*), i32 1) #2<br>
>>> -// CHECK-NEXT: %2 = bitcast i8* %1 to %struct.T*<br>
>>> -// CHECK-NEXT: ret %struct.T* %2<br>
>>> -// CHECK-NEXT: }<br>
>>> +// CHECK-LABEL: define %struct.T*<br>
>>> @"\01?test1@@YAPAUT@@PAUV@@@Z"(%struct.V* %x)<br>
>>> +// CHECK: [[CAST:%.*]] = bitcast %struct.V* %x to i8*<br>
>>> +// CHECK-NEXT: [[CALL:%.*]] = tail call i8* @__RTDynamicCast(i8*<br>
>>> [[CAST]], i32 0, i8* bitcast (%"MSRTTITypeDescriptor\07"*<br>
>>> @"\01??_R0?AUV@@@8" to i8*), i8* bitcast (%"MSRTTITypeDescriptor\07"*<br>
>>> @"\01??_R0?AUT@@@8" to i8*), i32 1)<br>
>>> +// CHECK-NEXT: [[RET:%.*]] = bitcast i8* [[CALL]] to %struct.T*<br>
>>> +// CHECK-NEXT: ret %struct.T* [[RET]]<br>
>>><br>
>>> T* test2(A* x) { return &dynamic_cast<T&>(*x); }<br>
>>> -// CHECK: define %struct.T* @"\01?test2@@YAPAUT@@PAUA@@@Z"(%struct.A*<br>
>>> %x) #1 {<br>
>>> -// CHECK-NEXT: entry:<br>
>>> -// CHECK-NEXT: %0 = bitcast %struct.A* %x to i8*<br>
>>> -// CHECK-NEXT: %1 = bitcast %struct.A* %x to i8**<br>
>>> -// CHECK-NEXT: %vbtable = load i8** %1, align 4<br>
>>> -// CHECK-NEXT: %2 = getelementptr inbounds i8* %vbtable, i32 4<br>
>>> -// CHECK-NEXT: %3 = bitcast i8* %2 to i32*<br>
>>> -// CHECK-NEXT: %vbase_offs = load i32* %3, align 4<br>
>>> -// CHECK-NEXT: %4 = getelementptr inbounds i8* %0, i32 %vbase_offs<br>
>>> -// CHECK-NEXT: %5 = tail call i8* @__RTDynamicCast(i8* %4, i32<br>
>>> %vbase_offs, i8* bitcast (%"MSRTTITypeDescriptor\07"* @"\01??_R0?AUA@@@8" to<br>
>>> i8*), i8* bitcast (%"MSRTTITypeDescriptor\07"* @"\01??_R0?AUT@@@8" to i8*),<br>
>>> i32 1) #2<br>
>>> -// CHECK-NEXT: %6 = bitcast i8* %5 to %struct.T*<br>
>>> -// CHECK-NEXT: ret %struct.T* %6<br>
>>> -// CHECK-NEXT: }<br>
>>> +// CHECK-LABEL: define %struct.T*<br>
>>> @"\01?test2@@YAPAUT@@PAUA@@@Z"(%struct.A* %x)<br>
>>> +// CHECK: [[CAST:%.*]] = bitcast %struct.A* %x to i8*<br>
>>> +// CHECK-NEXT: [[BITCAST:%.*]] = bitcast %struct.A* %x to i8**<br>
>>> +// CHECK-NEXT: [[VBTBL:%.*]] = load i8** [[BITCAST]], align 4<br>
>>> +// CHECK-NEXT: [[VBOFFP:%.*]] = getelementptr inbounds i8* [[VBTBL]],<br>
>>> i32 4<br>
>>> +// CHECK-NEXT: [[VBOFFPCAST:%.*]] = bitcast i8* [[VBOFFP]] to i32*<br>
>>> +// CHECK-NEXT: [[VBOFFS:%.*]] = load i32* [[VBOFFPCAST]], align 4<br>
>>> +// CHECK-NEXT: [[ADJ:%.*]] = getelementptr inbounds i8* [[CAST]], i32<br>
>>> [[VBOFFS]]<br>
>>> +// CHECK-NEXT: [[CALL:%.*]] = tail call i8* @__RTDynamicCast(i8*<br>
>>> [[ADJ]], i32 [[VBOFFS]], i8* bitcast (%"MSRTTITypeDescriptor\07"*<br>
>>> @"\01??_R0?AUA@@@8" to i8*), i8* bitcast (%"MSRTTITypeDescriptor\07"*<br>
>>> @"\01??_R0?AUT@@@8" to i8*), i32 1)<br>
>>> +// CHECK-NEXT: [[RET:%.*]] = bitcast i8* [[CALL]] to %struct.T*<br>
>>> +// CHECK-NEXT: ret %struct.T* [[RET]]<br>
>>><br>
>>> T* test3(B* x) { return &dynamic_cast<T&>(*x); }<br>
>>> -// CHECK: define %struct.T* @"\01?test3@@YAPAUT@@PAUB@@@Z"(%struct.B*<br>
>>> %x) #1 {<br>
>>> -// CHECK-NEXT: entry:<br>
>>> -// CHECK-NEXT: %0 = getelementptr inbounds %struct.B* %x, i32 0, i32<br>
>>> 0, i32 0<br>
>>> -// CHECK-NEXT: %vbptr = getelementptr inbounds i8* %0, i32 4<br>
>>> -// CHECK-NEXT: %1 = bitcast i8* %vbptr to i8**<br>
>>> -// CHECK-NEXT: %vbtable = load i8** %1, align 4<br>
>>> -// CHECK-NEXT: %2 = getelementptr inbounds i8* %vbtable, i32 4<br>
>>> -// CHECK-NEXT: %3 = bitcast i8* %2 to i32*<br>
>>> -// CHECK-NEXT: %vbase_offs = load i32* %3, align 4<br>
>>> -// CHECK-NEXT: %4 = add nsw i32 %vbase_offs, 4<br>
>>> -// CHECK-NEXT: %5 = getelementptr inbounds i8* %0, i32 %4<br>
>>> -// CHECK-NEXT: %6 = tail call i8* @__RTDynamicCast(i8* %5, i32 %4, i8*<br>
>>> bitcast (%"MSRTTITypeDescriptor\07"* @"\01??_R0?AUB@@@8" to i8*), i8*<br>
>>> bitcast (%"MSRTTITypeDescriptor\07"* @"\01??_R0?AUT@@@8" to i8*), i32 1) #2<br>
>>> -// CHECK-NEXT: %7 = bitcast i8* %6 to %struct.T*<br>
>>> -// CHECK-NEXT: ret %struct.T* %7<br>
>>> -// CHECK-NEXT: }<br>
>>> +// CHECK-LABEL: define %struct.T*<br>
>>> @"\01?test3@@YAPAUT@@PAUB@@@Z"(%struct.B* %x)<br>
>>> +// CHECK: [[VOIDP:%.*]] = getelementptr inbounds %struct.B* %x,<br>
>>> i32 0, i32 0, i32 0<br>
>>> +// CHECK-NEXT: [[VBPTR:%.*]] = getelementptr inbounds i8* [[VOIDP]],<br>
>>> i32 4<br>
>>> +// CHECK-NEXT: [[BITCAST:%.*]] = bitcast i8* [[VBPTR:%.*]] to i8**<br>
>>> +// CHECK-NEXT: [[VBTBL:%.*]] = load i8** [[BITCAST]], align 4<br>
>>> +// CHECK-NEXT: [[VBOFFP:%.*]] = getelementptr inbounds i8* [[VBTBL]],<br>
>>> i32 4<br>
>>> +// CHECK-NEXT: [[VBOFFPCAST:%.*]] = bitcast i8* [[VBOFFP]] to i32*<br>
>>> +// CHECK-NEXT: [[VBOFFS:%.*]] = load i32* [[VBOFFPCAST]], align 4<br>
>>> +// CHECK-NEXT: [[DELTA:%.*]] = add nsw i32 [[VBOFFS]], 4<br>
>>> +// CHECK-NEXT: [[ADJ:%.*]] = getelementptr inbounds i8* [[VOIDP]], i32<br>
>>> [[DELTA]]<br>
>>> +// CHECK-NEXT: [[CALL:%.*]] = tail call i8* @__RTDynamicCast(i8*<br>
>>> [[ADJ]], i32 [[DELTA]], i8* bitcast (%"MSRTTITypeDescriptor\07"*<br>
>>> @"\01??_R0?AUB@@@8" to i8*), i8* bitcast (%"MSRTTITypeDescriptor\07"*<br>
>>> @"\01??_R0?AUT@@@8" to i8*), i32 1)<br>
>>> +// CHECK-NEXT: [[RET:%.*]] = bitcast i8* [[CALL]] to %struct.T*<br>
>>> +// CHECK-NEXT: ret %struct.T* [[RET]]<br>
>>><br>
>>> T* test4(V* x) { return dynamic_cast<T*>(x); }<br>
>>> -// CHECK: define %struct.T* @"\01?test4@@YAPAUT@@PAUV@@@Z"(%struct.V*<br>
>>> %x) #1 {<br>
>>> -// CHECK-NEXT: entry:<br>
>>> -// CHECK-NEXT: %0 = bitcast %struct.V* %x to i8*<br>
>>> -// CHECK-NEXT: %1 = tail call i8* @__RTDynamicCast(i8* %0, i32 0, i8*<br>
>>> bitcast (%"MSRTTITypeDescriptor\07"* @"\01??_R0?AUV@@@8" to i8*), i8*<br>
>>> bitcast (%"MSRTTITypeDescriptor\07"* @"\01??_R0?AUT@@@8" to i8*), i32 0) #2<br>
>>> -// CHECK-NEXT: %2 = bitcast i8* %1 to %struct.T*<br>
>>> -// CHECK-NEXT: ret %struct.T* %2<br>
>>> -// CHECK-NEXT: }<br>
>>> +// CHECK-LABEL: define %struct.T*<br>
>>> @"\01?test4@@YAPAUT@@PAUV@@@Z"(%struct.V* %x)<br>
>>> +// CHECK: [[CAST:%.*]] = bitcast %struct.V* %x to i8*<br>
>>> +// CHECK-NEXT: [[CALL:%.*]] = tail call i8* @__RTDynamicCast(i8*<br>
>>> [[CAST]], i32 0, i8* bitcast (%"MSRTTITypeDescriptor\07"*<br>
>>> @"\01??_R0?AUV@@@8" to i8*), i8* bitcast (%"MSRTTITypeDescriptor\07"*<br>
>>> @"\01??_R0?AUT@@@8" to i8*), i32 0)<br>
>>> +// CHECK-NEXT: [[RET:%.*]] = bitcast i8* [[CALL]] to %struct.T*<br>
>>> +// CHECK-NEXT: ret %struct.T* [[RET]]<br>
>>><br>
>>> T* test5(A* x) { return dynamic_cast<T*>(x); }<br>
>>> -// CHECK: define %struct.T* @"\01?test5@@YAPAUT@@PAUA@@@Z"(%struct.A*<br>
>>> %x) #1 {<br>
>>> -// CHECK-NEXT: entry:<br>
>>> -// CHECK-NEXT: %0 = icmp eq %struct.A* %x, null<br>
>>> -// CHECK-NEXT: br i1 %0, label %dynamic_cast.call, label<br>
>>> %dynamic_cast.valid<br>
>>> -// CHECK: dynamic_cast.valid: ; preds =<br>
>>> %entry<br>
>>> -// CHECK-NEXT: %1 = bitcast %struct.A* %x to i8*<br>
>>> -// CHECK-NEXT: %2 = bitcast %struct.A* %x to i8**<br>
>>> -// CHECK-NEXT: %vbtable = load i8** %2, align 4<br>
>>> -// CHECK-NEXT: %3 = getelementptr inbounds i8* %vbtable, i32 4<br>
>>> -// CHECK-NEXT: %4 = bitcast i8* %3 to i32*<br>
>>> -// CHECK-NEXT: %vbase_offs = load i32* %4, align 4<br>
>>> -// CHECK-NEXT: %5 = getelementptr inbounds i8* %1, i32 %vbase_offs<br>
>>> -// CHECK-NEXT: %6 = tail call i8* @__RTDynamicCast(i8* %5, i32<br>
>>> %vbase_offs, i8* bitcast (%"MSRTTITypeDescriptor\07"* @"\01??_R0?AUA@@@8" to<br>
>>> i8*), i8* bitcast (%"MSRTTITypeDescriptor\07"* @"\01??_R0?AUT@@@8" to i8*),<br>
>>> i32 0) #2<br>
>>> -// CHECK-NEXT: %phitmp = bitcast i8* %6 to %struct.T*<br>
>>> -// CHECK-NEXT: br label %dynamic_cast.call<br>
>>> -// CHECK: dynamic_cast.call: ; preds =<br>
>>> %dynamic_cast.valid, %entry<br>
>>> -// CHECK-NEXT: %7 = phi %struct.T* [ %phitmp, %dynamic_cast.valid ], [<br>
>>> null, %entry ]<br>
>>> -// CHECK-NEXT: ret %struct.T* %7<br>
>>> -// CHECK-NEXT: }<br>
>>> +// CHECK-LABEL: define %struct.T*<br>
>>> @"\01?test5@@YAPAUT@@PAUA@@@Z"(%struct.A* %x)<br>
>>> +// CHECK: [[CHECK:%.*]] = icmp eq %struct.A* %x, null<br>
>>> +// CHECK-NEXT: br i1 [[CHECK]]<br>
>>> +// CHECK: [[VOIDP:%.*]] = bitcast %struct.A* %x to i8*<br>
>>> +// CHECK-NEXT: [[BITCAST:%.*]] = bitcast %struct.A* %x to i8**<br>
>>> +// CHECK-NEXT: [[VBTBL:%.*]] = load i8** [[BITCAST]], align 4<br>
>>> +// CHECK-NEXT: [[VBOFFP:%.*]] = getelementptr inbounds i8* [[VBTBL]],<br>
>>> i32 4<br>
>>> +// CHECK-NEXT: [[VBOFFPCAST:%.*]] = bitcast i8* [[VBOFFP]] to i32*<br>
>>> +// CHECK-NEXT: [[VBOFFS:%.*]] = load i32* [[VBOFFPCAST:%.*]], align 4<br>
>>> +// CHECK-NEXT: [[ADJ:%.*]] = getelementptr inbounds i8* [[VOIDP]], i32<br>
>>> [[VBOFFS]]<br>
>>> +// CHECK-NEXT: [[CALL:%.*]] = tail call i8* @__RTDynamicCast(i8*<br>
>>> [[ADJ]], i32 [[VBOFFS]], i8* bitcast (%"MSRTTITypeDescriptor\07"*<br>
>>> @"\01??_R0?AUA@@@8" to i8*), i8* bitcast (%"MSRTTITypeDescriptor\07"*<br>
>>> @"\01??_R0?AUT@@@8" to i8*), i32 0)<br>
>>> +// CHECK-NEXT: [[RES:%.*]] = bitcast i8* [[CALL]] to %struct.T*<br>
>>> +// CHECK-NEXT: br label<br>
>>> +// CHECK: [[RET:%.*]] = phi %struct.T*<br>
>>> +// CHECK-NEXT: ret %struct.T* [[RET]]<br>
>>><br>
>>> T* test6(B* x) { return dynamic_cast<T*>(x); }<br>
>>> -// CHECK: define %struct.T* @"\01?test6@@YAPAUT@@PAUB@@@Z"(%struct.B*<br>
>>> %x) #1 {<br>
>>> -// CHECK-NEXT: entry:<br>
>>> -// CHECK-NEXT: %0 = icmp eq %struct.B* %x, null<br>
>>> -// CHECK-NEXT: br i1 %0, label %dynamic_cast.call, label<br>
>>> %dynamic_cast.valid<br>
>>> -// CHECK: dynamic_cast.valid: ; preds =<br>
>>> %entry<br>
>>> -// CHECK-NEXT: %1 = getelementptr inbounds %struct.B* %x, i32 0, i32<br>
>>> 0, i32 0<br>
>>> -// CHECK-NEXT: %vbptr = getelementptr inbounds i8* %1, i32 4<br>
>>> -// CHECK-NEXT: %2 = bitcast i8* %vbptr to i8**<br>
>>> -// CHECK-NEXT: %vbtable = load i8** %2, align 4<br>
>>> -// CHECK-NEXT: %3 = getelementptr inbounds i8* %vbtable, i32 4<br>
>>> -// CHECK-NEXT: %4 = bitcast i8* %3 to i32*<br>
>>> -// CHECK-NEXT: %vbase_offs = load i32* %4, align 4<br>
>>> -// CHECK-NEXT: %5 = add nsw i32 %vbase_offs, 4<br>
>>> -// CHECK-NEXT: %6 = getelementptr inbounds i8* %1, i32 %5<br>
>>> -// CHECK-NEXT: %7 = tail call i8* @__RTDynamicCast(i8* %6, i32 %5, i8*<br>
>>> bitcast (%"MSRTTITypeDescriptor\07"* @"\01??_R0?AUB@@@8" to i8*), i8*<br>
>>> bitcast (%"MSRTTITypeDescriptor\07"* @"\01??_R0?AUT@@@8" to i8*), i32 0) #2<br>
>>> -// CHECK-NEXT: %phitmp = bitcast i8* %7 to %struct.T*<br>
>>> -// CHECK-NEXT: br label %dynamic_cast.call<br>
>>> -// CHECK: dynamic_cast.call: ; preds =<br>
>>> %dynamic_cast.valid, %entry<br>
>>> -// CHECK-NEXT: %8 = phi %struct.T* [ %phitmp, %dynamic_cast.valid ], [<br>
>>> null, %entry ]<br>
>>> -// CHECK-NEXT: ret %struct.T* %8<br>
>>> -// CHECK-NEXT: }<br>
>>> +// CHECK-LABEL: define %struct.T*<br>
>>> @"\01?test6@@YAPAUT@@PAUB@@@Z"(%struct.B* %x)<br>
>>> +// CHECK: [[CHECK:%.*]] = icmp eq %struct.B* %x, null<br>
>>> +// CHECK-NEXT: br i1 [[CHECK]]<br>
>>> +// CHECK: [[CAST:%.*]] = getelementptr inbounds %struct.B* %x,<br>
>>> i32 0, i32 0, i32 0<br>
>>> +// CHECK-NEXT: [[VBPTR:%.*]] = getelementptr inbounds i8* [[CAST]],<br>
>>> i32 4<br>
>>> +// CHECK-NEXT: [[BITCAST:%.*]] = bitcast i8* [[VBPTR]] to i8**<br>
>>> +// CHECK-NEXT: [[VBTBL:%.*]] = load i8** [[BITCAST]], align 4<br>
>>> +// CHECK-NEXT: [[VBOFFP:%.*]] = getelementptr inbounds i8* [[VBTBL]],<br>
>>> i32 4<br>
>>> +// CHECK-NEXT: [[VBOFFPCAST:%.*]] = bitcast i8* [[VBOFFP]] to i32*<br>
>>> +// CHECK-NEXT: [[VBOFFS:%.*]] = load i32* [[VBOFFPCAST:%.*]], align 4<br>
>>> +// CHECK-NEXT: [[DELTA:%.*]] = add nsw i32 [[VBOFFS]], 4<br>
>>> +// CHECK-NEXT: [[ADJ:%.*]] = getelementptr inbounds i8* [[CAST]], i32<br>
>>> [[DELTA]]<br>
>>> +// CHECK-NEXT: [[CALL:%.*]] = tail call i8* @__RTDynamicCast(i8*<br>
>>> [[ADJ]], i32 [[DELTA]], i8* bitcast (%"MSRTTITypeDescriptor\07"*<br>
>>> @"\01??_R0?AUB@@@8" to i8*), i8* bitcast (%"MSRTTITypeDescriptor\07"*<br>
>>> @"\01??_R0?AUT@@@8" to i8*), i32 0)<br>
>>> +// CHECK-NEXT: [[RES:%.*]] = bitcast i8* [[CALL]] to %struct.T*<br>
>>> +// CHECK-NEXT: br label<br>
>>> +// CHECK: [[RET:%.*]] = phi %struct.T*<br>
>>> +// CHECK-NEXT: ret %struct.T* [[RET]]<br>
>>><br>
>>> void* test7(V* x) { return dynamic_cast<void*>(x); }<br>
>>> -// CHECK: define i8* @"\01?test7@@YAPAXPAUV@@@Z"(%struct.V* %x) #1 {<br>
>>> -// CHECK-NEXT: entry:<br>
>>> -// CHECK-NEXT: %0 = bitcast %struct.V* %x to i8*<br>
>>> -// CHECK-NEXT: %1 = tail call i8* @__RTCastToVoid(i8* %0) #2<br>
>>> -// CHECK-NEXT: ret i8* %1<br>
>>> -// CHECK-NEXT: }<br>
>>> +// CHECK-LABEL: define i8* @"\01?test7@@YAPAXPAUV@@@Z"(%struct.V* %x)<br>
>>> +// CHECK: [[CAST:%.*]] = bitcast %struct.V* %x to i8*<br>
>>> +// CHECK-NEXT: [[RET:%.*]] = tail call i8* @__RTCastToVoid(i8*<br>
>>> [[CAST]])<br>
>>> +// CHECK-NEXT: ret i8* [[RET]]<br>
>>><br>
>>> void* test8(A* x) { return dynamic_cast<void*>(x); }<br>
>>> -// CHECK: define i8* @"\01?test8@@YAPAXPAUA@@@Z"(%struct.A* %x) #1 {<br>
>>> -// CHECK-NEXT: entry:<br>
>>> -// CHECK-NEXT: %0 = icmp eq %struct.A* %x, null<br>
>>> -// CHECK-NEXT: br i1 %0, label %dynamic_cast.call, label<br>
>>> %dynamic_cast.valid<br>
>>> -// CHECK: dynamic_cast.valid: ; preds =<br>
>>> %entry<br>
>>> -// CHECK-NEXT: %1 = bitcast %struct.A* %x to i8*<br>
>>> -// CHECK-NEXT: %2 = bitcast %struct.A* %x to i8**<br>
>>> -// CHECK-NEXT: %vbtable = load i8** %2, align 4<br>
>>> -// CHECK-NEXT: %3 = getelementptr inbounds i8* %vbtable, i32 4<br>
>>> -// CHECK-NEXT: %4 = bitcast i8* %3 to i32*<br>
>>> -// CHECK-NEXT: %vbase_offs = load i32* %4, align 4<br>
>>> -// CHECK-NEXT: %5 = getelementptr inbounds i8* %1, i32 %vbase_offs<br>
>>> -// CHECK-NEXT: %6 = tail call i8* @__RTCastToVoid(i8* %5) #2<br>
>>> -// CHECK-NEXT: br label %dynamic_cast.call<br>
>>> -// CHECK: dynamic_cast.call: ; preds =<br>
>>> %dynamic_cast.valid, %entry<br>
>>> -// CHECK-NEXT: %7 = phi i8* [ %6, %dynamic_cast.valid ], [ null,<br>
>>> %entry ]<br>
>>> -// CHECK-NEXT: ret i8* %7<br>
>>> -// CHECK-NEXT: }<br>
>>> +// CHECK-LABEL: define i8* @"\01?test8@@YAPAXPAUA@@@Z"(%struct.A* %x)<br>
>>> +// CHECK: [[CHECK:%.*]] = icmp eq %struct.A* %x, null<br>
>>> +// CHECK-NEXT: br i1 [[CHECK]]<br>
>>> +// CHECK: [[VOIDP:%.*]] = bitcast %struct.A* %x to i8*<br>
>>> +// CHECK-NEXT: [[BITCAST:%.*]] = bitcast %struct.A* %x to i8**<br>
>>> +// CHECK-NEXT: [[VBTBL:%.*]] = load i8** [[BITCAST]], align 4<br>
>>> +// CHECK-NEXT: [[VBOFFP:%.*]] = getelementptr inbounds i8* [[VBTBL]],<br>
>>> i32 4<br>
>>> +// CHECK-NEXT: [[VBOFFPCAST:%.*]] = bitcast i8* [[VBOFFP]] to i32*<br>
>>> +// CHECK-NEXT: [[VBOFFS:%.*]] = load i32* [[VBOFFPCAST:%.*]], align 4<br>
>>> +// CHECK-NEXT: [[ADJ:%.*]] = getelementptr inbounds i8* [[VOIDP]], i32<br>
>>> [[VBOFFS]]<br>
>>> +// CHECK-NEXT: [[RES:%.*]] = tail call i8* @__RTCastToVoid(i8*<br>
>>> [[ADJ]])<br>
>>> +// CHECK-NEXT: br label<br>
>>> +// CHECK: [[RET:%.*]] = phi i8*<br>
>>> +// CHECK-NEXT: ret i8* [[RET]]<br>
>>><br>
>>> void* test9(B* x) { return dynamic_cast<void*>(x); }<br>
>>> -// CHECK: define i8* @"\01?test9@@YAPAXPAUB@@@Z"(%struct.B* %x) #1 {<br>
>>> -// CHECK-NEXT: entry:<br>
>>> -// CHECK-NEXT: %0 = icmp eq %struct.B* %x, null<br>
>>> -// CHECK-NEXT: br i1 %0, label %dynamic_cast.call, label<br>
>>> %dynamic_cast.valid<br>
>>> -// CHECK: dynamic_cast.valid: ; preds =<br>
>>> %entry<br>
>>> -// CHECK-NEXT: %1 = getelementptr inbounds %struct.B* %x, i32 0, i32<br>
>>> 0, i32 0<br>
>>> -// CHECK-NEXT: %vbptr = getelementptr inbounds i8* %1, i32 4<br>
>>> -// CHECK-NEXT: %2 = bitcast i8* %vbptr to i8**<br>
>>> -// CHECK-NEXT: %vbtable = load i8** %2, align 4<br>
>>> -// CHECK-NEXT: %3 = getelementptr inbounds i8* %vbtable, i32 4<br>
>>> -// CHECK-NEXT: %4 = bitcast i8* %3 to i32*<br>
>>> -// CHECK-NEXT: %vbase_offs = load i32* %4, align 4<br>
>>> -// CHECK-NEXT: %5 = add nsw i32 %vbase_offs, 4<br>
>>> -// CHECK-NEXT: %6 = getelementptr inbounds i8* %1, i32 %5<br>
>>> -// CHECK-NEXT: %7 = tail call i8* @__RTCastToVoid(i8* %6) #2<br>
>>> -// CHECK-NEXT: br label %dynamic_cast.call<br>
>>> -// CHECK: dynamic_cast.call: ; preds =<br>
>>> %dynamic_cast.valid, %entry<br>
>>> -// CHECK-NEXT: %8 = phi i8* [ %7, %dynamic_cast.valid ], [ null,<br>
>>> %entry ]<br>
>>> -// CHECK-NEXT: ret i8* %8<br>
>>> -// CHECK-NEXT: }<br>
>>> +// CHECK-LABEL: define i8* @"\01?test9@@YAPAXPAUB@@@Z"(%struct.B* %x)<br>
>>> +// CHECK: [[CHECK:%.*]] = icmp eq %struct.B* %x, null<br>
>>> +// CHECK-NEXT: br i1 [[CHECK]]<br>
>>> +// CHECK: [[CAST:%.*]] = getelementptr inbounds %struct.B* %x,<br>
>>> i32 0, i32 0, i32 0<br>
>>> +// CHECK-NEXT: [[VBPTR:%.*]] = getelementptr inbounds i8* [[CAST]],<br>
>>> i32 4<br>
>>> +// CHECK-NEXT: [[BITCAST:%.*]] = bitcast i8* [[VBPTR]] to i8**<br>
>>> +// CHECK-NEXT: [[VBTBL:%.*]] = load i8** [[BITCAST]], align 4<br>
>>> +// CHECK-NEXT: [[VBOFFP:%.*]] = getelementptr inbounds i8* [[VBTBL]],<br>
>>> i32 4<br>
>>> +// CHECK-NEXT: [[VBOFFPCAST:%.*]] = bitcast i8* [[VBOFFP]] to i32*<br>
>>> +// CHECK-NEXT: [[VBOFFS:%.*]] = load i32* [[VBOFFPCAST:%.*]], align 4<br>
>>> +// CHECK-NEXT: [[DELTA:%.*]] = add nsw i32 [[VBOFFS]], 4<br>
>>> +// CHECK-NEXT: [[ADJ:%.*]] = getelementptr inbounds i8* [[CAST]], i32<br>
>>> [[DELTA]]<br>
>>> +// CHECK-NEXT: [[CALL:%.*]] = tail call i8* @__RTCastToVoid(i8*<br>
>>> [[ADJ]])<br>
>>> +// CHECK-NEXT: br label<br>
>>> +// CHECK: [[RET:%.*]] = phi i8*<br>
>>> +// CHECK-NEXT: ret i8* [[RET]]<br>
>>> +<br>
>>><br>
>>> Modified: cfe/trunk/test/CodeGenCXX/microsoft-abi-typeid.cpp<br>
>>> URL:<br>
>>> <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/microsoft-abi-typeid.cpp?rev=211473&r1=211472&r2=211473&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/microsoft-abi-typeid.cpp?rev=211473&r1=211472&r2=211473&view=diff</a><br>
>>><br>
>>> ==============================================================================<br>
>>> --- cfe/trunk/test/CodeGenCXX/microsoft-abi-typeid.cpp (original)<br>
>>> +++ cfe/trunk/test/CodeGenCXX/microsoft-abi-typeid.cpp Sun Jun 22<br>
>>> 14:05:33 2014<br>
>>> @@ -1,58 +1,45 @@<br>
>>> -// RUN: %clang_cc1 -emit-llvm -O2 -optzns -o - -triple=i386-pc-win32<br>
>>> 2>/dev/null %s | FileCheck %s<br>
>>> -// REQUIRES: asserts<br>
>>> +// RUN: %clang_cc1 -emit-llvm -O1 -o - -triple=i386-pc-win32 %s |<br>
>>> FileCheck %s<br>
>>><br>
>>> -struct type_info { const char* raw_name() const; };<br>
>>> +struct type_info;<br>
>>> namespace std { using ::type_info; }<br>
>>><br>
>>> -struct V { virtual void f() {}; };<br>
>>> -struct A : virtual V {};<br>
>>> +struct V { virtual void f(); };<br>
>>> +struct A : virtual V { A(); };<br>
>>><br>
>>> -A a;<br>
>>> -int b;<br>
>>> +extern A a;<br>
>>> +extern int b;<br>
>>> A* fn();<br>
>>><br>
>>> const std::type_info* test0_typeid() { return &typeid(int); }<br>
>>> -// CHECK: define %struct.type_info*<br>
>>> @"\01?test0_typeid@@YAPBUtype_info@@XZ"() #0 {<br>
>>> -// CHECK-NEXT: entry:<br>
>>> -// CHECK-NEXT: ret %struct.type_info* bitcast<br>
>>> (%"MSRTTITypeDescriptor\02"* @"\01??_R0H@8" to %struct.type_info*)<br>
>>> -// CHECK-NEXT: }<br>
>>> +// CHECK-LABEL: define %struct.type_info*<br>
>>> @"\01?test0_typeid@@YAPBUtype_info@@XZ"()<br>
>>> +// CHECK: ret %struct.type_info* bitcast (%"MSRTTITypeDescriptor\02"*<br>
>>> @"\01??_R0H@8" to %struct.type_info*)<br>
>>><br>
>>> const std::type_info* test1_typeid() { return &typeid(A); }<br>
>>> -// CHECK: define %struct.type_info*<br>
>>> @"\01?test1_typeid@@YAPBUtype_info@@XZ"() #0 {<br>
>>> -// CHECK-NEXT: entry:<br>
>>> -// CHECK-NEXT: ret %struct.type_info* bitcast<br>
>>> (%"MSRTTITypeDescriptor\07"* @"\01??_R0?AUA@@@8" to %struct.type_info*)<br>
>>> -// CHECK-NEXT: }<br>
>>> +// CHECK-LABEL: define %struct.type_info*<br>
>>> @"\01?test1_typeid@@YAPBUtype_info@@XZ"()<br>
>>> +// CHECK: ret %struct.type_info* bitcast (%"MSRTTITypeDescriptor\07"*<br>
>>> @"\01??_R0?AUA@@@8" to %struct.type_info*)<br>
>>><br>
>>> const std::type_info* test2_typeid() { return &typeid(&a); }<br>
>>> -// CHECK: define %struct.type_info*<br>
>>> @"\01?test2_typeid@@YAPBUtype_info@@XZ"() #0 {<br>
>>> -// CHECK-NEXT: entry:<br>
>>> -// CHECK-NEXT: ret %struct.type_info* bitcast<br>
>>> (%"MSRTTITypeDescriptor\07"* @"\01??_R0PAUA@@@8" to %struct.type_info*)<br>
>>> -// CHECK-NEXT: }<br>
>>> +// CHECK-LABEL: define %struct.type_info*<br>
>>> @"\01?test2_typeid@@YAPBUtype_info@@XZ"()<br>
>>> +// CHECK: ret %struct.type_info* bitcast (%"MSRTTITypeDescriptor\07"*<br>
>>> @"\01??_R0PAUA@@@8" to %struct.type_info*)<br>
>>><br>
>>> const std::type_info* test3_typeid() { return &typeid(*fn()); }<br>
>>> -// CHECK: define %struct.type_info*<br>
>>> @"\01?test3_typeid@@YAPBUtype_info@@XZ"() #1 {<br>
>>> -// CHECK-NEXT: entry:<br>
>>> -// CHECK-NEXT: %call = tail call %struct.A* @"\01?fn@@YAPAUA@@XZ"() #3<br>
>>> -// CHECK-NEXT: %0 = icmp eq %struct.A* %call, null<br>
>>> -// CHECK-NEXT: br i1 %0, label %type_id.call, label %type_id.valid<br>
>>> -// CHECK: type_id.valid: ; preds =<br>
>>> %entry<br>
>>> -// CHECK-NEXT: %1 = bitcast %struct.A* %call to i8*<br>
>>> -// CHECK-NEXT: %2 = bitcast %struct.A* %call to i8**<br>
>>> -// CHECK-NEXT: %vbtable = load i8** %2, align 4<br>
>>> -// CHECK-NEXT: %3 = getelementptr inbounds i8* %vbtable, i32 4<br>
>>> -// CHECK-NEXT: %4 = bitcast i8* %3 to i32*<br>
>>> -// CHECK-NEXT: %vbase_offs = load i32* %4, align 4<br>
>>> -// CHECK-NEXT: %5 = getelementptr inbounds i8* %1, i32 %vbase_offs<br>
>>> -// CHECK-NEXT: br label %type_id.call<br>
>>> -// CHECK: type_id.call: ; preds =<br>
>>> %type_id.valid, %entry<br>
>>> -// CHECK-NEXT: %6 = phi i8* [ %5, %type_id.valid ], [ null, %entry ]<br>
>>> -// CHECK-NEXT: %7 = tail call i8* @__RTtypeid(i8* %6) #3<br>
>>> -// CHECK-NEXT: %8 = bitcast i8* %7 to %struct.type_info*<br>
>>> -// CHECK-NEXT: ret %struct.type_info* %8<br>
>>> -// CHECK-NEXT: }<br>
>>> +// CHECK-LABEL: define %struct.type_info*<br>
>>> @"\01?test3_typeid@@YAPBUtype_info@@XZ"()<br>
>>> +// CHECK: [[CALL:%.*]] = tail call %struct.A*<br>
>>> @"\01?fn@@YAPAUA@@XZ"()<br>
>>> +// CHECK-NEXT: [[CMP:%.*]] = icmp eq %struct.A* [[CALL]], null<br>
>>> +// CHECK-NEXT: br i1 [[CMP]]<br>
>>> +// CHECK: tail call i8* @__RTtypeid(i8* null)<br>
>>> +// CHECK-NEXT: unreachable<br>
>>> +// CHECK: [[THIS:%.*]] = bitcast %struct.A* [[CALL]] to i8*<br>
>>> +// CHECK-NEXT: [[VBTBLP:%.*]] = bitcast %struct.A* [[CALL]] to i8**<br>
>>> +// CHECK-NEXT: [[VBTBL:%.*]] = load i8** [[VBTBLP]], align 4<br>
>>> +// CHECK-NEXT: [[VBSLOT:%.*]] = getelementptr inbounds i8* [[VBTBL]],<br>
>>> i32 4<br>
>>> +// CHECK-NEXT: [[VBITCST:%.*]] = bitcast i8* [[VBSLOT]] to i32*<br>
>>> +// CHECK-NEXT: [[VBASE_OFFS:%.*]] = load i32* [[VBITCST]], align 4<br>
>>> +// CHECK-NEXT: [[ADJ:%.*]] = getelementptr inbounds i8* [[THIS]], i32<br>
>>> [[VBASE_OFFS]]<br>
>>> +// CHECK-NEXT: [[RT:%.*]] = tail call i8* @__RTtypeid(i8* [[ADJ]])<br>
>>> +// CHECK-NEXT: [[RET:%.*]] = bitcast i8* [[RT]] to %struct.type_info*<br>
>>> +// CHECK-NEXT: ret %struct.type_info* [[RET]]<br>
>>><br>
>>> const std::type_info* test4_typeid() { return &typeid(b); }<br>
>>> -// CHECK: define %struct.type_info*<br>
>>> @"\01?test4_typeid@@YAPBUtype_info@@XZ"() #0 {<br>
>>> -// CHECK-NEXT: entry:<br>
>>> -// CHECK-NEXT: ret %struct.type_info* bitcast<br>
>>> (%"MSRTTITypeDescriptor\02"* @"\01??_R0H@8" to %struct.type_info*)<br>
>>> -// CHECK-NEXT: }<br>
>>> +// CHECK: define %struct.type_info*<br>
>>> @"\01?test4_typeid@@YAPBUtype_info@@XZ"()<br>
>>> +// CHECK: ret %struct.type_info* bitcast (%"MSRTTITypeDescriptor\02"*<br>
>>> @"\01??_R0H@8" to %struct.type_info*)<br>
>>><br>
>>><br>
>>> _______________________________________________<br>
>>> cfe-commits mailing list<br>
>>> <a href="mailto:cfe-commits@cs.uiuc.edu">cfe-commits@cs.uiuc.edu</a><br>
>>> <a href="http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits" target="_blank">http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits</a><br>
><br>
><br>
</div></div></blockquote></div><br></div></div>