First step towards vftable generation with -cxx-abi microsoft PR13231

llvm-svn: 173035
This commit is contained in:
Timur Iskhodzhanov 2013-01-21 13:02:41 +00:00
parent d11e9a8300
commit 52b8a05234
5 changed files with 230 additions and 33 deletions

View File

@ -215,12 +215,15 @@ private:
/// Address points - Address points for all vtables. /// Address points - Address points for all vtables.
AddressPointsMapTy AddressPoints; AddressPointsMapTy AddressPoints;
bool IsMicrosoftABI;
public: public:
VTableLayout(uint64_t NumVTableComponents, VTableLayout(uint64_t NumVTableComponents,
const VTableComponent *VTableComponents, const VTableComponent *VTableComponents,
uint64_t NumVTableThunks, uint64_t NumVTableThunks,
const VTableThunkTy *VTableThunks, const VTableThunkTy *VTableThunks,
const AddressPointsMapTy &AddressPoints); const AddressPointsMapTy &AddressPoints,
bool IsMicrosoftABI);
~VTableLayout(); ~VTableLayout();
uint64_t getNumVTableComponents() const { uint64_t getNumVTableComponents() const {
@ -252,7 +255,7 @@ public:
"Did not find address point!"); "Did not find address point!");
uint64_t AddressPoint = AddressPoints.lookup(Base); uint64_t AddressPoint = AddressPoints.lookup(Base);
assert(AddressPoint && "Address point must not be zero!"); assert(AddressPoint != 0 || IsMicrosoftABI);
return AddressPoint; return AddressPoint;
} }
@ -271,6 +274,8 @@ public:
typedef SmallVector<ThunkInfo, 1> ThunkInfoVectorTy; typedef SmallVector<ThunkInfo, 1> ThunkInfoVectorTy;
private: private:
bool IsMicrosoftABI;
/// MethodVTableIndices - Contains the index (relative to the vtable address /// MethodVTableIndices - Contains the index (relative to the vtable address
/// point) where the function pointer for a virtual function is stored. /// point) where the function pointer for a virtual function is stored.
typedef llvm::DenseMap<GlobalDecl, int64_t> MethodVTableIndicesTy; typedef llvm::DenseMap<GlobalDecl, int64_t> MethodVTableIndicesTy;
@ -306,10 +311,21 @@ private:
/// given record decl. /// given record decl.
void ComputeVTableRelatedInformation(const CXXRecordDecl *RD); 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: public:
VTableContext(ASTContext &Context) : Context(Context) {} VTableContext(ASTContext &Context);
~VTableContext(); ~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) { const VTableLayout &getVTableLayout(const CXXRecordDecl *RD) {
ComputeVTableRelatedInformation(RD); ComputeVTableRelatedInformation(RD);
assert(VTableLayouts.count(RD) && "No layout for this record decl!"); assert(VTableLayouts.count(RD) && "No layout for this record decl!");

View File

@ -1002,6 +1002,10 @@ public:
dumpLayout(llvm::errs()); dumpLayout(llvm::errs());
} }
bool isMicrosoftABI() const {
return VTables.isMicrosoftABI();
}
uint64_t getNumThunks() const { uint64_t getNumThunks() const {
return Thunks.size(); return Thunks.size();
} }
@ -1296,9 +1300,18 @@ VTableBuilder::AddMethod(const CXXMethodDecl *MD,
assert(ReturnAdjustment.isEmpty() && assert(ReturnAdjustment.isEmpty() &&
"Destructor can't have return adjustment!"); "Destructor can't have return adjustment!");
// Add both the complete destructor and the deleting destructor. // FIXME: Should probably add a layer of abstraction for vtable generation.
Components.push_back(VTableComponent::MakeCompleteDtor(DD)); if (!isMicrosoftABI()) {
Components.push_back(VTableComponent::MakeDeletingDtor(DD)); // 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 { } else {
// Add the return adjustment if necessary. // Add the return adjustment if necessary.
if (!ReturnAdjustment.isEmpty()) if (!ReturnAdjustment.isEmpty())
@ -1613,14 +1626,19 @@ VTableBuilder::LayoutPrimaryAndSecondaryVTables(BaseSubobject Base,
if (Base.getBase() == MostDerivedClass) if (Base.getBase() == MostDerivedClass)
VBaseOffsetOffsets = Builder.getVBaseOffsetOffsets(); VBaseOffsetOffsets = Builder.getVBaseOffsetOffsets();
// Add the offset to top. // FIXME: Should probably add a layer of abstraction for vtable generation.
CharUnits OffsetToTop = MostDerivedClassOffset - OffsetInLayoutClass; if (!isMicrosoftABI()) {
Components.push_back( // Add the offset to top.
VTableComponent::MakeOffsetToTop(OffsetToTop)); CharUnits OffsetToTop = MostDerivedClassOffset - OffsetInLayoutClass;
Components.push_back(VTableComponent::MakeOffsetToTop(OffsetToTop));
// Next, add the RTTI.
Components.push_back(VTableComponent::MakeRTTI(MostDerivedClass)); // 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(); uint64_t AddressPoint = Components.size();
// Now go through all virtual member functions and add them. // Now go through all virtual member functions and add them.
@ -2121,10 +2139,16 @@ void VTableBuilder::dumpLayout(raw_ostream& Out) {
MD); MD);
if (const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(MD)) { if (const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(MD)) {
IndicesMap[VTables.getMethodVTableIndex(GlobalDecl(DD, Dtor_Complete))] = // FIXME: Should add a layer of abstraction for vtable generation.
MethodName + " [complete]"; if (!isMicrosoftABI()) {
IndicesMap[VTables.getMethodVTableIndex(GlobalDecl(DD, Dtor_Deleting))] = IndicesMap[VTables.getMethodVTableIndex(GlobalDecl(DD, Dtor_Complete))]
MethodName + " [deleting]"; = MethodName + " [complete]";
IndicesMap[VTables.getMethodVTableIndex(GlobalDecl(DD, Dtor_Deleting))]
= MethodName + " [deleting]";
} else {
IndicesMap[VTables.getMethodVTableIndex(GlobalDecl(DD, Dtor_Complete))]
= MethodName;
}
} else { } else {
IndicesMap[VTables.getMethodVTableIndex(MD)] = MethodName; IndicesMap[VTables.getMethodVTableIndex(MD)] = MethodName;
} }
@ -2155,12 +2179,14 @@ VTableLayout::VTableLayout(uint64_t NumVTableComponents,
const VTableComponent *VTableComponents, const VTableComponent *VTableComponents,
uint64_t NumVTableThunks, uint64_t NumVTableThunks,
const VTableThunkTy *VTableThunks, const VTableThunkTy *VTableThunks,
const AddressPointsMapTy &AddressPoints) const AddressPointsMapTy &AddressPoints,
bool IsMicrosoftABI)
: NumVTableComponents(NumVTableComponents), : NumVTableComponents(NumVTableComponents),
VTableComponents(new VTableComponent[NumVTableComponents]), VTableComponents(new VTableComponent[NumVTableComponents]),
NumVTableThunks(NumVTableThunks), NumVTableThunks(NumVTableThunks),
VTableThunks(new VTableThunkTy[NumVTableThunks]), VTableThunks(new VTableThunkTy[NumVTableThunks]),
AddressPoints(AddressPoints) { AddressPoints(AddressPoints),
IsMicrosoftABI(IsMicrosoftABI) {
std::copy(VTableComponents, VTableComponents+NumVTableComponents, std::copy(VTableComponents, VTableComponents+NumVTableComponents,
this->VTableComponents.get()); this->VTableComponents.get());
std::copy(VTableThunks, VTableThunks+NumVTableThunks, std::copy(VTableThunks, VTableThunks+NumVTableThunks,
@ -2169,6 +2195,10 @@ VTableLayout::VTableLayout(uint64_t NumVTableComponents,
VTableLayout::~VTableLayout() { } VTableLayout::~VTableLayout() { }
VTableContext::VTableContext(ASTContext &Context)
: Context(Context),
IsMicrosoftABI(Context.getTargetInfo().getCXXABI() == CXXABI_Microsoft) { }
VTableContext::~VTableContext() { VTableContext::~VTableContext() {
llvm::DeleteContainerSeconds(VTableLayouts); llvm::DeleteContainerSeconds(VTableLayouts);
} }
@ -2240,12 +2270,17 @@ void VTableContext::ComputeMethodVTableIndices(const CXXRecordDecl *RD) {
if (const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(MD)) { if (const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(MD)) {
const CXXDestructorDecl *OverriddenDD = const CXXDestructorDecl *OverriddenDD =
cast<CXXDestructorDecl>(OverriddenMD); cast<CXXDestructorDecl>(OverriddenMD);
// Add both the complete and deleting entries. if (!isMicrosoftABI()) {
MethodVTableIndices[GlobalDecl(DD, Dtor_Complete)] = // Add both the complete and deleting entries.
getMethodVTableIndex(GlobalDecl(OverriddenDD, Dtor_Complete)); MethodVTableIndices[GlobalDecl(DD, Dtor_Complete)] =
MethodVTableIndices[GlobalDecl(DD, Dtor_Deleting)] = getMethodVTableIndex(GlobalDecl(OverriddenDD, Dtor_Complete));
getMethodVTableIndex(GlobalDecl(OverriddenDD, Dtor_Deleting)); MethodVTableIndices[GlobalDecl(DD, Dtor_Deleting)] =
getMethodVTableIndex(GlobalDecl(OverriddenDD, Dtor_Deleting));
} else {
MethodVTableIndices[GlobalDecl(DD, Dtor_Complete)] =
getMethodVTableIndex(GlobalDecl(OverriddenDD, Dtor_Complete));
}
} else { } else {
MethodVTableIndices[MD] = getMethodVTableIndex(OverriddenMD); MethodVTableIndices[MD] = getMethodVTableIndex(OverriddenMD);
} }
@ -2263,11 +2298,19 @@ void VTableContext::ComputeMethodVTableIndices(const CXXRecordDecl *RD) {
continue; continue;
} }
// Add the complete dtor. if (!isMicrosoftABI()) {
MethodVTableIndices[GlobalDecl(DD, Dtor_Complete)] = CurrentIndex++; // Add the complete dtor.
MethodVTableIndices[GlobalDecl(DD, Dtor_Complete)] = CurrentIndex++;
// Add the deleting dtor.
MethodVTableIndices[GlobalDecl(DD, Dtor_Deleting)] = 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 { } else {
// Add the entry. // Add the entry.
MethodVTableIndices[MD] = CurrentIndex++; MethodVTableIndices[MD] = CurrentIndex++;
@ -2279,6 +2322,11 @@ void VTableContext::ComputeMethodVTableIndices(const CXXRecordDecl *RD) {
// If a class has an implicitly-defined virtual destructor, // If a class has an implicitly-defined virtual destructor,
// its entries come after the declared virtual function pointers. // 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. // Add the complete dtor.
MethodVTableIndices[GlobalDecl(ImplicitVirtualDtor, Dtor_Complete)] = MethodVTableIndices[GlobalDecl(ImplicitVirtualDtor, Dtor_Complete)] =
CurrentIndex++; CurrentIndex++;
@ -2358,7 +2406,8 @@ static VTableLayout *CreateVTableLayout(const VTableBuilder &Builder) {
Builder.vtable_component_begin(), Builder.vtable_component_begin(),
VTableThunks.size(), VTableThunks.size(),
VTableThunks.data(), VTableThunks.data(),
Builder.getAddressPoints()); Builder.getAddressPoints(),
Builder.isMicrosoftABI());
} }
void VTableContext::ComputeVTableRelatedInformation(const CXXRecordDecl *RD) { 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( VTableLayout *VTableContext::createConstructionVTableLayout(
const CXXRecordDecl *MostDerivedClass, const CXXRecordDecl *MostDerivedClass,
CharUnits MostDerivedClassOffset, CharUnits MostDerivedClassOffset,

View File

@ -207,7 +207,7 @@ void MicrosoftCXXABI::EmitGuardedInit(CodeGenFunction &CGF, const VarDecl &D,
} }
void MicrosoftCXXABI::EmitVTables(const CXXRecordDecl *Class) { void MicrosoftCXXABI::EmitVTables(const CXXRecordDecl *Class) {
// FIXME: implement CGM.getVTables().GenerateClassData(CGM.getVTableLinkage(Class), Class);
} }
CGCXXABI *clang::CodeGen::CreateMicrosoftCXXABI(CodeGenModule &CGM) { CGCXXABI *clang::CodeGen::CreateMicrosoftCXXABI(CodeGenModule &CGM) {

View File

@ -22,3 +22,14 @@ void no_contstructor_destructor_infinite_recursion() {
// CHECK: ret // 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]]
}

View File

@ -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() {}