1//===----------------------------------------------------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// This contains code to compute the layout of a record.
10//
11//===----------------------------------------------------------------------===//
12
13#include "CIRGenBuilder.h"
14#include "CIRGenModule.h"
15#include "CIRGenTypes.h"
16
17#include "clang/AST/ASTContext.h"
18#include "clang/AST/Decl.h"
19#include "clang/AST/DeclCXX.h"
20#include "clang/AST/RecordLayout.h"
21#include "clang/CIR/Dialect/IR/CIRAttrs.h"
22#include "clang/CIR/Dialect/IR/CIRDataLayout.h"
23#include "llvm/Support/Casting.h"
24
25#include <memory>
26
27using namespace llvm;
28using namespace clang;
29using namespace clang::CIRGen;
30
31namespace {
32/// The CIRRecordLowering is responsible for lowering an ASTRecordLayout to an
33/// mlir::Type. Some of the lowering is straightforward, some is not.
34// TODO: Detail some of the complexities and weirdnesses?
35// (See CGRecordLayoutBuilder.cpp)
36struct CIRRecordLowering final {
37
38 // MemberInfo is a helper structure that contains information about a record
39 // member. In addition to the standard member types, there exists a sentinel
40 // member type that ensures correct rounding.
41 struct MemberInfo final {
42 CharUnits offset;
43 enum class InfoKind { Field, Base } kind;
44 mlir::Type data;
45 union {
46 const FieldDecl *fieldDecl;
47 const CXXRecordDecl *cxxRecordDecl;
48 };
49 MemberInfo(CharUnits offset, InfoKind kind, mlir::Type data,
50 const FieldDecl *fieldDecl = nullptr)
51 : offset{offset}, kind{kind}, data{data}, fieldDecl{fieldDecl} {}
52 MemberInfo(CharUnits offset, InfoKind kind, mlir::Type data,
53 const CXXRecordDecl *rd)
54 : offset{offset}, kind{kind}, data{data}, cxxRecordDecl{rd} {}
55 // MemberInfos are sorted so we define a < operator.
56 bool operator<(const MemberInfo &other) const {
57 return offset < other.offset;
58 }
59 };
60 // The constructor.
61 CIRRecordLowering(CIRGenTypes &cirGenTypes, const RecordDecl *recordDecl,
62 bool packed);
63
64 /// Constructs a MemberInfo instance from an offset and mlir::Type.
65 MemberInfo makeStorageInfo(CharUnits offset, mlir::Type data) {
66 return MemberInfo(offset, MemberInfo::InfoKind::Field, data);
67 }
68
69 void lower();
70 void lowerUnion();
71
72 /// Determines if we need a packed llvm struct.
73 void determinePacked();
74 /// Inserts padding everywhere it's needed.
75 void insertPadding();
76
77 void accumulateBases(const CXXRecordDecl *cxxRecordDecl);
78 void accumulateVPtrs();
79 void accumulateFields();
80
81 CharUnits bitsToCharUnits(uint64_t bitOffset) {
82 return astContext.toCharUnitsFromBits(BitSize: bitOffset);
83 }
84
85 void calculateZeroInit();
86
87 CharUnits getSize(mlir::Type Ty) {
88 return CharUnits::fromQuantity(dataLayout.layout.getTypeSize(Ty));
89 }
90 CharUnits getAlignment(mlir::Type Ty) {
91 return CharUnits::fromQuantity(dataLayout.layout.getTypeABIAlignment(Ty));
92 }
93
94 bool isZeroInitializable(const FieldDecl *fd) {
95 return cirGenTypes.isZeroInitializable(fd->getType());
96 }
97 bool isZeroInitializable(const RecordDecl *rd) {
98 return cirGenTypes.isZeroInitializable(rd);
99 }
100
101 /// Wraps cir::IntType with some implicit arguments.
102 mlir::Type getUIntNType(uint64_t numBits) {
103 unsigned alignedBits = llvm::PowerOf2Ceil(A: numBits);
104 alignedBits = std::max(a: 8u, b: alignedBits);
105 return cir::IntType::get(&cirGenTypes.getMLIRContext(), alignedBits,
106 /*isSigned=*/false);
107 }
108
109 mlir::Type getCharType() {
110 return cir::IntType::get(&cirGenTypes.getMLIRContext(),
111 astContext.getCharWidth(),
112 /*isSigned=*/false);
113 }
114
115 mlir::Type getByteArrayType(CharUnits numberOfChars) {
116 assert(!numberOfChars.isZero() && "Empty byte arrays aren't allowed.");
117 mlir::Type type = getCharType();
118 return numberOfChars == CharUnits::One()
119 ? type
120 : cir::ArrayType::get(type, numberOfChars.getQuantity());
121 }
122
123 // Gets the CIR BaseSubobject type from a CXXRecordDecl.
124 mlir::Type getStorageType(const CXXRecordDecl *RD) {
125 return cirGenTypes.getCIRGenRecordLayout(RD).getBaseSubobjectCIRType();
126 }
127
128 mlir::Type getStorageType(const FieldDecl *fieldDecl) {
129 mlir::Type type = cirGenTypes.convertTypeForMem(fieldDecl->getType());
130 if (fieldDecl->isBitField()) {
131 cirGenTypes.getCGModule().errorNYI(recordDecl->getSourceRange(),
132 "getStorageType for bitfields");
133 }
134 return type;
135 }
136
137 uint64_t getFieldBitOffset(const FieldDecl *fieldDecl) {
138 return astRecordLayout.getFieldOffset(FieldNo: fieldDecl->getFieldIndex());
139 }
140
141 /// Fills out the structures that are ultimately consumed.
142 void fillOutputFields();
143
144 void appendPaddingBytes(CharUnits size) {
145 if (!size.isZero()) {
146 fieldTypes.push_back(getByteArrayType(size));
147 padded = true;
148 }
149 }
150
151 CIRGenTypes &cirGenTypes;
152 CIRGenBuilderTy &builder;
153 const ASTContext &astContext;
154 const RecordDecl *recordDecl;
155 const ASTRecordLayout &astRecordLayout;
156 // Helpful intermediate data-structures
157 std::vector<MemberInfo> members;
158 // Output fields, consumed by CIRGenTypes::computeRecordLayout
159 llvm::SmallVector<mlir::Type, 16> fieldTypes;
160 llvm::DenseMap<const FieldDecl *, unsigned> fieldIdxMap;
161 llvm::DenseMap<const CXXRecordDecl *, unsigned> nonVirtualBases;
162 cir::CIRDataLayout dataLayout;
163
164 LLVM_PREFERRED_TYPE(bool)
165 unsigned zeroInitializable : 1;
166 LLVM_PREFERRED_TYPE(bool)
167 unsigned zeroInitializableAsBase : 1;
168 LLVM_PREFERRED_TYPE(bool)
169 unsigned packed : 1;
170 LLVM_PREFERRED_TYPE(bool)
171 unsigned padded : 1;
172
173private:
174 CIRRecordLowering(const CIRRecordLowering &) = delete;
175 void operator=(const CIRRecordLowering &) = delete;
176}; // CIRRecordLowering
177} // namespace
178
179CIRRecordLowering::CIRRecordLowering(CIRGenTypes &cirGenTypes,
180 const RecordDecl *recordDecl, bool packed)
181 : cirGenTypes(cirGenTypes), builder(cirGenTypes.getBuilder()),
182 astContext(cirGenTypes.getASTContext()), recordDecl(recordDecl),
183 astRecordLayout(
184 cirGenTypes.getASTContext().getASTRecordLayout(D: recordDecl)),
185 dataLayout(cirGenTypes.getCGModule().getModule()),
186 zeroInitializable(true), zeroInitializableAsBase(true), packed(packed),
187 padded(false) {}
188
189void CIRRecordLowering::lower() {
190 if (recordDecl->isUnion()) {
191 lowerUnion();
192 assert(!cir::MissingFeatures::bitfields());
193 return;
194 }
195
196 assert(!cir::MissingFeatures::recordLayoutVirtualBases());
197 CharUnits size = astRecordLayout.getSize();
198
199 accumulateFields();
200
201 if (const auto *cxxRecordDecl = dyn_cast<CXXRecordDecl>(Val: recordDecl)) {
202 accumulateVPtrs();
203 accumulateBases(cxxRecordDecl);
204 if (members.empty()) {
205 appendPaddingBytes(size);
206 assert(!cir::MissingFeatures::bitfields());
207 return;
208 }
209 assert(!cir::MissingFeatures::recordLayoutVirtualBases());
210 }
211
212 llvm::stable_sort(Range&: members);
213 // TODO: implement clipTailPadding once bitfields are implemented
214 assert(!cir::MissingFeatures::bitfields());
215 assert(!cir::MissingFeatures::recordZeroInit());
216
217 members.push_back(makeStorageInfo(size, getUIntNType(8)));
218 determinePacked();
219 insertPadding();
220 members.pop_back();
221
222 calculateZeroInit();
223 fillOutputFields();
224}
225
226void CIRRecordLowering::fillOutputFields() {
227 for (const MemberInfo &member : members) {
228 if (member.data)
229 fieldTypes.push_back(member.data);
230 if (member.kind == MemberInfo::InfoKind::Field) {
231 if (member.fieldDecl)
232 fieldIdxMap[member.fieldDecl->getCanonicalDecl()] =
233 fieldTypes.size() - 1;
234 // A field without storage must be a bitfield.
235 assert(!cir::MissingFeatures::bitfields());
236 } else if (member.kind == MemberInfo::InfoKind::Base) {
237 nonVirtualBases[member.cxxRecordDecl] = fieldTypes.size() - 1;
238 }
239 assert(!cir::MissingFeatures::recordLayoutVirtualBases());
240 }
241}
242
243void CIRRecordLowering::accumulateFields() {
244 for (const FieldDecl *field : recordDecl->fields()) {
245 if (field->isBitField()) {
246 cirGenTypes.getCGModule().errorNYI(recordDecl->getSourceRange(),
247 "accumulate bitfields");
248 ++field;
249 } else if (!field->isZeroSize(Ctx: astContext)) {
250 members.push_back(MemberInfo(bitsToCharUnits(getFieldBitOffset(field)),
251 MemberInfo::InfoKind::Field,
252 getStorageType(field), field));
253 ++field;
254 } else {
255 // TODO(cir): do we want to do anything special about zero size members?
256 assert(!cir::MissingFeatures::zeroSizeRecordMembers());
257 ++field;
258 }
259 }
260}
261
262void CIRRecordLowering::calculateZeroInit() {
263 for (const MemberInfo &member : members) {
264 if (member.kind == MemberInfo::InfoKind::Field) {
265 if (!member.fieldDecl || isZeroInitializable(fd: member.fieldDecl))
266 continue;
267 zeroInitializable = zeroInitializableAsBase = false;
268 return;
269 } else if (member.kind == MemberInfo::InfoKind::Base) {
270 if (isZeroInitializable(member.cxxRecordDecl))
271 continue;
272 zeroInitializable = false;
273 if (member.kind == MemberInfo::InfoKind::Base)
274 zeroInitializableAsBase = false;
275 }
276 assert(!cir::MissingFeatures::recordLayoutVirtualBases());
277 }
278}
279
280void CIRRecordLowering::determinePacked() {
281 if (packed)
282 return;
283 CharUnits alignment = CharUnits::One();
284
285 // TODO(cir): handle non-virtual base types
286 assert(!cir::MissingFeatures::cxxSupport());
287
288 for (const MemberInfo &member : members) {
289 if (!member.data)
290 continue;
291 // If any member falls at an offset that it not a multiple of its alignment,
292 // then the entire record must be packed.
293 if (member.offset % getAlignment(Ty: member.data))
294 packed = true;
295 alignment = std::max(alignment, getAlignment(Ty: member.data));
296 }
297 // If the size of the record (the capstone's offset) is not a multiple of the
298 // record's alignment, it must be packed.
299 if (members.back().offset % alignment)
300 packed = true;
301 // Update the alignment of the sentinel.
302 if (!packed)
303 members.back().data = getUIntNType(astContext.toBits(alignment));
304}
305
306void CIRRecordLowering::insertPadding() {
307 std::vector<std::pair<CharUnits, CharUnits>> padding;
308 CharUnits size = CharUnits::Zero();
309 for (const MemberInfo &member : members) {
310 if (!member.data)
311 continue;
312 CharUnits offset = member.offset;
313 assert(offset >= size);
314 // Insert padding if we need to.
315 if (offset !=
316 size.alignTo(Align: packed ? CharUnits::One() : getAlignment(Ty: member.data)))
317 padding.push_back(x: std::make_pair(x&: size, y: offset - size));
318 size = offset + getSize(Ty: member.data);
319 }
320 if (padding.empty())
321 return;
322 padded = true;
323 // Add the padding to the Members list and sort it.
324 for (const std::pair<CharUnits, CharUnits> &paddingPair : padding)
325 members.push_back(makeStorageInfo(paddingPair.first,
326 getByteArrayType(paddingPair.second)));
327 llvm::stable_sort(Range&: members);
328}
329
330std::unique_ptr<CIRGenRecordLayout>
331CIRGenTypes::computeRecordLayout(const RecordDecl *rd, cir::RecordType *ty) {
332 CIRRecordLowering lowering(*this, rd, /*packed=*/false);
333 assert(ty->isIncomplete() && "recomputing record layout?");
334 lowering.lower();
335
336 // If we're in C++, compute the base subobject type.
337 cir::RecordType baseTy;
338 if (llvm::isa<CXXRecordDecl>(rd) && !rd->isUnion() &&
339 !rd->hasAttr<FinalAttr>()) {
340 baseTy = *ty;
341 if (lowering.astRecordLayout.getNonVirtualSize() !=
342 lowering.astRecordLayout.getSize()) {
343 CIRRecordLowering baseLowering(*this, rd, /*Packed=*/lowering.packed);
344 baseLowering.lower();
345 std::string baseIdentifier = getRecordTypeName(rd, suffix: ".base");
346 baseTy =
347 builder.getCompleteRecordTy(baseLowering.fieldTypes, baseIdentifier,
348 baseLowering.packed, baseLowering.padded);
349 // TODO(cir): add something like addRecordTypeName
350
351 // BaseTy and Ty must agree on their packedness for getCIRFieldNo to work
352 // on both of them with the same index.
353 assert(lowering.packed == baseLowering.packed &&
354 "Non-virtual and complete types must agree on packedness");
355 }
356 }
357
358 if (llvm::isa<CXXRecordDecl>(rd) && !rd->isUnion() &&
359 !rd->hasAttr<FinalAttr>()) {
360 if (lowering.astRecordLayout.getNonVirtualSize() !=
361 lowering.astRecordLayout.getSize()) {
362 cgm.errorNYI(rd->getSourceRange(), "computeRecordLayout: CXXRecordDecl");
363 }
364 }
365
366 // Fill in the record *after* computing the base type. Filling in the body
367 // signifies that the type is no longer opaque and record layout is complete,
368 // but we may need to recursively layout rd while laying D out as a base type.
369 assert(!cir::MissingFeatures::astRecordDeclAttr());
370 ty->complete(lowering.fieldTypes, lowering.packed, lowering.padded);
371
372 auto rl = std::make_unique<CIRGenRecordLayout>(
373 ty ? *ty : cir::RecordType{}, baseTy ? baseTy : cir::RecordType{},
374 (bool)lowering.zeroInitializable, (bool)lowering.zeroInitializableAsBase);
375
376 assert(!cir::MissingFeatures::recordZeroInit());
377
378 rl->nonVirtualBases.swap(lowering.nonVirtualBases);
379
380 assert(!cir::MissingFeatures::cxxSupport());
381 assert(!cir::MissingFeatures::bitfields());
382
383 // Add all the field numbers.
384 rl->fieldIdxMap.swap(lowering.fieldIdxMap);
385
386 // Dump the layout, if requested.
387 if (getASTContext().getLangOpts().DumpRecordLayouts) {
388 cgm.errorNYI(rd->getSourceRange(), "computeRecordLayout: dump layout");
389 }
390
391 // TODO: implement verification
392 return rl;
393}
394
395void CIRRecordLowering::lowerUnion() {
396 CharUnits layoutSize = astRecordLayout.getSize();
397 mlir::Type storageType = nullptr;
398 bool seenNamedMember = false;
399
400 // Iterate through the fields setting bitFieldInfo and the Fields array. Also
401 // locate the "most appropriate" storage type.
402 for (const FieldDecl *field : recordDecl->fields()) {
403 mlir::Type fieldType;
404 if (field->isBitField())
405 cirGenTypes.getCGModule().errorNYI(recordDecl->getSourceRange(),
406 "bitfields in lowerUnion");
407 else
408 fieldType = getStorageType(field);
409
410 // This maps a field to its index. For unions, the index is always 0.
411 fieldIdxMap[field->getCanonicalDecl()] = 0;
412
413 // Compute zero-initializable status.
414 // This union might not be zero initialized: it may contain a pointer to
415 // data member which might have some exotic initialization sequence.
416 // If this is the case, then we ought not to try and come up with a "better"
417 // type, it might not be very easy to come up with a Constant which
418 // correctly initializes it.
419 if (!seenNamedMember) {
420 seenNamedMember = field->getIdentifier();
421 if (!seenNamedMember)
422 if (const RecordDecl *fieldRD = field->getType()->getAsRecordDecl())
423 seenNamedMember = fieldRD->findFirstNamedDataMember();
424 if (seenNamedMember && !isZeroInitializable(fd: field)) {
425 zeroInitializable = zeroInitializableAsBase = false;
426 storageType = fieldType;
427 }
428 }
429
430 // Because our union isn't zero initializable, we won't be getting a better
431 // storage type.
432 if (!zeroInitializable)
433 continue;
434
435 // Conditionally update our storage type if we've got a new "better" one.
436 if (!storageType || getAlignment(Ty: fieldType) > getAlignment(Ty: storageType) ||
437 (getAlignment(Ty: fieldType) == getAlignment(Ty: storageType) &&
438 getSize(Ty: fieldType) > getSize(Ty: storageType)))
439 storageType = fieldType;
440
441 // NOTE(cir): Track all union member's types, not just the largest one. It
442 // allows for proper type-checking and retain more info for analisys.
443 fieldTypes.push_back(fieldType);
444 }
445
446 if (!storageType)
447 cirGenTypes.getCGModule().errorNYI(recordDecl->getSourceRange(),
448 "No-storage Union NYI");
449
450 if (layoutSize < getSize(Ty: storageType))
451 storageType = getByteArrayType(layoutSize);
452 else
453 appendPaddingBytes(size: layoutSize - getSize(Ty: storageType));
454
455 // Set packed if we need it.
456 if (layoutSize % getAlignment(Ty: storageType))
457 packed = true;
458}
459
460void CIRRecordLowering::accumulateBases(const CXXRecordDecl *cxxRecordDecl) {
461 // If we've got a primary virtual base, we need to add it with the bases.
462 if (astRecordLayout.isPrimaryBaseVirtual()) {
463 cirGenTypes.getCGModule().errorNYI(recordDecl->getSourceRange(),
464 "accumulateBases: primary virtual base");
465 }
466
467 // Accumulate the non-virtual bases.
468 for ([[maybe_unused]] const auto &base : cxxRecordDecl->bases()) {
469 if (base.isVirtual()) {
470 cirGenTypes.getCGModule().errorNYI(recordDecl->getSourceRange(),
471 "accumulateBases: virtual base");
472 continue;
473 }
474 // Bases can be zero-sized even if not technically empty if they
475 // contain only a trailing array member.
476 const CXXRecordDecl *baseDecl = base.getType()->getAsCXXRecordDecl();
477 if (!baseDecl->isEmpty() &&
478 !astContext.getASTRecordLayout(baseDecl).getNonVirtualSize().isZero()) {
479 members.push_back(MemberInfo(astRecordLayout.getBaseClassOffset(baseDecl),
480 MemberInfo::InfoKind::Base,
481 getStorageType(baseDecl), baseDecl));
482 }
483 }
484}
485
486void CIRRecordLowering::accumulateVPtrs() {
487 if (astRecordLayout.hasOwnVFPtr())
488 cirGenTypes.getCGModule().errorNYI(recordDecl->getSourceRange(),
489 "accumulateVPtrs: hasOwnVFPtr");
490 if (astRecordLayout.hasOwnVBPtr())
491 cirGenTypes.getCGModule().errorNYI(recordDecl->getSourceRange(),
492 "accumulateVPtrs: hasOwnVBPtr");
493}
494

source code of clang/lib/CIR/CodeGen/CIRGenRecordLayoutBuilder.cpp