blob: fdd8d059267439b5296b5dbda3b7a53d2b50ea86 [file] [log] [blame]
Daniel Dunbar270e2032010-03-31 00:11:27 +00001//===--- CGRecordLayoutBuilder.cpp - CGRecordLayout builder ----*- C++ -*-===//
Anders Carlsson45372a62009-07-23 03:17:50 +00002//
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//
Daniel Dunbar270e2032010-03-31 00:11:27 +000010// Builder implementation for CGRecordLayout objects.
Anders Carlsson45372a62009-07-23 03:17:50 +000011//
12//===----------------------------------------------------------------------===//
13
Daniel Dunbar2924ade2010-03-30 22:26:10 +000014#include "CGRecordLayout.h"
Anders Carlsson45372a62009-07-23 03:17:50 +000015#include "clang/AST/ASTContext.h"
16#include "clang/AST/Attr.h"
17#include "clang/AST/DeclCXX.h"
18#include "clang/AST/Expr.h"
19#include "clang/AST/RecordLayout.h"
20#include "CodeGenTypes.h"
Daniel Dunbar270e2032010-03-31 00:11:27 +000021#include "llvm/Type.h"
Anders Carlsson45372a62009-07-23 03:17:50 +000022#include "llvm/DerivedTypes.h"
23#include "llvm/Target/TargetData.h"
Anders Carlsson45372a62009-07-23 03:17:50 +000024using namespace clang;
25using namespace CodeGen;
26
Daniel Dunbar270e2032010-03-31 00:11:27 +000027namespace clang {
28namespace CodeGen {
29
30class CGRecordLayoutBuilder {
31public:
32 /// FieldTypes - Holds the LLVM types that the struct is created from.
33 std::vector<const llvm::Type *> FieldTypes;
34
35 /// LLVMFieldInfo - Holds a field and its corresponding LLVM field number.
36 typedef std::pair<const FieldDecl *, unsigned> LLVMFieldInfo;
37 llvm::SmallVector<LLVMFieldInfo, 16> LLVMFields;
38
39 /// LLVMBitFieldInfo - Holds location and size information about a bit field.
Daniel Dunbarc7a984a2010-04-06 01:07:41 +000040 typedef std::pair<const FieldDecl *, CGBitFieldInfo> LLVMBitFieldInfo;
Daniel Dunbar270e2032010-03-31 00:11:27 +000041 llvm::SmallVector<LLVMBitFieldInfo, 16> LLVMBitFields;
42
43 /// ContainsPointerToDataMember - Whether one of the fields in this record
44 /// layout is a pointer to data member, or a struct that contains pointer to
45 /// data member.
46 bool ContainsPointerToDataMember;
47
48 /// Packed - Whether the resulting LLVM struct will be packed or not.
49 bool Packed;
50
51private:
52 CodeGenTypes &Types;
53
54 /// Alignment - Contains the alignment of the RecordDecl.
55 //
56 // FIXME: This is not needed and should be removed.
57 unsigned Alignment;
58
59 /// AlignmentAsLLVMStruct - Will contain the maximum alignment of all the
60 /// LLVM types.
61 unsigned AlignmentAsLLVMStruct;
62
63 /// BitsAvailableInLastField - If a bit field spans only part of a LLVM field,
64 /// this will have the number of bits still available in the field.
65 char BitsAvailableInLastField;
66
67 /// NextFieldOffsetInBytes - Holds the next field offset in bytes.
68 uint64_t NextFieldOffsetInBytes;
69
70 /// LayoutUnion - Will layout a union RecordDecl.
71 void LayoutUnion(const RecordDecl *D);
72
73 /// LayoutField - try to layout all fields in the record decl.
74 /// Returns false if the operation failed because the struct is not packed.
75 bool LayoutFields(const RecordDecl *D);
76
77 /// LayoutBases - layout the bases and vtable pointer of a record decl.
78 void LayoutBases(const CXXRecordDecl *RD, const ASTRecordLayout &Layout);
79
80 /// LayoutField - layout a single field. Returns false if the operation failed
81 /// because the current struct is not packed.
82 bool LayoutField(const FieldDecl *D, uint64_t FieldOffset);
83
84 /// LayoutBitField - layout a single bit field.
85 void LayoutBitField(const FieldDecl *D, uint64_t FieldOffset);
86
87 /// AppendField - Appends a field with the given offset and type.
88 void AppendField(uint64_t FieldOffsetInBytes, const llvm::Type *FieldTy);
89
90 /// AppendPadding - Appends enough padding bytes so that the total struct
91 /// size matches the alignment of the passed in type.
92 void AppendPadding(uint64_t FieldOffsetInBytes, const llvm::Type *FieldTy);
93
94 /// AppendPadding - Appends enough padding bytes so that the total
95 /// struct size is a multiple of the field alignment.
96 void AppendPadding(uint64_t FieldOffsetInBytes, unsigned FieldAlignment);
97
98 /// AppendBytes - Append a given number of bytes to the record.
99 void AppendBytes(uint64_t NumBytes);
100
101 /// AppendTailPadding - Append enough tail padding so that the type will have
102 /// the passed size.
103 void AppendTailPadding(uint64_t RecordSize);
104
105 unsigned getTypeAlignment(const llvm::Type *Ty) const;
106 uint64_t getTypeSizeInBytes(const llvm::Type *Ty) const;
107
108 /// CheckForPointerToDataMember - Check if the given type contains a pointer
109 /// to data member.
110 void CheckForPointerToDataMember(QualType T);
111
112public:
113 CGRecordLayoutBuilder(CodeGenTypes &Types)
114 : ContainsPointerToDataMember(false), Packed(false), Types(Types),
115 Alignment(0), AlignmentAsLLVMStruct(1),
116 BitsAvailableInLastField(0), NextFieldOffsetInBytes(0) { }
117
118 /// Layout - Will layout a RecordDecl.
119 void Layout(const RecordDecl *D);
120};
121
122}
123}
124
Anders Carlsson45372a62009-07-23 03:17:50 +0000125void CGRecordLayoutBuilder::Layout(const RecordDecl *D) {
Anders Carlssona5dd7222009-08-08 19:38:24 +0000126 Alignment = Types.getContext().getASTRecordLayout(D).getAlignment() / 8;
Anders Carlssond0eb3b92009-09-02 17:51:33 +0000127 Packed = D->hasAttr<PackedAttr>();
Anders Carlssona5dd7222009-08-08 19:38:24 +0000128
Anders Carlsson5a6e3982009-07-23 03:43:54 +0000129 if (D->isUnion()) {
130 LayoutUnion(D);
131 return;
132 }
Anders Carlssona860e752009-08-08 18:23:56 +0000133
Anders Carlsson45372a62009-07-23 03:17:50 +0000134 if (LayoutFields(D))
135 return;
Mike Stump1eb44332009-09-09 15:08:12 +0000136
Anders Carlsson45372a62009-07-23 03:17:50 +0000137 // We weren't able to layout the struct. Try again with a packed struct
Anders Carlsson4b5584b2009-07-23 17:24:40 +0000138 Packed = true;
Anders Carlsson45372a62009-07-23 03:17:50 +0000139 AlignmentAsLLVMStruct = 1;
Anders Carlssonc2cc1d52009-07-28 17:56:36 +0000140 NextFieldOffsetInBytes = 0;
Anders Carlsson45372a62009-07-23 03:17:50 +0000141 FieldTypes.clear();
Anders Carlsson45372a62009-07-23 03:17:50 +0000142 LLVMFields.clear();
143 LLVMBitFields.clear();
Mike Stump1eb44332009-09-09 15:08:12 +0000144
Anders Carlsson45372a62009-07-23 03:17:50 +0000145 LayoutFields(D);
146}
147
148void CGRecordLayoutBuilder::LayoutBitField(const FieldDecl *D,
149 uint64_t FieldOffset) {
Mike Stump1eb44332009-09-09 15:08:12 +0000150 uint64_t FieldSize =
Anders Carlsson45372a62009-07-23 03:17:50 +0000151 D->getBitWidth()->EvaluateAsInt(Types.getContext()).getZExtValue();
Mike Stump1eb44332009-09-09 15:08:12 +0000152
Anders Carlsson45372a62009-07-23 03:17:50 +0000153 if (FieldSize == 0)
154 return;
155
Anders Carlssonc2cc1d52009-07-28 17:56:36 +0000156 uint64_t NextFieldOffset = NextFieldOffsetInBytes * 8;
Anders Carlsson45372a62009-07-23 03:17:50 +0000157 unsigned NumBytesToAppend;
Mike Stump1eb44332009-09-09 15:08:12 +0000158
Anders Carlsson45372a62009-07-23 03:17:50 +0000159 if (FieldOffset < NextFieldOffset) {
160 assert(BitsAvailableInLastField && "Bitfield size mismatch!");
Anders Carlssonc2cc1d52009-07-28 17:56:36 +0000161 assert(NextFieldOffsetInBytes && "Must have laid out at least one byte!");
Mike Stump1eb44332009-09-09 15:08:12 +0000162
Anders Carlsson45372a62009-07-23 03:17:50 +0000163 // The bitfield begins in the previous bit-field.
Mike Stump1eb44332009-09-09 15:08:12 +0000164 NumBytesToAppend =
Anders Carlsson45372a62009-07-23 03:17:50 +0000165 llvm::RoundUpToAlignment(FieldSize - BitsAvailableInLastField, 8) / 8;
166 } else {
167 assert(FieldOffset % 8 == 0 && "Field offset not aligned correctly");
168
169 // Append padding if necessary.
170 AppendBytes((FieldOffset - NextFieldOffset) / 8);
Mike Stump1eb44332009-09-09 15:08:12 +0000171
172 NumBytesToAppend =
Anders Carlsson45372a62009-07-23 03:17:50 +0000173 llvm::RoundUpToAlignment(FieldSize, 8) / 8;
Mike Stump1eb44332009-09-09 15:08:12 +0000174
Anders Carlsson45372a62009-07-23 03:17:50 +0000175 assert(NumBytesToAppend && "No bytes to append!");
176 }
177
178 const llvm::Type *Ty = Types.ConvertTypeForMemRecursive(D->getType());
179 uint64_t TypeSizeInBits = getTypeSizeInBytes(Ty) * 8;
Mike Stump1eb44332009-09-09 15:08:12 +0000180
Daniel Dunbarefbf4872010-04-06 01:07:44 +0000181 bool IsSigned = D->getType()->isSignedIntegerType();
Daniel Dunbarc7a984a2010-04-06 01:07:41 +0000182 LLVMBitFields.push_back(LLVMBitFieldInfo(
Daniel Dunbar7f289642010-04-08 02:59:45 +0000183 D, CGBitFieldInfo(Ty, FieldOffset / TypeSizeInBits,
Daniel Dunbarc7a984a2010-04-06 01:07:41 +0000184 FieldOffset % TypeSizeInBits,
Daniel Dunbarefbf4872010-04-06 01:07:44 +0000185 FieldSize, IsSigned)));
Mike Stump1eb44332009-09-09 15:08:12 +0000186
Anders Carlsson45372a62009-07-23 03:17:50 +0000187 AppendBytes(NumBytesToAppend);
Mike Stump1eb44332009-09-09 15:08:12 +0000188
Mike Stump1eb44332009-09-09 15:08:12 +0000189 BitsAvailableInLastField =
Anders Carlssonc2cc1d52009-07-28 17:56:36 +0000190 NextFieldOffsetInBytes * 8 - (FieldOffset + FieldSize);
Anders Carlsson45372a62009-07-23 03:17:50 +0000191}
192
193bool CGRecordLayoutBuilder::LayoutField(const FieldDecl *D,
194 uint64_t FieldOffset) {
Anders Carlsson45372a62009-07-23 03:17:50 +0000195 // If the field is packed, then we need a packed struct.
Anders Carlssona860e752009-08-08 18:23:56 +0000196 if (!Packed && D->hasAttr<PackedAttr>())
Anders Carlsson45372a62009-07-23 03:17:50 +0000197 return false;
198
199 if (D->isBitField()) {
200 // We must use packed structs for unnamed bit fields since they
201 // don't affect the struct alignment.
Anders Carlsson4b5584b2009-07-23 17:24:40 +0000202 if (!Packed && !D->getDeclName())
Anders Carlsson45372a62009-07-23 03:17:50 +0000203 return false;
Mike Stump1eb44332009-09-09 15:08:12 +0000204
Anders Carlsson45372a62009-07-23 03:17:50 +0000205 LayoutBitField(D, FieldOffset);
206 return true;
207 }
Mike Stump1eb44332009-09-09 15:08:12 +0000208
Anders Carlsson2c12d032010-02-02 05:17:25 +0000209 // Check if we have a pointer to data member in this field.
210 CheckForPointerToDataMember(D->getType());
Daniel Dunbar270e2032010-03-31 00:11:27 +0000211
Anders Carlsson45372a62009-07-23 03:17:50 +0000212 assert(FieldOffset % 8 == 0 && "FieldOffset is not on a byte boundary!");
Anders Carlsson45372a62009-07-23 03:17:50 +0000213 uint64_t FieldOffsetInBytes = FieldOffset / 8;
Mike Stump1eb44332009-09-09 15:08:12 +0000214
Anders Carlssonde9f2c92009-08-04 16:29:15 +0000215 const llvm::Type *Ty = Types.ConvertTypeForMemRecursive(D->getType());
216 unsigned TypeAlignment = getTypeAlignment(Ty);
217
Anders Carlssona5dd7222009-08-08 19:38:24 +0000218 // If the type alignment is larger then the struct alignment, we must use
219 // a packed struct.
220 if (TypeAlignment > Alignment) {
221 assert(!Packed && "Alignment is wrong even with packed struct!");
222 return false;
223 }
Mike Stump1eb44332009-09-09 15:08:12 +0000224
Anders Carlssona5dd7222009-08-08 19:38:24 +0000225 if (const RecordType *RT = D->getType()->getAs<RecordType>()) {
226 const RecordDecl *RD = cast<RecordDecl>(RT->getDecl());
227 if (const PragmaPackAttr *PPA = RD->getAttr<PragmaPackAttr>()) {
228 if (PPA->getAlignment() != TypeAlignment * 8 && !Packed)
229 return false;
230 }
231 }
232
Anders Carlssonde9f2c92009-08-04 16:29:15 +0000233 // Round up the field offset to the alignment of the field type.
Mike Stump1eb44332009-09-09 15:08:12 +0000234 uint64_t AlignedNextFieldOffsetInBytes =
Anders Carlssonde9f2c92009-08-04 16:29:15 +0000235 llvm::RoundUpToAlignment(NextFieldOffsetInBytes, TypeAlignment);
236
237 if (FieldOffsetInBytes < AlignedNextFieldOffsetInBytes) {
238 assert(!Packed && "Could not place field even with packed struct!");
239 return false;
240 }
Mike Stump1eb44332009-09-09 15:08:12 +0000241
Anders Carlssonde9f2c92009-08-04 16:29:15 +0000242 if (AlignedNextFieldOffsetInBytes < FieldOffsetInBytes) {
243 // Even with alignment, the field offset is not at the right place,
244 // insert padding.
245 uint64_t PaddingInBytes = FieldOffsetInBytes - NextFieldOffsetInBytes;
Mike Stump1eb44332009-09-09 15:08:12 +0000246
Anders Carlssonde9f2c92009-08-04 16:29:15 +0000247 AppendBytes(PaddingInBytes);
248 }
Mike Stump1eb44332009-09-09 15:08:12 +0000249
Anders Carlsson45372a62009-07-23 03:17:50 +0000250 // Now append the field.
251 LLVMFields.push_back(LLVMFieldInfo(D, FieldTypes.size()));
Anders Carlsson728d7cd2009-07-24 02:45:50 +0000252 AppendField(FieldOffsetInBytes, Ty);
Mike Stump1eb44332009-09-09 15:08:12 +0000253
Anders Carlsson45372a62009-07-23 03:17:50 +0000254 return true;
255}
256
Anders Carlsson5a6e3982009-07-23 03:43:54 +0000257void CGRecordLayoutBuilder::LayoutUnion(const RecordDecl *D) {
258 assert(D->isUnion() && "Can't call LayoutUnion on a non-union record!");
Mike Stump1eb44332009-09-09 15:08:12 +0000259
Anders Carlsson5a6e3982009-07-23 03:43:54 +0000260 const ASTRecordLayout &Layout = Types.getContext().getASTRecordLayout(D);
Mike Stump1eb44332009-09-09 15:08:12 +0000261
Anders Carlsson5a6e3982009-07-23 03:43:54 +0000262 const llvm::Type *Ty = 0;
263 uint64_t Size = 0;
264 unsigned Align = 0;
Mike Stump1eb44332009-09-09 15:08:12 +0000265
Anders Carlsson21fd7d72010-01-28 18:22:03 +0000266 bool HasOnlyZeroSizedBitFields = true;
Daniel Dunbar270e2032010-03-31 00:11:27 +0000267
Anders Carlsson5a6e3982009-07-23 03:43:54 +0000268 unsigned FieldNo = 0;
Mike Stump1eb44332009-09-09 15:08:12 +0000269 for (RecordDecl::field_iterator Field = D->field_begin(),
Anders Carlsson5a6e3982009-07-23 03:43:54 +0000270 FieldEnd = D->field_end(); Field != FieldEnd; ++Field, ++FieldNo) {
Mike Stump1eb44332009-09-09 15:08:12 +0000271 assert(Layout.getFieldOffset(FieldNo) == 0 &&
Anders Carlsson5a6e3982009-07-23 03:43:54 +0000272 "Union field offset did not start at the beginning of record!");
Daniel Dunbar7f289642010-04-08 02:59:45 +0000273 const llvm::Type *FieldTy =
274 Types.ConvertTypeForMemRecursive(Field->getType());
Anders Carlsson2cc8f172009-07-23 04:00:39 +0000275
276 if (Field->isBitField()) {
Mike Stump1eb44332009-09-09 15:08:12 +0000277 uint64_t FieldSize =
Anders Carlsson2cc8f172009-07-23 04:00:39 +0000278 Field->getBitWidth()->EvaluateAsInt(Types.getContext()).getZExtValue();
Mike Stump1eb44332009-09-09 15:08:12 +0000279
Anders Carlsson2cc8f172009-07-23 04:00:39 +0000280 // Ignore zero sized bit fields.
281 if (FieldSize == 0)
282 continue;
Mike Stump1eb44332009-09-09 15:08:12 +0000283
Anders Carlsson94ae95f2009-07-23 22:52:34 +0000284 // Add the bit field info.
Daniel Dunbarefbf4872010-04-06 01:07:44 +0000285 bool IsSigned = Field->getType()->isSignedIntegerType();
Daniel Dunbarc7a984a2010-04-06 01:07:41 +0000286 LLVMBitFields.push_back(LLVMBitFieldInfo(
Daniel Dunbar7f289642010-04-08 02:59:45 +0000287 *Field, CGBitFieldInfo(FieldTy, 0, 0, FieldSize,
Daniel Dunbarefbf4872010-04-06 01:07:44 +0000288 IsSigned)));
Daniel Dunbar490fc902010-03-31 00:55:13 +0000289 } else {
290 LLVMFields.push_back(LLVMFieldInfo(*Field, 0));
291 }
Mike Stump1eb44332009-09-09 15:08:12 +0000292
Anders Carlsson21fd7d72010-01-28 18:22:03 +0000293 HasOnlyZeroSizedBitFields = false;
Daniel Dunbar270e2032010-03-31 00:11:27 +0000294
Anders Carlsson177d4d82009-07-23 21:52:03 +0000295 unsigned FieldAlign = Types.getTargetData().getABITypeAlignment(FieldTy);
296 uint64_t FieldSize = Types.getTargetData().getTypeAllocSize(FieldTy);
Mike Stump1eb44332009-09-09 15:08:12 +0000297
Anders Carlsson5a6e3982009-07-23 03:43:54 +0000298 if (FieldAlign < Align)
299 continue;
Mike Stump1eb44332009-09-09 15:08:12 +0000300
Anders Carlsson5a6e3982009-07-23 03:43:54 +0000301 if (FieldAlign > Align || FieldSize > Size) {
302 Ty = FieldTy;
303 Align = FieldAlign;
304 Size = FieldSize;
305 }
306 }
Mike Stump1eb44332009-09-09 15:08:12 +0000307
Anders Carlsson5a6e3982009-07-23 03:43:54 +0000308 // Now add our field.
Anders Carlsson36620002009-09-03 22:56:02 +0000309 if (Ty) {
Anders Carlsson728d7cd2009-07-24 02:45:50 +0000310 AppendField(0, Ty);
Anders Carlsson36620002009-09-03 22:56:02 +0000311
312 if (getTypeAlignment(Ty) > Layout.getAlignment() / 8) {
313 // We need a packed struct.
314 Packed = true;
315 Align = 1;
316 }
317 }
Fariborz Jahaniane5041702009-11-06 20:47:40 +0000318 if (!Align) {
Anders Carlsson21fd7d72010-01-28 18:22:03 +0000319 assert(HasOnlyZeroSizedBitFields &&
320 "0-align record did not have all zero-sized bit-fields!");
Fariborz Jahaniane5041702009-11-06 20:47:40 +0000321 Align = 1;
322 }
Daniel Dunbar270e2032010-03-31 00:11:27 +0000323
Anders Carlsson5a6e3982009-07-23 03:43:54 +0000324 // Append tail padding.
325 if (Layout.getSize() / 8 > Size)
326 AppendPadding(Layout.getSize() / 8, Align);
327}
328
Anders Carlsson4b3e5be2009-12-16 17:27:20 +0000329void CGRecordLayoutBuilder::LayoutBases(const CXXRecordDecl *RD,
330 const ASTRecordLayout &Layout) {
331 // Check if we need to add a vtable pointer.
332 if (RD->isDynamicClass() && !Layout.getPrimaryBase()) {
Daniel Dunbar270e2032010-03-31 00:11:27 +0000333 const llvm::Type *Int8PtrTy =
Anders Carlsson4b3e5be2009-12-16 17:27:20 +0000334 llvm::Type::getInt8PtrTy(Types.getLLVMContext());
Daniel Dunbar270e2032010-03-31 00:11:27 +0000335
Anders Carlsson4b3e5be2009-12-16 17:27:20 +0000336 assert(NextFieldOffsetInBytes == 0 &&
337 "Vtable pointer must come first!");
338 AppendField(NextFieldOffsetInBytes, Int8PtrTy->getPointerTo());
339 }
340}
341
Anders Carlsson45372a62009-07-23 03:17:50 +0000342bool CGRecordLayoutBuilder::LayoutFields(const RecordDecl *D) {
343 assert(!D->isUnion() && "Can't call LayoutFields on a union!");
Anders Carlssona5dd7222009-08-08 19:38:24 +0000344 assert(Alignment && "Did not set alignment!");
Mike Stump1eb44332009-09-09 15:08:12 +0000345
Anders Carlsson5a6e3982009-07-23 03:43:54 +0000346 const ASTRecordLayout &Layout = Types.getContext().getASTRecordLayout(D);
Mike Stump1eb44332009-09-09 15:08:12 +0000347
Anders Carlsson4b3e5be2009-12-16 17:27:20 +0000348 if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(D))
349 LayoutBases(RD, Layout);
Daniel Dunbar270e2032010-03-31 00:11:27 +0000350
Anders Carlsson45372a62009-07-23 03:17:50 +0000351 unsigned FieldNo = 0;
Fariborz Jahaniancad86652009-07-27 20:57:45 +0000352
Mike Stump1eb44332009-09-09 15:08:12 +0000353 for (RecordDecl::field_iterator Field = D->field_begin(),
Anders Carlsson45372a62009-07-23 03:17:50 +0000354 FieldEnd = D->field_end(); Field != FieldEnd; ++Field, ++FieldNo) {
355 if (!LayoutField(*Field, Layout.getFieldOffset(FieldNo))) {
Mike Stump1eb44332009-09-09 15:08:12 +0000356 assert(!Packed &&
Anders Carlsson45372a62009-07-23 03:17:50 +0000357 "Could not layout fields even with a packed LLVM struct!");
358 return false;
359 }
360 }
361
362 // Append tail padding if necessary.
Anders Carlssonc1efe362009-07-27 14:55:54 +0000363 AppendTailPadding(Layout.getSize());
Mike Stump1eb44332009-09-09 15:08:12 +0000364
Anders Carlsson45372a62009-07-23 03:17:50 +0000365 return true;
366}
367
Anders Carlssonc1efe362009-07-27 14:55:54 +0000368void CGRecordLayoutBuilder::AppendTailPadding(uint64_t RecordSize) {
369 assert(RecordSize % 8 == 0 && "Invalid record size!");
Mike Stump1eb44332009-09-09 15:08:12 +0000370
Anders Carlssonc1efe362009-07-27 14:55:54 +0000371 uint64_t RecordSizeInBytes = RecordSize / 8;
Anders Carlssonc2cc1d52009-07-28 17:56:36 +0000372 assert(NextFieldOffsetInBytes <= RecordSizeInBytes && "Size mismatch!");
Mike Stump1eb44332009-09-09 15:08:12 +0000373
Daniel Dunbar270e2032010-03-31 00:11:27 +0000374 uint64_t AlignedNextFieldOffset =
Anders Carlssonc2456822009-12-08 01:24:23 +0000375 llvm::RoundUpToAlignment(NextFieldOffsetInBytes, AlignmentAsLLVMStruct);
376
377 if (AlignedNextFieldOffset == RecordSizeInBytes) {
378 // We don't need any padding.
379 return;
380 }
Daniel Dunbar270e2032010-03-31 00:11:27 +0000381
Anders Carlssonc2cc1d52009-07-28 17:56:36 +0000382 unsigned NumPadBytes = RecordSizeInBytes - NextFieldOffsetInBytes;
Anders Carlssonc1efe362009-07-27 14:55:54 +0000383 AppendBytes(NumPadBytes);
384}
385
Mike Stump1eb44332009-09-09 15:08:12 +0000386void CGRecordLayoutBuilder::AppendField(uint64_t FieldOffsetInBytes,
Anders Carlsson45372a62009-07-23 03:17:50 +0000387 const llvm::Type *FieldTy) {
388 AlignmentAsLLVMStruct = std::max(AlignmentAsLLVMStruct,
389 getTypeAlignment(FieldTy));
Anders Carlsson728d7cd2009-07-24 02:45:50 +0000390
391 uint64_t FieldSizeInBytes = getTypeSizeInBytes(FieldTy);
392
Anders Carlsson45372a62009-07-23 03:17:50 +0000393 FieldTypes.push_back(FieldTy);
Anders Carlsson45372a62009-07-23 03:17:50 +0000394
Anders Carlssonc2cc1d52009-07-28 17:56:36 +0000395 NextFieldOffsetInBytes = FieldOffsetInBytes + FieldSizeInBytes;
Anders Carlsson45372a62009-07-23 03:17:50 +0000396 BitsAvailableInLastField = 0;
397}
398
Mike Stump1eb44332009-09-09 15:08:12 +0000399void
Anders Carlsson45372a62009-07-23 03:17:50 +0000400CGRecordLayoutBuilder::AppendPadding(uint64_t FieldOffsetInBytes,
401 const llvm::Type *FieldTy) {
402 AppendPadding(FieldOffsetInBytes, getTypeAlignment(FieldTy));
403}
404
Mike Stump1eb44332009-09-09 15:08:12 +0000405void CGRecordLayoutBuilder::AppendPadding(uint64_t FieldOffsetInBytes,
Anders Carlsson45372a62009-07-23 03:17:50 +0000406 unsigned FieldAlignment) {
Anders Carlsson45372a62009-07-23 03:17:50 +0000407 assert(NextFieldOffsetInBytes <= FieldOffsetInBytes &&
408 "Incorrect field layout!");
Mike Stump1eb44332009-09-09 15:08:12 +0000409
Anders Carlsson45372a62009-07-23 03:17:50 +0000410 // Round up the field offset to the alignment of the field type.
Mike Stump1eb44332009-09-09 15:08:12 +0000411 uint64_t AlignedNextFieldOffsetInBytes =
Anders Carlsson45372a62009-07-23 03:17:50 +0000412 llvm::RoundUpToAlignment(NextFieldOffsetInBytes, FieldAlignment);
413
414 if (AlignedNextFieldOffsetInBytes < FieldOffsetInBytes) {
415 // Even with alignment, the field offset is not at the right place,
416 // insert padding.
417 uint64_t PaddingInBytes = FieldOffsetInBytes - NextFieldOffsetInBytes;
418
419 AppendBytes(PaddingInBytes);
420 }
421}
422
423void CGRecordLayoutBuilder::AppendBytes(uint64_t NumBytes) {
424 if (NumBytes == 0)
425 return;
Mike Stump1eb44332009-09-09 15:08:12 +0000426
Owen Anderson0032b272009-08-13 21:57:51 +0000427 const llvm::Type *Ty = llvm::Type::getInt8Ty(Types.getLLVMContext());
Anders Carlssonc1efe362009-07-27 14:55:54 +0000428 if (NumBytes > 1)
Anders Carlsson45372a62009-07-23 03:17:50 +0000429 Ty = llvm::ArrayType::get(Ty, NumBytes);
Mike Stump1eb44332009-09-09 15:08:12 +0000430
Anders Carlsson45372a62009-07-23 03:17:50 +0000431 // Append the padding field
Anders Carlssonc2cc1d52009-07-28 17:56:36 +0000432 AppendField(NextFieldOffsetInBytes, Ty);
Anders Carlsson45372a62009-07-23 03:17:50 +0000433}
434
435unsigned CGRecordLayoutBuilder::getTypeAlignment(const llvm::Type *Ty) const {
Anders Carlsson4b5584b2009-07-23 17:24:40 +0000436 if (Packed)
Anders Carlsson45372a62009-07-23 03:17:50 +0000437 return 1;
Mike Stump1eb44332009-09-09 15:08:12 +0000438
Anders Carlsson45372a62009-07-23 03:17:50 +0000439 return Types.getTargetData().getABITypeAlignment(Ty);
440}
441
442uint64_t CGRecordLayoutBuilder::getTypeSizeInBytes(const llvm::Type *Ty) const {
443 return Types.getTargetData().getTypeAllocSize(Ty);
444}
445
Anders Carlsson2c12d032010-02-02 05:17:25 +0000446void CGRecordLayoutBuilder::CheckForPointerToDataMember(QualType T) {
Anders Carlssonfc3eaa42009-08-23 01:25:01 +0000447 // This record already contains a member pointer.
Anders Carlsson2c12d032010-02-02 05:17:25 +0000448 if (ContainsPointerToDataMember)
Anders Carlssonfc3eaa42009-08-23 01:25:01 +0000449 return;
Mike Stump1eb44332009-09-09 15:08:12 +0000450
Anders Carlssonfc3eaa42009-08-23 01:25:01 +0000451 // Can only have member pointers if we're compiling C++.
452 if (!Types.getContext().getLangOptions().CPlusPlus)
453 return;
Mike Stump1eb44332009-09-09 15:08:12 +0000454
Anders Carlsson2c12d032010-02-02 05:17:25 +0000455 T = Types.getContext().getBaseElementType(T);
Mike Stump1eb44332009-09-09 15:08:12 +0000456
Anders Carlsson2c12d032010-02-02 05:17:25 +0000457 if (const MemberPointerType *MPT = T->getAs<MemberPointerType>()) {
458 if (!MPT->getPointeeType()->isFunctionType()) {
459 // We have a pointer to data member.
460 ContainsPointerToDataMember = true;
461 }
462 } else if (const RecordType *RT = T->getAs<RecordType>()) {
463 const CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl());
Daniel Dunbar270e2032010-03-31 00:11:27 +0000464
Anders Carlsson2c12d032010-02-02 05:17:25 +0000465 // FIXME: It would be better if there was a way to explicitly compute the
466 // record layout instead of converting to a type.
467 Types.ConvertTagDeclType(RD);
Daniel Dunbar270e2032010-03-31 00:11:27 +0000468
Anders Carlsson2c12d032010-02-02 05:17:25 +0000469 const CGRecordLayout &Layout = Types.getCGRecordLayout(RD);
Daniel Dunbar270e2032010-03-31 00:11:27 +0000470
Anders Carlsson2c12d032010-02-02 05:17:25 +0000471 if (Layout.containsPointerToDataMember())
472 ContainsPointerToDataMember = true;
Daniel Dunbar270e2032010-03-31 00:11:27 +0000473 }
Anders Carlssonfc3eaa42009-08-23 01:25:01 +0000474}
475
Daniel Dunbar270e2032010-03-31 00:11:27 +0000476CGRecordLayout *CodeGenTypes::ComputeRecordLayout(const RecordDecl *D) {
477 CGRecordLayoutBuilder Builder(*this);
Mike Stump1eb44332009-09-09 15:08:12 +0000478
Anders Carlsson45372a62009-07-23 03:17:50 +0000479 Builder.Layout(D);
Anders Carlsson4c98efd2009-07-24 15:20:52 +0000480
Daniel Dunbar270e2032010-03-31 00:11:27 +0000481 const llvm::Type *Ty = llvm::StructType::get(getLLVMContext(),
Owen Anderson47a434f2009-08-05 23:18:46 +0000482 Builder.FieldTypes,
Anders Carlsson4b5584b2009-07-23 17:24:40 +0000483 Builder.Packed);
Daniel Dunbar270e2032010-03-31 00:11:27 +0000484 assert(getContext().getASTRecordLayout(D).getSize() / 8 ==
485 getTargetData().getTypeAllocSize(Ty) &&
Anders Carlssondf31e092009-08-08 18:01:57 +0000486 "Type size mismatch!");
Mike Stump1eb44332009-09-09 15:08:12 +0000487
Daniel Dunbar198bcb42010-03-31 01:09:11 +0000488 CGRecordLayout *RL =
489 new CGRecordLayout(Ty, Builder.ContainsPointerToDataMember);
490
Anders Carlsson45372a62009-07-23 03:17:50 +0000491 // Add all the field numbers.
Daniel Dunbarc7a984a2010-04-06 01:07:41 +0000492 for (unsigned i = 0, e = Builder.LLVMFields.size(); i != e; ++i)
493 RL->FieldInfo.insert(Builder.LLVMFields[i]);
Anders Carlsson45372a62009-07-23 03:17:50 +0000494
495 // Add bitfield info.
Daniel Dunbarc7a984a2010-04-06 01:07:41 +0000496 for (unsigned i = 0, e = Builder.LLVMBitFields.size(); i != e; ++i)
497 RL->BitFields.insert(Builder.LLVMBitFields[i]);
Mike Stump1eb44332009-09-09 15:08:12 +0000498
Daniel Dunbar198bcb42010-03-31 01:09:11 +0000499 return RL;
Anders Carlsson45372a62009-07-23 03:17:50 +0000500}