diff options
author | dim <dim@FreeBSD.org> | 2011-02-20 13:06:31 +0000 |
---|---|---|
committer | dim <dim@FreeBSD.org> | 2011-02-20 13:06:31 +0000 |
commit | 39fcc9a984e2820e4ea0fa2ac4abd17d9f3a31df (patch) | |
tree | a9243275843fbeaa590afc07ee888e006b8d54ea /lib/CodeGen/CGRecordLayoutBuilder.cpp | |
parent | 69b4eca4a4255ba43baa5c1d9bbdec3ec17f479e (diff) | |
download | FreeBSD-src-39fcc9a984e2820e4ea0fa2ac4abd17d9f3a31df.zip FreeBSD-src-39fcc9a984e2820e4ea0fa2ac4abd17d9f3a31df.tar.gz |
Vendor import of clang trunk r126079:
http://llvm.org/svn/llvm-project/cfe/trunk@126079
Diffstat (limited to 'lib/CodeGen/CGRecordLayoutBuilder.cpp')
-rw-r--r-- | lib/CodeGen/CGRecordLayoutBuilder.cpp | 613 |
1 files changed, 409 insertions, 204 deletions
diff --git a/lib/CodeGen/CGRecordLayoutBuilder.cpp b/lib/CodeGen/CGRecordLayoutBuilder.cpp index 77a319f..4b19aef 100644 --- a/lib/CodeGen/CGRecordLayoutBuilder.cpp +++ b/lib/CodeGen/CGRecordLayoutBuilder.cpp @@ -14,6 +14,7 @@ #include "CGRecordLayout.h" #include "clang/AST/ASTContext.h" #include "clang/AST/Attr.h" +#include "clang/AST/CXXInheritance.h" #include "clang/AST/DeclCXX.h" #include "clang/AST/Expr.h" #include "clang/AST/RecordLayout.h" @@ -27,28 +28,52 @@ using namespace clang; using namespace CodeGen; -namespace clang { -namespace CodeGen { +namespace { class CGRecordLayoutBuilder { public: /// FieldTypes - Holds the LLVM types that the struct is created from. + /// std::vector<const llvm::Type *> FieldTypes; - /// 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; - - typedef std::pair<const CXXRecordDecl *, unsigned> LLVMBaseInfo; - llvm::SmallVector<LLVMBaseInfo, 16> LLVMNonVirtualBases; + /// BaseSubobjectType - Holds the LLVM type for the non-virtual part + /// of the struct. For example, consider: + /// + /// struct A { int i; }; + /// struct B { void *v; }; + /// struct C : virtual A, B { }; + /// + /// The LLVM type of C will be + /// %struct.C = type { i32 (...)**, %struct.A, i32, %struct.B } + /// + /// And the LLVM type of the non-virtual base struct will be + /// %struct.C.base = type { i32 (...)**, %struct.A, i32 } + /// + /// This only gets initialized if the base subobject type is + /// different from the complete-object type. + const llvm::StructType *BaseSubobjectType; + + /// 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; + + 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. + CXXIndirectPrimaryBaseSet IndirectPrimaryBases; + + /// LaidOutVirtualBases - A set of all laid out virtual bases, used to avoid + /// avoid laying out virtual bases more than once. + llvm::SmallPtrSet<const CXXRecordDecl *, 4> LaidOutVirtualBases; /// 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; @@ -59,18 +84,14 @@ private: /// Alignment - Contains the alignment of the RecordDecl. // // FIXME: This is not needed and should be removed. - unsigned Alignment; - - /// AlignmentAsLLVMStruct - Will contain the maximum alignment of all the - /// LLVM types. - unsigned AlignmentAsLLVMStruct; + CharUnits Alignment; /// BitsAvailableInLastField - If a bit field spans only part of a LLVM field, /// this will have the number of bits still available in the field. char BitsAvailableInLastField; - /// NextFieldOffsetInBytes - Holds the next field offset in bytes. - uint64_t NextFieldOffsetInBytes; + /// NextFieldOffset - Holds the next field offset. + CharUnits NextFieldOffset; /// LayoutUnionField - Will layout a field in an union and return the type /// that the field will have. @@ -84,14 +105,30 @@ private: /// Returns false if the operation failed because the struct is not packed. bool LayoutFields(const RecordDecl *D); + /// Layout a single base, virtual or non-virtual + void LayoutBase(const CXXRecordDecl *base, + const CGRecordLayout &baseLayout, + CharUnits baseOffset); + + /// LayoutVirtualBase - layout a single virtual base. + void LayoutVirtualBase(const CXXRecordDecl *base, + CharUnits baseOffset); + + /// LayoutVirtualBases - layout the virtual bases of a record decl. + void LayoutVirtualBases(const CXXRecordDecl *RD, + const ASTRecordLayout &Layout); + /// LayoutNonVirtualBase - layout a single non-virtual base. - void LayoutNonVirtualBase(const CXXRecordDecl *BaseDecl, - uint64_t BaseOffset); + void LayoutNonVirtualBase(const CXXRecordDecl *base, + CharUnits baseOffset); - /// LayoutNonVirtualBases - layout the non-virtual bases of a record decl. + /// LayoutNonVirtualBases - layout the virtual bases of a record decl. void LayoutNonVirtualBases(const CXXRecordDecl *RD, const ASTRecordLayout &Layout); + /// ComputeNonVirtualBaseType - Compute the non-virtual base field types. + bool ComputeNonVirtualBaseType(const CXXRecordDecl *RD); + /// LayoutField - layout a single field. Returns false if the operation failed /// because the current struct is not packed. bool LayoutField(const FieldDecl *D, uint64_t FieldOffset); @@ -100,41 +137,47 @@ private: void LayoutBitField(const FieldDecl *D, uint64_t FieldOffset); /// AppendField - Appends a field with the given offset and type. - void AppendField(uint64_t FieldOffsetInBytes, const llvm::Type *FieldTy); + void AppendField(CharUnits fieldOffset, const llvm::Type *FieldTy); /// AppendPadding - Appends enough padding bytes so that the total /// struct size is a multiple of the field alignment. - void AppendPadding(uint64_t FieldOffsetInBytes, unsigned FieldAlignment); + void AppendPadding(CharUnits fieldOffset, CharUnits fieldAlignment); + /// getByteArrayType - Returns a byte array type with the given number of + /// elements. + const llvm::Type *getByteArrayType(CharUnits NumBytes); + /// AppendBytes - Append a given number of bytes to the record. - void AppendBytes(uint64_t NumBytes); + void AppendBytes(CharUnits numBytes); /// AppendTailPadding - Append enough tail padding so that the type will have /// the passed size. void AppendTailPadding(uint64_t RecordSize); - unsigned getTypeAlignment(const llvm::Type *Ty) const; + CharUnits getTypeAlignment(const llvm::Type *Ty) const; + + /// getAlignmentAsLLVMStruct - Returns the maximum alignment of all the + /// LLVM element types. + CharUnits getAlignmentAsLLVMStruct() const; /// 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) - : IsZeroInitializable(true), Packed(false), Types(Types), - Alignment(0), AlignmentAsLLVMStruct(1), - BitsAvailableInLastField(0), NextFieldOffsetInBytes(0) { } + : BaseSubobjectType(0), + IsZeroInitializable(true), IsZeroInitializableAsBase(true), + Packed(false), Types(Types), BitsAvailableInLastField(0) { } /// Layout - Will layout a RecordDecl. void Layout(const RecordDecl *D); }; } -} void CGRecordLayoutBuilder::Layout(const RecordDecl *D) { - Alignment = Types.getContext().getASTRecordLayout(D).getAlignment() / 8; + Alignment = Types.getContext().getASTRecordLayout(D).getAlignment(); Packed = D->hasAttr<PackedAttr>(); if (D->isUnion()) { @@ -147,12 +190,12 @@ void CGRecordLayoutBuilder::Layout(const RecordDecl *D) { // We weren't able to layout the struct. Try again with a packed struct Packed = true; - AlignmentAsLLVMStruct = 1; - NextFieldOffsetInBytes = 0; + NextFieldOffset = CharUnits::Zero(); FieldTypes.clear(); - LLVMFields.clear(); - LLVMBitFields.clear(); - LLVMNonVirtualBases.clear(); + Fields.clear(); + BitFields.clear(); + NonVirtualBases.clear(); + VirtualBases.clear(); LayoutFields(D); } @@ -182,6 +225,12 @@ CGBitFieldInfo CGBitFieldInfo::MakeInfo(CodeGenTypes &Types, FieldSize = TypeSizeInBits; } + // in big-endian machines the first fields are in higher bit positions, + // so revert the offset. The byte offsets are reversed(back) later. + if (Types.getTargetData().isBigEndian()) { + FieldOffset = ((ContainingTypeSizeInBits)-FieldOffset-FieldSize); + } + // Compute the access components. The policy we use is to start by attempting // to access using the width of the bit-field type itself and to always access // at aligned indices of that type. If such an access would fail because it @@ -189,7 +238,6 @@ CGBitFieldInfo CGBitFieldInfo::MakeInfo(CodeGenTypes &Types, // power of two and retry. The current algorithm assumes pow2 sized types, // although this is easy to fix. // - // FIXME: This algorithm is wrong on big-endian systems, I think. assert(llvm::isPowerOf2_32(TypeSizeInBits) && "Unexpected type size!"); CGBitFieldInfo::AccessInfo Components[3]; unsigned NumComponents = 0; @@ -237,7 +285,15 @@ CGBitFieldInfo CGBitFieldInfo::MakeInfo(CodeGenTypes &Types, // FIXME: We still follow the old access pattern of only using the field // byte offset. We should switch this once we fix the struct layout to be // pretty. - AI.FieldByteOffset = AccessStart / 8; + + // on big-endian machines we reverted the bit offset because first fields are + // in higher bits. But this also reverts the bytes, so fix this here by reverting + // the byte offset on big-endian machines. + if (Types.getTargetData().isBigEndian()) { + AI.FieldByteOffset = (ContainingTypeSizeInBits - AccessStart - AccessWidth )/8; + } else { + AI.FieldByteOffset = AccessStart / 8; + } AI.FieldBitStart = AccessBitsInFieldStart - AccessStart; AI.AccessWidth = AccessWidth; AI.AccessAlignment = llvm::MinAlign(ContainingTypeAlign, AccessStart) / 8; @@ -258,56 +314,54 @@ CGBitFieldInfo CGBitFieldInfo::MakeInfo(CodeGenTypes &Types, uint64_t FieldSize) { const RecordDecl *RD = FD->getParent(); const ASTRecordLayout &RL = Types.getContext().getASTRecordLayout(RD); - uint64_t ContainingTypeSizeInBits = RL.getSize(); - unsigned ContainingTypeAlign = RL.getAlignment(); + uint64_t ContainingTypeSizeInBits = Types.getContext().toBits(RL.getSize()); + unsigned ContainingTypeAlign = Types.getContext().toBits(RL.getAlignment()); return MakeInfo(Types, FD, FieldOffset, FieldSize, ContainingTypeSizeInBits, ContainingTypeAlign); } void CGRecordLayoutBuilder::LayoutBitField(const FieldDecl *D, - uint64_t FieldOffset) { - uint64_t FieldSize = + uint64_t fieldOffset) { + uint64_t fieldSize = D->getBitWidth()->EvaluateAsInt(Types.getContext()).getZExtValue(); - if (FieldSize == 0) + if (fieldSize == 0) return; - uint64_t NextFieldOffset = NextFieldOffsetInBytes * 8; - unsigned NumBytesToAppend; + uint64_t nextFieldOffsetInBits = NextFieldOffset.getQuantity() * 8; + unsigned numBytesToAppend; - if (FieldOffset < NextFieldOffset) { + if (fieldOffset < nextFieldOffsetInBits) { assert(BitsAvailableInLastField && "Bitfield size mismatch!"); - assert(NextFieldOffsetInBytes && "Must have laid out at least one byte!"); + assert(!NextFieldOffset.isZero() && "Must have laid out at least one byte"); // The bitfield begins in the previous bit-field. - NumBytesToAppend = - llvm::RoundUpToAlignment(FieldSize - BitsAvailableInLastField, 8) / 8; + numBytesToAppend = + llvm::RoundUpToAlignment(fieldSize - BitsAvailableInLastField, 8) / 8; } else { - assert(FieldOffset % 8 == 0 && "Field offset not aligned correctly"); + assert(fieldOffset % 8 == 0 && "Field offset not aligned correctly"); // Append padding if necessary. - AppendBytes((FieldOffset - NextFieldOffset) / 8); + AppendPadding(CharUnits::fromQuantity(fieldOffset / 8), CharUnits::One()); - NumBytesToAppend = - llvm::RoundUpToAlignment(FieldSize, 8) / 8; + numBytesToAppend = llvm::RoundUpToAlignment(fieldSize, 8) / 8; - assert(NumBytesToAppend && "No bytes to append!"); + assert(numBytesToAppend && "No bytes to append!"); } // 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); + AppendBytes(CharUnits::fromQuantity(numBytesToAppend)); BitsAvailableInLastField = - NextFieldOffsetInBytes * 8 - (FieldOffset + FieldSize); + NextFieldOffset.getQuantity() * 8 - (fieldOffset + fieldSize); } bool CGRecordLayoutBuilder::LayoutField(const FieldDecl *D, - uint64_t FieldOffset) { + uint64_t fieldOffset) { // If the field is packed, then we need a packed struct. if (!Packed && D->hasAttr<PackedAttr>()) return false; @@ -318,54 +372,50 @@ bool CGRecordLayoutBuilder::LayoutField(const FieldDecl *D, if (!Packed && !D->getDeclName()) return false; - LayoutBitField(D, FieldOffset); + LayoutBitField(D, fieldOffset); return true; } CheckZeroInitializable(D->getType()); - assert(FieldOffset % 8 == 0 && "FieldOffset is not on a byte boundary!"); - uint64_t FieldOffsetInBytes = FieldOffset / 8; + assert(fieldOffset % 8 == 0 && "FieldOffset is not on a byte boundary!"); + CharUnits fieldOffsetInBytes = CharUnits::fromQuantity(fieldOffset / 8); const llvm::Type *Ty = Types.ConvertTypeForMemRecursive(D->getType()); - unsigned TypeAlignment = getTypeAlignment(Ty); + CharUnits typeAlignment = getTypeAlignment(Ty); // If the type alignment is larger then the struct alignment, we must use // a packed struct. - if (TypeAlignment > Alignment) { + if (typeAlignment > Alignment) { assert(!Packed && "Alignment is wrong even with packed struct!"); return false; } - if (const RecordType *RT = D->getType()->getAs<RecordType>()) { - const RecordDecl *RD = cast<RecordDecl>(RT->getDecl()); - if (const MaxFieldAlignmentAttr *MFAA = - RD->getAttr<MaxFieldAlignmentAttr>()) { - if (MFAA->getAlignment() != TypeAlignment * 8 && !Packed) - return false; + if (!Packed) { + if (const RecordType *RT = D->getType()->getAs<RecordType>()) { + const RecordDecl *RD = cast<RecordDecl>(RT->getDecl()); + if (const MaxFieldAlignmentAttr *MFAA = + RD->getAttr<MaxFieldAlignmentAttr>()) { + if (MFAA->getAlignment() != typeAlignment.getQuantity() * 8) + return false; + } } } // Round up the field offset to the alignment of the field type. - uint64_t AlignedNextFieldOffsetInBytes = - llvm::RoundUpToAlignment(NextFieldOffsetInBytes, TypeAlignment); + CharUnits alignedNextFieldOffsetInBytes = + NextFieldOffset.RoundUpToAlignment(typeAlignment); - if (FieldOffsetInBytes < AlignedNextFieldOffsetInBytes) { + if (fieldOffsetInBytes < alignedNextFieldOffsetInBytes) { assert(!Packed && "Could not place field even with packed struct!"); return false; } - if (AlignedNextFieldOffsetInBytes < FieldOffsetInBytes) { - // Even with alignment, the field offset is not at the right place, - // insert padding. - uint64_t PaddingInBytes = FieldOffsetInBytes - NextFieldOffsetInBytes; - - AppendBytes(PaddingInBytes); - } + AppendPadding(fieldOffsetInBytes, typeAlignment); // Now append the field. - LLVMFields.push_back(LLVMFieldInfo(D, FieldTypes.size())); - AppendField(FieldOffsetInBytes, Ty); + Fields[D] = FieldTypes.size(); + AppendField(fieldOffsetInBytes, Ty); return true; } @@ -389,95 +439,167 @@ 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()); } void CGRecordLayoutBuilder::LayoutUnion(const RecordDecl *D) { assert(D->isUnion() && "Can't call LayoutUnion on a non-union record!"); - const ASTRecordLayout &Layout = Types.getContext().getASTRecordLayout(D); + const ASTRecordLayout &layout = Types.getContext().getASTRecordLayout(D); - const llvm::Type *Ty = 0; - uint64_t Size = 0; - unsigned Align = 0; + const llvm::Type *unionType = 0; + CharUnits unionSize = CharUnits::Zero(); + CharUnits unionAlign = CharUnits::Zero(); - bool HasOnlyZeroSizedBitFields = true; + bool hasOnlyZeroSizedBitFields = true; - unsigned FieldNo = 0; - for (RecordDecl::field_iterator Field = D->field_begin(), - FieldEnd = D->field_end(); Field != FieldEnd; ++Field, ++FieldNo) { - assert(Layout.getFieldOffset(FieldNo) == 0 && + unsigned fieldNo = 0; + for (RecordDecl::field_iterator field = D->field_begin(), + fieldEnd = D->field_end(); field != fieldEnd; ++field, ++fieldNo) { + assert(layout.getFieldOffset(fieldNo) == 0 && "Union field offset did not start at the beginning of record!"); - const llvm::Type *FieldTy = LayoutUnionField(*Field, Layout); + const llvm::Type *fieldType = LayoutUnionField(*field, layout); - if (!FieldTy) + if (!fieldType) continue; - HasOnlyZeroSizedBitFields = false; + hasOnlyZeroSizedBitFields = false; - unsigned FieldAlign = Types.getTargetData().getABITypeAlignment(FieldTy); - uint64_t FieldSize = Types.getTargetData().getTypeAllocSize(FieldTy); + CharUnits fieldAlign = CharUnits::fromQuantity( + Types.getTargetData().getABITypeAlignment(fieldType)); + CharUnits fieldSize = CharUnits::fromQuantity( + Types.getTargetData().getTypeAllocSize(fieldType)); - if (FieldAlign < Align) + if (fieldAlign < unionAlign) continue; - if (FieldAlign > Align || FieldSize > Size) { - Ty = FieldTy; - Align = FieldAlign; - Size = FieldSize; + if (fieldAlign > unionAlign || fieldSize > unionSize) { + unionType = fieldType; + unionAlign = fieldAlign; + unionSize = fieldSize; } } // Now add our field. - if (Ty) { - AppendField(0, Ty); + if (unionType) { + AppendField(CharUnits::Zero(), unionType); - if (getTypeAlignment(Ty) > Layout.getAlignment() / 8) { + if (getTypeAlignment(unionType) > layout.getAlignment()) { // We need a packed struct. Packed = true; - Align = 1; + unionAlign = CharUnits::One(); } } - if (!Align) { - assert(HasOnlyZeroSizedBitFields && + if (unionAlign.isZero()) { + assert(hasOnlyZeroSizedBitFields && "0-align record did not have all zero-sized bit-fields!"); - Align = 1; + unionAlign = CharUnits::One(); } // Append tail padding. - if (Layout.getSize() / 8 > Size) - AppendPadding(Layout.getSize() / 8, Align); + CharUnits recordSize = layout.getSize(); + if (recordSize > unionSize) + AppendPadding(recordSize, unionAlign); +} + +void CGRecordLayoutBuilder::LayoutBase(const CXXRecordDecl *base, + const CGRecordLayout &baseLayout, + CharUnits baseOffset) { + AppendPadding(baseOffset, CharUnits::One()); + + const ASTRecordLayout &baseASTLayout + = Types.getContext().getASTRecordLayout(base); + + // Fields and bases can be laid out in the tail padding of previous + // bases. If this happens, we need to allocate the base as an i8 + // array; otherwise, we can use the subobject type. However, + // actually doing that would require knowledge of what immediately + // follows this base in the layout, so instead we do a conservative + // approximation, which is to use the base subobject type if it + // has the same LLVM storage size as the nvsize. + + // The nvsize, i.e. the unpadded size of the base class. + CharUnits nvsize = baseASTLayout.getNonVirtualSize(); + +#if 0 + const llvm::StructType *subobjectType = baseLayout.getBaseSubobjectLLVMType(); + const llvm::StructLayout *baseLLVMLayout = + Types.getTargetData().getStructLayout(subobjectType); + CharUnits stsize = CharUnits::fromQuantity(baseLLVMLayout->getSizeInBytes()); + + if (nvsize == stsize) + AppendField(baseOffset, subobjectType); + else +#endif + AppendBytes(nvsize); } -void CGRecordLayoutBuilder::LayoutNonVirtualBase(const CXXRecordDecl *BaseDecl, - uint64_t BaseOffset) { - const ASTRecordLayout &Layout = - Types.getContext().getASTRecordLayout(BaseDecl); +void CGRecordLayoutBuilder::LayoutNonVirtualBase(const CXXRecordDecl *base, + CharUnits baseOffset) { + // Ignore empty bases. + if (base->isEmpty()) return; - uint64_t NonVirtualSize = Layout.getNonVirtualSize(); + const CGRecordLayout &baseLayout = Types.getCGRecordLayout(base); + if (IsZeroInitializableAsBase) { + assert(IsZeroInitializable && + "class zero-initializable as base but not as complete object"); - if (BaseDecl->isEmpty()) { - // FIXME: Lay out empty bases. - return; + IsZeroInitializable = IsZeroInitializableAsBase = + baseLayout.isZeroInitializableAsBase(); } - CheckZeroInitializable(BaseDecl); + LayoutBase(base, baseLayout, baseOffset); + NonVirtualBases[base] = (FieldTypes.size() - 1); +} - // FIXME: Actually use a better type than [sizeof(BaseDecl) x i8] when we can. - AppendPadding(BaseOffset / 8, 1); - - // Append the base field. - LLVMNonVirtualBases.push_back(LLVMBaseInfo(BaseDecl, FieldTypes.size())); +void +CGRecordLayoutBuilder::LayoutVirtualBase(const CXXRecordDecl *base, + CharUnits baseOffset) { + // Ignore empty bases. + if (base->isEmpty()) return; + + const CGRecordLayout &baseLayout = Types.getCGRecordLayout(base); + if (IsZeroInitializable) + IsZeroInitializable = baseLayout.isZeroInitializableAsBase(); + + LayoutBase(base, baseLayout, baseOffset); + VirtualBases[base] = (FieldTypes.size() - 1); +} - AppendBytes(NonVirtualSize / 8); +/// LayoutVirtualBases - layout the non-virtual bases of a record decl. +void +CGRecordLayoutBuilder::LayoutVirtualBases(const CXXRecordDecl *RD, + const ASTRecordLayout &Layout) { + for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(), + E = RD->bases_end(); I != E; ++I) { + const CXXRecordDecl *BaseDecl = + cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl()); + + // We only want to lay out virtual bases that aren't indirect primary bases + // of some other base. + if (I->isVirtual() && !IndirectPrimaryBases.count(BaseDecl)) { + // Only lay out the base once. + if (!LaidOutVirtualBases.insert(BaseDecl)) + continue; + + CharUnits vbaseOffset = Layout.getVBaseClassOffset(BaseDecl); + LayoutVirtualBase(BaseDecl, vbaseOffset); + } + + if (!BaseDecl->getNumVBases()) { + // This base isn't interesting since it doesn't have any virtual bases. + continue; + } + + LayoutVirtualBases(BaseDecl, Layout); + } } void @@ -493,13 +615,14 @@ CGRecordLayoutBuilder::LayoutNonVirtualBases(const CXXRecordDecl *RD, /*isVarArg=*/true); const llvm::Type *VTableTy = FunctionType->getPointerTo(); - assert(NextFieldOffsetInBytes == 0 && + assert(NextFieldOffset.isZero() && "VTable pointer must come first!"); - AppendField(NextFieldOffsetInBytes, VTableTy->getPointerTo()); + AppendField(CharUnits::Zero(), VTableTy->getPointerTo()); } else { - // FIXME: Handle a virtual primary base. - if (!Layout.getPrimaryBaseWasVirtual()) - LayoutNonVirtualBase(PrimaryBase, 0); + if (!Layout.isPrimaryBaseVirtual()) + LayoutNonVirtualBase(PrimaryBase, CharUnits::Zero()); + else + LayoutVirtualBase(PrimaryBase, CharUnits::Zero()); } } @@ -513,20 +636,61 @@ CGRecordLayoutBuilder::LayoutNonVirtualBases(const CXXRecordDecl *RD, cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl()); // We've already laid out the primary base. - if (BaseDecl == PrimaryBase && !Layout.getPrimaryBaseWasVirtual()) + if (BaseDecl == PrimaryBase && !Layout.isPrimaryBaseVirtual()) continue; LayoutNonVirtualBase(BaseDecl, Layout.getBaseClassOffset(BaseDecl)); } } +bool +CGRecordLayoutBuilder::ComputeNonVirtualBaseType(const CXXRecordDecl *RD) { + const ASTRecordLayout &Layout = Types.getContext().getASTRecordLayout(RD); + + CharUnits NonVirtualSize = Layout.getNonVirtualSize(); + CharUnits NonVirtualAlign = Layout.getNonVirtualAlign(); + CharUnits AlignedNonVirtualTypeSize = + NonVirtualSize.RoundUpToAlignment(NonVirtualAlign); + + // First check if we can use the same fields as for the complete class. + CharUnits RecordSize = Layout.getSize(); + if (AlignedNonVirtualTypeSize == RecordSize) + return true; + + // Check if we need padding. + CharUnits AlignedNextFieldOffset = + NextFieldOffset.RoundUpToAlignment(getAlignmentAsLLVMStruct()); + + if (AlignedNextFieldOffset > AlignedNonVirtualTypeSize) { + assert(!Packed && "cannot layout even as packed struct"); + return false; // Needs packing. + } + + bool needsPadding = (AlignedNonVirtualTypeSize != AlignedNextFieldOffset); + if (needsPadding) { + CharUnits NumBytes = AlignedNonVirtualTypeSize - AlignedNextFieldOffset; + 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; +} + bool CGRecordLayoutBuilder::LayoutFields(const RecordDecl *D) { assert(!D->isUnion() && "Can't call LayoutFields on a union!"); - assert(Alignment && "Did not set alignment!"); + assert(!Alignment.isZero() && "Did not set alignment!"); const ASTRecordLayout &Layout = Types.getContext().getASTRecordLayout(D); - if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(D)) + const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(D); + if (RD) LayoutNonVirtualBases(RD, Layout); unsigned FieldNo = 0; @@ -540,8 +704,23 @@ bool CGRecordLayoutBuilder::LayoutFields(const RecordDecl *D) { } } + if (RD) { + // We've laid out the non-virtual bases and the fields, now compute the + // non-virtual base field types. + if (!ComputeNonVirtualBaseType(RD)) { + assert(!Packed && "Could not layout even with a packed LLVM struct!"); + return false; + } + + // And lay out the virtual bases. + RD->getIndirectPrimaryBases(IndirectPrimaryBases); + if (Layout.isPrimaryBaseVirtual()) + IndirectPrimaryBases.insert(Layout.getPrimaryBase()); + LayoutVirtualBases(RD, Layout); + } + // Append tail padding if necessary. - AppendTailPadding(Layout.getSize()); + AppendTailPadding(Types.getContext().toBits(Layout.getSize())); return true; } @@ -549,129 +728,137 @@ bool CGRecordLayoutBuilder::LayoutFields(const RecordDecl *D) { void CGRecordLayoutBuilder::AppendTailPadding(uint64_t RecordSize) { assert(RecordSize % 8 == 0 && "Invalid record size!"); - uint64_t RecordSizeInBytes = RecordSize / 8; - assert(NextFieldOffsetInBytes <= RecordSizeInBytes && "Size mismatch!"); + CharUnits RecordSizeInBytes = CharUnits::fromQuantity(RecordSize / 8); + assert(NextFieldOffset <= RecordSizeInBytes && "Size mismatch!"); - uint64_t AlignedNextFieldOffset = - llvm::RoundUpToAlignment(NextFieldOffsetInBytes, AlignmentAsLLVMStruct); + CharUnits AlignedNextFieldOffset = + NextFieldOffset.RoundUpToAlignment(getAlignmentAsLLVMStruct()); if (AlignedNextFieldOffset == RecordSizeInBytes) { // We don't need any padding. return; } - unsigned NumPadBytes = RecordSizeInBytes - NextFieldOffsetInBytes; + CharUnits NumPadBytes = RecordSizeInBytes - NextFieldOffset; AppendBytes(NumPadBytes); } -void CGRecordLayoutBuilder::AppendField(uint64_t FieldOffsetInBytes, - const llvm::Type *FieldTy) { - AlignmentAsLLVMStruct = std::max(AlignmentAsLLVMStruct, - getTypeAlignment(FieldTy)); +void CGRecordLayoutBuilder::AppendField(CharUnits fieldOffset, + const llvm::Type *fieldType) { + CharUnits fieldSize = + CharUnits::fromQuantity(Types.getTargetData().getTypeAllocSize(fieldType)); - uint64_t FieldSizeInBytes = Types.getTargetData().getTypeAllocSize(FieldTy); + FieldTypes.push_back(fieldType); - FieldTypes.push_back(FieldTy); - - NextFieldOffsetInBytes = FieldOffsetInBytes + FieldSizeInBytes; + NextFieldOffset = fieldOffset + fieldSize; BitsAvailableInLastField = 0; } -void CGRecordLayoutBuilder::AppendPadding(uint64_t FieldOffsetInBytes, - unsigned FieldAlignment) { - assert(NextFieldOffsetInBytes <= FieldOffsetInBytes && +void CGRecordLayoutBuilder::AppendPadding(CharUnits fieldOffset, + CharUnits fieldAlignment) { + assert(NextFieldOffset <= fieldOffset && "Incorrect field layout!"); // Round up the field offset to the alignment of the field type. - uint64_t AlignedNextFieldOffsetInBytes = - llvm::RoundUpToAlignment(NextFieldOffsetInBytes, FieldAlignment); + CharUnits alignedNextFieldOffset = + NextFieldOffset.RoundUpToAlignment(fieldAlignment); - if (AlignedNextFieldOffsetInBytes < FieldOffsetInBytes) { + if (alignedNextFieldOffset < fieldOffset) { // Even with alignment, the field offset is not at the right place, // insert padding. - uint64_t PaddingInBytes = FieldOffsetInBytes - NextFieldOffsetInBytes; + CharUnits padding = fieldOffset - NextFieldOffset; - AppendBytes(PaddingInBytes); + AppendBytes(padding); } } -void CGRecordLayoutBuilder::AppendBytes(uint64_t NumBytes) { - if (NumBytes == 0) - return; +const llvm::Type *CGRecordLayoutBuilder::getByteArrayType(CharUnits numBytes) { + assert(!numBytes.isZero() && "Empty byte arrays aren't allowed."); const llvm::Type *Ty = llvm::Type::getInt8Ty(Types.getLLVMContext()); - if (NumBytes > 1) - Ty = llvm::ArrayType::get(Ty, NumBytes); + if (numBytes > CharUnits::One()) + Ty = llvm::ArrayType::get(Ty, numBytes.getQuantity()); + + return Ty; +} + +void CGRecordLayoutBuilder::AppendBytes(CharUnits numBytes) { + if (numBytes.isZero()) + return; // Append the padding field - AppendField(NextFieldOffsetInBytes, Ty); + AppendField(NextFieldOffset, getByteArrayType(numBytes)); } -unsigned CGRecordLayoutBuilder::getTypeAlignment(const llvm::Type *Ty) const { +CharUnits CGRecordLayoutBuilder::getTypeAlignment(const llvm::Type *Ty) const { if (Packed) - return 1; + return CharUnits::One(); - return Types.getTargetData().getABITypeAlignment(Ty); + return CharUnits::fromQuantity(Types.getTargetData().getABITypeAlignment(Ty)); } +CharUnits CGRecordLayoutBuilder::getAlignmentAsLLVMStruct() const { + if (Packed) + return CharUnits::One(); + + CharUnits maxAlignment = CharUnits::One(); + for (size_t i = 0; i != FieldTypes.size(); ++i) + maxAlignment = std::max(maxAlignment, getTypeAlignment(FieldTypes[i])); + + 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; - - // FIXME: It would be better if there was a way to explicitly compute the - // record layout instead of converting to a type. - Types.ConvertTagDeclType(RD); - - const CGRecordLayout &Layout = Types.getCGRecordLayout(RD); - - if (!Layout.isZeroInitializable()) - IsZeroInitializable = false; -} - CGRecordLayout *CodeGenTypes::ComputeRecordLayout(const RecordDecl *D) { CGRecordLayoutBuilder Builder(*this); Builder.Layout(D); - const llvm::Type *Ty = llvm::StructType::get(getLLVMContext(), - Builder.FieldTypes, - Builder.Packed); + const llvm::StructType *Ty = llvm::StructType::get(getLLVMContext(), + Builder.FieldTypes, + Builder.Packed); + + // If we're in C++, compute the base subobject type. + const llvm::StructType *BaseTy = 0; + if (isa<CXXRecordDecl>(D)) { + BaseTy = Builder.BaseSubobjectType; + if (!BaseTy) BaseTy = Ty; + } CGRecordLayout *RL = - new CGRecordLayout(Ty, 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) { @@ -684,10 +871,26 @@ CGRecordLayout *CodeGenTypes::ComputeRecordLayout(const RecordDecl *D) { #ifndef NDEBUG // Verify that the computed LLVM struct size matches the AST layout size. - uint64_t TypeSizeInBits = getContext().getASTRecordLayout(D).getSize(); + const ASTRecordLayout &Layout = getContext().getASTRecordLayout(D); + + uint64_t TypeSizeInBits = getContext().toBits(Layout.getSize()); assert(TypeSizeInBits == getTargetData().getTypeAllocSizeInBits(Ty) && "Type size mismatch!"); + if (BaseTy) { + CharUnits NonVirtualSize = Layout.getNonVirtualSize(); + CharUnits NonVirtualAlign = Layout.getNonVirtualAlign(); + CharUnits AlignedNonVirtualTypeSize = + NonVirtualSize.RoundUpToAlignment(NonVirtualAlign); + + uint64_t AlignedNonVirtualTypeSizeInBits = + getContext().toBits(AlignedNonVirtualTypeSize); + + assert(AlignedNonVirtualTypeSizeInBits == + getTargetData().getTypeAllocSizeInBits(BaseTy) && + "Type size mismatch!"); + } + // Verify that the LLVM and AST field offsets agree. const llvm::StructType *ST = dyn_cast<llvm::StructType>(RL->getLLVMType()); @@ -729,7 +932,9 @@ CGRecordLayout *CodeGenTypes::ComputeRecordLayout(const RecordDecl *D) { void CGRecordLayout::print(llvm::raw_ostream &OS) const { OS << "<CGRecordLayout\n"; - OS << " LLVMType:" << *LLVMType << "\n"; + OS << " LLVMType:" << *CompleteObjectType << "\n"; + if (BaseSubobjectType) + OS << " NonVirtualBaseLLVMType:" << *BaseSubobjectType << "\n"; OS << " IsZeroInitializable:" << IsZeroInitializable << "\n"; OS << " BitFields:[\n"; |