[cfe-commits] r125555 - in /cfe/trunk: lib/CodeGen/CGExprConstant.cpp lib/CodeGen/CGRecordLayout.h lib/CodeGen/CGRecordLayoutBuilder.cpp test/CodeGenCXX/pointers-to-data-members.cpp
John McCall
rjmccall at apple.com
Mon Feb 14 22:40:56 PST 2011
Author: rjmccall
Date: Tue Feb 15 00:40:56 2011
New Revision: 125555
URL: http://llvm.org/viewvc/llvm-project?rev=125555&view=rev
Log:
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.
Modified:
cfe/trunk/lib/CodeGen/CGExprConstant.cpp
cfe/trunk/lib/CodeGen/CGRecordLayout.h
cfe/trunk/lib/CodeGen/CGRecordLayoutBuilder.cpp
cfe/trunk/test/CodeGenCXX/pointers-to-data-members.cpp
Modified: cfe/trunk/lib/CodeGen/CGExprConstant.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGExprConstant.cpp?rev=125555&r1=125554&r2=125555&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGExprConstant.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGExprConstant.cpp Tue Feb 15 00:40:56 2011
@@ -1036,87 +1036,122 @@
}
}
-static llvm::Constant *EmitNullConstant(CodeGenModule &CGM,
- const CXXRecordDecl *RD) {
- QualType T = CGM.getContext().getTagDeclType(RD);
-
- const llvm::StructType *STy =
- cast<llvm::StructType>(CGM.getTypes().ConvertTypeForMem(T));
- unsigned NumElements = STy->getNumElements();
- std::vector<llvm::Constant *> Elements(NumElements);
-
- const CGRecordLayout &Layout = CGM.getTypes().getCGRecordLayout(RD);
+static llvm::Constant *EmitNullConstantForBase(CodeGenModule &CGM,
+ const llvm::Type *baseType,
+ const CXXRecordDecl *base);
- for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(),
- E = RD->bases_end(); I != E; ++I) {
+static llvm::Constant *EmitNullConstant(CodeGenModule &CGM,
+ const CXXRecordDecl *record,
+ bool asCompleteObject) {
+ const CGRecordLayout &layout = CGM.getTypes().getCGRecordLayout(record);
+ const llvm::StructType *structure =
+ (asCompleteObject ? layout.getLLVMType()
+ : layout.getBaseSubobjectLLVMType());
+
+ unsigned numElements = structure->getNumElements();
+ std::vector<llvm::Constant *> elements(numElements);
+
+ // Fill in all the bases.
+ for (CXXRecordDecl::base_class_const_iterator
+ I = record->bases_begin(), E = record->bases_end(); I != E; ++I) {
if (I->isVirtual()) {
- // Ignore virtual bases.
+ // Ignore virtual bases; if we're laying out for a complete
+ // object, we'll lay these out later.
continue;
}
- const CXXRecordDecl *BaseDecl =
- cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl());
+ const CXXRecordDecl *base =
+ cast<CXXRecordDecl>(I->getType()->castAs<RecordType>()->getDecl());
// Ignore empty bases.
- if (BaseDecl->isEmpty())
+ if (base->isEmpty())
continue;
- // Ignore bases that don't have any pointer to data members.
- if (CGM.getTypes().isZeroInitializable(BaseDecl))
- continue;
-
- unsigned BaseFieldNo = Layout.getNonVirtualBaseLLVMFieldNo(BaseDecl);
- const llvm::Type *BaseTy = STy->getElementType(BaseFieldNo);
-
- if (isa<llvm::StructType>(BaseTy)) {
- // We can just emit the base as a null constant.
- Elements[BaseFieldNo] = EmitNullConstant(CGM, BaseDecl);
- continue;
- }
-
- // Some bases are represented as arrays of i8 if the size of the
- // base is smaller than its corresponding LLVM type.
- // Figure out how many elements this base array has.
- const llvm::ArrayType *BaseArrayTy = cast<llvm::ArrayType>(BaseTy);
- unsigned NumBaseElements = BaseArrayTy->getNumElements();
-
- // Fill in null data member pointers.
- std::vector<llvm::Constant *> BaseElements(NumBaseElements);
- FillInNullDataMemberPointers(CGM, I->getType(), BaseElements, 0);
-
- // Now go through all other elements and zero them out.
- if (NumBaseElements) {
- const llvm::Type* Int8Ty = llvm::Type::getInt8Ty(CGM.getLLVMContext());
- llvm::Constant *Zero = llvm::Constant::getNullValue(Int8Ty);
- for (unsigned I = 0; I != NumBaseElements; ++I) {
- if (!BaseElements[I])
- BaseElements[I] = Zero;
- }
- }
-
- Elements[BaseFieldNo] = llvm::ConstantArray::get(BaseArrayTy, BaseElements);
+ unsigned fieldIndex = layout.getNonVirtualBaseLLVMFieldNo(base);
+ const llvm::Type *baseType = structure->getElementType(fieldIndex);
+ elements[fieldIndex] = EmitNullConstantForBase(CGM, baseType, base);
}
- // Visit all fields.
- for (RecordDecl::field_iterator I = RD->field_begin(), E = RD->field_end();
- I != E; ++I) {
- const FieldDecl *FD = *I;
+ // Fill in all the fields.
+ for (RecordDecl::field_iterator I = record->field_begin(),
+ E = record->field_end(); I != E; ++I) {
+ const FieldDecl *field = *I;
// Ignore bit fields.
- if (FD->isBitField())
+ if (field->isBitField())
continue;
- unsigned FieldNo = Layout.getLLVMFieldNo(FD);
- Elements[FieldNo] = CGM.EmitNullConstant(FD->getType());
+ unsigned fieldIndex = layout.getLLVMFieldNo(field);
+ elements[fieldIndex] = CGM.EmitNullConstant(field->getType());
+ }
+
+ // Fill in the virtual bases, if we're working with the complete object.
+ if (asCompleteObject) {
+ for (CXXRecordDecl::base_class_const_iterator
+ I = record->vbases_begin(), E = record->vbases_end(); I != E; ++I) {
+ const CXXRecordDecl *base =
+ cast<CXXRecordDecl>(I->getType()->castAs<RecordType>()->getDecl());
+
+ // Ignore empty bases.
+ if (base->isEmpty())
+ continue;
+
+ unsigned fieldIndex = layout.getVirtualBaseIndex(base);
+
+ // We might have already laid this field out.
+ if (elements[fieldIndex]) continue;
+
+ const llvm::Type *baseType = structure->getElementType(fieldIndex);
+ elements[fieldIndex] = EmitNullConstantForBase(CGM, baseType, base);
+ }
}
// Now go through all other fields and zero them out.
- for (unsigned i = 0; i != NumElements; ++i) {
- if (!Elements[i])
- Elements[i] = llvm::Constant::getNullValue(STy->getElementType(i));
+ for (unsigned i = 0; i != numElements; ++i) {
+ if (!elements[i])
+ elements[i] = llvm::Constant::getNullValue(structure->getElementType(i));
}
- return llvm::ConstantStruct::get(STy, Elements);
+ return llvm::ConstantStruct::get(structure, elements);
+}
+
+/// Emit the null constant for a base subobject.
+static llvm::Constant *EmitNullConstantForBase(CodeGenModule &CGM,
+ const llvm::Type *baseType,
+ const CXXRecordDecl *base) {
+ const CGRecordLayout &baseLayout = CGM.getTypes().getCGRecordLayout(base);
+
+ // Just zero out bases that don't have any pointer to data members.
+ if (baseLayout.isZeroInitializableAsBase())
+ return llvm::Constant::getNullValue(baseType);
+
+ // If the base type is a struct, we can just use its null constant.
+ if (isa<llvm::StructType>(baseType)) {
+ return EmitNullConstant(CGM, base, /*complete*/ false);
+ }
+
+ // Otherwise, some bases are represented as arrays of i8 if the size
+ // of the base is smaller than its corresponding LLVM type. Figure
+ // out how many elements this base array has.
+ const llvm::ArrayType *baseArrayType = cast<llvm::ArrayType>(baseType);
+ unsigned numBaseElements = baseArrayType->getNumElements();
+
+ // Fill in null data member pointers.
+ std::vector<llvm::Constant *> baseElements(numBaseElements);
+ FillInNullDataMemberPointers(CGM, CGM.getContext().getTypeDeclType(base),
+ baseElements, 0);
+
+ // Now go through all other elements and zero them out.
+ if (numBaseElements) {
+ const llvm::Type *i8 = llvm::Type::getInt8Ty(CGM.getLLVMContext());
+ llvm::Constant *i8_zero = llvm::Constant::getNullValue(i8);
+ for (unsigned i = 0; i != numBaseElements; ++i) {
+ if (!baseElements[i])
+ baseElements[i] = i8_zero;
+ }
+ }
+
+ return llvm::ConstantArray::get(baseArrayType, baseElements);
}
llvm::Constant *CodeGenModule::EmitNullConstant(QualType T) {
@@ -1140,7 +1175,7 @@
if (const RecordType *RT = T->getAs<RecordType>()) {
const CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl());
- return ::EmitNullConstant(*this, RD);
+ return ::EmitNullConstant(*this, RD, /*complete object*/ true);
}
assert(T->isMemberPointerType() && "Should only see member pointers here!");
Modified: cfe/trunk/lib/CodeGen/CGRecordLayout.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGRecordLayout.h?rev=125555&r1=125554&r2=125555&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGRecordLayout.h (original)
+++ cfe/trunk/lib/CodeGen/CGRecordLayout.h Tue Feb 15 00:40:56 2011
@@ -173,12 +173,13 @@
void operator=(const CGRecordLayout&); // DO NOT IMPLEMENT
private:
- /// The LLVM type corresponding to this record layout.
- llvm::PATypeHolder LLVMType;
-
- /// The LLVM type for the non-virtual part of this record layout, used for
- /// laying out the record as a base.
- llvm::PATypeHolder NonVirtualBaseLLVMType;
+ /// The LLVM type corresponding to this record layout; used when
+ /// laying it out as a complete object.
+ llvm::PATypeHolder CompleteObjectType;
+
+ /// The LLVM type for the non-virtual part of this record layout;
+ /// used when laying it out as a base subobject.
+ llvm::PATypeHolder BaseSubobjectType;
/// Map from (non-bit-field) struct field to the corresponding llvm struct
/// type field no. This info is populated by record builder.
@@ -190,26 +191,41 @@
// FIXME: Maybe we could use a CXXBaseSpecifier as the key and use a single
// map for both virtual and non virtual bases.
- llvm::DenseMap<const CXXRecordDecl *, unsigned> NonVirtualBaseFields;
+ llvm::DenseMap<const CXXRecordDecl *, unsigned> NonVirtualBases;
+
+ /// Map from virtual bases to their field index in the complete object.
+ llvm::DenseMap<const CXXRecordDecl *, unsigned> CompleteObjectVirtualBases;
- /// Whether one of the fields in this record layout is a pointer to data
- /// member, or a struct that contains pointer to data member.
+ /// False if any direct or indirect subobject of this class, when
+ /// considered as a complete object, requires a non-zero bitpattern
+ /// when zero-initialized.
bool IsZeroInitializable : 1;
+ /// False if any direct or indirect subobject of this class, when
+ /// considered as a base subobject, requires a non-zero bitpattern
+ /// when zero-initialized.
+ bool IsZeroInitializableAsBase : 1;
+
public:
- CGRecordLayout(const llvm::StructType *LLVMType,
- const llvm::StructType *NonVirtualBaseLLVMType,
- bool IsZeroInitializable)
- : LLVMType(LLVMType), NonVirtualBaseLLVMType(NonVirtualBaseLLVMType),
- IsZeroInitializable(IsZeroInitializable) {}
+ CGRecordLayout(const llvm::StructType *CompleteObjectType,
+ const llvm::StructType *BaseSubobjectType,
+ bool IsZeroInitializable,
+ bool IsZeroInitializableAsBase)
+ : CompleteObjectType(CompleteObjectType),
+ BaseSubobjectType(BaseSubobjectType),
+ IsZeroInitializable(IsZeroInitializable),
+ IsZeroInitializableAsBase(IsZeroInitializableAsBase) {}
- /// \brief Return the LLVM type associated with this record.
+ /// \brief Return the "complete object" LLVM type associated with
+ /// this record.
const llvm::StructType *getLLVMType() const {
- return cast<llvm::StructType>(LLVMType.get());
+ return cast<llvm::StructType>(CompleteObjectType.get());
}
- const llvm::StructType *getNonVirtualBaseLLVMType() const {
- return cast<llvm::StructType>(NonVirtualBaseLLVMType.get());
+ /// \brief Return the "base subobject" LLVM type associated with
+ /// this record.
+ const llvm::StructType *getBaseSubobjectLLVMType() const {
+ return cast<llvm::StructType>(BaseSubobjectType.get());
}
/// \brief Check whether this struct can be C++ zero-initialized
@@ -218,6 +234,12 @@
return IsZeroInitializable;
}
+ /// \brief Check whether this struct can be C++ zero-initialized
+ /// with a zeroinitializer when considered as a base subobject.
+ bool isZeroInitializableAsBase() const {
+ return IsZeroInitializableAsBase;
+ }
+
/// \brief Return llvm::StructType element number that corresponds to the
/// field FD.
unsigned getLLVMFieldNo(const FieldDecl *FD) const {
@@ -227,8 +249,15 @@
}
unsigned getNonVirtualBaseLLVMFieldNo(const CXXRecordDecl *RD) const {
- assert(NonVirtualBaseFields.count(RD) && "Invalid non-virtual base!");
- return NonVirtualBaseFields.lookup(RD);
+ assert(NonVirtualBases.count(RD) && "Invalid non-virtual base!");
+ return NonVirtualBases.lookup(RD);
+ }
+
+ /// \brief Return the LLVM field index corresponding to the given
+ /// virtual base. Only valid when operating on the complete object.
+ unsigned getVirtualBaseIndex(const CXXRecordDecl *base) const {
+ assert(CompleteObjectVirtualBases.count(base) && "Invalid virtual base!");
+ return CompleteObjectVirtualBases.lookup(base);
}
/// \brief Return the BitFieldInfo that corresponds to the field FD.
@@ -236,7 +265,7 @@
assert(FD->isBitField() && "Invalid call for non bit-field decl!");
llvm::DenseMap<const FieldDecl *, CGBitFieldInfo>::const_iterator
it = BitFields.find(FD);
- assert(it != BitFields.end() && "Unable to find bitfield info");
+ assert(it != BitFields.end() && "Unable to find bitfield info");
return it->second;
}
Modified: cfe/trunk/lib/CodeGen/CGRecordLayoutBuilder.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGRecordLayoutBuilder.cpp?rev=125555&r1=125554&r2=125555&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGRecordLayoutBuilder.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGRecordLayoutBuilder.cpp Tue Feb 15 00:40:56 2011
@@ -33,9 +33,10 @@
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 @@
///
/// 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;
-
- /// LLVMBitFieldInfo - Holds location and size information about a bit field.
- typedef std::pair<const FieldDecl *, CGBitFieldInfo> LLVMBitFieldInfo;
- llvm::SmallVector<LLVMBitFieldInfo, 16> LLVMBitFields;
+ /// FieldInfo - Holds a field and its corresponding LLVM field number.
+ llvm::DenseMap<const FieldDecl *, unsigned> Fields;
+
+ /// 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 @@
/// 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 @@
/// 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 @@
/// 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 @@
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 @@
}
// 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 @@
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 @@
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 @@
AppendPadding(RecordSize, Align);
}
-void CGRecordLayoutBuilder::LayoutBase(const CXXRecordDecl *BaseDecl,
- uint64_t BaseOffset) {
- CheckZeroInitializable(BaseDecl);
-
- 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());
+void CGRecordLayoutBuilder::LayoutBase(const CXXRecordDecl *base,
+ uint64_t baseOffsetInBits) {
+ uint64_t baseOffsetInBytes = baseOffsetInBits / 8;
+ AppendPadding(baseOffsetInBytes, 1);
+
+ 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;
+
+ const CGRecordLayout &baseLayout = Types.getCGRecordLayout(base);
+ if (IsZeroInitializable)
+ IsZeroInitializable = baseLayout.isZeroInitializableAsBase();
- // FIXME: Add the vbase field info.
+ LayoutBase(base, baseOffsetInBits);
+ VirtualBases[base] = (FieldTypes.size() - 1);
}
/// LayoutVirtualBases - layout the non-virtual bases of a record decl.
@@ -561,18 +570,6 @@
}
}
-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 @@
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.
+ }
- NonVirtualBaseFieldTypes = FieldTypes;
+ bool needsPadding = (AlignedNonVirtualTypeSize != AlignedNextFieldOffset);
+ if (needsPadding) {
+ uint64_t NumBytes = AlignedNonVirtualTypeSize - AlignedNextFieldOffset;
+ FieldTypes.push_back(getByteArrayType(NumBytes));
+ }
- if (AlignedNonVirtualTypeSize == AlignedNextFieldOffset) {
- // We don't need any padding.
- return true;
+ BaseSubobjectType = llvm::StructType::get(Types.getLLVMContext(),
+ FieldTypes, Packed);
+
+ 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 @@
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 @@
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 @@
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";
Modified: cfe/trunk/test/CodeGenCXX/pointers-to-data-members.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/pointers-to-data-members.cpp?rev=125555&r1=125554&r2=125555&view=diff
==============================================================================
--- cfe/trunk/test/CodeGenCXX/pointers-to-data-members.cpp (original)
+++ cfe/trunk/test/CodeGenCXX/pointers-to-data-members.cpp Tue Feb 15 00:40:56 2011
@@ -1,37 +1,41 @@
-// RUN: %clang_cc1 %s -emit-llvm -o - -triple=x86_64-apple-darwin10 | FileCheck %s
-// RUN: %clang_cc1 %s -emit-llvm -o - -triple=x86_64-apple-darwin10 -O3 | FileCheck --check-prefix=CHECK-O3 %s
+// RUN: %clang_cc1 %s -emit-llvm -o %t.ll -triple=x86_64-apple-darwin10
+// RUN: FileCheck %s < %t.ll
+// RUN: FileCheck -check-prefix=CHECK-GLOBAL %s < %t.ll
+// RUN: %clang_cc1 %s -emit-llvm -o %t-opt.ll -triple=x86_64-apple-darwin10 -O3
+// RUN: FileCheck --check-prefix=CHECK-O3 %s < %t-opt.ll
+
struct A { int a; int b; };
struct B { int b; };
struct C : B, A { };
// Zero init.
namespace ZeroInit {
- // CHECK: @_ZN8ZeroInit1aE = global i64 -1
+ // CHECK-GLOBAL: @_ZN8ZeroInit1aE = global i64 -1
int A::* a;
- // CHECK: @_ZN8ZeroInit2aaE = global [2 x i64] [i64 -1, i64 -1]
+ // CHECK-GLOBAL: @_ZN8ZeroInit2aaE = global [2 x i64] [i64 -1, i64 -1]
int A::* aa[2];
- // CHECK: @_ZN8ZeroInit3aaaE = global [2 x [2 x i64]] {{\[}}[2 x i64] [i64 -1, i64 -1], [2 x i64] [i64 -1, i64 -1]]
+ // CHECK-GLOBAL: @_ZN8ZeroInit3aaaE = global [2 x [2 x i64]] {{\[}}[2 x i64] [i64 -1, i64 -1], [2 x i64] [i64 -1, i64 -1]]
int A::* aaa[2][2];
- // CHECK: @_ZN8ZeroInit1bE = global i64 -1,
+ // CHECK-GLOBAL: @_ZN8ZeroInit1bE = global i64 -1,
int A::* b = 0;
- // CHECK: @_ZN8ZeroInit2saE = internal global %struct.anon { i64 -1 }
+ // CHECK-GLOBAL: @_ZN8ZeroInit2saE = internal global %struct.anon { i64 -1 }
struct {
int A::*a;
} sa;
void test_sa() { (void) sa; } // force emission
- // CHECK: @_ZN8ZeroInit3ssaE = internal
- // CHECK: [2 x i64] [i64 -1, i64 -1]
+ // CHECK-GLOBAL: @_ZN8ZeroInit3ssaE = internal
+ // CHECK-GLOBAL: [2 x i64] [i64 -1, i64 -1]
struct {
int A::*aa[2];
} ssa[2];
void test_ssa() { (void) ssa; }
- // CHECK: @_ZN8ZeroInit2ssE = internal global %1 { %struct.anon { i64 -1 } }
+ // CHECK-GLOBAL: @_ZN8ZeroInit2ssE = internal global %1 { %struct.anon { i64 -1 } }
struct {
struct {
int A::*pa;
@@ -51,13 +55,13 @@
};
struct C : A, B { int j; };
- // CHECK: @_ZN8ZeroInit1cE = global %"struct.ZeroInit::C" { [16 x i8] c"\FF\FF\FF\FF\FF\FF\FF\FF\00\00\00\00\00\00\00\00", [176 x i8] c"\FF\FF\FF\FF\FF\FF\FF\FF\00\00\00\00\00\00\00\00\FF\FF\FF\FF\FF\FF\FF\FF\00\00\00\00\00\00\00\00\FF\FF\FF\FF\FF\FF\FF\FF\00\00\00\00\00\00\00\00\FF\FF\FF\FF\FF\FF\FF\FF\00\00\00\00\00\00\00\00\FF\FF\FF\FF\FF\FF\FF\FF\00\00\00\00\00\00\00\00\FF\FF\FF\FF\FF\FF\FF\FF\00\00\00\00\00\00\00\00\FF\FF\FF\FF\FF\FF\FF\FF\00\00\00\00\00\00\00\00\FF\FF\FF\FF\FF\FF\FF\FF\00\00\00\00\00\00\00\00\FF\FF\FF\FF\FF\FF\FF\FF\00\00\00\00\00\00\00\00\FF\FF\FF\FF\FF\FF\FF\FF\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\FF\FF\FF\FF\FF\FF\FF\FF", i32 0, [4 x i8] zeroinitializer }
+ // CHECK-GLOBAL: @_ZN8ZeroInit1cE = global {{%.*}} { [16 x i8] c"\FF\FF\FF\FF\FF\FF\FF\FF\00\00\00\00\00\00\00\00", [176 x i8] c"\FF\FF\FF\FF\FF\FF\FF\FF\00\00\00\00\00\00\00\00\FF\FF\FF\FF\FF\FF\FF\FF\00\00\00\00\00\00\00\00\FF\FF\FF\FF\FF\FF\FF\FF\00\00\00\00\00\00\00\00\FF\FF\FF\FF\FF\FF\FF\FF\00\00\00\00\00\00\00\00\FF\FF\FF\FF\FF\FF\FF\FF\00\00\00\00\00\00\00\00\FF\FF\FF\FF\FF\FF\FF\FF\00\00\00\00\00\00\00\00\FF\FF\FF\FF\FF\FF\FF\FF\00\00\00\00\00\00\00\00\FF\FF\FF\FF\FF\FF\FF\FF\00\00\00\00\00\00\00\00\FF\FF\FF\FF\FF\FF\FF\FF\00\00\00\00\00\00\00\00\FF\FF\FF\FF\FF\FF\FF\FF\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\FF\FF\FF\FF\FF\FF\FF\FF", i32 0, [4 x i8] zeroinitializer }
C c;
}
// PR5674
namespace PR5674 {
- // CHECK: @_ZN6PR56742pbE = global i64 4
+ // CHECK-GLOBAL: @_ZN6PR56742pbE = global i64 4
int A::*pb = &A::b;
}
@@ -168,15 +172,15 @@
int A::*i;
};
-// FIXME: A::i should be initialized to -1 here.
+// CHECK-GLOBAL: @_ZN12VirtualBases1bE = global {{%.*}} { i32 (...)** null, [16 x i8] c"\00\00\00\00\00\00\00\00\FF\FF\FF\FF\FF\FF\FF\FF" }
struct B : virtual A { };
B b;
-// FIXME: A::i should be initialized to -1 here.
+// CHECK-GLOBAL: @_ZN12VirtualBases1cE = global {{%.*}} { i32 (...)** null, i64 -1, [16 x i8] c"\00\00\00\00\00\00\00\00\FF\FF\FF\FF\FF\FF\FF\FF" }
struct C : virtual A { int A::*i; };
C c;
-// FIXME: C::A::i should be initialized to -1 here.
+ // CHECK-GLOBAL: @_ZN12VirtualBases1dE = global {{%.*}} { [16 x i8] c"\00\00\00\00\00\00\00\00\FF\FF\FF\FF\FF\FF\FF\FF", i64 -1, [16 x i8] c"\00\00\00\00\00\00\00\00\FF\FF\FF\FF\FF\FF\FF\FF" }
struct D : C { int A::*i; };
D d;
@@ -217,3 +221,12 @@
}
+namespace test4 {
+ struct A { int A_i; };
+ struct B : virtual A { int A::*B_p; };
+ struct C : virtual B { int *C_p; };
+ struct D : C { int *D_p; };
+
+ // CHECK-GLOBAL: @_ZN5test41dE = global {{%.*}} { [16 x i8] zeroinitializer, i32* null, [16 x i8] c"\00\00\00\00\00\00\00\00\FF\FF\FF\FF\FF\FF\FF\FF", [4 x i8] zeroinitializer }
+ D d;
+}
More information about the cfe-commits
mailing list