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.

llvm-svn: 125555
This commit is contained in:
John McCall 2011-02-15 06:40:56 +00:00
parent 98196b4ebb
commit 0217dfc2ba
4 changed files with 277 additions and 212 deletions

View File

@ -1036,87 +1036,122 @@ FillInNullDataMemberPointers(CodeGenModule &CGM, QualType T,
} }
} }
static llvm::Constant *EmitNullConstantForBase(CodeGenModule &CGM,
const llvm::Type *baseType,
const CXXRecordDecl *base);
static llvm::Constant *EmitNullConstant(CodeGenModule &CGM, static llvm::Constant *EmitNullConstant(CodeGenModule &CGM,
const CXXRecordDecl *RD) { const CXXRecordDecl *record,
QualType T = CGM.getContext().getTagDeclType(RD); bool asCompleteObject) {
const CGRecordLayout &layout = CGM.getTypes().getCGRecordLayout(record);
const llvm::StructType *structure =
(asCompleteObject ? layout.getLLVMType()
: layout.getBaseSubobjectLLVMType());
const llvm::StructType *STy = unsigned numElements = structure->getNumElements();
cast<llvm::StructType>(CGM.getTypes().ConvertTypeForMem(T)); std::vector<llvm::Constant *> elements(numElements);
unsigned NumElements = STy->getNumElements();
std::vector<llvm::Constant *> Elements(NumElements);
const CGRecordLayout &Layout = CGM.getTypes().getCGRecordLayout(RD); // Fill in all the bases.
for (CXXRecordDecl::base_class_const_iterator
for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(), I = record->bases_begin(), E = record->bases_end(); I != E; ++I) {
E = RD->bases_end(); I != E; ++I) {
if (I->isVirtual()) { 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; continue;
} }
const CXXRecordDecl *BaseDecl = const CXXRecordDecl *base =
cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl()); cast<CXXRecordDecl>(I->getType()->castAs<RecordType>()->getDecl());
// Ignore empty bases. // Ignore empty bases.
if (BaseDecl->isEmpty()) if (base->isEmpty())
continue; continue;
// Ignore bases that don't have any pointer to data members. unsigned fieldIndex = layout.getNonVirtualBaseLLVMFieldNo(base);
if (CGM.getTypes().isZeroInitializable(BaseDecl)) const llvm::Type *baseType = structure->getElementType(fieldIndex);
continue; elements[fieldIndex] = EmitNullConstantForBase(CGM, baseType, base);
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 // Fill in all the fields.
// base is smaller than its corresponding LLVM type. for (RecordDecl::field_iterator I = record->field_begin(),
// Figure out how many elements this base array has. E = record->field_end(); I != E; ++I) {
const llvm::ArrayType *BaseArrayTy = cast<llvm::ArrayType>(BaseTy); const FieldDecl *field = *I;
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);
}
// Visit all fields.
for (RecordDecl::field_iterator I = RD->field_begin(), E = RD->field_end();
I != E; ++I) {
const FieldDecl *FD = *I;
// Ignore bit fields. // Ignore bit fields.
if (FD->isBitField()) if (field->isBitField())
continue; continue;
unsigned FieldNo = Layout.getLLVMFieldNo(FD); unsigned fieldIndex = layout.getLLVMFieldNo(field);
Elements[FieldNo] = CGM.EmitNullConstant(FD->getType()); 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. // Now go through all other fields and zero them out.
for (unsigned i = 0; i != NumElements; ++i) { for (unsigned i = 0; i != numElements; ++i) {
if (!Elements[i]) if (!elements[i])
Elements[i] = llvm::Constant::getNullValue(STy->getElementType(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) { llvm::Constant *CodeGenModule::EmitNullConstant(QualType T) {
@ -1140,7 +1175,7 @@ llvm::Constant *CodeGenModule::EmitNullConstant(QualType T) {
if (const RecordType *RT = T->getAs<RecordType>()) { if (const RecordType *RT = T->getAs<RecordType>()) {
const CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl()); 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!"); assert(T->isMemberPointerType() && "Should only see member pointers here!");

View File

@ -173,12 +173,13 @@ class CGRecordLayout {
void operator=(const CGRecordLayout&); // DO NOT IMPLEMENT void operator=(const CGRecordLayout&); // DO NOT IMPLEMENT
private: private:
/// The LLVM type corresponding to this record layout. /// The LLVM type corresponding to this record layout; used when
llvm::PATypeHolder LLVMType; /// laying it out as a complete object.
llvm::PATypeHolder CompleteObjectType;
/// The LLVM type for the non-virtual part of this record layout, used for /// The LLVM type for the non-virtual part of this record layout;
/// laying out the record as a base. /// used when laying it out as a base subobject.
llvm::PATypeHolder NonVirtualBaseLLVMType; llvm::PATypeHolder BaseSubobjectType;
/// Map from (non-bit-field) struct field to the corresponding llvm struct /// Map from (non-bit-field) struct field to the corresponding llvm struct
/// type field no. This info is populated by record builder. /// type field no. This info is populated by record builder.
@ -190,26 +191,41 @@ private:
// FIXME: Maybe we could use a CXXBaseSpecifier as the key and use a single // FIXME: Maybe we could use a CXXBaseSpecifier as the key and use a single
// map for both virtual and non virtual bases. // map for both virtual and non virtual bases.
llvm::DenseMap<const CXXRecordDecl *, unsigned> NonVirtualBaseFields; llvm::DenseMap<const CXXRecordDecl *, unsigned> NonVirtualBases;
/// Whether one of the fields in this record layout is a pointer to data /// Map from virtual bases to their field index in the complete object.
/// member, or a struct that contains pointer to data member. llvm::DenseMap<const CXXRecordDecl *, unsigned> CompleteObjectVirtualBases;
/// 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; bool IsZeroInitializable : 1;
public: /// False if any direct or indirect subobject of this class, when
CGRecordLayout(const llvm::StructType *LLVMType, /// considered as a base subobject, requires a non-zero bitpattern
const llvm::StructType *NonVirtualBaseLLVMType, /// when zero-initialized.
bool IsZeroInitializable) bool IsZeroInitializableAsBase : 1;
: LLVMType(LLVMType), NonVirtualBaseLLVMType(NonVirtualBaseLLVMType),
IsZeroInitializable(IsZeroInitializable) {}
/// \brief Return the LLVM type associated with this record. public:
CGRecordLayout(const llvm::StructType *CompleteObjectType,
const llvm::StructType *BaseSubobjectType,
bool IsZeroInitializable,
bool IsZeroInitializableAsBase)
: CompleteObjectType(CompleteObjectType),
BaseSubobjectType(BaseSubobjectType),
IsZeroInitializable(IsZeroInitializable),
IsZeroInitializableAsBase(IsZeroInitializableAsBase) {}
/// \brief Return the "complete object" LLVM type associated with
/// this record.
const llvm::StructType *getLLVMType() const { const llvm::StructType *getLLVMType() const {
return cast<llvm::StructType>(LLVMType.get()); return cast<llvm::StructType>(CompleteObjectType.get());
} }
const llvm::StructType *getNonVirtualBaseLLVMType() const { /// \brief Return the "base subobject" LLVM type associated with
return cast<llvm::StructType>(NonVirtualBaseLLVMType.get()); /// this record.
const llvm::StructType *getBaseSubobjectLLVMType() const {
return cast<llvm::StructType>(BaseSubobjectType.get());
} }
/// \brief Check whether this struct can be C++ zero-initialized /// \brief Check whether this struct can be C++ zero-initialized
@ -218,6 +234,12 @@ public:
return IsZeroInitializable; 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 /// \brief Return llvm::StructType element number that corresponds to the
/// field FD. /// field FD.
unsigned getLLVMFieldNo(const FieldDecl *FD) const { unsigned getLLVMFieldNo(const FieldDecl *FD) const {
@ -227,8 +249,15 @@ public:
} }
unsigned getNonVirtualBaseLLVMFieldNo(const CXXRecordDecl *RD) const { unsigned getNonVirtualBaseLLVMFieldNo(const CXXRecordDecl *RD) const {
assert(NonVirtualBaseFields.count(RD) && "Invalid non-virtual base!"); assert(NonVirtualBases.count(RD) && "Invalid non-virtual base!");
return NonVirtualBaseFields.lookup(RD); 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. /// \brief Return the BitFieldInfo that corresponds to the field FD.

View File

@ -33,9 +33,10 @@ namespace {
class CGRecordLayoutBuilder { class CGRecordLayoutBuilder {
public: public:
/// FieldTypes - Holds the LLVM types that the struct is created from. /// FieldTypes - Holds the LLVM types that the struct is created from.
///
std::vector<const llvm::Type *> FieldTypes; 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: /// of the struct. For example, consider:
/// ///
/// struct A { int i; }; /// struct A { int i; };
@ -47,22 +48,19 @@ public:
/// ///
/// And the LLVM type of the non-virtual base struct will be /// And the LLVM type of the non-virtual base struct will be
/// %struct.C.base = type { i32 (...)**, %struct.A, i32 } /// %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 /// FieldInfo - Holds a field and its corresponding LLVM field number.
/// the struct is equivalent to the complete struct. llvm::DenseMap<const FieldDecl *, unsigned> Fields;
bool NonVirtualBaseTypeIsSameAsCompleteType;
/// LLVMFieldInfo - Holds a field and its corresponding LLVM field number. /// BitFieldInfo - Holds location and size information about a bit field.
typedef std::pair<const FieldDecl *, unsigned> LLVMFieldInfo; llvm::DenseMap<const FieldDecl *, CGBitFieldInfo> BitFields;
llvm::SmallVector<LLVMFieldInfo, 16> LLVMFields;
/// LLVMBitFieldInfo - Holds location and size information about a bit field. llvm::DenseMap<const CXXRecordDecl *, unsigned> NonVirtualBases;
typedef std::pair<const FieldDecl *, CGBitFieldInfo> LLVMBitFieldInfo; llvm::DenseMap<const CXXRecordDecl *, unsigned> VirtualBases;
llvm::SmallVector<LLVMBitFieldInfo, 16> LLVMBitFields;
typedef std::pair<const CXXRecordDecl *, unsigned> LLVMBaseInfo;
llvm::SmallVector<LLVMBaseInfo, 16> LLVMNonVirtualBases;
/// IndirectPrimaryBases - Virtual base classes, direct or indirect, that are /// IndirectPrimaryBases - Virtual base classes, direct or indirect, that are
/// primary base classes for some other direct or indirect base class. /// primary base classes for some other direct or indirect base class.
@ -75,6 +73,7 @@ public:
/// IsZeroInitializable - Whether this struct can be C++ /// IsZeroInitializable - Whether this struct can be C++
/// zero-initialized with an LLVM zeroinitializer. /// zero-initialized with an LLVM zeroinitializer.
bool IsZeroInitializable; bool IsZeroInitializable;
bool IsZeroInitializableAsBase;
/// Packed - Whether the resulting LLVM struct will be packed or not. /// Packed - Whether the resulting LLVM struct will be packed or not.
bool Packed; bool Packed;
@ -148,6 +147,7 @@ private:
/// AppendBytes - Append a given number of bytes to the record. /// AppendBytes - Append a given number of bytes to the record.
void AppendBytes(uint64_t NumBytes); void AppendBytes(uint64_t NumBytes);
void AppendBytes(CharUnits numBytes) { AppendBytes(numBytes.getQuantity()); }
/// AppendTailPadding - Append enough tail padding so that the type will have /// AppendTailPadding - Append enough tail padding so that the type will have
/// the passed size. /// the passed size.
@ -162,13 +162,13 @@ private:
/// CheckZeroInitializable - Check if the given type contains a pointer /// CheckZeroInitializable - Check if the given type contains a pointer
/// to data member. /// to data member.
void CheckZeroInitializable(QualType T); void CheckZeroInitializable(QualType T);
void CheckZeroInitializable(const CXXRecordDecl *RD);
public: public:
CGRecordLayoutBuilder(CodeGenTypes &Types) CGRecordLayoutBuilder(CodeGenTypes &Types)
: NonVirtualBaseTypeIsSameAsCompleteType(false), IsZeroInitializable(true), : BaseSubobjectType(0),
Packed(false), Types(Types), Alignment(0), BitsAvailableInLastField(0), IsZeroInitializable(true), IsZeroInitializableAsBase(true),
NextFieldOffsetInBytes(0) { } Packed(false), Types(Types), Alignment(0),
BitsAvailableInLastField(0), NextFieldOffsetInBytes(0) { }
/// Layout - Will layout a RecordDecl. /// Layout - Will layout a RecordDecl.
void Layout(const RecordDecl *D); void Layout(const RecordDecl *D);
@ -193,9 +193,10 @@ void CGRecordLayoutBuilder::Layout(const RecordDecl *D) {
Packed = true; Packed = true;
NextFieldOffsetInBytes = 0; NextFieldOffsetInBytes = 0;
FieldTypes.clear(); FieldTypes.clear();
LLVMFields.clear(); Fields.clear();
LLVMBitFields.clear(); BitFields.clear();
LLVMNonVirtualBases.clear(); NonVirtualBases.clear();
VirtualBases.clear();
LayoutFields(D); LayoutFields(D);
} }
@ -339,9 +340,8 @@ void CGRecordLayoutBuilder::LayoutBitField(const FieldDecl *D,
} }
// Add the bit field info. // Add the bit field info.
LLVMBitFields.push_back( BitFields.insert(std::make_pair(D,
LLVMBitFieldInfo(D, CGBitFieldInfo::MakeInfo(Types, D, FieldOffset, CGBitFieldInfo::MakeInfo(Types, D, FieldOffset, FieldSize)));
FieldSize)));
AppendBytes(NumBytesToAppend); AppendBytes(NumBytesToAppend);
@ -401,7 +401,7 @@ bool CGRecordLayoutBuilder::LayoutField(const FieldDecl *D,
AppendPadding(FieldOffsetInBytes, TypeAlignment); AppendPadding(FieldOffsetInBytes, TypeAlignment);
// Now append the field. // Now append the field.
LLVMFields.push_back(LLVMFieldInfo(D, FieldTypes.size())); Fields[D] = FieldTypes.size();
AppendField(FieldOffsetInBytes, Ty); AppendField(FieldOffsetInBytes, Ty);
return true; return true;
@ -426,14 +426,13 @@ CGRecordLayoutBuilder::LayoutUnionField(const FieldDecl *Field,
FieldTy = llvm::ArrayType::get(FieldTy, NumBytesToAppend); FieldTy = llvm::ArrayType::get(FieldTy, NumBytesToAppend);
// Add the bit field info. // Add the bit field info.
LLVMBitFields.push_back( BitFields.insert(std::make_pair(Field,
LLVMBitFieldInfo(Field, CGBitFieldInfo::MakeInfo(Types, Field, CGBitFieldInfo::MakeInfo(Types, Field, 0, FieldSize)));
0, FieldSize)));
return FieldTy; return FieldTy;
} }
// This is a regular union field. // This is a regular union field.
LLVMFields.push_back(LLVMFieldInfo(Field, 0)); Fields[Field] = 0;
return Types.ConvertTypeForMemRecursive(Field->getType()); return Types.ConvertTypeForMemRecursive(Field->getType());
} }
@ -495,41 +494,51 @@ void CGRecordLayoutBuilder::LayoutUnion(const RecordDecl *D) {
AppendPadding(RecordSize, Align); AppendPadding(RecordSize, Align);
} }
void CGRecordLayoutBuilder::LayoutBase(const CXXRecordDecl *BaseDecl, void CGRecordLayoutBuilder::LayoutBase(const CXXRecordDecl *base,
uint64_t BaseOffset) { uint64_t baseOffsetInBits) {
CheckZeroInitializable(BaseDecl); uint64_t baseOffsetInBytes = baseOffsetInBits / 8;
AppendPadding(baseOffsetInBytes, 1);
const ASTRecordLayout &Layout = const ASTRecordLayout &baseASTLayout
Types.getContext().getASTRecordLayout(BaseDecl); = Types.getContext().getASTRecordLayout(base);
CharUnits NonVirtualSize = Layout.getNonVirtualSize(); // 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());
}
AppendPadding(BaseOffset / 8, 1); void CGRecordLayoutBuilder::LayoutNonVirtualBase(const CXXRecordDecl *base,
uint64_t baseOffsetInBits) {
// Ignore empty bases.
if (base->isEmpty()) return;
// FIXME: Actually use a better type than [sizeof(BaseDecl) x i8] when we can. const CGRecordLayout &baseLayout = Types.getCGRecordLayout(base);
AppendBytes(NonVirtualSize.getQuantity()); if (IsZeroInitializableAsBase) {
assert(IsZeroInitializable &&
"class zero-initializable as base but not as complete object");
IsZeroInitializable = IsZeroInitializableAsBase =
baseLayout.isZeroInitializableAsBase();
}
LayoutBase(base, baseOffsetInBits);
NonVirtualBases[base] = (FieldTypes.size() - 1);
} }
void void
CGRecordLayoutBuilder::LayoutVirtualBase(const CXXRecordDecl *BaseDecl, CGRecordLayoutBuilder::LayoutVirtualBase(const CXXRecordDecl *base,
uint64_t BaseOffset) { uint64_t baseOffsetInBits) {
// Ignore empty bases. // Ignore empty bases.
if (BaseDecl->isEmpty()) if (base->isEmpty()) return;
return;
CheckZeroInitializable(BaseDecl); const CGRecordLayout &baseLayout = Types.getCGRecordLayout(base);
if (IsZeroInitializable)
IsZeroInitializable = baseLayout.isZeroInitializableAsBase();
const ASTRecordLayout &Layout = LayoutBase(base, baseOffsetInBits);
Types.getContext().getASTRecordLayout(BaseDecl); VirtualBases[base] = (FieldTypes.size() - 1);
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());
// FIXME: Add the vbase field info.
} }
/// LayoutVirtualBases - layout the non-virtual bases of a record decl. /// 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 void
CGRecordLayoutBuilder::LayoutNonVirtualBases(const CXXRecordDecl *RD, CGRecordLayoutBuilder::LayoutNonVirtualBases(const CXXRecordDecl *RD,
const ASTRecordLayout &Layout) { const ASTRecordLayout &Layout) {
@ -618,37 +615,40 @@ bool
CGRecordLayoutBuilder::ComputeNonVirtualBaseType(const CXXRecordDecl *RD) { CGRecordLayoutBuilder::ComputeNonVirtualBaseType(const CXXRecordDecl *RD) {
const ASTRecordLayout &Layout = Types.getContext().getASTRecordLayout(RD); const ASTRecordLayout &Layout = Types.getContext().getASTRecordLayout(RD);
CharUnits NonVirtualSize = Layout.getNonVirtualSize(); CharUnits NonVirtualSize = Layout.getNonVirtualSize();
CharUnits NonVirtualAlign = Layout.getNonVirtualAlign(); CharUnits NonVirtualAlign = Layout.getNonVirtualAlign();
uint64_t AlignedNonVirtualTypeSize = uint64_t AlignedNonVirtualTypeSize =
NonVirtualSize.RoundUpToAlignment(NonVirtualAlign).getQuantity(); NonVirtualSize.RoundUpToAlignment(NonVirtualAlign).getQuantity();
// First check if we can use the same fields as for the complete class. // First check if we can use the same fields as for the complete class.
uint64_t RecordSize = Layout.getSize().getQuantity(); uint64_t RecordSize = Layout.getSize().getQuantity();
if (AlignedNonVirtualTypeSize == RecordSize) { if (AlignedNonVirtualTypeSize == RecordSize)
NonVirtualBaseTypeIsSameAsCompleteType = true;
return true; return true;
}
// Check if we need padding. // Check if we need padding.
uint64_t AlignedNextFieldOffset = uint64_t AlignedNextFieldOffset =
llvm::RoundUpToAlignment(NextFieldOffsetInBytes, llvm::RoundUpToAlignment(NextFieldOffsetInBytes,
getAlignmentAsLLVMStruct()); getAlignmentAsLLVMStruct());
if (AlignedNextFieldOffset > AlignedNonVirtualTypeSize) if (AlignedNextFieldOffset > AlignedNonVirtualTypeSize) {
assert(!Packed && "cannot layout even as packed struct");
return false; // Needs packing. return false; // Needs packing.
NonVirtualBaseFieldTypes = FieldTypes;
if (AlignedNonVirtualTypeSize == AlignedNextFieldOffset) {
// We don't need any padding.
return true;
} }
bool needsPadding = (AlignedNonVirtualTypeSize != AlignedNextFieldOffset);
if (needsPadding) {
uint64_t NumBytes = AlignedNonVirtualTypeSize - AlignedNextFieldOffset; uint64_t NumBytes = AlignedNonVirtualTypeSize - AlignedNextFieldOffset;
NonVirtualBaseFieldTypes.push_back(getByteArrayType(NumBytes)); FieldTypes.push_back(getByteArrayType(NumBytes));
}
BaseSubobjectType = llvm::StructType::get(Types.getLLVMContext(),
FieldTypes, Packed);
if (needsPadding) {
// Pull the padding back off.
FieldTypes.pop_back();
}
return true; return true;
} }
@ -777,34 +777,27 @@ unsigned CGRecordLayoutBuilder::getAlignmentAsLLVMStruct() const {
return MaxAlignment; return MaxAlignment;
} }
/// Merge in whether a field of the given type is zero-initializable.
void CGRecordLayoutBuilder::CheckZeroInitializable(QualType T) { void CGRecordLayoutBuilder::CheckZeroInitializable(QualType T) {
// This record already contains a member pointer. // This record already contains a member pointer.
if (!IsZeroInitializable) if (!IsZeroInitializableAsBase)
return; return;
// Can only have member pointers if we're compiling C++. // Can only have member pointers if we're compiling C++.
if (!Types.getContext().getLangOptions().CPlusPlus) if (!Types.getContext().getLangOptions().CPlusPlus)
return; 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)) if (!Types.getCXXABI().isZeroInitializable(MPT))
IsZeroInitializable = false; IsZeroInitializable = IsZeroInitializableAsBase = false;
} else if (const RecordType *RT = T->getAs<RecordType>()) { } else if (const RecordType *RT = elementType->getAs<RecordType>()) {
const CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl()); const CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl());
CheckZeroInitializable(RD);
}
}
void CGRecordLayoutBuilder::CheckZeroInitializable(const CXXRecordDecl *RD) {
// This record already contains a member pointer.
if (!IsZeroInitializable)
return;
const CGRecordLayout &Layout = Types.getCGRecordLayout(RD); const CGRecordLayout &Layout = Types.getCGRecordLayout(RD);
if (!Layout.isZeroInitializable()) if (!Layout.isZeroInitializable())
IsZeroInitializable = false; IsZeroInitializable = IsZeroInitializableAsBase = false;
}
} }
CGRecordLayout *CodeGenTypes::ComputeRecordLayout(const RecordDecl *D) { CGRecordLayout *CodeGenTypes::ComputeRecordLayout(const RecordDecl *D) {
@ -816,30 +809,25 @@ CGRecordLayout *CodeGenTypes::ComputeRecordLayout(const RecordDecl *D) {
Builder.FieldTypes, Builder.FieldTypes,
Builder.Packed); Builder.Packed);
// If we're in C++, compute the base subobject type.
const llvm::StructType *BaseTy = 0; const llvm::StructType *BaseTy = 0;
if (isa<CXXRecordDecl>(D)) { if (isa<CXXRecordDecl>(D)) {
if (Builder.NonVirtualBaseTypeIsSameAsCompleteType) BaseTy = Builder.BaseSubobjectType;
BaseTy = Ty; if (!BaseTy) BaseTy = Ty;
else if (!Builder.NonVirtualBaseFieldTypes.empty())
BaseTy = llvm::StructType::get(getLLVMContext(),
Builder.NonVirtualBaseFieldTypes,
Builder.Packed);
} }
CGRecordLayout *RL = 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->NonVirtualBases.swap(Builder.NonVirtualBases);
RL->NonVirtualBaseFields.insert(Builder.LLVMNonVirtualBases.begin(), RL->CompleteObjectVirtualBases.swap(Builder.VirtualBases);
Builder.LLVMNonVirtualBases.end());
// Add all the field numbers. // Add all the field numbers.
RL->FieldInfo.insert(Builder.LLVMFields.begin(), RL->FieldInfo.swap(Builder.Fields);
Builder.LLVMFields.end());
// Add bitfield info. // Add bitfield info.
RL->BitFields.insert(Builder.LLVMBitFields.begin(), RL->BitFields.swap(Builder.BitFields);
Builder.LLVMBitFields.end());
// Dump the layout, if requested. // Dump the layout, if requested.
if (getContext().getLangOptions().DumpRecordLayouts) { if (getContext().getLangOptions().DumpRecordLayouts) {
@ -913,9 +901,9 @@ CGRecordLayout *CodeGenTypes::ComputeRecordLayout(const RecordDecl *D) {
void CGRecordLayout::print(llvm::raw_ostream &OS) const { void CGRecordLayout::print(llvm::raw_ostream &OS) const {
OS << "<CGRecordLayout\n"; OS << "<CGRecordLayout\n";
OS << " LLVMType:" << *LLVMType << "\n"; OS << " LLVMType:" << *CompleteObjectType << "\n";
if (NonVirtualBaseLLVMType) if (BaseSubobjectType)
OS << " NonVirtualBaseLLVMType:" << *NonVirtualBaseLLVMType << "\n"; OS << " NonVirtualBaseLLVMType:" << *BaseSubobjectType << "\n";
OS << " IsZeroInitializable:" << IsZeroInitializable << "\n"; OS << " IsZeroInitializable:" << IsZeroInitializable << "\n";
OS << " BitFields:[\n"; OS << " BitFields:[\n";

View File

@ -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 %t.ll -triple=x86_64-apple-darwin10
// RUN: %clang_cc1 %s -emit-llvm -o - -triple=x86_64-apple-darwin10 -O3 | FileCheck --check-prefix=CHECK-O3 %s // 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 A { int a; int b; };
struct B { int b; }; struct B { int b; };
struct C : B, A { }; struct C : B, A { };
// Zero init. // Zero init.
namespace ZeroInit { namespace ZeroInit {
// CHECK: @_ZN8ZeroInit1aE = global i64 -1 // CHECK-GLOBAL: @_ZN8ZeroInit1aE = global i64 -1
int A::* a; 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]; 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]; int A::* aaa[2][2];
// CHECK: @_ZN8ZeroInit1bE = global i64 -1, // CHECK-GLOBAL: @_ZN8ZeroInit1bE = global i64 -1,
int A::* b = 0; int A::* b = 0;
// CHECK: @_ZN8ZeroInit2saE = internal global %struct.anon { i64 -1 } // CHECK-GLOBAL: @_ZN8ZeroInit2saE = internal global %struct.anon { i64 -1 }
struct { struct {
int A::*a; int A::*a;
} sa; } sa;
void test_sa() { (void) sa; } // force emission void test_sa() { (void) sa; } // force emission
// CHECK: @_ZN8ZeroInit3ssaE = internal // CHECK-GLOBAL: @_ZN8ZeroInit3ssaE = internal
// CHECK: [2 x i64] [i64 -1, i64 -1] // CHECK-GLOBAL: [2 x i64] [i64 -1, i64 -1]
struct { struct {
int A::*aa[2]; int A::*aa[2];
} ssa[2]; } ssa[2];
void test_ssa() { (void) ssa; } 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 {
struct { struct {
int A::*pa; int A::*pa;
@ -51,13 +55,13 @@ namespace ZeroInit {
}; };
struct C : A, B { int j; }; 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; C c;
} }
// PR5674 // PR5674
namespace PR5674 { namespace PR5674 {
// CHECK: @_ZN6PR56742pbE = global i64 4 // CHECK-GLOBAL: @_ZN6PR56742pbE = global i64 4
int A::*pb = &A::b; int A::*pb = &A::b;
} }
@ -168,15 +172,15 @@ struct A {
int A::*i; 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 { }; struct B : virtual A { };
B b; 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; }; struct C : virtual A { int A::*i; };
C c; 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; }; struct D : C { int A::*i; };
D d; D d;
@ -217,3 +221,12 @@ void f(S* p, double S::*pm) {
} }
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;
}