From: Chris Lattner Date: Wed, 18 Jul 2007 17:52:12 +0000 (+0000) Subject: initial layout support for structures and unions. This isn't actually X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=464175bba1318bef7905122e9fda20cff926df78;p=clang initial layout support for structures and unions. This isn't actually hooked up to anything, so it's not very useful yet. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@40006 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/AST/ASTContext.cpp b/AST/ASTContext.cpp index f7ae1a0e3a..e2447b972a 100644 --- a/AST/ASTContext.cpp +++ b/AST/ASTContext.cpp @@ -145,6 +145,9 @@ void ASTContext::InitBuiltinTypes() { LongDoubleComplexTy = getComplexType(LongDoubleTy); } +//===----------------------------------------------------------------------===// +// Type Sizing and Analysis +//===----------------------------------------------------------------------===// /// getTypeSize - Return the size of the specified type, in bits. This method /// does not work on incomplete types. @@ -197,9 +200,76 @@ ASTContext::getTypeInfo(QualType T, SourceLocation L) { return getTypeInfo(cast(T)->getReferenceeType(), L); } + assert(Align && (Align & (Align-1)) == 0 && "Alignment must be power of 2"); return std::make_pair(Size, Align); } +/// getRecordLayout - Get or compute information about the layout of the +/// specified record (struct/union/class), which indicates its size and field +/// position information. +const RecordLayout &ASTContext::getRecordLayout(const RecordDecl *D, + SourceLocation L) { + assert(D->isDefinition() && "Cannot get layout of forward declarations!"); + + // Look up this layout, if already laid out, return what we have. + const RecordLayout *&Entry = RecordLayoutInfo[D]; + if (Entry) return *Entry; + + // Allocate and assign into RecordLayoutInfo here. The "Entry" reference can + // be invalidated (dangle) if the RecordLayoutInfo hashtable is inserted into. + RecordLayout *NewEntry = new RecordLayout(); + Entry = NewEntry; + + uint64_t *FieldOffsets = new uint64_t[D->getNumMembers()]; + uint64_t RecordSize = 0; + unsigned RecordAlign = 8; // Default alignment = 1 byte = 8 bits. + + if (D->getKind() != Decl::Union) { + // Layout each field, for now, just sequentially, respecting alignment. In + // the future, this will need to be tweakable by targets. + for (unsigned i = 0, e = D->getNumMembers(); i != e; ++i) { + const FieldDecl *FD = D->getMember(i); + std::pair FieldInfo = getTypeInfo(FD->getType(), L); + uint64_t FieldSize = FieldInfo.first; + unsigned FieldAlign = FieldInfo.second; + + // Round up the current record size to the field's alignment boundary. + RecordSize = (RecordSize+FieldAlign-1) & ~(FieldAlign-1); + + // Place this field at the current location. + FieldOffsets[i] = RecordSize; + + // Reserve space for this field. + RecordSize += FieldSize; + + // Remember max struct/class alignment. + RecordAlign = std::max(RecordAlign, FieldAlign); + } + + // Finally, round the size of the total struct up to the alignment of the + // struct itself. + RecordSize = (RecordSize+RecordAlign-1) & ~(RecordAlign-1); + } else { + // Union layout just puts each member at the start of the record. + for (unsigned i = 0, e = D->getNumMembers(); i != e; ++i) { + const FieldDecl *FD = D->getMember(i); + std::pair FieldInfo = getTypeInfo(FD->getType(), L); + uint64_t FieldSize = FieldInfo.first; + unsigned FieldAlign = FieldInfo.second; + + // Round up the current record size to the field's alignment boundary. + RecordSize = std::max(RecordSize, FieldSize); + + // Place this field at the start of the record. + FieldOffsets[i] = 0; + + // Remember max struct/class alignment. + RecordAlign = std::max(RecordAlign, FieldAlign); + } + } +} + + //===----------------------------------------------------------------------===// // Type creation/memoization methods //===----------------------------------------------------------------------===// diff --git a/clang.xcodeproj/project.pbxproj b/clang.xcodeproj/project.pbxproj index 560076196a..fe2507f9f6 100644 --- a/clang.xcodeproj/project.pbxproj +++ b/clang.xcodeproj/project.pbxproj @@ -58,6 +58,7 @@ DE67E7170C020EE400F66BC5 /* Sema.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DE67E7160C020EE400F66BC5 /* Sema.cpp */; }; DE67E71A0C020F4F00F66BC5 /* ASTStreamer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DE67E7190C020F4F00F66BC5 /* ASTStreamer.cpp */; }; DE67E7280C02109800F66BC5 /* ASTStreamer.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = DE67E7270C02109800F66BC5 /* ASTStreamer.h */; }; + DE6951C70C4D1F5D00A5826B /* RecordLayout.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = DE6951C60C4D1F5D00A5826B /* RecordLayout.h */; }; DE75ED290B044DC90020CF81 /* ASTContext.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = DE75ED280B044DC90020CF81 /* ASTContext.h */; }; DE75EDF10B06880E0020CF81 /* Type.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DE75EDF00B06880E0020CF81 /* Type.cpp */; }; DE927FFD0C055DE900231DA4 /* LLVMCodegen.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DE927FFC0C055DE900231DA4 /* LLVMCodegen.cpp */; }; @@ -178,6 +179,7 @@ DEB0AEB90C2087A700718A22 /* TextDiagnostics.h in CopyFiles */, DEEBC3BA0C2363B800A9FE82 /* CodeGenTypes.h in CopyFiles */, DEEBCBE30C33702C00A9FE82 /* TextDiagnosticBuffer.h in CopyFiles */, + DE6951C70C4D1F5D00A5826B /* RecordLayout.h in CopyFiles */, ); runOnlyForDeploymentPostprocessing = 1; }; @@ -236,6 +238,7 @@ DE67E7160C020EE400F66BC5 /* Sema.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = Sema.cpp; path = Sema/Sema.cpp; sourceTree = ""; }; DE67E7190C020F4F00F66BC5 /* ASTStreamer.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = ASTStreamer.cpp; path = Sema/ASTStreamer.cpp; sourceTree = ""; }; DE67E7270C02109800F66BC5 /* ASTStreamer.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = ASTStreamer.h; path = clang/Sema/ASTStreamer.h; sourceTree = ""; }; + DE6951C60C4D1F5D00A5826B /* RecordLayout.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = RecordLayout.h; path = clang/AST/RecordLayout.h; sourceTree = ""; }; DE75ED280B044DC90020CF81 /* ASTContext.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = ASTContext.h; path = clang/AST/ASTContext.h; sourceTree = ""; }; DE75EDF00B06880E0020CF81 /* Type.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = Type.cpp; path = AST/Type.cpp; sourceTree = ""; }; DE927FFC0C055DE900231DA4 /* LLVMCodegen.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = LLVMCodegen.cpp; path = Driver/LLVMCodegen.cpp; sourceTree = ""; }; @@ -459,6 +462,7 @@ DEC8D9900A9433CD00353FCA /* Decl.h */, DE0FCA620A95859D00248FD5 /* Expr.h */, 1A30A9E80B93A4C800201A91 /* ExprCXX.h */, + DE6951C60C4D1F5D00A5826B /* RecordLayout.h */, DE3452800AEF1B1800DBC861 /* Stmt.h */, DE345F210AFD347900DBC861 /* StmtNodes.def */, DE345C190AFC658B00DBC861 /* StmtVisitor.h */, diff --git a/include/clang/AST/ASTContext.h b/include/clang/AST/ASTContext.h index 9010a85416..fc599b51f7 100644 --- a/include/clang/AST/ASTContext.h +++ b/include/clang/AST/ASTContext.h @@ -15,8 +15,10 @@ #define LLVM_CLANG_AST_ASTCONTEXT_H #include "clang/AST/Builtins.h" -#include "clang/AST/Type.h" #include "clang/AST/Expr.h" +#include "clang/AST/RecordLayout.h" +#include "clang/AST/Type.h" +#include "llvm/ADT/DenseMap.h" #include namespace clang { @@ -33,6 +35,7 @@ class ASTContext { llvm::FoldingSet VectorTypes; llvm::FoldingSet FunctionTypeNoProtos; llvm::FoldingSet FunctionTypeProtos; + llvm::DenseMap RecordLayoutInfo; public: TargetInfo &Target; Builtin::Context BuiltinInfo; @@ -55,21 +58,9 @@ public: void PrintStats() const; - /// getTypeInfo - Get the size and alignment of the specified complete type in - /// bits. - std::pair getTypeInfo(QualType T, SourceLocation L); - - /// getTypeSize - Return the size of the specified type, in bits. This method - /// does not work on incomplete types. - uint64_t getTypeSize(QualType T, SourceLocation L) { - return getTypeInfo(T, L).first; - } - - /// getTypeAlign - Return the alignment of the specified type, in bits. This - /// method does not work on incomplete types. - unsigned getTypeAlign(QualType T, SourceLocation L) { - return getTypeInfo(T, L).second; - } + //===--------------------------------------------------------------------===// + // Type Constructors + //===--------------------------------------------------------------------===// /// getComplexType - Return the uniqued reference to the type for a complex /// number with the specified element type. @@ -118,21 +109,50 @@ public: /// defined in . Pointer - pointer requires this (C99 6.5.6p9). QualType getPointerDiffType() const; + //===--------------------------------------------------------------------===// + // Type Sizing and Analysis + //===--------------------------------------------------------------------===// + + /// getTypeInfo - Get the size and alignment of the specified complete type in + /// bits. + std::pair getTypeInfo(QualType T, SourceLocation L); + + /// getTypeSize - Return the size of the specified type, in bits. This method + /// does not work on incomplete types. + uint64_t getTypeSize(QualType T, SourceLocation L) { + return getTypeInfo(T, L).first; + } + + /// getTypeAlign - Return the alignment of the specified type, in bits. This + /// method does not work on incomplete types. + unsigned getTypeAlign(QualType T, SourceLocation L) { + return getTypeInfo(T, L).second; + } + + /// getRecordLayout - Get or compute information about the layout of the + /// specified record (struct/union/class), which indicates its size and field + /// position information. + const RecordLayout &getRecordLayout(const RecordDecl *D, SourceLocation L); + + //===--------------------------------------------------------------------===// + // Type Operators + //===--------------------------------------------------------------------===// + /// getIntegerBitwidth - Return the bitwidth of the specified integer type /// according to the target. 'Loc' specifies the source location that /// requires evaluation of this property. unsigned getIntegerBitwidth(QualType T, SourceLocation Loc); - - // maxIntegerType - Returns the highest ranked integer type. Handles 3 - // different type combos: unsigned/unsigned, signed/signed, signed/unsigned. + + /// maxIntegerType - Returns the highest ranked integer type. Handles 3 + /// different type combos: unsigned/unsigned, signed/signed, signed/unsigned. static QualType maxIntegerType(QualType lhs, QualType rhs); - // maxFloatingType - Returns the highest ranked float type. Both input - // types are required to be floats. + /// maxFloatingType - Returns the highest ranked float type. Both input + /// types are required to be floats. static QualType maxFloatingType(QualType lt, QualType rt); - // maxComplexType - Returns the highest ranked complex type. Handles 3 - // different type combos: complex/complex, complex/float, float/complex. + /// maxComplexType - Returns the highest ranked complex type. Handles 3 + /// different type combos: complex/complex, complex/float, float/complex. QualType maxComplexType(QualType lt, QualType rt) const; private: diff --git a/include/clang/AST/RecordLayout.h b/include/clang/AST/RecordLayout.h new file mode 100644 index 0000000000..5169737636 --- /dev/null +++ b/include/clang/AST/RecordLayout.h @@ -0,0 +1,57 @@ +//===--- RecordLayout.h - Layout information for a struct/union -*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file was developed by Chris Lattner and is distributed under +// the University of Illinois Open Source License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the RecordLayout interface. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_AST_LAYOUTINFO_H +#define LLVM_CLANG_AST_LAYOUTINFO_H + +#include "llvm/Support/DataTypes.h" + +namespace clang { + class ASTContext; + class RecordDecl; + +/// RecordLayout - This class contains layout information for one RecordDecl, +/// which is a struct/union/class. The decl represented must be a definition, +/// not a forward declaration. These objects are managed by ASTContext. +class RecordLayout { + uint64_t Size; // Size of record in bits. + unsigned Alignment; // Alignment of record in bits. + uint64_t *FieldOffsets; + friend class ASTContext; + + RecordLayout() {} + ~RecordLayout() { + delete [] FieldOffsets; + } + + void SetLayout(uint64_t size, unsigned alignment, uint64_t *fieldOffsets) { + Size = Size; Alignment = alignment; + FieldOffsets = fieldOffsets; + } + + RecordLayout(const RecordLayout&); // DO NOT IMPLEMENT + void operator=(const RecordLayout&); // DO NOT IMPLEMENT +public: + + unsigned getAlignment() const { return Alignment; } + uint64_t getSize() const { return Size; } + + uint64_t getFieldOffset(unsigned FieldNo) const { + return FieldOffsets[FieldNo]; + } + +}; + +} // end namespace clang + +#endif