27#include "llvm/Support/Casting.h"
40struct CIRRecordLowering final {
45 struct MemberInfo final {
47 enum class InfoKind { VFPtr,
Field,
Base, VBase } kind;
50 cir::RecordMemberKind memberKind;
55 MemberInfo(CharUnits offset, InfoKind kind, mlir::Type data,
56 cir::RecordMemberKind memberKind,
58 : offset{offset}, kind{kind}, data{data}, memberKind{memberKind},
60 MemberInfo(CharUnits offset, InfoKind kind, mlir::Type data,
61 cir::RecordMemberKind memberKind,
const CXXRecordDecl *rd)
62 : offset{offset}, kind{kind}, data{data}, memberKind{memberKind},
65 bool operator<(
const MemberInfo &other)
const {
66 return offset < other.offset;
70 static bool ownsBytes(
const MemberInfo &member) {
74 cir::BitFieldDeclAttr getBitFieldDecl(
const FieldDecl *field) {
75 return cir::BitFieldDeclAttr::get(
76 cirGenTypes.convertTypeForMem(field->
getType()),
80 MemberInfo makeAccessUnitInfo(CharUnits offset, mlir::Type storage,
81 llvm::ArrayRef<cir::BitFieldDeclAttr> fields) {
83 cir::BitFieldType::get(&cirGenTypes.getMLIRContext(), storage, fields);
85 const bool holdsNamedField =
86 mlir::cast<cir::BitFieldType>(unitTy).holdsNamedField();
87 return makeStorageInfo(offset, unitTy,
88 holdsNamedField ? cir::RecordMemberKind::BitField
89 : cir::RecordMemberKind::Empty);
95 MemberInfo makeZeroWidthBitFieldInfo(
const FieldDecl *field) {
97 return makeAccessUnitInfo(bitsToCharUnits(getFieldBitOffset(field)),
98 mlir::Type{}, getBitFieldDecl(field));
102 CIRRecordLowering(CIRGenTypes &cirGenTypes,
const RecordDecl *recordDecl,
106 MemberInfo makeStorageInfo(CharUnits offset, mlir::Type data,
107 cir::RecordMemberKind memberKind) {
108 return MemberInfo(offset, MemberInfo::InfoKind::Field, data, memberKind);
112 void setBitFieldInfo(
const FieldDecl *fd, CharUnits startOffset,
113 mlir::Type storageType);
115 void lower(
bool nonVirtualBaseType);
116 void lowerUnion(
bool nonVirtualBaseType);
119 void determinePacked(
bool nvBaseType);
121 void insertPadding();
123 void computeVolatileBitfields();
124 void accumulateBases();
125 void accumulateVPtrs();
126 void accumulateVBases();
127 void accumulateFields(
bool nonVirtualBaseType);
132 mlir::Type getVFPtrType();
135 bool isBigEndian()
const {
return astContext.getTargetInfo().isBigEndian(); }
137 CharUnits bitsToCharUnits(uint64_t bitOffset) {
138 return astContext.toCharUnitsFromBits(bitOffset);
141 void calculateZeroInit();
143 CharUnits getSize(mlir::Type Ty) {
146 CharUnits getSizeInBits(mlir::Type ty) {
150 CharUnits getMemberAlignment(mlir::Type Ty) {
153 if (
auto bitFieldTy = mlir::dyn_cast<cir::BitFieldType>(Ty)) {
154 if (mlir::Type storage = bitFieldTy.getStorageType())
155 return getMemberAlignment(storage);
159 if (
auto arrayTy = mlir::dyn_cast<cir::ArrayType>(Ty))
160 return getMemberAlignment(arrayTy.getElementType());
163 if (
auto intTy = mlir::dyn_cast<cir::IntType>(Ty))
165 intTy.getStorageTypeAlignment(dataLayout.layout));
170 bool isZeroInitializable(
const FieldDecl *fd) {
171 return cirGenTypes.isZeroInitializable(fd->
getType());
173 bool isZeroInitializable(
const RecordDecl *rd) {
174 return cirGenTypes.isZeroInitializable(rd);
181 static cir::RecordMemberKind makeMemberKind(
bool holdsData,
182 bool isNamedBitField) {
184 return cir::RecordMemberKind::Empty;
186 : cir::RecordMemberKind::Data;
192 cir::RecordMemberKind getFieldMemberKind(
const FieldDecl *fd) {
193 assert(!fd->
isBitField() &&
"a bit-field is marked with its access unit");
201 cir::RecordMemberKind getBaseMemberKind(
const CXXRecordDecl *baseDecl) {
203 astContext.getCanonicalTagType(baseDecl))
204 ? cir::RecordMemberKind::Empty
205 : cir::RecordMemberKind::Data;
209 mlir::Type getUIntNType(uint64_t numBits) {
210 unsigned alignedBits = llvm::PowerOf2Ceil(numBits);
211 alignedBits = std::max(8u, alignedBits);
212 return cir::IntType::get(&cirGenTypes.getMLIRContext(), alignedBits,
216 mlir::Type getCharType() {
217 return cir::IntType::get(&cirGenTypes.getMLIRContext(),
218 astContext.getCharWidth(),
222 mlir::Type getByteArrayType(CharUnits numberOfChars) {
223 assert(!numberOfChars.
isZero() &&
"Empty byte arrays aren't allowed.");
224 mlir::Type
type = getCharType();
231 mlir::Type getStorageType(
const CXXRecordDecl *RD) {
232 return cirGenTypes.getCIRGenRecordLayout(RD).getBaseSubobjectCIRType();
237 mlir::Type getBitfieldStorageType(
unsigned numBits) {
238 unsigned alignedBits = llvm::alignTo(numBits, astContext.getCharWidth());
240 return builder.getUIntNTy(alignedBits);
242 mlir::Type
type = getCharType();
243 return cir::ArrayType::get(
type, alignedBits / astContext.getCharWidth());
246 mlir::Type getStorageType(
const FieldDecl *
fieldDecl) {
247 mlir::Type
type = cirGenTypes.convertTypeForMem(
fieldDecl->getType());
249 cirGenTypes.getCGModule().errorNYI(recordDecl->getSourceRange(),
250 "getStorageType for bitfields");
252 if (hasBoolVectorStorageAlignMismatch(
type))
253 cirGenTypes.getCGModule().errorNYI(
255 "getStorageType for bool vector whose storage integer is aligned "
256 "differently from the vector");
267 bool hasBoolVectorStorageAlignMismatch(mlir::Type
type) {
268 while (
auto arrTy = mlir::dyn_cast<cir::ArrayType>(
type))
269 type = arrTy.getElementType();
270 auto vecTy = mlir::dyn_cast<cir::VectorType>(
type);
271 if (!vecTy || !mlir::isa<cir::BoolType>(vecTy.getElementType()))
274 mlir::IntegerType::get(
type.getContext(), vecTy.getBoolStorageWidth());
275 return dataLayout.layout.getTypeABIAlignment(storageTy) !=
276 dataLayout.layout.getTypeABIAlignment(vecTy);
280 return astRecordLayout.getFieldOffset(
fieldDecl->getFieldIndex());
284 void fillOutputFields();
286 void appendPaddingBytes(CharUnits size) {
289 mlir::Type padTy = getByteArrayType(size);
290 if (recordDecl->isUnion()) {
291 assert(!unionPadding &&
"at most one union tail-padding type");
292 unionPadding = padTy;
294 addField(padTy, cir::RecordMemberKind::Pad);
298 void addField(mlir::Type ty, cir::RecordMemberKind memberKind) {
299 fieldTypes.push_back(ty);
300 fieldKinds.push_back(memberKind);
308 llvm::ArrayRef<mlir::Type> getFieldTypes()
const {
return fieldTypes; }
309 llvm::ArrayRef<cir::RecordMemberKind> getFieldKinds()
const {
313 CIRGenTypes &cirGenTypes;
314 CIRGenBuilderTy &builder;
315 const ASTContext &astContext;
316 const RecordDecl *recordDecl;
317 const CXXRecordDecl *cxxRecordDecl;
318 const ASTRecordLayout &astRecordLayout;
320 std::vector<MemberInfo> members;
321 mlir::Type unionPadding;
322 llvm::DenseMap<const FieldDecl *, CIRGenBitFieldInfo> bitFields;
323 llvm::DenseMap<const FieldDecl *, unsigned> fieldIdxMap;
324 llvm::DenseMap<const CXXRecordDecl *, unsigned> nonVirtualBases;
325 llvm::DenseMap<const CXXRecordDecl *, unsigned> virtualBases;
326 cir::CIRDataLayout dataLayout;
328 LLVM_PREFERRED_TYPE(
bool)
329 unsigned zeroInitializable : 1;
330 LLVM_PREFERRED_TYPE(
bool)
331 unsigned zeroInitializableAsBase : 1;
332 LLVM_PREFERRED_TYPE(
bool)
339 llvm::SmallVector<mlir::Type, 16> fieldTypes;
340 llvm::SmallVector<cir::RecordMemberKind> fieldKinds;
342 CIRRecordLowering(
const CIRRecordLowering &) =
delete;
343 void operator=(
const CIRRecordLowering &) =
delete;
347CIRRecordLowering::CIRRecordLowering(
CIRGenTypes &cirGenTypes,
349 : cirGenTypes{cirGenTypes}, builder{cirGenTypes.getBuilder()},
353 cirGenTypes.getASTContext().getASTRecordLayout(
recordDecl)},
354 dataLayout{cirGenTypes.getCGModule().getModule()},
355 zeroInitializable{
true}, zeroInitializableAsBase{
true}, packed{packed} {}
357void CIRRecordLowering::setBitFieldInfo(
const FieldDecl *fd,
359 mlir::Type storageType) {
363 (unsigned)(getFieldBitOffset(fd) - astContext.
toBits(startOffset));
365 info.storageSize = getSizeInBits(storageType).getQuantity();
366 info.storageOffset = startOffset;
367 info.storageType = storageType;
379 info.volatileStorageSize = 0;
380 info.volatileOffset = 0;
384void CIRRecordLowering::lower(
bool nonVirtualBaseType) {
386 lowerUnion(nonVirtualBaseType);
387 computeVolatileBitfields();
394 accumulateFields(nonVirtualBaseType);
399 if (members.empty()) {
400 appendPaddingBytes(size);
401 computeVolatileBitfields();
404 if (!nonVirtualBaseType)
408 llvm::stable_sort(members);
415 makeStorageInfo(size, getUIntNType(8), cir::RecordMemberKind::Data));
416 determinePacked(nonVirtualBaseType);
422 computeVolatileBitfields();
425void CIRRecordLowering::fillOutputFields() {
426 for (
const MemberInfo &member : members) {
429 if (
member.kind == MemberInfo::InfoKind::Field) {
431 fieldIdxMap[
member.fieldDecl->getCanonicalDecl()] =
432 fieldTypes.size() - 1;
436 assert(
member.fieldDecl &&
437 "member.data is a nullptr so member.fieldDecl should not be");
441 }
else if (
member.kind == MemberInfo::InfoKind::Base) {
442 nonVirtualBases[
member.cxxRecordDecl] = fieldTypes.size() - 1;
443 }
else if (
member.kind == MemberInfo::InfoKind::VBase) {
444 virtualBases[
member.cxxRecordDecl] = fieldTypes.size() - 1;
466 mlir::Type unitStorage;
467 llvm::SmallVector<cir::BitFieldDeclAttr> unitFields;
468 for (; field != fieldEnd && field->isBitField(); ++field) {
470 if (field->isZeroLengthBitField()) {
471 members.push_back(makeZeroWidthBitFieldInfo(*field));
475 uint64_t bitOffset = getFieldBitOffset(*field);
477 cir::BitFieldDeclAttr
decl = getBitFieldDecl(*field);
480 if (run == fieldEnd || bitOffset >= tail) {
482 startBitOffset = bitOffset;
486 unitIdx = members.size();
488 unitFields.assign(1,
decl);
489 members.push_back(makeAccessUnitInfo(bitsToCharUnits(startBitOffset),
490 unitStorage, unitFields));
492 unitFields.push_back(
decl);
493 members[unitIdx] = makeAccessUnitInfo(bitsToCharUnits(startBitOffset),
494 unitStorage, unitFields);
496 assert(members[unitIdx].offset == bitsToCharUnits(startBitOffset) &&
497 "unitIdx must name the current run's access unit");
500 members.push_back(MemberInfo(bitsToCharUnits(startBitOffset),
501 MemberInfo::InfoKind::Field,
nullptr,
502 cir::RecordMemberKind::Data, *field));
518 CharUnits beginOffset;
527 CharUnits bestEndOffset;
535 bool atAlignedBoundary =
false;
537 if (field != fieldEnd && field->isBitField()) {
538 uint64_t bitOffset = getFieldBitOffset(*field);
539 if (begin == fieldEnd) {
544 assert((bitOffset % charBits) == 0 &&
"Not at start of char");
545 beginOffset = bitsToCharUnits(bitOffset);
546 bitSizeSinceBegin = 0;
547 }
else if ((bitOffset % charBits) != 0) {
555 astContext.
toBits(beginOffset) + bitSizeSinceBegin &&
556 "Concatenating non-contiguous bitfields");
561 if (field->isZeroLengthBitField())
563 atAlignedBoundary =
true;
568 if (begin == fieldEnd)
572 atAlignedBoundary =
true;
578 bool installBest =
false;
579 if (atAlignedBoundary) {
585 CharUnits accessSize = bitsToCharUnits(bitSizeSinceBegin + charBits - 1);
586 if (bestEnd == begin) {
590 bestEndOffset = beginOffset + accessSize;
593 if (!bitSizeSinceBegin)
597 }
else if (accessSize > regSize) {
606 mlir::Type
type = getUIntNType(astContext.
toBits(accessSize));
613 CharUnits
align = getMemberAlignment(
type);
624 if (installBest && bestEnd == field) {
627 if (getSize(
type) == accessSize)
637 CharUnits limitOffset;
638 for (
auto probe = field; probe != fieldEnd; ++probe)
641 assert((getFieldBitOffset(*probe) % charBits) == 0 &&
642 "Next storage is not byte-aligned");
643 limitOffset = bitsToCharUnits(getFieldBitOffset(*probe));
650 CharUnits typeSize = getSize(
type);
651 if (beginOffset + typeSize <= limitOffset) {
654 bestEndOffset = beginOffset + typeSize;
663 .FineGrainedBitfieldAccesses) {
669 bitSizeSinceBegin = astContext.
toBits(limitOffset - beginOffset);
676 assert((field == fieldEnd || !field->isBitField() ||
677 (getFieldBitOffset(*field) % charBits) == 0) &&
678 "Installing but not at an aligned bitfield or limit");
679 CharUnits accessSize = bestEndOffset - beginOffset;
680 if (!accessSize.
isZero()) {
686 assert(getSize(getUIntNType(astContext.
toBits(accessSize))) >
688 "Clipped access need not be clipped");
689 type = getByteArrayType(accessSize);
691 type = getUIntNType(astContext.
toBits(accessSize));
692 assert(getSize(
type) == accessSize &&
693 "Unclipped access must be clipped");
698 llvm::SmallVector<cir::BitFieldDeclAttr> unitFields;
699 for (
auto occupant = begin; occupant != bestEnd; ++occupant)
700 if (!occupant->isZeroLengthBitField())
701 unitFields.push_back(getBitFieldDecl(*occupant));
702 assert(!unitFields.empty() &&
"an access unit holds a bit-field");
703 members.push_back(makeAccessUnitInfo(beginOffset,
type, unitFields));
705 for (; begin != bestEnd; ++begin)
706 if (!begin->isZeroLengthBitField())
707 members.push_back(MemberInfo(beginOffset,
708 MemberInfo::InfoKind::Field,
nullptr,
709 cir::RecordMemberKind::Data, *begin));
715 assert(field != fieldEnd && field->isBitField() &&
716 "Accumulating past end of bitfields");
717 assert(!
barrier &&
"Accumulating across barrier");
718 if (field->isZeroLengthBitField())
719 members.push_back(makeZeroWidthBitFieldInfo(*field));
721 bitSizeSinceBegin += field->getBitWidthValue();
729void CIRRecordLowering::accumulateFields(
bool nonVirtualBaseType) {
732 field != fieldEnd;) {
733 if (field->isBitField()) {
734 field = accumulateBitFields(field, fieldEnd);
735 assert((field == fieldEnd || !field->isBitField()) &&
736 "Failed to accumulate all the bitfields");
738 field->isPotentiallyOverlapping()) {
755 MemberInfo(bitsToCharUnits(getFieldBitOffset(*field)),
756 MemberInfo::InfoKind::Field,
757 getStorageType(field->getType()->getAsCXXRecordDecl()),
758 getFieldMemberKind(*field), *field));
766 members.push_back(MemberInfo(
767 bitsToCharUnits(getFieldBitOffset(*field)),
768 MemberInfo::InfoKind::Field,
769 field->isPotentiallyOverlapping()
770 ? getStorageType(field->getType()->getAsCXXRecordDecl())
771 : getStorageType(*field),
772 getFieldMemberKind(*field), *field));
778void CIRRecordLowering::calculateZeroInit() {
779 for (
const MemberInfo &member : members) {
780 if (
member.kind == MemberInfo::InfoKind::Field) {
781 if (!
member.fieldDecl || isZeroInitializable(
member.fieldDecl))
783 zeroInitializable = zeroInitializableAsBase =
false;
785 }
else if (
member.kind == MemberInfo::InfoKind::Base ||
786 member.kind == MemberInfo::InfoKind::VBase) {
787 if (isZeroInitializable(
member.cxxRecordDecl))
789 zeroInitializable =
false;
790 if (
member.kind == MemberInfo::InfoKind::Base)
791 zeroInitializableAsBase =
false;
796void CIRRecordLowering::determinePacked(
bool nvBaseType) {
805 for (
const MemberInfo &member : members) {
808 if (!ownsBytes(member))
812 if (!
member.offset.isMultipleOf(getMemberAlignment(
member.data)))
814 if (
member.offset < nvSize)
815 nvAlignment = std::max(nvAlignment, getMemberAlignment(
member.data));
816 alignment = std::max(alignment, getMemberAlignment(
member.data));
820 if (!members.back().offset.isMultipleOf(alignment))
829 members.back().data = getUIntNType(astContext.
toBits(alignment));
832void CIRRecordLowering::insertPadding() {
833 std::vector<std::pair<CharUnits, CharUnits>> padding;
835 for (
const MemberInfo &member : members) {
843 if (!ownsBytes(member)) {
844 if (
member.offset > size) {
845 padding.push_back(std::make_pair(size,
member.offset - size));
850 CharUnits offset =
member.offset;
851 assert(offset >= size);
854 : getMemberAlignment(
member.data)))
855 padding.push_back(std::make_pair(size, offset - size));
856 size = offset + getSize(
member.data);
861 for (
const std::pair<CharUnits, CharUnits> &paddingPair : padding)
862 members.push_back(makeStorageInfo(paddingPair.first,
863 getByteArrayType(paddingPair.second),
864 cir::RecordMemberKind::Pad));
865 llvm::stable_sort(members);
868static cir::ArgPassingKind
872 return cir::ArgPassingKind::CanPassInRegs;
874 return cir::ArgPassingKind::CannotPassInRegs;
876 return cir::ArgPassingKind::CanNeverPassInRegs;
878 llvm_unreachable(
"unknown RecordArgPassingKind");
883[[maybe_unused]]
static bool
890std::unique_ptr<CIRGenRecordLayout>
892 CIRRecordLowering lowering(*
this, rd,
false);
893 assert(ty->
isIncomplete() &&
"recomputing record layout?");
894 lowering.lower(
false);
906 if (llvm::isa<CXXRecordDecl>(rd)) {
915 lowering.astRecordLayout.
getSize()) {
916 CIRRecordLowering baseLowering(*
this, rd, lowering.packed);
917 baseLowering.lower(
true);
919 baseTy = builder.getCompleteNamedRecordType(
920 baseLowering.getFieldTypes(), baseLowering.packed, baseIdentifier,
921 baseLowering.getFieldKinds());
930 assert((rd->
isUnion() || lowering.packed == baseLowering.packed) &&
931 "Non-virtual and complete types must agree on packedness");
936 cgm.getDiags().hasErrorOccurred()) &&
937 "base subobject member kinds must reproduce its ABI emptiness");
945 ty->
complete(lowering.getFieldTypes(), lowering.packed, lowering.unionPadding,
946 lowering.getFieldKinds());
953 cgm.getDiags().hasErrorOccurred()) &&
954 "member kinds must reproduce the ABI emptiness of the record");
958 mlir::MLIRContext *mlirCtx = ty->getContext();
959 cir::ArgPassingKind apk =
962 bool hasTrivialDestructor =
true;
963 if (
auto *cxxRD = dyn_cast<CXXRecordDecl>(rd))
964 hasTrivialDestructor = cxxRD->hasTrivialDestructor();
965 const auto &astLayout = astContext.getASTRecordLayout(rd);
966 uint64_t recordAlignInBytes = astLayout.getAlignment().getQuantity();
967 uint64_t unadjustedAlignInBytes =
968 astLayout.getUnadjustedAlignment().getQuantity();
973 cir::RecordLayoutAttr::get(mlirCtx, apk, hasTrivialDestructor,
974 recordAlignInBytes, unadjustedAlignInBytes,
978 auto rl = std::make_unique<CIRGenRecordLayout>(
980 (bool)lowering.zeroInitializable, (bool)lowering.zeroInitializableAsBase);
982 rl->nonVirtualBases.swap(lowering.nonVirtualBases);
983 rl->completeObjectVirtualBases.swap(lowering.virtualBases);
986 rl->fieldIdxMap.swap(lowering.fieldIdxMap);
988 rl->bitFields.swap(lowering.bitFields);
992 llvm::outs() <<
"\n*** Dumping CIRgen Record Layout\n";
993 llvm::outs() <<
"Record: ";
994 rd->
dump(llvm::outs());
995 llvm::outs() <<
"\nLayout: ";
996 rl->print(llvm::outs());
1004 os <<
"<CIRecordLayout\n";
1005 os <<
" CIR Type:" << completeObjectType <<
"\n";
1006 if (baseSubobjectType)
1007 os <<
" NonVirtualBaseCIRType:" << baseSubobjectType <<
"\n";
1008 os <<
" IsZeroInitializable:" << zeroInitializable <<
"\n";
1009 os <<
" BitFields:[\n";
1010 std::vector<std::pair<unsigned, const CIRGenBitFieldInfo *>> bitInfo;
1011 for (
auto &[
decl, info] : bitFields) {
1016 bitInfo.push_back(std::make_pair(
index, &info));
1018 llvm::array_pod_sort(bitInfo.begin(), bitInfo.end());
1019 for (std::pair<unsigned, const CIRGenBitFieldInfo *> &info : bitInfo) {
1021 info.second->print(os);
1028 os <<
"<CIRBitFieldInfo" <<
" name:" <<
name <<
" offset:" <<
offset
1041void CIRRecordLowering::lowerUnion(
bool nonVirtualBaseType) {
1053 mlir::Type fieldType;
1054 cir::RecordMemberKind fieldKind;
1055 if (field->isBitField()) {
1056 if (field->isZeroLengthBitField())
1060 mlir::Type unitStorage =
1061 getBitfieldStorageType(field->getBitWidthValue());
1064 getBitFieldDecl(field));
1065 fieldType = unit.data;
1066 fieldKind = unit.memberKind;
1068 fieldType = getStorageType(field);
1069 fieldKind = getFieldMemberKind(field);
1072 fieldIdxMap[field->getCanonicalDecl()] = 0;
1073 addField(fieldType, fieldKind);
1081 auto hasNamedMember = [](
const FieldDecl *curField) ->
bool {
1082 const auto *rd = curField->getType()->getAsRecordDecl();
1088 auto isNamedMember = [hasNamedMember](
const FieldDecl *curField) ->
bool {
1089 if (curField->isZeroLengthBitField())
1091 return curField->getIdentifier() || hasNamedMember(curField);
1093 auto firstNamedMemberItr = llvm::find_if(
recordDecl->fields(), isNamedMember);
1095 if (firstNamedMemberItr !=
recordDecl->fields().end() &&
1096 !isZeroInitializable(*firstNamedMemberItr))
1097 zeroInitializable = zeroInitializableAsBase =
false;
1100 if (getFieldTypes().empty()) {
1101 appendPaddingBytes(layoutSize);
1105 mlir::Type storageType =
1106 cir::UnionType::getUnionStorageType(dataLayout.
layout, getFieldTypes());
1110 if (layoutSize < getSize(storageType))
1111 storageType = getByteArrayType(layoutSize);
1116 if (nonVirtualBaseType) {
1124 const cir::RecordMemberKind storageKind = makeMemberKind(
1126 llvm::any_of(getFieldKinds(),
1129 addField(storageType, storageKind);
1130 CharUnits padding = layoutSize - getSize(storageType);
1132 addField(getByteArrayType(padding), cir::RecordMemberKind::Pad);
1135 appendPaddingBytes(layoutSize - getSize(storageType));
1137 packed = !layoutSize.
isMultipleOf(getMemberAlignment(storageType));
1153void CIRRecordLowering::computeVolatileBitfields() {
1158 for (
auto &[field, info] : bitFields) {
1162 getSizeInBits(resLTy).getQuantity())
1170 const unsigned oldOffset =
1171 isBigEndian() ?
info.storageSize - (
info.offset +
info.size)
1174 const unsigned absoluteOffset =
1175 astContext.
toBits(
info.storageOffset) + oldOffset;
1178 const unsigned storageSize = getSizeInBits(resLTy).getQuantity();
1181 if (
info.storageSize == storageSize && (oldOffset % storageSize == 0))
1185 unsigned offset = absoluteOffset & (storageSize - 1);
1190 if (offset +
info.size > storageSize)
1195 offset = storageSize - (offset +
info.size);
1197 const CharUnits storageOffset =
1199 const CharUnits end = storageOffset +
1203 const ASTRecordLayout &layout =
1206 const CharUnits recordSize = layout.
getSize();
1207 if (end >= recordSize)
1211 bool conflict =
false;
1214 if (f->isBitField() && !f->isZeroLengthBitField())
1224 if (f->isZeroLengthBitField()) {
1225 if (end > fOffset && storageOffset < fOffset) {
1231 const CharUnits fEnd =
1238 if (end < fOffset || fEnd < storageOffset)
1251 info.volatileStorageOffset =
1254 info.volatileStorageSize = storageSize;
1255 info.volatileOffset = offset;
1259void CIRRecordLowering::accumulateBases() {
1262 const CXXRecordDecl *baseDecl = astRecordLayout.
getPrimaryBase();
1263 members.push_back(MemberInfo(
CharUnits::Zero(), MemberInfo::InfoKind::Base,
1264 getStorageType(baseDecl),
1265 getBaseMemberKind(baseDecl), baseDecl));
1270 if (base.isVirtual())
1274 const CXXRecordDecl *baseDecl = base.getType()->getAsCXXRecordDecl();
1278 MemberInfo::InfoKind::Base,
1279 getStorageType(baseDecl),
1280 getBaseMemberKind(baseDecl), baseDecl));
1285void CIRRecordLowering::accumulateVBases() {
1287 const CXXRecordDecl *baseDecl = base.getType()->getAsCXXRecordDecl();
1296 members.push_back(MemberInfo(offset, MemberInfo::InfoKind::VBase,
nullptr,
1297 cir::RecordMemberKind::Data, baseDecl));
1303 ->second.hasVtorDisp())
1306 cir::RecordMemberKind::Data));
1307 members.push_back(MemberInfo(offset, MemberInfo::InfoKind::VBase,
1308 getStorageType(baseDecl),
1309 getBaseMemberKind(baseDecl), baseDecl));
1313void CIRRecordLowering::accumulateVPtrs() {
1315 members.push_back(MemberInfo(
CharUnits::Zero(), MemberInfo::InfoKind::VFPtr,
1316 getVFPtrType(), cir::RecordMemberKind::Data));
1320 "accumulateVPtrs: hasOwnVBPtr");
1323mlir::Type CIRRecordLowering::getVFPtrType() {
1324 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)
static bool isTransparentUnion(QualType T)
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]).
This is an opaque type for sizes expressed in character units.
bool isZero() const
Test whether the quantity equals zero.
CharUnits alignTo(CharUnits Align) const
Returns the next integer (mod 2**64) that is greater than or equal to this quantity and is a multiple...
QuantityType getQuantity() const
Get the raw integer representation of this quantity.
static CharUnits 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)
Construct a CharUnits quantity from a raw integer type.
static CharUnits 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 isAAPCS(const TargetInfo &TargetInfo)
Helper method to check if the underlying ABI is AAPCS.
bool isDiscreteBitFieldABI(const ASTContext &Ctx, const RecordDecl *RD)
The Microsoft bitfield layout rule allocates discrete storage units of the field's formal type and on...
bool hasOwnStorage(const ASTContext &Ctx, const CXXRecordDecl *Decl, const CXXRecordDecl *Query)
Recursively searches all of the bases of Decl to find out whether Query is not the primary vbase of s...
bool isOverlappingVBaseABI(const ASTContext &Ctx)
The Itanium base layout rule allows virtual bases to overlap other bases, which complicates layout in...
bool isEmptyFieldForLayout(const ASTContext &Ctx, const FieldDecl *FD)
Return true iff the field is "empty", that is, either a zero-width bit-field or an isEmptyRecordForLa...
bool isEmptyRecordForLayout(const ASTContext &Ctx, QualType T)
Return true iff a structure contains only empty base classes (per isEmptyRecordForLayout) and fields ...
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.