blob: e3581d88d24623e0dbd48a69745e14bfe17f373b [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 =
Ted Kremenekc23c7e62009-07-29 21:53:49 +000036 cast<CXXRecordDecl>(i->getType()->getAs<RecordType>()->getDecl());
Anders Carlsson6d9f6f32009-07-19 00:18:47 +000037 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
Anders Carlsson6d9f6f32009-07-19 00:18:47 +000057 // Reserve space for this base.
58 Size += BaseSize;
59
60 // Remember the next available offset.
61 NextOffset = Size;
62
63 // Remember max struct/class alignment.
64 UpdateAlignment(BaseAlign);
65}
66
Anders Carlsson79474332009-07-18 20:20:21 +000067void ASTRecordLayoutBuilder::Layout(const RecordDecl *D) {
68 IsUnion = D->isUnion();
69
70 if (const PackedAttr* PA = D->getAttr<PackedAttr>())
71 StructPacking = PA->getAlignment();
72
73 if (const AlignedAttr *AA = D->getAttr<AlignedAttr>())
74 UpdateAlignment(AA->getAlignment());
Anders Carlsson6d9f6f32009-07-19 00:18:47 +000075
76 // If this is a C++ class, lay out the nonvirtual bases.
77 if (Ctx.getLangOptions().CPlusPlus)
78 LayoutNonVirtualBases(cast<CXXRecordDecl>(D));
79
Anders Carlsson118ce162009-07-18 21:48:39 +000080 LayoutFields(D);
Anders Carlsson79474332009-07-18 20:20:21 +000081
Anders Carlssonfc8cfa82009-07-28 19:24:15 +000082 NonVirtualSize = Size;
83 NonVirtualAlignment = Alignment;
84
Anders Carlsson79474332009-07-18 20:20:21 +000085 // Finally, round the size of the total struct up to the alignment of the
86 // struct itself.
87 FinishLayout();
88}
89
Anders Carlsson4f516282009-07-18 20:50:59 +000090void ASTRecordLayoutBuilder::Layout(const ObjCInterfaceDecl *D,
91 const ObjCImplementationDecl *Impl) {
92 if (ObjCInterfaceDecl *SD = D->getSuperClass()) {
93 const ASTRecordLayout &SL = Ctx.getASTObjCInterfaceLayout(SD);
94
95 UpdateAlignment(SL.getAlignment());
96
97 // We start laying out ivars not at the end of the superclass
98 // structure, but at the next byte following the last field.
Anders Carlsson27b50132009-07-18 21:26:44 +000099 Size = llvm::RoundUpToAlignment(SL.getDataSize(), 8);
Anders Carlsson4f516282009-07-18 20:50:59 +0000100 NextOffset = Size;
101 }
102
103 if (const PackedAttr *PA = D->getAttr<PackedAttr>())
104 StructPacking = PA->getAlignment();
105
106 if (const AlignedAttr *AA = D->getAttr<AlignedAttr>())
107 UpdateAlignment(AA->getAlignment());
108
109 // Layout each ivar sequentially.
110 llvm::SmallVector<ObjCIvarDecl*, 16> Ivars;
111 Ctx.ShallowCollectObjCIvars(D, Ivars, Impl);
112 for (unsigned i = 0, e = Ivars.size(); i != e; ++i)
113 LayoutField(Ivars[i]);
114
115 // Finally, round the size of the total struct up to the alignment of the
116 // struct itself.
117 FinishLayout();
118}
119
Anders Carlsson118ce162009-07-18 21:48:39 +0000120void ASTRecordLayoutBuilder::LayoutFields(const RecordDecl *D) {
121 // Layout each field, for now, just sequentially, respecting alignment. In
122 // the future, this will need to be tweakable by targets.
123 for (RecordDecl::field_iterator Field = D->field_begin(),
124 FieldEnd = D->field_end(); Field != FieldEnd; ++Field)
125 LayoutField(*Field);
126}
127
Anders Carlsson79474332009-07-18 20:20:21 +0000128void ASTRecordLayoutBuilder::LayoutField(const FieldDecl *D) {
129 unsigned FieldPacking = StructPacking;
130 uint64_t FieldOffset = IsUnion ? 0 : Size;
131 uint64_t FieldSize;
132 unsigned FieldAlign;
133
134 // FIXME: Should this override struct packing? Probably we want to
135 // take the minimum?
136 if (const PackedAttr *PA = D->getAttr<PackedAttr>())
137 FieldPacking = PA->getAlignment();
138
139 if (const Expr *BitWidthExpr = D->getBitWidth()) {
140 // TODO: Need to check this algorithm on other targets!
141 // (tested on Linux-X86)
142 FieldSize = BitWidthExpr->EvaluateAsInt(Ctx).getZExtValue();
143
144 std::pair<uint64_t, unsigned> FieldInfo = Ctx.getTypeInfo(D->getType());
145 uint64_t TypeSize = FieldInfo.first;
146
147 // Determine the alignment of this bitfield. The packing
148 // attributes define a maximum and the alignment attribute defines
149 // a minimum.
150 // FIXME: What is the right behavior when the specified alignment
151 // is smaller than the specified packing?
152 FieldAlign = FieldInfo.second;
153 if (FieldPacking)
154 FieldAlign = std::min(FieldAlign, FieldPacking);
155 if (const AlignedAttr *AA = D->getAttr<AlignedAttr>())
156 FieldAlign = std::max(FieldAlign, AA->getAlignment());
157
158 // Check if we need to add padding to give the field the correct
159 // alignment.
160 if (FieldSize == 0 || (FieldOffset & (FieldAlign-1)) + FieldSize > TypeSize)
161 FieldOffset = (FieldOffset + (FieldAlign-1)) & ~(FieldAlign-1);
162
163 // Padding members don't affect overall alignment
164 if (!D->getIdentifier())
165 FieldAlign = 1;
166 } else {
167 if (D->getType()->isIncompleteArrayType()) {
168 // This is a flexible array member; we can't directly
169 // query getTypeInfo about these, so we figure it out here.
170 // Flexible array members don't have any size, but they
171 // have to be aligned appropriately for their element type.
172 FieldSize = 0;
173 const ArrayType* ATy = Ctx.getAsArrayType(D->getType());
174 FieldAlign = Ctx.getTypeAlign(ATy->getElementType());
Ted Kremenekc23c7e62009-07-29 21:53:49 +0000175 } else if (const ReferenceType *RT = D->getType()->getAs<ReferenceType>()) {
Anders Carlsson79474332009-07-18 20:20:21 +0000176 unsigned AS = RT->getPointeeType().getAddressSpace();
177 FieldSize = Ctx.Target.getPointerWidth(AS);
178 FieldAlign = Ctx.Target.getPointerAlign(AS);
179 } else {
180 std::pair<uint64_t, unsigned> FieldInfo = Ctx.getTypeInfo(D->getType());
181 FieldSize = FieldInfo.first;
182 FieldAlign = FieldInfo.second;
183 }
184
185 // Determine the alignment of this bitfield. The packing
186 // attributes define a maximum and the alignment attribute defines
187 // a minimum. Additionally, the packing alignment must be at least
188 // a byte for non-bitfields.
189 //
190 // FIXME: What is the right behavior when the specified alignment
191 // is smaller than the specified packing?
192 if (FieldPacking)
193 FieldAlign = std::min(FieldAlign, std::max(8U, FieldPacking));
194 if (const AlignedAttr *AA = D->getAttr<AlignedAttr>())
195 FieldAlign = std::max(FieldAlign, AA->getAlignment());
196
197 // Round up the current record size to the field's alignment boundary.
198 FieldOffset = (FieldOffset + (FieldAlign-1)) & ~(FieldAlign-1);
199 }
200
201 // Place this field at the current location.
202 FieldOffsets.push_back(FieldOffset);
203
204 // Reserve space for this field.
205 if (IsUnion)
206 Size = std::max(Size, FieldSize);
207 else
208 Size = FieldOffset + FieldSize;
209
210 // Remember the next available offset.
211 NextOffset = Size;
212
213 // Remember max struct/class alignment.
214 UpdateAlignment(FieldAlign);
215}
216
217void ASTRecordLayoutBuilder::FinishLayout() {
218 // In C++, records cannot be of size 0.
219 if (Ctx.getLangOptions().CPlusPlus && Size == 0)
220 Size = 8;
221 // Finally, round the size of the record up to the alignment of the
222 // record itself.
223 Size = (Size + (Alignment-1)) & ~(Alignment-1);
224}
225
226void ASTRecordLayoutBuilder::UpdateAlignment(unsigned NewAlignment) {
227 if (NewAlignment <= Alignment)
228 return;
229
230 assert(llvm::isPowerOf2_32(NewAlignment && "Alignment not a power of 2"));
231
232 Alignment = NewAlignment;
233}
234
235const ASTRecordLayout *
236ASTRecordLayoutBuilder::ComputeLayout(ASTContext &Ctx,
237 const RecordDecl *D) {
238 ASTRecordLayoutBuilder Builder(Ctx);
239
240 Builder.Layout(D);
241
Anders Carlssonfc8cfa82009-07-28 19:24:15 +0000242 if (!isa<CXXRecordDecl>(D))
243 return new ASTRecordLayout(Builder.Size, Builder.Alignment, Builder.Size,
244 Builder.FieldOffsets.data(),
245 Builder.FieldOffsets.size());
Anders Carlsson6d9f6f32009-07-19 00:18:47 +0000246
Anders Carlssonfc8cfa82009-07-28 19:24:15 +0000247 // FIXME: This is not always correct. See the part about bitfields at
248 // http://www.codesourcery.com/public/cxx-abi/abi.html#POD for more info.
249 // FIXME: IsPODForThePurposeOfLayout should be stored in the record layout.
250 bool IsPODForThePurposeOfLayout = cast<CXXRecordDecl>(D)->isPOD();
251
252 assert(Builder.Bases.size() == Builder.BaseOffsets.size() &&
253 "Base offsets vector must be same size as bases vector!");
254
255 // FIXME: This should be done in FinalizeLayout.
Anders Carlsson6d9f6f32009-07-19 00:18:47 +0000256 uint64_t DataSize =
257 IsPODForThePurposeOfLayout ? Builder.Size : Builder.NextOffset;
Anders Carlssonfc8cfa82009-07-28 19:24:15 +0000258 uint64_t NonVirtualSize =
259 IsPODForThePurposeOfLayout ? DataSize : Builder.NonVirtualSize;
Anders Carlsson6d9f6f32009-07-19 00:18:47 +0000260
261 return new ASTRecordLayout(Builder.Size, Builder.Alignment, DataSize,
Anders Carlsson4f516282009-07-18 20:50:59 +0000262 Builder.FieldOffsets.data(),
Anders Carlssonfc8cfa82009-07-28 19:24:15 +0000263 Builder.FieldOffsets.size(),
264 NonVirtualSize,
265 Builder.NonVirtualAlignment,
266 Builder.Bases.data(),
267 Builder.BaseOffsets.data(),
268 Builder.Bases.size());
Anders Carlsson4f516282009-07-18 20:50:59 +0000269}
270
271const ASTRecordLayout *
272ASTRecordLayoutBuilder::ComputeLayout(ASTContext &Ctx,
273 const ObjCInterfaceDecl *D,
274 const ObjCImplementationDecl *Impl) {
275 ASTRecordLayoutBuilder Builder(Ctx);
276
277 Builder.Layout(D, Impl);
278
279 return new ASTRecordLayout(Builder.Size, Builder.Alignment,
280 Builder.NextOffset,
Anders Carlsson79474332009-07-18 20:20:21 +0000281 Builder.FieldOffsets.data(),
282 Builder.FieldOffsets.size());
283}