From: Eli Friedman Date: Sun, 6 Dec 2009 22:01:30 +0000 (+0000) Subject: Work-in-progess rewrite of thunks: move thunk generation outside of vtable X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=72649ed78a25365d003b5218cae7b332c418800e;p=clang Work-in-progess rewrite of thunks: move thunk generation outside of vtable generation, and make sure we generate thunks when the function is defined rather than when the vtable is defined. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@90722 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/CodeGen/CGCXX.cpp b/lib/CodeGen/CGCXX.cpp index a2674b82d1..77bee48b58 100644 --- a/lib/CodeGen/CGCXX.cpp +++ b/lib/CodeGen/CGCXX.cpp @@ -993,6 +993,102 @@ CodeGenFunction::GenerateCovariantThunk(llvm::Function *Fn, return Fn; } +llvm::Constant * +CodeGenModule::GetAddrOfThunk(GlobalDecl GD, + const ThunkAdjustment &ThisAdjustment) { + const CXXMethodDecl *MD = cast(GD.getDecl()); + + // Compute mangled name + llvm::SmallString<256> OutName; + if (const CXXDestructorDecl* DD = dyn_cast(MD)) + getMangleContext().mangleCXXDtorThunk(DD, GD.getDtorType(), ThisAdjustment, + OutName); + else + getMangleContext().mangleThunk(MD, ThisAdjustment, OutName); + OutName += '\0'; + const char* Name = UniqueMangledName(OutName.begin(), OutName.end()); + + // Get function for mangled name + const llvm::Type *Ty = getTypes().GetFunctionTypeForVtable(MD); + return GetOrCreateLLVMFunction(Name, Ty, GlobalDecl()); +} + +llvm::Constant * +CodeGenModule::GetAddrOfCovariantThunk(GlobalDecl GD, + const CovariantThunkAdjustment &Adjustment) { + const CXXMethodDecl *MD = cast(GD.getDecl()); + + // Compute mangled name + llvm::SmallString<256> OutName; + getMangleContext().mangleCovariantThunk(MD, Adjustment, OutName); + OutName += '\0'; + const char* Name = UniqueMangledName(OutName.begin(), OutName.end()); + + // Get function for mangled name + const llvm::Type *Ty = getTypes().GetFunctionTypeForVtable(MD); + return GetOrCreateLLVMFunction(Name, Ty, GlobalDecl()); +} + +void CodeGenModule::BuildThunksForVirtual(GlobalDecl GD) { + BuildThunksForVirtualRecursive(GD, GD); +} + +void +CodeGenModule::BuildThunksForVirtualRecursive(GlobalDecl GD, + GlobalDecl BaseOGD) { + const CXXMethodDecl *MD = cast(GD.getDecl()); + const CXXMethodDecl *BaseOMD = cast(BaseOGD.getDecl()); + for (CXXMethodDecl::method_iterator mi = BaseOMD->begin_overridden_methods(), + e = BaseOMD->end_overridden_methods(); + mi != e; ++mi) { + GlobalDecl OGD; + const CXXMethodDecl *OMD = *mi; + if (const CXXDestructorDecl *DD = dyn_cast(OMD)) + OGD = GlobalDecl(DD, GD.getDtorType()); + else + OGD = GlobalDecl(OMD); + QualType nc_oret = OMD->getType()->getAs()->getResultType(); + CanQualType oret = getContext().getCanonicalType(nc_oret); + QualType nc_ret = MD->getType()->getAs()->getResultType(); + CanQualType ret = getContext().getCanonicalType(nc_ret); + ThunkAdjustment ReturnAdjustment; + if (oret != ret) { + QualType qD = nc_ret->getPointeeType(); + QualType qB = nc_oret->getPointeeType(); + CXXRecordDecl *D = cast(qD->getAs()->getDecl()); + CXXRecordDecl *B = cast(qB->getAs()->getDecl()); + ReturnAdjustment = ComputeThunkAdjustment(D, B); + } + ThunkAdjustment ThisAdjustment = + getVtableInfo().getThisAdjustment(GD, OGD); + bool Extern = !cast(OMD->getDeclContext())->isInAnonymousNamespace(); + if (!ReturnAdjustment.isEmpty() || !ThisAdjustment.isEmpty()) { + CovariantThunkAdjustment CoAdj(ThisAdjustment, ReturnAdjustment); + llvm::Constant *FnConst; + if (!ReturnAdjustment.isEmpty()) + FnConst = GetAddrOfCovariantThunk(GD, CoAdj); + else + FnConst = GetAddrOfThunk(GD, ThisAdjustment); + if (!isa(FnConst)) { + assert(0 && "Figure out how to handle incomplete-type cases!"); + } + llvm::Function *Fn = cast(FnConst); + if (Fn->isDeclaration()) { + llvm::GlobalVariable::LinkageTypes linktype; + linktype = llvm::GlobalValue::WeakAnyLinkage; + if (!Extern) + linktype = llvm::GlobalValue::InternalLinkage; + Fn->setLinkage(linktype); + if (!Features.Exceptions && !Features.ObjCNonFragileABI) + Fn->addFnAttr(llvm::Attribute::NoUnwind); + Fn->setAlignment(2); + CodeGenFunction(*this).GenerateCovariantThunk(Fn, GD, Extern, CoAdj); + } + } + BuildThunksForVirtualRecursive(GD, OGD); + } +} + llvm::Constant * CodeGenModule::BuildThunk(GlobalDecl GD, bool Extern, const ThunkAdjustment &ThisAdjustment) { diff --git a/lib/CodeGen/CGVtable.cpp b/lib/CodeGen/CGVtable.cpp index 65c412e0b0..857e661254 100644 --- a/lib/CodeGen/CGVtable.cpp +++ b/lib/CodeGen/CGVtable.cpp @@ -73,6 +73,7 @@ private: /// Methods - The methods, in vtable order. typedef llvm::SmallVector MethodsVectorTy; MethodsVectorTy Methods; + MethodsVectorTy OrigMethods; public: /// AddMethod - Add a method to the vtable methods. @@ -82,6 +83,7 @@ private: MethodToIndexMap[GD] = Methods.size(); Methods.push_back(GD); + OrigMethods.push_back(GD); } /// OverrideMethod - Replace a method with another. @@ -113,6 +115,10 @@ private: return true; } + GlobalDecl getOrigMethod(uint64_t Index) const { + return OrigMethods[Index]; + } + MethodsVectorTy::size_type size() const { return Methods.size(); } @@ -120,6 +126,7 @@ private: void clear() { MethodToIndexMap.clear(); Methods.clear(); + OrigMethods.clear(); } GlobalDecl operator[](uint64_t Index) const { @@ -135,6 +142,10 @@ private: typedef llvm::DenseMap ThisAdjustmentsMapTy; ThisAdjustmentsMapTy ThisAdjustments; + typedef std::vector, + ThunkAdjustment> > SavedThisAdjustmentsVectorTy; + SavedThisAdjustmentsVectorTy SavedThisAdjustments; + /// BaseReturnTypes - Contains the base return types of methods who have been /// overridden with methods whose return types require adjustment. Used for /// generating covariant thunk information. @@ -202,6 +213,9 @@ public: llvm::DenseMap &getVBIndex() { return VBIndex; } + SavedThisAdjustmentsVectorTy &getSavedThisAdjustments() + { return SavedThisAdjustments; } + llvm::Constant *wrap(Index_t i) { llvm::Constant *m; m = llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext), i); @@ -762,11 +776,17 @@ bool VtableBuilder::OverrideMethod(GlobalDecl GD, bool MorallyVirtual, else OGD = OMD; - // FIXME: Explain why this is necessary! + // Check whether this is the method being overridden in this section of + // the vtable. uint64_t Index; if (!Methods.getIndex(OGD, Index)) continue; + // Get the original method, which we should be computing thunks, etc, + // against. + OGD = Methods.getOrigMethod(Index); + OMD = cast(OGD.getDecl()); + QualType ReturnType = MD->getType()->getAs()->getResultType(); QualType OverriddenReturnType = @@ -777,10 +797,6 @@ bool VtableBuilder::OverrideMethod(GlobalDecl GD, bool MorallyVirtual, OverriddenReturnType)) { CanQualType &BaseReturnType = BaseReturnTypes[Index]; - // Get the canonical return type. - CanQualType CanReturnType = - CGM.getContext().getCanonicalType(ReturnType); - // Insert the base return type. if (BaseReturnType.isNull()) BaseReturnType = @@ -820,8 +836,12 @@ bool VtableBuilder::OverrideMethod(GlobalDecl GD, bool MorallyVirtual, ThunkAdjustment ThisAdjustment(NonVirtualAdjustment, VirtualAdjustment); - if (!isPure && !ThisAdjustment.isEmpty()) + if (!isPure && !ThisAdjustment.isEmpty()) { ThisAdjustments[Index] = ThisAdjustment; + // FIXME: Might this end up inserting some false adjustments? + SavedThisAdjustments.push_back(std::make_pair(std::make_pair(GD, OGD), + ThisAdjustment)); + } return true; } @@ -882,10 +902,10 @@ void VtableBuilder::AppendMethodsToVtable() { if (!ReturnAdjustment.isEmpty()) { // Build a covariant thunk. CovariantThunkAdjustment Adjustment(ThisAdjustment, ReturnAdjustment); - Method = CGM.BuildCovariantThunk(MD, Extern, Adjustment); + Method = wrap(CGM.GetAddrOfCovariantThunk(GD, Adjustment)); } else if (!ThisAdjustment.isEmpty()) { // Build a "regular" thunk. - Method = CGM.BuildThunk(GD, Extern, ThisAdjustment); + Method = wrap(CGM.GetAddrOfThunk(GD, ThisAdjustment)); } else if (MD->isPure()) { // We have a pure virtual method. Method = getPureVirtualFn(); @@ -1048,6 +1068,32 @@ uint64_t CGVtableInfo::getMethodVtableIndex(GlobalDecl GD) { return I->second; } +ThunkAdjustment CGVtableInfo::getThisAdjustment(GlobalDecl GD, + GlobalDecl OGD) { + SavedThisAdjustmentsTy::iterator I = + SavedThisAdjustments.find(std::make_pair(GD, OGD)); + if (I != SavedThisAdjustments.end()) + return I->second; + + const CXXRecordDecl *RD = cast(GD.getDecl()->getDeclContext()); + if (!SavedThisAdjustmentRecords.insert(RD).second) + return ThunkAdjustment(); + + VtableBuilder b(RD, RD, 0, CGM, false); + D1(printf("vtable %s\n", RD->getNameAsCString())); + b.GenerateVtableForBase(RD); + b.GenerateVtableForVBases(RD); + + SavedThisAdjustments.insert(b.getSavedThisAdjustments().begin(), + b.getSavedThisAdjustments().end()); + + I = SavedThisAdjustments.find(std::make_pair(GD, OGD)); + if (I != SavedThisAdjustments.end()) + return I->second; + + return ThunkAdjustment(); +} + int64_t CGVtableInfo::getVirtualBaseOffsetIndex(const CXXRecordDecl *RD, const CXXRecordDecl *VBase) { ClassPairTy ClassPair(RD, VBase); @@ -1416,5 +1462,17 @@ void CGVtableInfo::MaybeEmitVtable(GlobalDecl GD) { // Emit the data. GenerateClassData(Linkage, RD); + + for (CXXRecordDecl::method_iterator i = RD->method_begin(), + e = RD->method_end(); i != e; ++i) { + if ((*i)->isVirtual() && (*i)->hasInlineBody()) { + if (const CXXDestructorDecl *DD = dyn_cast(*i)) { + CGM.BuildThunksForVirtual(GlobalDecl(DD, Dtor_Complete)); + CGM.BuildThunksForVirtual(GlobalDecl(DD, Dtor_Deleting)); + } else { + CGM.BuildThunksForVirtual(GlobalDecl(*i)); + } + } + } } diff --git a/lib/CodeGen/CGVtable.h b/lib/CodeGen/CGVtable.h index fd7a4865b6..1507725f0f 100644 --- a/lib/CodeGen/CGVtable.h +++ b/lib/CodeGen/CGVtable.h @@ -15,6 +15,7 @@ #define CLANG_CODEGEN_CGVTABLE_H #include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/DenseSet.h" #include "llvm/GlobalVariable.h" #include "GlobalDecl.h" @@ -83,6 +84,11 @@ class CGVtableInfo { /// pointers in the vtable for a given record decl. llvm::DenseMap NumVirtualFunctionPointers; + typedef llvm::DenseMap, + ThunkAdjustment> SavedThisAdjustmentsTy; + SavedThisAdjustmentsTy SavedThisAdjustments; + llvm::DenseSet SavedThisAdjustmentRecords; + /// getNumVirtualFunctionPointers - Return the number of virtual function /// pointers in the vtable for a given record decl. uint64_t getNumVirtualFunctionPointers(const CXXRecordDecl *RD); @@ -122,6 +128,8 @@ public: int64_t getVirtualBaseOffsetIndex(const CXXRecordDecl *RD, const CXXRecordDecl *VBase); + ThunkAdjustment getThisAdjustment(GlobalDecl GD, GlobalDecl OGD); + /// getVtableAddressPoint - returns the address point of the vtable for the /// given record decl. /// FIXME: This should return a list of address points. diff --git a/lib/CodeGen/CodeGenModule.cpp b/lib/CodeGen/CodeGenModule.cpp index 8fb03b2d19..5f822f509f 100644 --- a/lib/CodeGen/CodeGenModule.cpp +++ b/lib/CodeGen/CodeGenModule.cpp @@ -621,8 +621,13 @@ void CodeGenModule::EmitGlobalDefinition(GlobalDecl GD) { Context.getSourceManager(), "Generating code for declaration"); - if (isa(D)) + if (const CXXMethodDecl *MD = dyn_cast(D)) { getVtableInfo().MaybeEmitVtable(GD); + if (MD->isVirtual() && MD->isOutOfLine() && + (!isa(D) || GD.getDtorType() != Dtor_Base)) { + BuildThunksForVirtual(GD); + } + } if (const CXXConstructorDecl *CD = dyn_cast(D)) EmitCXXConstructor(CD, GD.getCtorType()); diff --git a/lib/CodeGen/CodeGenModule.h b/lib/CodeGen/CodeGenModule.h index cf36bcf9a0..466aaa67cc 100644 --- a/lib/CodeGen/CodeGenModule.h +++ b/lib/CodeGen/CodeGenModule.h @@ -223,6 +223,13 @@ public: /// non-class type. llvm::Constant *GenerateRTTI(QualType Ty); + llvm::Constant *GetAddrOfThunk(GlobalDecl GD, + const ThunkAdjustment &ThisAdjustment); + llvm::Constant *GetAddrOfCovariantThunk(GlobalDecl GD, + const CovariantThunkAdjustment &ThisAdjustment); + void BuildThunksForVirtual(GlobalDecl GD); + void BuildThunksForVirtualRecursive(GlobalDecl GD, GlobalDecl BaseOGD); + /// BuildThunk - Build a thunk for the given method. llvm::Constant *BuildThunk(GlobalDecl GD, bool Extern, const ThunkAdjustment &ThisAdjustment); diff --git a/test/CodeGenCXX/virt.cpp b/test/CodeGenCXX/virt.cpp index 7135aaf81e..e3b2afe2f7 100644 --- a/test/CodeGenCXX/virt.cpp +++ b/test/CodeGenCXX/virt.cpp @@ -768,7 +768,7 @@ struct test16_D : test16_NV1, virtual test16_B2 { // FIXME: This is the wrong thunk, but until these issues are fixed, better // than nothing. -// CHECK-LPLL64:define weak %class.test8_D* @_ZTcvn16_n72_v16_n32_N8test16_D4foo1Ev(%class.test8_D*) { +// CHECK-LPLL64:define weak %class.test8_D* @_ZTcvn16_n72_v16_n32_N8test16_D4foo1Ev(%class.test8_D*) // CHECK-LPLL64:entry: // CHECK-LPLL64: %retval = alloca %class.test8_D* // CHECK-LPLL64: %.addr = alloca %class.test8_D* @@ -790,7 +790,7 @@ struct test16_D : test16_NV1, virtual test16_B2 { // CHECK-LPLL64: ret %class.test8_D* %10 // CHECK-LPLL64:} -// CHECK-LPLL64:define weak %class.test8_D* @_ZTch0_v16_n32_N8test16_D4foo1Ev(%class.test8_D*) { +// CHECK-LPLL64:define weak %class.test8_D* @_ZTch0_v16_n32_N8test16_D4foo1Ev(%class.test8_D*) // CHECK-LPLL64:entry: // CHECK-LPLL64: %retval = alloca %class.test8_D* // CHECK-LPLL64: %.addr = alloca %class.test8_D*