diff options
-rw-r--r-- | clang.xcodeproj/project.pbxproj | 6 | ||||
-rw-r--r-- | lib/CodeGen/CGRecordLayoutBuilder.cpp | 272 | ||||
-rw-r--r-- | lib/CodeGen/CGRecordLayoutBuilder.h | 128 | ||||
-rw-r--r-- | lib/CodeGen/CodeGenTypes.cpp | 28 | ||||
-rw-r--r-- | lib/CodeGen/CodeGenTypes.h | 7 |
5 files changed, 429 insertions, 12 deletions
diff --git a/clang.xcodeproj/project.pbxproj b/clang.xcodeproj/project.pbxproj index 24f704aee3..137f5e4423 100644 --- a/clang.xcodeproj/project.pbxproj +++ b/clang.xcodeproj/project.pbxproj @@ -43,6 +43,7 @@ 1ABC36940C7A4BDC006DB0AB /* CGBuiltin.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1ABC36930C7A4BDC006DB0AB /* CGBuiltin.cpp */; }; 1ADF47AF0F782C3200E48A8A /* SemaTemplateInstantiateDecl.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1ADF47AE0F782C3200E48A8A /* SemaTemplateInstantiateDecl.cpp */; }; 1AFEF4070F8A6B2300476F2B /* clang-cc.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1AFEF4050F8A6B2300476F2B /* clang-cc.cpp */; }; + 1AFF8AE31012BFC900D248DA /* CGRecordLayoutBuilder.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1AFF8AE11012BFC900D248DA /* CGRecordLayoutBuilder.cpp */; }; 3507E4C20E27FE2D00FB7B57 /* CheckObjCInstMethSignature.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3507E4C10E27FE2D00FB7B57 /* CheckObjCInstMethSignature.cpp */; }; 352246E70F5C6BE000D0D279 /* HTMLDiagnostics.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 352246E10F5C6BE000D0D279 /* HTMLDiagnostics.cpp */; }; 352246E80F5C6BE000D0D279 /* InitHeaderSearch.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 352246E20F5C6BE000D0D279 /* InitHeaderSearch.cpp */; }; @@ -368,6 +369,8 @@ 1ABC36930C7A4BDC006DB0AB /* CGBuiltin.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = CGBuiltin.cpp; path = lib/CodeGen/CGBuiltin.cpp; sourceTree = "<group>"; tabWidth = 2; }; 1ADF47AE0F782C3200E48A8A /* SemaTemplateInstantiateDecl.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = SemaTemplateInstantiateDecl.cpp; path = lib/Sema/SemaTemplateInstantiateDecl.cpp; sourceTree = "<group>"; tabWidth = 2; }; 1AFEF4050F8A6B2300476F2B /* clang-cc.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = "clang-cc.cpp"; path = "tools/clang-cc/clang-cc.cpp"; sourceTree = "<group>"; tabWidth = 2; }; + 1AFF8AE11012BFC900D248DA /* CGRecordLayoutBuilder.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = CGRecordLayoutBuilder.cpp; path = lib/CodeGen/CGRecordLayoutBuilder.cpp; sourceTree = "<group>"; tabWidth = 2; }; + 1AFF8AE21012BFC900D248DA /* CGRecordLayoutBuilder.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = CGRecordLayoutBuilder.h; path = lib/CodeGen/CGRecordLayoutBuilder.h; sourceTree = "<group>"; tabWidth = 2; }; 3507E4C10E27FE2D00FB7B57 /* CheckObjCInstMethSignature.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CheckObjCInstMethSignature.cpp; path = lib/Analysis/CheckObjCInstMethSignature.cpp; sourceTree = "<group>"; }; 352246E10F5C6BE000D0D279 /* HTMLDiagnostics.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = HTMLDiagnostics.cpp; path = lib/Frontend/HTMLDiagnostics.cpp; sourceTree = "<group>"; }; 352246E20F5C6BE000D0D279 /* InitHeaderSearch.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = InitHeaderSearch.cpp; path = lib/Frontend/InitHeaderSearch.cpp; sourceTree = "<group>"; }; @@ -1110,6 +1113,8 @@ DE38CD4E0D794CF900A273B6 /* CGObjCRuntime.h */, DE38CD4F0D794D0100A273B6 /* CGObjCGNU.cpp */, 3552E7580E520DD7003A8CA5 /* CGObjCMac.cpp */, + 1AFF8AE11012BFC900D248DA /* CGRecordLayoutBuilder.cpp */, + 1AFF8AE21012BFC900D248DA /* CGRecordLayoutBuilder.h */, DE4772F90C10EAE5002239E8 /* CGStmt.cpp */, 35475B230E7997680000BFE4 /* CGValue.h */, DE928B800C0A615B00231DA4 /* CodeGenFunction.h */, @@ -1697,6 +1702,7 @@ 1A14D3A70FD78A3F00DA2835 /* DeclPrinter.cpp in Sources */, DE37252E0FE481AD00CF2CC2 /* Builtins.cpp in Sources */, 1AA1D91810125DE30078DEBC /* RecordLayoutBuilder.cpp in Sources */, + 1AFF8AE31012BFC900D248DA /* CGRecordLayoutBuilder.cpp in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/lib/CodeGen/CGRecordLayoutBuilder.cpp b/lib/CodeGen/CGRecordLayoutBuilder.cpp new file mode 100644 index 0000000000..6a95566247 --- /dev/null +++ b/lib/CodeGen/CGRecordLayoutBuilder.cpp @@ -0,0 +1,272 @@ +//===--- CGRecordLayoutBuilder.cpp - Record builder helper ------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This is a helper class used to build CGRecordLayout objects and LLVM types. +// +//===----------------------------------------------------------------------===// + +#include "CGRecordLayoutBuilder.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/DerivedTypes.h" +#include "llvm/Target/TargetData.h" + + +using namespace clang; +using namespace CodeGen; + +void CGRecordLayoutBuilder::Layout(const RecordDecl *D) { + if (const PackedAttr* PA = D->getAttr<PackedAttr>()) + StructPacking = PA->getAlignment(); + + if (LayoutFields(D)) + return; + + assert(!StructPacking && + "FIXME: Were not able to lay out a struct with #pragma pack!"); + + // We weren't able to layout the struct. Try again with a packed struct + StructPacking = 1; + AlignmentAsLLVMStruct = 1; + FieldTypes.clear(); + FieldInfos.clear(); + LLVMFields.clear(); + LLVMBitFields.clear(); + + LayoutFields(D); +} + +void CGRecordLayoutBuilder::LayoutBitField(const FieldDecl *D, + uint64_t FieldOffset) { + uint64_t FieldSize = + D->getBitWidth()->EvaluateAsInt(Types.getContext()).getZExtValue(); + + if (FieldSize == 0) + return; + + uint64_t NextFieldOffset = getNextFieldOffsetInBytes() * 8; + unsigned NumBytesToAppend; + + if (FieldOffset < NextFieldOffset) { + assert(BitsAvailableInLastField && "Bitfield size mismatch!"); + assert(!FieldInfos.empty() && "Field infos can't be empty!"); + + // The bitfield begins in the previous bit-field. + NumBytesToAppend = + llvm::RoundUpToAlignment(FieldSize - BitsAvailableInLastField, 8) / 8; + } else { + assert(FieldOffset % 8 == 0 && "Field offset not aligned correctly"); + + // Append padding if necessary. + AppendBytes((FieldOffset - NextFieldOffset) / 8); + + NumBytesToAppend = + llvm::RoundUpToAlignment(FieldSize, 8) / 8; + + assert(NumBytesToAppend && "No bytes to append!"); + } + + const llvm::Type *Ty = Types.ConvertTypeForMemRecursive(D->getType()); + uint64_t TypeSizeInBits = getTypeSizeInBytes(Ty) * 8; + + LLVMFields.push_back(LLVMFieldInfo(D, FieldOffset / TypeSizeInBits)); + LLVMBitFields.push_back(LLVMBitFieldInfo(D, FieldOffset % TypeSizeInBits, + FieldSize)); + + AppendBytes(NumBytesToAppend); + + if (!NumBytesToAppend) + BitsAvailableInLastField -= FieldSize; + else + BitsAvailableInLastField = NumBytesToAppend * 8 - FieldSize; +} + +bool CGRecordLayoutBuilder::LayoutField(const FieldDecl *D, + uint64_t FieldOffset) { + unsigned FieldPacking = StructPacking; + + // FIXME: Should this override struct packing? Probably we want to + // take the minimum? + if (const PackedAttr *PA = D->getAttr<PackedAttr>()) + FieldPacking = PA->getAlignment(); + + // If the field is packed, then we need a packed struct. + if (!StructPacking && FieldPacking) + return false; + + if (D->isBitField()) { + // We must use packed structs for unnamed bit fields since they + // don't affect the struct alignment. + if (!StructPacking && !D->getDeclName()) + return false; + + LayoutBitField(D, FieldOffset); + return true; + } + + const llvm::Type *Ty = Types.ConvertTypeForMemRecursive(D->getType()); + + // Check if the field is aligned. + if (const AlignedAttr *PA = D->getAttr<AlignedAttr>()) { + unsigned FieldAlign = PA->getAlignment(); + + if (!StructPacking && getTypeAlignment(Ty) > FieldAlign) + return false; + } + + assert(FieldOffset % 8 == 0 && "FieldOffset is not on a byte boundary!"); + + uint64_t FieldOffsetInBytes = FieldOffset / 8; + + // Append padding if necessary. + AppendPadding(FieldOffsetInBytes, Ty); + + uint64_t FieldSizeInBytes = getTypeSizeInBytes(Ty); + + // Now append the field. + LLVMFields.push_back(LLVMFieldInfo(D, FieldTypes.size())); + AppendField(FieldOffsetInBytes, FieldSizeInBytes, Ty); + + return true; +} + +bool CGRecordLayoutBuilder::LayoutFields(const RecordDecl *D) { + assert(!D->isUnion() && "Can't call LayoutFields on a union!"); + + const ASTRecordLayout &Layout = + Types.getContext().getASTRecordLayout(D); + + unsigned FieldNo = 0; + for (RecordDecl::field_iterator Field = D->field_begin(), + FieldEnd = D->field_end(); Field != FieldEnd; ++Field, ++FieldNo) { + if (!LayoutField(*Field, Layout.getFieldOffset(FieldNo))) { + assert(!StructPacking && + "Could not layout fields even with a packed LLVM struct!"); + return false; + } + } + + // Append tail padding if necessary. + if (Layout.getSize() / 8 > getNextFieldOffsetInBytes()) + AppendPadding(Layout.getSize() / 8, AlignmentAsLLVMStruct); + + return true; +} + +void CGRecordLayoutBuilder::AppendField(uint64_t FieldOffsetInBytes, + uint64_t FieldSizeInBytes, + const llvm::Type *FieldTy) { + AlignmentAsLLVMStruct = std::max(AlignmentAsLLVMStruct, + getTypeAlignment(FieldTy)); + + FieldTypes.push_back(FieldTy); + FieldInfos.push_back(FieldInfo(FieldOffsetInBytes, FieldSizeInBytes)); + + BitsAvailableInLastField = 0; +} + +void +CGRecordLayoutBuilder::AppendPadding(uint64_t FieldOffsetInBytes, + const llvm::Type *FieldTy) { + AppendPadding(FieldOffsetInBytes, getTypeAlignment(FieldTy)); +} + +void CGRecordLayoutBuilder::AppendPadding(uint64_t FieldOffsetInBytes, + unsigned FieldAlignment) { + uint64_t NextFieldOffsetInBytes = getNextFieldOffsetInBytes(); + assert(NextFieldOffsetInBytes <= FieldOffsetInBytes && + "Incorrect field layout!"); + + // Round up the field offset to the alignment of the field type. + uint64_t AlignedNextFieldOffsetInBytes = + llvm::RoundUpToAlignment(NextFieldOffsetInBytes, FieldAlignment); + + if (AlignedNextFieldOffsetInBytes < FieldOffsetInBytes) { + // Even with alignment, the field offset is not at the right place, + // insert padding. + uint64_t PaddingInBytes = FieldOffsetInBytes - NextFieldOffsetInBytes; + + AppendBytes(PaddingInBytes); + } +} + +void CGRecordLayoutBuilder::AppendBytes(uint64_t NumBytes) { + if (NumBytes == 0) + return; + + const llvm::Type *Ty = llvm::Type::Int8Ty; + if (NumBytes > 1) { + // FIXME: Use a VMContext. + Ty = llvm::ArrayType::get(Ty, NumBytes); + } + + // Append the padding field + AppendField(getNextFieldOffsetInBytes(), NumBytes, Ty); +} + +uint64_t CGRecordLayoutBuilder::getNextFieldOffsetInBytes() const { + if (FieldInfos.empty()) + return 0; + + const FieldInfo &LastInfo = FieldInfos.back(); + return LastInfo.OffsetInBytes + LastInfo.SizeInBytes; +} + +unsigned CGRecordLayoutBuilder::getTypeAlignment(const llvm::Type *Ty) const { + if (StructPacking) { + assert(StructPacking == 1 && "FIXME: What if StructPacking is not 1 here"); + return 1; + } + + return Types.getTargetData().getABITypeAlignment(Ty); +} + +uint64_t CGRecordLayoutBuilder::getTypeSizeInBytes(const llvm::Type *Ty) const { + return Types.getTargetData().getTypeAllocSize(Ty); +} + +CGRecordLayout * +CGRecordLayoutBuilder::ComputeLayout(CodeGenTypes &Types, + const RecordDecl *D) { + CGRecordLayoutBuilder Builder(Types); + + if (D->isUnion()) + return 0; + + Builder.Layout(D); + + // FIXME: Once this works well enough, enable it. + return 0; + + // FIXME: Use a VMContext. + const llvm::Type *Ty = llvm::StructType::get(Builder.FieldTypes, + Builder.StructPacking); + + // 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); + } + + // Add bitfield info. + for (unsigned i = 0, e = Builder.LLVMBitFields.size(); i != e; ++i) { + const LLVMBitFieldInfo &Info = Builder.LLVMBitFields[i]; + + Types.addBitFieldInfo(Info.FD, Info.Start, Info.Size); + } + + return new CGRecordLayout(Ty, llvm::SmallSet<unsigned, 8>()); +} diff --git a/lib/CodeGen/CGRecordLayoutBuilder.h b/lib/CodeGen/CGRecordLayoutBuilder.h new file mode 100644 index 0000000000..ac2f53c508 --- /dev/null +++ b/lib/CodeGen/CGRecordLayoutBuilder.h @@ -0,0 +1,128 @@ +//===--- CGRecordLayoutBuilder.h - Record builder helper --------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This is a helper class used to build CGRecordLayout objects and LLVM types. +// +//===----------------------------------------------------------------------===// + +#ifndef CLANG_CODEGEN_CGRECORDLAYOUTBUILDER_H +#define CLANG_CODEGEN_CGRECORDLAYOUTBUILDER_H + +#include "llvm/ADT/SmallVector.h" +#include "llvm/Support/DataTypes.h" +#include <vector> + +namespace llvm { + class Type; +} + +namespace clang { + class FieldDecl; + class RecordDecl; + +namespace CodeGen { + class CGRecordLayout; + class CodeGenTypes; + +class CGRecordLayoutBuilder { + CodeGenTypes &Types; + + /// StructPacking - Will be 0 if this struct is not packed. If it is packed, + /// it will have the packing alignment in bits. + /// + unsigned StructPacking; + + /// 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; + + /// FieldTypes - Holds the LLVM types that the struct is created from. + std::vector<const llvm::Type *> FieldTypes; + + /// FieldInfo - Holds size and offset information about a field. + /// FIXME: I think we can get rid of this. + struct FieldInfo { + FieldInfo(uint64_t OffsetInBytes, uint64_t SizeInBytes) + : OffsetInBytes(OffsetInBytes), SizeInBytes(SizeInBytes) { } + + const uint64_t OffsetInBytes; + const uint64_t SizeInBytes; + }; + llvm::SmallVector<FieldInfo, 16> FieldInfos; + + /// 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 Start, unsigned Size) + : FD(FD), Start(Start), Size(Size) { } + + const FieldDecl *FD; + + unsigned Start; + unsigned Size; + }; + llvm::SmallVector<LLVMBitFieldInfo, 16> LLVMBitFields; + + CGRecordLayoutBuilder(CodeGenTypes &Types) + : Types(Types), StructPacking(0), AlignmentAsLLVMStruct(1) + , BitsAvailableInLastField(0) { } + + /// Layout - Will layout a RecordDecl. + void Layout(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); + + /// 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 size and type. + void AppendField(uint64_t FieldOffsetInBytes, uint64_t FieldSizeInBytes, + 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); + + /// getNextFieldOffsetInBytes - returns where the next field offset is. + uint64_t getNextFieldOffsetInBytes() const; + + unsigned getTypeAlignment(const llvm::Type *Ty) const; + uint64_t getTypeSizeInBytes(const llvm::Type *Ty) const; + +public: + /// ComputeLayout - Return the right record layout for a given record decl. + static CGRecordLayout *ComputeLayout(CodeGenTypes &Types, + const RecordDecl *D); +}; + +} // end namespace CodeGen +} // end namespace clang + + +#endif diff --git a/lib/CodeGen/CodeGenTypes.cpp b/lib/CodeGen/CodeGenTypes.cpp index 41d2ba24fe..59463fa24f 100644 --- a/lib/CodeGen/CodeGenTypes.cpp +++ b/lib/CodeGen/CodeGenTypes.cpp @@ -21,6 +21,7 @@ #include "llvm/Target/TargetData.h" #include "CGCall.h" +#include "CGRecordLayoutBuilder.h" using namespace clang; using namespace CodeGen; @@ -456,21 +457,30 @@ const llvm::Type *CodeGenTypes::ConvertTagDeclType(const TagDecl *TD) { ResultType = llvm::StructType::get(std::vector<const llvm::Type*>()); } else { // Layout fields. - RecordOrganizer RO(*this, *RD); + CGRecordLayout *Layout = + CGRecordLayoutBuilder::ComputeLayout(*this, RD); - if (TD->isStruct() || TD->isClass()) - RO.layoutStructFields(Context.getASTRecordLayout(RD)); - else { - assert(TD->isUnion() && "unknown tag decl kind!"); - RO.layoutUnionFields(Context.getASTRecordLayout(RD)); + if (!Layout) { + // Layout fields. + RecordOrganizer RO(*this, *RD); + + if (TD->isStruct() || TD->isClass()) + RO.layoutStructFields(Context.getASTRecordLayout(RD)); + else { + assert(TD->isUnion() && "unknown tag decl kind!"); + RO.layoutUnionFields(Context.getASTRecordLayout(RD)); + } + + Layout = new CGRecordLayout(RO.getLLVMType(), + RO.getPaddingFields()); } // Get llvm::StructType. const Type *Key = Context.getTagDeclType(const_cast<TagDecl*>(TD)).getTypePtr(); - CGRecordLayouts[Key] = new CGRecordLayout(RO.getLLVMType(), - RO.getPaddingFields()); - ResultType = RO.getLLVMType(); + + CGRecordLayouts[Key] = Layout; + ResultType = Layout->getLLVMType(); } // Refine our Opaque type to ResultType. This can invalidate ResultType, so diff --git a/lib/CodeGen/CodeGenTypes.h b/lib/CodeGen/CodeGenTypes.h index b72d8e9201..925b933fca 100644 --- a/lib/CodeGen/CodeGenTypes.h +++ b/lib/CodeGen/CodeGenTypes.h @@ -52,14 +52,15 @@ namespace CodeGen { class CGRecordLayout { CGRecordLayout(); // DO NOT IMPLEMENT public: - CGRecordLayout(llvm::Type *T, llvm::SmallSet<unsigned, 8> &PF) + CGRecordLayout(const llvm::Type *T, + const llvm::SmallSet<unsigned, 8> &PF) : STy(T), PaddingFields(PF) { // FIXME : Collect info about fields that requires adjustments // (i.e. fields that do not directly map to llvm struct fields.) } /// getLLVMType - Return llvm type associated with this record. - llvm::Type *getLLVMType() const { + const llvm::Type *getLLVMType() const { return STy; } @@ -72,7 +73,7 @@ namespace CodeGen { } private: - llvm::Type *STy; + const llvm::Type *STy; llvm::SmallSet<unsigned, 8> PaddingFields; }; |