From: Anders Carlsson Date: Sat, 18 Jul 2009 20:20:21 +0000 (+0000) Subject: Add a new ASTRecordLayoutBuilder class. Not used yet. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=bda4c1015e27ac82d31afb4519dd53586e61a51a;p=clang Add a new ASTRecordLayoutBuilder class. Not used yet. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@76330 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/clang.xcodeproj/project.pbxproj b/clang.xcodeproj/project.pbxproj index 26be7bb0b7..24f704aee3 100644 --- a/clang.xcodeproj/project.pbxproj +++ b/clang.xcodeproj/project.pbxproj @@ -39,6 +39,7 @@ 1A7342480C7B57D500122F56 /* CGObjC.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A7342470C7B57D500122F56 /* CGObjC.cpp */; }; 1A869A700BA2164C008DA07A /* LiteralSupport.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 1A869A6E0BA2164C008DA07A /* LiteralSupport.h */; }; 1A869AA80BA21ABA008DA07A /* LiteralSupport.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A869AA70BA21ABA008DA07A /* LiteralSupport.cpp */; }; + 1AA1D91810125DE30078DEBC /* RecordLayoutBuilder.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1AA1D91610125DE30078DEBC /* RecordLayoutBuilder.cpp */; }; 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 */; }; @@ -188,7 +189,6 @@ DEB076CF0F3A222200F5A2BE /* DeclTemplate.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DEB076CE0F3A222200F5A2BE /* DeclTemplate.cpp */; }; DEB077990F44F97800F5A2BE /* TokenConcatenation.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DEB077980F44F97800F5A2BE /* TokenConcatenation.cpp */; }; DEB07AC80F4A427E00F5A2BE /* SemaAttr.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DEB07AC70F4A427E00F5A2BE /* SemaAttr.cpp */; }; - DEC63B1A0C7B940200DBF169 /* CFG.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DEC63B190C7B940200DBF169 /* CFG.cpp */; }; DEC63B1C0C7B940600DBF169 /* CFG.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = DEC63B1B0C7B940600DBF169 /* CFG.h */; }; DEC8D9910A9433CD00353FCA /* Decl.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = DEC8D9900A9433CD00353FCA /* Decl.h */; }; DEC8D9A40A94346E00353FCA /* AST.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = DEC8D9A30A94346E00353FCA /* AST.h */; }; @@ -363,6 +363,8 @@ 1A7342470C7B57D500122F56 /* CGObjC.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = CGObjC.cpp; path = lib/CodeGen/CGObjC.cpp; sourceTree = ""; tabWidth = 2; }; 1A869A6E0BA2164C008DA07A /* LiteralSupport.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LiteralSupport.h; sourceTree = ""; }; 1A869AA70BA21ABA008DA07A /* LiteralSupport.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = LiteralSupport.cpp; sourceTree = ""; }; + 1AA1D91610125DE30078DEBC /* RecordLayoutBuilder.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = RecordLayoutBuilder.cpp; path = lib/AST/RecordLayoutBuilder.cpp; sourceTree = ""; tabWidth = 2; }; + 1AA1D91710125DE30078DEBC /* RecordLayoutBuilder.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = RecordLayoutBuilder.h; path = lib/AST/RecordLayoutBuilder.h; sourceTree = ""; tabWidth = 2; }; 1ABC36930C7A4BDC006DB0AB /* CGBuiltin.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = CGBuiltin.cpp; path = lib/CodeGen/CGBuiltin.cpp; sourceTree = ""; tabWidth = 2; }; 1ADF47AE0F782C3200E48A8A /* SemaTemplateInstantiateDecl.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = SemaTemplateInstantiateDecl.cpp; path = lib/Sema/SemaTemplateInstantiateDecl.cpp; sourceTree = ""; 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 = ""; tabWidth = 2; }; @@ -603,7 +605,6 @@ DEB077980F44F97800F5A2BE /* TokenConcatenation.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = TokenConcatenation.cpp; sourceTree = ""; }; DEB07AC70F4A427E00F5A2BE /* SemaAttr.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = SemaAttr.cpp; path = lib/Sema/SemaAttr.cpp; sourceTree = ""; tabWidth = 2; }; DEB089EE0F12F1D900522C07 /* TypeTraits.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TypeTraits.h; sourceTree = ""; }; - DEC63B190C7B940200DBF169 /* CFG.cpp */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = CFG.cpp; path = lib/AST/CFG.cpp; sourceTree = ""; tabWidth = 2; }; DEC63B1B0C7B940600DBF169 /* CFG.h */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = CFG.h; path = clang/AST/CFG.h; sourceTree = ""; tabWidth = 2; }; DEC8D9900A9433CD00353FCA /* Decl.h */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = Decl.h; path = clang/AST/Decl.h; sourceTree = ""; tabWidth = 2; }; DEC8D9A30A94346E00353FCA /* AST.h */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 2; lastKnownFileType = sourcecode.c.h; name = AST.h; path = clang/AST/AST.h; sourceTree = ""; tabWidth = 2; }; @@ -1182,7 +1183,6 @@ DE8823CA0ED0046600CBC30A /* APValue.cpp */, 35BB2D7E0D19954000944DB5 /* ASTConsumer.cpp */, DE1732FF0B068B700080B521 /* ASTContext.cpp */, - DEC63B190C7B940200DBF169 /* CFG.cpp */, 35FE6BCE0DF6EE1F00739712 /* DeclBase.cpp */, DED62ABA0AE2EDF1001E80A4 /* Decl.cpp */, 3538FDB70ED24A4E005EC283 /* DeclarationName.cpp */, @@ -1197,6 +1197,8 @@ 3557D1A80EB136B100C59739 /* InheritViz.cpp */, DEDFE5CE0F7206E40035BD10 /* NestedNameSpecifier.cpp */, 35EE48B00E0C4CCA00715C54 /* ParentMap.cpp */, + 1AA1D91610125DE30078DEBC /* RecordLayoutBuilder.cpp */, + 1AA1D91710125DE30078DEBC /* RecordLayoutBuilder.h */, DE3452400AEF1A2D00DBC861 /* Stmt.cpp */, DEF2EDA60C6A4252000C4259 /* StmtDumper.cpp */, DE34621C0AFEB19B00DBC861 /* StmtPrinter.cpp */, @@ -1545,7 +1547,6 @@ 1ABC36940C7A4BDC006DB0AB /* CGBuiltin.cpp in Sources */, DE224FF80C7AA98800D370A5 /* CGExprComplex.cpp in Sources */, 1A7342480C7B57D500122F56 /* CGObjC.cpp in Sources */, - DEC63B1A0C7B940200DBF169 /* CFG.cpp in Sources */, DE2252700C7E82D000D370A5 /* CGExprScalar.cpp in Sources */, 35260CA50C7F75C000D66CE9 /* ExprCXX.cpp in Sources */, DE2255FC0C8004E600D370A5 /* ParseDeclCXX.cpp in Sources */, @@ -1695,6 +1696,7 @@ BDF87CF70FD746F300BBF872 /* SemaTemplateDeduction.cpp in Sources */, 1A14D3A70FD78A3F00DA2835 /* DeclPrinter.cpp in Sources */, DE37252E0FE481AD00CF2CC2 /* Builtins.cpp in Sources */, + 1AA1D91810125DE30078DEBC /* RecordLayoutBuilder.cpp in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/include/clang/AST/RecordLayout.h b/include/clang/AST/RecordLayout.h index ab184563da..fcf81f88bc 100644 --- a/include/clang/AST/RecordLayout.h +++ b/include/clang/AST/RecordLayout.h @@ -18,6 +18,7 @@ namespace clang { class ASTContext; + class FieldDecl; class RecordDecl; /// ASTRecordLayout - @@ -34,6 +35,7 @@ class ASTRecordLayout { unsigned Alignment; // Alignment of record in bits. unsigned FieldCount; // Number of fields friend class ASTContext; + friend class ASTRecordLayoutBuilder; ASTRecordLayout(uint64_t S = 0, unsigned A = 8) : Size(S), NextOffset(S), Alignment(A), FieldCount(0) {} @@ -41,6 +43,16 @@ class ASTRecordLayout { delete [] FieldOffsets; } + ASTRecordLayout(uint64_t Size, unsigned Alignment, + const uint64_t *fieldoffsets, unsigned fieldcount) + : Size(Size), FieldOffsets(0), Alignment(Alignment), FieldCount(fieldcount) { + if (FieldCount > 0) { + FieldOffsets = new uint64_t[FieldCount]; + for (unsigned i = 0; i < FieldCount; ++i) + FieldOffsets[i] = fieldoffsets[i]; + } + } + /// Initialize record layout. N is the number of fields in this record. void InitializeLayout(unsigned N) { FieldCount = N; diff --git a/lib/AST/RecordLayoutBuilder.cpp b/lib/AST/RecordLayoutBuilder.cpp new file mode 100644 index 0000000000..b72e588ca7 --- /dev/null +++ b/lib/AST/RecordLayoutBuilder.cpp @@ -0,0 +1,162 @@ +//=== ASTRecordLayoutBuilder.cpp - Helper class for building record layouts ==// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "RecordLayoutBuilder.h" + +#include "clang/AST/Attr.h" +#include "clang/AST/Decl.h" +#include "clang/AST/Expr.h" +#include "clang/AST/RecordLayout.h" +#include "clang/Basic/TargetInfo.h" +#include + +using namespace clang; + +ASTRecordLayoutBuilder::ASTRecordLayoutBuilder(ASTContext &Ctx) + : Ctx(Ctx), Size(0), Alignment(8), StructPacking(0), NextOffset(0), + IsUnion(false) {} + +void ASTRecordLayoutBuilder::Layout(const RecordDecl *D) { + IsUnion = D->isUnion(); + + if (const PackedAttr* PA = D->getAttr()) + StructPacking = PA->getAlignment(); + + if (const AlignedAttr *AA = D->getAttr()) + UpdateAlignment(AA->getAlignment()); + + // Layout each field, for now, just sequentially, respecting alignment. In + // the future, this will need to be tweakable by targets. + for (RecordDecl::field_iterator Field = D->field_begin(), + FieldEnd = D->field_end(); Field != FieldEnd; ++Field) + LayoutField(*Field); + + // Finally, round the size of the total struct up to the alignment of the + // struct itself. + FinishLayout(); +} + +void ASTRecordLayoutBuilder::LayoutField(const FieldDecl *D) { + unsigned FieldPacking = StructPacking; + uint64_t FieldOffset = IsUnion ? 0 : Size; + uint64_t FieldSize; + unsigned FieldAlign; + + // FIXME: Should this override struct packing? Probably we want to + // take the minimum? + if (const PackedAttr *PA = D->getAttr()) + FieldPacking = PA->getAlignment(); + + if (const Expr *BitWidthExpr = D->getBitWidth()) { + // TODO: Need to check this algorithm on other targets! + // (tested on Linux-X86) + FieldSize = BitWidthExpr->EvaluateAsInt(Ctx).getZExtValue(); + + std::pair FieldInfo = Ctx.getTypeInfo(D->getType()); + uint64_t TypeSize = FieldInfo.first; + + // Determine the alignment of this bitfield. The packing + // attributes define a maximum and the alignment attribute defines + // a minimum. + // FIXME: What is the right behavior when the specified alignment + // is smaller than the specified packing? + FieldAlign = FieldInfo.second; + if (FieldPacking) + FieldAlign = std::min(FieldAlign, FieldPacking); + if (const AlignedAttr *AA = D->getAttr()) + FieldAlign = std::max(FieldAlign, AA->getAlignment()); + + // Check if we need to add padding to give the field the correct + // alignment. + if (FieldSize == 0 || (FieldOffset & (FieldAlign-1)) + FieldSize > TypeSize) + FieldOffset = (FieldOffset + (FieldAlign-1)) & ~(FieldAlign-1); + + // Padding members don't affect overall alignment + if (!D->getIdentifier()) + FieldAlign = 1; + } else { + if (D->getType()->isIncompleteArrayType()) { + // This is a flexible array member; we can't directly + // query getTypeInfo about these, so we figure it out here. + // Flexible array members don't have any size, but they + // have to be aligned appropriately for their element type. + FieldSize = 0; + const ArrayType* ATy = Ctx.getAsArrayType(D->getType()); + FieldAlign = Ctx.getTypeAlign(ATy->getElementType()); + } else if (const ReferenceType *RT = D->getType()->getAsReferenceType()) { + unsigned AS = RT->getPointeeType().getAddressSpace(); + FieldSize = Ctx.Target.getPointerWidth(AS); + FieldAlign = Ctx.Target.getPointerAlign(AS); + } else { + std::pair FieldInfo = Ctx.getTypeInfo(D->getType()); + FieldSize = FieldInfo.first; + FieldAlign = FieldInfo.second; + } + + // Determine the alignment of this bitfield. The packing + // attributes define a maximum and the alignment attribute defines + // a minimum. Additionally, the packing alignment must be at least + // a byte for non-bitfields. + // + // FIXME: What is the right behavior when the specified alignment + // is smaller than the specified packing? + if (FieldPacking) + FieldAlign = std::min(FieldAlign, std::max(8U, FieldPacking)); + if (const AlignedAttr *AA = D->getAttr()) + FieldAlign = std::max(FieldAlign, AA->getAlignment()); + + // Round up the current record size to the field's alignment boundary. + FieldOffset = (FieldOffset + (FieldAlign-1)) & ~(FieldAlign-1); + } + + // Place this field at the current location. + FieldOffsets.push_back(FieldOffset); + + // Reserve space for this field. + if (IsUnion) + Size = std::max(Size, FieldSize); + else + Size = FieldOffset + FieldSize; + + // Remember the next available offset. + NextOffset = Size; + + // Remember max struct/class alignment. + UpdateAlignment(FieldAlign); +} + +void ASTRecordLayoutBuilder::FinishLayout() { + // In C++, records cannot be of size 0. + if (Ctx.getLangOptions().CPlusPlus && Size == 0) + Size = 8; + // Finally, round the size of the record up to the alignment of the + // record itself. + Size = (Size + (Alignment-1)) & ~(Alignment-1); +} + +void ASTRecordLayoutBuilder::UpdateAlignment(unsigned NewAlignment) { + if (NewAlignment <= Alignment) + return; + + assert(llvm::isPowerOf2_32(NewAlignment && "Alignment not a power of 2")); + + Alignment = NewAlignment; +} + +const ASTRecordLayout * +ASTRecordLayoutBuilder::ComputeLayout(ASTContext &Ctx, + const RecordDecl *D) { + ASTRecordLayoutBuilder Builder(Ctx); + + Builder.Layout(D); + + return new ASTRecordLayout(Builder.Size, Builder.Alignment, + Builder.FieldOffsets.data(), + Builder.FieldOffsets.size()); +} diff --git a/lib/AST/RecordLayoutBuilder.h b/lib/AST/RecordLayoutBuilder.h new file mode 100644 index 0000000000..a51c626e14 --- /dev/null +++ b/lib/AST/RecordLayoutBuilder.h @@ -0,0 +1,51 @@ +//===- ASTRecordLayoutBuilder.h - Helper class for building record layouts ===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_AST_RECORDLAYOUTBUILDER_H +#define LLVM_CLANG_AST_RECORDLAYOUTBUILDER_H + +#include "llvm/ADT/SmallVector.h" + +namespace clang { + class ASTContext; + class ASTRecordLayout; + class FieldDecl; + class RecordDecl; + +class ASTRecordLayoutBuilder { + ASTContext &Ctx; + + uint64_t Size; + uint64_t Alignment; + llvm::SmallVector FieldOffsets; + + unsigned StructPacking; + unsigned NextOffset; + bool IsUnion; + + ASTRecordLayoutBuilder(ASTContext &Ctx); + + void Layout(const RecordDecl *D); + void LayoutField(const FieldDecl *D); + void FinishLayout(); + + void UpdateAlignment(unsigned NewAlignment); + + ASTRecordLayoutBuilder(const ASTRecordLayoutBuilder&); // DO NOT IMPLEMENT + void operator=(const ASTRecordLayoutBuilder&); // DO NOT IMPLEMENT +public: + static const ASTRecordLayout *ComputeLayout(ASTContext &Ctx, + const RecordDecl *RD); + +}; + +} // end namespace clang + +#endif +