diff options
Diffstat (limited to 'lib/CodeGen/CGRecordLayoutBuilder.cpp')
| -rw-r--r-- | lib/CodeGen/CGRecordLayoutBuilder.cpp | 176 | 
1 files changed, 143 insertions, 33 deletions
| diff --git a/lib/CodeGen/CGRecordLayoutBuilder.cpp b/lib/CodeGen/CGRecordLayoutBuilder.cpp index baafd6836c631..daebabddc61fb 100644 --- a/lib/CodeGen/CGRecordLayoutBuilder.cpp +++ b/lib/CodeGen/CGRecordLayoutBuilder.cpp @@ -1,4 +1,4 @@ -//===--- CGRecordLayoutBuilder.cpp - Record builder helper ------*- C++ -*-===// +//===--- CGRecordLayoutBuilder.cpp - CGRecordLayout builder  ----*- C++ -*-===//  //  //                     The LLVM Compiler Infrastructure  // @@ -7,25 +7,131 @@  //  //===----------------------------------------------------------------------===//  // -// This is a helper class used to build CGRecordLayout objects and LLVM types. +// Builder implementation for CGRecordLayout objects.  //  //===----------------------------------------------------------------------===// -#include "CGRecordLayoutBuilder.h" - +#include "CGRecordLayout.h"  #include "clang/AST/ASTContext.h"  #include "clang/AST/Attr.h"  #include "clang/AST/DeclCXX.h"  #include "clang/AST/Expr.h"  #include "clang/AST/RecordLayout.h"  #include "CodeGenTypes.h" +#include "llvm/Type.h"  #include "llvm/DerivedTypes.h"  #include "llvm/Target/TargetData.h" - -  using namespace clang;  using namespace CodeGen; +namespace clang { +namespace CodeGen { + +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. +  struct LLVMBitFieldInfo { +    LLVMBitFieldInfo(const FieldDecl *FD, unsigned FieldNo, unsigned Start, +                     unsigned Size) +      : FD(FD), FieldNo(FieldNo), Start(Start), Size(Size) { } + +    const FieldDecl *FD; + +    unsigned FieldNo; +    unsigned Start; +    unsigned Size; +  }; +  llvm::SmallVector<LLVMBitFieldInfo, 16> LLVMBitFields; + +  /// ContainsPointerToDataMember - Whether one of the fields in this record +  /// layout is a pointer to data member, or a struct that contains pointer to +  /// data member. +  bool ContainsPointerToDataMember; + +  /// Packed - Whether the resulting LLVM struct will be packed or not. +  bool Packed; + +private: +  CodeGenTypes &Types; + +  /// 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; + +  /// 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; + +  /// LayoutUnion - Will layout a union RecordDecl. +  void LayoutUnion(const RecordDecl *D); + +  /// LayoutField - try to layout all fields in the record decl. +  /// Returns false if the operation failed because the struct is not packed. +  bool LayoutFields(const RecordDecl *D); + +  /// LayoutBases - layout the bases and vtable pointer of a record decl. +  void LayoutBases(const CXXRecordDecl *RD, const ASTRecordLayout &Layout); + +  /// 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); + +  /// LayoutBitField - layout a single bit field. +  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); + +  /// AppendPadding - Appends enough padding bytes so that the total struct +  /// size matches the alignment of the passed in type. +  void AppendPadding(uint64_t FieldOffsetInBytes, 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); + +  /// AppendBytes - Append a given number of bytes to the record. +  void AppendBytes(uint64_t 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; +  uint64_t getTypeSizeInBytes(const llvm::Type *Ty) const; + +  /// CheckForPointerToDataMember - Check if the given type contains a pointer +  /// to data member. +  void CheckForPointerToDataMember(QualType T); + +public: +  CGRecordLayoutBuilder(CodeGenTypes &Types) +    : ContainsPointerToDataMember(false), Packed(false), Types(Types), +      Alignment(0), AlignmentAsLLVMStruct(1), +      BitsAvailableInLastField(0), NextFieldOffsetInBytes(0) { } + +  /// Layout - Will layout a RecordDecl. +  void Layout(const RecordDecl *D); +}; + +} +} +  void CGRecordLayoutBuilder::Layout(const RecordDecl *D) {    Alignment = Types.getContext().getASTRecordLayout(D).getAlignment() / 8;    Packed = D->hasAttr<PackedAttr>(); @@ -110,7 +216,7 @@ bool CGRecordLayoutBuilder::LayoutField(const FieldDecl *D,    // Check if we have a pointer to data member in this field.    CheckForPointerToDataMember(D->getType()); -   +    assert(FieldOffset % 8 == 0 && "FieldOffset is not on a byte boundary!");    uint64_t FieldOffsetInBytes = FieldOffset / 8; @@ -166,7 +272,7 @@ void CGRecordLayoutBuilder::LayoutUnion(const RecordDecl *D) {    unsigned Align = 0;    bool HasOnlyZeroSizedBitFields = true; -   +    unsigned FieldNo = 0;    for (RecordDecl::field_iterator Field = D->field_begin(),         FieldEnd = D->field_end(); Field != FieldEnd; ++Field, ++FieldNo) { @@ -182,12 +288,13 @@ void CGRecordLayoutBuilder::LayoutUnion(const RecordDecl *D) {          continue;        // Add the bit field info. -      Types.addBitFieldInfo(*Field, 0, 0, FieldSize); -    } else -      Types.addFieldInfo(*Field, 0); +      LLVMBitFields.push_back(LLVMBitFieldInfo(*Field, 0, 0, FieldSize)); +    } else { +      LLVMFields.push_back(LLVMFieldInfo(*Field, 0)); +    }      HasOnlyZeroSizedBitFields = false; -     +      const llvm::Type *FieldTy =        Types.ConvertTypeForMemRecursive(Field->getType());      unsigned FieldAlign = Types.getTargetData().getABITypeAlignment(FieldTy); @@ -218,7 +325,7 @@ void CGRecordLayoutBuilder::LayoutUnion(const RecordDecl *D) {             "0-align record did not have all zero-sized bit-fields!");      Align = 1;    } -   +    // Append tail padding.    if (Layout.getSize() / 8 > Size)      AppendPadding(Layout.getSize() / 8, Align); @@ -228,9 +335,9 @@ void CGRecordLayoutBuilder::LayoutBases(const CXXRecordDecl *RD,                                          const ASTRecordLayout &Layout) {    // Check if we need to add a vtable pointer.    if (RD->isDynamicClass() && !Layout.getPrimaryBase()) { -    const llvm::Type *Int8PtrTy =  +    const llvm::Type *Int8PtrTy =        llvm::Type::getInt8PtrTy(Types.getLLVMContext()); -     +      assert(NextFieldOffsetInBytes == 0 &&             "Vtable pointer must come first!");      AppendField(NextFieldOffsetInBytes, Int8PtrTy->getPointerTo()); @@ -245,7 +352,7 @@ bool CGRecordLayoutBuilder::LayoutFields(const RecordDecl *D) {    if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(D))      LayoutBases(RD, Layout); -   +    unsigned FieldNo = 0;    for (RecordDecl::field_iterator Field = D->field_begin(), @@ -269,14 +376,14 @@ void CGRecordLayoutBuilder::AppendTailPadding(uint64_t RecordSize) {    uint64_t RecordSizeInBytes = RecordSize / 8;    assert(NextFieldOffsetInBytes <= RecordSizeInBytes && "Size mismatch!"); -  uint64_t AlignedNextFieldOffset =  +  uint64_t AlignedNextFieldOffset =      llvm::RoundUpToAlignment(NextFieldOffsetInBytes, AlignmentAsLLVMStruct);    if (AlignedNextFieldOffset == RecordSizeInBytes) {      // We don't need any padding.      return;    } -   +    unsigned NumPadBytes = RecordSizeInBytes - NextFieldOffsetInBytes;    AppendBytes(NumPadBytes);  } @@ -359,46 +466,49 @@ void CGRecordLayoutBuilder::CheckForPointerToDataMember(QualType T) {      }    } else if (const RecordType *RT = T->getAs<RecordType>()) {      const CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl()); -     +      // 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.containsPointerToDataMember())        ContainsPointerToDataMember = true; -  }     +  }  } -CGRecordLayout * -CGRecordLayoutBuilder::ComputeLayout(CodeGenTypes &Types, -                                     const RecordDecl *D) { -  CGRecordLayoutBuilder Builder(Types); +CGRecordLayout *CodeGenTypes::ComputeRecordLayout(const RecordDecl *D) { +  CGRecordLayoutBuilder Builder(*this);    Builder.Layout(D); -  const llvm::Type *Ty = llvm::StructType::get(Types.getLLVMContext(), +  const llvm::Type *Ty = llvm::StructType::get(getLLVMContext(),                                                 Builder.FieldTypes,                                                 Builder.Packed); -  assert(Types.getContext().getASTRecordLayout(D).getSize() / 8 == -         Types.getTargetData().getTypeAllocSize(Ty) && +  assert(getContext().getASTRecordLayout(D).getSize() / 8 == +         getTargetData().getTypeAllocSize(Ty) &&           "Type size mismatch!"); +  CGRecordLayout *RL = +    new CGRecordLayout(Ty, Builder.ContainsPointerToDataMember); +    // Add all the field numbers.    for (unsigned i = 0, e = Builder.LLVMFields.size(); i != e; ++i) {      const FieldDecl *FD = Builder.LLVMFields[i].first;      unsigned FieldNo = Builder.LLVMFields[i].second; -    Types.addFieldInfo(FD, FieldNo); +    RL->FieldInfo.insert(std::make_pair(FD, FieldNo));    }    // Add bitfield info.    for (unsigned i = 0, e = Builder.LLVMBitFields.size(); i != e; ++i) { -    const LLVMBitFieldInfo &Info = Builder.LLVMBitFields[i]; +    const CGRecordLayoutBuilder::LLVMBitFieldInfo &Info = +      Builder.LLVMBitFields[i]; -    Types.addBitFieldInfo(Info.FD, Info.FieldNo, Info.Start, Info.Size); +    CGRecordLayout::BitFieldInfo BFI(Info.FieldNo, Info.Start, Info.Size); +    RL->BitFields.insert(std::make_pair(Info.FD, BFI));    } -  return new CGRecordLayout(Ty, Builder.ContainsPointerToDataMember); +  return RL;  } | 
