1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | |
10 | |
11 | |
12 | |
13 | #include "CGRecordLayout.h" |
14 | #include "CGCXXABI.h" |
15 | #include "CodeGenTypes.h" |
16 | #include "clang/AST/ASTContext.h" |
17 | #include "clang/AST/Attr.h" |
18 | #include "clang/AST/CXXInheritance.h" |
19 | #include "clang/AST/DeclCXX.h" |
20 | #include "clang/AST/Expr.h" |
21 | #include "clang/AST/RecordLayout.h" |
22 | #include "clang/Basic/CodeGenOptions.h" |
23 | #include "llvm/IR/DataLayout.h" |
24 | #include "llvm/IR/DerivedTypes.h" |
25 | #include "llvm/IR/Type.h" |
26 | #include "llvm/Support/Debug.h" |
27 | #include "llvm/Support/MathExtras.h" |
28 | #include "llvm/Support/raw_ostream.h" |
29 | using namespace clang; |
30 | using namespace CodeGen; |
31 | |
32 | namespace { |
33 | |
34 | |
35 | |
36 | |
37 | |
38 | |
39 | |
40 | |
41 | |
42 | |
43 | |
44 | |
45 | |
46 | |
47 | |
48 | |
49 | |
50 | |
51 | |
52 | |
53 | |
54 | |
55 | |
56 | |
57 | |
58 | |
59 | |
60 | |
61 | |
62 | |
63 | |
64 | |
65 | |
66 | |
67 | |
68 | |
69 | |
70 | |
71 | |
72 | |
73 | struct CGRecordLowering { |
74 | |
75 | |
76 | |
77 | struct MemberInfo { |
78 | CharUnits Offset; |
79 | enum InfoKind { VFPtr, VBPtr, Field, Base, VBase, Scissor } Kind; |
80 | llvm::Type *Data; |
81 | union { |
82 | const FieldDecl *FD; |
83 | const CXXRecordDecl *RD; |
84 | }; |
85 | MemberInfo(CharUnits Offset, InfoKind Kind, llvm::Type *Data, |
86 | const FieldDecl *FD = nullptr) |
87 | : Offset(Offset), Kind(Kind), Data(Data), FD(FD) {} |
88 | MemberInfo(CharUnits Offset, InfoKind Kind, llvm::Type *Data, |
89 | const CXXRecordDecl *RD) |
90 | : Offset(Offset), Kind(Kind), Data(Data), RD(RD) {} |
91 | |
92 | bool operator <(const MemberInfo& a) const { return Offset < a.Offset; } |
93 | }; |
94 | |
95 | CGRecordLowering(CodeGenTypes &Types, const RecordDecl *D, bool Packed); |
96 | |
97 | |
98 | MemberInfo StorageInfo(CharUnits Offset, llvm::Type *Data) { |
99 | return MemberInfo(Offset, MemberInfo::Field, Data); |
100 | } |
101 | |
102 | |
103 | |
104 | |
105 | |
106 | |
107 | bool isDiscreteBitFieldABI() { |
108 | return Context.getTargetInfo().getCXXABI().isMicrosoft() || |
109 | D->isMsStruct(Context); |
110 | } |
111 | |
112 | |
113 | |
114 | |
115 | |
116 | bool isOverlappingVBaseABI() { |
117 | return !Context.getTargetInfo().getCXXABI().isMicrosoft(); |
118 | } |
119 | |
120 | |
121 | llvm::Type *getIntNType(uint64_t NumBits) { |
122 | return llvm::Type::getIntNTy(Types.getLLVMContext(), |
123 | (unsigned)llvm::alignTo(NumBits, 8)); |
124 | } |
125 | |
126 | llvm::Type *getByteArrayType(CharUnits NumBytes) { |
127 | (0) . __assert_fail ("!NumBytes.isZero() && \"Empty byte arrays aren't allowed.\"", "/home/seafit/code_projects/clang_source/clang/lib/CodeGen/CGRecordLayoutBuilder.cpp", 127, __PRETTY_FUNCTION__))" file_link="../../../include/assert.h.html#88" macro="true">assert(!NumBytes.isZero() && "Empty byte arrays aren't allowed."); |
128 | llvm::Type *Type = llvm::Type::getInt8Ty(Types.getLLVMContext()); |
129 | return NumBytes == CharUnits::One() ? Type : |
130 | (llvm::Type *)llvm::ArrayType::get(Type, NumBytes.getQuantity()); |
131 | } |
132 | |
133 | |
134 | llvm::Type *getStorageType(const FieldDecl *FD) { |
135 | llvm::Type *Type = Types.ConvertTypeForMem(FD->getType()); |
136 | if (!FD->isBitField()) return Type; |
137 | if (isDiscreteBitFieldABI()) return Type; |
138 | return getIntNType(std::min(FD->getBitWidthValue(Context), |
139 | (unsigned)Context.toBits(getSize(Type)))); |
140 | } |
141 | |
142 | llvm::Type *getStorageType(const CXXRecordDecl *RD) { |
143 | return Types.getCGRecordLayout(RD).getBaseSubobjectLLVMType(); |
144 | } |
145 | CharUnits bitsToCharUnits(uint64_t BitOffset) { |
146 | return Context.toCharUnitsFromBits(BitOffset); |
147 | } |
148 | CharUnits getSize(llvm::Type *Type) { |
149 | return CharUnits::fromQuantity(DataLayout.getTypeAllocSize(Type)); |
150 | } |
151 | CharUnits getAlignment(llvm::Type *Type) { |
152 | return CharUnits::fromQuantity(DataLayout.getABITypeAlignment(Type)); |
153 | } |
154 | bool isZeroInitializable(const FieldDecl *FD) { |
155 | return Types.isZeroInitializable(FD->getType()); |
156 | } |
157 | bool isZeroInitializable(const RecordDecl *RD) { |
158 | return Types.isZeroInitializable(RD); |
159 | } |
160 | void appendPaddingBytes(CharUnits Size) { |
161 | if (!Size.isZero()) |
162 | FieldTypes.push_back(getByteArrayType(Size)); |
163 | } |
164 | uint64_t getFieldBitOffset(const FieldDecl *FD) { |
165 | return Layout.getFieldOffset(FD->getFieldIndex()); |
166 | } |
167 | |
168 | void setBitFieldInfo(const FieldDecl *FD, CharUnits StartOffset, |
169 | llvm::Type *StorageType); |
170 | |
171 | void lower(bool NonVirtualBaseType); |
172 | void lowerUnion(); |
173 | void accumulateFields(); |
174 | void accumulateBitFields(RecordDecl::field_iterator Field, |
175 | RecordDecl::field_iterator FieldEnd); |
176 | void accumulateBases(); |
177 | void accumulateVPtrs(); |
178 | void accumulateVBases(); |
179 | |
180 | |
181 | bool hasOwnStorage(const CXXRecordDecl *Decl, const CXXRecordDecl *Query); |
182 | void calculateZeroInit(); |
183 | |
184 | |
185 | void clipTailPadding(); |
186 | |
187 | void determinePacked(bool NVBaseType); |
188 | |
189 | void insertPadding(); |
190 | |
191 | void fillOutputFields(); |
192 | |
193 | CodeGenTypes &Types; |
194 | const ASTContext &Context; |
195 | const RecordDecl *D; |
196 | const CXXRecordDecl *RD; |
197 | const ASTRecordLayout &Layout; |
198 | const llvm::DataLayout &DataLayout; |
199 | |
200 | std::vector<MemberInfo> Members; |
201 | |
202 | SmallVector<llvm::Type *, 16> FieldTypes; |
203 | llvm::DenseMap<const FieldDecl *, unsigned> Fields; |
204 | llvm::DenseMap<const FieldDecl *, CGBitFieldInfo> BitFields; |
205 | llvm::DenseMap<const CXXRecordDecl *, unsigned> NonVirtualBases; |
206 | llvm::DenseMap<const CXXRecordDecl *, unsigned> VirtualBases; |
207 | bool IsZeroInitializable : 1; |
208 | bool IsZeroInitializableAsBase : 1; |
209 | bool Packed : 1; |
210 | private: |
211 | CGRecordLowering(const CGRecordLowering &) = delete; |
212 | void operator =(const CGRecordLowering &) = delete; |
213 | }; |
214 | } |
215 | |
216 | CGRecordLowering::CGRecordLowering(CodeGenTypes &Types, const RecordDecl *D, |
217 | bool Packed) |
218 | : Types(Types), Context(Types.getContext()), D(D), |
219 | RD(dyn_cast<CXXRecordDecl>(D)), |
220 | Layout(Types.getContext().getASTRecordLayout(D)), |
221 | DataLayout(Types.getDataLayout()), IsZeroInitializable(true), |
222 | IsZeroInitializableAsBase(true), Packed(Packed) {} |
223 | |
224 | void CGRecordLowering::setBitFieldInfo( |
225 | const FieldDecl *FD, CharUnits StartOffset, llvm::Type *StorageType) { |
226 | CGBitFieldInfo &Info = BitFields[FD->getCanonicalDecl()]; |
227 | Info.IsSigned = FD->getType()->isSignedIntegerOrEnumerationType(); |
228 | Info.Offset = (unsigned)(getFieldBitOffset(FD) - Context.toBits(StartOffset)); |
229 | Info.Size = FD->getBitWidthValue(Context); |
230 | Info.StorageSize = (unsigned)DataLayout.getTypeAllocSizeInBits(StorageType); |
231 | Info.StorageOffset = StartOffset; |
232 | if (Info.Size > Info.StorageSize) |
233 | Info.Size = Info.StorageSize; |
234 | |
235 | |
236 | |
237 | |
238 | if (DataLayout.isBigEndian()) |
239 | Info.Offset = Info.StorageSize - (Info.Offset + Info.Size); |
240 | } |
241 | |
242 | void CGRecordLowering::lower(bool NVBaseType) { |
243 | |
244 | |
245 | |
246 | |
247 | |
248 | |
249 | |
250 | |
251 | |
252 | |
253 | |
254 | |
255 | |
256 | |
257 | |
258 | |
259 | |
260 | |
261 | |
262 | |
263 | CharUnits Size = NVBaseType ? Layout.getNonVirtualSize() : Layout.getSize(); |
264 | if (D->isUnion()) |
265 | return lowerUnion(); |
266 | accumulateFields(); |
267 | |
268 | if (RD) { |
269 | accumulateVPtrs(); |
270 | accumulateBases(); |
271 | if (Members.empty()) |
272 | return appendPaddingBytes(Size); |
273 | if (!NVBaseType) |
274 | accumulateVBases(); |
275 | } |
276 | std::stable_sort(Members.begin(), Members.end()); |
277 | Members.push_back(StorageInfo(Size, getIntNType(8))); |
278 | clipTailPadding(); |
279 | determinePacked(NVBaseType); |
280 | insertPadding(); |
281 | Members.pop_back(); |
282 | calculateZeroInit(); |
283 | fillOutputFields(); |
284 | } |
285 | |
286 | void CGRecordLowering::lowerUnion() { |
287 | CharUnits LayoutSize = Layout.getSize(); |
288 | llvm::Type *StorageType = nullptr; |
289 | bool SeenNamedMember = false; |
290 | |
291 | |
292 | |
293 | |
294 | |
295 | for (const auto *Field : D->fields()) { |
296 | if (Field->isBitField()) { |
297 | if (Field->isZeroLengthBitField(Context)) |
298 | continue; |
299 | llvm::Type *FieldType = getStorageType(Field); |
300 | if (LayoutSize < getSize(FieldType)) |
301 | FieldType = getByteArrayType(LayoutSize); |
302 | setBitFieldInfo(Field, CharUnits::Zero(), FieldType); |
303 | } |
304 | Fields[Field->getCanonicalDecl()] = 0; |
305 | llvm::Type *FieldType = getStorageType(Field); |
306 | |
307 | |
308 | |
309 | |
310 | |
311 | |
312 | if (!SeenNamedMember) { |
313 | SeenNamedMember = Field->getIdentifier(); |
314 | if (!SeenNamedMember) |
315 | if (const auto *FieldRD = Field->getType()->getAsRecordDecl()) |
316 | SeenNamedMember = FieldRD->findFirstNamedDataMember(); |
317 | if (SeenNamedMember && !isZeroInitializable(Field)) { |
318 | IsZeroInitializable = IsZeroInitializableAsBase = false; |
319 | StorageType = FieldType; |
320 | } |
321 | } |
322 | |
323 | |
324 | if (!IsZeroInitializable) |
325 | continue; |
326 | |
327 | if (!StorageType || |
328 | getAlignment(FieldType) > getAlignment(StorageType) || |
329 | (getAlignment(FieldType) == getAlignment(StorageType) && |
330 | getSize(FieldType) > getSize(StorageType))) |
331 | StorageType = FieldType; |
332 | } |
333 | |
334 | if (!StorageType) |
335 | return appendPaddingBytes(LayoutSize); |
336 | |
337 | |
338 | if (LayoutSize < getSize(StorageType)) |
339 | StorageType = getByteArrayType(LayoutSize); |
340 | FieldTypes.push_back(StorageType); |
341 | appendPaddingBytes(LayoutSize - getSize(StorageType)); |
342 | |
343 | if (LayoutSize % getAlignment(StorageType)) |
344 | Packed = true; |
345 | } |
346 | |
347 | void CGRecordLowering::accumulateFields() { |
348 | for (RecordDecl::field_iterator Field = D->field_begin(), |
349 | FieldEnd = D->field_end(); |
350 | Field != FieldEnd;) |
351 | if (Field->isBitField()) { |
352 | RecordDecl::field_iterator Start = Field; |
353 | |
354 | for (++Field; Field != FieldEnd && Field->isBitField(); ++Field); |
355 | accumulateBitFields(Start, Field); |
356 | } else { |
357 | Members.push_back(MemberInfo( |
358 | bitsToCharUnits(getFieldBitOffset(*Field)), MemberInfo::Field, |
359 | getStorageType(*Field), *Field)); |
360 | ++Field; |
361 | } |
362 | } |
363 | |
364 | void |
365 | CGRecordLowering::accumulateBitFields(RecordDecl::field_iterator Field, |
366 | RecordDecl::field_iterator FieldEnd) { |
367 | |
368 | |
369 | |
370 | |
371 | |
372 | RecordDecl::field_iterator Run = FieldEnd; |
373 | |
374 | |
375 | |
376 | uint64_t StartBitOffset, Tail = 0; |
377 | if (isDiscreteBitFieldABI()) { |
378 | for (; Field != FieldEnd; ++Field) { |
379 | uint64_t BitOffset = getFieldBitOffset(*Field); |
380 | |
381 | if (Field->isZeroLengthBitField(Context)) { |
382 | Run = FieldEnd; |
383 | continue; |
384 | } |
385 | llvm::Type *Type = Types.ConvertTypeForMem(Field->getType()); |
386 | |
387 | |
388 | if (Run == FieldEnd || BitOffset >= Tail) { |
389 | Run = Field; |
390 | StartBitOffset = BitOffset; |
391 | Tail = StartBitOffset + DataLayout.getTypeAllocSizeInBits(Type); |
392 | |
393 | |
394 | |
395 | Members.push_back(StorageInfo(bitsToCharUnits(StartBitOffset), Type)); |
396 | } |
397 | |
398 | |
399 | Members.push_back(MemberInfo(bitsToCharUnits(StartBitOffset), |
400 | MemberInfo::Field, nullptr, *Field)); |
401 | } |
402 | return; |
403 | } |
404 | |
405 | |
406 | |
407 | |
408 | |
409 | auto IsBetterAsSingleFieldRun = [&](uint64_t OffsetInRecord, |
410 | uint64_t StartBitOffset) { |
411 | if (!Types.getCodeGenOpts().FineGrainedBitfieldAccesses) |
412 | return false; |
413 | if (!DataLayout.isLegalInteger(OffsetInRecord)) |
414 | return false; |
415 | |
416 | |
417 | if (StartBitOffset % |
418 | Context.toBits(getAlignment(getIntNType(OffsetInRecord))) != |
419 | 0) |
420 | return false; |
421 | return true; |
422 | }; |
423 | |
424 | |
425 | bool StartFieldAsSingleRun = false; |
426 | for (;;) { |
427 | |
428 | if (Run == FieldEnd) { |
429 | |
430 | if (Field == FieldEnd) |
431 | break; |
432 | |
433 | if (!Field->isZeroLengthBitField(Context)) { |
434 | Run = Field; |
435 | StartBitOffset = getFieldBitOffset(*Field); |
436 | Tail = StartBitOffset + Field->getBitWidthValue(Context); |
437 | StartFieldAsSingleRun = IsBetterAsSingleFieldRun(Tail - StartBitOffset, |
438 | StartBitOffset); |
439 | } |
440 | ++Field; |
441 | continue; |
442 | } |
443 | |
444 | |
445 | |
446 | |
447 | |
448 | |
449 | |
450 | |
451 | |
452 | |
453 | if (!StartFieldAsSingleRun && Field != FieldEnd && |
454 | !IsBetterAsSingleFieldRun(Tail - StartBitOffset, StartBitOffset) && |
455 | (!Field->isZeroLengthBitField(Context) || |
456 | (!Context.getTargetInfo().useZeroLengthBitfieldAlignment() && |
457 | !Context.getTargetInfo().useBitFieldTypeAlignment())) && |
458 | Tail == getFieldBitOffset(*Field)) { |
459 | Tail += Field->getBitWidthValue(Context); |
460 | ++Field; |
461 | continue; |
462 | } |
463 | |
464 | |
465 | llvm::Type *Type = getIntNType(Tail - StartBitOffset); |
466 | |
467 | |
468 | |
469 | Members.push_back(StorageInfo(bitsToCharUnits(StartBitOffset), Type)); |
470 | for (; Run != Field; ++Run) |
471 | Members.push_back(MemberInfo(bitsToCharUnits(StartBitOffset), |
472 | MemberInfo::Field, nullptr, *Run)); |
473 | Run = FieldEnd; |
474 | StartFieldAsSingleRun = false; |
475 | } |
476 | } |
477 | |
478 | void CGRecordLowering::accumulateBases() { |
479 | |
480 | if (Layout.isPrimaryBaseVirtual()) { |
481 | const CXXRecordDecl *BaseDecl = Layout.getPrimaryBase(); |
482 | Members.push_back(MemberInfo(CharUnits::Zero(), MemberInfo::Base, |
483 | getStorageType(BaseDecl), BaseDecl)); |
484 | } |
485 | |
486 | for (const auto &Base : RD->bases()) { |
487 | if (Base.isVirtual()) |
488 | continue; |
489 | |
490 | |
491 | |
492 | const CXXRecordDecl *BaseDecl = Base.getType()->getAsCXXRecordDecl(); |
493 | if (!BaseDecl->isEmpty() && |
494 | !Context.getASTRecordLayout(BaseDecl).getNonVirtualSize().isZero()) |
495 | Members.push_back(MemberInfo(Layout.getBaseClassOffset(BaseDecl), |
496 | MemberInfo::Base, getStorageType(BaseDecl), BaseDecl)); |
497 | } |
498 | } |
499 | |
500 | void CGRecordLowering::accumulateVPtrs() { |
501 | if (Layout.hasOwnVFPtr()) |
502 | Members.push_back(MemberInfo(CharUnits::Zero(), MemberInfo::VFPtr, |
503 | llvm::FunctionType::get(getIntNType(32), )-> |
504 | getPointerTo()->getPointerTo())); |
505 | if (Layout.hasOwnVBPtr()) |
506 | Members.push_back(MemberInfo(Layout.getVBPtrOffset(), MemberInfo::VBPtr, |
507 | llvm::Type::getInt32PtrTy(Types.getLLVMContext()))); |
508 | } |
509 | |
510 | void CGRecordLowering::accumulateVBases() { |
511 | CharUnits ScissorOffset = Layout.getNonVirtualSize(); |
512 | |
513 | |
514 | |
515 | |
516 | if (isOverlappingVBaseABI()) |
517 | for (const auto &Base : RD->vbases()) { |
518 | const CXXRecordDecl *BaseDecl = Base.getType()->getAsCXXRecordDecl(); |
519 | if (BaseDecl->isEmpty()) |
520 | continue; |
521 | |
522 | |
523 | if (Context.isNearlyEmpty(BaseDecl) && !hasOwnStorage(RD, BaseDecl)) |
524 | continue; |
525 | ScissorOffset = std::min(ScissorOffset, |
526 | Layout.getVBaseClassOffset(BaseDecl)); |
527 | } |
528 | Members.push_back(MemberInfo(ScissorOffset, MemberInfo::Scissor, nullptr, |
529 | RD)); |
530 | for (const auto &Base : RD->vbases()) { |
531 | const CXXRecordDecl *BaseDecl = Base.getType()->getAsCXXRecordDecl(); |
532 | if (BaseDecl->isEmpty()) |
533 | continue; |
534 | CharUnits Offset = Layout.getVBaseClassOffset(BaseDecl); |
535 | |
536 | |
537 | if (isOverlappingVBaseABI() && |
538 | Context.isNearlyEmpty(BaseDecl) && |
539 | !hasOwnStorage(RD, BaseDecl)) { |
540 | Members.push_back(MemberInfo(Offset, MemberInfo::VBase, nullptr, |
541 | BaseDecl)); |
542 | continue; |
543 | } |
544 | |
545 | if (Layout.getVBaseOffsetsMap().find(BaseDecl)->second.hasVtorDisp()) |
546 | Members.push_back(StorageInfo(Offset - CharUnits::fromQuantity(4), |
547 | getIntNType(32))); |
548 | Members.push_back(MemberInfo(Offset, MemberInfo::VBase, |
549 | getStorageType(BaseDecl), BaseDecl)); |
550 | } |
551 | } |
552 | |
553 | bool CGRecordLowering::hasOwnStorage(const CXXRecordDecl *Decl, |
554 | const CXXRecordDecl *Query) { |
555 | const ASTRecordLayout &DeclLayout = Context.getASTRecordLayout(Decl); |
556 | if (DeclLayout.isPrimaryBaseVirtual() && DeclLayout.getPrimaryBase() == Query) |
557 | return false; |
558 | for (const auto &Base : Decl->bases()) |
559 | if (!hasOwnStorage(Base.getType()->getAsCXXRecordDecl(), Query)) |
560 | return false; |
561 | return true; |
562 | } |
563 | |
564 | void CGRecordLowering::calculateZeroInit() { |
565 | for (std::vector<MemberInfo>::const_iterator Member = Members.begin(), |
566 | MemberEnd = Members.end(); |
567 | IsZeroInitializableAsBase && Member != MemberEnd; ++Member) { |
568 | if (Member->Kind == MemberInfo::Field) { |
569 | if (!Member->FD || isZeroInitializable(Member->FD)) |
570 | continue; |
571 | IsZeroInitializable = IsZeroInitializableAsBase = false; |
572 | } else if (Member->Kind == MemberInfo::Base || |
573 | Member->Kind == MemberInfo::VBase) { |
574 | if (isZeroInitializable(Member->RD)) |
575 | continue; |
576 | IsZeroInitializable = false; |
577 | if (Member->Kind == MemberInfo::Base) |
578 | IsZeroInitializableAsBase = false; |
579 | } |
580 | } |
581 | } |
582 | |
583 | void CGRecordLowering::clipTailPadding() { |
584 | std::vector<MemberInfo>::iterator Prior = Members.begin(); |
585 | CharUnits Tail = getSize(Prior->Data); |
586 | for (std::vector<MemberInfo>::iterator Member = Prior + 1, |
587 | MemberEnd = Members.end(); |
588 | Member != MemberEnd; ++Member) { |
589 | |
590 | if (!Member->Data && Member->Kind != MemberInfo::Scissor) |
591 | continue; |
592 | if (Member->Offset < Tail) { |
593 | (0) . __assert_fail ("Prior->Kind == MemberInfo..Field && !Prior->FD && \"Only storage fields have tail padding!\"", "/home/seafit/code_projects/clang_source/clang/lib/CodeGen/CGRecordLayoutBuilder.cpp", 594, __PRETTY_FUNCTION__))" file_link="../../../include/assert.h.html#88" macro="true">assert(Prior->Kind == MemberInfo::Field && !Prior->FD && |
594 | (0) . __assert_fail ("Prior->Kind == MemberInfo..Field && !Prior->FD && \"Only storage fields have tail padding!\"", "/home/seafit/code_projects/clang_source/clang/lib/CodeGen/CGRecordLayoutBuilder.cpp", 594, __PRETTY_FUNCTION__))" file_link="../../../include/assert.h.html#88" macro="true"> "Only storage fields have tail padding!"); |
595 | Prior->Data = getByteArrayType(bitsToCharUnits(llvm::alignTo( |
596 | cast<llvm::IntegerType>(Prior->Data)->getIntegerBitWidth(), 8))); |
597 | } |
598 | if (Member->Data) |
599 | Prior = Member; |
600 | Tail = Prior->Offset + getSize(Prior->Data); |
601 | } |
602 | } |
603 | |
604 | void CGRecordLowering::determinePacked(bool NVBaseType) { |
605 | if (Packed) |
606 | return; |
607 | CharUnits Alignment = CharUnits::One(); |
608 | CharUnits NVAlignment = CharUnits::One(); |
609 | CharUnits NVSize = |
610 | !NVBaseType && RD ? Layout.getNonVirtualSize() : CharUnits::Zero(); |
611 | for (std::vector<MemberInfo>::const_iterator Member = Members.begin(), |
612 | MemberEnd = Members.end(); |
613 | Member != MemberEnd; ++Member) { |
614 | if (!Member->Data) |
615 | continue; |
616 | |
617 | |
618 | if (Member->Offset % getAlignment(Member->Data)) |
619 | Packed = true; |
620 | if (Member->Offset < NVSize) |
621 | NVAlignment = std::max(NVAlignment, getAlignment(Member->Data)); |
622 | Alignment = std::max(Alignment, getAlignment(Member->Data)); |
623 | } |
624 | |
625 | |
626 | if (Members.back().Offset % Alignment) |
627 | Packed = true; |
628 | |
629 | |
630 | |
631 | if (NVSize % NVAlignment) |
632 | Packed = true; |
633 | |
634 | if (!Packed) |
635 | Members.back().Data = getIntNType(Context.toBits(Alignment)); |
636 | } |
637 | |
638 | void CGRecordLowering::insertPadding() { |
639 | std::vector<std::pair<CharUnits, CharUnits> > Padding; |
640 | CharUnits Size = CharUnits::Zero(); |
641 | for (std::vector<MemberInfo>::const_iterator Member = Members.begin(), |
642 | MemberEnd = Members.end(); |
643 | Member != MemberEnd; ++Member) { |
644 | if (!Member->Data) |
645 | continue; |
646 | CharUnits Offset = Member->Offset; |
647 | = Size", "/home/seafit/code_projects/clang_source/clang/lib/CodeGen/CGRecordLayoutBuilder.cpp", 647, __PRETTY_FUNCTION__))" file_link="../../../include/assert.h.html#88" macro="true">assert(Offset >= Size); |
648 | |
649 | if (Offset != |
650 | Size.alignTo(Packed ? CharUnits::One() : getAlignment(Member->Data))) |
651 | Padding.push_back(std::make_pair(Size, Offset - Size)); |
652 | Size = Offset + getSize(Member->Data); |
653 | } |
654 | if (Padding.empty()) |
655 | return; |
656 | |
657 | for (std::vector<std::pair<CharUnits, CharUnits> >::const_iterator |
658 | Pad = Padding.begin(), PadEnd = Padding.end(); |
659 | Pad != PadEnd; ++Pad) |
660 | Members.push_back(StorageInfo(Pad->first, getByteArrayType(Pad->second))); |
661 | std::stable_sort(Members.begin(), Members.end()); |
662 | } |
663 | |
664 | void CGRecordLowering::fillOutputFields() { |
665 | for (std::vector<MemberInfo>::const_iterator Member = Members.begin(), |
666 | MemberEnd = Members.end(); |
667 | Member != MemberEnd; ++Member) { |
668 | if (Member->Data) |
669 | FieldTypes.push_back(Member->Data); |
670 | if (Member->Kind == MemberInfo::Field) { |
671 | if (Member->FD) |
672 | Fields[Member->FD->getCanonicalDecl()] = FieldTypes.size() - 1; |
673 | |
674 | if (!Member->Data) |
675 | setBitFieldInfo(Member->FD, Member->Offset, FieldTypes.back()); |
676 | } else if (Member->Kind == MemberInfo::Base) |
677 | NonVirtualBases[Member->RD] = FieldTypes.size() - 1; |
678 | else if (Member->Kind == MemberInfo::VBase) |
679 | VirtualBases[Member->RD] = FieldTypes.size() - 1; |
680 | } |
681 | } |
682 | |
683 | CGBitFieldInfo CGBitFieldInfo::MakeInfo(CodeGenTypes &Types, |
684 | const FieldDecl *FD, |
685 | uint64_t Offset, uint64_t Size, |
686 | uint64_t StorageSize, |
687 | CharUnits StorageOffset) { |
688 | |
689 | |
690 | |
691 | llvm::Type *Ty = Types.ConvertTypeForMem(FD->getType()); |
692 | CharUnits TypeSizeInBytes = |
693 | CharUnits::fromQuantity(Types.getDataLayout().getTypeAllocSize(Ty)); |
694 | uint64_t TypeSizeInBits = Types.getContext().toBits(TypeSizeInBytes); |
695 | |
696 | bool IsSigned = FD->getType()->isSignedIntegerOrEnumerationType(); |
697 | |
698 | if (Size > TypeSizeInBits) { |
699 | |
700 | |
701 | |
702 | |
703 | |
704 | |
705 | |
706 | |
707 | |
708 | Size = TypeSizeInBits; |
709 | } |
710 | |
711 | |
712 | |
713 | |
714 | |
715 | if (Types.getDataLayout().isBigEndian()) { |
716 | Offset = StorageSize - (Offset + Size); |
717 | } |
718 | |
719 | return CGBitFieldInfo(Offset, Size, IsSigned, StorageSize, StorageOffset); |
720 | } |
721 | |
722 | CGRecordLayout *CodeGenTypes::ComputeRecordLayout(const RecordDecl *D, |
723 | llvm::StructType *Ty) { |
724 | CGRecordLowering Builder(*this, D, ); |
725 | |
726 | Builder.lower(); |
727 | |
728 | |
729 | llvm::StructType *BaseTy = nullptr; |
730 | if (isa<CXXRecordDecl>(D) && !D->isUnion() && !D->hasAttr<FinalAttr>()) { |
731 | BaseTy = Ty; |
732 | if (Builder.Layout.getNonVirtualSize() != Builder.Layout.getSize()) { |
733 | CGRecordLowering BaseBuilder(*this, D, .Packed); |
734 | BaseBuilder.lower(); |
735 | BaseTy = llvm::StructType::create( |
736 | getLLVMContext(), BaseBuilder.FieldTypes, "", BaseBuilder.Packed); |
737 | addRecordTypeName(D, BaseTy, ".base"); |
738 | |
739 | |
740 | (0) . __assert_fail ("Builder.Packed == BaseBuilder.Packed && \"Non-virtual and complete types must agree on packedness\"", "/home/seafit/code_projects/clang_source/clang/lib/CodeGen/CGRecordLayoutBuilder.cpp", 741, __PRETTY_FUNCTION__))" file_link="../../../include/assert.h.html#88" macro="true">assert(Builder.Packed == BaseBuilder.Packed && |
741 | (0) . __assert_fail ("Builder.Packed == BaseBuilder.Packed && \"Non-virtual and complete types must agree on packedness\"", "/home/seafit/code_projects/clang_source/clang/lib/CodeGen/CGRecordLayoutBuilder.cpp", 741, __PRETTY_FUNCTION__))" file_link="../../../include/assert.h.html#88" macro="true"> "Non-virtual and complete types must agree on packedness"); |
742 | } |
743 | } |
744 | |
745 | |
746 | |
747 | |
748 | Ty->setBody(Builder.FieldTypes, Builder.Packed); |
749 | |
750 | CGRecordLayout *RL = |
751 | new CGRecordLayout(Ty, BaseTy, Builder.IsZeroInitializable, |
752 | Builder.IsZeroInitializableAsBase); |
753 | |
754 | RL->NonVirtualBases.swap(Builder.NonVirtualBases); |
755 | RL->CompleteObjectVirtualBases.swap(Builder.VirtualBases); |
756 | |
757 | |
758 | RL->FieldInfo.swap(Builder.Fields); |
759 | |
760 | |
761 | RL->BitFields.swap(Builder.BitFields); |
762 | |
763 | |
764 | if (getContext().getLangOpts().DumpRecordLayouts) { |
765 | llvm::outs() << "\n*** Dumping IRgen Record Layout\n"; |
766 | llvm::outs() << "Record: "; |
767 | D->dump(llvm::outs()); |
768 | llvm::outs() << "\nLayout: "; |
769 | RL->print(llvm::outs()); |
770 | } |
771 | |
772 | #ifndef NDEBUG |
773 | |
774 | const ASTRecordLayout &Layout = getContext().getASTRecordLayout(D); |
775 | |
776 | uint64_t TypeSizeInBits = getContext().toBits(Layout.getSize()); |
777 | (0) . __assert_fail ("TypeSizeInBits == getDataLayout().getTypeAllocSizeInBits(Ty) && \"Type size mismatch!\"", "/home/seafit/code_projects/clang_source/clang/lib/CodeGen/CGRecordLayoutBuilder.cpp", 778, __PRETTY_FUNCTION__))" file_link="../../../include/assert.h.html#88" macro="true">assert(TypeSizeInBits == getDataLayout().getTypeAllocSizeInBits(Ty) && |
778 | (0) . __assert_fail ("TypeSizeInBits == getDataLayout().getTypeAllocSizeInBits(Ty) && \"Type size mismatch!\"", "/home/seafit/code_projects/clang_source/clang/lib/CodeGen/CGRecordLayoutBuilder.cpp", 778, __PRETTY_FUNCTION__))" file_link="../../../include/assert.h.html#88" macro="true"> "Type size mismatch!"); |
779 | |
780 | if (BaseTy) { |
781 | CharUnits NonVirtualSize = Layout.getNonVirtualSize(); |
782 | |
783 | uint64_t AlignedNonVirtualTypeSizeInBits = |
784 | getContext().toBits(NonVirtualSize); |
785 | |
786 | (0) . __assert_fail ("AlignedNonVirtualTypeSizeInBits == getDataLayout().getTypeAllocSizeInBits(BaseTy) && \"Type size mismatch!\"", "/home/seafit/code_projects/clang_source/clang/lib/CodeGen/CGRecordLayoutBuilder.cpp", 788, __PRETTY_FUNCTION__))" file_link="../../../include/assert.h.html#88" macro="true">assert(AlignedNonVirtualTypeSizeInBits == |
787 | (0) . __assert_fail ("AlignedNonVirtualTypeSizeInBits == getDataLayout().getTypeAllocSizeInBits(BaseTy) && \"Type size mismatch!\"", "/home/seafit/code_projects/clang_source/clang/lib/CodeGen/CGRecordLayoutBuilder.cpp", 788, __PRETTY_FUNCTION__))" file_link="../../../include/assert.h.html#88" macro="true"> getDataLayout().getTypeAllocSizeInBits(BaseTy) && |
788 | (0) . __assert_fail ("AlignedNonVirtualTypeSizeInBits == getDataLayout().getTypeAllocSizeInBits(BaseTy) && \"Type size mismatch!\"", "/home/seafit/code_projects/clang_source/clang/lib/CodeGen/CGRecordLayoutBuilder.cpp", 788, __PRETTY_FUNCTION__))" file_link="../../../include/assert.h.html#88" macro="true"> "Type size mismatch!"); |
789 | } |
790 | |
791 | |
792 | llvm::StructType *ST = RL->getLLVMType(); |
793 | const llvm::StructLayout *SL = getDataLayout().getStructLayout(ST); |
794 | |
795 | const ASTRecordLayout &AST_RL = getContext().getASTRecordLayout(D); |
796 | RecordDecl::field_iterator it = D->field_begin(); |
797 | for (unsigned i = 0, e = AST_RL.getFieldCount(); i != e; ++i, ++it) { |
798 | const FieldDecl *FD = *it; |
799 | |
800 | |
801 | |
802 | if (!FD->isBitField()) { |
803 | unsigned FieldNo = RL->getLLVMFieldNo(FD); |
804 | (0) . __assert_fail ("AST_RL.getFieldOffset(i) == SL->getElementOffsetInBits(FieldNo) && \"Invalid field offset!\"", "/home/seafit/code_projects/clang_source/clang/lib/CodeGen/CGRecordLayoutBuilder.cpp", 805, __PRETTY_FUNCTION__))" file_link="../../../include/assert.h.html#88" macro="true">assert(AST_RL.getFieldOffset(i) == SL->getElementOffsetInBits(FieldNo) && |
805 | (0) . __assert_fail ("AST_RL.getFieldOffset(i) == SL->getElementOffsetInBits(FieldNo) && \"Invalid field offset!\"", "/home/seafit/code_projects/clang_source/clang/lib/CodeGen/CGRecordLayoutBuilder.cpp", 805, __PRETTY_FUNCTION__))" file_link="../../../include/assert.h.html#88" macro="true"> "Invalid field offset!"); |
806 | continue; |
807 | } |
808 | |
809 | |
810 | if (!FD->getDeclName()) |
811 | continue; |
812 | |
813 | |
814 | if (FD->isZeroLengthBitField(getContext())) |
815 | continue; |
816 | |
817 | const CGBitFieldInfo &Info = RL->getBitFieldInfo(FD); |
818 | llvm::Type *ElementTy = ST->getTypeAtIndex(RL->getLLVMFieldNo(FD)); |
819 | |
820 | |
821 | |
822 | |
823 | if (D->isUnion()) { |
824 | |
825 | |
826 | |
827 | |
828 | if (getDataLayout().isBigEndian()) |
829 | (0) . __assert_fail ("static_cast(Info.Offset + Info.Size) == Info.StorageSize && \"Big endian union bitfield does not end at the back\"", "/home/seafit/code_projects/clang_source/clang/lib/CodeGen/CGRecordLayoutBuilder.cpp", 831, __PRETTY_FUNCTION__))" file_link="../../../include/assert.h.html#88" macro="true">assert(static_cast<unsigned>(Info.Offset + Info.Size) == |
830 | (0) . __assert_fail ("static_cast(Info.Offset + Info.Size) == Info.StorageSize && \"Big endian union bitfield does not end at the back\"", "/home/seafit/code_projects/clang_source/clang/lib/CodeGen/CGRecordLayoutBuilder.cpp", 831, __PRETTY_FUNCTION__))" file_link="../../../include/assert.h.html#88" macro="true"> Info.StorageSize && |
831 | (0) . __assert_fail ("static_cast(Info.Offset + Info.Size) == Info.StorageSize && \"Big endian union bitfield does not end at the back\"", "/home/seafit/code_projects/clang_source/clang/lib/CodeGen/CGRecordLayoutBuilder.cpp", 831, __PRETTY_FUNCTION__))" file_link="../../../include/assert.h.html#88" macro="true"> "Big endian union bitfield does not end at the back"); |
832 | else |
833 | (0) . __assert_fail ("Info.Offset == 0 && \"Little endian union bitfield with a non-zero offset\"", "/home/seafit/code_projects/clang_source/clang/lib/CodeGen/CGRecordLayoutBuilder.cpp", 834, __PRETTY_FUNCTION__))" file_link="../../../include/assert.h.html#88" macro="true">assert(Info.Offset == 0 && |
834 | (0) . __assert_fail ("Info.Offset == 0 && \"Little endian union bitfield with a non-zero offset\"", "/home/seafit/code_projects/clang_source/clang/lib/CodeGen/CGRecordLayoutBuilder.cpp", 834, __PRETTY_FUNCTION__))" file_link="../../../include/assert.h.html#88" macro="true"> "Little endian union bitfield with a non-zero offset"); |
835 | (0) . __assert_fail ("Info.StorageSize <= SL->getSizeInBits() && \"Union not large enough for bitfield storage\"", "/home/seafit/code_projects/clang_source/clang/lib/CodeGen/CGRecordLayoutBuilder.cpp", 836, __PRETTY_FUNCTION__))" file_link="../../../include/assert.h.html#88" macro="true">assert(Info.StorageSize <= SL->getSizeInBits() && |
836 | (0) . __assert_fail ("Info.StorageSize <= SL->getSizeInBits() && \"Union not large enough for bitfield storage\"", "/home/seafit/code_projects/clang_source/clang/lib/CodeGen/CGRecordLayoutBuilder.cpp", 836, __PRETTY_FUNCTION__))" file_link="../../../include/assert.h.html#88" macro="true"> "Union not large enough for bitfield storage"); |
837 | } else { |
838 | (0) . __assert_fail ("Info.StorageSize == getDataLayout().getTypeAllocSizeInBits(ElementTy) && \"Storage size does not match the element type size\"", "/home/seafit/code_projects/clang_source/clang/lib/CodeGen/CGRecordLayoutBuilder.cpp", 840, __PRETTY_FUNCTION__))" file_link="../../../include/assert.h.html#88" macro="true">assert(Info.StorageSize == |
839 | (0) . __assert_fail ("Info.StorageSize == getDataLayout().getTypeAllocSizeInBits(ElementTy) && \"Storage size does not match the element type size\"", "/home/seafit/code_projects/clang_source/clang/lib/CodeGen/CGRecordLayoutBuilder.cpp", 840, __PRETTY_FUNCTION__))" file_link="../../../include/assert.h.html#88" macro="true"> getDataLayout().getTypeAllocSizeInBits(ElementTy) && |
840 | (0) . __assert_fail ("Info.StorageSize == getDataLayout().getTypeAllocSizeInBits(ElementTy) && \"Storage size does not match the element type size\"", "/home/seafit/code_projects/clang_source/clang/lib/CodeGen/CGRecordLayoutBuilder.cpp", 840, __PRETTY_FUNCTION__))" file_link="../../../include/assert.h.html#88" macro="true"> "Storage size does not match the element type size"); |
841 | } |
842 | (0) . __assert_fail ("Info.Size > 0 && \"Empty bitfield!\"", "/home/seafit/code_projects/clang_source/clang/lib/CodeGen/CGRecordLayoutBuilder.cpp", 842, __PRETTY_FUNCTION__))" file_link="../../../include/assert.h.html#88" macro="true">assert(Info.Size > 0 && "Empty bitfield!"); |
843 | (0) . __assert_fail ("static_cast(Info.Offset) + Info.Size <= Info.StorageSize && \"Bitfield outside of its allocated storage\"", "/home/seafit/code_projects/clang_source/clang/lib/CodeGen/CGRecordLayoutBuilder.cpp", 844, __PRETTY_FUNCTION__))" file_link="../../../include/assert.h.html#88" macro="true">assert(static_cast<unsigned>(Info.Offset) + Info.Size <= Info.StorageSize && |
844 | (0) . __assert_fail ("static_cast(Info.Offset) + Info.Size <= Info.StorageSize && \"Bitfield outside of its allocated storage\"", "/home/seafit/code_projects/clang_source/clang/lib/CodeGen/CGRecordLayoutBuilder.cpp", 844, __PRETTY_FUNCTION__))" file_link="../../../include/assert.h.html#88" macro="true"> "Bitfield outside of its allocated storage"); |
845 | } |
846 | #endif |
847 | |
848 | return RL; |
849 | } |
850 | |
851 | void CGRecordLayout::print(raw_ostream &OS) const { |
852 | OS << "<CGRecordLayout\n"; |
853 | OS << " LLVMType:" << *CompleteObjectType << "\n"; |
854 | if (BaseSubobjectType) |
855 | OS << " NonVirtualBaseLLVMType:" << *BaseSubobjectType << "\n"; |
856 | OS << " IsZeroInitializable:" << IsZeroInitializable << "\n"; |
857 | OS << " BitFields:[\n"; |
858 | |
859 | |
860 | std::vector<std::pair<unsigned, const CGBitFieldInfo*> > BFIs; |
861 | for (llvm::DenseMap<const FieldDecl*, CGBitFieldInfo>::const_iterator |
862 | it = BitFields.begin(), ie = BitFields.end(); |
863 | it != ie; ++it) { |
864 | const RecordDecl *RD = it->first->getParent(); |
865 | unsigned Index = 0; |
866 | for (RecordDecl::field_iterator |
867 | it2 = RD->field_begin(); *it2 != it->first; ++it2) |
868 | ++Index; |
869 | BFIs.push_back(std::make_pair(Index, &it->second)); |
870 | } |
871 | llvm::array_pod_sort(BFIs.begin(), BFIs.end()); |
872 | for (unsigned i = 0, e = BFIs.size(); i != e; ++i) { |
873 | OS.indent(4); |
874 | BFIs[i].second->print(OS); |
875 | OS << "\n"; |
876 | } |
877 | |
878 | OS << "]>\n"; |
879 | } |
880 | |
881 | LLVM_DUMP_METHOD void CGRecordLayout::dump() const { |
882 | print(llvm::errs()); |
883 | } |
884 | |
885 | void CGBitFieldInfo::print(raw_ostream &OS) const { |
886 | OS << "<CGBitFieldInfo" |
887 | << " Offset:" << Offset |
888 | << " Size:" << Size |
889 | << " IsSigned:" << IsSigned |
890 | << " StorageSize:" << StorageSize |
891 | << " StorageOffset:" << StorageOffset.getQuantity() << ">"; |
892 | } |
893 | |
894 | LLVM_DUMP_METHOD void CGBitFieldInfo::dump() const { |
895 | print(llvm::errs()); |
896 | } |
897 | |