From: Timur Iskhodzhanov Date: Mon, 21 Jan 2013 13:02:41 +0000 (+0000) Subject: First step towards vftable generation with -cxx-abi microsoft PR13231 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=649c7316aa29181df7270732722fe5d07ab3c7ad;p=clang First step towards vftable generation with -cxx-abi microsoft PR13231 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@173035 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/AST/VTableBuilder.h b/include/clang/AST/VTableBuilder.h index a6aa40b9d6..ac71441aed 100644 --- a/include/clang/AST/VTableBuilder.h +++ b/include/clang/AST/VTableBuilder.h @@ -215,12 +215,15 @@ private: /// Address points - Address points for all vtables. AddressPointsMapTy AddressPoints; + bool IsMicrosoftABI; + public: VTableLayout(uint64_t NumVTableComponents, const VTableComponent *VTableComponents, uint64_t NumVTableThunks, const VTableThunkTy *VTableThunks, - const AddressPointsMapTy &AddressPoints); + const AddressPointsMapTy &AddressPoints, + bool IsMicrosoftABI); ~VTableLayout(); uint64_t getNumVTableComponents() const { @@ -252,7 +255,7 @@ public: "Did not find address point!"); uint64_t AddressPoint = AddressPoints.lookup(Base); - assert(AddressPoint && "Address point must not be zero!"); + assert(AddressPoint != 0 || IsMicrosoftABI); return AddressPoint; } @@ -271,6 +274,8 @@ public: typedef SmallVector ThunkInfoVectorTy; private: + bool IsMicrosoftABI; + /// MethodVTableIndices - Contains the index (relative to the vtable address /// point) where the function pointer for a virtual function is stored. typedef llvm::DenseMap MethodVTableIndicesTy; @@ -306,10 +311,21 @@ private: /// given record decl. void ComputeVTableRelatedInformation(const CXXRecordDecl *RD); + /// ErrorUnsupported - Print out an error that the v-table layout code + /// doesn't support the particular C++ feature yet. + void ErrorUnsupported(StringRef Feature, SourceLocation Location); + public: - VTableContext(ASTContext &Context) : Context(Context) {} + VTableContext(ASTContext &Context); ~VTableContext(); + bool isMicrosoftABI() const { + // FIXME: Currently, this method is only used in the VTableContext and + // VTableBuilder code which is ABI-specific. Probably we can remove it + // when we add a layer of abstraction for vtable generation. + return IsMicrosoftABI; + } + const VTableLayout &getVTableLayout(const CXXRecordDecl *RD) { ComputeVTableRelatedInformation(RD); assert(VTableLayouts.count(RD) && "No layout for this record decl!"); diff --git a/lib/AST/VTableBuilder.cpp b/lib/AST/VTableBuilder.cpp index 1ab2b990ea..00a186e9ee 100644 --- a/lib/AST/VTableBuilder.cpp +++ b/lib/AST/VTableBuilder.cpp @@ -1002,6 +1002,10 @@ public: dumpLayout(llvm::errs()); } + bool isMicrosoftABI() const { + return VTables.isMicrosoftABI(); + } + uint64_t getNumThunks() const { return Thunks.size(); } @@ -1296,9 +1300,18 @@ VTableBuilder::AddMethod(const CXXMethodDecl *MD, assert(ReturnAdjustment.isEmpty() && "Destructor can't have return adjustment!"); - // Add both the complete destructor and the deleting destructor. - Components.push_back(VTableComponent::MakeCompleteDtor(DD)); - Components.push_back(VTableComponent::MakeDeletingDtor(DD)); + // FIXME: Should probably add a layer of abstraction for vtable generation. + if (!isMicrosoftABI()) { + // Add both the complete destructor and the deleting destructor. + Components.push_back(VTableComponent::MakeCompleteDtor(DD)); + Components.push_back(VTableComponent::MakeDeletingDtor(DD)); + } else { + // Add only one destructor in MS mode. + // FIXME: The virtual destructors are handled differently in MS ABI, + // we should add such a support later. For now, put the complete + // destructor into the vftable just to make its layout right. + Components.push_back(VTableComponent::MakeCompleteDtor(DD)); + } } else { // Add the return adjustment if necessary. if (!ReturnAdjustment.isEmpty()) @@ -1613,14 +1626,19 @@ VTableBuilder::LayoutPrimaryAndSecondaryVTables(BaseSubobject Base, if (Base.getBase() == MostDerivedClass) VBaseOffsetOffsets = Builder.getVBaseOffsetOffsets(); - // Add the offset to top. - CharUnits OffsetToTop = MostDerivedClassOffset - OffsetInLayoutClass; - Components.push_back( - VTableComponent::MakeOffsetToTop(OffsetToTop)); - - // Next, add the RTTI. - Components.push_back(VTableComponent::MakeRTTI(MostDerivedClass)); - + // FIXME: Should probably add a layer of abstraction for vtable generation. + if (!isMicrosoftABI()) { + // Add the offset to top. + CharUnits OffsetToTop = MostDerivedClassOffset - OffsetInLayoutClass; + Components.push_back(VTableComponent::MakeOffsetToTop(OffsetToTop)); + + // Next, add the RTTI. + Components.push_back(VTableComponent::MakeRTTI(MostDerivedClass)); + } else { + // FIXME: unclear what to do with RTTI in MS ABI as emitting it anywhere + // breaks the vftable layout. Just skip RTTI for now, can't mangle anyway. + } + uint64_t AddressPoint = Components.size(); // Now go through all virtual member functions and add them. @@ -2121,10 +2139,16 @@ void VTableBuilder::dumpLayout(raw_ostream& Out) { MD); if (const CXXDestructorDecl *DD = dyn_cast(MD)) { - IndicesMap[VTables.getMethodVTableIndex(GlobalDecl(DD, Dtor_Complete))] = - MethodName + " [complete]"; - IndicesMap[VTables.getMethodVTableIndex(GlobalDecl(DD, Dtor_Deleting))] = - MethodName + " [deleting]"; + // FIXME: Should add a layer of abstraction for vtable generation. + if (!isMicrosoftABI()) { + IndicesMap[VTables.getMethodVTableIndex(GlobalDecl(DD, Dtor_Complete))] + = MethodName + " [complete]"; + IndicesMap[VTables.getMethodVTableIndex(GlobalDecl(DD, Dtor_Deleting))] + = MethodName + " [deleting]"; + } else { + IndicesMap[VTables.getMethodVTableIndex(GlobalDecl(DD, Dtor_Complete))] + = MethodName; + } } else { IndicesMap[VTables.getMethodVTableIndex(MD)] = MethodName; } @@ -2155,12 +2179,14 @@ VTableLayout::VTableLayout(uint64_t NumVTableComponents, const VTableComponent *VTableComponents, uint64_t NumVTableThunks, const VTableThunkTy *VTableThunks, - const AddressPointsMapTy &AddressPoints) + const AddressPointsMapTy &AddressPoints, + bool IsMicrosoftABI) : NumVTableComponents(NumVTableComponents), VTableComponents(new VTableComponent[NumVTableComponents]), NumVTableThunks(NumVTableThunks), VTableThunks(new VTableThunkTy[NumVTableThunks]), - AddressPoints(AddressPoints) { + AddressPoints(AddressPoints), + IsMicrosoftABI(IsMicrosoftABI) { std::copy(VTableComponents, VTableComponents+NumVTableComponents, this->VTableComponents.get()); std::copy(VTableThunks, VTableThunks+NumVTableThunks, @@ -2169,6 +2195,10 @@ VTableLayout::VTableLayout(uint64_t NumVTableComponents, VTableLayout::~VTableLayout() { } +VTableContext::VTableContext(ASTContext &Context) + : Context(Context), + IsMicrosoftABI(Context.getTargetInfo().getCXXABI() == CXXABI_Microsoft) { } + VTableContext::~VTableContext() { llvm::DeleteContainerSeconds(VTableLayouts); } @@ -2240,12 +2270,17 @@ void VTableContext::ComputeMethodVTableIndices(const CXXRecordDecl *RD) { if (const CXXDestructorDecl *DD = dyn_cast(MD)) { const CXXDestructorDecl *OverriddenDD = cast(OverriddenMD); - - // Add both the complete and deleting entries. - MethodVTableIndices[GlobalDecl(DD, Dtor_Complete)] = - getMethodVTableIndex(GlobalDecl(OverriddenDD, Dtor_Complete)); - MethodVTableIndices[GlobalDecl(DD, Dtor_Deleting)] = - getMethodVTableIndex(GlobalDecl(OverriddenDD, Dtor_Deleting)); + + if (!isMicrosoftABI()) { + // Add both the complete and deleting entries. + MethodVTableIndices[GlobalDecl(DD, Dtor_Complete)] = + getMethodVTableIndex(GlobalDecl(OverriddenDD, Dtor_Complete)); + MethodVTableIndices[GlobalDecl(DD, Dtor_Deleting)] = + getMethodVTableIndex(GlobalDecl(OverriddenDD, Dtor_Deleting)); + } else { + MethodVTableIndices[GlobalDecl(DD, Dtor_Complete)] = + getMethodVTableIndex(GlobalDecl(OverriddenDD, Dtor_Complete)); + } } else { MethodVTableIndices[MD] = getMethodVTableIndex(OverriddenMD); } @@ -2263,11 +2298,19 @@ void VTableContext::ComputeMethodVTableIndices(const CXXRecordDecl *RD) { continue; } - // Add the complete dtor. - MethodVTableIndices[GlobalDecl(DD, Dtor_Complete)] = CurrentIndex++; - - // Add the deleting dtor. - MethodVTableIndices[GlobalDecl(DD, Dtor_Deleting)] = CurrentIndex++; + if (!isMicrosoftABI()) { + // Add the complete dtor. + MethodVTableIndices[GlobalDecl(DD, Dtor_Complete)] = CurrentIndex++; + + // Add the deleting dtor. + MethodVTableIndices[GlobalDecl(DD, Dtor_Deleting)] = CurrentIndex++; + } else { + // Add only the deleting dtor. + // FIXME: The virtual destructors are handled differently in MS ABI, + // we should add such a support later. For now, put the complete + // destructor into the vftable indices. + MethodVTableIndices[GlobalDecl(DD, Dtor_Complete)] = CurrentIndex++; + } } else { // Add the entry. MethodVTableIndices[MD] = CurrentIndex++; @@ -2279,6 +2322,11 @@ void VTableContext::ComputeMethodVTableIndices(const CXXRecordDecl *RD) { // If a class has an implicitly-defined virtual destructor, // its entries come after the declared virtual function pointers. + if (isMicrosoftABI()) { + ErrorUnsupported("implicit virtual destructor in the Microsoft ABI", + ImplicitVirtualDtor->getLocation()); + } + // Add the complete dtor. MethodVTableIndices[GlobalDecl(ImplicitVirtualDtor, Dtor_Complete)] = CurrentIndex++; @@ -2358,7 +2406,8 @@ static VTableLayout *CreateVTableLayout(const VTableBuilder &Builder) { Builder.vtable_component_begin(), VTableThunks.size(), VTableThunks.data(), - Builder.getAddressPoints()); + Builder.getAddressPoints(), + Builder.isMicrosoftABI()); } void VTableContext::ComputeVTableRelatedInformation(const CXXRecordDecl *RD) { @@ -2398,6 +2447,14 @@ void VTableContext::ComputeVTableRelatedInformation(const CXXRecordDecl *RD) { } } +void VTableContext::ErrorUnsupported(StringRef Feature, + SourceLocation Location) { + clang::DiagnosticsEngine &Diags = Context.getDiagnostics(); + unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error, + "v-table layout for %0 is not supported yet"); + Diags.Report(Context.getFullLoc(Location), DiagID) << Feature; +} + VTableLayout *VTableContext::createConstructionVTableLayout( const CXXRecordDecl *MostDerivedClass, CharUnits MostDerivedClassOffset, diff --git a/lib/CodeGen/MicrosoftCXXABI.cpp b/lib/CodeGen/MicrosoftCXXABI.cpp index 8d205c3d0f..8e4929294d 100644 --- a/lib/CodeGen/MicrosoftCXXABI.cpp +++ b/lib/CodeGen/MicrosoftCXXABI.cpp @@ -207,7 +207,7 @@ void MicrosoftCXXABI::EmitGuardedInit(CodeGenFunction &CGF, const VarDecl &D, } void MicrosoftCXXABI::EmitVTables(const CXXRecordDecl *Class) { - // FIXME: implement + CGM.getVTables().GenerateClassData(CGM.getVTableLinkage(Class), Class); } CGCXXABI *clang::CodeGen::CreateMicrosoftCXXABI(CodeGenModule &CGM) { diff --git a/test/CodeGenCXX/microsoft-abi-constructors.cpp b/test/CodeGenCXX/microsoft-abi-constructors.cpp index 89731ff38e..c9701e8270 100644 --- a/test/CodeGenCXX/microsoft-abi-constructors.cpp +++ b/test/CodeGenCXX/microsoft-abi-constructors.cpp @@ -22,3 +22,14 @@ void no_contstructor_destructor_infinite_recursion() { // CHECK: ret } +struct B { + virtual ~B(); + virtual void foo(); +}; + +void check_vftable_offset() { + B b; +// The vftable pointer should point at the beginning of the vftable. +// CHECK: [[THIS_PTR:%[0-9]+]] = bitcast %struct.B* {{.*}} to i8*** +// CHECK: store i8** getelementptr inbounds ([2 x i8*]* @"\01??_7B@@6B@", i64 0, i64 0), i8*** [[THIS_PTR]] +} diff --git a/test/CodeGenCXX/microsoft-abi-vtables-single-inheritance.cpp b/test/CodeGenCXX/microsoft-abi-vtables-single-inheritance.cpp new file mode 100644 index 0000000000..176ecf19f1 --- /dev/null +++ b/test/CodeGenCXX/microsoft-abi-vtables-single-inheritance.cpp @@ -0,0 +1,113 @@ +// RUN: %clang_cc1 %s -fno-rtti -cxx-abi microsoft -triple=i386-pc-win32 -emit-llvm -fdump-vtable-layouts -o - > %t 2>&1 +// RUN: FileCheck --check-prefix=EMITS-VTABLE %s < %t +// RUN: FileCheck --check-prefix=CHECK-A %s < %t +// RUN: FileCheck --check-prefix=CHECK-B %s < %t +// RUN: FileCheck --check-prefix=CHECK-C %s < %t +// RUN: FileCheck --check-prefix=CHECK-D %s < %t +// RUN: FileCheck --check-prefix=CHECK-E %s < %t +// RUN: FileCheck --check-prefix=CHECK-F %s < %t +// RUN: FileCheck --check-prefix=CHECK-G %s < %t + +struct A { + // CHECK-A: Vtable for 'A' (3 entries) + // CHECK-A-NEXT: 0 | void A::f() + // CHECK-A-NEXT: 1 | void A::g() + // CHECK-A-NEXT: 2 | void A::h() + // EMITS-VTABLE: @"\01??_7A@@6B@" = unnamed_addr constant [3 x i8*] + virtual void f(); + virtual void g(); + virtual void h(); + int ia; +}; +void A::f() {} + +struct B : A { + // CHECK-B: Vtable for 'B' (5 entries) + // CHECK-B-NEXT: 0 | void B::f() + // CHECK-B-NEXT: 1 | void A::g() + // CHECK-B-NEXT: 2 | void A::h() + // CHECK-B-NEXT: 3 | void B::i() + // CHECK-B-NEXT: 4 | void B::j() + // EMITS-VTABLE: @"\01??_7B@@6B@" = unnamed_addr constant [5 x i8*] + virtual void f(); // overrides A::f() + virtual void i(); + virtual void j(); +}; +void B::f() {} + +struct C { + // CHECK-C: Vtable for 'C' (2 entries) + // CHECK-C-NEXT: 0 | C::~C() + // CHECK-C-NEXT: 1 | void C::f() + // CHECK-C: VTable indices for 'C' (2 entries). + // CHECK-C-NEXT: 0 | C::~C() + // CHECK-C-NEXT: 1 | void C::f() + // Never used, so doesn't emit a vtable. + virtual ~C(); + + virtual void f(); +}; +void C::f() {} + +struct D { + // CHECK-D: Vtable for 'D' (2 entries) + // CHECK-D-NEXT: 0 | void D::f() + // CHECK-D-NEXT: 1 | D::~D() + // EMITS-VTABLE: @"\01??_7D@@6B@" = unnamed_addr constant [2 x i8*] + virtual void f(); + + virtual ~D(); +}; +void D::f() {} + +struct E : A { + // CHECK-E: Vtable for 'E' (5 entries) + // CHECK-E-NEXT: 0 | void A::f() + // CHECK-E-NEXT: 1 | void A::g() + // CHECK-E-NEXT: 2 | void A::h() + // CHECK-E-NEXT: 3 | E::~E() + // CHECK-E-NEXT: 4 | void E::i() + // CHECK-E: VTable indices for 'E' (2 entries). + // CHECK-E-NEXT: 3 | E::~E() + // CHECK-E-NEXT: 4 | void E::i() + + // Never used, so doesn't emit a vtable. + virtual ~E(); + virtual void i(); +}; +void E::i() {} + +struct F : A { + // CHECK-F: Vtable for 'F' (5 entries) + // CHECK-F-NEXT: 0 | void A::f() + // CHECK-F-NEXT: 1 | void A::g() + // CHECK-F-NEXT: 2 | void A::h() + // CHECK-F-NEXT: 3 | void F::i() + // CHECK-F-NEXT: 4 | F::~F() + // CHECK-F: VTable indices for 'F' (2 entries). + // CHECK-F-NEXT: 3 | void F::i() + // CHECK-F-NEXT: 4 | F::~F() + // EMITS-VTABLE: @"\01??_7F@@6B@" = unnamed_addr constant [5 x i8*] + virtual void i(); + virtual ~F(); +}; +void F::i() {} + +struct G : E { + // CHECK-G: Vtable for 'G' (6 entries) + // CHECK-G-NEXT: 0 | void G::f() + // CHECK-G-NEXT: 1 | void A::g() + // CHECK-G-NEXT: 2 | void A::h() + // CHECK-G-NEXT: 3 | G::~G() + // CHECK-G-NEXT: 4 | void E::i() + // CHECK-G-NEXT: 5 | void G::j() + // CHECK-G: VTable indices for 'G' (3 entries). + // CHECK-G-NEXT: 0 | void G::f() + // CHECK-G-NEXT: 3 | G::~G() + // CHECK-G-NEXT: 5 | void G::j() + // Never used, so doesn't emit a vtable. + virtual void f(); // overrides A::f() + virtual ~G(); + virtual void j(); +}; +void G::j() {}