From: Mike Stump Date: Thu, 13 Aug 2009 22:53:07 +0000 (+0000) Subject: Refine vtable layout for virtual bases and keep better track of X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=4ef980984fd0e131fca3f9e6ba15e8a79cabf88c;p=clang Refine vtable layout for virtual bases and keep better track of primaries. WIP. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@78950 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/AST/RecordLayoutBuilder.cpp b/lib/AST/RecordLayoutBuilder.cpp index bd99414308..7988106de5 100644 --- a/lib/AST/RecordLayoutBuilder.cpp +++ b/lib/AST/RecordLayoutBuilder.cpp @@ -26,14 +26,15 @@ ASTRecordLayoutBuilder::ASTRecordLayoutBuilder(ASTContext &Ctx) NextOffset(0), IsUnion(false), NonVirtualSize(0), NonVirtualAlignment(8) {} /// LayoutVtable - Lay out the vtable and set PrimaryBase. -void ASTRecordLayoutBuilder::LayoutVtable(const CXXRecordDecl *RD) { +void ASTRecordLayoutBuilder::LayoutVtable(const CXXRecordDecl *RD, + llvm::SmallSet &IndirectPrimary) { if (!RD->isDynamicClass()) { // There is no primary base in this case. setPrimaryBase(0, false); return; } - SelectPrimaryBase(RD); + SelectPrimaryBase(RD, IndirectPrimary); if (PrimaryBase == 0) { int AS = 0; UpdateAlignment(Ctx.Target.getPointerAlign(AS)); @@ -85,9 +86,8 @@ void ASTRecordLayoutBuilder::SelectPrimaryForBase(const CXXRecordDecl *RD, cast(i->getType()->getAs()->getDecl()); // Only bases with virtual bases participate in computing the // indirect primary virtual base classes. - if (Base->getNumVBases() == 0) - continue; - SelectPrimaryForBase(Base, IndirectPrimary); + if (Base->getNumVBases()) + SelectPrimaryForBase(Base, IndirectPrimary); } } @@ -117,7 +117,8 @@ void ASTRecordLayoutBuilder::SelectPrimaryVBase(const CXXRecordDecl *RD, /// SelectPrimaryBase - Selects the primary base for the given class and /// record that with setPrimaryBase. -void ASTRecordLayoutBuilder::SelectPrimaryBase(const CXXRecordDecl *RD) { +void ASTRecordLayoutBuilder::SelectPrimaryBase(const CXXRecordDecl *RD, + llvm::SmallSet &IndirectPrimary) { // The primary base is the first non-virtual indirect or direct base class, // if one exists. for (CXXRecordDecl::base_class_const_iterator i = RD->bases_begin(), @@ -146,7 +147,6 @@ void ASTRecordLayoutBuilder::SelectPrimaryBase(const CXXRecordDecl *RD) { // First, we compute all the primary virtual bases for all of our direct and // indirect bases, and record all their primary virtual base classes. const CXXRecordDecl *FirstPrimary = 0; - llvm::SmallSet IndirectPrimary; for (CXXRecordDecl::base_class_const_iterator i = RD->bases_begin(), e = RD->bases_end(); i != e; ++i) { const CXXRecordDecl *Base = @@ -169,13 +169,19 @@ void ASTRecordLayoutBuilder::LayoutVirtualBase(const CXXRecordDecl *RD) { void ASTRecordLayoutBuilder::LayoutVirtualBases(const CXXRecordDecl *RD, llvm::SmallSet &IndirectPrimary) { - // FIXME: Though complete, this is the wrong order - for (CXXRecordDecl::base_class_const_iterator i = RD->vbases_begin(), - e = RD->vbases_end(); i != e; ++i) { + // FIXME: Calculate IndirectPrimary when !PrimaryBaseWasVirtual + // assert(PrimaryBaseWasVirtual && "FIXME: calculate IndirectPrimary"); + for (CXXRecordDecl::base_class_const_iterator i = RD->bases_begin(), + e = RD->bases_end(); i != e; ++i) { const CXXRecordDecl *Base = cast(i->getType()->getAs()->getDecl()); - if (!IndirectPrimary.count(Base)) + if (i->isVirtual() && !IndirectPrimary.count(Base)) { + // Mark it so we don't output it twice. + IndirectPrimary.insert(Base); LayoutVirtualBase(Base); + } + if (Base->getNumVBases()) + LayoutVirtualBases(Base, IndirectPrimary); } } @@ -216,13 +222,12 @@ void ASTRecordLayoutBuilder::Layout(const RecordDecl *D) { if (const AlignedAttr *AA = D->getAttr()) UpdateAlignment(AA->getAlignment()); - // FIXME: Calculate this completely. llvm::SmallSet IndirectPrimary; // If this is a C++ class, lay out the nonvirtual bases. const CXXRecordDecl *RD = dyn_cast(D); if (RD) { - LayoutVtable(RD); + LayoutVtable(RD, IndirectPrimary); // PrimaryBase goes first. if (PrimaryBase) { // FIXME: We need all the primaries. diff --git a/lib/AST/RecordLayoutBuilder.h b/lib/AST/RecordLayoutBuilder.h index 05944ece7d..24a185c8ab 100644 --- a/lib/AST/RecordLayoutBuilder.h +++ b/lib/AST/RecordLayoutBuilder.h @@ -53,7 +53,8 @@ class ASTRecordLayoutBuilder { void LayoutFields(const RecordDecl *D); void LayoutField(const FieldDecl *D); - void SelectPrimaryBase(const CXXRecordDecl *RD); + void SelectPrimaryBase(const CXXRecordDecl *RD, + llvm::SmallSet &IndirectPrimary); void SelectPrimaryVBase(const CXXRecordDecl *RD, const CXXRecordDecl *&FirstPrimary, llvm::SmallSet &IndirectPrimary); @@ -64,7 +65,8 @@ class ASTRecordLayoutBuilder { PrimaryBaseWasVirtual = Virtual; } bool IsNearlyEmpty(const CXXRecordDecl *RD); - void LayoutVtable(const CXXRecordDecl *RD); + void LayoutVtable(const CXXRecordDecl *RD, + llvm::SmallSet &IndirectPrimary); void LayoutNonVirtualBases(const CXXRecordDecl *RD); void LayoutBaseNonVirtually(const CXXRecordDecl *RD); void LayoutVirtualBase(const CXXRecordDecl *RD); diff --git a/lib/CodeGen/CGCXX.cpp b/lib/CodeGen/CGCXX.cpp index 2940f18b4d..24e87f521f 100644 --- a/lib/CodeGen/CGCXX.cpp +++ b/lib/CodeGen/CGCXX.cpp @@ -617,10 +617,10 @@ llvm::Constant *CodeGenFunction::GenerateRtti(const CXXRecordDecl *RD) { llvm::GlobalVariable::LinkageTypes linktype; linktype = llvm::GlobalValue::WeakAnyLinkage; std::vector info; - // assert (0 && "FIXME: implement rtti descriptor"); + // assert(0 && "FIXME: implement rtti descriptor"); // FIXME: descriptor info.push_back(llvm::Constant::getNullValue(Ptr8Ty)); - // assert (0 && "FIXME: implement rtti ts"); + // assert(0 && "FIXME: implement rtti ts"); // FIXME: TS info.push_back(llvm::Constant::getNullValue(Ptr8Ty)); @@ -666,6 +666,25 @@ void CodeGenFunction::GenerateMethods(std::vector &methods, } } +void CodeGenFunction::GenerateVtableForVBases(const CXXRecordDecl *RD, + llvm::Constant *rtti, + std::vector &methods, + llvm::SmallSet &IndirectPrimary) { + for (CXXRecordDecl::base_class_const_iterator i = RD->bases_begin(), + e = RD->bases_end(); i != e; ++i) { + const CXXRecordDecl *Base = + cast(i->getType()->getAs()->getDecl()); + if (i->isVirtual() && !IndirectPrimary.count(Base)) { + // Mark it so we don't output it twice. + IndirectPrimary.insert(Base); + GenerateVtableForBase(Base, RD, rtti, methods, false, true, + IndirectPrimary); + } + if (Base->getNumVBases()) + GenerateVtableForVBases(Base, rtti, methods, IndirectPrimary); + } +} + void CodeGenFunction::GenerateVtableForBase(const CXXRecordDecl *RD, const CXXRecordDecl *Class, llvm::Constant *rtti, @@ -776,15 +795,8 @@ llvm::Value *CodeGenFunction::GenerateVtable(const CXXRecordDecl *RD) { IndirectPrimary); } - // FIXME: Though complete, this is the wrong order - for (CXXRecordDecl::base_class_const_iterator i = RD->vbases_begin(), - e = RD->vbases_end(); i != e; ++i) { - const CXXRecordDecl *Base = - cast(i->getType()->getAs()->getDecl()); - if (!IndirectPrimary.count(Base)) - GenerateVtableForBase(Base, RD, rtti, methods, false, true, - IndirectPrimary); - } + // Then come the vtables for all the virtual bases. + GenerateVtableForVBases(RD, rtti, methods, IndirectPrimary); llvm::Constant *C; llvm::ArrayType *type = llvm::ArrayType::get(Ptr8Ty, methods.size()); diff --git a/lib/CodeGen/CodeGenFunction.h b/lib/CodeGen/CodeGenFunction.h index 1ea19c6e13..aa4bcceae2 100644 --- a/lib/CodeGen/CodeGenFunction.h +++ b/lib/CodeGen/CodeGenFunction.h @@ -363,6 +363,10 @@ public: const CXXRecordDecl *RD, llvm::Type *Ptr8Ty); void GenerateMethods(std::vector &methods, const CXXRecordDecl *RD, llvm::Type *Ptr8Ty); +void GenerateVtableForVBases(const CXXRecordDecl *RD, + llvm::Constant *rtti, + std::vector &methods, + llvm::SmallSet &IndirectPrimary); void GenerateVtableForBase(const CXXRecordDecl *RD, const CXXRecordDecl *Class, llvm::Constant *rtti, diff --git a/test/CodeGenCXX/virt.cpp b/test/CodeGenCXX/virt.cpp index 0a8fb0edda..eb1c83940a 100644 --- a/test/CodeGenCXX/virt.cpp +++ b/test/CodeGenCXX/virt.cpp @@ -224,7 +224,7 @@ struct test5_D : virtual test5_B1, virtual test5_B21, virtual test5_B31 { // CHECK-LP32 .long -4 // CHECK-LP32: .long __ZTI7test5_D // CHECK-LP32: .long __ZN9test5_B237funcB23Ev -// CHECK-LP32: .long __ZN9test5_B227funcB22Ev +// CHECK-LP32 .long __ZN9test5_B227funcB22Ev // CHECK-LP32 .long __ZN9test5_B217funcB21Ev // CHECK-LP32 .space 4 // CHECK-LP32 .long 8 @@ -276,7 +276,7 @@ struct test5_D : virtual test5_B1, virtual test5_B21, virtual test5_B31 { // CHECK-LP64 .quad 18446744073709551608 // CHECK-LP64: .quad __ZTI7test5_D // CHECK-LP64: .quad __ZN9test5_B237funcB23Ev -// CHECK-LP64: .quad __ZN9test5_B227funcB22Ev +// CHECK-LP64 .quad __ZN9test5_B227funcB22Ev // CHECK-LP64 .quad __ZN9test5_B217funcB21Ev // CHECK-LP64 .space 8 // CHECK-LP64 .quad 16