Add a field for C++ specific data to ASTRecordLayout. Use it to store the non-virtual size and alignment + base offsets.

llvm-svn: 77352
This commit is contained in:
Anders Carlsson 2009-07-28 19:24:15 +00:00
parent a399dfae19
commit fc8cfa8b9f
3 changed files with 119 additions and 22 deletions

View File

@ -20,6 +20,7 @@ namespace clang {
class ASTContext;
class FieldDecl;
class RecordDecl;
class CXXRecordDecl;
/// ASTRecordLayout -
/// This class contains layout information for one RecordDecl,
@ -29,26 +30,78 @@ namespace clang {
/// ObjCInterfaceDecl. FIXME - Find appropriate name.
/// These objects are managed by ASTContext.
class ASTRecordLayout {
uint64_t Size; // Size of record in bits.
uint64_t DataSize; // Size of record in bits without tail padding.
/// Size - Size of record in bits.
uint64_t Size;
/// DataSize - Size of record in bits without tail padding.
uint64_t DataSize;
/// FieldOffsets - Array of field offsets in bits.
uint64_t *FieldOffsets;
unsigned Alignment; // Alignment of record in bits.
unsigned FieldCount; // Number of fields
// Alignment - Alignment of record in bits.
unsigned Alignment;
// FieldCount - Number of fields.
unsigned FieldCount;
struct CXXRecordLayoutInfo {
/// NonVirtualSize - The non-virtual size (in bits) of an object, which is
/// the size of the object without virtual bases.
uint64_t NonVirtualSize;
/// NonVirtualAlign - The non-virtual alignment (in bits) of an object,
/// which is the alignment of the object without virtual bases.
uint64_t NonVirtualAlign;
/// BaseOffsets - Contains a map from base classes to their offset.
/// FIXME: Does it make sense to store offsets for virtual base classes
/// here?
/// FIXME: This should really use a SmallPtrMap, once we have one in LLVM :)
llvm::DenseMap<const CXXRecordDecl *, uint64_t> BaseOffsets;
};
/// CXXInfo - If the record layout is for a C++ record, this will have
/// C++ specific information about the record.
CXXRecordLayoutInfo *CXXInfo;
friend class ASTContext;
friend class ASTRecordLayoutBuilder;
ASTRecordLayout(uint64_t size, unsigned alignment, unsigned datasize,
const uint64_t *fieldoffsets, unsigned fieldcount)
: Size(size), DataSize(datasize), FieldOffsets(0), Alignment(alignment),
FieldCount(fieldcount) {
FieldCount(fieldcount), CXXInfo(0) {
if (FieldCount > 0) {
FieldOffsets = new uint64_t[FieldCount];
for (unsigned i = 0; i < FieldCount; ++i)
FieldOffsets[i] = fieldoffsets[i];
}
}
// Constructor for C++ records.
ASTRecordLayout(uint64_t size, unsigned alignment, unsigned datasize,
const uint64_t *fieldoffsets, unsigned fieldcount,
uint64_t nonvirtualsize, unsigned nonvirtualalign,
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) {
FieldOffsets = new uint64_t[FieldCount];
for (unsigned i = 0; i < FieldCount; ++i)
FieldOffsets[i] = fieldoffsets[i];
}
CXXInfo->NonVirtualSize = nonvirtualsize;
CXXInfo->NonVirtualAlign = nonvirtualalign;
for (unsigned i = 0; i != basecount; ++i)
CXXInfo->BaseOffsets[bases[i]] = baseoffsets[i];
}
~ASTRecordLayout() {
delete [] FieldOffsets;
delete CXXInfo;
}
ASTRecordLayout(const ASTRecordLayout&); // DO NOT IMPLEMENT
@ -76,6 +129,30 @@ public:
uint64_t getDataSize() const {
return DataSize;
}
/// getNonVirtualSize - Get the non-virtual size (in bits) of an object,
/// which is the size of the object without virtual bases.
uint64_t getNonVirtualSize() const {
assert(CXXInfo && "Record layout does not have C++ specific info!");
return CXXInfo->NonVirtualSize;
}
/// getNonVirtualSize - Get the non-virtual alignment (in bits) of an object,
/// which is the alignment of the object without virtual bases.
unsigned getNonVirtualAlign() const {
assert(CXXInfo && "Record layout does not have C++ specific info!");
return CXXInfo->NonVirtualAlign;
}
/// 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!");
assert(CXXInfo->BaseOffsets.count(Base) && "Did not find base!");
return CXXInfo->BaseOffsets[Base];
}
};
} // end namespace clang

