diff options
Diffstat (limited to 'lib/CodeGen')
-rw-r--r-- | lib/CodeGen/CGCXXABI.h | 5 | ||||
-rw-r--r-- | lib/CodeGen/CGRTTI.cpp | 10 | ||||
-rw-r--r-- | lib/CodeGen/CGVTables.cpp | 208 | ||||
-rw-r--r-- | lib/CodeGen/CGVTables.h | 18 | ||||
-rw-r--r-- | lib/CodeGen/CodeGenModule.cpp | 93 | ||||
-rw-r--r-- | lib/CodeGen/CodeGenModule.h | 13 | ||||
-rw-r--r-- | lib/CodeGen/ItaniumCXXABI.cpp | 7 | ||||
-rw-r--r-- | lib/CodeGen/MicrosoftCXXABI.cpp | 7 |
8 files changed, 214 insertions, 147 deletions
diff --git a/lib/CodeGen/CGCXXABI.h b/lib/CodeGen/CGCXXABI.h index a3e49d8035..60e1020b99 100644 --- a/lib/CodeGen/CGCXXABI.h +++ b/lib/CodeGen/CGCXXABI.h @@ -294,11 +294,6 @@ public: /// \param addr - a pointer to pass to the destructor function. virtual void registerGlobalDtor(CodeGenFunction &CGF, llvm::Constant *dtor, llvm::Constant *addr); - - /***************************** Virtual Tables *******************************/ - - /// Generates and emits the virtual tables for a class. - virtual void EmitVTables(const CXXRecordDecl *Class) = 0; }; /// Creates an instance of a C++ ABI class. diff --git a/lib/CodeGen/CGRTTI.cpp b/lib/CodeGen/CGRTTI.cpp index 3d65892b2e..366ce29fc0 100644 --- a/lib/CodeGen/CGRTTI.cpp +++ b/lib/CodeGen/CGRTTI.cpp @@ -251,10 +251,12 @@ static bool IsStandardLibraryRTTIDescriptor(QualType Ty) { /// the given type exists somewhere else, and that we should not emit the type /// information in this translation unit. Assumes that it is not a /// standard-library type. -static bool ShouldUseExternalRTTIDescriptor(CodeGenModule &CGM, QualType Ty) { +static bool ShouldUseExternalRTTIDescriptor(CodeGenModule &CGM, + QualType Ty) { ASTContext &Context = CGM.getContext(); - // If RTTI is disabled, don't consider key functions. + // If RTTI is disabled, assume it might be disabled in the + // translation unit that defines any potential key function, too. if (!Context.getLangOpts().RTTI) return false; if (const RecordType *RecordTy = dyn_cast<RecordType>(Ty)) { @@ -265,7 +267,9 @@ static bool ShouldUseExternalRTTIDescriptor(CodeGenModule &CGM, QualType Ty) { if (!RD->isDynamicClass()) return false; - return !CGM.getVTables().ShouldEmitVTableInThisTU(RD); + // FIXME: this may need to be reconsidered if the key function + // changes. + return CGM.getVTables().isVTableExternal(RD); } return false; diff --git a/lib/CodeGen/CGVTables.cpp b/lib/CodeGen/CGVTables.cpp index 64c7939588..6d402197e0 100644 --- a/lib/CodeGen/CGVTables.cpp +++ b/lib/CodeGen/CGVTables.cpp @@ -31,33 +31,6 @@ using namespace CodeGen; CodeGenVTables::CodeGenVTables(CodeGenModule &CGM) : CGM(CGM), VTContext(CGM.getContext()) { } -bool CodeGenVTables::ShouldEmitVTableInThisTU(const CXXRecordDecl *RD) { - assert(RD->isDynamicClass() && "Non dynamic classes have no VTable."); - - TemplateSpecializationKind TSK = RD->getTemplateSpecializationKind(); - if (TSK == TSK_ExplicitInstantiationDeclaration) - return false; - - const CXXMethodDecl *KeyFunction = CGM.getContext().getKeyFunction(RD); - if (!KeyFunction) - return true; - - // Itanium C++ ABI, 5.2.6 Instantiated Templates: - // An instantiation of a class template requires: - // - In the object where instantiated, the virtual table... - if (TSK == TSK_ImplicitInstantiation || - TSK == TSK_ExplicitInstantiationDefinition) - return true; - - // If we're building with optimization, we always emit VTables since that - // allows for virtual function calls to be devirtualized. - // (We don't want to do this in -fapple-kext mode however). - if (CGM.getCodeGenOpts().OptimizationLevel && !CGM.getLangOpts().AppleKext) - return true; - - return KeyFunction->hasBody(); -} - llvm::Constant *CodeGenModule::GetAddrOfThunk(GlobalDecl GD, const ThunkInfo &Thunk) { const CXXMethodDecl *MD = cast<CXXMethodDecl>(GD.getDecl()); @@ -645,9 +618,8 @@ llvm::GlobalVariable *CodeGenVTables::GetAddrOfVTable(const CXXRecordDecl *RD) { if (VTable) return VTable; - // We may need to generate a definition for this vtable. - if (ShouldEmitVTableInThisTU(RD)) - CGM.DeferredVTables.push_back(RD); + // Queue up this v-table for possible deferred emission. + CGM.addDeferredVTable(RD); SmallString<256> OutName; llvm::raw_svector_ostream Out(OutName); @@ -734,13 +706,108 @@ CodeGenVTables::GenerateConstructionVTable(const CXXRecordDecl *RD, return VTable; } +/// Compute the required linkage of the v-table for the given class. +/// +/// Note that we only call this at the end of the translation unit. +llvm::GlobalVariable::LinkageTypes +CodeGenModule::getVTableLinkage(const CXXRecordDecl *RD) { + if (RD->getLinkage() != ExternalLinkage) + return llvm::GlobalVariable::InternalLinkage; + + // We're at the end of the translation unit, so the current key + // function is fully correct. + if (const CXXMethodDecl *keyFunction = Context.getCurrentKeyFunction(RD)) { + // If this class has a key function, use that to determine the + // linkage of the vtable. + const FunctionDecl *def = 0; + if (keyFunction->hasBody(def)) + keyFunction = cast<CXXMethodDecl>(def); + + switch (keyFunction->getTemplateSpecializationKind()) { + case TSK_Undeclared: + case TSK_ExplicitSpecialization: + // When compiling with optimizations turned on, we emit all vtables, + // even if the key function is not defined in the current translation + // unit. If this is the case, use available_externally linkage. + if (!def && CodeGenOpts.OptimizationLevel) + return llvm::GlobalVariable::AvailableExternallyLinkage; + + if (keyFunction->isInlined()) + return !Context.getLangOpts().AppleKext ? + llvm::GlobalVariable::LinkOnceODRLinkage : + llvm::Function::InternalLinkage; + + return llvm::GlobalVariable::ExternalLinkage; + + case TSK_ImplicitInstantiation: + return !Context.getLangOpts().AppleKext ? + llvm::GlobalVariable::LinkOnceODRLinkage : + llvm::Function::InternalLinkage; + + case TSK_ExplicitInstantiationDefinition: + return !Context.getLangOpts().AppleKext ? + llvm::GlobalVariable::WeakODRLinkage : + llvm::Function::InternalLinkage; + + case TSK_ExplicitInstantiationDeclaration: + // FIXME: Use available_externally linkage. However, this currently + // breaks LLVM's build due to undefined symbols. + // return llvm::GlobalVariable::AvailableExternallyLinkage; + return !Context.getLangOpts().AppleKext ? + llvm::GlobalVariable::LinkOnceODRLinkage : + llvm::Function::InternalLinkage; + } + } + + // -fapple-kext mode does not support weak linkage, so we must use + // internal linkage. + if (Context.getLangOpts().AppleKext) + return llvm::Function::InternalLinkage; + + switch (RD->getTemplateSpecializationKind()) { + case TSK_Undeclared: + case TSK_ExplicitSpecialization: + case TSK_ImplicitInstantiation: + return llvm::GlobalVariable::LinkOnceODRLinkage; + + case TSK_ExplicitInstantiationDeclaration: + // FIXME: Use available_externally linkage. However, this currently + // breaks LLVM's build due to undefined symbols. + // return llvm::GlobalVariable::AvailableExternallyLinkage; + return llvm::GlobalVariable::LinkOnceODRLinkage; + + case TSK_ExplicitInstantiationDefinition: + return llvm::GlobalVariable::WeakODRLinkage; + } + + llvm_unreachable("Invalid TemplateSpecializationKind!"); +} + +/// This is a callback from Sema to tell us that it believes that a +/// particular v-table is required to be emitted in this translation +/// unit. +/// +/// The reason we don't simply trust this callback is because Sema +/// will happily report that something is used even when it's used +/// only in code that we don't actually have to emit. +/// +/// \param isRequired - if true, the v-table is mandatory, e.g. +/// because the translation unit defines the key function +void CodeGenModule::EmitVTable(CXXRecordDecl *theClass, bool isRequired) { + if (!isRequired) return; + + VTables.GenerateClassData(theClass); +} + void -CodeGenVTables::GenerateClassData(llvm::GlobalVariable::LinkageTypes Linkage, - const CXXRecordDecl *RD) { +CodeGenVTables::GenerateClassData(const CXXRecordDecl *RD) { + // First off, check whether we've already emitted the v-table and + // associated stuff. llvm::GlobalVariable *VTable = GetAddrOfVTable(RD); if (VTable->hasInitializer()) return; + llvm::GlobalVariable::LinkageTypes Linkage = CGM.getVTableLinkage(RD); EmitVTableDefinition(VTable, Linkage, RD); if (RD->getNumVBases()) { @@ -760,3 +827,80 @@ CodeGenVTables::GenerateClassData(llvm::GlobalVariable::LinkageTypes Linkage, DC->getParent()->isTranslationUnit()) CGM.EmitFundamentalRTTIDescriptors(); } + +/// At this point in the translation unit, does it appear that can we +/// rely on the vtable being defined elsewhere in the program? +/// +/// The response is really only definitive when called at the end of +/// the translation unit. +/// +/// The only semantic restriction here is that the object file should +/// not contain a v-table definition when that v-table is defined +/// strongly elsewhere. Otherwise, we'd just like to avoid emitting +/// v-tables when unnecessary. +bool CodeGenVTables::isVTableExternal(const CXXRecordDecl *RD) { + assert(RD->isDynamicClass() && "Non dynamic classes have no VTable."); + + // If we have an explicit instantiation declaration (and not a + // definition), the v-table is defined elsewhere. + TemplateSpecializationKind TSK = RD->getTemplateSpecializationKind(); + if (TSK == TSK_ExplicitInstantiationDeclaration) + return true; + + // Otherwise, if the class is an instantiated template, the + // v-table must be defined here. + if (TSK == TSK_ImplicitInstantiation || + TSK == TSK_ExplicitInstantiationDefinition) + return false; + + // Otherwise, if the class doesn't have a key function (possibly + // anymore), the v-table must be defined here. + const CXXMethodDecl *keyFunction = CGM.getContext().getCurrentKeyFunction(RD); + if (!keyFunction) + return false; + + // Otherwise, if we don't have a definition of the key function, the + // v-table must be defined somewhere else. + return !keyFunction->hasBody(); +} + +/// Given that we're currently at the end of the translation unit, and +/// we've emitted a reference to the v-table for this class, should +/// we define that v-table? +static bool shouldEmitVTableAtEndOfTranslationUnit(CodeGenModule &CGM, + const CXXRecordDecl *RD) { + // If we're building with optimization, we always emit v-tables + // since that allows for virtual function calls to be devirtualized. + // If the v-table is defined strongly elsewhere, this definition + // will be emitted available_externally. + // + // However, we don't want to do this in -fapple-kext mode, because + // kext mode does not permit devirtualization. + if (CGM.getCodeGenOpts().OptimizationLevel && !CGM.getLangOpts().AppleKext) + return true; + + return !CGM.getVTables().isVTableExternal(RD); +} + +/// Given that at some point we emitted a reference to one or more +/// v-tables, and that we are now at the end of the translation unit, +/// decide whether we should emit them. +void CodeGenModule::EmitDeferredVTables() { +#ifndef NDEBUG + // Remember the size of DeferredVTables, because we're going to assume + // that this entire operation doesn't modify it. + size_t savedSize = DeferredVTables.size(); +#endif + + typedef std::vector<const CXXRecordDecl *>::const_iterator const_iterator; + for (const_iterator i = DeferredVTables.begin(), + e = DeferredVTables.end(); i != e; ++i) { + const CXXRecordDecl *RD = *i; + if (shouldEmitVTableAtEndOfTranslationUnit(*this, RD)) + VTables.GenerateClassData(RD); + } + + assert(savedSize == DeferredVTables.size() && + "deferred extra v-tables during v-table emission?"); + DeferredVTables.clear(); +} diff --git a/lib/CodeGen/CGVTables.h b/lib/CodeGen/CGVTables.h index 5f3d814c0a..bd3bdb1358 100644 --- a/lib/CodeGen/CGVTables.h +++ b/lib/CodeGen/CGVTables.h @@ -77,10 +77,6 @@ public: VTableContext &getVTableContext() { return VTContext; } - /// \brief True if the VTable of this record must be emitted in the - /// translation unit. - bool ShouldEmitVTableInThisTU(const CXXRecordDecl *RD); - /// needsVTTParameter - Return whether the given global decl needs a VTT /// parameter, which it does if it's a base constructor or destructor with /// virtual bases. @@ -127,13 +123,13 @@ public: /// EmitThunks - Emit the associated thunks for the given global decl. void EmitThunks(GlobalDecl GD); - /// GenerateClassData - Generate all the class data required to be generated - /// upon definition of a KeyFunction. This includes the vtable, the - /// rtti data structure and the VTT. - /// - /// \param Linkage - The desired linkage of the vtable, the RTTI and the VTT. - void GenerateClassData(llvm::GlobalVariable::LinkageTypes Linkage, - const CXXRecordDecl *RD); + /// GenerateClassData - Generate all the class data required to be + /// generated upon definition of a KeyFunction. This includes the + /// vtable, the RTTI data structure (if RTTI is enabled) and the VTT + /// (if the class has virtual bases). + void GenerateClassData(const CXXRecordDecl *RD); + + bool isVTableExternal(const CXXRecordDecl *RD); }; } // end namespace CodeGen diff --git a/lib/CodeGen/CodeGenModule.cpp b/lib/CodeGen/CodeGenModule.cpp index 2da9dba5b7..9d7854975e 100644 --- a/lib/CodeGen/CodeGenModule.cpp +++ b/lib/CodeGen/CodeGenModule.cpp @@ -371,7 +371,9 @@ void CodeGenModule::setTypeVisibility(llvm::GlobalValue *GV, // that don't have the key function's definition. But ignore // this if we're emitting RTTI under -fno-rtti. if (!(TVK != TVK_ForRTTI) || LangOpts.RTTI) { - if (Context.getKeyFunction(RD)) + // FIXME: what should we do if we "lose" the key function during + // the emission of the file? + if (Context.getCurrentKeyFunction(RD)) return; } @@ -836,14 +838,19 @@ void CodeGenModule::EmitDeferred() { // previously unused static decl may become used during the generation of code // for a static function, iterate until no changes are made. - while (!DeferredDeclsToEmit.empty() || !DeferredVTables.empty()) { + while (true) { if (!DeferredVTables.empty()) { - const CXXRecordDecl *RD = DeferredVTables.back(); - DeferredVTables.pop_back(); - getCXXABI().EmitVTables(RD); - continue; + EmitDeferredVTables(); + + // Emitting a v-table doesn't directly cause more v-tables to + // become deferred, although it can cause functions to be + // emitted that then need those v-tables. + assert(DeferredVTables.empty()); } + // Stop if we're out of both deferred v-tables and deferred declarations. + if (DeferredDeclsToEmit.empty()) break; + GlobalDecl D = DeferredDeclsToEmit.back(); DeferredDeclsToEmit.pop_back(); @@ -1526,80 +1533,6 @@ void CodeGenModule::EmitTentativeDefinition(const VarDecl *D) { EmitGlobalVarDefinition(D); } -void CodeGenModule::EmitVTable(CXXRecordDecl *Class, bool DefinitionRequired) { - if (DefinitionRequired) - getCXXABI().EmitVTables(Class); -} - -llvm::GlobalVariable::LinkageTypes -CodeGenModule::getVTableLinkage(const CXXRecordDecl *RD) { - if (RD->getLinkage() != ExternalLinkage) - return llvm::GlobalVariable::InternalLinkage; - - if (const CXXMethodDecl *KeyFunction - = RD->getASTContext().getKeyFunction(RD)) { - // If this class has a key function, use that to determine the linkage of - // the vtable. - const FunctionDecl *Def = 0; - if (KeyFunction->hasBody(Def)) - KeyFunction = cast<CXXMethodDecl>(Def); - - switch (KeyFunction->getTemplateSpecializationKind()) { - case TSK_Undeclared: - case TSK_ExplicitSpecialization: - // When compiling with optimizations turned on, we emit all vtables, - // even if the key function is not defined in the current translation - // unit. If this is the case, use available_externally linkage. - if (!Def && CodeGenOpts.OptimizationLevel) - return llvm::GlobalVariable::AvailableExternallyLinkage; - - if (KeyFunction->isInlined()) - return !Context.getLangOpts().AppleKext ? - llvm::GlobalVariable::LinkOnceODRLinkage : - llvm::Function::InternalLinkage; - - return llvm::GlobalVariable::ExternalLinkage; - - case TSK_ImplicitInstantiation: - return !Context.getLangOpts().AppleKext ? - llvm::GlobalVariable::LinkOnceODRLinkage : - llvm::Function::InternalLinkage; - - case TSK_ExplicitInstantiationDefinition: - return !Context.getLangOpts().AppleKext ? - llvm::GlobalVariable::WeakODRLinkage : - llvm::Function::InternalLinkage; - - case TSK_ExplicitInstantiationDeclaration: - // FIXME: Use available_externally linkage. However, this currently - // breaks LLVM's build due to undefined symbols. - // return llvm::GlobalVariable::AvailableExternallyLinkage; - return !Context.getLangOpts().AppleKext ? - llvm::GlobalVariable::LinkOnceODRLinkage : - llvm::Function::InternalLinkage; - } - } - - if (Context.getLangOpts().AppleKext) - return llvm::Function::InternalLinkage; - - switch (RD->getTemplateSpecializationKind()) { - case TSK_Undeclared: - case TSK_ExplicitSpecialization: - case TSK_ImplicitInstantiation: - // FIXME: Use available_externally linkage. However, this currently - // breaks LLVM's build due to undefined symbols. - // return llvm::GlobalVariable::AvailableExternallyLinkage; - case TSK_ExplicitInstantiationDeclaration: - return llvm::GlobalVariable::LinkOnceODRLinkage; - - case TSK_ExplicitInstantiationDefinition: - return llvm::GlobalVariable::WeakODRLinkage; - } - - llvm_unreachable("Invalid TemplateSpecializationKind!"); -} - CharUnits CodeGenModule::GetTargetTypeStoreSize(llvm::Type *Ty) const { return Context.toCharUnitsFromBits( TheDataLayout.getTypeStoreSizeInBits(Ty)); diff --git a/lib/CodeGen/CodeGenModule.h b/lib/CodeGen/CodeGenModule.h index 0f011205a7..75c5e93634 100644 --- a/lib/CodeGen/CodeGenModule.h +++ b/lib/CodeGen/CodeGenModule.h @@ -258,6 +258,9 @@ class CodeGenModule : public CodeGenTypeCache { /// is done. std::vector<GlobalDecl> DeferredDeclsToEmit; + /// DeferredVTables - A queue of (optional) vtables to consider emitting. + std::vector<const CXXRecordDecl*> DeferredVTables; + /// LLVMUsed - List of global values which are required to be /// present in the object file; bitcast to i8*. This is used for /// forcing visibility of symbols which may otherwise be optimized @@ -865,8 +868,6 @@ public: GetLLVMLinkageVarDefinition(const VarDecl *D, llvm::GlobalVariable *GV); - std::vector<const CXXRecordDecl*> DeferredVTables; - /// Emit all the global annotations. void EmitGlobalAnnotations(); @@ -900,6 +901,10 @@ public: const SanitizerOptions &getSanOpts() const { return SanOpts; } + void addDeferredVTable(const CXXRecordDecl *RD) { + DeferredVTables.push_back(RD); + } + private: llvm::GlobalValue *GetGlobalValue(StringRef Ref); @@ -1002,6 +1007,10 @@ private: /// was deferred. void EmitDeferred(); + /// EmitDeferredVTables - Emit any vtables which we deferred and + /// still have a use for. + void EmitDeferredVTables(); + /// EmitLLVMUsed - Emit the llvm.used metadata used to force /// references to global which may otherwise be optimized out. void EmitLLVMUsed(); diff --git a/lib/CodeGen/ItaniumCXXABI.cpp b/lib/CodeGen/ItaniumCXXABI.cpp index b761055043..9fce392352 100644 --- a/lib/CodeGen/ItaniumCXXABI.cpp +++ b/lib/CodeGen/ItaniumCXXABI.cpp @@ -129,8 +129,6 @@ public: llvm::GlobalVariable *DeclPtr, bool PerformInit); void registerGlobalDtor(CodeGenFunction &CGF, llvm::Constant *dtor, llvm::Constant *addr); - - void EmitVTables(const CXXRecordDecl *Class); }; class ARMCXXABI : public ItaniumCXXABI { @@ -1180,8 +1178,3 @@ void ItaniumCXXABI::registerGlobalDtor(CodeGenFunction &CGF, CGF.registerGlobalDtorWithAtExit(dtor, addr); } - -/// Generate and emit virtual tables for the given class. -void ItaniumCXXABI::EmitVTables(const CXXRecordDecl *Class) { - CGM.getVTables().GenerateClassData(CGM.getVTableLinkage(Class), Class); -} diff --git a/lib/CodeGen/MicrosoftCXXABI.cpp b/lib/CodeGen/MicrosoftCXXABI.cpp index 8e4929294d..477720bd25 100644 --- a/lib/CodeGen/MicrosoftCXXABI.cpp +++ b/lib/CodeGen/MicrosoftCXXABI.cpp @@ -60,9 +60,6 @@ public: llvm::GlobalVariable *DeclPtr, bool PerformInit); - void EmitVTables(const CXXRecordDecl *Class); - - // ==== Notes on array cookies ========= // // MSVC seems to only use cookies when the class has a destructor; a @@ -206,10 +203,6 @@ void MicrosoftCXXABI::EmitGuardedInit(CodeGenFunction &CGF, const VarDecl &D, CGF.EmitCXXGlobalVarDeclInit(D, DeclPtr, PerformInit); } -void MicrosoftCXXABI::EmitVTables(const CXXRecordDecl *Class) { - CGM.getVTables().GenerateClassData(CGM.getVTableLinkage(Class), Class); -} - CGCXXABI *clang::CodeGen::CreateMicrosoftCXXABI(CodeGenModule &CGM) { return new MicrosoftCXXABI(CGM); } |