summaryrefslogtreecommitdiffstats
path: root/lib/AST/RecordLayoutBuilder.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/AST/RecordLayoutBuilder.cpp')
-rw-r--r--lib/AST/RecordLayoutBuilder.cpp259
1 files changed, 159 insertions, 100 deletions
diff --git a/lib/AST/RecordLayoutBuilder.cpp b/lib/AST/RecordLayoutBuilder.cpp
index b9cfcfe..326a1dc 100644
--- a/lib/AST/RecordLayoutBuilder.cpp
+++ b/lib/AST/RecordLayoutBuilder.cpp
@@ -14,7 +14,6 @@
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/Expr.h"
-#include "clang/AST/RecordLayout.h"
#include "clang/Basic/TargetInfo.h"
#include <llvm/ADT/SmallSet.h>
#include <llvm/Support/MathExtras.h>
@@ -22,9 +21,9 @@
using namespace clang;
ASTRecordLayoutBuilder::ASTRecordLayoutBuilder(ASTContext &Ctx)
- : Ctx(Ctx), Size(0), Alignment(8), Packed(false), MaxFieldAlignment(0),
- DataSize(0), IsUnion(false), NonVirtualSize(0), NonVirtualAlignment(8),
- PrimaryBase(0), PrimaryBaseWasVirtual(false) {}
+ : Ctx(Ctx), Size(0), Alignment(8), Packed(false), UnfilledBitsInLastByte(0),
+ MaxFieldAlignment(0), DataSize(0), IsUnion(false), NonVirtualSize(0),
+ NonVirtualAlignment(8) { }
/// LayoutVtable - Lay out the vtable and set PrimaryBase.
void ASTRecordLayoutBuilder::LayoutVtable(const CXXRecordDecl *RD) {
@@ -34,7 +33,7 @@ void ASTRecordLayoutBuilder::LayoutVtable(const CXXRecordDecl *RD) {
}
SelectPrimaryBase(RD);
- if (PrimaryBase == 0) {
+ if (!PrimaryBase.getBase()) {
int AS = 0;
UpdateAlignment(Ctx.Target.getPointerAlign(AS));
Size += Ctx.Target.getPointerWidth(AS);
@@ -52,7 +51,7 @@ ASTRecordLayoutBuilder::LayoutNonVirtualBases(const CXXRecordDecl *RD) {
const CXXRecordDecl *Base =
cast<CXXRecordDecl>(i->getType()->getAs<RecordType>()->getDecl());
// Skip the PrimaryBase here, as it is laid down first.
- if (Base != PrimaryBase || PrimaryBaseWasVirtual)
+ if (Base != PrimaryBase.getBase() || PrimaryBase.isVirtual())
LayoutBaseNonVirtually(Base, false);
}
}
@@ -74,12 +73,13 @@ bool ASTRecordLayoutBuilder::IsNearlyEmpty(const CXXRecordDecl *RD) const {
}
void ASTRecordLayoutBuilder::IdentifyPrimaryBases(const CXXRecordDecl *RD) {
- const ASTRecordLayout &Layout = Ctx.getASTRecordLayout(RD);
+ const ASTRecordLayout::PrimaryBaseInfo &BaseInfo =
+ Ctx.getASTRecordLayout(RD).getPrimaryBaseInfo();
// If the record has a primary base class that is virtual, add it to the set
// of primary bases.
- if (Layout.getPrimaryBaseWasVirtual())
- IndirectPrimaryBases.insert(Layout.getPrimaryBase());
+ if (BaseInfo.isVirtual())
+ IndirectPrimaryBases.insert(BaseInfo.getBase());
// Now traverse all bases and find primary bases for them.
for (CXXRecordDecl::base_class_const_iterator i = RD->bases_begin(),
@@ -107,7 +107,7 @@ ASTRecordLayoutBuilder::SelectPrimaryVBase(const CXXRecordDecl *RD,
cast<CXXRecordDecl>(i->getType()->getAs<RecordType>()->getDecl());
if (!i->isVirtual()) {
SelectPrimaryVBase(Base, FirstPrimary);
- if (PrimaryBase)
+ if (PrimaryBase.getBase())
return;
continue;
}
@@ -115,7 +115,7 @@ ASTRecordLayoutBuilder::SelectPrimaryVBase(const CXXRecordDecl *RD,
if (FirstPrimary==0)
FirstPrimary = Base;
if (!IndirectPrimaryBases.count(Base)) {
- setPrimaryBase(Base, true);
+ setPrimaryBase(Base, /*IsVirtual=*/true);
return;
}
}
@@ -141,14 +141,17 @@ void ASTRecordLayoutBuilder::SelectPrimaryBase(const CXXRecordDecl *RD) {
// base class, if one exists.
for (CXXRecordDecl::base_class_const_iterator i = RD->bases_begin(),
e = RD->bases_end(); i != e; ++i) {
- if (!i->isVirtual()) {
- const CXXRecordDecl *Base =
- cast<CXXRecordDecl>(i->getType()->getAs<RecordType>()->getDecl());
- if (Base->isDynamicClass()) {
- // We found it.
- setPrimaryBase(Base, false);
- return;
- }
+ // Ignore virtual bases.
+ if (i->isVirtual())
+ continue;
+
+ const CXXRecordDecl *Base =
+ cast<CXXRecordDecl>(i->getType()->getAs<RecordType>()->getDecl());
+
+ if (Base->isDynamicClass()) {
+ // We found it.
+ PrimaryBase = ASTRecordLayout::PrimaryBaseInfo(Base, /*IsVirtual=*/false);
+ return;
}
}
@@ -166,8 +169,8 @@ void ASTRecordLayoutBuilder::SelectPrimaryBase(const CXXRecordDecl *RD) {
// Otherwise if is the first nearly empty virtual base, if one exists,
// otherwise there is no primary base class.
- if (!PrimaryBase)
- setPrimaryBase(FirstPrimary, true);
+ if (!PrimaryBase.getBase())
+ setPrimaryBase(FirstPrimary, /*IsVirtual=*/true);
}
void ASTRecordLayoutBuilder::LayoutVirtualBase(const CXXRecordDecl *RD) {
@@ -232,9 +235,10 @@ void ASTRecordLayoutBuilder::LayoutVirtualBases(const CXXRecordDecl *Class,
}
if (Base->getNumVBases()) {
- const ASTRecordLayout &L = Ctx.getASTRecordLayout(Base);
- const CXXRecordDecl *PB = L.getPrimaryBase();
- LayoutVirtualBases(Class, Base, PB, BaseOffset, mark, IndirectPrimary);
+ const ASTRecordLayout &Layout = Ctx.getASTRecordLayout(Base);
+ const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBaseInfo().getBase();
+ LayoutVirtualBases(Class, Base, PrimaryBase, BaseOffset, mark,
+ IndirectPrimary);
}
}
}
@@ -448,17 +452,17 @@ void ASTRecordLayoutBuilder::Layout(const RecordDecl *D) {
MaxFieldAlignment = PPA->getAlignment();
if (const AlignedAttr *AA = D->getAttr<AlignedAttr>())
- UpdateAlignment(AA->getAlignment());
+ UpdateAlignment(AA->getMaxAlignment());
// If this is a C++ class, lay out the vtable and the non-virtual bases.
const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(D);
if (RD) {
LayoutVtable(RD);
// PrimaryBase goes first.
- if (PrimaryBase) {
- if (PrimaryBaseWasVirtual)
- IndirectPrimaryBases.insert(PrimaryBase);
- LayoutBaseNonVirtually(PrimaryBase, PrimaryBaseWasVirtual);
+ if (PrimaryBase.getBase()) {
+ if (PrimaryBase.isVirtual())
+ IndirectPrimaryBases.insert(PrimaryBase.getBase());
+ LayoutBaseNonVirtually(PrimaryBase.getBase(), PrimaryBase.isVirtual());
}
LayoutNonVirtualBases(RD);
}
@@ -470,7 +474,8 @@ void ASTRecordLayoutBuilder::Layout(const RecordDecl *D) {
if (RD) {
llvm::SmallSet<const CXXRecordDecl*, 32> mark;
- LayoutVirtualBases(RD, RD, PrimaryBase, 0, mark, IndirectPrimaryBases);
+ LayoutVirtualBases(RD, RD, PrimaryBase.getBase(),
+ 0, mark, IndirectPrimaryBases);
}
// Finally, round the size of the total struct up to the alignment of the
@@ -498,7 +503,7 @@ void ASTRecordLayoutBuilder::Layout(const ObjCInterfaceDecl *D,
MaxFieldAlignment = PPA->getAlignment();
if (const AlignedAttr *AA = D->getAttr<AlignedAttr>())
- UpdateAlignment(AA->getAlignment());
+ UpdateAlignment(AA->getMaxAlignment());
// Layout each ivar sequentially.
llvm::SmallVector<ObjCIvarDecl*, 16> Ivars;
@@ -519,84 +524,111 @@ void ASTRecordLayoutBuilder::LayoutFields(const RecordDecl *D) {
LayoutField(*Field);
}
+void ASTRecordLayoutBuilder::LayoutBitField(const FieldDecl *D) {
+ bool FieldPacked = Packed || D->hasAttr<PackedAttr>();
+ uint64_t FieldOffset = IsUnion ? 0 : (DataSize - UnfilledBitsInLastByte);
+ uint64_t FieldSize = D->getBitWidth()->EvaluateAsInt(Ctx).getZExtValue();
+
+ std::pair<uint64_t, unsigned> FieldInfo = Ctx.getTypeInfo(D->getType());
+ uint64_t TypeSize = FieldInfo.first;
+ unsigned FieldAlign = FieldInfo.second;
+
+ if (FieldPacked)
+ FieldAlign = 1;
+ if (const AlignedAttr *AA = D->getAttr<AlignedAttr>())
+ FieldAlign = std::max(FieldAlign, AA->getMaxAlignment());
+
+ // 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)
+ FieldOffset = (FieldOffset + (FieldAlign-1)) & ~(FieldAlign-1);
+
+ // Padding members don't affect overall alignment
+ if (!D->getIdentifier())
+ FieldAlign = 1;
+
+ // Place this field at the current location.
+ FieldOffsets.push_back(FieldOffset);
+
+ // Update DataSize to include the last byte containing (part of) the bitfield.
+ if (IsUnion) {
+ // FIXME: I think FieldSize should be TypeSize here.
+ DataSize = std::max(DataSize, FieldSize);
+ } else {
+ uint64_t NewSizeInBits = FieldOffset + FieldSize;
+
+ DataSize = llvm::RoundUpToAlignment(NewSizeInBits, 8);
+ UnfilledBitsInLastByte = DataSize - NewSizeInBits;
+ }
+
+ // Update the size.
+ Size = std::max(Size, DataSize);
+
+ // Remember max struct/class alignment.
+ UpdateAlignment(FieldAlign);
+}
+
void ASTRecordLayoutBuilder::LayoutField(const FieldDecl *D) {
- bool FieldPacked = Packed;
+ if (D->isBitField()) {
+ LayoutBitField(D);
+ return;
+ }
+
+ // Reset the unfilled bits.
+ UnfilledBitsInLastByte = 0;
+
+ bool FieldPacked = Packed || D->hasAttr<PackedAttr>();
uint64_t FieldOffset = IsUnion ? 0 : DataSize;
uint64_t FieldSize;
unsigned FieldAlign;
-
- FieldPacked |= D->hasAttr<PackedAttr>();
-
- if (const Expr *BitWidthExpr = D->getBitWidth()) {
- // TODO: Need to check this algorithm on other targets!
- // (tested on Linux-X86)
- FieldSize = BitWidthExpr->EvaluateAsInt(Ctx).getZExtValue();
-
+
+ if (D->getType()->isIncompleteArrayType()) {
+ // This is a flexible array member; we can't directly
+ // query getTypeInfo about these, so we figure it out here.
+ // Flexible array members don't have any size, but they
+ // have to be aligned appropriately for their element type.
+ FieldSize = 0;
+ const ArrayType* ATy = Ctx.getAsArrayType(D->getType());
+ FieldAlign = Ctx.getTypeAlign(ATy->getElementType());
+ } else if (const ReferenceType *RT = D->getType()->getAs<ReferenceType>()) {
+ unsigned AS = RT->getPointeeType().getAddressSpace();
+ FieldSize = Ctx.Target.getPointerWidth(AS);
+ FieldAlign = Ctx.Target.getPointerAlign(AS);
+ } else {
std::pair<uint64_t, unsigned> FieldInfo = Ctx.getTypeInfo(D->getType());
- uint64_t TypeSize = FieldInfo.first;
-
+ FieldSize = FieldInfo.first;
FieldAlign = FieldInfo.second;
+ }
- 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)
- FieldOffset = (FieldOffset + (FieldAlign-1)) & ~(FieldAlign-1);
-
- // Padding members don't affect overall alignment
- if (!D->getIdentifier())
- FieldAlign = 1;
- } else {
- if (D->getType()->isIncompleteArrayType()) {
- // This is a flexible array member; we can't directly
- // query getTypeInfo about these, so we figure it out here.
- // Flexible array members don't have any size, but they
- // have to be aligned appropriately for their element type.
- FieldSize = 0;
- const ArrayType* ATy = Ctx.getAsArrayType(D->getType());
- FieldAlign = Ctx.getTypeAlign(ATy->getElementType());
- } else if (const ReferenceType *RT = D->getType()->getAs<ReferenceType>()) {
- unsigned AS = RT->getPointeeType().getAddressSpace();
- FieldSize = Ctx.Target.getPointerWidth(AS);
- FieldAlign = Ctx.Target.getPointerAlign(AS);
- } else {
- std::pair<uint64_t, unsigned> FieldInfo = Ctx.getTypeInfo(D->getType());
- FieldSize = FieldInfo.first;
- FieldAlign = FieldInfo.second;
- }
+ if (FieldPacked)
+ FieldAlign = 8;
+ if (const AlignedAttr *AA = D->getAttr<AlignedAttr>())
+ FieldAlign = std::max(FieldAlign, AA->getMaxAlignment());
- 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);
+ // 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 = llvm::RoundUpToAlignment(FieldOffset, FieldAlign);
-
- if (!IsUnion) {
- while (true) {
- // Check if we can place the field at this offset.
- if (canPlaceFieldAtOffset(D, FieldOffset))
- break;
-
- // We couldn't place the field at the offset. Try again at a new offset.
- FieldOffset += FieldAlign;
- }
+ // Round up the current record size to the field's alignment boundary.
+ FieldOffset = llvm::RoundUpToAlignment(FieldOffset, FieldAlign);
+
+ if (!IsUnion) {
+ while (true) {
+ // Check if we can place the field at this offset.
+ if (canPlaceFieldAtOffset(D, FieldOffset))
+ break;
- UpdateEmptyClassOffsets(D, FieldOffset);
+ // We couldn't place the field at the offset. Try again at a new offset.
+ FieldOffset += FieldAlign;
}
+
+ UpdateEmptyClassOffsets(D, FieldOffset);
}
-
+
// Place this field at the current location.
FieldOffsets.push_back(FieldOffset);
@@ -619,7 +651,7 @@ void ASTRecordLayoutBuilder::FinishLayout() {
Size = 8;
// Finally, round the size of the record up to the alignment of the
// record itself.
- Size = (Size + (Alignment-1)) & ~(Alignment-1);
+ Size = llvm::RoundUpToAlignment(Size, Alignment);
}
void ASTRecordLayoutBuilder::UpdateAlignment(unsigned NewAlignment) {
@@ -631,6 +663,31 @@ void ASTRecordLayoutBuilder::UpdateAlignment(unsigned NewAlignment) {
Alignment = NewAlignment;
}
+static const CXXMethodDecl *GetKeyFunction(const CXXRecordDecl *RD) {
+ if (!RD->isDynamicClass())
+ return 0;
+
+ for (CXXRecordDecl::method_iterator I = RD->method_begin(),
+ E = RD->method_end(); I != E; ++I) {
+ const CXXMethodDecl *MD = *I;
+
+ if (!MD->isVirtual())
+ continue;
+
+ if (MD->isPure())
+ continue;
+
+ const FunctionDecl *fn;
+ if (MD->getBody(fn) && !fn->isOutOfLine())
+ continue;
+
+ // We found it.
+ return MD;
+ }
+
+ return 0;
+}
+
const ASTRecordLayout *
ASTRecordLayoutBuilder::ComputeLayout(ASTContext &Ctx,
const RecordDecl *D) {
@@ -654,17 +711,19 @@ ASTRecordLayoutBuilder::ComputeLayout(ASTContext &Ctx,
uint64_t NonVirtualSize =
IsPODForThePurposeOfLayout ? DataSize : Builder.NonVirtualSize;
+ const CXXMethodDecl *KeyFunction = GetKeyFunction(cast<CXXRecordDecl>(D));
+
return new ASTRecordLayout(Builder.Size, Builder.Alignment, DataSize,
Builder.FieldOffsets.data(),
Builder.FieldOffsets.size(),
NonVirtualSize,
Builder.NonVirtualAlignment,
Builder.PrimaryBase,
- Builder.PrimaryBaseWasVirtual,
Builder.Bases.data(),
Builder.Bases.size(),
Builder.VBases.data(),
- Builder.VBases.size());
+ Builder.VBases.size(),
+ KeyFunction);
}
const ASTRecordLayout *
OpenPOWER on IntegriCloud