summaryrefslogtreecommitdiffstats
path: root/clang/lib/AST/RecordLayoutBuilder.cpp
diff options
context:
space:
mode:
authorWarren Hunt <whunt@google.com>2013-12-06 00:01:17 +0000
committerWarren Hunt <whunt@google.com>2013-12-06 00:01:17 +0000
commit7b252d24adf8a76376fef344b3f9e37a1363a669 (patch)
treea252ad289158272f6d3ab416ad94be34e6f9565e /clang/lib/AST/RecordLayoutBuilder.cpp
parente6ac50ad71b7dd63e5b746fce9eb3a1e76debb01 (diff)
downloadbcm5719-llvm-7b252d24adf8a76376fef344b3f9e37a1363a669.tar.gz
bcm5719-llvm-7b252d24adf8a76376fef344b3f9e37a1363a669.zip
Support MS-ABI's concept of "Required Alignment" imposed by
__declspec(align()) This patch implements required alignment in a way that makes __declspec(align()) and #pragma pack play correctly together. In the MS-ABI, __declspec(align()) is a hard rule and cannot be overridden by #pragma pack. This cases each record to have two interesting alignments "preferred alignment" (which matches Itanium's concept of alignment) and "required alignment" which is an alignment that must never be violated, even in the case of #pragma pack. This patch introduces the concept of Required Alignment to the record builder and tracks/uses it appropriately. Test cases are included. Differential Revision: http://llvm-reviews.chandlerc.com/D2283 llvm-svn: 196549
Diffstat (limited to 'clang/lib/AST/RecordLayoutBuilder.cpp')
-rw-r--r--clang/lib/AST/RecordLayoutBuilder.cpp77
1 files changed, 53 insertions, 24 deletions
diff --git a/clang/lib/AST/RecordLayoutBuilder.cpp b/clang/lib/AST/RecordLayoutBuilder.cpp
index f0142525b1a..a1f6c41ef86 100644
--- a/clang/lib/AST/RecordLayoutBuilder.cpp
+++ b/clang/lib/AST/RecordLayoutBuilder.cpp
@@ -2064,6 +2064,7 @@ public:
void updateAlignment(CharUnits NewAlignment) {
Alignment = std::max(Alignment, NewAlignment);
}
+ CharUnits getBaseAlignment(const ASTRecordLayout& Layout);
/// \brief Gets the size and alignment taking attributes into account.
std::pair<CharUnits, CharUnits> getAdjustedFieldInfo(const FieldDecl *FD);
/// \brief Places a field at offset 0.
@@ -2089,9 +2090,9 @@ public:
SmallVector<uint64_t, 16> FieldOffsets;
/// \brief The maximum allowed field alignment. This is set by #pragma pack.
CharUnits MaxFieldAlignment;
- /// \brief Alignment does not occur for virtual bases unless something
- /// forces it to by explicitly using __declspec(align())
- bool AlignAfterVBases : 1;
+ /// \brief The alignment that this record must obey. This is imposed by
+ /// __declspec(align()) on the record itself or one of its fields or bases.
+ CharUnits RequiredAlignment;
bool IsUnion : 1;
/// \brief True if the last field laid out was a bitfield and was not 0
/// width.
@@ -2148,6 +2149,16 @@ public:
};
} // namespace
+CharUnits
+MicrosoftRecordLayoutBuilder::getBaseAlignment(const ASTRecordLayout& Layout) {
+ CharUnits BaseAlignment = Layout.getAlignment();
+ if (!MaxFieldAlignment.isZero())
+ BaseAlignment = std::min(BaseAlignment,
+ std::max(MaxFieldAlignment,
+ Layout.getRequiredAlignment()));
+ return BaseAlignment;
+}
+
std::pair<CharUnits, CharUnits>
MicrosoftRecordLayoutBuilder::getAdjustedFieldInfo(const FieldDecl *FD) {
std::pair<CharUnits, CharUnits> FieldInfo =
@@ -2174,9 +2185,18 @@ MicrosoftRecordLayoutBuilder::getAdjustedFieldInfo(const FieldDecl *FD) {
// Respect alignment attributes.
if (unsigned fieldAlign = FD->getMaxAlignment()) {
CharUnits FieldAlign = Context.toCharUnitsFromBits(fieldAlign);
- AlignAfterVBases = true;
+ RequiredAlignment = std::max(RequiredAlignment, FieldAlign);
FieldInfo.second = std::max(FieldInfo.second, FieldAlign);
}
+ // Respect attributes applied inside field base types.
+ if (const RecordType *RT =
+ FD->getType()->getBaseElementTypeUnsafe()->getAs<RecordType>()) {
+ const ASTRecordLayout &Layout = Context.getASTRecordLayout(RT->getDecl());
+ RequiredAlignment = std::max(RequiredAlignment,
+ Layout.getRequiredAlignment());
+ FieldInfo.second = std::max(FieldInfo.second,
+ Layout.getRequiredAlignment());
+ }
return FieldInfo;
}
@@ -2186,7 +2206,10 @@ void MicrosoftRecordLayoutBuilder::initializeLayout(const RecordDecl *RD) {
Size = CharUnits::Zero();
Alignment = CharUnits::One();
- AlignAfterVBases = false;
+ // In 64-bit mode we always perform an alignment step after laying out vbases.
+ // In 32-bit mode we do not. The check to see if we need to perform alignment
+ // checks the RequiredAlignment field and performs alignment if it isn't 0.
+ RequiredAlignment = Is64BitMode ? CharUnits::One() : CharUnits::Zero();
// Compute the maximum field alignment.
MaxFieldAlignment = CharUnits::Zero();
@@ -2236,7 +2259,6 @@ MicrosoftRecordLayoutBuilder::initializeCXXLayout(const CXXRecordDecl *RD) {
SharedVBPtrBase = 0;
PrimaryBase = 0;
VirtualAlignment = CharUnits::One();
- AlignAfterVBases = Is64BitMode;
// If the record has a dynamic base class, attempt to choose a primary base
// class. It is the first (in direct base class order) non-virtual dynamic
@@ -2247,12 +2269,12 @@ MicrosoftRecordLayoutBuilder::initializeCXXLayout(const CXXRecordDecl *RD) {
const CXXRecordDecl *BaseDecl =
cast<CXXRecordDecl>(i->getType()->getAs<RecordType>()->getDecl());
const ASTRecordLayout &Layout = Context.getASTRecordLayout(BaseDecl);
- // Handle forced alignment.
- if (Layout.getAlignAfterVBases())
- AlignAfterVBases = true;
+ // Handle required alignment.
+ RequiredAlignment = std::max(RequiredAlignment,
+ Layout.getRequiredAlignment());
// Handle virtual bases.
if (i->isVirtual()) {
- VirtualAlignment = std::max(VirtualAlignment, Layout.getAlignment());
+ VirtualAlignment = std::max(VirtualAlignment, getBaseAlignment(Layout));
HasVBPtr = true;
continue;
}
@@ -2266,7 +2288,7 @@ MicrosoftRecordLayoutBuilder::initializeCXXLayout(const CXXRecordDecl *RD) {
SharedVBPtrBase = BaseDecl;
HasVBPtr = true;
}
- updateAlignment(Layout.getAlignment());
+ updateAlignment(getBaseAlignment(Layout));
}
// Use LayoutFields to compute the alignment of the fields. The layout
@@ -2335,7 +2357,7 @@ MicrosoftRecordLayoutBuilder::layoutNonVirtualBase(const CXXRecordDecl *RD) {
if (LazyEmptyBase) {
const ASTRecordLayout &LazyLayout =
Context.getASTRecordLayout(LazyEmptyBase);
- Size = Size.RoundUpToAlignment(LazyLayout.getAlignment());
+ Size = Size.RoundUpToAlignment(getBaseAlignment(LazyLayout));
// If the last non-virtual base has a vbptr we add a byte of padding for no
// obvious reason.
if (LastNonVirtualBaseHasVBPtr)
@@ -2360,7 +2382,7 @@ MicrosoftRecordLayoutBuilder::layoutNonVirtualBase(const CXXRecordDecl *RD) {
}
// Insert the base here.
- CharUnits BaseOffset = Size.RoundUpToAlignment(Layout->getAlignment());
+ CharUnits BaseOffset = Size.RoundUpToAlignment(getBaseAlignment(*Layout));
Bases.insert(std::make_pair(RD, BaseOffset));
Size = BaseOffset + Layout->getDataSize();
// Note: we don't update alignment here because it was accounted
@@ -2536,7 +2558,7 @@ void MicrosoftRecordLayoutBuilder::layoutVirtualBase(const CXXRecordDecl *RD,
if (LazyEmptyBase) {
const ASTRecordLayout &LazyLayout =
Context.getASTRecordLayout(LazyEmptyBase);
- Size = Size.RoundUpToAlignment(LazyLayout.getAlignment());
+ Size = Size.RoundUpToAlignment(getBaseAlignment(LazyLayout));
VBases.insert(
std::make_pair(LazyEmptyBase, ASTRecordLayout::VBaseInfo(Size, false)));
// Empty bases only consume space when followed by another empty base.
@@ -2560,7 +2582,7 @@ void MicrosoftRecordLayoutBuilder::layoutVirtualBase(const CXXRecordDecl *RD,
}
CharUnits BaseNVSize = Layout.getNonVirtualSize();
- CharUnits BaseAlign = Layout.getAlignment();
+ CharUnits BaseAlign = getBaseAlignment(Layout);
// vtordisps are always 4 bytes (even in 64-bit mode)
if (HasVtordisp)
@@ -2580,7 +2602,7 @@ void MicrosoftRecordLayoutBuilder::finalizeCXXLayout(const CXXRecordDecl *RD) {
// Flush the lazy virtual base.
layoutVirtualBase(0, false);
- if (RD->vbases_begin() == RD->vbases_end() || AlignAfterVBases)
+ if (RD->vbases_begin() == RD->vbases_end() || !RequiredAlignment.isZero())
Size = Size.RoundUpToAlignment(Alignment);
if (Size.isZero())
@@ -2588,9 +2610,10 @@ void MicrosoftRecordLayoutBuilder::finalizeCXXLayout(const CXXRecordDecl *RD) {
}
void MicrosoftRecordLayoutBuilder::honorDeclspecAlign(const RecordDecl *RD) {
- if (unsigned MaxAlign = RD->getMaxAlignment()) {
- AlignAfterVBases = true;
- updateAlignment(Context.toCharUnitsFromBits(MaxAlign));
+ RequiredAlignment = std::max(RequiredAlignment,
+ Context.toCharUnitsFromBits(RD->getMaxAlignment()));
+ if (!RequiredAlignment.isZero()) {
+ updateAlignment(RequiredAlignment);
Size = Size.RoundUpToAlignment(Alignment);
}
}
@@ -2684,19 +2707,19 @@ ASTContext::BuildMicrosoftASTRecordLayout(const RecordDecl *D) const {
if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(D)) {
Builder.cxxLayout(RD);
return new (*this) ASTRecordLayout(
- *this, Builder.Size, Builder.Alignment,
+ *this, Builder.Size, Builder.Alignment, Builder.RequiredAlignment,
Builder.HasExtendableVFPtr && !Builder.PrimaryBase,
Builder.HasExtendableVFPtr,
Builder.VBPtrOffset, Builder.DataSize, Builder.FieldOffsets.data(),
Builder.FieldOffsets.size(), Builder.DataSize,
Builder.NonVirtualAlignment, CharUnits::Zero(), Builder.PrimaryBase,
- false, Builder.SharedVBPtrBase, Builder.AlignAfterVBases, Builder.Bases,
+ false, Builder.SharedVBPtrBase, Builder.Bases,
Builder.VBases);
} else {
Builder.layout(D);
return new (*this) ASTRecordLayout(
- *this, Builder.Size, Builder.Alignment, Builder.Size,
- Builder.FieldOffsets.data(), Builder.FieldOffsets.size());
+ *this, Builder.Size, Builder.Alignment, Builder.RequiredAlignment,
+ Builder.Size, Builder.FieldOffsets.data(), Builder.FieldOffsets.size());
}
}
@@ -2747,6 +2770,8 @@ ASTContext::getASTRecordLayout(const RecordDecl *D) const {
NewEntry =
new (*this) ASTRecordLayout(*this, Builder.getSize(),
Builder.Alignment,
+ /*RequiredAlignment : used by MS-ABI)*/
+ Builder.Alignment,
Builder.HasOwnVFPtr,
RD->isDynamicClass(),
CharUnits::fromQuantity(-1),
@@ -2758,7 +2783,7 @@ ASTContext::getASTRecordLayout(const RecordDecl *D) const {
EmptySubobjects.SizeOfLargestEmptySubobject,
Builder.PrimaryBase,
Builder.PrimaryBaseIsVirtual,
- 0, true,
+ 0,
Builder.Bases, Builder.VBases);
} else {
RecordLayoutBuilder Builder(*this, /*EmptySubobjects=*/0);
@@ -2767,6 +2792,8 @@ ASTContext::getASTRecordLayout(const RecordDecl *D) const {
NewEntry =
new (*this) ASTRecordLayout(*this, Builder.getSize(),
Builder.Alignment,
+ /*RequiredAlignment : used by MS-ABI)*/
+ Builder.Alignment,
Builder.getSize(),
Builder.FieldOffsets.data(),
Builder.FieldOffsets.size());
@@ -2876,6 +2903,8 @@ ASTContext::getObjCLayout(const ObjCInterfaceDecl *D,
const ASTRecordLayout *NewEntry =
new (*this) ASTRecordLayout(*this, Builder.getSize(),
Builder.Alignment,
+ /*RequiredAlignment : used by MS-ABI)*/
+ Builder.Alignment,
Builder.getDataSize(),
Builder.FieldOffsets.data(),
Builder.FieldOffsets.size());
OpenPOWER on IntegriCloud