summaryrefslogtreecommitdiffstats
path: root/clang/lib/CodeGen
diff options
context:
space:
mode:
Diffstat (limited to 'clang/lib/CodeGen')
-rw-r--r--clang/lib/CodeGen/CGCXXABI.h3
-rw-r--r--clang/lib/CodeGen/CGVTables.cpp42
-rw-r--r--clang/lib/CodeGen/ItaniumCXXABI.cpp33
-rw-r--r--clang/lib/CodeGen/MicrosoftCXXABI.cpp4
4 files changed, 70 insertions, 12 deletions
diff --git a/clang/lib/CodeGen/CGCXXABI.h b/clang/lib/CodeGen/CGCXXABI.h
index 436b96a615e..5ef409ecdee 100644
--- a/clang/lib/CodeGen/CGCXXABI.h
+++ b/clang/lib/CodeGen/CGCXXABI.h
@@ -218,6 +218,9 @@ public:
virtual void emitThrow(CodeGenFunction &CGF, const CXXThrowExpr *E) = 0;
virtual llvm::GlobalVariable *getThrowInfo(QualType T) { return nullptr; }
+ virtual bool canEmitAvailableExternallyVTable(
+ const CXXRecordDecl *RD) const = 0;
+
virtual void emitBeginCatch(CodeGenFunction &CGF, const CXXCatchStmt *C) = 0;
virtual llvm::CallInst *
diff --git a/clang/lib/CodeGen/CGVTables.cpp b/clang/lib/CodeGen/CGVTables.cpp
index 7321dbfe340..c6d7e0632c7 100644
--- a/clang/lib/CodeGen/CGVTables.cpp
+++ b/clang/lib/CodeGen/CGVTables.cpp
@@ -679,6 +679,12 @@ CodeGenVTables::GenerateConstructionVTable(const CXXRecordDecl *RD,
return VTable;
}
+static bool shouldEmitAvailableExternallyVTable(const CodeGenModule &CGM,
+ const CXXRecordDecl *RD) {
+ return CGM.getCodeGenOpts().OptimizationLevel > 0 &&
+ CGM.getCXXABI().canEmitAvailableExternallyVTable(RD);
+}
+
/// 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.
@@ -700,7 +706,12 @@ CodeGenModule::getVTableLinkage(const CXXRecordDecl *RD) {
switch (keyFunction->getTemplateSpecializationKind()) {
case TSK_Undeclared:
case TSK_ExplicitSpecialization:
- assert(def && "Should not have been asked to emit this");
+ assert((def || CodeGenOpts.OptimizationLevel > 0) &&
+ "Shouldn't query vtable linkage without key function or "
+ "optimizations");
+ if (!def && CodeGenOpts.OptimizationLevel > 0)
+ return llvm::GlobalVariable::AvailableExternallyLinkage;
+
if (keyFunction->isInlined())
return !Context.getLangOpts().AppleKext ?
llvm::GlobalVariable::LinkOnceODRLinkage :
@@ -742,16 +753,18 @@ CodeGenModule::getVTableLinkage(const CXXRecordDecl *RD) {
}
switch (RD->getTemplateSpecializationKind()) {
- case TSK_Undeclared:
- case TSK_ExplicitSpecialization:
- case TSK_ImplicitInstantiation:
- return DiscardableODRLinkage;
-
- case TSK_ExplicitInstantiationDeclaration:
- return llvm::GlobalVariable::ExternalLinkage;
-
- case TSK_ExplicitInstantiationDefinition:
- return NonDiscardableODRLinkage;
+ case TSK_Undeclared:
+ case TSK_ExplicitSpecialization:
+ case TSK_ImplicitInstantiation:
+ return DiscardableODRLinkage;
+
+ case TSK_ExplicitInstantiationDeclaration:
+ return shouldEmitAvailableExternallyVTable(*this, RD)
+ ? llvm::GlobalVariable::AvailableExternallyLinkage
+ : llvm::GlobalVariable::ExternalLinkage;
+
+ case TSK_ExplicitInstantiationDefinition:
+ return NonDiscardableODRLinkage;
}
llvm_unreachable("Invalid TemplateSpecializationKind!");
@@ -819,7 +832,12 @@ bool CodeGenVTables::isVTableExternal(const CXXRecordDecl *RD) {
/// we define that v-table?
static bool shouldEmitVTableAtEndOfTranslationUnit(CodeGenModule &CGM,
const CXXRecordDecl *RD) {
- return !CGM.getVTables().isVTableExternal(RD);
+ // If vtable is internal then it has to be done
+ if (!CGM.getVTables().isVTableExternal(RD))
+ return true;
+
+ // If it's external then maybe we will need it as available_externally
+ return shouldEmitAvailableExternallyVTable(CGM, RD);
}
/// Given that at some point we emitted a reference to one or more
diff --git a/clang/lib/CodeGen/ItaniumCXXABI.cpp b/clang/lib/CodeGen/ItaniumCXXABI.cpp
index 70af69b7645..eb85413a5de 100644
--- a/clang/lib/CodeGen/ItaniumCXXABI.cpp
+++ b/clang/lib/CodeGen/ItaniumCXXABI.cpp
@@ -215,6 +215,8 @@ public:
void emitVirtualInheritanceTables(const CXXRecordDecl *RD) override;
+ bool canEmitAvailableExternallyVTable(const CXXRecordDecl *RD) const override;
+
void setThunkLinkage(llvm::Function *Thunk, bool ForVTable, GlobalDecl GD,
bool ReturnAdjustment) override {
// Allow inlining of thunks by emitting them with available_externally
@@ -302,6 +304,24 @@ public:
friend class ItaniumRTTIBuilder;
void emitCXXStructor(const CXXMethodDecl *MD, StructorType Type) override;
+
+ private:
+ /// Checks if function has any virtual inline function.
+ bool hasAnyVirtualInlineFunction(const CXXRecordDecl *RD) const {
+ const auto &VtableLayout =
+ CGM.getItaniumVTableContext().getVTableLayout(RD);
+
+ for (const auto &VtableComponent : VtableLayout.vtable_components()) {
+ if (VtableComponent.getKind() !=
+ VTableComponent::Kind::CK_FunctionPointer)
+ continue;
+
+ const auto &Method = VtableComponent.getFunctionDecl();
+ if (Method->getCanonicalDecl()->isInlined())
+ return true;
+ }
+ return false;
+ }
};
class ARMCXXABI : public ItaniumCXXABI {
@@ -1481,6 +1501,19 @@ void ItaniumCXXABI::emitVirtualInheritanceTables(const CXXRecordDecl *RD) {
VTables.EmitVTTDefinition(VTT, CGM.getVTableLinkage(RD), RD);
}
+bool ItaniumCXXABI::canEmitAvailableExternallyVTable(
+ const CXXRecordDecl *RD) const {
+ // We don't emit available_externally vtables if we are in -fapple-kext mode
+ // because kext mode does not permit devirtualization.
+ if (CGM.getLangOpts().AppleKext)
+ return false;
+
+ // If we don't have any inline virtual functions,
+ // then we are safe to emit available_externally copy of vtable.
+ // FIXME we can still emit a copy of the vtable if we
+ // can emit definition of the inline functions.
+ return !hasAnyVirtualInlineFunction(RD);
+}
static llvm::Value *performTypeAdjustment(CodeGenFunction &CGF,
llvm::Value *Ptr,
int64_t NonVirtualAdjustment,
diff --git a/clang/lib/CodeGen/MicrosoftCXXABI.cpp b/clang/lib/CodeGen/MicrosoftCXXABI.cpp
index f864213566a..613d29a63cd 100644
--- a/clang/lib/CodeGen/MicrosoftCXXABI.cpp
+++ b/clang/lib/CodeGen/MicrosoftCXXABI.cpp
@@ -106,6 +106,10 @@ public:
QualType DestTy) override;
bool EmitBadCastCall(CodeGenFunction &CGF) override;
+ bool canEmitAvailableExternallyVTable(
+ const CXXRecordDecl *RD) const override {
+ return false;
+ }
llvm::Value *
GetVirtualBaseClassOffset(CodeGenFunction &CGF, llvm::Value *This,
OpenPOWER on IntegriCloud