26#include "llvm/Support/Casting.h"
39struct CIRRecordLowering final {
44 struct MemberInfo final {
46 enum class InfoKind { VFPtr,
Field,
Base, VBase } kind;
49 cir::RecordMemberKind memberKind;
54 MemberInfo(CharUnits offset, InfoKind kind, mlir::Type data,
55 cir::RecordMemberKind memberKind,
57 : offset{offset}, kind{kind}, data{data}, memberKind{memberKind},
59 MemberInfo(CharUnits offset, InfoKind kind, mlir::Type data,
60 cir::RecordMemberKind memberKind,
const CXXRecordDecl *rd)
61 : offset{offset}, kind{kind}, data{data}, memberKind{memberKind},
64 bool operator<(
const MemberInfo &other)
const {
65 return offset < other.offset;
69 static bool ownsBytes(
const MemberInfo &member) {
73 cir::BitFieldDeclAttr getBitFieldDecl(
const FieldDecl *field) {
74 return cir::BitFieldDeclAttr::get(
75 cirGenTypes.convertTypeForMem(field->
getType()),
79 MemberInfo makeAccessUnitInfo(CharUnits offset, mlir::Type storage,
80 llvm::ArrayRef<cir::BitFieldDeclAttr> fields) {
82 cir::BitFieldType::get(&cirGenTypes.getMLIRContext(), storage, fields);
84 const bool holdsNamedField =
85 mlir::cast<cir::BitFieldType>(unitTy).holdsNamedField();
86 return makeStorageInfo(offset, unitTy,
87 holdsNamedField ? cir::RecordMemberKind::BitField
88 : cir::RecordMemberKind::Empty);
94 MemberInfo makeZeroWidthBitFieldInfo(
const FieldDecl *field) {
96 return makeAccessUnitInfo(bitsToCharUnits(getFieldBitOffset(field)),
97 mlir::Type{}, getBitFieldDecl(field));
101 CIRRecordLowering(CIRGenTypes &cirGenTypes,
const RecordDecl *recordDecl,
105 MemberInfo makeStorageInfo(CharUnits offset, mlir::Type data,
106 cir::RecordMemberKind memberKind) {
107 return MemberInfo(offset, MemberInfo::InfoKind::Field, data, memberKind);
111 void setBitFieldInfo(
const FieldDecl *fd, CharUnits startOffset,
112 mlir::Type storageType);
114 void lower(
bool nonVirtualBaseType);
115 void lowerUnion(
bool nonVirtualBaseType);
118 void determinePacked(
bool nvBaseType);
120 void insertPadding();
122 void computeVolatileBitfields();
123 void accumulateBases();
124 void accumulateVPtrs();
125 void accumulateVBases();
126 void accumulateFields(
bool nonVirtualBaseType);
131 mlir::Type getVFPtrType();
134 bool isBigEndian()
const {
return astContext.getTargetInfo().isBigEndian(); }
140 bool isOverlappingVBaseABI() {
141 return !astContext.getTargetInfo().getCXXABI().isMicrosoft();
145 bool hasOwnStorage(
const CXXRecordDecl *
decl,
const CXXRecordDecl *query);
152 bool isDiscreteBitFieldABI() {
153 return astContext.getTargetInfo().getCXXABI().isMicrosoft() ||
154 recordDecl->isMsStruct(astContext);
157 CharUnits bitsToCharUnits(uint64_t bitOffset) {
158 return astContext.toCharUnitsFromBits(bitOffset);
161 void calculateZeroInit();
163 CharUnits getSize(mlir::Type Ty) {
166 CharUnits getSizeInBits(mlir::Type ty) {
170 CharUnits getMemberAlignment(mlir::Type Ty) {
173 if (
auto bitFieldTy = mlir::dyn_cast<cir::BitFieldType>(Ty)) {
174 if (mlir::Type storage = bitFieldTy.getStorageType())
175 return getMemberAlignment(storage);
179 if (
auto arrayTy = mlir::dyn_cast<cir::ArrayType>(Ty))
180 return getMemberAlignment(arrayTy.getElementType());
183 if (
auto intTy = mlir::dyn_cast<cir::IntType>(Ty))
185 intTy.getStorageTypeAlignment(dataLayout.layout));
190 bool isZeroInitializable(
const FieldDecl *fd) {
191 return cirGenTypes.isZeroInitializable(fd->
getType());
193 bool isZeroInitializable(
const RecordDecl *rd) {
194 return cirGenTypes.isZeroInitializable(rd);
201 static cir::RecordMemberKind makeMemberKind(
bool holdsData,
202 bool isNamedBitField) {
204 return cir::RecordMemberKind::Empty;
206 : cir::RecordMemberKind::Data;
212 cir::RecordMemberKind getFieldMemberKind(
const FieldDecl *fd) {
213 assert(!fd->
isBitField() &&
"a bit-field is marked with its access unit");
221 cir::RecordMemberKind getBaseMemberKind(
const CXXRecordDecl *baseDecl) {
223 astContext.getCanonicalTagType(baseDecl))
224 ? cir::RecordMemberKind::Empty
225 : cir::RecordMemberKind::Data;
229 mlir::Type getUIntNType(uint64_t numBits) {
230 unsigned alignedBits = llvm::PowerOf2Ceil(numBits);
231 alignedBits = std::max(8u, alignedBits);
232 return cir::IntType::get(&cirGenTypes.getMLIRContext(), alignedBits,
236 mlir::Type getCharType() {
237 return cir::IntType::get(&cirGenTypes.getMLIRContext(),
238 astContext.getCharWidth(),
242 mlir::Type getByteArrayType(CharUnits numberOfChars) {
243 assert(!numberOfChars.
isZero() &&
"Empty byte arrays aren't allowed.");
244 mlir::Type
type = getCharType();
251 mlir::Type getStorageType(
const CXXRecordDecl *RD) {
252 return cirGenTypes.getCIRGenRecordLayout(RD).getBaseSubobjectCIRType();
257 mlir::Type getBitfieldStorageType(
unsigned numBits) {
258 unsigned alignedBits = llvm::alignTo(numBits, astContext.getCharWidth());
260 return builder.getUIntNTy(alignedBits);
262 mlir::Type
type = getCharType();
263 return cir::ArrayType::get(
type, alignedBits / astContext.getCharWidth());
266 mlir::Type getStorageType(
const FieldDecl *
fieldDecl) {
267 mlir::Type
type = cirGenTypes.convertTypeForMem(
fieldDecl->getType());
269 cirGenTypes.getCGModule().errorNYI(recordDecl->getSourceRange(),
270 "getStorageType for bitfields");
276 return astRecordLayout.getFieldOffset(
fieldDecl->getFieldIndex());
280 void fillOutputFields();
282 void appendPaddingBytes(CharUnits size) {
285 mlir::Type padTy = getByteArrayType(size);
286 if (recordDecl->isUnion()) {
287 assert(!unionPadding &&
"at most one union tail-padding type");
288 unionPadding = padTy;
290 addField(padTy, cir::RecordMemberKind::Pad);
294 void addField(mlir::Type ty, cir::RecordMemberKind memberKind) {
295 fieldTypes.push_back(ty);
296 fieldKinds.push_back(memberKind);
304 llvm::ArrayRef<mlir::Type> getFieldTypes()
const {
return fieldTypes; }
305 llvm::ArrayRef<cir::RecordMemberKind> getFieldKinds()
const {
309 CIRGenTypes &cirGenTypes;
310 CIRGenBuilderTy &builder;
311 const ASTContext &astContext;
312 const RecordDecl *recordDecl;
313 const CXXRecordDecl *cxxRecordDecl;
314 const ASTRecordLayout &astRecordLayout;
316 std::vector<MemberInfo> members;
317 mlir::Type unionPadding;
318 llvm::DenseMap<const FieldDecl *, CIRGenBitFieldInfo> bitFields;
319 llvm::DenseMap<const FieldDecl *, unsigned> fieldIdxMap;
320 llvm::DenseMap<const CXXRecordDecl *, unsigned> nonVirtualBases;
321 llvm::DenseMap<const CXXRecordDecl *, unsigned> virtualBases;
322 cir::CIRDataLayout dataLayout;
324 LLVM_PREFERRED_TYPE(
bool)
325 unsigned zeroInitializable : 1;
326 LLVM_PREFERRED_TYPE(
bool)
327 unsigned zeroInitializableAsBase : 1;
328 LLVM_PREFERRED_TYPE(
bool)
335 llvm::SmallVector<mlir::Type, 16> fieldTypes;
336 llvm::SmallVector<cir::RecordMemberKind> fieldKinds;
338 CIRRecordLowering(
const CIRRecordLowering &) =
delete;
339 void operator=(
const CIRRecordLowering &) =
delete;
343CIRRecordLowering::CIRRecordLowering(
CIRGenTypes &cirGenTypes,
345 : cirGenTypes{cirGenTypes}, builder{cirGenTypes.getBuilder()},
349 cirGenTypes.getASTContext().getASTRecordLayout(
recordDecl)},
350 dataLayout{cirGenTypes.getCGModule().getModule()},
351 zeroInitializable{
true}, zeroInitializableAsBase{
true}, packed{packed} {}
353void CIRRecordLowering::setBitFieldInfo(
const FieldDecl *fd,
355 mlir::Type storageType) {
359 (unsigned)(getFieldBitOffset(fd) - astContext.
toBits(startOffset));
361 info.storageSize = getSizeInBits(storageType).getQuantity();
362 info.storageOffset = startOffset;
363 info.storageType = storageType;
375 info.volatileStorageSize = 0;
376 info.volatileOffset = 0;
380void CIRRecordLowering::lower(
bool nonVirtualBaseType) {
382 lowerUnion(nonVirtualBaseType);
383 computeVolatileBitfields();
390 accumulateFields(nonVirtualBaseType);
395 if (members.empty()) {
396 appendPaddingBytes(size);
397 computeVolatileBitfields();
400 if (!nonVirtualBaseType)
404 llvm::stable_sort(members);
411 makeStorageInfo(size, getUIntNType(8), cir::RecordMemberKind::Data));
412 determinePacked(nonVirtualBaseType);
418 computeVolatileBitfields();
421void CIRRecordLowering::fillOutputFields() {
422 for (
const MemberInfo &member : members) {
425 if (
member.kind == MemberInfo::InfoKind::Field) {
427 fieldIdxMap[
member.fieldDecl->getCanonicalDecl()] =
428 fieldTypes.size() - 1;
432 assert(
member.fieldDecl &&
433 "member.data is a nullptr so member.fieldDecl should not be");
437 }
else if (
member.kind == MemberInfo::InfoKind::Base) {
438 nonVirtualBases[
member.cxxRecordDecl] = fieldTypes.size() - 1;
439 }
else if (
member.kind == MemberInfo::InfoKind::VBase) {
440 virtualBases[
member.cxxRecordDecl] = fieldTypes.size() - 1;
448 if (isDiscreteBitFieldABI()) {
462 mlir::Type unitStorage;
463 llvm::SmallVector<cir::BitFieldDeclAttr> unitFields;
464 for (; field != fieldEnd && field->isBitField(); ++field) {
466 if (field->isZeroLengthBitField()) {
467 members.push_back(makeZeroWidthBitFieldInfo(*field));
471 uint64_t bitOffset = getFieldBitOffset(*field);
473 cir::BitFieldDeclAttr
decl = getBitFieldDecl(*field);
476 if (run == fieldEnd || bitOffset >= tail) {
478 startBitOffset = bitOffset;
482 unitIdx = members.size();
484 unitFields.assign(1,
decl);
485 members.push_back(makeAccessUnitInfo(bitsToCharUnits(startBitOffset),
486 unitStorage, unitFields));
488 unitFields.push_back(
decl);
489 members[unitIdx] = makeAccessUnitInfo(bitsToCharUnits(startBitOffset),
490 unitStorage, unitFields);
492 assert(members[unitIdx].offset == bitsToCharUnits(startBitOffset) &&
493 "unitIdx must name the current run's access unit");
496 members.push_back(MemberInfo(bitsToCharUnits(startBitOffset),
497 MemberInfo::InfoKind::Field,
nullptr,
498 cir::RecordMemberKind::Data, *field));
514 CharUnits beginOffset;
523 CharUnits bestEndOffset;
531 bool atAlignedBoundary =
false;
533 if (field != fieldEnd && field->isBitField()) {
534 uint64_t bitOffset = getFieldBitOffset(*field);
535 if (begin == fieldEnd) {
540 assert((bitOffset % charBits) == 0 &&
"Not at start of char");
541 beginOffset = bitsToCharUnits(bitOffset);
542 bitSizeSinceBegin = 0;
543 }
else if ((bitOffset % charBits) != 0) {
551 astContext.
toBits(beginOffset) + bitSizeSinceBegin &&
552 "Concatenating non-contiguous bitfields");
557 if (field->isZeroLengthBitField())
559 atAlignedBoundary =
true;
564 if (begin == fieldEnd)
568 atAlignedBoundary =
true;
574 bool installBest =
false;
575 if (atAlignedBoundary) {
581 CharUnits accessSize = bitsToCharUnits(bitSizeSinceBegin + charBits - 1);
582 if (bestEnd == begin) {
586 bestEndOffset = beginOffset + accessSize;
589 if (!bitSizeSinceBegin)
593 }
else if (accessSize > regSize) {
602 mlir::Type
type = getUIntNType(astContext.
toBits(accessSize));
609 CharUnits
align = getMemberAlignment(
type);
620 if (installBest && bestEnd == field) {
623 if (getSize(
type) == accessSize)
633 CharUnits limitOffset;
634 for (
auto probe = field; probe != fieldEnd; ++probe)
637 assert((getFieldBitOffset(*probe) % charBits) == 0 &&
638 "Next storage is not byte-aligned");
639 limitOffset = bitsToCharUnits(getFieldBitOffset(*probe));
646 CharUnits typeSize = getSize(
type);
647 if (beginOffset + typeSize <= limitOffset) {
650 bestEndOffset = beginOffset + typeSize;
659 .FineGrainedBitfieldAccesses) {
665 bitSizeSinceBegin = astContext.
toBits(limitOffset - beginOffset);
672 assert((field == fieldEnd || !field->isBitField() ||
673 (getFieldBitOffset(*field) % charBits) == 0) &&
674 "Installing but not at an aligned bitfield or limit");
675 CharUnits accessSize = bestEndOffset - beginOffset;
676 if (!accessSize.
isZero()) {
682 assert(getSize(getUIntNType(astContext.
toBits(accessSize))) >
684 "Clipped access need not be clipped");
685 type = getByteArrayType(accessSize);
687 type = getUIntNType(astContext.
toBits(accessSize));
688 assert(getSize(
type) == accessSize &&
689 "Unclipped access must be clipped");
694 llvm::SmallVector<cir::BitFieldDeclAttr> unitFields;
695 for (
auto occupant = begin; occupant != bestEnd; ++occupant)
696 if (!occupant->isZeroLengthBitField())
697 unitFields.push_back(getBitFieldDecl(*occupant));
698 assert(!unitFields.empty() &&
"an access unit holds a bit-field");
699 members.push_back(makeAccessUnitInfo(beginOffset,
type, unitFields));
701 for (; begin != bestEnd; ++begin)
702 if (!begin->isZeroLengthBitField())
703 members.push_back(MemberInfo(beginOffset,
704 MemberInfo::InfoKind::Field,
nullptr,
705 cir::RecordMemberKind::Data, *begin));
711 assert(field != fieldEnd && field->isBitField() &&
712 "Accumulating past end of bitfields");
713 assert(!
barrier &&
"Accumulating across barrier");
714 if (field->isZeroLengthBitField())
715 members.push_back(makeZeroWidthBitFieldInfo(*field));
717 bitSizeSinceBegin += field->getBitWidthValue();
725void CIRRecordLowering::accumulateFields(
bool nonVirtualBaseType) {
728 field != fieldEnd;) {
729 if (field->isBitField()) {
730 field = accumulateBitFields(field, fieldEnd);
731 assert((field == fieldEnd || !field->isBitField()) &&
732 "Failed to accumulate all the bitfields");
734 field->isPotentiallyOverlapping()) {
751 MemberInfo(bitsToCharUnits(getFieldBitOffset(*field)),
752 MemberInfo::InfoKind::Field,
753 getStorageType(field->getType()->getAsCXXRecordDecl()),
754 getFieldMemberKind(*field), *field));
762 members.push_back(MemberInfo(
763 bitsToCharUnits(getFieldBitOffset(*field)),
764 MemberInfo::InfoKind::Field,
765 field->isPotentiallyOverlapping()
766 ? getStorageType(field->getType()->getAsCXXRecordDecl())
767 : getStorageType(*field),
768 getFieldMemberKind(*field), *field));
774void CIRRecordLowering::calculateZeroInit() {
775 for (
const MemberInfo &member : members) {
776 if (
member.kind == MemberInfo::InfoKind::Field) {
777 if (!
member.fieldDecl || isZeroInitializable(
member.fieldDecl))
779 zeroInitializable = zeroInitializableAsBase =
false;
781 }
else if (
member.kind == MemberInfo::InfoKind::Base ||
782 member.kind == MemberInfo::InfoKind::VBase) {
783 if (isZeroInitializable(
member.cxxRecordDecl))
785 zeroInitializable =
false;
786 if (
member.kind == MemberInfo::InfoKind::Base)
787 zeroInitializableAsBase =
false;
792void CIRRecordLowering::determinePacked(
bool nvBaseType) {
801 for (
const MemberInfo &member : members) {
804 if (!ownsBytes(member))
808 if (!
member.offset.isMultipleOf(getMemberAlignment(
member.data)))
810 if (
member.offset < nvSize)
811 nvAlignment = std::max(nvAlignment, getMemberAlignment(
member.data));
812 alignment = std::max(alignment, getMemberAlignment(
member.data));
816 if (!members.back().offset.isMultipleOf(alignment))
825 members.back().data = getUIntNType(astContext.
toBits(alignment));
828void CIRRecordLowering::insertPadding() {
829 std::vector<std::pair<CharUnits, CharUnits>> padding;
831 for (
const MemberInfo &member : members) {
839 if (!ownsBytes(member)) {
840 if (
member.offset > size) {
841 padding.push_back(std::make_pair(size,
member.offset - size));
846 CharUnits offset =
member.offset;
847 assert(offset >= size);
850 : getMemberAlignment(
member.data)))
851 padding.push_back(std::make_pair(size, offset - size));
852 size = offset + getSize(
member.data);
857 for (
const std::pair<CharUnits, CharUnits> &paddingPair : padding)
858 members.push_back(makeStorageInfo(paddingPair.first,
859 getByteArrayType(paddingPair.second),
860 cir::RecordMemberKind::Pad));
861 llvm::stable_sort(members);
864static cir::ArgPassingKind
868 return cir::ArgPassingKind::CanPassInRegs;
870 return cir::ArgPassingKind::CannotPassInRegs;
872 return cir::ArgPassingKind::CanNeverPassInRegs;
874 llvm_unreachable(
"unknown RecordArgPassingKind");
879[[maybe_unused]]
static bool
886std::unique_ptr<CIRGenRecordLayout>
888 CIRRecordLowering lowering(*
this, rd,
false);
889 assert(ty->
isIncomplete() &&
"recomputing record layout?");
890 lowering.lower(
false);
902 if (llvm::isa<CXXRecordDecl>(rd)) {
911 lowering.astRecordLayout.
getSize()) {
912 CIRRecordLowering baseLowering(*
this, rd, lowering.packed);
913 baseLowering.lower(
true);
915 baseTy = builder.getCompleteNamedRecordType(
916 baseLowering.getFieldTypes(), baseLowering.packed, baseIdentifier,
917 baseLowering.getFieldKinds());
926 assert((rd->
isUnion() || lowering.packed == baseLowering.packed) &&
927 "Non-virtual and complete types must agree on packedness");
932 cgm.getDiags().hasErrorOccurred()) &&
933 "base subobject member kinds must reproduce its ABI emptiness");
941 ty->
complete(lowering.getFieldTypes(), lowering.packed, lowering.unionPadding,
942 lowering.getFieldKinds());
949 cgm.getDiags().hasErrorOccurred()) &&
950 "member kinds must reproduce the ABI emptiness of the record");
954 mlir::MLIRContext *mlirCtx = ty->getContext();
955 cir::ArgPassingKind apk =
958 bool hasTrivialDestructor =
true;
959 if (
auto *cxxRD = dyn_cast<CXXRecordDecl>(rd))
960 hasTrivialDestructor = cxxRD->hasTrivialDestructor();
961 const auto &astLayout = astContext.getASTRecordLayout(rd);
962 uint64_t recordAlignInBytes = astLayout.getAlignment().getQuantity();
964 cgm.addRecordLayout(ty->
getName(), cir::RecordLayoutAttr::get(
965 mlirCtx, apk, hasTrivialDestructor,
966 recordAlignInBytes));
969 auto rl = std::make_unique<CIRGenRecordLayout>(
971 (bool)lowering.zeroInitializable, (bool)lowering.zeroInitializableAsBase);
973 rl->nonVirtualBases.swap(lowering.nonVirtualBases);
974 rl->completeObjectVirtualBases.swap(lowering.virtualBases);
977 rl->fieldIdxMap.swap(lowering.fieldIdxMap);
979 rl->bitFields.swap(lowering.bitFields);
983 llvm::outs() <<
"\n*** Dumping CIRgen Record Layout\n";
984 llvm::outs() <<
"Record: ";
985 rd->
dump(llvm::outs());
986 llvm::outs() <<
"\nLayout: ";
987 rl->print(llvm::outs());
995 os <<
"<CIRecordLayout\n";
996 os <<
" CIR Type:" << completeObjectType <<
"\n";
997 if (baseSubobjectType)
998 os <<
" NonVirtualBaseCIRType:" << baseSubobjectType <<
"\n";
999 os <<
" IsZeroInitializable:" << zeroInitializable <<
"\n";
1000 os <<
" BitFields:[\n";
1001 std::vector<std::pair<unsigned, const CIRGenBitFieldInfo *>> bitInfo;
1002 for (
auto &[
decl, info] : bitFields) {
1007 bitInfo.push_back(std::make_pair(
index, &info));
1009 llvm::array_pod_sort(bitInfo.begin(), bitInfo.end());
1010 for (std::pair<unsigned, const CIRGenBitFieldInfo *> &info : bitInfo) {
1012 info.second->print(os);
1019 os <<
"<CIRBitFieldInfo" <<
" name:" <<
name <<
" offset:" <<
offset
1032void CIRRecordLowering::lowerUnion(
bool nonVirtualBaseType) {
1044 mlir::Type fieldType;
1045 cir::RecordMemberKind fieldKind;
1046 if (field->isBitField()) {
1047 if (field->isZeroLengthBitField())
1051 mlir::Type unitStorage =
1052 getBitfieldStorageType(field->getBitWidthValue());
1055 getBitFieldDecl(field));
1056 fieldType = unit.data;
1057 fieldKind = unit.memberKind;
1059 fieldType = getStorageType(field);
1060 fieldKind = getFieldMemberKind(field);
1063 fieldIdxMap[field->getCanonicalDecl()] = 0;
1064 addField(fieldType, fieldKind);
1072 auto hasNamedMember = [](
const FieldDecl *curField) ->
bool {
1073 const auto *rd = curField->getType()->getAsRecordDecl();
1079 auto isNamedMember = [hasNamedMember](
const FieldDecl *curField) ->
bool {
1080 if (curField->isZeroLengthBitField())
1082 return curField->getIdentifier() || hasNamedMember(curField);
1084 auto firstNamedMemberItr = llvm::find_if(
recordDecl->fields(), isNamedMember);
1086 if (firstNamedMemberItr !=
recordDecl->fields().end() &&
1087 !isZeroInitializable(*firstNamedMemberItr))
1088 zeroInitializable = zeroInitializableAsBase =
false;
1091 if (getFieldTypes().empty()) {
1092 appendPaddingBytes(layoutSize);
1096 mlir::Type storageType =
1097 cir::UnionType::getUnionStorageType(dataLayout.
layout, getFieldTypes());
1101 if (layoutSize < getSize(storageType))
1102 storageType = getByteArrayType(layoutSize);
1107 if (nonVirtualBaseType) {
1115 const cir::RecordMemberKind storageKind = makeMemberKind(
1117 llvm::any_of(getFieldKinds(),
1120 addField(storageType, storageKind);
1121 CharUnits padding = layoutSize - getSize(storageType);
1123 addField(getByteArrayType(padding), cir::RecordMemberKind::Pad);
1126 appendPaddingBytes(layoutSize - getSize(storageType));
1128 packed = !layoutSize.
isMultipleOf(getMemberAlignment(storageType));
1131bool CIRRecordLowering::hasOwnStorage(
const CXXRecordDecl *
decl,
1132 const CXXRecordDecl *query) {
1136 for (
const auto &base :
decl->bases())
1137 if (!hasOwnStorage(base.getType()->getAsCXXRecordDecl(), query))
1155void CIRRecordLowering::computeVolatileBitfields() {
1160 for (
auto &[field, info] : bitFields) {
1164 getSizeInBits(resLTy).getQuantity())
1172 const unsigned oldOffset =
1173 isBigEndian() ?
info.storageSize - (
info.offset +
info.size)
1176 const unsigned absoluteOffset =
1177 astContext.
toBits(
info.storageOffset) + oldOffset;
1180 const unsigned storageSize = getSizeInBits(resLTy).getQuantity();
1183 if (
info.storageSize == storageSize && (oldOffset % storageSize == 0))
1187 unsigned offset = absoluteOffset & (storageSize - 1);
1192 if (offset +
info.size > storageSize)
1197 offset = storageSize - (offset +
info.size);
1199 const CharUnits storageOffset =
1201 const CharUnits end = storageOffset +
1205 const ASTRecordLayout &layout =
1208 const CharUnits recordSize = layout.
getSize();
1209 if (end >= recordSize)
1213 bool conflict =
false;
1216 if (f->isBitField() && !f->isZeroLengthBitField())
1226 if (f->isZeroLengthBitField()) {
1227 if (end > fOffset && storageOffset < fOffset) {
1233 const CharUnits fEnd =
1240 if (end < fOffset || fEnd < storageOffset)
1253 info.volatileStorageOffset =
1256 info.volatileStorageSize = storageSize;
1257 info.volatileOffset = offset;
1261void CIRRecordLowering::accumulateBases() {
1264 const CXXRecordDecl *baseDecl = astRecordLayout.
getPrimaryBase();
1265 members.push_back(MemberInfo(
CharUnits::Zero(), MemberInfo::InfoKind::Base,
1266 getStorageType(baseDecl),
1267 getBaseMemberKind(baseDecl), baseDecl));
1272 if (base.isVirtual())
1276 const CXXRecordDecl *baseDecl = base.getType()->getAsCXXRecordDecl();
1280 MemberInfo::InfoKind::Base,
1281 getStorageType(baseDecl),
1282 getBaseMemberKind(baseDecl), baseDecl));
1287void CIRRecordLowering::accumulateVBases() {
1289 const CXXRecordDecl *baseDecl = base.getType()->getAsCXXRecordDecl();
1295 if (isOverlappingVBaseABI() && astContext.
isNearlyEmpty(baseDecl) &&
1297 members.push_back(MemberInfo(offset, MemberInfo::InfoKind::VBase,
nullptr,
1298 cir::RecordMemberKind::Data, baseDecl));
1304 ->second.hasVtorDisp())
1307 cir::RecordMemberKind::Data));
1308 members.push_back(MemberInfo(offset, MemberInfo::InfoKind::VBase,
1309 getStorageType(baseDecl),
1310 getBaseMemberKind(baseDecl), baseDecl));
1314void CIRRecordLowering::accumulateVPtrs() {
1316 members.push_back(MemberInfo(
CharUnits::Zero(), MemberInfo::InfoKind::VFPtr,
1317 getVFPtrType(), cir::RecordMemberKind::Data));
1321 "accumulateVPtrs: hasOwnVBPtr");
1324mlir::Type CIRRecordLowering::getVFPtrType() {
1325 return cir::VPtrType::get(builder.getContext());
Defines the clang::ASTContext interface.
static bool marksMatchABIEmptiness(const ASTContext &astContext, const RecordDecl *rd, cir::RecordType recordTy)
Whether the member kinds on recordTy answer the record's ABI emptiness the same way the AST predicate...
static cir::ArgPassingKind convertRecordArgPassingKind(RecordArgPassingKind kind)
Defines the C++ Decl subclasses, other than those for templates (found in DeclTemplate....
static void print(llvm::raw_ostream &OS, const T &V, const Context &Ctx, QualType Ty)
*collection of selector each with an associated kind and an ordered *collection of selectors A selector has a kind
llvm::TypeSize getTypeAllocSizeInBits(mlir::Type ty) const
Returns the offset in bits between successive objects of the specified type, including alignment padd...
C++ view class that accepts both !cir.struct and !cir.union types.
bool isIncomplete() const
bool isEmptyForABI() const
Whether no member holds data.
mlir::StringAttr getName() const
void complete(llvm::ArrayRef< mlir::Type > members, bool packed, mlir::Type padding, llvm::ArrayRef< RecordMemberKind > memberKinds)
padding is union-only.
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
const ASTRecordLayout & getASTRecordLayout(const RecordDecl *D) const
Get or compute information about the layout of the specified record (struct/union/class) D,...
bool isNearlyEmpty(const CXXRecordDecl *RD) const
int64_t toBits(CharUnits CharSize) const
Convert a size in characters to a size in bits.
const TargetInfo & getTargetInfo() const
CharUnits toCharUnitsFromBits(int64_t BitSize) const
Convert a size in bits to a size in characters.
CanQualType getCanonicalTagType(const TagDecl *TD) const
uint64_t getCharWidth() const
Return the size of the character type, in bits.
bool hasOwnVFPtr() const
hasOwnVFPtr - Does this class provide its own virtual-function table pointer, rather than inheriting ...
CharUnits getAlignment() const
getAlignment - Get the record alignment in characters.
bool hasOwnVBPtr() const
hasOwnVBPtr - Does this class provide its own virtual-base table pointer, rather than inheriting one ...
CharUnits getSize() const
getSize - Get the record size in characters.
uint64_t getFieldOffset(unsigned FieldNo) const
getFieldOffset - Get the offset of the given field index, in bits.
CharUnits getDataSize() const
getDataSize() - Get the record data size, which is the record size without tail padding,...
CharUnits getBaseClassOffset(const CXXRecordDecl *Base) const
getBaseClassOffset - Get the offset, in chars, for the given base class.
CharUnits getVBaseClassOffset(const CXXRecordDecl *VBase) const
getVBaseClassOffset - Get the offset, in chars, for the given base class.
const VBaseOffsetsMapTy & getVBaseOffsetsMap() const
const CXXRecordDecl * getPrimaryBase() const
getPrimaryBase - Get the primary base for this record.
bool isPrimaryBaseVirtual() const
isPrimaryBaseVirtual - Get whether the primary base for this record is virtual or not.
CharUnits getNonVirtualSize() const
getNonVirtualSize - Get the non-virtual size (in chars) of an object, which is the size of the object...
DiagnosticBuilder errorNYI(SourceLocation, llvm::StringRef)
Helpers to emit "not yet implemented" error diagnostics.
const clang::CodeGenOptions & getCodeGenOpts() const
LLVM_DUMP_METHOD void dump() const
void print(raw_ostream &os) const
This class organizes the cross-module state that is used while lowering AST types to CIR types.
CIRGenModule & getCGModule() const
std::string getRecordTypeName(const clang::RecordDecl *, llvm::StringRef suffix)
clang::ASTContext & getASTContext() const
std::unique_ptr< CIRGenRecordLayout > computeRecordLayout(const clang::RecordDecl *rd, cir::RecordType *ty)
mlir::Type convertTypeForMem(clang::QualType, bool forBitField=false)
Convert type T into an mlir::Type.
Represents a C++ struct/union/class.
bool isEmpty() const
Determine whether this is an empty class in the sense of (C++11 [meta.unary.prop]).
CharUnits - This is an opaque type for sizes expressed in character units.
bool isZero() const
isZero - Test whether the quantity equals zero.
QuantityType getQuantity() const
getQuantity - Get the raw integer representation of this quantity.
static CharUnits One()
One - Construct a CharUnits quantity of one.
bool isMultipleOf(CharUnits N) const
Test whether this is a multiple of the other value.
static CharUnits fromQuantity(QuantityType Quantity)
fromQuantity - Construct a CharUnits quantity from a raw integer type.
CharUnits alignTo(const CharUnits &Align) const
alignTo - Returns the next integer (mod 2**64) that is greater than or equal to this quantity and is ...
static CharUnits Zero()
Zero - Construct a CharUnits quantity of zero.
Represents a member of a struct/union/class.
bool isBitField() const
Determines whether this field is a bitfield.
unsigned getBitWidthValue() const
Computes the bit width of this field, if this is a bit field.
FieldDecl * getCanonicalDecl() override
Retrieves the canonical declaration of this field.
bool isUnnamedBitField() const
Determines whether this is an unnamed bitfield.
bool isZeroLengthBitField() const
Is this a zero-length bit-field?
StringRef getName() const
Get the name of identifier for this declaration as a StringRef.
Represents a struct/union/class.
RecordArgPassingKind getArgPassingRestrictions() const
const FieldDecl * findFirstNamedDataMember() const
Finds the first data member which has a name.
specific_decl_iterator< FieldDecl > field_iterator
field_iterator field_begin() const
virtual unsigned getRegisterWidth() const
Return the "preferred" register width on this target.
bool hasCheapUnalignedBitFieldAccess() const
Return true iff unaligned accesses are cheap.
bool isSignedIntegerOrEnumerationType() const
Determines whether this is an integer type that is signed or an enumeration types whose underlying ty...
mlir::Type memberStorageType(mlir::Type memberTy)
The storage a member is stored as: the access unit for a bit-field member, and the member type itself...
bool memberOwnsBytes(mlir::Type memberTy)
Whether a record member occupies bytes of its record.
bool isValidFundamentalIntWidth(unsigned width)
bool anyMemberHoldsDataForABI(llvm::ArrayRef< RecordMemberKind > kinds)
Whether any member holds data for argument passing on its mark alone.
bool isNamedBitField(RecordMemberKind kind)
Whether a member of this kind is an access unit the source can read a bit-field of.
bool isEmptyRecordForABI(const ASTContext &context, QualType t)
isEmptyRecordForABI - Return true if a structure contains only empty base classes and fields.
bool isEmptyFieldForABI(const ASTContext &context, const FieldDecl *fd)
isEmptyFieldForABI - Return true if the field is "empty", that is, it is a zero-width bit-field or an...
bool isEmptyFieldForLayout(const ASTContext &context, const FieldDecl *fd)
isEmptyFieldForLayout - Return true if the field is "empty", that is, either a zero-width bit-field o...
bool isEmptyRecordForLayout(const ASTContext &context, QualType t)
isEmptyRecordForLayout - Return true if a structure contains only empty base classes (per isEmptyReco...
bool isAAPCS(const TargetInfo &TargetInfo)
Helper method to check if the underlying ABI is AAPCS.
const internal::VariadicAllOfMatcher< Type > type
Matches Types in the clang AST.
const internal::VariadicDynCastAllOfMatcher< Decl, FieldDecl > fieldDecl
Matches field declarations.
const internal::VariadicDynCastAllOfMatcher< Decl, CXXRecordDecl > cxxRecordDecl
Matches C++ class declarations.
const internal::VariadicAllOfMatcher< Decl > decl
Matches declarations.
const internal::VariadicDynCastAllOfMatcher< Decl, RecordDecl > recordDecl
Matches class, struct, and union declarations.
constexpr size_t align(size_t Size)
Aligns a size to the pointer alignment.
void info(bool Verbose, unsigned Level, const char *Fmt, Ts &&...Args)
Prints an indented note to stderr when Verbose is set.
Top level wrappers for InstallAPI frontend operations.
bool operator<(DeclarationName LHS, DeclarationName RHS)
Ordering on two declaration names.
RecordArgPassingKind
Enum that represents the different ways arguments are passed to and returned from function calls.
@ CanPassInRegs
The argument of this type can be passed directly in registers.
@ CanNeverPassInRegs
The argument of this type cannot be passed directly in registers.
@ CannotPassInRegs
The argument of this type cannot be passed directly in registers.
Diagnostic wrappers for TextAPI types for error reporting.
void __ovld __conv barrier(cl_mem_fence_flags)
All work-items in a work-group executing the kernel on a processor must execute this function before ...
static bool noUniqueAddressLayout()
static bool checkBitfieldClipping()
static bool astRecordDeclAttr()
unsigned offset
The offset within a contiguous run of bitfields that are represented as a single "field" within the c...
void print(llvm::raw_ostream &os) const
LLVM_DUMP_METHOD void dump() const
unsigned storageSize
The storage size in bits which should be used when accessing this bitfield.
unsigned volatileStorageSize
The storage size in bits which should be used when accessing this bitfield.
clang::CharUnits storageOffset
The offset of the bitfield storage from the start of the record.
unsigned size
The total size of the bit-field, in bits.
unsigned isSigned
Whether the bit-field is signed.
clang::CharUnits volatileStorageOffset
The offset of the bitfield storage from the start of the record.
unsigned volatileOffset
The offset within a contiguous run of bitfields that are represented as a single "field" within the c...
llvm::StringRef name
The name of a bitfield.