forked from OSchip/llvm-project
Calculate the primary base class better and use that when laying down
the vtable. Still a work in progress. llvm-svn: 78252
This commit is contained in:
parent
dc3416b7b3
commit
d8fe7b2792
|
@ -398,6 +398,10 @@ public:
|
|||
|
||||
virtual void Destroy(ASTContext& C);
|
||||
|
||||
bool isDynamicClass() const {
|
||||
return Polymorphic || NumVBases!=0;
|
||||
}
|
||||
|
||||
/// setBases - Sets the base classes of this struct or class.
|
||||
void setBases(ASTContext &C,
|
||||
CXXBaseSpecifier const * const *Bases, unsigned NumBases);
|
||||
|
|
|
@ -54,6 +54,9 @@ class ASTRecordLayout {
|
|||
/// which is the alignment of the object without virtual bases.
|
||||
uint64_t NonVirtualAlign;
|
||||
|
||||
/// PrimaryBase - The primary base for our vtable.
|
||||
const CXXRecordDecl *PrimaryBase;
|
||||
|
||||
/// BaseOffsets - Contains a map from base classes to their offset.
|
||||
/// FIXME: Does it make sense to store offsets for virtual base classes
|
||||
/// here?
|
||||
|
@ -83,8 +86,8 @@ class ASTRecordLayout {
|
|||
ASTRecordLayout(uint64_t size, unsigned alignment, uint64_t datasize,
|
||||
const uint64_t *fieldoffsets, unsigned fieldcount,
|
||||
uint64_t nonvirtualsize, unsigned nonvirtualalign,
|
||||
const CXXRecordDecl **bases, const uint64_t *baseoffsets,
|
||||
unsigned basecount)
|
||||
const CXXRecordDecl *PB, const CXXRecordDecl **bases,
|
||||
const uint64_t *baseoffsets, unsigned basecount)
|
||||
: Size(size), DataSize(datasize), FieldOffsets(0), Alignment(alignment),
|
||||
FieldCount(fieldcount), CXXInfo(new CXXRecordLayoutInfo) {
|
||||
if (FieldCount > 0) {
|
||||
|
@ -93,6 +96,7 @@ class ASTRecordLayout {
|
|||
FieldOffsets[i] = fieldoffsets[i];
|
||||
}
|
||||
|
||||
CXXInfo->PrimaryBase = PB;
|
||||
CXXInfo->NonVirtualSize = nonvirtualsize;
|
||||
CXXInfo->NonVirtualAlign = nonvirtualalign;
|
||||
for (unsigned i = 0; i != basecount; ++i)
|
||||
|
@ -146,6 +150,13 @@ public:
|
|||
return CXXInfo->NonVirtualAlign;
|
||||
}
|
||||
|
||||
/// getPrimaryBase - Get the primary base.
|
||||
const CXXRecordDecl *getPrimaryBase() const {
|
||||
assert(CXXInfo && "Record layout does not have C++ specific info!");
|
||||
|
||||
return CXXInfo->PrimaryBase;
|
||||
}
|
||||
|
||||
/// getBaseClassOffset - Get the offset, in bits, for the given base class.
|
||||
uint64_t getBaseClassOffset(const CXXRecordDecl *Base) const {
|
||||
assert(CXXInfo && "Record layout does not have C++ specific info!");
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
#include "clang/AST/Expr.h"
|
||||
#include "clang/AST/RecordLayout.h"
|
||||
#include "clang/Basic/TargetInfo.h"
|
||||
#include <llvm/ADT/SmallSet.h>
|
||||
#include <llvm/Support/MathExtras.h>
|
||||
|
||||
using namespace clang;
|
||||
|
@ -25,14 +26,17 @@ ASTRecordLayoutBuilder::ASTRecordLayoutBuilder(ASTContext &Ctx)
|
|||
IsUnion(false), NonVirtualSize(0), NonVirtualAlignment(8) {}
|
||||
|
||||
void ASTRecordLayoutBuilder::LayoutVtable(const CXXRecordDecl *RD) {
|
||||
if (RD->isPolymorphic() || RD->getNumVBases())
|
||||
{
|
||||
// assert (RD->getNumBases() == 0 && "no polymorphic inheritance yet");
|
||||
int AS = 0;
|
||||
UpdateAlignment(Ctx.Target.getPointerAlign(AS));
|
||||
Size += Ctx.Target.getPointerWidth(AS);
|
||||
NextOffset = Size;
|
||||
}
|
||||
// FIXME: audit indirect virtual bases
|
||||
if (!RD->isPolymorphic() && !RD->getNumVBases())
|
||||
return;
|
||||
|
||||
SelectPrimaryBase(RD);
|
||||
if (PrimaryBase == 0) {
|
||||
int AS = 0;
|
||||
UpdateAlignment(Ctx.Target.getPointerAlign(AS));
|
||||
Size += Ctx.Target.getPointerWidth(AS);
|
||||
NextOffset = Size;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -47,6 +51,104 @@ ASTRecordLayoutBuilder::LayoutNonVirtualBases(const CXXRecordDecl *RD) {
|
|||
}
|
||||
}
|
||||
|
||||
// Helper routines related to the abi definition from:
|
||||
// http://www.codesourcery.com/public/cxx-abi/abi.html
|
||||
//
|
||||
/// IsNearlyEmpty - Indicates when a class has a vtable pointer, but
|
||||
/// no other data.
|
||||
bool ASTRecordLayoutBuilder::IsNearlyEmpty(const CXXRecordDecl *RD) {
|
||||
// FIXME: Audit the corners
|
||||
if (!RD->isDynamicClass())
|
||||
return false;
|
||||
const ASTRecordLayout &BaseInfo = Ctx.getASTRecordLayout(RD);
|
||||
if (BaseInfo.getNonVirtualSize() == Ctx.Target.getPointerWidth(0))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
void ASTRecordLayoutBuilder::SelectPrimaryForBase(const CXXRecordDecl *RD,
|
||||
llvm::SmallSet<const CXXRecordDecl*, 32> &IndirectPrimary) {
|
||||
for (CXXRecordDecl::base_class_const_iterator i = RD->bases_begin(),
|
||||
e = RD->bases_end(); i != e; ++i) {
|
||||
if (!i->isVirtual()) {
|
||||
const CXXRecordDecl *Base =
|
||||
cast<CXXRecordDecl>(i->getType()->getAs<RecordType>()->getDecl());
|
||||
// Only bases with virtual bases participate in computing the
|
||||
// indirect primary base classes.
|
||||
// FIXME: audit indirect virtual bases
|
||||
if (Base->getNumVBases() == 0)
|
||||
return;
|
||||
// FIXME: This information is recomputed a whole lot, cache it instead.
|
||||
SelectPrimaryBase(Base);
|
||||
IndirectPrimary.insert(PrimaryBase);
|
||||
SelectPrimaryForBase(Base, IndirectPrimary);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// SelectPrimaryBase - Selects the primary base for the given class and
|
||||
/// records that with setPrimaryBase.
|
||||
void ASTRecordLayoutBuilder::SelectPrimaryBase(const CXXRecordDecl *RD) {
|
||||
// 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(),
|
||||
e = RD->bases_end(); i != e; ++i) {
|
||||
if (!i->isVirtual()) {
|
||||
const CXXRecordDecl *Base =
|
||||
cast<CXXRecordDecl>(i->getType()->getAs<RecordType>()->getDecl());
|
||||
if (Base->isDynamicClass()) {
|
||||
setPrimaryBase(Base);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Otherwise, it is the first nearly empty virtual base that is not an
|
||||
// indirect primary base class, if one exists.
|
||||
|
||||
// If we have no virtual bases at this point, bail out as the searching below
|
||||
// is expensive.
|
||||
// FIXME: audit indirect virtual bases
|
||||
if (RD->getNumVBases() == 0) {
|
||||
setPrimaryBase(0);
|
||||
return;
|
||||
}
|
||||
|
||||
// First, we compute all the primary bases for all of out direct and indirect
|
||||
// non-virtual bases, and record all their primary base classes.
|
||||
const CXXRecordDecl *FirstPrimary = 0;
|
||||
llvm::SmallSet<const CXXRecordDecl*, 32> IndirectPrimary;
|
||||
for (CXXRecordDecl::base_class_const_iterator i = RD->bases_begin(),
|
||||
e = RD->bases_end(); i != e; ++i) {
|
||||
if (!i->isVirtual()) {
|
||||
const CXXRecordDecl *Base =
|
||||
cast<CXXRecordDecl>(i->getType()->getAs<RecordType>()->getDecl());
|
||||
SelectPrimaryForBase(Base, IndirectPrimary);
|
||||
}
|
||||
}
|
||||
|
||||
// Then we can search for the first nearly empty virtual base itself.
|
||||
// FIXME: audit indirect virtual bases
|
||||
for (CXXRecordDecl::base_class_const_iterator i = RD->vbases_begin(),
|
||||
e = RD->vbases_end(); i != e; ++i) {
|
||||
const CXXRecordDecl *Base =
|
||||
cast<CXXRecordDecl>(i->getType()->getAs<RecordType>()->getDecl());
|
||||
if (IsNearlyEmpty(Base)) {
|
||||
if (FirstPrimary==0)
|
||||
FirstPrimary = Base;
|
||||
if (!IndirectPrimary.count(Base)) {
|
||||
setPrimaryBase(Base);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Otherwise if is the first nearly empty base, if one exists, otherwise
|
||||
// there is no primary base class.
|
||||
setPrimaryBase(FirstPrimary);
|
||||
return;
|
||||
}
|
||||
|
||||
void ASTRecordLayoutBuilder::LayoutNonVirtualBase(const CXXRecordDecl *RD) {
|
||||
const ASTRecordLayout &BaseInfo = Ctx.getASTRecordLayout(RD);
|
||||
assert(BaseInfo.getDataSize() > 0 &&
|
||||
|
@ -86,6 +188,7 @@ void ASTRecordLayoutBuilder::Layout(const RecordDecl *D) {
|
|||
LayoutVtable(RD);
|
||||
LayoutNonVirtualBases(RD);
|
||||
|
||||
// FIXME: audit indirect virtual bases
|
||||
assert (RD->getNumVBases() == 0
|
||||
&& "FIXME: We don't support virtual bases yet!");
|
||||
// FIXME: We need to layout the virtual bases in the complete object layout.
|
||||
|
@ -277,6 +380,7 @@ ASTRecordLayoutBuilder::ComputeLayout(ASTContext &Ctx,
|
|||
Builder.FieldOffsets.size(),
|
||||
NonVirtualSize,
|
||||
Builder.NonVirtualAlignment,
|
||||
Builder.PrimaryBase,
|
||||
Builder.Bases.data(),
|
||||
Builder.BaseOffsets.data(),
|
||||
Builder.Bases.size());
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
#define LLVM_CLANG_AST_RECORDLAYOUTBUILDER_H
|
||||
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include "llvm/ADT/SmallSet.h"
|
||||
#include "llvm/Support/DataTypes.h"
|
||||
|
||||
namespace clang {
|
||||
|
@ -35,6 +36,8 @@ class ASTRecordLayoutBuilder {
|
|||
|
||||
uint64_t NonVirtualSize;
|
||||
unsigned NonVirtualAlignment;
|
||||
const CXXRecordDecl *PrimaryBase;
|
||||
|
||||
llvm::SmallVector<const CXXRecordDecl *, 4> Bases;
|
||||
llvm::SmallVector<uint64_t, 4> BaseOffsets;
|
||||
|
||||
|
@ -48,6 +51,11 @@ class ASTRecordLayoutBuilder {
|
|||
void LayoutFields(const RecordDecl *D);
|
||||
void LayoutField(const FieldDecl *D);
|
||||
|
||||
void SelectPrimaryBase(const CXXRecordDecl *RD);
|
||||
void SelectPrimaryForBase(const CXXRecordDecl *RD,
|
||||
llvm::SmallSet<const CXXRecordDecl*, 32> &IndirectPrimary);
|
||||
void setPrimaryBase(const CXXRecordDecl *PB) { PrimaryBase = PB; }
|
||||
bool IsNearlyEmpty(const CXXRecordDecl *RD);
|
||||
void LayoutVtable(const CXXRecordDecl *RD);
|
||||
void LayoutNonVirtualBases(const CXXRecordDecl *RD);
|
||||
void LayoutNonVirtualBase(const CXXRecordDecl *RD);
|
||||
|
|
|
@ -540,9 +540,12 @@ llvm::Value *CodeGenFunction::GenerateVtable(const CXXRecordDecl *RD) {
|
|||
llvm::Type *Ptr8Ty;
|
||||
Ptr8Ty = llvm::PointerType::get(llvm::Type::Int8Ty, 0);
|
||||
m = llvm::Constant::getNullValue(Ptr8Ty);
|
||||
int64_t offset = 0;
|
||||
methods.push_back(m); offset += LLVMPointerWidth;
|
||||
methods.push_back(GenerateRtti(RD)); offset += LLVMPointerWidth;
|
||||
int64_t Offset = 0;
|
||||
methods.push_back(m); Offset += LLVMPointerWidth;
|
||||
methods.push_back(GenerateRtti(RD)); Offset += LLVMPointerWidth;
|
||||
|
||||
const ASTRecordLayout &Layout = getContext().getASTRecordLayout(RD);
|
||||
const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBase();
|
||||
|
||||
for (CXXRecordDecl::base_class_const_iterator i = RD->bases_begin(),
|
||||
e = RD->bases_end(); i != e; ++i) {
|
||||
|
@ -550,6 +553,16 @@ llvm::Value *CodeGenFunction::GenerateVtable(const CXXRecordDecl *RD) {
|
|||
continue;
|
||||
const CXXRecordDecl *Base =
|
||||
cast<CXXRecordDecl>(i->getType()->getAs<RecordType>()->getDecl());
|
||||
if (PrimaryBase != Base) {
|
||||
const ASTRecordLayout &Layout = getContext().getASTRecordLayout(RD);
|
||||
int64_t BaseOffset = -(Layout.getBaseClassOffset(Base) / 8);
|
||||
m = llvm::ConstantInt::get(llvm::Type::Int64Ty, BaseOffset);
|
||||
m = llvm::ConstantExpr::getIntToPtr(m, Ptr8Ty);
|
||||
methods.push_back(m);
|
||||
// FIXME: GenerateRtti for Base in RD.
|
||||
m = llvm::Constant::getNullValue(Ptr8Ty);
|
||||
methods.push_back(m);
|
||||
}
|
||||
for (meth_iter mi = Base->method_begin(), me = Base->method_end(); mi != me;
|
||||
++mi) {
|
||||
if (mi->isVirtual()) {
|
||||
|
@ -558,16 +571,28 @@ llvm::Value *CodeGenFunction::GenerateVtable(const CXXRecordDecl *RD) {
|
|||
methods.push_back(m);
|
||||
}
|
||||
}
|
||||
if (PrimaryBase == Base) {
|
||||
for (meth_iter mi = RD->method_begin(), me = RD->method_end(); mi != me;
|
||||
++mi) {
|
||||
if (mi->isVirtual()) {
|
||||
m = CGM.GetAddrOfFunction(GlobalDecl(*mi));
|
||||
m = llvm::ConstantExpr::getBitCast(m, Ptr8Ty);
|
||||
methods.push_back(m);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (PrimaryBase == 0) {
|
||||
for (meth_iter mi = RD->method_begin(), me = RD->method_end(); mi != me;
|
||||
++mi) {
|
||||
if (mi->isVirtual()) {
|
||||
m = CGM.GetAddrOfFunction(GlobalDecl(*mi));
|
||||
m = llvm::ConstantExpr::getBitCast(m, Ptr8Ty);
|
||||
methods.push_back(m);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (meth_iter mi = RD->method_begin(), me = RD->method_end(); mi != me;
|
||||
++mi) {
|
||||
if (mi->isVirtual()) {
|
||||
m = CGM.GetAddrOfFunction(GlobalDecl(*mi));
|
||||
m = llvm::ConstantExpr::getBitCast(m, Ptr8Ty);
|
||||
methods.push_back(m);
|
||||
}
|
||||
}
|
||||
llvm::Constant *C;
|
||||
llvm::ArrayType *type = llvm::ArrayType::get(Ptr8Ty, methods.size());
|
||||
C = llvm::ConstantArray::get(type, methods);
|
||||
|
@ -577,7 +602,7 @@ llvm::Value *CodeGenFunction::GenerateVtable(const CXXRecordDecl *RD) {
|
|||
// FIXME: finish layout for virtual bases
|
||||
vtable = Builder.CreateGEP(vtable,
|
||||
llvm::ConstantInt::get(llvm::Type::Int64Ty,
|
||||
offset/8));
|
||||
Offset/8));
|
||||
return vtable;
|
||||
}
|
||||
|
||||
|
|
|
@ -8,15 +8,26 @@ struct B {
|
|||
virtual void bar1();
|
||||
virtual void bar2();
|
||||
};
|
||||
void B::bar1() { }
|
||||
void B::bar2() { }
|
||||
|
||||
struct C {
|
||||
virtual void bee1();
|
||||
virtual void bee2();
|
||||
};
|
||||
void C::bee1() { }
|
||||
void C::bee2() { }
|
||||
|
||||
static_assert (sizeof (B) == (sizeof(void *)), "vtable pointer layout");
|
||||
|
||||
class A : public B {
|
||||
class A : public B, public C {
|
||||
public:
|
||||
virtual void foo1();
|
||||
virtual void foo2();
|
||||
A() { }
|
||||
} *a;
|
||||
void A::foo1() { }
|
||||
void A::foo2() { }
|
||||
|
||||
int main() {
|
||||
A a;
|
||||
|
@ -29,6 +40,10 @@ int main() {
|
|||
// CHECK-LP64: .quad __ZN1B4bar2Ev
|
||||
// CHECK-LP64: .quad __ZN1A4foo1Ev
|
||||
// CHECK-LP64: .quad __ZN1A4foo2Ev
|
||||
// CHECK-LP64: .quad 18446744073709551608
|
||||
// CHECK-LP64: .space 8
|
||||
// CHECK-LP64: .quad __ZN1C4bee1Ev
|
||||
// CHECK-LP64: .quad __ZN1C4bee2Ev
|
||||
|
||||
// CHECK-LP32: __ZTV1A:
|
||||
// CHECK-LP32: .space 4
|
||||
|
@ -37,3 +52,7 @@ int main() {
|
|||
// CHECK-LP32: .long __ZN1B4bar2Ev
|
||||
// CHECK-LP32: .long __ZN1A4foo1Ev
|
||||
// CHECK-LP32: .long __ZN1A4foo2Ev
|
||||
// CHECK-LP32: .long 4294967292
|
||||
// CHECK-LP32: .space 4
|
||||
// CHECK-LP32: .long __ZN1C4bee1Ev
|
||||
// CHECK-LP32: .long __ZN1C4bee2Ev
|
||||
|
|
Loading…
Reference in New Issue