Index: cfe/trunk/include/clang/AST/VTableBuilder.h =================================================================== --- cfe/trunk/include/clang/AST/VTableBuilder.h +++ cfe/trunk/include/clang/AST/VTableBuilder.h @@ -205,8 +205,11 @@ typedef const VTableComponent *vtable_component_iterator; typedef const VTableThunkTy *vtable_thunk_iterator; + typedef llvm::iterator_range + vtable_component_range; typedef llvm::DenseMap AddressPointsMapTy; + private: uint64_t NumVTableComponents; std::unique_ptr VTableComponents; @@ -233,6 +236,11 @@ return NumVTableComponents; } + vtable_component_range vtable_components() const { + return vtable_component_range(vtable_component_begin(), + vtable_component_end()); + } + vtable_component_iterator vtable_component_begin() const { return VTableComponents.get(); } Index: cfe/trunk/lib/CodeGen/CGCXXABI.h =================================================================== --- cfe/trunk/lib/CodeGen/CGCXXABI.h +++ cfe/trunk/lib/CodeGen/CGCXXABI.h @@ -218,6 +218,9 @@ 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 * Index: cfe/trunk/lib/CodeGen/CGVTables.cpp =================================================================== --- cfe/trunk/lib/CodeGen/CGVTables.cpp +++ cfe/trunk/lib/CodeGen/CGVTables.cpp @@ -679,6 +679,12 @@ 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 @@ 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 @@ } switch (RD->getTemplateSpecializationKind()) { - case TSK_Undeclared: - case TSK_ExplicitSpecialization: - case TSK_ImplicitInstantiation: - return DiscardableODRLinkage; + 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_ExplicitInstantiationDeclaration: - return llvm::GlobalVariable::ExternalLinkage; - - case TSK_ExplicitInstantiationDefinition: - return NonDiscardableODRLinkage; + case TSK_ExplicitInstantiationDefinition: + return NonDiscardableODRLinkage; } llvm_unreachable("Invalid TemplateSpecializationKind!"); @@ -819,7 +832,12 @@ /// 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 Index: cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp =================================================================== --- cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp +++ cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp @@ -215,6 +215,8 @@ 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 @@ 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 @@ 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, Index: cfe/trunk/lib/CodeGen/MicrosoftCXXABI.cpp =================================================================== --- cfe/trunk/lib/CodeGen/MicrosoftCXXABI.cpp +++ cfe/trunk/lib/CodeGen/MicrosoftCXXABI.cpp @@ -106,6 +106,10 @@ 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, Index: cfe/trunk/test/CodeGenCXX/vtable-available-externally.cpp =================================================================== --- cfe/trunk/test/CodeGenCXX/vtable-available-externally.cpp +++ cfe/trunk/test/CodeGenCXX/vtable-available-externally.cpp @@ -1,7 +1,12 @@ -// RUN: %clang_cc1 %s -I%S -triple=x86_64-apple-darwin10 -emit-llvm -o %t +// RUN: %clang_cc1 %s -I%S -triple=x86_64-apple-darwin10 -emit-llvm -o %t +// RUN: %clang_cc1 %s -I%S -triple=x86_64-apple-darwin10 -O2 -disable-llvm-optzns -emit-llvm -o %t.opt // RUN: FileCheck --check-prefix=CHECK-TEST1 %s < %t // RUN: FileCheck --check-prefix=CHECK-TEST2 %s < %t // RUN: FileCheck --check-prefix=CHECK-TEST5 %s < %t +// RUN: FileCheck --check-prefix=CHECK-TEST8 %s < %t.opt +// RUN: FileCheck --check-prefix=CHECK-TEST9 %s < %t.opt +// RUN: FileCheck --check-prefix=CHECK-TEST10 %s < %t.opt +// RUN: FileCheck --check-prefix=CHECK-TEST11 %s < %t.opt #include @@ -152,3 +157,135 @@ void f6 (); }; } + +namespace Test8 { +// CHECK-TEST8: @_ZTVN5Test81YE = available_externally unnamed_addr constant +// vtable for X is not generated because there are no stores here +struct X { + X(); + virtual void foo(); +}; +struct Y : X { + void foo(); +}; + +void g(X* p) { p->foo(); } +void f() { + Y y; + g(&y); + X x; + g(&x); +} + +} // Test8 + +namespace Test9 { +// all virtual functions are outline, so we can assume that it will +// be generated in translation unit where foo is defined +// CHECK-TEST9: @_ZTVN5Test91AE = available_externally unnamed_addr constant +// CHECK-TEST9: @_ZTVN5Test91BE = available_externally unnamed_addr constant +struct A { + virtual void foo(); + virtual void bar(); +}; +void A::bar() {} + +struct B : A { + void foo(); +}; + +void g() { + A a; + a.foo(); + B b; + b.foo(); +} + +} // Test9 + +namespace Test10 { + +// because A's key function is defined here, vtable is generated in this TU +// CHECK-TEST10: @_ZTVN6Test101AE = unnamed_addr constant +struct A { + virtual void foo(); + virtual void bar(); +}; +void A::foo() {} + +// Because key function is inline we will generate vtable as linkonce_odr +// CHECK-TEST10: @_ZTVN6Test101DE = linkonce_odr unnamed_addr constant +struct D : A { + void bar(); +}; +inline void D::bar() {} + +// because B has outline key function then we can refer to +// CHECK-TEST10: @_ZTVN6Test101BE = available_externally unnamed_addr constant +struct B : A { + void foo(); + void bar(); +}; + +// C's key function (car) is outline, but C has inline virtual function so we +// can't guarantee that we will be able to refer to bar from name +// so (at the moment) we can't emit vtable available_externally +// CHECK-TEST10: @_ZTVN6Test101CE = external unnamed_addr constant +struct C : A { + void bar() {} // defined in body - not key function + virtual inline void gar(); // inline in body - not key function + virtual void car(); +}; + +// no key function, vtable will be generated everywhere it will be used +// CHECK-TEST10: @_ZTVN6Test101EE = linkonce_odr unnamed_addr constant +struct E : A {}; + +void g(A& a) { + a.foo(); + a.bar(); +} + +void f() { + A a; + g(a); + B b; + g(b); + C c; + g(c); + D d; + g(d); + E e; + g(e); +} + +} // Test10 + +namespace Test11 { +struct D; +// Can emit C's vtable available_externally. +// CHECK-TEST11: @_ZTVN6Test111CE = available_externally unnamed_addr constant +struct C { + virtual D& operator=(const D&); +}; + +// Cannot emit B's vtable available_externally, because we cannot create +// a reference to the inline virtual B::operator= function. +// CHECK-TEST11: @_ZTVN6Test111DE = external unnamed_addr constant +struct D : C { + virtual void key(); +}; +D f(); + +void g(D& a) { + C c; + c = a; + a.key(); + a.key(); +} +void g() { + D d; + d = f(); + g(d); +} +} // Test 11 Index: cfe/trunk/test/CodeGenCXX/vtable-linkage.cpp =================================================================== --- cfe/trunk/test/CodeGenCXX/vtable-linkage.cpp +++ cfe/trunk/test/CodeGenCXX/vtable-linkage.cpp @@ -139,10 +139,11 @@ // CHECK-OPT-DAG: @_ZTV1FIiE = external unnamed_addr constant // E is an explicit template instantiation declaration. It has a -// key function that is not instantiated, so we should only reference -// its vtable, not define it. +// key function is not instantiated, so we know that vtable definition +// will be generated in TU where key function will be defined +// so we can mark it as available_externally (only with optimizations) // CHECK-DAG: @_ZTV1EIiE = external unnamed_addr constant -// CHECK-OPT-DAG: @_ZTV1EIiE = external unnamed_addr constant +// CHECK-OPT-DAG: @_ZTV1EIiE = available_externally unnamed_addr constant // The anonymous struct for e has no linkage, so the vtable should have // internal linkage. @@ -196,8 +197,8 @@ // CHECK-DAG: @_ZTT1IIiE = external unnamed_addr constant // CHECK-NOT: @_ZTC1IIiE // -// CHECK-OPT-DAG: @_ZTV1IIiE = external unnamed_addr constant -// CHECK-OPT-DAG: @_ZTT1IIiE = external unnamed_addr constant +// CHECK-OPT-DAG: @_ZTV1IIiE = available_externally unnamed_addr constant +// CHECK-OPT-DAG: @_ZTT1IIiE = available_externally unnamed_addr constant struct VBase1 { virtual void f(); }; struct VBase2 : virtual VBase1 {}; template struct I : VBase2 {};