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