Scaffolding for supporting empty bases/fields.

llvm-svn: 82678
This commit is contained in:
Anders Carlsson 2009-09-24 03:13:30 +00:00
parent 26ea28eb5f
commit 6522b05db7
2 changed files with 55 additions and 16 deletions

View File

@ -219,8 +219,18 @@ void ASTRecordLayoutBuilder::LayoutVirtualBases(const CXXRecordDecl *RD,
} }
} }
void ASTRecordLayoutBuilder::LayoutBaseNonVirtually(const CXXRecordDecl *RD, bool ASTRecordLayoutBuilder::canPlaceRecordAtOffset(const CXXRecordDecl *RD,
bool IsVirtualBase) { uint64_t Offset) const {
// FIXME: Implement.
return true;
}
void ASTRecordLayoutBuilder::UpdateEmptyClassOffsets(const CXXRecordDecl *RD,
uint64_t Offset) {
// FIXME: Implement.
}
uint64_t ASTRecordLayoutBuilder::LayoutBase(const CXXRecordDecl *RD) {
const ASTRecordLayout &BaseInfo = Ctx.getASTRecordLayout(RD); const ASTRecordLayout &BaseInfo = Ctx.getASTRecordLayout(RD);
if (!Bases.empty()) { if (!Bases.empty()) {
assert(BaseInfo.getDataSize() > 0 && assert(BaseInfo.getDataSize() > 0 &&
@ -229,15 +239,32 @@ void ASTRecordLayoutBuilder::LayoutBaseNonVirtually(const CXXRecordDecl *RD,
unsigned BaseAlign = BaseInfo.getNonVirtualAlign(); unsigned BaseAlign = BaseInfo.getNonVirtualAlign();
uint64_t BaseSize = BaseInfo.getNonVirtualSize(); uint64_t BaseSize = BaseInfo.getNonVirtualSize();
// Round up the current record size to the base's alignment boundary. // Round up the current record size to the base's alignment boundary.
Size = (Size + (BaseAlign-1)) & ~(BaseAlign-1); uint64_t Offset = llvm::RoundUpToAlignment(Size, BaseAlign);
// Reserve space for this base.
Size = Offset + BaseSize;
// Remember the next available offset.
NextOffset = Size;
// Remember max struct/class alignment.
UpdateAlignment(BaseAlign);
return Offset;
}
void ASTRecordLayoutBuilder::LayoutBaseNonVirtually(const CXXRecordDecl *RD,
bool IsVirtualBase) {
// Layout the base.
unsigned Offset = LayoutBase(RD);
// Add base class offsets. // Add base class offsets.
if (IsVirtualBase) if (IsVirtualBase)
VBases.push_back(std::make_pair(RD, Size)); VBases.push_back(std::make_pair(RD, Offset));
else else
Bases.push_back(std::make_pair(RD, Size)); Bases.push_back(std::make_pair(RD, Offset));
#if 0 #if 0
// And now add offsets for all our primary virtual bases as well, so // And now add offsets for all our primary virtual bases as well, so
@ -254,15 +281,6 @@ void ASTRecordLayoutBuilder::LayoutBaseNonVirtually(const CXXRecordDecl *RD,
L = &Ctx.getASTRecordLayout(PB); L = &Ctx.getASTRecordLayout(PB);
} }
#endif #endif
// Reserve space for this base.
Size += BaseSize;
// Remember the next available offset.
NextOffset = Size;
// Remember max struct/class alignment.
UpdateAlignment(BaseAlign);
} }
void ASTRecordLayoutBuilder::Layout(const RecordDecl *D) { void ASTRecordLayoutBuilder::Layout(const RecordDecl *D) {
@ -408,7 +426,7 @@ void ASTRecordLayoutBuilder::LayoutField(const FieldDecl *D) {
FieldAlign = std::min(FieldAlign, MaxFieldAlignment); FieldAlign = std::min(FieldAlign, MaxFieldAlignment);
// 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 + (FieldAlign-1)) & ~(FieldAlign-1); FieldOffset = llvm::RoundUpToAlignment(FieldOffset, FieldAlign);
} }
// Place this field at the current location. // Place this field at the current location.

View File

@ -13,6 +13,7 @@
#include "llvm/ADT/SmallVector.h" #include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/SmallSet.h" #include "llvm/ADT/SmallSet.h"
#include "llvm/Support/DataTypes.h" #include "llvm/Support/DataTypes.h"
#include <map>
namespace clang { namespace clang {
class ASTContext; class ASTContext;
@ -53,6 +54,10 @@ class ASTRecordLayoutBuilder {
/// primary base classes for some other direct or indirect base class. /// primary base classes for some other direct or indirect base class.
llvm::SmallSet<const CXXRecordDecl*, 32> IndirectPrimaryBases; llvm::SmallSet<const CXXRecordDecl*, 32> IndirectPrimaryBases;
/// EmptyClassOffsets - A map from offsets to empty record decls.
typedef std::multimap<uint64_t, const CXXRecordDecl *> EmptyClassOffsetsTy;
EmptyClassOffsetsTy EmptyClassOffsets;
ASTRecordLayoutBuilder(ASTContext &Ctx); ASTRecordLayoutBuilder(ASTContext &Ctx);
void Layout(const RecordDecl *D); void Layout(const RecordDecl *D);
@ -79,6 +84,10 @@ class ASTRecordLayoutBuilder {
bool IsNearlyEmpty(const CXXRecordDecl *RD) const; bool IsNearlyEmpty(const CXXRecordDecl *RD) const;
/// LayoutBase - Will lay out a base and return the offset where it was
/// placed, in bits.
uint64_t LayoutBase(const CXXRecordDecl *RD);
void LayoutVtable(const CXXRecordDecl *RD); void LayoutVtable(const CXXRecordDecl *RD);
void LayoutNonVirtualBases(const CXXRecordDecl *RD); void LayoutNonVirtualBases(const CXXRecordDecl *RD);
void LayoutBaseNonVirtually(const CXXRecordDecl *RD, bool IsVBase); void LayoutBaseNonVirtually(const CXXRecordDecl *RD, bool IsVBase);
@ -88,6 +97,18 @@ class ASTRecordLayoutBuilder {
llvm::SmallSet<const CXXRecordDecl*, 32> &mark, llvm::SmallSet<const CXXRecordDecl*, 32> &mark,
llvm::SmallSet<const CXXRecordDecl*, 32> &IndirectPrimary); llvm::SmallSet<const CXXRecordDecl*, 32> &IndirectPrimary);
/// canPlaceRecordAtOffset - Return whether a record (either a base class
/// or a field) can be placed at the given offset.
/// Returns false if placing the record will result in two components
/// (direct or indirect) of the same type having the same offset.
bool canPlaceRecordAtOffset(const CXXRecordDecl *RD, uint64_t Offset) const;
/// UpdateEmptyClassOffsets - Called after a record (either a base class
/// or a field) has been placed at the given offset. Will update the
/// EmptyClassOffsets map if the class is empty or has any empty bases or
/// fields.
void UpdateEmptyClassOffsets(const CXXRecordDecl *RD, uint64_t Offset);
/// FinishLayout - Finalize record layout. Adjust record size based on the /// FinishLayout - Finalize record layout. Adjust record size based on the
/// alignment. /// alignment.
void FinishLayout(); void FinishLayout();