using namespace clang;
ASTRecordLayoutBuilder::ASTRecordLayoutBuilder(ASTContext &Ctx)
- : Ctx(Ctx), Size(0), Alignment(8), StructPacking(0), NextOffset(0),
- IsUnion(false), NonVirtualSize(0), NonVirtualAlignment(8) {}
+ : Ctx(Ctx), Size(0), Alignment(8), Packed(false), MaxFieldAlignment(0),
+ NextOffset(0), IsUnion(false), NonVirtualSize(0), NonVirtualAlignment(8) {}
/// LayoutVtable - Lay out the vtable and set PrimaryBase.
void ASTRecordLayoutBuilder::LayoutVtable(const CXXRecordDecl *RD) {
void ASTRecordLayoutBuilder::Layout(const RecordDecl *D) {
IsUnion = D->isUnion();
- if (D->hasAttr<PackedAttr>())
- StructPacking = 1;
+ Packed = D->hasAttr<PackedAttr>();
+
+ // The #pragma pack attribute specifies the maximum field alignment.
if (const PragmaPackAttr *PPA = D->getAttr<PragmaPackAttr>())
- StructPacking = PPA->getAlignment();
+ MaxFieldAlignment = PPA->getAlignment();
if (const AlignedAttr *AA = D->getAttr<AlignedAttr>())
UpdateAlignment(AA->getAlignment());
NextOffset = Size;
}
- if (D->hasAttr<PackedAttr>())
- StructPacking = 1;
+ Packed = D->hasAttr<PackedAttr>();
+
+ // The #pragma pack attribute specifies the maximum field alignment.
+ if (const PragmaPackAttr *PPA = D->getAttr<PragmaPackAttr>())
+ MaxFieldAlignment = PPA->getAlignment();
if (const AlignedAttr *AA = D->getAttr<AlignedAttr>())
UpdateAlignment(AA->getAlignment());
}
void ASTRecordLayoutBuilder::LayoutField(const FieldDecl *D) {
- unsigned FieldPacking = StructPacking;
+ bool FieldPacked = Packed;
uint64_t FieldOffset = IsUnion ? 0 : Size;
uint64_t FieldSize;
unsigned FieldAlign;
- // FIXME: Should this override struct packing? Probably we want to
- // take the minimum?
- if (D->hasAttr<PackedAttr>())
- FieldPacking = 1;
+ FieldPacked |= D->hasAttr<PackedAttr>();
if (const Expr *BitWidthExpr = D->getBitWidth()) {
// TODO: Need to check this algorithm on other targets!
std::pair<uint64_t, unsigned> FieldInfo = Ctx.getTypeInfo(D->getType());
uint64_t TypeSize = FieldInfo.first;
-
- // Determine the alignment of this bitfield. The packing
- // attributes define a maximum and the alignment attribute defines
- // a minimum.
- // FIXME: What is the right behavior when the specified alignment
- // is smaller than the specified packing?
+
FieldAlign = FieldInfo.second;
- if (FieldPacking)
- FieldAlign = std::min(FieldAlign, FieldPacking);
+
+ if (FieldPacked)
+ FieldAlign = 1;
if (const AlignedAttr *AA = D->getAttr<AlignedAttr>())
FieldAlign = std::max(FieldAlign, AA->getAlignment());
-
+ // The maximum field alignment overrides the aligned attribute.
+ if (MaxFieldAlignment)
+ FieldAlign = std::min(FieldAlign, MaxFieldAlignment);
+
// Check if we need to add padding to give the field the correct
// alignment.
if (FieldSize == 0 || (FieldOffset & (FieldAlign-1)) + FieldSize > TypeSize)
FieldAlign = FieldInfo.second;
}
- // Determine the alignment of this bitfield. The packing
- // attributes define a maximum and the alignment attribute defines
- // a minimum. Additionally, the packing alignment must be at least
- // a byte for non-bitfields.
- //
- // FIXME: What is the right behavior when the specified alignment
- // is smaller than the specified packing?
- if (FieldPacking)
- FieldAlign = std::min(FieldAlign, std::max(8U, FieldPacking));
+ if (FieldPacked)
+ FieldAlign = 8;
if (const AlignedAttr *AA = D->getAttr<AlignedAttr>())
FieldAlign = std::max(FieldAlign, AA->getAlignment());
+ // The maximum field alignment overrides the aligned attribute.
+ if (MaxFieldAlignment)
+ FieldAlign = std::min(FieldAlign, MaxFieldAlignment);
// Round up the current record size to the field's alignment boundary.
FieldOffset = (FieldOffset + (FieldAlign-1)) & ~(FieldAlign-1);
using namespace CodeGen;
void CGRecordLayoutBuilder::Layout(const RecordDecl *D) {
+ Alignment = Types.getContext().getASTRecordLayout(D).getAlignment() / 8;
+
if (D->isUnion()) {
LayoutUnion(D);
return;
}
Packed = D->hasAttr<PackedAttr>();
-
+
if (LayoutFields(D))
return;
const llvm::Type *Ty = Types.ConvertTypeForMemRecursive(D->getType());
unsigned TypeAlignment = getTypeAlignment(Ty);
+ // If the type alignment is larger then the struct alignment, we must use
+ // a packed struct.
+ if (TypeAlignment > Alignment) {
+ assert(!Packed && "Alignment is wrong even with packed struct!");
+ return false;
+ }
+
+ if (const RecordType *RT = D->getType()->getAs<RecordType>()) {
+ const RecordDecl *RD = cast<RecordDecl>(RT->getDecl());
+ if (const PragmaPackAttr *PPA = RD->getAttr<PragmaPackAttr>()) {
+ if (PPA->getAlignment() != TypeAlignment * 8 && !Packed)
+ return false;
+ }
+ }
+
// Round up the field offset to the alignment of the field type.
uint64_t AlignedNextFieldOffsetInBytes =
llvm::RoundUpToAlignment(NextFieldOffsetInBytes, TypeAlignment);
bool CGRecordLayoutBuilder::LayoutFields(const RecordDecl *D) {
assert(!D->isUnion() && "Can't call LayoutFields on a union!");
+ assert(Alignment && "Did not set alignment!");
const ASTRecordLayout &Layout = Types.getContext().getASTRecordLayout(D);