Allow the external AST source to provide a layout without specifying

the alignment (because it's not encoded in DWARF). In this case, make
an educated guess at the alignment.

llvm-svn: 149161
This commit is contained in:
Douglas Gregor 2012-01-28 00:53:29 +00:00
parent caab74e02d
commit 44ba7899c4
1 changed files with 76 additions and 42 deletions

View File

@ -561,6 +561,10 @@ protected:
/// \brief Whether the external AST source has provided a layout for this /// \brief Whether the external AST source has provided a layout for this
/// record. /// record.
unsigned ExternalLayout : 1; unsigned ExternalLayout : 1;
/// \brief Whether we need to infer alignment, even when we have an
/// externally-provided layout.
unsigned InferAlignment : 1;
/// Packed - Whether the record is packed or not. /// Packed - Whether the record is packed or not.
unsigned Packed : 1; unsigned Packed : 1;
@ -641,8 +645,8 @@ protected:
EmptySubobjectMap *EmptySubobjects) EmptySubobjectMap *EmptySubobjects)
: Context(Context), EmptySubobjects(EmptySubobjects), Size(0), : Context(Context), EmptySubobjects(EmptySubobjects), Size(0),
Alignment(CharUnits::One()), UnpackedAlignment(CharUnits::One()), Alignment(CharUnits::One()), UnpackedAlignment(CharUnits::One()),
ExternalLayout(false), Packed(false), IsUnion(false), ExternalLayout(false), InferAlignment(false),
IsMac68kAlign(false), IsMsStruct(false), Packed(false), IsUnion(false), IsMac68kAlign(false), IsMsStruct(false),
UnfilledBitsInLastByte(0), MaxFieldAlignment(CharUnits::Zero()), UnfilledBitsInLastByte(0), MaxFieldAlignment(CharUnits::Zero()),
DataSize(0), NonVirtualSize(CharUnits::Zero()), DataSize(0), NonVirtualSize(CharUnits::Zero()),
NonVirtualAlignment(CharUnits::One()), NonVirtualAlignment(CharUnits::One()),
@ -747,6 +751,14 @@ protected:
UpdateAlignment(NewAlignment, NewAlignment); UpdateAlignment(NewAlignment, NewAlignment);
} }
/// \brief Retrieve the externally-supplied field offset for the given
/// field.
///
/// \param Field The field whose offset is being queried.
/// \param ComputedOffset The offset that we've computed for this field.
uint64_t updateExternalFieldOffset(const FieldDecl *Field,
uint64_t ComputedOffset);
void CheckFieldPadding(uint64_t Offset, uint64_t UnpaddedOffset, void CheckFieldPadding(uint64_t Offset, uint64_t UnpaddedOffset,
uint64_t UnpackedOffset, unsigned UnpackedAlign, uint64_t UnpackedOffset, unsigned UnpackedAlign,
bool isPacked, const FieldDecl *D); bool isPacked, const FieldDecl *D);
@ -1416,8 +1428,13 @@ void RecordLayoutBuilder::InitializeLayout(const Decl *D) {
// Update based on external alignment. // Update based on external alignment.
if (ExternalLayout) { if (ExternalLayout) {
Alignment = Context.toCharUnitsFromBits(ExternalAlign); if (ExternalAlign > 0) {
UnpackedAlignment = Alignment; Alignment = Context.toCharUnitsFromBits(ExternalAlign);
UnpackedAlignment = Alignment;
} else {
// The external source didn't have alignment information; infer it.
InferAlignment = true;
}
} }
} }
} }
@ -1712,12 +1729,6 @@ void RecordLayoutBuilder::LayoutBitField(const FieldDecl *D) {
uint64_t TypeSize = FieldInfo.first; uint64_t TypeSize = FieldInfo.first;
unsigned FieldAlign = FieldInfo.second; unsigned FieldAlign = FieldInfo.second;
if (ExternalLayout) {
assert(ExternalFieldOffsets.find(D) != ExternalFieldOffsets.end() &&
"Field does not have an external offset");
FieldOffset = ExternalFieldOffsets[D];
}
// This check is needed for 'long long' in -m32 mode. // This check is needed for 'long long' in -m32 mode.
if (IsMsStruct && (TypeSize > FieldAlign) && if (IsMsStruct && (TypeSize > FieldAlign) &&
(Context.hasSameType(D->getType(), (Context.hasSameType(D->getType(),
@ -1778,19 +1789,17 @@ void RecordLayoutBuilder::LayoutBitField(const FieldDecl *D) {
UnpackedFieldAlign = std::min(UnpackedFieldAlign, MaxFieldAlignmentInBits); UnpackedFieldAlign = std::min(UnpackedFieldAlign, MaxFieldAlignmentInBits);
} }
if (!ExternalLayout) { // Check if we need to add padding to give the field the correct alignment.
// Check if we need to add padding to give the field the correct alignment. if (FieldSize == 0 ||
if (FieldSize == 0 || (MaxFieldAlignment.isZero() &&
(MaxFieldAlignment.isZero() && (FieldOffset & (FieldAlign-1)) + FieldSize > TypeSize))
(FieldOffset & (FieldAlign-1)) + FieldSize > TypeSize)) FieldOffset = llvm::RoundUpToAlignment(FieldOffset, FieldAlign);
FieldOffset = llvm::RoundUpToAlignment(FieldOffset, FieldAlign);
if (FieldSize == 0 || if (FieldSize == 0 ||
(MaxFieldAlignment.isZero() && (MaxFieldAlignment.isZero() &&
(UnpackedFieldOffset & (UnpackedFieldAlign-1)) + FieldSize > TypeSize)) (UnpackedFieldOffset & (UnpackedFieldAlign-1)) + FieldSize > TypeSize))
UnpackedFieldOffset = llvm::RoundUpToAlignment(UnpackedFieldOffset, UnpackedFieldOffset = llvm::RoundUpToAlignment(UnpackedFieldOffset,
UnpackedFieldAlign); UnpackedFieldAlign);
}
// Padding members don't affect overall alignment, unless zero length bitfield // Padding members don't affect overall alignment, unless zero length bitfield
// alignment is enabled. // alignment is enabled.
@ -1800,6 +1809,9 @@ void RecordLayoutBuilder::LayoutBitField(const FieldDecl *D) {
if (!IsMsStruct) if (!IsMsStruct)
ZeroLengthBitfield = 0; ZeroLengthBitfield = 0;
if (ExternalLayout)
FieldOffset = updateExternalFieldOffset(D, FieldOffset);
// Place this field at the current location. // Place this field at the current location.
FieldOffsets.push_back(FieldOffset); FieldOffsets.push_back(FieldOffset);
@ -1844,13 +1856,6 @@ void RecordLayoutBuilder::LayoutField(const FieldDecl *D) {
CharUnits FieldSize; CharUnits FieldSize;
CharUnits FieldAlign; CharUnits FieldAlign;
if (ExternalLayout) {
assert(ExternalFieldOffsets.find(D) != ExternalFieldOffsets.end() &&
"Field does not have an external offset");
FieldOffset = Context.toCharUnitsFromBits(ExternalFieldOffsets[D]);
}
if (D->getType()->isIncompleteArrayType()) { if (D->getType()->isIncompleteArrayType()) {
// This is a flexible array member; we can't directly // This is a flexible array member; we can't directly
// query getTypeInfo about these, so we figure it out here. // query getTypeInfo about these, so we figure it out here.
@ -1928,12 +1933,22 @@ void RecordLayoutBuilder::LayoutField(const FieldDecl *D) {
UnpackedFieldAlign = std::min(UnpackedFieldAlign, MaxFieldAlignment); UnpackedFieldAlign = std::min(UnpackedFieldAlign, MaxFieldAlignment);
} }
if (!ExternalLayout) { // Round up the current record size to the field's alignment boundary.
// Round up the current record size to the field's alignment boundary. FieldOffset = FieldOffset.RoundUpToAlignment(FieldAlign);
FieldOffset = FieldOffset.RoundUpToAlignment(FieldAlign); UnpackedFieldOffset =
UnpackedFieldOffset = UnpackedFieldOffset.RoundUpToAlignment(UnpackedFieldAlign);
UnpackedFieldOffset.RoundUpToAlignment(UnpackedFieldAlign);
if (ExternalLayout) {
FieldOffset = Context.toCharUnitsFromBits(
updateExternalFieldOffset(D, Context.toBits(FieldOffset)));
if (!IsUnion && EmptySubobjects) {
// Record the fact that we're placing a field at this offset.
bool Allowed = EmptySubobjects->CanPlaceFieldAtOffset(D, FieldOffset);
(void)Allowed;
assert(Allowed && "Externally-placed field cannot be placed here");
}
} else {
if (!IsUnion && EmptySubobjects) { if (!IsUnion && EmptySubobjects) {
// Check if we can place the field at this offset. // Check if we can place the field at this offset.
while (!EmptySubobjects->CanPlaceFieldAtOffset(D, FieldOffset)) { while (!EmptySubobjects->CanPlaceFieldAtOffset(D, FieldOffset)) {
@ -1941,11 +1956,6 @@ void RecordLayoutBuilder::LayoutField(const FieldDecl *D) {
FieldOffset += FieldAlign; FieldOffset += FieldAlign;
} }
} }
} else if (!IsUnion && EmptySubobjects) {
// Record the fact that we're placing a field at this offset.
bool Allowed = EmptySubobjects->CanPlaceFieldAtOffset(D, FieldOffset);
(void)Allowed;
assert(Allowed && "Externally-placed field cannot be placed here");
} }
// Place this field at the current location. // Place this field at the current location.
@ -1971,6 +1981,11 @@ void RecordLayoutBuilder::LayoutField(const FieldDecl *D) {
} }
void RecordLayoutBuilder::FinishLayout(const NamedDecl *D) { void RecordLayoutBuilder::FinishLayout(const NamedDecl *D) {
if (ExternalLayout) {
setSize(ExternalSize);
return;
}
// In C++, records cannot be of size 0. // In C++, records cannot be of size 0.
if (Context.getLangOptions().CPlusPlus && getSizeInBits() == 0) { if (Context.getLangOptions().CPlusPlus && getSizeInBits() == 0) {
if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(D)) { if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(D)) {
@ -2027,8 +2042,8 @@ void RecordLayoutBuilder::FinishLayout(const NamedDecl *D) {
void RecordLayoutBuilder::UpdateAlignment(CharUnits NewAlignment, void RecordLayoutBuilder::UpdateAlignment(CharUnits NewAlignment,
CharUnits UnpackedNewAlignment) { CharUnits UnpackedNewAlignment) {
// The alignment is not modified when using 'mac68k' alignment or when // The alignment is not modified when using 'mac68k' alignment or when
// we have an externally-supplied layout. // we have an externally-supplied layout that also provides overall alignment.
if (IsMac68kAlign || ExternalLayout) if (IsMac68kAlign || (ExternalLayout && !InferAlignment))
return; return;
if (NewAlignment > Alignment) { if (NewAlignment > Alignment) {
@ -2044,6 +2059,25 @@ void RecordLayoutBuilder::UpdateAlignment(CharUnits NewAlignment,
} }
} }
uint64_t
RecordLayoutBuilder::updateExternalFieldOffset(const FieldDecl *Field,
uint64_t ComputedOffset) {
assert(ExternalFieldOffsets.find(Field) != ExternalFieldOffsets.end() &&
"Field does not have an external offset");
uint64_t ExternalFieldOffset = ExternalFieldOffsets[Field];
if (InferAlignment && ExternalFieldOffset < ComputedOffset) {
// The externally-supplied field offset is before the field offset we
// computed. Assume that the structure is packed.
Alignment = CharUnits::fromQuantity(1);
InferAlignment = false;
}
// Use the externally-supplied field offset.
return ExternalFieldOffset;
}
void RecordLayoutBuilder::CheckFieldPadding(uint64_t Offset, void RecordLayoutBuilder::CheckFieldPadding(uint64_t Offset,
uint64_t UnpaddedOffset, uint64_t UnpaddedOffset,
uint64_t UnpackedOffset, uint64_t UnpackedOffset,