blob: e6479bf0f5346a6dbd5f0994cef6bc3bb7a441f7 [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 Carlsson6d9f6f32009-07-19 00:18:47 +000014#include "clang/AST/DeclCXX.h"
Anders Carlsson4f516282009-07-18 20:50:59 +000015#include "clang/AST/DeclObjC.h"
Anders Carlsson79474332009-07-18 20:20:21 +000016#include "clang/AST/Expr.h"
17#include "clang/AST/RecordLayout.h"
18#include "clang/Basic/TargetInfo.h"
19#include <llvm/Support/MathExtras.h>
20
21using namespace clang;
22
23ASTRecordLayoutBuilder::ASTRecordLayoutBuilder(ASTContext &Ctx)
Anders Carlsson6d9f6f32009-07-19 00:18:47 +000024 : Ctx(Ctx), Size(0), Alignment(8), StructPacking(0), NextOffset(0),
Anders Carlssonfc8cfa82009-07-28 19:24:15 +000025 IsUnion(false), NonVirtualSize(0), NonVirtualAlignment(8) {}
Anders Carlsson79474332009-07-18 20:20:21 +000026
Anders Carlsson6d9f6f32009-07-19 00:18:47 +000027void
28ASTRecordLayoutBuilder::LayoutNonVirtualBases(const CXXRecordDecl *RD) {
29 assert(!RD->isPolymorphic() &&
30 "FIXME: We don't support polymorphic classes yet!");
31
32 for (CXXRecordDecl::base_class_const_iterator i = RD->bases_begin(),
33 e = RD->bases_end(); i != e; ++i) {
34 if (!i->isVirtual()) {
35 const CXXRecordDecl *Base =
36 cast<CXXRecordDecl>(i->getType()->getAsRecordType()->getDecl());
37 LayoutNonVirtualBase(Base);
38 }
39 }
40}
41
42void ASTRecordLayoutBuilder::LayoutNonVirtualBase(const CXXRecordDecl *RD) {
43 const ASTRecordLayout &BaseInfo = Ctx.getASTRecordLayout(RD);
44 assert(BaseInfo.getDataSize() > 0 &&
45 "FIXME: Handle empty classes.");
46
Anders Carlssonfc8cfa82009-07-28 19:24:15 +000047 unsigned BaseAlign = BaseInfo.getNonVirtualAlign();
48 uint64_t BaseSize = BaseInfo.getNonVirtualSize();
Anders Carlsson6d9f6f32009-07-19 00:18:47 +000049
50 // Round up the current record size to the base's alignment boundary.
51 Size = (Size + (BaseAlign-1)) & ~(BaseAlign-1);
52
Anders Carlssonfc8cfa82009-07-28 19:24:15 +000053 // Add base class offsets.
54 Bases.push_back(RD);
55 BaseOffsets.push_back(Size);
56
Fariborz Jahaniandedf1e42009-07-25 21:12:28 +000057 // Non-virtual base class has offset too.
58 FieldOffsets.push_back(Size);
59
Anders Carlsson6d9f6f32009-07-19 00:18:47 +000060 // Reserve space for this base.
61 Size += BaseSize;
62
63 // Remember the next available offset.
64 NextOffset = Size;
65
66 // Remember max struct/class alignment.
67 UpdateAlignment(BaseAlign);
68}
69
Anders Carlsson79474332009-07-18 20:20:21 +000070void ASTRecordLayoutBuilder::Layout(const RecordDecl *D) {
71 IsUnion = D->isUnion();
72
73 if (const PackedAttr* PA = D->getAttr<PackedAttr>())
74 StructPacking = PA->getAlignment();
75
76 if (const AlignedAttr *AA = D->getAttr<AlignedAttr>())
77 UpdateAlignment(AA->getAlignment());
Anders Carlsson6d9f6f32009-07-19 00:18:47 +000078
79 // If this is a C++ class, lay out the nonvirtual bases.
80 if (Ctx.getLangOptions().CPlusPlus)
81 LayoutNonVirtualBases(cast<CXXRecordDecl>(D));
82
Anders Carlsson118ce162009-07-18 21:48:39 +000083 LayoutFields(D);
Anders Carlsson79474332009-07-18 20:20:21 +000084
Anders Carlssonfc8cfa82009-07-28 19:24:15 +000085 NonVirtualSize = Size;
86 NonVirtualAlignment = Alignment;
87
Anders Carlsson79474332009-07-18 20:20:21 +000088 // Finally, round the size of the total struct up to the alignment of the
89 // struct itself.
90 FinishLayout();
91}
92
Anders Carlsson4f516282009-07-18 20:50:59 +000093void ASTRecordLayoutBuilder::Layout(const ObjCInterfaceDecl *D,
94 const ObjCImplementationDecl *Impl) {
95 if (ObjCInterfaceDecl *SD = D->getSuperClass()) {
96 const ASTRecordLayout &SL = Ctx.getASTObjCInterfaceLayout(SD);
97
98 UpdateAlignment(SL.getAlignment());
99
100 // We start laying out ivars not at the end of the superclass
101 // structure, but at the next byte following the last field.
Anders Carlsson27b50132009-07-18 21:26:44 +0000102 Size = llvm::RoundUpToAlignment(SL.getDataSize(), 8);
Anders Carlsson4f516282009-07-18 20:50:59 +0000103 NextOffset = Size;
104 }
105
106 if (const PackedAttr *PA = D->getAttr<PackedAttr>())
107 StructPacking = PA->getAlignment();
108
109 if (const AlignedAttr *AA = D->getAttr<AlignedAttr>())
110 UpdateAlignment(AA->getAlignment());
111
112 // Layout each ivar sequentially.
113 llvm::SmallVector<ObjCIvarDecl*, 16> Ivars;
114 Ctx.ShallowCollectObjCIvars(D, Ivars, Impl);
115 for (unsigned i = 0, e = Ivars.size(); i != e; ++i)
116 LayoutField(Ivars[i]);
117
118 // Finally, round the size of the total struct up to the alignment of the
119 // struct itself.
120 FinishLayout();
121}
122
Anders Carlsson118ce162009-07-18 21:48:39 +0000123void ASTRecordLayoutBuilder::LayoutFields(const RecordDecl *D) {
124 // Layout each field, for now, just sequentially, respecting alignment. In
125 // the future, this will need to be tweakable by targets.
126 for (RecordDecl::field_iterator Field = D->field_begin(),
127 FieldEnd = D->field_end(); Field != FieldEnd; ++Field)
128 LayoutField(*Field);
129}
130
Anders Carlsson79474332009-07-18 20:20:21 +0000131void ASTRecordLayoutBuilder::LayoutField(const FieldDecl *D) {
132 unsigned FieldPacking = StructPacking;
133 uint64_t FieldOffset = IsUnion ? 0 : Size;
134 uint64_t FieldSize;
135 unsigned FieldAlign;
136
137 // FIXME: Should this override struct packing? Probably we want to
138 // take the minimum?
139 if (const PackedAttr *PA = D->getAttr<PackedAttr>())
140 FieldPacking = PA->getAlignment();
141
142 if (const Expr *BitWidthExpr = D->getBitWidth()) {
143 // TODO: Need to check this algorithm on other targets!
144 // (tested on Linux-X86)
145 FieldSize = BitWidthExpr->EvaluateAsInt(Ctx).getZExtValue();
146
147 std::pair<uint64_t, unsigned> FieldInfo = Ctx.getTypeInfo(D->getType());
148 uint64_t TypeSize = FieldInfo.first;
149
150 // Determine the alignment of this bitfield. The packing
151 // attributes define a maximum and the alignment attribute defines
152 // a minimum.
153 // FIXME: What is the right behavior when the specified alignment
154 // is smaller than the specified packing?
155 FieldAlign = FieldInfo.second;
156 if (FieldPacking)
157 FieldAlign = std::min(FieldAlign, FieldPacking);
158 if (const AlignedAttr *AA = D->getAttr<AlignedAttr>())
159 FieldAlign = std::max(FieldAlign, AA->getAlignment());
160
161 // Check if we need to add padding to give the field the correct
162 // alignment.
163 if (FieldSize == 0 || (FieldOffset & (FieldAlign-1)) + FieldSize > TypeSize)
164 FieldOffset = (FieldOffset + (FieldAlign-1)) & ~(FieldAlign-1);
165
166 // Padding members don't affect overall alignment
167 if (!D->getIdentifier())
168 FieldAlign = 1;
169 } else {
170 if (D->getType()->isIncompleteArrayType()) {
171 // This is a flexible array member; we can't directly
172 // query getTypeInfo about these, so we figure it out here.
173 // Flexible array members don't have any size, but they
174 // have to be aligned appropriately for their element type.
175 FieldSize = 0;
176 const ArrayType* ATy = Ctx.getAsArrayType(D->getType());
177 FieldAlign = Ctx.getTypeAlign(ATy->getElementType());
178 } else if (const ReferenceType *RT = D->getType()->getAsReferenceType()) {
179 unsigned AS = RT->getPointeeType().getAddressSpace();
180 FieldSize = Ctx.Target.getPointerWidth(AS);
181 FieldAlign = Ctx.Target.getPointerAlign(AS);
182 } else {
183 std::pair<uint64_t, unsigned> FieldInfo = Ctx.getTypeInfo(D->getType());
184 FieldSize = FieldInfo.first;
185 FieldAlign = FieldInfo.second;
186 }
187
188 // Determine the alignment of this bitfield. The packing
189 // attributes define a maximum and the alignment attribute defines
190 // a minimum. Additionally, the packing alignment must be at least
191 // a byte for non-bitfields.
192 //
193 // FIXME: What is the right behavior when the specified alignment
194 // is smaller than the specified packing?
195 if (FieldPacking)
196 FieldAlign = std::min(FieldAlign, std::max(8U, FieldPacking));
197 if (const AlignedAttr *AA = D->getAttr<AlignedAttr>())
198 FieldAlign = std::max(FieldAlign, AA->getAlignment());
199
200 // Round up the current record size to the field's alignment boundary.
201 FieldOffset = (FieldOffset + (FieldAlign-1)) & ~(FieldAlign-1);
202 }
203
204 // Place this field at the current location.
205 FieldOffsets.push_back(FieldOffset);
206
207 // Reserve space for this field.
208 if (IsUnion)
209 Size = std::max(Size, FieldSize);
210 else
211 Size = FieldOffset + FieldSize;
212
213 // Remember the next available offset.
214 NextOffset = Size;
215
216 // Remember max struct/class alignment.
217 UpdateAlignment(FieldAlign);
218}
219
220void ASTRecordLayoutBuilder::FinishLayout() {
221 // In C++, records cannot be of size 0.
222 if (Ctx.getLangOptions().CPlusPlus && Size == 0)
223 Size = 8;
224 // Finally, round the size of the record up to the alignment of the
225 // record itself.
226 Size = (Size + (Alignment-1)) & ~(Alignment-1);
227}
228
229void ASTRecordLayoutBuilder::UpdateAlignment(unsigned NewAlignment) {
230 if (NewAlignment <= Alignment)
231 return;
232
233 assert(llvm::isPowerOf2_32(NewAlignment && "Alignment not a power of 2"));
234
235 Alignment = NewAlignment;
236}
237
238const ASTRecordLayout *
239ASTRecordLayoutBuilder::ComputeLayout(ASTContext &Ctx,
240 const RecordDecl *D) {
241 ASTRecordLayoutBuilder Builder(Ctx);
242
243 Builder.Layout(D);
244
Anders Carlssonfc8cfa82009-07-28 19:24:15 +0000245 if (!isa<CXXRecordDecl>(D))
246 return new ASTRecordLayout(Builder.Size, Builder.Alignment, Builder.Size,
247 Builder.FieldOffsets.data(),
248 Builder.FieldOffsets.size());
Anders Carlsson6d9f6f32009-07-19 00:18:47 +0000249
Anders Carlssonfc8cfa82009-07-28 19:24:15 +0000250 // FIXME: This is not always correct. See the part about bitfields at
251 // http://www.codesourcery.com/public/cxx-abi/abi.html#POD for more info.
252 // FIXME: IsPODForThePurposeOfLayout should be stored in the record layout.
253 bool IsPODForThePurposeOfLayout = cast<CXXRecordDecl>(D)->isPOD();
254
255 assert(Builder.Bases.size() == Builder.BaseOffsets.size() &&
256 "Base offsets vector must be same size as bases vector!");
257
258 // FIXME: This should be done in FinalizeLayout.
Anders Carlsson6d9f6f32009-07-19 00:18:47 +0000259 uint64_t DataSize =
260 IsPODForThePurposeOfLayout ? Builder.Size : Builder.NextOffset;
Anders Carlssonfc8cfa82009-07-28 19:24:15 +0000261 uint64_t NonVirtualSize =
262 IsPODForThePurposeOfLayout ? DataSize : Builder.NonVirtualSize;
Anders Carlsson6d9f6f32009-07-19 00:18:47 +0000263
264 return new ASTRecordLayout(Builder.Size, Builder.Alignment, DataSize,
Anders Carlsson4f516282009-07-18 20:50:59 +0000265 Builder.FieldOffsets.data(),
Anders Carlssonfc8cfa82009-07-28 19:24:15 +0000266 Builder.FieldOffsets.size(),
267 NonVirtualSize,
268 Builder.NonVirtualAlignment,
269 Builder.Bases.data(),
270 Builder.BaseOffsets.data(),
271 Builder.Bases.size());
Anders Carlsson4f516282009-07-18 20:50:59 +0000272}
273
274const ASTRecordLayout *
275ASTRecordLayoutBuilder::ComputeLayout(ASTContext &Ctx,
276 const ObjCInterfaceDecl *D,
277 const ObjCImplementationDecl *Impl) {
278 ASTRecordLayoutBuilder Builder(Ctx);
279
280 Builder.Layout(D, Impl);
281
282 return new ASTRecordLayout(Builder.Size, Builder.Alignment,
283 Builder.NextOffset,
Anders Carlsson79474332009-07-18 20:20:21 +0000284 Builder.FieldOffsets.data(),
285 Builder.FieldOffsets.size());
286}