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:
parent
caab74e02d
commit
44ba7899c4
|
@ -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,
|
||||||
|
|
Loading…
Reference in New Issue