Refactoring.
Move field layout code in a ASTRecordLayout member fn. llvm-svn: 51966
This commit is contained in:
parent
6da61be501
commit
21979193bb
|
@ -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:
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue