diff options
author | Anders Carlsson <andersca@mac.com> | 2009-07-23 03:17:50 +0000 |
---|---|---|
committer | Anders Carlsson <andersca@mac.com> | 2009-07-23 03:17:50 +0000 |
commit | 45372a6fdcd2b0840704569478db456822e02bae (patch) | |
tree | 9b19eda1cf1e031252487ae8a8033dae6ea97106 /lib/CodeGen/CGRecordLayoutBuilder.cpp | |
parent | f1c8380d26cc392ad8f26e788af176a6e0bf8fd1 (diff) |
Check in CGRecordLayoutBuilder which is a reimplementation of the record layout code. (Yay, no more packed structs unless absolutely necessary). We currently don't use the layouts being built but that will change when the new code is mature enough :)
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@76845 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/CodeGen/CGRecordLayoutBuilder.cpp')
-rw-r--r-- | lib/CodeGen/CGRecordLayoutBuilder.cpp | 272 |
1 files changed, 272 insertions, 0 deletions
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>()); +} |