The standard ARM C++ ABI dictates that inline functions are
never key functions. We did not implement that rule for the
iOS ABI, which was driven by what was implemented in gcc-4.2.
However, implement it now for other ARM-based platforms.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@173515 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/CodeGen/CGCXXABI.h b/lib/CodeGen/CGCXXABI.h
index a3e49d8..60e1020 100644
--- a/lib/CodeGen/CGCXXABI.h
+++ b/lib/CodeGen/CGCXXABI.h
@@ -294,11 +294,6 @@
/// \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 3d65892..366ce29 100644
--- a/lib/CodeGen/CGRTTI.cpp
+++ b/lib/CodeGen/CGRTTI.cpp
@@ -251,10 +251,12 @@
/// 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 @@
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 64c7939..6d40219 100644
--- a/lib/CodeGen/CGVTables.cpp
+++ b/lib/CodeGen/CGVTables.cpp
@@ -31,33 +31,6 @@
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 @@
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 @@
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 @@
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 5f3d814..bd3bdb1 100644
--- a/lib/CodeGen/CGVTables.h
+++ b/lib/CodeGen/CGVTables.h
@@ -77,10 +77,6 @@
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 @@
/// 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 2da9dba..9d78549 100644
--- a/lib/CodeGen/CodeGenModule.cpp
+++ b/lib/CodeGen/CodeGenModule.cpp
@@ -371,7 +371,9 @@
// 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 @@
// 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 @@
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 0f01120..75c5e93 100644
--- a/lib/CodeGen/CodeGenModule.h
+++ b/lib/CodeGen/CodeGenModule.h
@@ -258,6 +258,9 @@
/// 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 @@
GetLLVMLinkageVarDefinition(const VarDecl *D,
llvm::GlobalVariable *GV);
- std::vector<const CXXRecordDecl*> DeferredVTables;
-
/// Emit all the global annotations.
void EmitGlobalAnnotations();
@@ -900,6 +901,10 @@
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 @@
/// 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 b761055..9fce392 100644
--- a/lib/CodeGen/ItaniumCXXABI.cpp
+++ b/lib/CodeGen/ItaniumCXXABI.cpp
@@ -129,8 +129,6 @@
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 @@
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 8e49292..477720b 100644
--- a/lib/CodeGen/MicrosoftCXXABI.cpp
+++ b/lib/CodeGen/MicrosoftCXXABI.cpp
@@ -60,9 +60,6 @@
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 @@
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);
}