More work on the empty subobjects map.

llvm-svn: 104787
This commit is contained in:
Anders Carlsson 2010-05-27 00:07:01 +00:00
parent 69dac58e7d
commit c121b4e59f
1 changed files with 49 additions and 28 deletions

View File

@ -42,8 +42,16 @@ public:
uint64_t SizeOfLargestEmptySubobject;
EmptySubobjectMap(ASTContext &Context, const CXXRecordDecl *Class)
: Context(Context), Class(Class), SizeOfLargestEmptySubobject(0) { }
: Context(Context), Class(Class), SizeOfLargestEmptySubobject(0) {
ComputeEmptySubobjectSizes();
}
/// CanPlaceBaseAtOffset - Return whether the given base class can be placed
/// at the given offset.
/// Returns false if placing the record will result in two components
/// (direct or indirect) of the same type having the same offset.
bool CanPlaceBaseAtOffset(const CXXRecordDecl *RD, bool BaseIsVirtual,
uint64_t Offset);
};
void EmptySubobjectMap::ComputeEmptySubobjectSizes() {
@ -95,6 +103,18 @@ void EmptySubobjectMap::ComputeEmptySubobjectSizes() {
}
}
bool
EmptySubobjectMap::CanPlaceBaseAtOffset(const CXXRecordDecl *RD,
bool BaseIsVirtual,
uint64_t Offset) {
// If we know this class doesn't have any empty subobjects we don't need to
// bother checking.
if (!SizeOfLargestEmptySubobject)
return true;
return true;
}
class RecordLayoutBuilder {
// FIXME: Remove this and make the appropriate fields public.
friend class clang::ASTContext;
@ -163,8 +183,8 @@ class RecordLayoutBuilder {
typedef std::multimap<uint64_t, const CXXRecordDecl *> EmptyClassOffsetsTy;
EmptyClassOffsetsTy EmptyClassOffsets;
RecordLayoutBuilder(ASTContext &Context)
: Context(Context), EmptySubobjects(0), Size(0), Alignment(8),
RecordLayoutBuilder(ASTContext &Context, EmptySubobjectMap *EmptySubobjects)
: Context(Context), EmptySubobjects(EmptySubobjects), Size(0), Alignment(8),
Packed(false), UnfilledBitsInLastByte(0), MaxFieldAlignment(0), DataSize(0),
IsUnion(false), NonVirtualSize(0), NonVirtualAlignment(8), PrimaryBase(0),
PrimaryBaseIsVirtual(false), FirstNearlyEmptyVBase(0) { }
@ -199,7 +219,7 @@ class RecordLayoutBuilder {
void LayoutNonVirtualBases(const CXXRecordDecl *RD);
/// LayoutNonVirtualBase - Lays out a single non-virtual base.
void LayoutNonVirtualBase(const CXXRecordDecl *RD);
void LayoutNonVirtualBase(const CXXRecordDecl *Base);
void AddPrimaryVirtualBaseOffsets(const CXXRecordDecl *RD, uint64_t Offset,
const CXXRecordDecl *MostDerivedClass);
@ -209,11 +229,11 @@ class RecordLayoutBuilder {
const CXXRecordDecl *MostDerivedClass);
/// LayoutVirtualBase - Lays out a single virtual base.
void LayoutVirtualBase(const CXXRecordDecl *RD);
void LayoutVirtualBase(const CXXRecordDecl *Base);
/// LayoutBase - Will lay out a base and return the offset where it was
/// placed, in bits.
uint64_t LayoutBase(const CXXRecordDecl *RD);
uint64_t LayoutBase(const CXXRecordDecl *Base, bool BaseIsVirtual);
/// canPlaceRecordAtOffset - Return whether a record (either a base class
/// or a field) can be placed at the given offset.
@ -250,10 +270,6 @@ class RecordLayoutBuilder {
void operator=(const RecordLayoutBuilder&); // DO NOT IMPLEMENT
public:
static const CXXMethodDecl *ComputeKeyFunction(const CXXRecordDecl *RD);
uint64_t getSizeOfLargestEmptySubobject() {
return EmptySubobjects->SizeOfLargestEmptySubobject;
}
};
} // end anonymous namespace
@ -431,12 +447,12 @@ RecordLayoutBuilder::LayoutNonVirtualBases(const CXXRecordDecl *RD) {
}
}
void RecordLayoutBuilder::LayoutNonVirtualBase(const CXXRecordDecl *RD) {
void RecordLayoutBuilder::LayoutNonVirtualBase(const CXXRecordDecl *Base) {
// Layout the base.
uint64_t Offset = LayoutBase(RD);
uint64_t Offset = LayoutBase(Base, /*BaseIsVirtual=*/false);
// Add its base class offset.
if (!Bases.insert(std::make_pair(RD, Offset)).second)
if (!Bases.insert(std::make_pair(Base, Offset)).second)
assert(false && "Added same base offset more than once!");
}
@ -544,22 +560,25 @@ RecordLayoutBuilder::LayoutVirtualBases(const CXXRecordDecl *RD,
}
}
void RecordLayoutBuilder::LayoutVirtualBase(const CXXRecordDecl *RD) {
void RecordLayoutBuilder::LayoutVirtualBase(const CXXRecordDecl *Base) {
// Layout the base.
uint64_t Offset = LayoutBase(RD);
uint64_t Offset = LayoutBase(Base, /*BaseIsVirtual=*/true);
// Add its base class offset.
if (!VBases.insert(std::make_pair(RD, Offset)).second)
if (!VBases.insert(std::make_pair(Base, Offset)).second)
assert(false && "Added same vbase offset more than once!");
}
uint64_t RecordLayoutBuilder::LayoutBase(const CXXRecordDecl *RD) {
const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD);
uint64_t RecordLayoutBuilder::LayoutBase(const CXXRecordDecl *Base,
bool BaseIsVirtual) {
const ASTRecordLayout &Layout = Context.getASTRecordLayout(Base);
// If we have an empty base class, try to place it at offset 0.
if (RD->isEmpty() && canPlaceRecordAtOffset(RD, 0, /*CheckVBases=*/false)) {
if (Base->isEmpty() &&
EmptySubobjects->CanPlaceBaseAtOffset(Base, BaseIsVirtual, 0) &&
canPlaceRecordAtOffset(Base, 0, /*CheckVBases=*/false)) {
// We were able to place the class at offset 0.
UpdateEmptyClassOffsets(RD, 0, /*UpdateVBases=*/false);
UpdateEmptyClassOffsets(Base, 0, /*UpdateVBases=*/false);
Size = std::max(Size, Layout.getSize());
@ -573,13 +592,14 @@ uint64_t RecordLayoutBuilder::LayoutBase(const CXXRecordDecl *RD) {
// Try to place the base.
while (true) {
if (canPlaceRecordAtOffset(RD, Offset, /*CheckVBases=*/false))
if (EmptySubobjects->CanPlaceBaseAtOffset(Base, BaseIsVirtual, Offset) &&
canPlaceRecordAtOffset(Base, Offset, /*CheckVBases=*/false))
break;
Offset += BaseAlign;
}
if (!RD->isEmpty()) {
if (!Base->isEmpty()) {
// Update the data size.
DataSize = Offset + Layout.getNonVirtualSize();
@ -590,7 +610,7 @@ uint64_t RecordLayoutBuilder::LayoutBase(const CXXRecordDecl *RD) {
// Remember max struct/class alignment.
UpdateAlignment(BaseAlign);
UpdateEmptyClassOffsets(RD, Offset, /*UpdateVBases=*/false);
UpdateEmptyClassOffsets(Base, Offset, /*UpdateVBases=*/false);
return Offset;
}
@ -1125,7 +1145,8 @@ const ASTRecordLayout &ASTContext::getASTRecordLayout(const RecordDecl *D) {
const ASTRecordLayout *NewEntry;
if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(D)) {
RecordLayoutBuilder Builder(*this);
EmptySubobjectMap EmptySubobjects(*this, RD);
RecordLayoutBuilder Builder(*this, &EmptySubobjects);
Builder.Layout(RD);
// FIXME: This is not always correct. See the part about bitfields at
@ -1145,12 +1166,12 @@ const ASTRecordLayout &ASTContext::getASTRecordLayout(const RecordDecl *D) {
Builder.FieldOffsets.size(),
NonVirtualSize,
Builder.NonVirtualAlignment,
Builder.getSizeOfLargestEmptySubobject(),
EmptySubobjects.SizeOfLargestEmptySubobject,
Builder.PrimaryBase,
Builder.PrimaryBaseIsVirtual,
Builder.Bases, Builder.VBases);
} else {
RecordLayoutBuilder Builder(*this);
RecordLayoutBuilder Builder(*this, /*EmptySubobjects=*/0);
Builder.Layout(D);
NewEntry =
@ -1211,7 +1232,7 @@ ASTContext::getObjCLayout(const ObjCInterfaceDecl *D,
return getObjCLayout(D, 0);
}
RecordLayoutBuilder Builder(*this);
RecordLayoutBuilder Builder(*this, /*EmptySubobjects=*/0);
Builder.Layout(D);
const ASTRecordLayout *NewEntry =