blob: 5230ba95d1db2babb3ff20cf3a9ebd79596e2e7f [file] [log] [blame]
Anders Carlsson79474332009-07-18 20:20:21 +00001//=== ASTRecordLayoutBuilder.cpp - Helper class for building record layouts ==//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9
10#include "RecordLayoutBuilder.h"
11
12#include "clang/AST/Attr.h"
13#include "clang/AST/Decl.h"
Anders Carlsson4f516282009-07-18 20:50:59 +000014#include "clang/AST/DeclObjC.h"
Anders Carlsson79474332009-07-18 20:20:21 +000015#include "clang/AST/Expr.h"
16#include "clang/AST/RecordLayout.h"
17#include "clang/Basic/TargetInfo.h"
18#include <llvm/Support/MathExtras.h>
19
20using namespace clang;
21
22ASTRecordLayoutBuilder::ASTRecordLayoutBuilder(ASTContext &Ctx)
23 : Ctx(Ctx), Size(0), Alignment(8), StructPacking(0), NextOffset(0),
24 IsUnion(false) {}
25
26void ASTRecordLayoutBuilder::Layout(const RecordDecl *D) {
27 IsUnion = D->isUnion();
28
29 if (const PackedAttr* PA = D->getAttr<PackedAttr>())
30 StructPacking = PA->getAlignment();
31
32 if (const AlignedAttr *AA = D->getAttr<AlignedAttr>())
33 UpdateAlignment(AA->getAlignment());
34
35 // Layout each field, for now, just sequentially, respecting alignment. In
36 // the future, this will need to be tweakable by targets.
37 for (RecordDecl::field_iterator Field = D->field_begin(),
38 FieldEnd = D->field_end(); Field != FieldEnd; ++Field)
39 LayoutField(*Field);
40
41 // Finally, round the size of the total struct up to the alignment of the
42 // struct itself.
43 FinishLayout();
44}
45
Anders Carlsson4f516282009-07-18 20:50:59 +000046void ASTRecordLayoutBuilder::Layout(const ObjCInterfaceDecl *D,
47 const ObjCImplementationDecl *Impl) {
48 if (ObjCInterfaceDecl *SD = D->getSuperClass()) {
49 const ASTRecordLayout &SL = Ctx.getASTObjCInterfaceLayout(SD);
50
51 UpdateAlignment(SL.getAlignment());
52
53 // We start laying out ivars not at the end of the superclass
54 // structure, but at the next byte following the last field.
55 Size = llvm::RoundUpToAlignment(SL.NextOffset, 8);
56 NextOffset = Size;
57 }
58
59 if (const PackedAttr *PA = D->getAttr<PackedAttr>())
60 StructPacking = PA->getAlignment();
61
62 if (const AlignedAttr *AA = D->getAttr<AlignedAttr>())
63 UpdateAlignment(AA->getAlignment());
64
65 // Layout each ivar sequentially.
66 llvm::SmallVector<ObjCIvarDecl*, 16> Ivars;
67 Ctx.ShallowCollectObjCIvars(D, Ivars, Impl);
68 for (unsigned i = 0, e = Ivars.size(); i != e; ++i)
69 LayoutField(Ivars[i]);
70
71 // Finally, round the size of the total struct up to the alignment of the
72 // struct itself.
73 FinishLayout();
74}
75
Anders Carlsson79474332009-07-18 20:20:21 +000076void ASTRecordLayoutBuilder::LayoutField(const FieldDecl *D) {
77 unsigned FieldPacking = StructPacking;
78 uint64_t FieldOffset = IsUnion ? 0 : Size;
79 uint64_t FieldSize;
80 unsigned FieldAlign;
81
82 // FIXME: Should this override struct packing? Probably we want to
83 // take the minimum?
84 if (const PackedAttr *PA = D->getAttr<PackedAttr>())
85 FieldPacking = PA->getAlignment();
86
87 if (const Expr *BitWidthExpr = D->getBitWidth()) {
88 // TODO: Need to check this algorithm on other targets!
89 // (tested on Linux-X86)
90 FieldSize = BitWidthExpr->EvaluateAsInt(Ctx).getZExtValue();
91
92 std::pair<uint64_t, unsigned> FieldInfo = Ctx.getTypeInfo(D->getType());
93 uint64_t TypeSize = FieldInfo.first;
94
95 // Determine the alignment of this bitfield. The packing
96 // attributes define a maximum and the alignment attribute defines
97 // a minimum.
98 // FIXME: What is the right behavior when the specified alignment
99 // is smaller than the specified packing?
100 FieldAlign = FieldInfo.second;
101 if (FieldPacking)
102 FieldAlign = std::min(FieldAlign, FieldPacking);
103 if (const AlignedAttr *AA = D->getAttr<AlignedAttr>())
104 FieldAlign = std::max(FieldAlign, AA->getAlignment());
105
106 // Check if we need to add padding to give the field the correct
107 // alignment.
108 if (FieldSize == 0 || (FieldOffset & (FieldAlign-1)) + FieldSize > TypeSize)
109 FieldOffset = (FieldOffset + (FieldAlign-1)) & ~(FieldAlign-1);
110
111 // Padding members don't affect overall alignment
112 if (!D->getIdentifier())
113 FieldAlign = 1;
114 } else {
115 if (D->getType()->isIncompleteArrayType()) {
116 // This is a flexible array member; we can't directly
117 // query getTypeInfo about these, so we figure it out here.
118 // Flexible array members don't have any size, but they
119 // have to be aligned appropriately for their element type.
120 FieldSize = 0;
121 const ArrayType* ATy = Ctx.getAsArrayType(D->getType());
122 FieldAlign = Ctx.getTypeAlign(ATy->getElementType());
123 } else if (const ReferenceType *RT = D->getType()->getAsReferenceType()) {
124 unsigned AS = RT->getPointeeType().getAddressSpace();
125 FieldSize = Ctx.Target.getPointerWidth(AS);
126 FieldAlign = Ctx.Target.getPointerAlign(AS);
127 } else {
128 std::pair<uint64_t, unsigned> FieldInfo = Ctx.getTypeInfo(D->getType());
129 FieldSize = FieldInfo.first;
130 FieldAlign = FieldInfo.second;
131 }
132
133 // Determine the alignment of this bitfield. The packing
134 // attributes define a maximum and the alignment attribute defines
135 // a minimum. Additionally, the packing alignment must be at least
136 // a byte for non-bitfields.
137 //
138 // FIXME: What is the right behavior when the specified alignment
139 // is smaller than the specified packing?
140 if (FieldPacking)
141 FieldAlign = std::min(FieldAlign, std::max(8U, FieldPacking));
142 if (const AlignedAttr *AA = D->getAttr<AlignedAttr>())
143 FieldAlign = std::max(FieldAlign, AA->getAlignment());
144
145 // Round up the current record size to the field's alignment boundary.
146 FieldOffset = (FieldOffset + (FieldAlign-1)) & ~(FieldAlign-1);
147 }
148
149 // Place this field at the current location.
150 FieldOffsets.push_back(FieldOffset);
151
152 // Reserve space for this field.
153 if (IsUnion)
154 Size = std::max(Size, FieldSize);
155 else
156 Size = FieldOffset + FieldSize;
157
158 // Remember the next available offset.
159 NextOffset = Size;
160
161 // Remember max struct/class alignment.
162 UpdateAlignment(FieldAlign);
163}
164
165void ASTRecordLayoutBuilder::FinishLayout() {
166 // In C++, records cannot be of size 0.
167 if (Ctx.getLangOptions().CPlusPlus && Size == 0)
168 Size = 8;
169 // Finally, round the size of the record up to the alignment of the
170 // record itself.
171 Size = (Size + (Alignment-1)) & ~(Alignment-1);
172}
173
174void ASTRecordLayoutBuilder::UpdateAlignment(unsigned NewAlignment) {
175 if (NewAlignment <= Alignment)
176 return;
177
178 assert(llvm::isPowerOf2_32(NewAlignment && "Alignment not a power of 2"));
179
180 Alignment = NewAlignment;
181}
182
183const ASTRecordLayout *
184ASTRecordLayoutBuilder::ComputeLayout(ASTContext &Ctx,
185 const RecordDecl *D) {
186 ASTRecordLayoutBuilder Builder(Ctx);
187
188 Builder.Layout(D);
189
190 return new ASTRecordLayout(Builder.Size, Builder.Alignment,
Anders Carlsson4f516282009-07-18 20:50:59 +0000191 Builder.NextOffset,
192 Builder.FieldOffsets.data(),
193 Builder.FieldOffsets.size());
194}
195
196const ASTRecordLayout *
197ASTRecordLayoutBuilder::ComputeLayout(ASTContext &Ctx,
198 const ObjCInterfaceDecl *D,
199 const ObjCImplementationDecl *Impl) {
200 ASTRecordLayoutBuilder Builder(Ctx);
201
202 Builder.Layout(D, Impl);
203
204 return new ASTRecordLayout(Builder.Size, Builder.Alignment,
205 Builder.NextOffset,
Anders Carlsson79474332009-07-18 20:20:21 +0000206 Builder.FieldOffsets.data(),
207 Builder.FieldOffsets.size());
208}