diff options
Diffstat (limited to 'clang/lib')
-rw-r--r-- | clang/lib/AST/ASTContext.cpp | 154 |
1 files changed, 80 insertions, 74 deletions
diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp index 2fe1f515c0c..6b5eaa112ce 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<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; } |