Refactoring.

Move field layout code in a ASTRecordLayout member fn.

llvm-svn: 51966
This commit is contained in:
Devang Patel 2008-06-04 21:22:16 +00:00
parent 6da61be501
commit 21979193bb
2 changed files with 99 additions and 79 deletions

View File

@ -29,16 +29,30 @@ class ASTRecordLayout {
uint64_t *FieldOffsets;
friend class ASTContext;
ASTRecordLayout() {}
ASTRecordLayout() : Size(0), Alignment(8) {}
~ASTRecordLayout() {
delete [] FieldOffsets;
}
void SetLayout(uint64_t size, unsigned alignment, uint64_t *fieldOffsets) {
Size = size; Alignment = alignment;
FieldOffsets = fieldOffsets;
/// Initialize record layout. N is the number of fields in this record.
void InitializeLayout(unsigned N) {
FieldOffsets = new uint64_t[N];
}
/// Finalize record layout. Adjust record size based on the alignment.
void FinalizeLayout() {
// Finally, round the size of the record up to the alignment of the
// record itself.
Size = (Size + (Alignment-1)) & ~(Alignment-1);
}
void SetAlignment(unsigned A) { Alignment = A; }
/// LayoutField - Field layout.
void LayoutField(const FieldDecl *FD, unsigned FieldNo,
bool IsUnion, bool StructIsPacked,
ASTContext &Context);
ASTRecordLayout(const ASTRecordLayout&); // DO NOT IMPLEMENT
void operator=(const ASTRecordLayout&); // DO NOT IMPLEMENT
public:

View File

@ -311,6 +311,81 @@ ASTContext::getTypeInfo(QualType T) {
return std::make_pair(Width, Align);
}
/// LayoutField - Field layout.
void ASTRecordLayout::LayoutField(const FieldDecl *FD, unsigned FieldNo,
bool IsUnion, bool StructIsPacked,
ASTContext &Context) {
bool FieldIsPacked = StructIsPacked || FD->getAttr<PackedAttr>();
uint64_t FieldOffset = IsUnion ? 0 : Size;
uint64_t FieldSize;
unsigned FieldAlign;
if (const Expr *BitWidthExpr = FD->getBitWidth()) {
// TODO: Need to check this algorithm on other targets!
// (tested on Linux-X86)
llvm::APSInt I(32);
bool BitWidthIsICE =
BitWidthExpr->isIntegerConstantExpr(I, Context);
assert (BitWidthIsICE && "Invalid BitField size expression");
FieldSize = I.getZExtValue();
std::pair<uint64_t, unsigned> FieldInfo =
Context.getTypeInfo(FD->getType());
uint64_t TypeSize = FieldInfo.first;
FieldAlign = FieldInfo.second;
if (FieldIsPacked)
FieldAlign = 1;
if (const AlignedAttr *AA = FD->getAttr<AlignedAttr>())
FieldAlign = std::max(FieldAlign, AA->getAlignment());
// Check if we need to add padding to give the field the correct
// alignment.
if (FieldSize == 0 || (FieldOffset & (FieldAlign-1)) + FieldSize > TypeSize)
FieldOffset = (FieldOffset + (FieldAlign-1)) & ~(FieldAlign-1);
// Padding members don't affect overall alignment
if (!FD->getIdentifier())
FieldAlign = 1;
} else {
if (FD->getType()->isIncompleteType()) {
// This must be a flexible array member; we can't directly
// query getTypeInfo about these, so we figure it out here.
// Flexible array members don't have any size, but they
// have to be aligned appropriately for their element type.
FieldSize = 0;
const ArrayType* ATy = FD->getType()->getAsArrayType();
FieldAlign = Context.getTypeAlign(ATy->getElementType());
} else {
std::pair<uint64_t, unsigned> FieldInfo =
Context.getTypeInfo(FD->getType());
FieldSize = FieldInfo.first;
FieldAlign = FieldInfo.second;
}
if (FieldIsPacked)
FieldAlign = 8;
if (const AlignedAttr *AA = FD->getAttr<AlignedAttr>())
FieldAlign = std::max(FieldAlign, AA->getAlignment());
// Round up the current record size to the field's alignment boundary.
FieldOffset = (FieldOffset + (FieldAlign-1)) & ~(FieldAlign-1);
}
// Place this field at the current location.
FieldOffsets[FieldNo] = FieldOffset;
// Reserve space for this field.
if (IsUnion) {
Size = std::max(Size, FieldSize);
} else {
Size = FieldOffset + FieldSize;
}
// Remember max struct/class alignment.
Alignment = std::max(Alignment, FieldAlign);
}
/// getASTRecordLayout - Get or compute information about the layout of the
/// specified record (struct/union/class), which indicates its size and field
/// position information.
@ -326,93 +401,24 @@ const ASTRecordLayout &ASTContext::getASTRecordLayout(const RecordDecl *D) {
ASTRecordLayout *NewEntry = new ASTRecordLayout();
Entry = NewEntry;
uint64_t *FieldOffsets = new uint64_t[D->getNumMembers()];
uint64_t RecordSize = 0;
unsigned RecordAlign = 8; // Default alignment = 1 byte = 8 bits.
NewEntry->InitializeLayout(D->getNumMembers());
bool StructIsPacked = D->getAttr<PackedAttr>();
bool IsUnion = (D->getKind() == Decl::Union);
if (const AlignedAttr *AA = D->getAttr<AlignedAttr>())
RecordAlign = std::max(RecordAlign, AA->getAlignment());
NewEntry->SetAlignment(std::max(NewEntry->getAlignment(),
AA->getAlignment()));
// Layout each field, for now, just sequentially, respecting alignment. In
// the future, this will need to be tweakable by targets.
for (unsigned i = 0, e = D->getNumMembers(); i != e; ++i) {
const FieldDecl *FD = D->getMember(i);
bool FieldIsPacked = StructIsPacked || FD->getAttr<PackedAttr>();
uint64_t FieldOffset = IsUnion ? 0 : RecordSize;
uint64_t FieldSize;
unsigned FieldAlign;
if (const Expr *BitWidthExpr = FD->getBitWidth()) {
// TODO: Need to check this algorithm on other targets!
// (tested on Linux-X86)
llvm::APSInt I(32);
bool BitWidthIsICE =
BitWidthExpr->isIntegerConstantExpr(I, *this);
assert (BitWidthIsICE && "Invalid BitField size expression");
FieldSize = I.getZExtValue();
std::pair<uint64_t, unsigned> FieldInfo = getTypeInfo(FD->getType());
uint64_t TypeSize = FieldInfo.first;
FieldAlign = FieldInfo.second;
if (FieldIsPacked)
FieldAlign = 1;
if (const AlignedAttr *AA = FD->getAttr<AlignedAttr>())
FieldAlign = std::max(FieldAlign, AA->getAlignment());
// Check if we need to add padding to give the field the correct
// alignment.
if (FieldSize == 0 || (FieldOffset & (FieldAlign-1)) + FieldSize > TypeSize)
FieldOffset = (FieldOffset + (FieldAlign-1)) & ~(FieldAlign-1);
// Padding members don't affect overall alignment
if (!FD->getIdentifier())
FieldAlign = 1;
} else {
if (FD->getType()->isIncompleteType()) {
// This must be a flexible array member; we can't directly
// query getTypeInfo about these, so we figure it out here.
// Flexible array members don't have any size, but they
// have to be aligned appropriately for their element type.
FieldSize = 0;
const ArrayType* ATy = FD->getType()->getAsArrayType();
FieldAlign = getTypeAlign(ATy->getElementType());
} else {
std::pair<uint64_t, unsigned> FieldInfo = getTypeInfo(FD->getType());
FieldSize = FieldInfo.first;
FieldAlign = FieldInfo.second;
}
if (FieldIsPacked)
FieldAlign = 8;
if (const AlignedAttr *AA = FD->getAttr<AlignedAttr>())
FieldAlign = std::max(FieldAlign, AA->getAlignment());
// Round up the current record size to the field's alignment boundary.
FieldOffset = (FieldOffset + (FieldAlign-1)) & ~(FieldAlign-1);
}
// Place this field at the current location.
FieldOffsets[i] = FieldOffset;
// Reserve space for this field.
if (IsUnion) {
RecordSize = std::max(RecordSize, FieldSize);
} else {
RecordSize = FieldOffset + FieldSize;
}
// Remember max struct/class alignment.
RecordAlign = std::max(RecordAlign, FieldAlign);
NewEntry->LayoutField(FD, i, IsUnion, StructIsPacked, *this);
}
// Finally, round the size of the total struct up to the alignment of the
// struct itself.
RecordSize = (RecordSize + (RecordAlign-1)) & ~(RecordAlign-1);
NewEntry->SetLayout(RecordSize, RecordAlign, FieldOffsets);
NewEntry->FinalizeLayout();
return *NewEntry;
}