diff options
author | Anders Carlsson <andersca@mac.com> | 2010-11-09 05:25:47 +0000 |
---|---|---|
committer | Anders Carlsson <andersca@mac.com> | 2010-11-09 05:25:47 +0000 |
commit | 3d155e683a74d3783362ef1865be91544eb8a9fc (patch) | |
tree | d1078787b96e6ed3da422c642919a2b7aeac3c52 /lib/CodeGen | |
parent | b87b29ec2ae449686a745c257e577b7158d8d4aa (diff) |
Introduce the concept of a non-virtual base type to CGRecordLayoutBuilder as a first step towards fixing PR6995.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@118491 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/CodeGen')
-rw-r--r-- | lib/CodeGen/CGRecordLayout.h | 16 | ||||
-rw-r--r-- | lib/CodeGen/CGRecordLayoutBuilder.cpp | 118 |
2 files changed, 122 insertions, 12 deletions
diff --git a/lib/CodeGen/CGRecordLayout.h b/lib/CodeGen/CGRecordLayout.h index 9b4e9f86c6..dd10024dd4 100644 --- a/lib/CodeGen/CGRecordLayout.h +++ b/lib/CodeGen/CGRecordLayout.h @@ -172,9 +172,13 @@ class CGRecordLayout { void operator=(const CGRecordLayout&); // DO NOT IMPLEMENT private: - /// The LLVMType corresponding to this record layout. + /// The LLVM type corresponding to this record layout. const llvm::Type *LLVMType; + /// The LLVM type for the non-virtual part of this record layout, used for + /// laying out the record as a base. + const llvm::Type *BaseLLVMType; + /// Map from (non-bit-field) struct field to the corresponding llvm struct /// type field no. This info is populated by record builder. llvm::DenseMap<const FieldDecl *, unsigned> FieldInfo; @@ -192,14 +196,20 @@ private: bool IsZeroInitializable : 1; public: - CGRecordLayout(const llvm::Type *T, bool IsZeroInitializable) - : LLVMType(T), IsZeroInitializable(IsZeroInitializable) {} + CGRecordLayout(const llvm::Type *LLVMType, const llvm::Type *BaseLLVMType, + bool IsZeroInitializable) + : LLVMType(LLVMType), BaseLLVMType(BaseLLVMType), + IsZeroInitializable(IsZeroInitializable) {} /// \brief Return the LLVM type associated with this record. const llvm::Type *getLLVMType() const { return LLVMType; } + const llvm::Type *getBaseLLVMType() const { + return BaseLLVMType; + } + /// \brief Check whether this struct can be C++ zero-initialized /// with a zeroinitializer. bool isZeroInitializable() const { diff --git a/lib/CodeGen/CGRecordLayoutBuilder.cpp b/lib/CodeGen/CGRecordLayoutBuilder.cpp index 6f53cafa77..c3f45a35fb 100644 --- a/lib/CodeGen/CGRecordLayoutBuilder.cpp +++ b/lib/CodeGen/CGRecordLayoutBuilder.cpp @@ -35,6 +35,24 @@ 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 + /// 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 } + std::vector<const llvm::Type *> NonVirtualBaseFieldTypes; + + /// 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; @@ -92,6 +110,9 @@ private: void LayoutNonVirtualBases(const CXXRecordDecl *RD, const ASTRecordLayout &Layout); + /// ComputeNonVirtualBaseType - Compute the non-virtual base field types. + void 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); @@ -106,6 +127,10 @@ private: /// struct size is a multiple of the field alignment. void AppendPadding(uint64_t FieldOffsetInBytes, unsigned FieldAlignment); + /// getByteArrayType - Returns a byte array type with the given number of + /// elements. + const llvm::Type *getByteArrayType(uint64_t NumBytes); + /// AppendBytes - Append a given number of bytes to the record. void AppendBytes(uint64_t NumBytes); @@ -122,8 +147,8 @@ private: public: CGRecordLayoutBuilder(CodeGenTypes &Types) - : IsZeroInitializable(true), Packed(false), Types(Types), - Alignment(0), AlignmentAsLLVMStruct(1), + : NonVirtualBaseTypeIsSameAsCompleteType(false), IsZeroInitializable(true), + Packed(false), Types(Types), Alignment(0), AlignmentAsLLVMStruct(1), BitsAvailableInLastField(0), NextFieldOffsetInBytes(0) { } /// Layout - Will layout a RecordDecl. @@ -520,13 +545,50 @@ CGRecordLayoutBuilder::LayoutNonVirtualBases(const CXXRecordDecl *RD, } } +void +CGRecordLayoutBuilder::ComputeNonVirtualBaseType(const CXXRecordDecl *RD) { + const ASTRecordLayout &Layout = Types.getContext().getASTRecordLayout(RD); + + uint64_t AlignedNonVirtualTypeSize = + llvm::RoundUpToAlignment(Layout.getNonVirtualSize(), + Layout.getNonVirtualAlign()) / 8; + + + // First check if we can use the same fields as for the complete class. + if (AlignedNonVirtualTypeSize == Layout.getSize() / 8) { + NonVirtualBaseTypeIsSameAsCompleteType = true; + return; + } + + NonVirtualBaseFieldTypes = FieldTypes; + + // Check if we need padding. + uint64_t AlignedNextFieldOffset = + llvm::RoundUpToAlignment(NextFieldOffsetInBytes, AlignmentAsLLVMStruct); + + assert(AlignedNextFieldOffset <= AlignedNonVirtualTypeSize && + "Size mismatch!"); + + if (AlignedNonVirtualTypeSize == AlignedNextFieldOffset) { + // We don't need any padding. + return; + } + + uint64_t NumBytes = AlignedNonVirtualTypeSize - AlignedNextFieldOffset; + NonVirtualBaseFieldTypes.push_back(getByteArrayType(NumBytes)); + + printf("nvts: %llu, aligned nfo: %llu\n", + AlignedNonVirtualTypeSize, AlignedNextFieldOffset); +} + bool CGRecordLayoutBuilder::LayoutFields(const RecordDecl *D) { assert(!D->isUnion() && "Can't call LayoutFields on a union!"); assert(Alignment && "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,6 +602,14 @@ bool CGRecordLayoutBuilder::LayoutFields(const RecordDecl *D) { } } + // We've laid out the non-virtual bases and the fields, now compute the + // non-virtual base field types. + if (RD) + ComputeNonVirtualBaseType(RD); + + // FIXME: Lay out the virtual bases instead of just treating them as tail + // padding. + // Append tail padding if necessary. AppendTailPadding(Layout.getSize()); @@ -595,16 +665,22 @@ void CGRecordLayoutBuilder::AppendPadding(uint64_t FieldOffsetInBytes, } } -void CGRecordLayoutBuilder::AppendBytes(uint64_t NumBytes) { - if (NumBytes == 0) - return; +const llvm::Type *CGRecordLayoutBuilder::getByteArrayType(uint64_t NumBytes) { + assert(NumBytes != 0 && "Empty byte array's aren't allowed."); const llvm::Type *Ty = llvm::Type::getInt8Ty(Types.getLLVMContext()); if (NumBytes > 1) Ty = llvm::ArrayType::get(Ty, NumBytes); + return Ty; +} + +void CGRecordLayoutBuilder::AppendBytes(uint64_t NumBytes) { + if (NumBytes == 0) + return; + // Append the padding field - AppendField(NextFieldOffsetInBytes, Ty); + AppendField(NextFieldOffsetInBytes, getByteArrayType(NumBytes)); } unsigned CGRecordLayoutBuilder::getTypeAlignment(const llvm::Type *Ty) const { @@ -658,8 +734,18 @@ CGRecordLayout *CodeGenTypes::ComputeRecordLayout(const RecordDecl *D) { Builder.FieldTypes, Builder.Packed); + const llvm::Type *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); + } + CGRecordLayout *RL = - new CGRecordLayout(Ty, Builder.IsZeroInitializable); + new CGRecordLayout(Ty, BaseTy, Builder.IsZeroInitializable); // Add all the non-virtual base field numbers. RL->NonVirtualBaseFields.insert(Builder.LLVMNonVirtualBases.begin(), @@ -684,10 +770,22 @@ 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 = Layout.getSize(); assert(TypeSizeInBits == getTargetData().getTypeAllocSizeInBits(Ty) && "Type size mismatch!"); + if (BaseTy) { + uint64_t AlignedNonVirtualTypeSizeInBits = + llvm::RoundUpToAlignment(Layout.getNonVirtualSize(), + Layout.getNonVirtualAlign()); + + 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()); @@ -730,6 +828,8 @@ CGRecordLayout *CodeGenTypes::ComputeRecordLayout(const RecordDecl *D) { void CGRecordLayout::print(llvm::raw_ostream &OS) const { OS << "<CGRecordLayout\n"; OS << " LLVMType:" << *LLVMType << "\n"; + if (BaseLLVMType) + OS << " BaseLLVMType:" << *BaseLLVMType << "\n"; OS << " IsZeroInitializable:" << IsZeroInitializable << "\n"; OS << " BitFields:[\n"; |