From: Timur Iskhodzhanov Date: Wed, 21 Aug 2013 06:25:03 +0000 (+0000) Subject: Abstract out virtual calls and virtual function prologue code generation; implement... X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=8f189a9911a992a5c4118c3789485a85bd96e045;p=clang Abstract out virtual calls and virtual function prologue code generation; implement them for -cxx-abi microsoft git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@188870 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/AST/VTableBuilder.h b/include/clang/AST/VTableBuilder.h index 9568efff80..2ea455e1fa 100644 --- a/include/clang/AST/VTableBuilder.h +++ b/include/clang/AST/VTableBuilder.h @@ -417,6 +417,10 @@ public: /// If nonzero, holds the vbtable index of the virtual base with the vfptr. uint64_t VBTableIndex; + /// If nonnull, holds the last vbase which contains the vfptr that the + /// method definition is adjusted to. + const CXXRecordDecl *VBase; + /// This is the offset of the vfptr from the start of the last vbase, or the /// complete type if there are no virtual bases. CharUnits VFTableOffset; @@ -425,19 +429,24 @@ public: uint64_t Index; MethodVFTableLocation() - : VBTableIndex(0), VFTableOffset(CharUnits::Zero()), Index(0) {} + : VBTableIndex(0), VBase(0), VFTableOffset(CharUnits::Zero()), + Index(0) {} - MethodVFTableLocation(uint64_t VBTableIndex, CharUnits VFTableOffset, - uint64_t Index) - : VBTableIndex(VBTableIndex), VFTableOffset(VFTableOffset), - Index(Index) {} + MethodVFTableLocation(uint64_t VBTableIndex, const CXXRecordDecl *VBase, + CharUnits VFTableOffset, uint64_t Index) + : VBTableIndex(VBTableIndex), VBase(VBase), + VFTableOffset(VFTableOffset), Index(Index) {} bool operator<(const MethodVFTableLocation &other) const { - if (VBTableIndex != other.VBTableIndex) + if (VBTableIndex != other.VBTableIndex) { + assert(VBase != other.VBase); return VBTableIndex < other.VBTableIndex; + } if (VFTableOffset != other.VFTableOffset) return VFTableOffset < other.VFTableOffset; - return Index < other.Index; + if (Index != other.Index) + return Index < other.Index; + return false; } }; diff --git a/lib/AST/VTableBuilder.cpp b/lib/AST/VTableBuilder.cpp index 9067b4bd59..ffa01681c5 100644 --- a/lib/AST/VTableBuilder.cpp +++ b/lib/AST/VTableBuilder.cpp @@ -2490,6 +2490,10 @@ private: /// this method's base has, or zero. const uint64_t VBTableIndex; + /// VBase - If nonnull, holds the last vbase which contains the vfptr that + /// the method definition is adjusted to. + const CXXRecordDecl *VBase; + /// VFTableIndex - The index in the vftable that this method has. const uint64_t VFTableIndex; @@ -2498,11 +2502,13 @@ private: /// or used for vcalls in the most derived class. bool Shadowed; - MethodInfo(uint64_t VBTableIndex, uint64_t VFTableIndex) - : VBTableIndex(VBTableIndex), VFTableIndex(VFTableIndex), + MethodInfo(uint64_t VBTableIndex, const CXXRecordDecl *VBase, + uint64_t VFTableIndex) + : VBTableIndex(VBTableIndex), VBase(VBase), VFTableIndex(VFTableIndex), Shadowed(false) {} - MethodInfo() : VBTableIndex(0), VFTableIndex(0), Shadowed(false) {} + MethodInfo() + : VBTableIndex(0), VBase(0), VFTableIndex(0), Shadowed(false) {} }; typedef llvm::DenseMap MethodInfoMapTy; @@ -2584,8 +2590,8 @@ private: // and the entries shadowed by return adjusting thunks. if (MD->getParent() != MostDerivedClass || MI.Shadowed) continue; - MethodVFTableLocation Loc(MI.VBTableIndex, WhichVFPtr.VFPtrOffset, - MI.VFTableIndex); + MethodVFTableLocation Loc(MI.VBTableIndex, MI.VBase, + WhichVFPtr.VFPtrOffset, MI.VFTableIndex); if (const CXXDestructorDecl *DD = dyn_cast(MD)) { MethodVFTableLocations[GlobalDecl(DD, Dtor_Deleting)] = Loc; } else { @@ -2838,6 +2844,7 @@ void VFTableBuilder::AddMethods(BaseSubobject Base, unsigned BaseDepth, // No return adjustment needed - just replace the overridden method info // with the current info. MethodInfo MI(OverriddenMethodInfo.VBTableIndex, + OverriddenMethodInfo.VBase, OverriddenMethodInfo.VFTableIndex); MethodInfoMap.erase(OverriddenMDIterator); @@ -2882,7 +2889,7 @@ void VFTableBuilder::AddMethods(BaseSubobject Base, unsigned BaseDepth, // it requires return adjustment. Insert the method info for this method. unsigned VBIndex = LastVBase ? GetVBTableIndex(MostDerivedClass, LastVBase) : 0; - MethodInfo MI(VBIndex, Components.size()); + MethodInfo MI(VBIndex, LastVBase, Components.size()); assert(!MethodInfoMap.count(MD) && "Should not have method info for this method yet!"); diff --git a/lib/CodeGen/CGCXX.cpp b/lib/CodeGen/CGCXX.cpp index 0453b73006..4932c07844 100644 --- a/lib/CodeGen/CGCXX.cpp +++ b/lib/CodeGen/CGCXX.cpp @@ -272,23 +272,12 @@ CodeGenModule::GetAddrOfCXXDestructor(const CXXDestructorDecl *dtor, /*ForVTable=*/false)); } -llvm::Value * -CodeGenFunction::BuildVirtualCall(GlobalDecl GD, llvm::Value *This, - llvm::Type *Ty) { - GD = GD.getCanonicalDecl(); - uint64_t VTableIndex = CGM.getVTableContext().getMethodVTableIndex(GD); - - Ty = Ty->getPointerTo()->getPointerTo(); - llvm::Value *VTable = GetVTablePtr(This, Ty); - llvm::Value *VFuncPtr = - Builder.CreateConstInBoundsGEP1_64(VTable, VTableIndex, "vfn"); - return Builder.CreateLoad(VFuncPtr); -} - static llvm::Value *BuildAppleKextVirtualCall(CodeGenFunction &CGF, GlobalDecl GD, llvm::Type *Ty, const CXXRecordDecl *RD) { + assert(!CGF.CGM.getTarget().getCXXABI().isMicrosoft() && + "No kext in Microsoft ABI"); GD = GD.getCanonicalDecl(); CodeGenModule &CGM = CGF.CGM; llvm::Value *VTable = CGM.getVTables().GetAddrOfVTable(RD); diff --git a/lib/CodeGen/CGCXXABI.h b/lib/CodeGen/CGCXXABI.h index c5ff02488f..5baedfba1a 100644 --- a/lib/CodeGen/CGCXXABI.h +++ b/lib/CodeGen/CGCXXABI.h @@ -256,6 +256,23 @@ public: /// Emit destructor variants required by this ABI. virtual void EmitCXXDestructors(const CXXDestructorDecl *D) = 0; + /// Get the type of the implicit "this" parameter used by a method. May return + /// zero if no specific type is applicable, e.g. if the ABI expects the "this" + /// parameter to point to some artificial offset in a complete object due to + /// vbases being reordered. + virtual const CXXRecordDecl * + getThisArgumentTypeForMethod(const CXXMethodDecl *MD) { + return MD->getParent(); + } + + /// Perform ABI-specific "this" argument adjustment required prior to + /// a virtual function call. + virtual llvm::Value *adjustThisArgumentForVirtualCall(CodeGenFunction &CGF, + GlobalDecl GD, + llvm::Value *This) { + return This; + } + /// Build the ABI-specific portion of the parameter list for a /// function. This generally involves a 'this' parameter and /// possibly some extra data for constructors and destructors. @@ -267,6 +284,13 @@ public: QualType &ResTy, FunctionArgList &Params) = 0; + /// Perform ABI-specific "this" parameter adjustment in a virtual function + /// prologue. + virtual llvm::Value *adjustThisParameterInVirtualFunctionPrologue( + CodeGenFunction &CGF, GlobalDecl GD, llvm::Value *This) { + return This; + } + /// Emit the ABI-specific prolog for the function. virtual void EmitInstanceFunctionProlog(CodeGenFunction &CGF) = 0; @@ -279,6 +303,12 @@ public: CallExpr::const_arg_iterator ArgBeg, CallExpr::const_arg_iterator ArgEnd) = 0; + /// Build a virtual function pointer in the ABI-specific way. + virtual llvm::Value *getVirtualFunctionPointer(CodeGenFunction &CGF, + GlobalDecl GD, + llvm::Value *This, + llvm::Type *Ty) = 0; + /// Emit the ABI-specific virtual destructor call. virtual void EmitVirtualDestructorCall(CodeGenFunction &CGF, const CXXDestructorDecl *Dtor, diff --git a/lib/CodeGen/CGCall.cpp b/lib/CodeGen/CGCall.cpp index 11ee3883b3..32dbfab07d 100644 --- a/lib/CodeGen/CGCall.cpp +++ b/lib/CodeGen/CGCall.cpp @@ -160,6 +160,8 @@ static CallingConv getCallingConventionForDecl(const Decl *D) { /// Arrange the argument and result information for a call to an /// unknown C++ non-static member function of the given abstract type. +/// (Zero value of RD means we don't have any meaningful "this" argument type, +/// so fall back to a generic pointer type). /// The member function must be an ordinary function, i.e. not a /// constructor or destructor. const CGFunctionInfo & @@ -168,7 +170,10 @@ CodeGenTypes::arrangeCXXMethodType(const CXXRecordDecl *RD, SmallVector argTypes; // Add the 'this' pointer. - argTypes.push_back(GetThisType(Context, RD)); + if (RD) + argTypes.push_back(GetThisType(Context, RD)); + else + argTypes.push_back(Context.VoidPtrTy); return ::arrangeCXXMethodType(*this, argTypes, FTP->getCanonicalTypeUnqualified().getAs()); @@ -187,7 +192,9 @@ CodeGenTypes::arrangeCXXMethodDeclaration(const CXXMethodDecl *MD) { if (MD->isInstance()) { // The abstract case is perfectly fine. - return arrangeCXXMethodType(MD->getParent(), prototype.getTypePtr()); + const CXXRecordDecl *ThisType = + CGM.getCXXABI().getThisArgumentTypeForMethod(MD); + return arrangeCXXMethodType(ThisType, prototype.getTypePtr()); } return arrangeFreeFunctionType(prototype); @@ -1341,6 +1348,11 @@ void CodeGenFunction::EmitFunctionProlog(const CGFunctionInfo &FI, if (isPromoted) V = emitArgumentDemotion(*this, Arg, V); + if (const CXXMethodDecl *MD = dyn_cast_or_null(CurCodeDecl)) { + if (MD->isVirtual() && Arg == CXXABIThisDecl) + V = CGM.getCXXABI().adjustThisParameterInVirtualFunctionPrologue(*this, CurGD, V); + } + // Because of merging of function types from multiple decls it is // possible for the type of an argument to not match the corresponding // type in the function type. Since we are codegening the callee diff --git a/lib/CodeGen/CGClass.cpp b/lib/CodeGen/CGClass.cpp index d00d1d062a..f47920d8b5 100644 --- a/lib/CodeGen/CGClass.cpp +++ b/lib/CodeGen/CGClass.cpp @@ -2125,7 +2125,7 @@ CodeGenFunction::EmitCXXOperatorMemberCallee(const CXXOperatorCallExpr *E, CGM.getTypes().arrangeCXXMethodDeclaration(MD)); if (UseVirtualCall(getContext(), E, MD)) - return BuildVirtualCall(MD, This, fnType); + return CGM.getCXXABI().getVirtualFunctionPointer(*this, MD, This, fnType); return CGM.GetAddrOfFunction(MD, fnType); } diff --git a/lib/CodeGen/CGExprCXX.cpp b/lib/CodeGen/CGExprCXX.cpp index 5ec135ea50..43318a73d5 100644 --- a/lib/CodeGen/CGExprCXX.cpp +++ b/lib/CodeGen/CGExprCXX.cpp @@ -299,7 +299,7 @@ RValue CodeGenFunction::EmitCXXMemberCallExpr(const CXXMemberCallExpr *CE, if (const CXXConstructorDecl *Ctor = dyn_cast(MD)) { Callee = CGM.GetAddrOfFunction(GlobalDecl(Ctor, Ctor_Complete), Ty); } else if (UseVirtualCall) { - Callee = BuildVirtualCall(MD, This, Ty); + Callee = CGM.getCXXABI().getVirtualFunctionPointer(*this, MD, This, Ty); } else { if (getLangOpts().AppleKext && MD->isVirtual() && @@ -312,6 +312,9 @@ RValue CodeGenFunction::EmitCXXMemberCallExpr(const CXXMemberCallExpr *CE, } } + if (MD->isVirtual()) + This = CGM.getCXXABI().adjustThisArgumentForVirtualCall(*this, MD, This); + return EmitCXXMemberCall(MD, CE->getExprLoc(), Callee, ReturnValue, This, /*ImplicitParam=*/0, QualType(), CE->arg_begin(), CE->arg_end()); diff --git a/lib/CodeGen/CGVTables.h b/lib/CodeGen/CGVTables.h index bd70b5c359..e4f5366bae 100644 --- a/lib/CodeGen/CGVTables.h +++ b/lib/CodeGen/CGVTables.h @@ -31,6 +31,8 @@ namespace CodeGen { class CodeGenVTables { CodeGenModule &CGM; + // FIXME: Consider moving VTContext and VFTContext into respective CXXABI + // classes? VTableContext VTContext; OwningPtr VFTContext; @@ -78,6 +80,8 @@ public: VTableContext &getVTableContext() { return VTContext; } + MicrosoftVFTableContext &getVFTableContext() { return *VFTContext.get(); } + /// getSubVTTIndex - Return the index of the sub-VTT for the base class of the /// given record decl. uint64_t getSubVTTIndex(const CXXRecordDecl *RD, BaseSubobject Base); diff --git a/lib/CodeGen/CodeGenFunction.h b/lib/CodeGen/CodeGenFunction.h index 688b12fd45..af9373a3c7 100644 --- a/lib/CodeGen/CodeGenFunction.h +++ b/lib/CodeGen/CodeGenFunction.h @@ -2102,8 +2102,6 @@ public: void EmitNoreturnRuntimeCallOrInvoke(llvm::Value *callee, ArrayRef args); - llvm::Value *BuildVirtualCall(GlobalDecl GD, llvm::Value *This, - llvm::Type *Ty); llvm::Value *BuildAppleKextVirtualCall(const CXXMethodDecl *MD, NestedNameSpecifier *Qual, llvm::Type *Ty); diff --git a/lib/CodeGen/CodeGenModule.h b/lib/CodeGen/CodeGenModule.h index 393d96dc3a..96b97bc180 100644 --- a/lib/CodeGen/CodeGenModule.h +++ b/lib/CodeGen/CodeGenModule.h @@ -519,8 +519,13 @@ public: CodeGenTypes &getTypes() { return Types; } CodeGenVTables &getVTables() { return VTables; } + VTableContext &getVTableContext() { return VTables.getVTableContext(); } + MicrosoftVFTableContext &getVFTableContext() { + return VTables.getVFTableContext(); + } + llvm::MDNode *getTBAAInfo(QualType QTy); llvm::MDNode *getTBAAInfoForVTablePtr(); llvm::MDNode *getTBAAStructInfo(QualType QTy); diff --git a/lib/CodeGen/ItaniumCXXABI.cpp b/lib/CodeGen/ItaniumCXXABI.cpp index f3ac03dbce..66387d3268 100644 --- a/lib/CodeGen/ItaniumCXXABI.cpp +++ b/lib/CodeGen/ItaniumCXXABI.cpp @@ -142,6 +142,9 @@ public: CallExpr::const_arg_iterator ArgBeg, CallExpr::const_arg_iterator ArgEnd); + llvm::Value *getVirtualFunctionPointer(CodeGenFunction &CGF, GlobalDecl GD, + llvm::Value *This, llvm::Type *Ty); + void EmitVirtualDestructorCall(CodeGenFunction &CGF, const CXXDestructorDecl *Dtor, CXXDtorType DtorType, SourceLocation CallLoc, @@ -885,6 +888,20 @@ void ItaniumCXXABI::EmitConstructorCall(CodeGenFunction &CGF, This, VTT, VTTTy, ArgBeg, ArgEnd); } +llvm::Value *ItaniumCXXABI::getVirtualFunctionPointer(CodeGenFunction &CGF, + GlobalDecl GD, + llvm::Value *This, + llvm::Type *Ty) { + GD = GD.getCanonicalDecl(); + Ty = Ty->getPointerTo()->getPointerTo(); + llvm::Value *VTable = CGF.GetVTablePtr(This, Ty); + + uint64_t VTableIndex = CGM.getVTableContext().getMethodVTableIndex(GD); + llvm::Value *VFuncPtr = + CGF.Builder.CreateConstInBoundsGEP1_64(VTable, VTableIndex, "vfn"); + return CGF.Builder.CreateLoad(VFuncPtr); +} + void ItaniumCXXABI::EmitVirtualDestructorCall(CodeGenFunction &CGF, const CXXDestructorDecl *Dtor, CXXDtorType DtorType, @@ -895,8 +912,8 @@ void ItaniumCXXABI::EmitVirtualDestructorCall(CodeGenFunction &CGF, const CGFunctionInfo *FInfo = &CGM.getTypes().arrangeCXXDestructor(Dtor, DtorType); llvm::Type *Ty = CGF.CGM.getTypes().GetFunctionType(*FInfo); - llvm::Value *Callee - = CGF.BuildVirtualCall(GlobalDecl(Dtor, DtorType), This, Ty); + llvm::Value *Callee = + getVirtualFunctionPointer(CGF, GlobalDecl(Dtor, DtorType), This, Ty); CGF.EmitCXXMemberCall(Dtor, CallLoc, Callee, ReturnValueSlot(), This, /*ImplicitParam=*/0, QualType(), 0, 0); diff --git a/lib/CodeGen/MicrosoftCXXABI.cpp b/lib/CodeGen/MicrosoftCXXABI.cpp index b2c9ef0213..79f142e071 100644 --- a/lib/CodeGen/MicrosoftCXXABI.cpp +++ b/lib/CodeGen/MicrosoftCXXABI.cpp @@ -113,10 +113,34 @@ public: void EmitCXXDestructors(const CXXDestructorDecl *D); + const CXXRecordDecl *getThisArgumentTypeForMethod(const CXXMethodDecl *MD) { + MD = MD->getCanonicalDecl(); + if (MD->isVirtual() && !isa(MD)) { + MicrosoftVFTableContext::MethodVFTableLocation ML = + CGM.getVFTableContext().getMethodVFTableLocation(MD); + // The vbases might be ordered differently in the final overrider object + // and the complete object, so the "this" argument may sometimes point to + // memory that has no particular type (e.g. past the complete object). + // In this case, we just use a generic pointer type. + // FIXME: might want to have a more precise type in the non-virtual + // multiple inheritance case. + if (ML.VBase || !ML.VFTableOffset.isZero()) + return 0; + } + return MD->getParent(); + } + + llvm::Value *adjustThisArgumentForVirtualCall(CodeGenFunction &CGF, + GlobalDecl GD, + llvm::Value *This); + void BuildInstanceFunctionParams(CodeGenFunction &CGF, QualType &ResTy, FunctionArgList &Params); + llvm::Value *adjustThisParameterInVirtualFunctionPrologue( + CodeGenFunction &CGF, GlobalDecl GD, llvm::Value *This); + void EmitInstanceFunctionProlog(CodeGenFunction &CGF); void EmitConstructorCall(CodeGenFunction &CGF, @@ -125,7 +149,10 @@ public: llvm::Value *This, CallExpr::const_arg_iterator ArgBeg, CallExpr::const_arg_iterator ArgEnd); - + + llvm::Value *getVirtualFunctionPointer(CodeGenFunction &CGF, GlobalDecl GD, + llvm::Value *This, llvm::Type *Ty); + void EmitVirtualDestructorCall(CodeGenFunction &CGF, const CXXDestructorDecl *Dtor, CXXDtorType DtorType, SourceLocation CallLoc, @@ -423,6 +450,34 @@ void MicrosoftCXXABI::EmitCXXDestructors(const CXXDestructorDecl *D) { CGM.EmitGlobal(GlobalDecl(D, Dtor_Base)); } +llvm::Value *MicrosoftCXXABI::adjustThisArgumentForVirtualCall( + CodeGenFunction &CGF, GlobalDecl GD, llvm::Value *This) { + GD = GD.getCanonicalDecl(); + const CXXMethodDecl *MD = cast(GD.getDecl()); + if (isa(MD)) + return This; + + MicrosoftVFTableContext::MethodVFTableLocation ML = + CGM.getVFTableContext().getMethodVFTableLocation(GD); + + unsigned AS = cast(This->getType())->getAddressSpace(); + llvm::Type *charPtrTy = CGF.Int8Ty->getPointerTo(AS); + if (ML.VBase) { + This = CGF.Builder.CreateBitCast(This, charPtrTy); + llvm::Value *VBaseOffset = CGM.getCXXABI() + .GetVirtualBaseClassOffset(CGF, This, MD->getParent(), ML.VBase); + This = CGF.Builder.CreateInBoundsGEP(This, VBaseOffset); + } + CharUnits StaticOffset = ML.VFTableOffset; + if (!StaticOffset.isZero()) { + assert(StaticOffset.isPositive()); + This = CGF.Builder.CreateBitCast(This, charPtrTy); + This = CGF.Builder + .CreateConstInBoundsGEP1_64(This, StaticOffset.getQuantity()); + } + return This; +} + static bool IsDeletingDtor(GlobalDecl GD) { const CXXMethodDecl* MD = cast(GD.getDecl()); if (isa(MD)) { @@ -457,6 +512,41 @@ void MicrosoftCXXABI::BuildInstanceFunctionParams(CodeGenFunction &CGF, } } +llvm::Value *MicrosoftCXXABI::adjustThisParameterInVirtualFunctionPrologue( + CodeGenFunction &CGF, GlobalDecl GD, llvm::Value *This) { + GD = GD.getCanonicalDecl(); + const CXXMethodDecl *MD = cast(GD.getDecl()); + if (isa(MD)) + return This; + + // In this ABI, every virtual function takes a pointer to one of the + // subobjects that first defines it as the 'this' parameter, rather than a + // pointer to ther final overrider subobject. Thus, we need to adjust it back + // to the final overrider subobject before use. + // See comments in the MicrosoftVFTableContext implementation for the details. + + MicrosoftVFTableContext::MethodVFTableLocation ML = + CGM.getVFTableContext().getMethodVFTableLocation(GD); + CharUnits Adjustment = ML.VFTableOffset; + if (ML.VBase) { + const ASTRecordLayout &DerivedLayout = + CGF.getContext().getASTRecordLayout(MD->getParent()); + Adjustment += DerivedLayout.getVBaseClassOffset(ML.VBase); + } + + if (Adjustment.isZero()) + return This; + + unsigned AS = cast(This->getType())->getAddressSpace(); + llvm::Type *charPtrTy = CGF.Int8Ty->getPointerTo(AS), + *thisTy = This->getType(); + + This = CGF.Builder.CreateBitCast(This, charPtrTy); + assert(Adjustment.isPositive()); + This = CGF.Builder.CreateConstGEP1_64(This, -Adjustment.getQuantity()); + return CGF.Builder.CreateBitCast(This, thisTy); +} + void MicrosoftCXXABI::EmitInstanceFunctionProlog(CodeGenFunction &CGF) { EmitThisParam(CGF); @@ -514,6 +604,24 @@ void MicrosoftCXXABI::EmitConstructorCall(CodeGenFunction &CGF, ImplicitParam, ImplicitParamTy, ArgBeg, ArgEnd); } +llvm::Value *MicrosoftCXXABI::getVirtualFunctionPointer(CodeGenFunction &CGF, + GlobalDecl GD, + llvm::Value *This, + llvm::Type *Ty) { + GD = GD.getCanonicalDecl(); + CGBuilderTy &Builder = CGF.Builder; + + Ty = Ty->getPointerTo()->getPointerTo(); + llvm::Value *VPtr = adjustThisArgumentForVirtualCall(CGF, GD, This); + llvm::Value *VTable = CGF.GetVTablePtr(VPtr, Ty); + + MicrosoftVFTableContext::MethodVFTableLocation ML = + CGM.getVFTableContext().getMethodVFTableLocation(GD); + llvm::Value *VFuncPtr = + Builder.CreateConstInBoundsGEP1_64(VTable, ML.Index, "vfn"); + return Builder.CreateLoad(VFuncPtr); +} + void MicrosoftCXXABI::EmitVirtualDestructorCall(CodeGenFunction &CGF, const CXXDestructorDecl *Dtor, CXXDtorType DtorType, @@ -523,15 +631,15 @@ void MicrosoftCXXABI::EmitVirtualDestructorCall(CodeGenFunction &CGF, // We have only one destructor in the vftable but can get both behaviors // by passing an implicit bool parameter. - const CGFunctionInfo *FInfo - = &CGM.getTypes().arrangeCXXDestructor(Dtor, Dtor_Deleting); + const CGFunctionInfo *FInfo = + &CGM.getTypes().arrangeCXXDestructor(Dtor, Dtor_Deleting); llvm::Type *Ty = CGF.CGM.getTypes().GetFunctionType(*FInfo); - llvm::Value *Callee - = CGF.BuildVirtualCall(GlobalDecl(Dtor, Dtor_Deleting), This, Ty); + llvm::Value *Callee = + getVirtualFunctionPointer(CGF, GlobalDecl(Dtor, Dtor_Deleting), This, Ty); ASTContext &Context = CGF.getContext(); - llvm::Value *ImplicitParam - = llvm::ConstantInt::get(llvm::IntegerType::getInt1Ty(CGF.getLLVMContext()), + llvm::Value *ImplicitParam = + llvm::ConstantInt::get(llvm::IntegerType::getInt1Ty(CGF.getLLVMContext()), DtorType == Dtor_Deleting); CGF.EmitCXXMemberCall(Dtor, CallLoc, Callee, ReturnValueSlot(), This, diff --git a/test/CodeGenCXX/microsoft-abi-multiple-nonvirtual-inheritance.cpp b/test/CodeGenCXX/microsoft-abi-multiple-nonvirtual-inheritance.cpp new file mode 100644 index 0000000000..9059e6f028 --- /dev/null +++ b/test/CodeGenCXX/microsoft-abi-multiple-nonvirtual-inheritance.cpp @@ -0,0 +1,147 @@ +// RUN: %clang_cc1 -fno-rtti -emit-llvm %s -o - -cxx-abi microsoft -triple=i386-pc-win32 | FileCheck %s + +struct Left { + virtual void left(); +}; + +struct Right { + virtual void right(); +}; + +struct ChildNoOverride : Left, Right { +}; + +struct ChildOverride : Left, Right { + virtual void left(); + virtual void right(); +}; + +extern "C" void foo(void *); + +void call_left_no_override(ChildNoOverride *child) { +// CHECK: define void @"\01?call_left_no_override +// CHECK: %[[CHILD:.*]] = load %struct.ChildNoOverride + + child->left(); +// Only need to cast 'this' to Left*. +// CHECK: %[[LEFT:.*]] = bitcast %struct.ChildNoOverride* %[[CHILD]] to %struct.Left* +// CHECK: %[[VFPTR:.*]] = bitcast %struct.Left* %[[LEFT]] to void (%struct.Left*)*** +// CHECK: %[[VFTABLE:.*]] = load void (%struct.Left*)*** %[[VFPTR]] +// CHECK: %[[VFUN:.*]] = getelementptr inbounds void (%struct.Left*)** %[[VFTABLE]], i64 0 +// CHECK: %[[VFUN_VALUE:.*]] = load void (%struct.Left*)** %[[VFUN]] +// CHECK: call x86_thiscallcc void %[[VFUN_VALUE]](%struct.Left* %[[LEFT]]) +// CHECK: ret +} + +void ChildOverride::left() { +// CHECK: define x86_thiscallcc void @"\01?left@ChildOverride@@UAEXXZ"(%struct.ChildOverride* %[[THIS:.*]]) +// +// No need to adjust 'this' as the ChildOverride's layout begins with Left. +// CHECK: %[[THIS_ADDR:.*]] = alloca %struct.ChildOverride*, align 4 +// CHECK: store %struct.ChildOverride* %[[THIS]], %struct.ChildOverride** %[[THIS_ADDR]], align 4 + + foo(this); +// CHECK: %[[THIS:.*]] = load %struct.ChildOverride** %[[THIS_ADDR]] +// CHECK: %[[THIS_i8:.*]] = bitcast %struct.ChildOverride* %[[THIS]] to i8* +// CHECK: call void @foo(i8* %[[THIS_i8]]) +// CHECK: ret +} + +void call_left_override(ChildOverride *child) { +// CHECK: define void @"\01?call_left_override +// CHECK: %[[CHILD:.*]] = load %struct.ChildOverride + + child->left(); +// CHECK: %[[VFPTR:.*]] = bitcast %struct.ChildOverride* %[[CHILD]] to void (%struct.ChildOverride*)*** +// CHECK: %[[VFTABLE:.*]] = load void (%struct.ChildOverride*)*** %[[VFPTR]] +// CHECK: %[[VFUN:.*]] = getelementptr inbounds void (%struct.ChildOverride*)** %[[VFTABLE]], i64 0 +// CHECK: %[[VFUN_VALUE:.*]] = load void (%struct.ChildOverride*)** %[[VFUN]] +// +// CHECK: call x86_thiscallcc void %[[VFUN_VALUE]](%struct.ChildOverride* %[[CHILD]]) +// CHECK: ret +} + +void call_right_no_override(ChildNoOverride *child) { +// CHECK: define void @"\01?call_right_no_override +// CHECK: %[[CHILD:.*]] = load %struct.ChildNoOverride + + child->right(); +// When calling a right base's virtual method, one needs to adjust 'this' at +// the caller site. +// +// CHECK: %[[CHILD_i8:.*]] = bitcast %struct.ChildNoOverride* %[[CHILD]] to i8* +// CHECK: %[[RIGHT_i8:.*]] = getelementptr inbounds i8* %[[CHILD_i8]], i32 4 +// CHECK: %[[RIGHT:.*]] = bitcast i8* %[[RIGHT_i8]] to %struct.Right* +// +// CHECK: %[[VFPTR:.*]] = bitcast %struct.Right* %[[RIGHT]] to void (%struct.Right*)*** +// CHECK: %[[VFTABLE:.*]] = load void (%struct.Right*)*** %[[VFPTR]] +// CHECK: %[[VFUN:.*]] = getelementptr inbounds void (%struct.Right*)** %[[VFTABLE]], i64 0 +// CHECK: %[[VFUN_VALUE:.*]] = load void (%struct.Right*)** %[[VFUN]] +// CHECK: call x86_thiscallcc void %[[VFUN_VALUE]](%struct.Right* %[[RIGHT]]) +// CHECK: ret +} + +void ChildOverride::right() { +// CHECK: define x86_thiscallcc void @"\01?right@ChildOverride@@UAEXXZ"(i8* +// +// ChildOverride::right gets 'this' cast to Right* in ECX (i.e. this+4) so we +// need to adjust 'this' before use. +// +// CHECK: %[[THIS_ADDR:.*]] = alloca %struct.ChildOverride*, align 4 +// CHECK: %[[THIS_i8:.*]] = getelementptr i8* %[[ECX:.*]], i64 -4 +// CHECK: %[[THIS:.*]] = bitcast i8* %[[THIS_i8]] to %struct.ChildOverride* +// CHECK: store %struct.ChildOverride* %[[THIS]], %struct.ChildOverride** %[[THIS_ADDR]], align 4 + + foo(this); +// CHECK: %[[THIS:.*]] = load %struct.ChildOverride** %[[THIS_ADDR]] +// CHECK: %[[THIS_PARAM:.*]] = bitcast %struct.ChildOverride* %[[THIS]] to i8* +// CHECK: call void @foo(i8* %[[THIS_PARAM]]) +// CHECK: ret +} + +void call_right_override(ChildOverride *child) { +// CHECK: define void @"\01?call_right_override +// CHECK: %[[CHILD:.*]] = load %struct.ChildOverride + + child->right(); +// When calling a right child's virtual method, one needs to adjust 'this' at +// the caller site. +// +// CHECK: %[[CHILD_i8:.*]] = bitcast %struct.ChildOverride* %[[CHILD]] to i8* +// +// CHECK: %[[VFPTR_i8:.*]] = getelementptr inbounds i8* %[[CHILD_i8]], i64 4 +// CHECK: %[[VFPTR:.*]] = bitcast i8* %[[VFPTR_i8]] to void (i8*)*** +// CHECK: %[[VFTABLE:.*]] = load void (i8*)*** %[[VFPTR]] +// CHECK: %[[VFUN:.*]] = getelementptr inbounds void (i8*)** %[[VFTABLE]], i64 0 +// CHECK: %[[VFUN_VALUE:.*]] = load void (i8*)** %[[VFUN]] +// +// CHECK: %[[CHILD_i8:.*]] = bitcast %struct.ChildOverride* %[[CHILD]] to i8* +// CHECK: %[[RIGHT:.*]] = getelementptr inbounds i8* %[[CHILD_i8]], i64 4 +// +// CHECK: call x86_thiscallcc void %[[VFUN_VALUE]](i8* %[[RIGHT]]) +// CHECK: ret +} + +struct GrandchildOverride : ChildOverride { + virtual void right(); +}; + +void GrandchildOverride::right() { +// CHECK: define x86_thiscallcc void @"\01?right@GrandchildOverride@@UAEXXZ"(i8* +// +// CHECK: %[[THIS_ADDR:.*]] = alloca %struct.GrandchildOverride*, align 4 +// CHECK: %[[THIS_i8:.*]] = getelementptr i8* %[[ECX:.*]], i64 -4 +// CHECK: %[[THIS:.*]] = bitcast i8* %[[THIS_i8]] to %struct.GrandchildOverride* +// CHECK: store %struct.GrandchildOverride* %[[THIS]], %struct.GrandchildOverride** %[[THIS_ADDR]], align 4 + + foo(this); +// CHECK: %[[THIS:.*]] = load %struct.GrandchildOverride** %[[THIS_ADDR]] +// CHECK: %[[THIS_PARAM:.*]] = bitcast %struct.GrandchildOverride* %[[THIS]] to i8* +// CHECK: call void @foo(i8* %[[THIS_PARAM]]) +// CHECK: ret +} + +void call_grandchild_right(GrandchildOverride *obj) { + // Just make sure we don't crash. + obj->right(); +} diff --git a/test/CodeGenCXX/microsoft-abi-virtual-inheritance.cpp b/test/CodeGenCXX/microsoft-abi-virtual-inheritance.cpp index 7e631c1d78..ecbb843379 100644 --- a/test/CodeGenCXX/microsoft-abi-virtual-inheritance.cpp +++ b/test/CodeGenCXX/microsoft-abi-virtual-inheritance.cpp @@ -1,11 +1,79 @@ -// RUN: %clang_cc1 %s -fno-rtti -cxx-abi microsoft -triple=i386-pc-win32 -emit-llvm -o %t +// RUN: %clang_cc1 %s -fno-rtti -cxx-abi microsoft -triple=i386-pc-win32 -emit-llvm -o - | FileCheck %s -struct A {}; -struct B : virtual A { - virtual ~B(); +struct VBase { + virtual void foo(); + virtual void bar(); + int field; }; -struct C : B { - C(); + +struct B : virtual VBase { + virtual void foo(); + virtual void bar(); }; -C::C() {} +void B::foo() { +// CHECK: define x86_thiscallcc void @"\01?foo@B@@UAEXXZ"(i8* +// +// B::foo gets 'this' cast to VBase* in ECX (i.e. this+8) so we +// need to adjust 'this' before use. +// +// CHECK: %[[THIS_ADDR:.*]] = alloca %struct.B*, align 4 +// CHECK: %[[THIS_i8:.*]] = getelementptr i8* %[[ECX:.*]], i64 -8 +// CHECK: %[[THIS:.*]] = bitcast i8* %[[THIS_i8]] to %struct.B* +// CHECK: store %struct.B* %[[THIS]], %struct.B** %[[THIS_ADDR]], align 4 + + field = 42; +// CHECK: %[[THIS:.*]] = load %struct.B** %[[THIS_ADDR]] +// CHECK: %[[THIS8:.*]] = bitcast %struct.B* %[[THIS]] to i8* +// CHECK: %[[VBPTR:.*]] = getelementptr inbounds i8* %[[THIS8]], i32 0 +// CHECK: %[[VBPTR8:.*]] = bitcast i8* %[[VBPTR]] to i8** +// CHECK: %[[VBTABLE:.*]] = load i8** %[[VBPTR8]] +// CHECK: %[[VBENTRY8:.*]] = getelementptr inbounds i8* %[[VBTABLE]], i32 4 +// CHECK: %[[VBENTRY:.*]] = bitcast i8* %[[VBENTRY8]] to i32* +// CHECK: %[[VBOFFSET32:.*]] = load i32* %[[VBENTRY]] +// CHECK: %[[VBOFFSET:.*]] = add nsw i32 0, %[[VBOFFSET32]] +// CHECK: %[[THIS8:.*]] = bitcast %struct.B* %[[THIS]] to i8* +// CHECK: %[[VBASE_i8:.*]] = getelementptr inbounds i8* %[[THIS8]], i32 %[[VBOFFSET]] +// CHECK: %[[VBASE:.*]] = bitcast i8* %[[VBASE_i8]] to %struct.VBase* +// CHECK: %[[FIELD:.*]] = getelementptr inbounds %struct.VBase* %[[VBASE]], i32 0, i32 1 +// CHECK: store i32 42, i32* %[[FIELD]], align 4 +// +// CHECK: ret void +} + +void call_vbase_bar(B *obj) { +// CHECK: define void @"\01?call_vbase_bar@@YAXPAUB@@@Z"(%struct.B* %obj) +// CHECK: %[[OBJ:.*]] = load %struct.B + + obj->bar(); +// When calling a vbase's virtual method, one needs to adjust 'this' +// at the caller site. +// +// CHECK: %[[OBJ_i8:.*]] = bitcast %struct.B* %[[OBJ]] to i8* +// CHECK: %[[VBPTR:.*]] = getelementptr inbounds i8* %[[OBJ_i8]], i32 0 +// CHECK: %[[VBPTR8:.*]] = bitcast i8* %[[VBPTR]] to i8** +// CHECK: %[[VBTABLE:.*]] = load i8** %[[VBPTR8]] +// CHECK: %[[VBENTRY8:.*]] = getelementptr inbounds i8* %[[VBTABLE]], i32 4 +// CHECK: %[[VBENTRY:.*]] = bitcast i8* %[[VBENTRY8]] to i32* +// CHECK: %[[VBOFFSET32:.*]] = load i32* %[[VBENTRY]] +// CHECK: %[[VBOFFSET:.*]] = add nsw i32 0, %[[VBOFFSET32]] +// CHECK: %[[VBASE_i8:.*]] = getelementptr inbounds i8* %[[OBJ_i8]], i32 %[[VBOFFSET]] +// CHECK: %[[VFPTR:.*]] = bitcast i8* %[[VBASE_i8]] to void (i8*)*** +// CHECK: %[[VFTABLE:.*]] = load void (i8*)*** %[[VFPTR]] +// CHECK: %[[VFUN:.*]] = getelementptr inbounds void (i8*)** %[[VFTABLE]], i64 1 +// CHECK: %[[VFUN_VALUE:.*]] = load void (i8*)** %[[VFUN]] +// +// CHECK: %[[OBJ_i8:.*]] = bitcast %struct.B* %[[OBJ]] to i8* +// CHECK: %[[VBPTR:.*]] = getelementptr inbounds i8* %[[OBJ_i8]], i32 0 +// CHECK: %[[VBPTR8:.*]] = bitcast i8* %[[VBPTR]] to i8** +// CHECK: %[[VBTABLE:.*]] = load i8** %[[VBPTR8]] +// CHECK: %[[VBENTRY8:.*]] = getelementptr inbounds i8* %[[VBTABLE]], i32 4 +// CHECK: %[[VBENTRY:.*]] = bitcast i8* %[[VBENTRY8]] to i32* +// CHECK: %[[VBOFFSET32:.*]] = load i32* %[[VBENTRY]] +// CHECK: %[[VBOFFSET:.*]] = add nsw i32 0, %[[VBOFFSET32]] +// CHECK: %[[VBASE:.*]] = getelementptr inbounds i8* %[[OBJ_i8]], i32 %[[VBOFFSET]] +// +// CHECK: call x86_thiscallcc void %[[VFUN_VALUE]](i8* %[[VBASE]]) +// +// CHECK: ret void +} diff --git a/test/CodeGenCXX/microsoft-abi-vtables-single-inheritance.cpp b/test/CodeGenCXX/microsoft-abi-vtables-single-inheritance.cpp index 1bebec9d67..9a065d4c02 100644 --- a/test/CodeGenCXX/microsoft-abi-vtables-single-inheritance.cpp +++ b/test/CodeGenCXX/microsoft-abi-vtables-single-inheritance.cpp @@ -17,12 +17,12 @@ // v*table info was required by a constructor or a method definition. struct A { - // CHECK-A: Vtable for 'A' (3 entries) + // CHECK-A: VFTable for 'A' (3 entries) // CHECK-A-NEXT: 0 | void A::f() // CHECK-A-NEXT: 1 | void A::g() // CHECK-A-NEXT: 2 | void A::h() - // CHECK-A: VFTable for 'A' (3 entries) + // CHECK-A: Vtable for 'A' (3 entries) // CHECK-A-NEXT: 0 | void A::f() // CHECK-A-NEXT: 1 | void A::g() // CHECK-A-NEXT: 2 | void A::h()