View File

@ -22,7 +22,7 @@ using namespace clang;
ASTRecordLayoutBuilder::ASTRecordLayoutBuilder(ASTContext &Ctx)
: Ctx(Ctx), Size(0), Alignment(8), StructPacking(0), NextOffset(0),
IsUnion(false) {}
IsUnion(false), NonVirtualSize(0), NonVirtualAlignment(8) {}
void
ASTRecordLayoutBuilder::LayoutNonVirtualBases(const CXXRecordDecl *RD) {
@ -44,15 +44,16 @@ void ASTRecordLayoutBuilder::LayoutNonVirtualBase(const CXXRecordDecl *RD) {
assert(BaseInfo.getDataSize() > 0 &&
"FIXME: Handle empty classes.");
// FIXME: Should get the non-virtual alignment of the base.
unsigned BaseAlign = BaseInfo.getAlignment();
// FIXME: Should get the non-virtual size of the base.
uint64_t BaseSize = BaseInfo.getDataSize();
unsigned BaseAlign = BaseInfo.getNonVirtualAlign();
uint64_t BaseSize = BaseInfo.getNonVirtualSize();
// Round up the current record size to the base's alignment boundary.
Size = (Size + (BaseAlign-1)) & ~(BaseAlign-1);
// Add base class offsets.
Bases.push_back(RD);
BaseOffsets.push_back(Size);
// Non-virtual base class has offset too.
FieldOffsets.push_back(Size);
@ -81,6 +82,9 @@ void ASTRecordLayoutBuilder::Layout(const RecordDecl *D) {
LayoutFields(D);
NonVirtualSize = Size;
NonVirtualAlignment = Alignment;
// Finally, round the size of the total struct up to the alignment of the
// struct itself.
FinishLayout();
@ -238,22 +242,33 @@ ASTRecordLayoutBuilder::ComputeLayout(ASTContext &Ctx,
Builder.Layout(D);
bool IsPODForThePurposeOfLayout;
if (!Ctx.getLangOptions().CPlusPlus) {
// In C, all record types are POD.
IsPODForThePurposeOfLayout = true;
} else {
if (!isa<CXXRecordDecl>(D))
return new ASTRecordLayout(Builder.Size, Builder.Alignment, Builder.Size,
Builder.FieldOffsets.data(),
Builder.FieldOffsets.size());
// FIXME: This is not always correct. See the part about bitfields at
// http://www.codesourcery.com/public/cxx-abi/abi.html#POD for more info.
IsPODForThePurposeOfLayout = cast<CXXRecordDecl>(D)->isPOD();
}
// FIXME: IsPODForThePurposeOfLayout should be stored in the record layout.
bool IsPODForThePurposeOfLayout = cast<CXXRecordDecl>(D)->isPOD();
assert(Builder.Bases.size() == Builder.BaseOffsets.size() &&
"Base offsets vector must be same size as bases vector!");
// FIXME: This should be done in FinalizeLayout.
uint64_t DataSize =
IsPODForThePurposeOfLayout ? Builder.Size : Builder.NextOffset;
uint64_t NonVirtualSize =
IsPODForThePurposeOfLayout ? DataSize : Builder.NonVirtualSize;
return new ASTRecordLayout(Builder.Size, Builder.Alignment, DataSize,
Builder.FieldOffsets.data(),
Builder.FieldOffsets.size());
Builder.FieldOffsets.size(),
NonVirtualSize,
Builder.NonVirtualAlignment,
Builder.Bases.data(),
Builder.BaseOffsets.data(),
Builder.Bases.size());
}
const ASTRecordLayout *

View File

@ -26,13 +26,18 @@ class ASTRecordLayoutBuilder {
ASTContext &Ctx;
uint64_t Size;
uint64_t Alignment;
unsigned Alignment;
llvm::SmallVector<uint64_t, 16> FieldOffsets;
unsigned StructPacking;
unsigned NextOffset;
bool IsUnion;
uint64_t NonVirtualSize;
unsigned NonVirtualAlignment;
llvm::SmallVector<const CXXRecordDecl *, 4> Bases;
llvm::SmallVector<uint64_t, 4> BaseOffsets;
ASTRecordLayoutBuilder(ASTContext &Ctx);
void Layout(const RecordDecl *D);