unsigned IsMsStruct : 1;
- /// UnfilledBitsInLastByte - If the last field laid out was a bitfield,
- /// this contains the number of bits in the last byte that can be used for
- /// an adjacent bitfield if necessary.
- unsigned char UnfilledBitsInLastByte;
+ /// UnfilledBitsInLastUnit - If the last field laid out was a bitfield,
+ /// this contains the number of bits in the last unit that can be used for
+ /// an adjacent bitfield if necessary. The unit in question is usually
+ /// a byte, but larger units are used if IsMsStruct.
+ unsigned char UnfilledBitsInLastUnit;
+ /// LastBitfieldTypeSize - If IsMsStruct, represents the size of the type
+ /// of the previous field if it was a bitfield.
+ unsigned char LastBitfieldTypeSize;
/// MaxFieldAlignment - The maximum allowed field alignment. This is set by
/// #pragma pack.
Alignment(CharUnits::One()), UnpackedAlignment(CharUnits::One()),
ExternalLayout(false), InferAlignment(false),
Packed(false), IsUnion(false), IsMac68kAlign(false), IsMsStruct(false),
- UnfilledBitsInLastByte(0), MaxFieldAlignment(CharUnits::Zero()),
+ UnfilledBitsInLastUnit(0), LastBitfieldTypeSize(0),
+ MaxFieldAlignment(CharUnits::Zero()),
DataSize(0), NonVirtualSize(CharUnits::Zero()),
NonVirtualAlignment(CharUnits::One()),
ZeroLengthBitfield(0), PrimaryBase(0),
void RecordLayoutBuilder::LayoutFields(const RecordDecl *D) {
// Layout each field, for now, just sequentially, respecting alignment. In
// the future, this will need to be tweakable by targets.
- const FieldDecl *LastFD = 0;
ZeroLengthBitfield = 0;
- unsigned RemainingInAlignment = 0;
for (RecordDecl::field_iterator Field = D->field_begin(),
FieldEnd = D->field_end(); Field != FieldEnd; ++Field) {
- if (IsMsStruct) {
- FieldDecl *FD = *Field;
- if (Context.ZeroBitfieldFollowsBitfield(FD, LastFD))
- ZeroLengthBitfield = FD;
- // Zero-length bitfields following non-bitfield members are
- // ignored:
- else if (Context.ZeroBitfieldFollowsNonBitfield(FD, LastFD))
- continue;
- // FIXME. streamline these conditions into a simple one.
- else if (Context.BitfieldFollowsBitfield(FD, LastFD) ||
- Context.BitfieldFollowsNonBitfield(FD, LastFD) ||
- Context.NonBitfieldFollowsBitfield(FD, LastFD)) {
- // 1) Adjacent bit fields are packed into the same 1-, 2-, or
- // 4-byte allocation unit if the integral types are the same
- // size and if the next bit field fits into the current
- // allocation unit without crossing the boundary imposed by the
- // common alignment requirements of the bit fields.
- // 2) Establish a new alignment for a bitfield following
- // a non-bitfield if size of their types differ.
- // 3) Establish a new alignment for a non-bitfield following
- // a bitfield if size of their types differ.
- std::pair<uint64_t, unsigned> FieldInfo =
- Context.getTypeInfo(FD->getType());
- uint64_t TypeSize = FieldInfo.first;
- unsigned FieldAlign = FieldInfo.second;
- // This check is needed for 'long long' in -m32 mode.
- if (TypeSize > FieldAlign &&
- (Context.hasSameType(FD->getType(),
- Context.UnsignedLongLongTy)
- ||Context.hasSameType(FD->getType(),
- Context.LongLongTy)))
- FieldAlign = TypeSize;
- FieldInfo = Context.getTypeInfo(LastFD->getType());
- uint64_t TypeSizeLastFD = FieldInfo.first;
- unsigned FieldAlignLastFD = FieldInfo.second;
- // This check is needed for 'long long' in -m32 mode.
- if (TypeSizeLastFD > FieldAlignLastFD &&
- (Context.hasSameType(LastFD->getType(),
- Context.UnsignedLongLongTy)
- || Context.hasSameType(LastFD->getType(),
- Context.LongLongTy)))
- FieldAlignLastFD = TypeSizeLastFD;
-
- if (TypeSizeLastFD != TypeSize) {
- if (RemainingInAlignment &&
- LastFD && LastFD->isBitField() &&
- LastFD->getBitWidthValue(Context)) {
- // If previous field was a bitfield with some remaining unfilled
- // bits, pad the field so current field starts on its type boundary.
- uint64_t FieldOffset =
- getDataSizeInBits() - UnfilledBitsInLastByte;
- uint64_t NewSizeInBits = RemainingInAlignment + FieldOffset;
- setDataSize(llvm::RoundUpToAlignment(NewSizeInBits,
- Context.getTargetInfo().getCharAlign()));
- setSize(std::max(getSizeInBits(), getDataSizeInBits()));
- RemainingInAlignment = 0;
- }
-
- uint64_t UnpaddedFieldOffset =
- getDataSizeInBits() - UnfilledBitsInLastByte;
- FieldAlign = std::max(FieldAlign, FieldAlignLastFD);
-
- // The maximum field alignment overrides the aligned attribute.
- if (!MaxFieldAlignment.isZero()) {
- unsigned MaxFieldAlignmentInBits =
- Context.toBits(MaxFieldAlignment);
- FieldAlign = std::min(FieldAlign, MaxFieldAlignmentInBits);
- }
-
- uint64_t NewSizeInBits =
- llvm::RoundUpToAlignment(UnpaddedFieldOffset, FieldAlign);
- setDataSize(llvm::RoundUpToAlignment(NewSizeInBits,
- Context.getTargetInfo().getCharAlign()));
- UnfilledBitsInLastByte = getDataSizeInBits() - NewSizeInBits;
- setSize(std::max(getSizeInBits(), getDataSizeInBits()));
- }
- if (FD->isBitField()) {
- uint64_t FieldSize = FD->getBitWidthValue(Context);
- assert (FieldSize > 0 && "LayoutFields - ms_struct layout");
- if (RemainingInAlignment < FieldSize)
- RemainingInAlignment = TypeSize - FieldSize;
- else
- RemainingInAlignment -= FieldSize;
- }
- }
- else if (FD->isBitField()) {
- uint64_t FieldSize = FD->getBitWidthValue(Context);
- std::pair<uint64_t, unsigned> FieldInfo =
- Context.getTypeInfo(FD->getType());
- uint64_t TypeSize = FieldInfo.first;
- RemainingInAlignment = TypeSize - FieldSize;
- }
- LastFD = FD;
- }
- else if (!Context.getTargetInfo().useBitFieldTypeAlignment() &&
- Context.getTargetInfo().useZeroLengthBitfieldAlignment()) {
+ if (!Context.getTargetInfo().useBitFieldTypeAlignment() &&
+ Context.getTargetInfo().useZeroLengthBitfieldAlignment()) {
if (Field->isBitField() && Field->getBitWidthValue(Context) == 0)
ZeroLengthBitfield = *Field;
}
LayoutField(*Field);
}
- if (IsMsStruct && RemainingInAlignment &&
- LastFD && LastFD->isBitField() && LastFD->getBitWidthValue(Context)) {
- // If we ended a bitfield before the full length of the type then
- // pad the struct out to the full length of the last type.
- uint64_t FieldOffset =
- getDataSizeInBits() - UnfilledBitsInLastByte;
- uint64_t NewSizeInBits = RemainingInAlignment + FieldOffset;
- setDataSize(llvm::RoundUpToAlignment(NewSizeInBits,
- Context.getTargetInfo().getCharAlign()));
- setSize(std::max(getSizeInBits(), getDataSizeInBits()));
- }
}
void RecordLayoutBuilder::LayoutWideBitField(uint64_t FieldSize,
CharUnits TypeAlign = Context.getTypeAlignInChars(Type);
// We're not going to use any of the unfilled bits in the last byte.
- UnfilledBitsInLastByte = 0;
+ UnfilledBitsInLastUnit = 0;
+ LastBitfieldTypeSize = 0;
uint64_t FieldOffset;
- uint64_t UnpaddedFieldOffset = getDataSizeInBits() - UnfilledBitsInLastByte;
+ uint64_t UnpaddedFieldOffset = getDataSizeInBits() - UnfilledBitsInLastUnit;
if (IsUnion) {
setDataSize(std::max(getDataSizeInBits(), FieldSize));
setDataSize(llvm::RoundUpToAlignment(NewSizeInBits,
Context.getTargetInfo().getCharAlign()));
- UnfilledBitsInLastByte = getDataSizeInBits() - NewSizeInBits;
+ UnfilledBitsInLastUnit = getDataSizeInBits() - NewSizeInBits;
}
// Place this field at the current location.
void RecordLayoutBuilder::LayoutBitField(const FieldDecl *D) {
bool FieldPacked = Packed || D->hasAttr<PackedAttr>();
- uint64_t UnpaddedFieldOffset = getDataSizeInBits() - UnfilledBitsInLastByte;
- uint64_t FieldOffset = IsUnion ? 0 : UnpaddedFieldOffset;
uint64_t FieldSize = D->getBitWidthValue(Context);
-
std::pair<uint64_t, unsigned> FieldInfo = Context.getTypeInfo(D->getType());
uint64_t TypeSize = FieldInfo.first;
unsigned FieldAlign = FieldInfo.second;
-
- // This check is needed for 'long long' in -m32 mode.
- if (IsMsStruct && (TypeSize > FieldAlign) &&
- (Context.hasSameType(D->getType(),
- Context.UnsignedLongLongTy)
- || Context.hasSameType(D->getType(), Context.LongLongTy)))
+
+ if (IsMsStruct) {
+ // The field alignment for integer types in ms_struct structs is
+ // always the size.
FieldAlign = TypeSize;
+ // Ignore zero-length bitfields after non-bitfields in ms_struct structs.
+ if (!FieldSize && !LastBitfieldTypeSize)
+ FieldAlign = 1;
+ // If a bitfield is followed by a bitfield of a different size, don't
+ // pack the bits together in ms_struct structs.
+ if (LastBitfieldTypeSize != TypeSize) {
+ UnfilledBitsInLastUnit = 0;
+ LastBitfieldTypeSize = 0;
+ }
+ }
+
+ uint64_t UnpaddedFieldOffset = getDataSizeInBits() - UnfilledBitsInLastUnit;
+ uint64_t FieldOffset = IsUnion ? 0 : UnpaddedFieldOffset;
if (ZeroLengthBitfield) {
- std::pair<uint64_t, unsigned> FieldInfo;
- unsigned ZeroLengthBitfieldAlignment;
- if (IsMsStruct) {
- // If a zero-length bitfield is inserted after a bitfield,
- // and the alignment of the zero-length bitfield is
- // greater than the member that follows it, `bar', `bar'
- // will be aligned as the type of the zero-length bitfield.
- if (ZeroLengthBitfield != D) {
- FieldInfo = Context.getTypeInfo(ZeroLengthBitfield->getType());
- ZeroLengthBitfieldAlignment = FieldInfo.second;
- // Ignore alignment of subsequent zero-length bitfields.
- if ((ZeroLengthBitfieldAlignment > FieldAlign) || (FieldSize == 0))
- FieldAlign = ZeroLengthBitfieldAlignment;
- if (FieldSize)
- ZeroLengthBitfield = 0;
- }
- } else {
- // The alignment of a zero-length bitfield affects the alignment
- // of the next member. The alignment is the max of the zero
- // length bitfield's alignment and a target specific fixed value.
- unsigned ZeroLengthBitfieldBoundary =
- Context.getTargetInfo().getZeroLengthBitfieldBoundary();
- if (ZeroLengthBitfieldBoundary > FieldAlign)
- FieldAlign = ZeroLengthBitfieldBoundary;
- }
+ // The alignment of a zero-length bitfield affects the alignment
+ // of the next member. The alignment is the max of the zero
+ // length bitfield's alignment and a target specific fixed value.
+ unsigned ZeroLengthBitfieldBoundary =
+ Context.getTargetInfo().getZeroLengthBitfieldBoundary();
+ if (ZeroLengthBitfieldBoundary > FieldAlign)
+ FieldAlign = ZeroLengthBitfieldBoundary;
}
if (FieldSize > TypeSize) {
UnpackedFieldAlign = std::min(UnpackedFieldAlign, MaxFieldAlignmentInBits);
}
+ // ms_struct bitfields always have to start at a round alignment.
+ if (IsMsStruct && !LastBitfieldTypeSize) {
+ FieldOffset = llvm::RoundUpToAlignment(FieldOffset, FieldAlign);
+ UnpackedFieldOffset = llvm::RoundUpToAlignment(UnpackedFieldOffset,
+ UnpackedFieldAlign);
+ }
+
// Check if we need to add padding to give the field the correct alignment.
if (FieldSize == 0 ||
(MaxFieldAlignment.isZero() &&
// Padding members don't affect overall alignment, unless zero length bitfield
// alignment is enabled.
- if (!D->getIdentifier() && !Context.getTargetInfo().useZeroLengthBitfieldAlignment())
+ if (!D->getIdentifier() &&
+ !Context.getTargetInfo().useZeroLengthBitfieldAlignment() &&
+ !IsMsStruct)
FieldAlign = UnpackedFieldAlign = 1;
- if (!IsMsStruct)
- ZeroLengthBitfield = 0;
+ ZeroLengthBitfield = 0;
if (ExternalLayout)
FieldOffset = updateExternalFieldOffset(D, FieldOffset);
// FIXME: I think FieldSize should be TypeSize here.
setDataSize(std::max(getDataSizeInBits(), FieldSize));
} else {
- uint64_t NewSizeInBits = FieldOffset + FieldSize;
-
- setDataSize(llvm::RoundUpToAlignment(NewSizeInBits,
- Context.getTargetInfo().getCharAlign()));
- UnfilledBitsInLastByte = getDataSizeInBits() - NewSizeInBits;
+ if (IsMsStruct && FieldSize) {
+ // Under ms_struct, a bitfield always takes up space equal to the size
+ // of the type. We can't just change the alignment computation on the
+ // other codepath because of the way this interacts with #pragma pack:
+ // in a packed struct, we need to allocate misaligned space in the
+ // struct to hold the bitfield.
+ if (!UnfilledBitsInLastUnit) {
+ setDataSize(FieldOffset + TypeSize);
+ UnfilledBitsInLastUnit = TypeSize - FieldSize;
+ } else if (UnfilledBitsInLastUnit < FieldSize) {
+ setDataSize(getDataSizeInBits() + TypeSize);
+ UnfilledBitsInLastUnit = TypeSize - FieldSize;
+ } else {
+ UnfilledBitsInLastUnit -= FieldSize;
+ }
+ LastBitfieldTypeSize = TypeSize;
+ } else {
+ uint64_t NewSizeInBits = FieldOffset + FieldSize;
+ uint64_t BitfieldAlignment = Context.getTargetInfo().getCharAlign();
+ setDataSize(llvm::RoundUpToAlignment(NewSizeInBits, BitfieldAlignment));
+ UnfilledBitsInLastUnit = getDataSizeInBits() - NewSizeInBits;
+ LastBitfieldTypeSize = 0;
+ }
}
// Update the size.
return;
}
- uint64_t UnpaddedFieldOffset = getDataSizeInBits() - UnfilledBitsInLastByte;
+ uint64_t UnpaddedFieldOffset = getDataSizeInBits() - UnfilledBitsInLastUnit;
// Reset the unfilled bits.
- UnfilledBitsInLastByte = 0;
+ UnfilledBitsInLastUnit = 0;
+ LastBitfieldTypeSize = 0;
bool FieldPacked = Packed || D->hasAttr<PackedAttr>();
CharUnits FieldOffset =
// Finally, round the size of the record up to the alignment of the
// record itself.
- uint64_t UnpaddedSize = getSizeInBits() - UnfilledBitsInLastByte;
+ uint64_t UnpaddedSize = getSizeInBits() - UnfilledBitsInLastUnit;
uint64_t UnpackedSizeInBits =
llvm::RoundUpToAlignment(getSizeInBits(),
Context.toBits(UnpackedAlignment));