 |
|
 |
|
| Files: |
1 |
|
Branches Taken: |
83.3% |
110 / 132 |
| Generated: |
2010-02-10 01:31 |
|
Branches Executed: |
98.5% |
130 / 132 |
| |
|
Line Coverage: |
96.8% |
183 / 189 |
| |
 |
|
 |
1 : //===--- CGRecordLayoutBuilder.cpp - Record builder helper ------*- C++ -*-===//
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 : // This is a helper class used to build CGRecordLayout objects and LLVM types.
11 : //
12 : //===----------------------------------------------------------------------===//
13 :
14 : #include "CGRecordLayoutBuilder.h"
15 :
16 : #include "clang/AST/ASTContext.h"
17 : #include "clang/AST/Attr.h"
18 : #include "clang/AST/DeclCXX.h"
19 : #include "clang/AST/Expr.h"
20 : #include "clang/AST/RecordLayout.h"
21 : #include "CodeGenTypes.h"
22 : #include "llvm/DerivedTypes.h"
23 : #include "llvm/Target/TargetData.h"
24 :
25 :
26 : using namespace clang;
27 : using namespace CodeGen;
28 :
29 1341: void CGRecordLayoutBuilder::Layout(const RecordDecl *D) {
30 1341: Alignment = Types.getContext().getASTRecordLayout(D).getAlignment() / 8;
31 1341: Packed = D->hasAttr<PackedAttr>();
32 :
46: branch 1 taken
1295: branch 2 taken
33 1341: if (D->isUnion()) {
34 46: LayoutUnion(D);
35 46: return;
36 : }
37 :
1270: branch 1 taken
25: branch 2 taken
38 1295: if (LayoutFields(D))
39 1270: return;
40 :
41 : // We weren't able to layout the struct. Try again with a packed struct
42 25: Packed = true;
43 25: AlignmentAsLLVMStruct = 1;
44 25: NextFieldOffsetInBytes = 0;
45 25: FieldTypes.clear();
46 25: LLVMFields.clear();
47 25: LLVMBitFields.clear();
48 :
49 25: LayoutFields(D);
50 : }
51 :
52 : void CGRecordLayoutBuilder::LayoutBitField(const FieldDecl *D,
53 116: uint64_t FieldOffset) {
54 : uint64_t FieldSize =
55 116: D->getBitWidth()->EvaluateAsInt(Types.getContext()).getZExtValue();
56 :
21: branch 0 taken
95: branch 1 taken
57 116: if (FieldSize == 0)
58 21: return;
59 :
60 95: uint64_t NextFieldOffset = NextFieldOffsetInBytes * 8;
61 : unsigned NumBytesToAppend;
62 :
35: branch 0 taken
60: branch 1 taken
63 95: if (FieldOffset < NextFieldOffset) {
0: branch 0 not taken
35: branch 1 taken
64 35: assert(BitsAvailableInLastField && "Bitfield size mismatch!");
0: branch 0 not taken
35: branch 1 taken
65 35: assert(NextFieldOffsetInBytes && "Must have laid out at least one byte!");
66 :
67 : // The bitfield begins in the previous bit-field.
68 : NumBytesToAppend =
69 35: llvm::RoundUpToAlignment(FieldSize - BitsAvailableInLastField, 8) / 8;
70 : } else {
0: branch 0 not taken
60: branch 1 taken
71 60: assert(FieldOffset % 8 == 0 && "Field offset not aligned correctly");
72 :
73 : // Append padding if necessary.
74 60: AppendBytes((FieldOffset - NextFieldOffset) / 8);
75 :
76 : NumBytesToAppend =
77 60: llvm::RoundUpToAlignment(FieldSize, 8) / 8;
78 :
0: branch 0 not taken
60: branch 1 taken
79 60: assert(NumBytesToAppend && "No bytes to append!");
80 : }
81 :
82 95: const llvm::Type *Ty = Types.ConvertTypeForMemRecursive(D->getType());
83 95: uint64_t TypeSizeInBits = getTypeSizeInBytes(Ty) * 8;
84 :
85 : LLVMBitFields.push_back(LLVMBitFieldInfo(D, FieldOffset / TypeSizeInBits,
86 : FieldOffset % TypeSizeInBits,
87 95: FieldSize));
88 :
89 95: AppendBytes(NumBytesToAppend);
90 :
91 : BitsAvailableInLastField =
92 95: NextFieldOffsetInBytes * 8 - (FieldOffset + FieldSize);
93 : }
94 :
95 : bool CGRecordLayoutBuilder::LayoutField(const FieldDecl *D,
96 1829: uint64_t FieldOffset) {
97 : // If the field is packed, then we need a packed struct.
1773: branch 0 taken
56: branch 1 taken
3: branch 3 taken
1770: branch 4 taken
3: branch 5 taken
1826: branch 6 taken
98 1829: if (!Packed && D->hasAttr<PackedAttr>())
99 3: return false;
100 :
134: branch 1 taken
1692: branch 2 taken
101 1826: if (D->isBitField()) {
102 : // We must use packed structs for unnamed bit fields since they
103 : // don't affect the struct alignment.
107: branch 0 taken
27: branch 1 taken
18: branch 4 taken
89: branch 5 taken
18: branch 6 taken
116: branch 7 taken
104 134: if (!Packed && !D->getDeclName())
105 18: return false;
106 :
107 116: LayoutBitField(D, FieldOffset);
108 116: return true;
109 : }
110 :
111 : // Check if we have a pointer to data member in this field.
112 1692: CheckForPointerToDataMember(D->getType());
113 :
0: branch 0 not taken
1692: branch 1 taken
114 1692: assert(FieldOffset % 8 == 0 && "FieldOffset is not on a byte boundary!");
115 1692: uint64_t FieldOffsetInBytes = FieldOffset / 8;
116 :
117 1692: const llvm::Type *Ty = Types.ConvertTypeForMemRecursive(D->getType());
118 1692: unsigned TypeAlignment = getTypeAlignment(Ty);
119 :
120 : // If the type alignment is larger then the struct alignment, we must use
121 : // a packed struct.
3: branch 0 taken
1689: branch 1 taken
122 1692: if (TypeAlignment > Alignment) {
0: branch 0 not taken
3: branch 1 taken
123 3: assert(!Packed && "Alignment is wrong even with packed struct!");
124 3: return false;
125 : }
126 :
101: branch 3 taken
1588: branch 4 taken
127 1689: if (const RecordType *RT = D->getType()->getAs<RecordType>()) {
128 101: const RecordDecl *RD = cast<RecordDecl>(RT->getDecl());
3: branch 1 taken
98: branch 2 taken
129 101: if (const PragmaPackAttr *PPA = RD->getAttr<PragmaPackAttr>()) {
2: branch 1 taken
1: branch 2 taken
1: branch 3 taken
1: branch 4 taken
1: branch 5 taken
2: branch 6 taken
130 3: if (PPA->getAlignment() != TypeAlignment * 8 && !Packed)
131 1: return false;
132 : }
133 : }
134 :
135 : // Round up the field offset to the alignment of the field type.
136 : uint64_t AlignedNextFieldOffsetInBytes =
137 1688: llvm::RoundUpToAlignment(NextFieldOffsetInBytes, TypeAlignment);
138 :
0: branch 0 not taken
1688: branch 1 taken
139 1688: if (FieldOffsetInBytes < AlignedNextFieldOffsetInBytes) {
0: branch 0 not taken
0: branch 1 not taken
140 0: assert(!Packed && "Could not place field even with packed struct!");
141 0: return false;
142 : }
143 :
54: branch 0 taken
1634: branch 1 taken
144 1688: if (AlignedNextFieldOffsetInBytes < FieldOffsetInBytes) {
145 : // Even with alignment, the field offset is not at the right place,
146 : // insert padding.
147 54: uint64_t PaddingInBytes = FieldOffsetInBytes - NextFieldOffsetInBytes;
148 :
149 54: AppendBytes(PaddingInBytes);
150 : }
151 :
152 : // Now append the field.
153 1688: LLVMFields.push_back(LLVMFieldInfo(D, FieldTypes.size()));
154 1688: AppendField(FieldOffsetInBytes, Ty);
155 :
156 1688: return true;
157 : }
158 :
159 46: void CGRecordLayoutBuilder::LayoutUnion(const RecordDecl *D) {
46: branch 1 taken
0: branch 2 not taken
160 46: assert(D->isUnion() && "Can't call LayoutUnion on a non-union record!");
161 :
162 46: const ASTRecordLayout &Layout = Types.getContext().getASTRecordLayout(D);
163 :
164 46: const llvm::Type *Ty = 0;
165 46: uint64_t Size = 0;
166 46: unsigned Align = 0;
167 :
168 46: bool HasOnlyZeroSizedBitFields = true;
169 :
170 46: unsigned FieldNo = 0;
80: branch 3 taken
46: branch 4 taken
171 172: for (RecordDecl::field_iterator Field = D->field_begin(),
172 46: FieldEnd = D->field_end(); Field != FieldEnd; ++Field, ++FieldNo) {
173 : assert(Layout.getFieldOffset(FieldNo) == 0 &&
80: branch 1 taken
0: branch 2 not taken
174 80: "Union field offset did not start at the beginning of record!");
175 :
2: branch 2 taken
78: branch 3 taken
176 80: if (Field->isBitField()) {
177 : uint64_t FieldSize =
178 2: Field->getBitWidth()->EvaluateAsInt(Types.getContext()).getZExtValue();
179 :
180 : // Ignore zero sized bit fields.
1: branch 0 taken
1: branch 1 taken
181 2: if (FieldSize == 0)
182 1: continue;
183 :
184 : // Add the bit field info.
185 1: Types.addBitFieldInfo(*Field, 0, 0, FieldSize);
186 : } else
187 78: Types.addFieldInfo(*Field, 0);
188 :
189 79: HasOnlyZeroSizedBitFields = false;
190 :
191 : const llvm::Type *FieldTy =
192 79: Types.ConvertTypeForMemRecursive(Field->getType());
193 79: unsigned FieldAlign = Types.getTargetData().getABITypeAlignment(FieldTy);
194 79: uint64_t FieldSize = Types.getTargetData().getTypeAllocSize(FieldTy);
195 :
6: branch 0 taken
73: branch 1 taken
196 79: if (FieldAlign < Align)
197 6: continue;
198 :
27: branch 0 taken
46: branch 1 taken
3: branch 2 taken
24: branch 3 taken
199 73: if (FieldAlign > Align || FieldSize > Size) {
200 49: Ty = FieldTy;
201 49: Align = FieldAlign;
202 49: Size = FieldSize;
203 : }
204 : }
205 :
206 : // Now add our field.
41: branch 0 taken
5: branch 1 taken
207 46: if (Ty) {
208 41: AppendField(0, Ty);
209 :
2: branch 2 taken
39: branch 3 taken
210 41: if (getTypeAlignment(Ty) > Layout.getAlignment() / 8) {
211 : // We need a packed struct.
212 2: Packed = true;
213 2: Align = 1;
214 : }
215 : }
5: branch 0 taken
41: branch 1 taken
216 46: if (!Align) {
217 : assert(HasOnlyZeroSizedBitFields &&
0: branch 0 not taken
5: branch 1 taken
218 5: "0-align record did not have all zero-sized bit-fields!");
219 5: Align = 1;
220 : }
221 :
222 : // Append tail padding.
5: branch 1 taken
41: branch 2 taken
223 46: if (Layout.getSize() / 8 > Size)
224 5: AppendPadding(Layout.getSize() / 8, Align);
225 46: }
226 :
227 : void CGRecordLayoutBuilder::LayoutBases(const CXXRecordDecl *RD,
228 750: const ASTRecordLayout &Layout) {
229 : // Check if we need to add a vtable pointer.
331: branch 1 taken
419: branch 2 taken
203: branch 4 taken
128: branch 5 taken
203: branch 6 taken
547: branch 7 taken
230 750: if (RD->isDynamicClass() && !Layout.getPrimaryBase()) {
231 : const llvm::Type *Int8PtrTy =
232 203: llvm::Type::getInt8PtrTy(Types.getLLVMContext());
233 :
234 : assert(NextFieldOffsetInBytes == 0 &&
0: branch 0 not taken
203: branch 1 taken
235 203: "Vtable pointer must come first!");
236 203: AppendField(NextFieldOffsetInBytes, Int8PtrTy->getPointerTo());
237 : }
238 750: }
239 :
240 1320: bool CGRecordLayoutBuilder::LayoutFields(const RecordDecl *D) {
1320: branch 1 taken
0: branch 2 not taken
241 1320: assert(!D->isUnion() && "Can't call LayoutFields on a union!");
0: branch 0 not taken
1320: branch 1 taken
242 1320: assert(Alignment && "Did not set alignment!");
243 :
244 1320: const ASTRecordLayout &Layout = Types.getContext().getASTRecordLayout(D);
245 :
750: branch 1 taken
570: branch 2 taken
246 1320: if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(D))
247 750: LayoutBases(RD, Layout);
248 :
249 1320: unsigned FieldNo = 0;
250 :
1829: branch 3 taken
1295: branch 4 taken
251 4444: for (RecordDecl::field_iterator Field = D->field_begin(),
252 1320: FieldEnd = D->field_end(); Field != FieldEnd; ++Field, ++FieldNo) {
25: branch 3 taken
1804: branch 4 taken
253 1829: if (!LayoutField(*Field, Layout.getFieldOffset(FieldNo))) {
254 : assert(!Packed &&
0: branch 0 not taken
25: branch 1 taken
255 25: "Could not layout fields even with a packed LLVM struct!");
256 25: return false;
257 : }
258 : }
259 :
260 : // Append tail padding if necessary.
261 1295: AppendTailPadding(Layout.getSize());
262 :
263 1295: return true;
264 : }
265 :
266 1295: void CGRecordLayoutBuilder::AppendTailPadding(uint64_t RecordSize) {
0: branch 0 not taken
1295: branch 1 taken
267 1295: assert(RecordSize % 8 == 0 && "Invalid record size!");
268 :
269 1295: uint64_t RecordSizeInBytes = RecordSize / 8;
0: branch 0 not taken
1295: branch 1 taken
270 1295: assert(NextFieldOffsetInBytes <= RecordSizeInBytes && "Size mismatch!");
271 :
272 : uint64_t AlignedNextFieldOffset =
273 1295: llvm::RoundUpToAlignment(NextFieldOffsetInBytes, AlignmentAsLLVMStruct);
274 :
888: branch 0 taken
407: branch 1 taken
275 1295: if (AlignedNextFieldOffset == RecordSizeInBytes) {
276 : // We don't need any padding.
277 888: return;
278 : }
279 :
280 407: unsigned NumPadBytes = RecordSizeInBytes - NextFieldOffsetInBytes;
281 407: AppendBytes(NumPadBytes);
282 : }
283 :
284 : void CGRecordLayoutBuilder::AppendField(uint64_t FieldOffsetInBytes,
285 2461: const llvm::Type *FieldTy) {
286 : AlignmentAsLLVMStruct = std::max(AlignmentAsLLVMStruct,
287 2461: getTypeAlignment(FieldTy));
288 :
289 2461: uint64_t FieldSizeInBytes = getTypeSizeInBytes(FieldTy);
290 :
291 2461: FieldTypes.push_back(FieldTy);
292 :
293 2461: NextFieldOffsetInBytes = FieldOffsetInBytes + FieldSizeInBytes;
294 2461: BitsAvailableInLastField = 0;
295 2461: }
296 :
297 : void
298 : CGRecordLayoutBuilder::AppendPadding(uint64_t FieldOffsetInBytes,
299 0: const llvm::Type *FieldTy) {
300 0: AppendPadding(FieldOffsetInBytes, getTypeAlignment(FieldTy));
301 0: }
302 :
303 : void CGRecordLayoutBuilder::AppendPadding(uint64_t FieldOffsetInBytes,
304 5: unsigned FieldAlignment) {
305 : assert(NextFieldOffsetInBytes <= FieldOffsetInBytes &&
0: branch 0 not taken
5: branch 1 taken
306 5: "Incorrect field layout!");
307 :
308 : // Round up the field offset to the alignment of the field type.
309 : uint64_t AlignedNextFieldOffsetInBytes =
310 5: llvm::RoundUpToAlignment(NextFieldOffsetInBytes, FieldAlignment);
311 :
5: branch 0 taken
0: branch 1 not taken
312 5: if (AlignedNextFieldOffsetInBytes < FieldOffsetInBytes) {
313 : // Even with alignment, the field offset is not at the right place,
314 : // insert padding.
315 5: uint64_t PaddingInBytes = FieldOffsetInBytes - NextFieldOffsetInBytes;
316 :
317 5: AppendBytes(PaddingInBytes);
318 : }
319 5: }
320 :
321 621: void CGRecordLayoutBuilder::AppendBytes(uint64_t NumBytes) {
92: branch 0 taken
529: branch 1 taken
322 621: if (NumBytes == 0)
323 92: return;
324 :
325 529: const llvm::Type *Ty = llvm::Type::getInt8Ty(Types.getLLVMContext());
269: branch 0 taken
260: branch 1 taken
326 529: if (NumBytes > 1)
327 269: Ty = llvm::ArrayType::get(Ty, NumBytes);
328 :
329 : // Append the padding field
330 529: AppendField(NextFieldOffsetInBytes, Ty);
331 : }
332 :
333 4194: unsigned CGRecordLayoutBuilder::getTypeAlignment(const llvm::Type *Ty) const {
75: branch 0 taken
4119: branch 1 taken
334 4194: if (Packed)
335 75: return 1;
336 :
337 4119: return Types.getTargetData().getABITypeAlignment(Ty);
338 : }
339 :
340 2556: uint64_t CGRecordLayoutBuilder::getTypeSizeInBytes(const llvm::Type *Ty) const {
341 2556: return Types.getTargetData().getTypeAllocSize(Ty);
342 : }
343 :
344 1692: void CGRecordLayoutBuilder::CheckForPointerToDataMember(QualType T) {
345 : // This record already contains a member pointer.
0: branch 0 not taken
1692: branch 1 taken
346 1692: if (ContainsPointerToDataMember)
347 0: return;
348 :
349 : // Can only have member pointers if we're compiling C++.
1233: branch 2 taken
459: branch 3 taken
350 1692: if (!Types.getContext().getLangOptions().CPlusPlus)
351 1233: return;
352 :
353 459: T = Types.getContext().getBaseElementType(T);
354 :
10: branch 2 taken
449: branch 3 taken
355 459: if (const MemberPointerType *MPT = T->getAs<MemberPointerType>()) {
5: branch 3 taken
5: branch 4 taken
356 10: if (!MPT->getPointeeType()->isFunctionType()) {
357 : // We have a pointer to data member.
358 5: ContainsPointerToDataMember = true;
359 : }
82: branch 2 taken
367: branch 3 taken
360 449: } else if (const RecordType *RT = T->getAs<RecordType>()) {
361 82: const CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl());
362 :
363 : // FIXME: It would be better if there was a way to explicitly compute the
364 : // record layout instead of converting to a type.
365 82: Types.ConvertTagDeclType(RD);
366 :
367 82: const CGRecordLayout &Layout = Types.getCGRecordLayout(RD);
368 :
1: branch 1 taken
81: branch 2 taken
369 82: if (Layout.containsPointerToDataMember())
370 1: ContainsPointerToDataMember = true;
371 : }
372 : }
373 :
374 : CGRecordLayout *
375 : CGRecordLayoutBuilder::ComputeLayout(CodeGenTypes &Types,
376 1341: const RecordDecl *D) {
377 1341: CGRecordLayoutBuilder Builder(Types);
378 :
379 1341: Builder.Layout(D);
380 :
381 : const llvm::Type *Ty = llvm::StructType::get(Types.getLLVMContext(),
382 : Builder.FieldTypes,
383 1341: Builder.Packed);
384 : assert(Types.getContext().getASTRecordLayout(D).getSize() / 8 ==
385 : Types.getTargetData().getTypeAllocSize(Ty) &&
1341: branch 5 taken
0: branch 6 not taken
386 1341: "Type size mismatch!");
387 :
388 : // Add all the field numbers.
1677: branch 1 taken
1341: branch 2 taken
389 3018: for (unsigned i = 0, e = Builder.LLVMFields.size(); i != e; ++i) {
390 1677: const FieldDecl *FD = Builder.LLVMFields[i].first;
391 1677: unsigned FieldNo = Builder.LLVMFields[i].second;
392 :
393 1677: Types.addFieldInfo(FD, FieldNo);
394 : }
395 :
396 : // Add bitfield info.
92: branch 1 taken
1341: branch 2 taken
397 1433: for (unsigned i = 0, e = Builder.LLVMBitFields.size(); i != e; ++i) {
398 92: const LLVMBitFieldInfo &Info = Builder.LLVMBitFields[i];
399 :
400 92: Types.addBitFieldInfo(Info.FD, Info.FieldNo, Info.Start, Info.Size);
401 : }
402 :
403 1341: return new CGRecordLayout(Ty, Builder.ContainsPointerToDataMember);
404 : }
Generated: 2010-02-10 01:31 by zcov