aboutsummaryrefslogtreecommitdiff
path: root/lib/CodeGen/CGRecordLayoutBuilder.cpp
diff options
context:
space:
mode:
authorJohn McCall <rjmccall@apple.com>2011-02-15 06:40:56 +0000
committerJohn McCall <rjmccall@apple.com>2011-02-15 06:40:56 +0000
commit9b7da1c46d6d2849f9cb51328d7fcddf2c417672 (patch)
tree586f035ba023d43ad7c063ca7c2ac642e9bef469 /lib/CodeGen/CGRecordLayoutBuilder.cpp
parentfe59b7472c06b36efb74fbb50bbdf464fa30c0d8 (diff)
Perform zero-initialization of virtual base classes when emitting
a zero constant for a complete class. rdar://problem/8424975 To make this happen, track the field indexes for virtual bases in the complete object. I'm curious whether we might be better off making CGRecordLayoutBuilder *much* more reliant on ASTRecordLayout; we're currently duplicating an awful lot of the ABI layout logic. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@125555 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/CodeGen/CGRecordLayoutBuilder.cpp')
-rw-r--r--lib/CodeGen/CGRecordLayoutBuilder.cpp212
1 files changed, 100 insertions, 112 deletions
diff --git a/lib/CodeGen/CGRecordLayoutBuilder.cpp b/lib/CodeGen/CGRecordLayoutBuilder.cpp
index aaff7fc9f7..f2864944f9 100644
--- a/lib/CodeGen/CGRecordLayoutBuilder.cpp
+++ b/lib/CodeGen/CGRecordLayoutBuilder.cpp
@@ -33,9 +33,10 @@ namespace {
class CGRecordLayoutBuilder {
public:
/// FieldTypes - Holds the LLVM types that the struct is created from.
+ ///
std::vector<const llvm::Type *> FieldTypes;
- /// NonVirtualBaseFieldTypes - Holds the LLVM types for the non-virtual part
+ /// BaseSubobjectType - Holds the LLVM type for the non-virtual part
/// of the struct. For example, consider:
///
/// struct A { int i; };
@@ -47,22 +48,19 @@ public:
///
/// And the LLVM type of the non-virtual base struct will be
/// %struct.C.base = type { i32 (...)**, %struct.A, i32 }
- std::vector<const llvm::Type *> NonVirtualBaseFieldTypes;
+ ///
+ /// This only gets initialized if the base subobject type is
+ /// different from the complete-object type.
+ const llvm::StructType *BaseSubobjectType;
- /// NonVirtualBaseTypeIsSameAsCompleteType - Whether the non-virtual part of
- /// the struct is equivalent to the complete struct.
- bool NonVirtualBaseTypeIsSameAsCompleteType;
-
- /// LLVMFieldInfo - Holds a field and its corresponding LLVM field number.
- typedef std::pair<const FieldDecl *, unsigned> LLVMFieldInfo;
- llvm::SmallVector<LLVMFieldInfo, 16> LLVMFields;
+ /// FieldInfo - Holds a field and its corresponding LLVM field number.
+ llvm::DenseMap<const FieldDecl *, unsigned> Fields;
- /// LLVMBitFieldInfo - Holds location and size information about a bit field.
- typedef std::pair<const FieldDecl *, CGBitFieldInfo> LLVMBitFieldInfo;
- llvm::SmallVector<LLVMBitFieldInfo, 16> LLVMBitFields;
+ /// BitFieldInfo - Holds location and size information about a bit field.
+ llvm::DenseMap<const FieldDecl *, CGBitFieldInfo> BitFields;
- typedef std::pair<const CXXRecordDecl *, unsigned> LLVMBaseInfo;
- llvm::SmallVector<LLVMBaseInfo, 16> LLVMNonVirtualBases;
+ llvm::DenseMap<const CXXRecordDecl *, unsigned> NonVirtualBases;
+ llvm::DenseMap<const CXXRecordDecl *, unsigned> VirtualBases;
/// IndirectPrimaryBases - Virtual base classes, direct or indirect, that are
/// primary base classes for some other direct or indirect base class.
@@ -75,6 +73,7 @@ public:
/// IsZeroInitializable - Whether this struct can be C++
/// zero-initialized with an LLVM zeroinitializer.
bool IsZeroInitializable;
+ bool IsZeroInitializableAsBase;
/// Packed - Whether the resulting LLVM struct will be packed or not.
bool Packed;
@@ -148,6 +147,7 @@ private:
/// AppendBytes - Append a given number of bytes to the record.
void AppendBytes(uint64_t NumBytes);
+ void AppendBytes(CharUnits numBytes) { AppendBytes(numBytes.getQuantity()); }
/// AppendTailPadding - Append enough tail padding so that the type will have
/// the passed size.
@@ -162,13 +162,13 @@ private:
/// CheckZeroInitializable - Check if the given type contains a pointer
/// to data member.
void CheckZeroInitializable(QualType T);
- void CheckZeroInitializable(const CXXRecordDecl *RD);
public:
CGRecordLayoutBuilder(CodeGenTypes &Types)
- : NonVirtualBaseTypeIsSameAsCompleteType(false), IsZeroInitializable(true),
- Packed(false), Types(Types), Alignment(0), BitsAvailableInLastField(0),
- NextFieldOffsetInBytes(0) { }
+ : BaseSubobjectType(0),
+ IsZeroInitializable(true), IsZeroInitializableAsBase(true),
+ Packed(false), Types(Types), Alignment(0),
+ BitsAvailableInLastField(0), NextFieldOffsetInBytes(0) { }
/// Layout - Will layout a RecordDecl.
void Layout(const RecordDecl *D);
@@ -193,9 +193,10 @@ void CGRecordLayoutBuilder::Layout(const RecordDecl *D) {
Packed = true;
NextFieldOffsetInBytes = 0;
FieldTypes.clear();
- LLVMFields.clear();
- LLVMBitFields.clear();
- LLVMNonVirtualBases.clear();
+ Fields.clear();
+ BitFields.clear();
+ NonVirtualBases.clear();
+ VirtualBases.clear();
LayoutFields(D);
}
@@ -339,9 +340,8 @@ void CGRecordLayoutBuilder::LayoutBitField(const FieldDecl *D,
}
// Add the bit field info.
- LLVMBitFields.push_back(
- LLVMBitFieldInfo(D, CGBitFieldInfo::MakeInfo(Types, D, FieldOffset,
- FieldSize)));
+ BitFields.insert(std::make_pair(D,
+ CGBitFieldInfo::MakeInfo(Types, D, FieldOffset, FieldSize)));
AppendBytes(NumBytesToAppend);
@@ -401,7 +401,7 @@ bool CGRecordLayoutBuilder::LayoutField(const FieldDecl *D,
AppendPadding(FieldOffsetInBytes, TypeAlignment);
// Now append the field.
- LLVMFields.push_back(LLVMFieldInfo(D, FieldTypes.size()));
+ Fields[D] = FieldTypes.size();
AppendField(FieldOffsetInBytes, Ty);
return true;
@@ -426,14 +426,13 @@ CGRecordLayoutBuilder::LayoutUnionField(const FieldDecl *Field,
FieldTy = llvm::ArrayType::get(FieldTy, NumBytesToAppend);
// Add the bit field info.
- LLVMBitFields.push_back(
- LLVMBitFieldInfo(Field, CGBitFieldInfo::MakeInfo(Types, Field,
- 0, FieldSize)));
+ BitFields.insert(std::make_pair(Field,
+ CGBitFieldInfo::MakeInfo(Types, Field, 0, FieldSize)));
return FieldTy;
}
// This is a regular union field.
- LLVMFields.push_back(LLVMFieldInfo(Field, 0));
+ Fields[Field] = 0;
return Types.ConvertTypeForMemRecursive(Field->getType());
}
@@ -495,41 +494,51 @@ void CGRecordLayoutBuilder::LayoutUnion(const RecordDecl *D) {
AppendPadding(RecordSize, Align);
}
-void CGRecordLayoutBuilder::LayoutBase(const CXXRecordDecl *BaseDecl,
- uint64_t BaseOffset) {
- CheckZeroInitializable(BaseDecl);
+void CGRecordLayoutBuilder::LayoutBase(const CXXRecordDecl *base,
+ uint64_t baseOffsetInBits) {
+ uint64_t baseOffsetInBytes = baseOffsetInBits / 8;
+ AppendPadding(baseOffsetInBytes, 1);
- const ASTRecordLayout &Layout =
- Types.getContext().getASTRecordLayout(BaseDecl);
-
- CharUnits NonVirtualSize = Layout.getNonVirtualSize();
-
- AppendPadding(BaseOffset / 8, 1);
-
- // FIXME: Actually use a better type than [sizeof(BaseDecl) x i8] when we can.
- AppendBytes(NonVirtualSize.getQuantity());
+ const ASTRecordLayout &baseASTLayout
+ = Types.getContext().getASTRecordLayout(base);
+
+ // FIXME: use a better type than [sizeof(base) x i8].
+ // We could use the base layout's subobject type as the actualy
+ // subobject type in the layout if its size is the nvsize of the
+ // base, or if we'd need padding out to the enclosing object anyhow.
+ AppendBytes(baseASTLayout.getNonVirtualSize());
}
-void
-CGRecordLayoutBuilder::LayoutVirtualBase(const CXXRecordDecl *BaseDecl,
- uint64_t BaseOffset) {
+void CGRecordLayoutBuilder::LayoutNonVirtualBase(const CXXRecordDecl *base,
+ uint64_t baseOffsetInBits) {
// Ignore empty bases.
- if (BaseDecl->isEmpty())
- return;
+ if (base->isEmpty()) return;
- CheckZeroInitializable(BaseDecl);
+ const CGRecordLayout &baseLayout = Types.getCGRecordLayout(base);
+ if (IsZeroInitializableAsBase) {
+ assert(IsZeroInitializable &&
+ "class zero-initializable as base but not as complete object");
- const ASTRecordLayout &Layout =
- Types.getContext().getASTRecordLayout(BaseDecl);
+ IsZeroInitializable = IsZeroInitializableAsBase =
+ baseLayout.isZeroInitializableAsBase();
+ }
- CharUnits NonVirtualSize = Layout.getNonVirtualSize();
+ LayoutBase(base, baseOffsetInBits);
+ NonVirtualBases[base] = (FieldTypes.size() - 1);
+}
- AppendPadding(BaseOffset / 8, 1);
-
- // FIXME: Actually use a better type than [sizeof(BaseDecl) x i8] when we can.
- AppendBytes(NonVirtualSize.getQuantity());
+void
+CGRecordLayoutBuilder::LayoutVirtualBase(const CXXRecordDecl *base,
+ uint64_t baseOffsetInBits) {
+ // Ignore empty bases.
+ if (base->isEmpty()) return;
- // FIXME: Add the vbase field info.
+ const CGRecordLayout &baseLayout = Types.getCGRecordLayout(base);
+ if (IsZeroInitializable)
+ IsZeroInitializable = baseLayout.isZeroInitializableAsBase();
+
+ LayoutBase(base, baseOffsetInBits);
+ VirtualBases[base] = (FieldTypes.size() - 1);
}
/// LayoutVirtualBases - layout the non-virtual bases of a record decl.
@@ -561,18 +570,6 @@ CGRecordLayoutBuilder::LayoutVirtualBases(const CXXRecordDecl *RD,
}
}
-void CGRecordLayoutBuilder::LayoutNonVirtualBase(const CXXRecordDecl *BaseDecl,
- uint64_t BaseOffset) {
- // Ignore empty bases.
- if (BaseDecl->isEmpty())
- return;
-
- LayoutBase(BaseDecl, BaseOffset);
-
- // Append the base field.
- LLVMNonVirtualBases.push_back(LLVMBaseInfo(BaseDecl, FieldTypes.size() - 1));
-}
-
void
CGRecordLayoutBuilder::LayoutNonVirtualBases(const CXXRecordDecl *RD,
const ASTRecordLayout &Layout) {
@@ -618,37 +615,40 @@ bool
CGRecordLayoutBuilder::ComputeNonVirtualBaseType(const CXXRecordDecl *RD) {
const ASTRecordLayout &Layout = Types.getContext().getASTRecordLayout(RD);
-
CharUnits NonVirtualSize = Layout.getNonVirtualSize();
CharUnits NonVirtualAlign = Layout.getNonVirtualAlign();
uint64_t AlignedNonVirtualTypeSize =
NonVirtualSize.RoundUpToAlignment(NonVirtualAlign).getQuantity();
-
// First check if we can use the same fields as for the complete class.
uint64_t RecordSize = Layout.getSize().getQuantity();
- if (AlignedNonVirtualTypeSize == RecordSize) {
- NonVirtualBaseTypeIsSameAsCompleteType = true;
+ if (AlignedNonVirtualTypeSize == RecordSize)
return true;
- }
// Check if we need padding.
uint64_t AlignedNextFieldOffset =
llvm::RoundUpToAlignment(NextFieldOffsetInBytes,
getAlignmentAsLLVMStruct());
- if (AlignedNextFieldOffset > AlignedNonVirtualTypeSize)
+ if (AlignedNextFieldOffset > AlignedNonVirtualTypeSize) {
+ assert(!Packed && "cannot layout even as packed struct");
return false; // Needs packing.
+ }
+
+ bool needsPadding = (AlignedNonVirtualTypeSize != AlignedNextFieldOffset);
+ if (needsPadding) {
+ uint64_t NumBytes = AlignedNonVirtualTypeSize - AlignedNextFieldOffset;
+ FieldTypes.push_back(getByteArrayType(NumBytes));
+ }
- NonVirtualBaseFieldTypes = FieldTypes;
+ BaseSubobjectType = llvm::StructType::get(Types.getLLVMContext(),
+ FieldTypes, Packed);
- if (AlignedNonVirtualTypeSize == AlignedNextFieldOffset) {
- // We don't need any padding.
- return true;
+ if (needsPadding) {
+ // Pull the padding back off.
+ FieldTypes.pop_back();
}
- uint64_t NumBytes = AlignedNonVirtualTypeSize - AlignedNextFieldOffset;
- NonVirtualBaseFieldTypes.push_back(getByteArrayType(NumBytes));
return true;
}
@@ -777,36 +777,29 @@ unsigned CGRecordLayoutBuilder::getAlignmentAsLLVMStruct() const {
return MaxAlignment;
}
+/// Merge in whether a field of the given type is zero-initializable.
void CGRecordLayoutBuilder::CheckZeroInitializable(QualType T) {
// This record already contains a member pointer.
- if (!IsZeroInitializable)
+ if (!IsZeroInitializableAsBase)
return;
// Can only have member pointers if we're compiling C++.
if (!Types.getContext().getLangOptions().CPlusPlus)
return;
- T = Types.getContext().getBaseElementType(T);
+ const Type *elementType = T->getBaseElementTypeUnsafe();
- if (const MemberPointerType *MPT = T->getAs<MemberPointerType>()) {
+ if (const MemberPointerType *MPT = elementType->getAs<MemberPointerType>()) {
if (!Types.getCXXABI().isZeroInitializable(MPT))
- IsZeroInitializable = false;
- } else if (const RecordType *RT = T->getAs<RecordType>()) {
+ IsZeroInitializable = IsZeroInitializableAsBase = false;
+ } else if (const RecordType *RT = elementType->getAs<RecordType>()) {
const CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl());
- CheckZeroInitializable(RD);
+ const CGRecordLayout &Layout = Types.getCGRecordLayout(RD);
+ if (!Layout.isZeroInitializable())
+ IsZeroInitializable = IsZeroInitializableAsBase = false;
}
}
-void CGRecordLayoutBuilder::CheckZeroInitializable(const CXXRecordDecl *RD) {
- // This record already contains a member pointer.
- if (!IsZeroInitializable)
- return;
-
- const CGRecordLayout &Layout = Types.getCGRecordLayout(RD);
- if (!Layout.isZeroInitializable())
- IsZeroInitializable = false;
-}
-
CGRecordLayout *CodeGenTypes::ComputeRecordLayout(const RecordDecl *D) {
CGRecordLayoutBuilder Builder(*this);
@@ -816,30 +809,25 @@ CGRecordLayout *CodeGenTypes::ComputeRecordLayout(const RecordDecl *D) {
Builder.FieldTypes,
Builder.Packed);
+ // If we're in C++, compute the base subobject type.
const llvm::StructType *BaseTy = 0;
if (isa<CXXRecordDecl>(D)) {
- if (Builder.NonVirtualBaseTypeIsSameAsCompleteType)
- BaseTy = Ty;
- else if (!Builder.NonVirtualBaseFieldTypes.empty())
- BaseTy = llvm::StructType::get(getLLVMContext(),
- Builder.NonVirtualBaseFieldTypes,
- Builder.Packed);
+ BaseTy = Builder.BaseSubobjectType;
+ if (!BaseTy) BaseTy = Ty;
}
CGRecordLayout *RL =
- new CGRecordLayout(Ty, BaseTy, Builder.IsZeroInitializable);
+ new CGRecordLayout(Ty, BaseTy, Builder.IsZeroInitializable,
+ Builder.IsZeroInitializableAsBase);
- // Add all the non-virtual base field numbers.
- RL->NonVirtualBaseFields.insert(Builder.LLVMNonVirtualBases.begin(),
- Builder.LLVMNonVirtualBases.end());
+ RL->NonVirtualBases.swap(Builder.NonVirtualBases);
+ RL->CompleteObjectVirtualBases.swap(Builder.VirtualBases);
// Add all the field numbers.
- RL->FieldInfo.insert(Builder.LLVMFields.begin(),
- Builder.LLVMFields.end());
+ RL->FieldInfo.swap(Builder.Fields);
// Add bitfield info.
- RL->BitFields.insert(Builder.LLVMBitFields.begin(),
- Builder.LLVMBitFields.end());
+ RL->BitFields.swap(Builder.BitFields);
// Dump the layout, if requested.
if (getContext().getLangOptions().DumpRecordLayouts) {
@@ -913,9 +901,9 @@ CGRecordLayout *CodeGenTypes::ComputeRecordLayout(const RecordDecl *D) {
void CGRecordLayout::print(llvm::raw_ostream &OS) const {
OS << "<CGRecordLayout\n";
- OS << " LLVMType:" << *LLVMType << "\n";
- if (NonVirtualBaseLLVMType)
- OS << " NonVirtualBaseLLVMType:" << *NonVirtualBaseLLVMType << "\n";
+ OS << " LLVMType:" << *CompleteObjectType << "\n";
+ if (BaseSubobjectType)
+ OS << " NonVirtualBaseLLVMType:" << *BaseSubobjectType << "\n";
OS << " IsZeroInitializable:" << IsZeroInitializable << "\n";
OS << " BitFields:[\n";