From 21979193bbbcda052611f76ba906bbd0c885c8f5 Mon Sep 17 00:00:00 2001 From: Devang Patel Date: Wed, 4 Jun 2008 21:22:16 +0000 Subject: [PATCH] Refactoring. Move field layout code in a ASTRecordLayout member fn. llvm-svn: 51966 --- clang/include/clang/AST/RecordLayout.h | 24 +++- clang/lib/AST/ASTContext.cpp | 154 +++++++++++++------------ 2 files changed, 99 insertions(+), 79 deletions(-) diff --git a/clang/include/clang/AST/RecordLayout.h b/clang/include/clang/AST/RecordLayout.h index 10c10c9a2c29..a4964b36915c 100644 --- a/clang/include/clang/AST/RecordLayout.h +++ b/clang/include/clang/AST/RecordLayout.h @@ -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: diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp index 2fe1f515c0ce..6b5eaa112ce0 100644 --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -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(); + 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 FieldInfo = + Context.getTypeInfo(FD->getType()); + uint64_t TypeSize = FieldInfo.first; + + FieldAlign = FieldInfo.second; + if (FieldIsPacked) + FieldAlign = 1; + if (const AlignedAttr *AA = FD->getAttr()) + 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 FieldInfo = + Context.getTypeInfo(FD->getType()); + FieldSize = FieldInfo.first; + FieldAlign = FieldInfo.second; + } + + if (FieldIsPacked) + FieldAlign = 8; + if (const AlignedAttr *AA = FD->getAttr()) + 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(); bool IsUnion = (D->getKind() == Decl::Union); if (const AlignedAttr *AA = D->getAttr()) - 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(); - 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 FieldInfo = getTypeInfo(FD->getType()); - uint64_t TypeSize = FieldInfo.first; - - FieldAlign = FieldInfo.second; - if (FieldIsPacked) - FieldAlign = 1; - if (const AlignedAttr *AA = FD->getAttr()) - 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 FieldInfo = getTypeInfo(FD->getType()); - FieldSize = FieldInfo.first; - FieldAlign = FieldInfo.second; - } - - if (FieldIsPacked) - FieldAlign = 8; - if (const AlignedAttr *AA = FD->getAttr()) - 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; }