25#include "llvm/Support/Casting.h"
38struct CIRRecordLowering final {
43 struct MemberInfo final {
45 enum class InfoKind { VFPtr,
Field,
Base, VBase } kind;
48 cir::RecordMemberKind memberKind;
53 MemberInfo(CharUnits offset, InfoKind kind, mlir::Type data,
54 cir::RecordMemberKind memberKind,
56 : offset{offset}, kind{kind}, data{data}, memberKind{memberKind},
58 MemberInfo(CharUnits offset, InfoKind kind, mlir::Type data,
59 cir::RecordMemberKind memberKind,
const CXXRecordDecl *rd)
60 : offset{offset}, kind{kind}, data{data}, memberKind{memberKind},
63 bool operator<(
const MemberInfo &other)
const {
64 return offset < other.offset;
68 CIRRecordLowering(CIRGenTypes &cirGenTypes,
const RecordDecl *recordDecl,
72 MemberInfo makeStorageInfo(CharUnits offset, mlir::Type data,
73 cir::RecordMemberKind memberKind) {
74 return MemberInfo(offset, MemberInfo::InfoKind::Field, data, memberKind);
78 void setBitFieldInfo(
const FieldDecl *fd, CharUnits startOffset,
79 mlir::Type storageType);
81 void lower(
bool nonVirtualBaseType);
82 void lowerUnion(
bool nonVirtualBaseType);
85 void determinePacked(
bool nvBaseType);
89 void computeVolatileBitfields();
90 void accumulateBases();
91 void accumulateVPtrs();
92 void accumulateVBases();
93 void accumulateFields(
bool nonVirtualBaseType);
98 mlir::Type getVFPtrType();
101 return astContext.getTargetInfo().getABI().starts_with(
"aapcs");
105 bool isBigEndian()
const {
return astContext.getTargetInfo().isBigEndian(); }
111 bool isOverlappingVBaseABI() {
112 return !astContext.getTargetInfo().getCXXABI().isMicrosoft();
116 bool hasOwnStorage(
const CXXRecordDecl *
decl,
const CXXRecordDecl *query);
123 bool isDiscreteBitFieldABI() {
124 return astContext.getTargetInfo().getCXXABI().isMicrosoft() ||
125 recordDecl->isMsStruct(astContext);
128 CharUnits bitsToCharUnits(uint64_t bitOffset) {
129 return astContext.toCharUnitsFromBits(bitOffset);
132 void calculateZeroInit();
134 CharUnits getSize(mlir::Type Ty) {
137 CharUnits getSizeInBits(mlir::Type ty) {
140 CharUnits getAlignment(mlir::Type Ty) {
144 bool isZeroInitializable(
const FieldDecl *fd) {
145 return cirGenTypes.isZeroInitializable(fd->
getType());
147 bool isZeroInitializable(
const RecordDecl *rd) {
148 return cirGenTypes.isZeroInitializable(rd);
152 cir::RecordMemberKind getFieldMemberKind(
const FieldDecl *fd) {
154 : cir::RecordMemberKind::Data;
160 cir::RecordMemberKind getBaseMemberKind(
const CXXRecordDecl *baseDecl) {
162 astContext.getCanonicalTagType(baseDecl))
163 ? cir::RecordMemberKind::Empty
164 : cir::RecordMemberKind::Data;
168 mlir::Type getUIntNType(uint64_t numBits) {
169 unsigned alignedBits = llvm::PowerOf2Ceil(numBits);
170 alignedBits = std::max(8u, alignedBits);
171 return cir::IntType::get(&cirGenTypes.getMLIRContext(), alignedBits,
175 mlir::Type getCharType() {
176 return cir::IntType::get(&cirGenTypes.getMLIRContext(),
177 astContext.getCharWidth(),
181 mlir::Type getByteArrayType(CharUnits numberOfChars) {
182 assert(!numberOfChars.
isZero() &&
"Empty byte arrays aren't allowed.");
183 mlir::Type
type = getCharType();
190 mlir::Type getStorageType(
const CXXRecordDecl *RD) {
191 return cirGenTypes.getCIRGenRecordLayout(RD).getBaseSubobjectCIRType();
196 mlir::Type getBitfieldStorageType(
unsigned numBits) {
197 unsigned alignedBits = llvm::alignTo(numBits, astContext.getCharWidth());
199 return builder.getUIntNTy(alignedBits);
201 mlir::Type
type = getCharType();
202 return cir::ArrayType::get(
type, alignedBits / astContext.getCharWidth());
205 mlir::Type getStorageType(
const FieldDecl *
fieldDecl) {
206 mlir::Type
type = cirGenTypes.convertTypeForMem(
fieldDecl->getType());
208 cirGenTypes.getCGModule().errorNYI(recordDecl->getSourceRange(),
209 "getStorageType for bitfields");
215 return astRecordLayout.getFieldOffset(
fieldDecl->getFieldIndex());
219 void fillOutputFields();
221 void appendPaddingBytes(CharUnits size) {
224 mlir::Type padTy = getByteArrayType(size);
225 if (recordDecl->isUnion()) {
226 assert(!unionPadding &&
"at most one union tail-padding type");
227 unionPadding = padTy;
229 addField(padTy, cir::RecordMemberKind::Pad);
233 void addField(mlir::Type ty, cir::RecordMemberKind memberKind) {
234 fieldTypes.push_back(ty);
235 fieldKinds.push_back(memberKind);
243 llvm::ArrayRef<mlir::Type> getFieldTypes()
const {
return fieldTypes; }
244 llvm::ArrayRef<cir::RecordMemberKind> getFieldKinds()
const {
248 CIRGenTypes &cirGenTypes;
249 CIRGenBuilderTy &builder;
250 const ASTContext &astContext;
251 const RecordDecl *recordDecl;
252 const CXXRecordDecl *cxxRecordDecl;
253 const ASTRecordLayout &astRecordLayout;
255 std::vector<MemberInfo> members;
256 mlir::Type unionPadding;
257 llvm::DenseMap<const FieldDecl *, CIRGenBitFieldInfo> bitFields;
258 llvm::DenseMap<const FieldDecl *, unsigned> fieldIdxMap;
259 llvm::DenseMap<const CXXRecordDecl *, unsigned> nonVirtualBases;
260 llvm::DenseMap<const CXXRecordDecl *, unsigned> virtualBases;
261 cir::CIRDataLayout dataLayout;
263 LLVM_PREFERRED_TYPE(
bool)
264 unsigned zeroInitializable : 1;
265 LLVM_PREFERRED_TYPE(
bool)
266 unsigned zeroInitializableAsBase : 1;
267 LLVM_PREFERRED_TYPE(
bool)
274 llvm::SmallVector<mlir::Type, 16> fieldTypes;
275 llvm::SmallVector<cir::RecordMemberKind> fieldKinds;
277 CIRRecordLowering(
const CIRRecordLowering &) =
delete;
278 void operator=(
const CIRRecordLowering &) =
delete;
282CIRRecordLowering::CIRRecordLowering(
CIRGenTypes &cirGenTypes,
284 : cirGenTypes{cirGenTypes}, builder{cirGenTypes.getBuilder()},
288 cirGenTypes.getASTContext().getASTRecordLayout(
recordDecl)},
289 dataLayout{cirGenTypes.getCGModule().getModule()},
290 zeroInitializable{
true}, zeroInitializableAsBase{
true}, packed{packed} {}
292void CIRRecordLowering::setBitFieldInfo(
const FieldDecl *fd,
294 mlir::Type storageType) {
298 (unsigned)(getFieldBitOffset(fd) - astContext.
toBits(startOffset));
300 info.storageSize = getSizeInBits(storageType).getQuantity();
301 info.storageOffset = startOffset;
302 info.storageType = storageType;
314 info.volatileStorageSize = 0;
315 info.volatileOffset = 0;
319void CIRRecordLowering::lower(
bool nonVirtualBaseType) {
321 lowerUnion(nonVirtualBaseType);
322 computeVolatileBitfields();
329 accumulateFields(nonVirtualBaseType);
334 if (members.empty()) {
335 appendPaddingBytes(size);
336 computeVolatileBitfields();
339 if (!nonVirtualBaseType)
343 llvm::stable_sort(members);
350 makeStorageInfo(size, getUIntNType(8), cir::RecordMemberKind::Data));
351 determinePacked(nonVirtualBaseType);
357 computeVolatileBitfields();
360void CIRRecordLowering::fillOutputFields() {
361 for (
const MemberInfo &member : members) {
364 if (
member.kind == MemberInfo::InfoKind::Field) {
366 fieldIdxMap[
member.fieldDecl->getCanonicalDecl()] =
367 fieldTypes.size() - 1;
370 assert(
member.fieldDecl &&
371 "member.data is a nullptr so member.fieldDecl should not be");
372 setBitFieldInfo(
member.fieldDecl,
member.offset, fieldTypes.back());
374 }
else if (
member.kind == MemberInfo::InfoKind::Base) {
375 nonVirtualBases[
member.cxxRecordDecl] = fieldTypes.size() - 1;
376 }
else if (
member.kind == MemberInfo::InfoKind::VBase) {
377 virtualBases[
member.cxxRecordDecl] = fieldTypes.size() - 1;
385 if (isDiscreteBitFieldABI()) {
398 size_t storageIdx = 0;
399 for (; field != fieldEnd && field->isBitField(); ++field) {
401 if (field->isZeroLengthBitField()) {
405 uint64_t bitOffset = getFieldBitOffset(*field);
409 if (run == fieldEnd || bitOffset >= tail) {
411 startBitOffset = bitOffset;
418 storageIdx = members.size();
419 members.push_back(makeStorageInfo(bitsToCharUnits(startBitOffset),
type,
420 cir::RecordMemberKind::Empty));
422 assert(members[storageIdx].offset == bitsToCharUnits(startBitOffset) &&
423 "storageIdx must name the current run's storage");
424 if (!field->isUnnamedBitField())
425 members[storageIdx].memberKind = cir::RecordMemberKind::Data;
428 members.push_back(MemberInfo(bitsToCharUnits(startBitOffset),
429 MemberInfo::InfoKind::Field,
nullptr,
430 cir::RecordMemberKind::Data, *field));
446 CharUnits beginOffset;
455 CharUnits bestEndOffset;
463 bool atAlignedBoundary =
false;
465 if (field != fieldEnd && field->isBitField()) {
466 uint64_t bitOffset = getFieldBitOffset(*field);
467 if (begin == fieldEnd) {
472 assert((bitOffset % charBits) == 0 &&
"Not at start of char");
473 beginOffset = bitsToCharUnits(bitOffset);
474 bitSizeSinceBegin = 0;
475 }
else if ((bitOffset % charBits) != 0) {
483 astContext.
toBits(beginOffset) + bitSizeSinceBegin &&
484 "Concatenating non-contiguous bitfields");
489 if (field->isZeroLengthBitField())
491 atAlignedBoundary =
true;
496 if (begin == fieldEnd)
500 atAlignedBoundary =
true;
506 bool installBest =
false;
507 if (atAlignedBoundary) {
513 CharUnits accessSize = bitsToCharUnits(bitSizeSinceBegin + charBits - 1);
514 if (bestEnd == begin) {
518 bestEndOffset = beginOffset + accessSize;
521 if (!bitSizeSinceBegin)
525 }
else if (accessSize > regSize) {
534 mlir::Type
type = getUIntNType(astContext.
toBits(accessSize));
537 field->getSourceRange(),
"NYI CheapUnalignedBitFieldAccess");
544 CharUnits limitOffset;
545 for (
auto probe = field; probe != fieldEnd; ++probe)
548 assert((getFieldBitOffset(*probe) % charBits) == 0 &&
549 "Next storage is not byte-aligned");
550 limitOffset = bitsToCharUnits(getFieldBitOffset(*probe));
557 CharUnits typeSize = getSize(
type);
558 if (beginOffset + typeSize <= limitOffset) {
561 bestEndOffset = beginOffset + typeSize;
570 .FineGrainedBitfieldAccesses) {
576 bitSizeSinceBegin = astContext.
toBits(limitOffset - beginOffset);
583 assert((field == fieldEnd || !field->isBitField() ||
584 (getFieldBitOffset(*field) % charBits) == 0) &&
585 "Installing but not at an aligned bitfield or limit");
586 CharUnits accessSize = bestEndOffset - beginOffset;
587 if (!accessSize.
isZero()) {
593 assert(getSize(getUIntNType(astContext.
toBits(accessSize))) >
595 "Clipped access need not be clipped");
596 type = getByteArrayType(accessSize);
598 type = getUIntNType(astContext.
toBits(accessSize));
599 assert(getSize(
type) == accessSize &&
600 "Unclipped access must be clipped");
605 const size_t storageIdx = members.size();
607 makeStorageInfo(beginOffset,
type, cir::RecordMemberKind::Empty));
608 for (; begin != bestEnd; ++begin) {
609 if (!begin->isUnnamedBitField())
610 members[storageIdx].memberKind = cir::RecordMemberKind::Data;
611 if (!begin->isZeroLengthBitField())
612 members.push_back(MemberInfo(beginOffset,
613 MemberInfo::InfoKind::Field,
nullptr,
614 cir::RecordMemberKind::Data, *begin));
621 assert(field != fieldEnd && field->isBitField() &&
622 "Accumulating past end of bitfields");
623 assert(!
barrier &&
"Accumulating across barrier");
625 bitSizeSinceBegin += field->getBitWidthValue();
633void CIRRecordLowering::accumulateFields(
bool nonVirtualBaseType) {
636 field != fieldEnd;) {
637 if (field->isBitField()) {
638 field = accumulateBitFields(field, fieldEnd);
639 assert((field == fieldEnd || !field->isBitField()) &&
640 "Failed to accumulate all the bitfields");
642 field->isPotentiallyOverlapping()) {
662 field->getSourceRange(),
663 "[[no_unique_address]] field that is empty for layout but holds "
672 members.push_back(MemberInfo(
673 bitsToCharUnits(getFieldBitOffset(*field)),
674 MemberInfo::InfoKind::Field,
675 field->isPotentiallyOverlapping()
676 ? getStorageType(field->getType()->getAsCXXRecordDecl())
677 : getStorageType(*field),
678 getFieldMemberKind(*field), *field));
684void CIRRecordLowering::calculateZeroInit() {
685 for (
const MemberInfo &member : members) {
686 if (
member.kind == MemberInfo::InfoKind::Field) {
687 if (!
member.fieldDecl || isZeroInitializable(
member.fieldDecl))
689 zeroInitializable = zeroInitializableAsBase =
false;
691 }
else if (
member.kind == MemberInfo::InfoKind::Base ||
692 member.kind == MemberInfo::InfoKind::VBase) {
693 if (isZeroInitializable(
member.cxxRecordDecl))
695 zeroInitializable =
false;
696 if (
member.kind == MemberInfo::InfoKind::Base)
697 zeroInitializableAsBase =
false;
702void CIRRecordLowering::determinePacked(
bool nvBaseType) {
711 for (
const MemberInfo &member : members) {
716 if (!
member.offset.isMultipleOf(getAlignment(
member.data)))
718 if (
member.offset < nvSize)
719 nvAlignment = std::max(nvAlignment, getAlignment(
member.data));
720 alignment = std::max(alignment, getAlignment(
member.data));
724 if (!members.back().offset.isMultipleOf(alignment))
733 members.back().data = getUIntNType(astContext.
toBits(alignment));
736void CIRRecordLowering::insertPadding() {
737 std::vector<std::pair<CharUnits, CharUnits>> padding;
739 for (
const MemberInfo &member : members) {
742 CharUnits offset =
member.offset;
743 assert(offset >= size);
747 padding.push_back(std::make_pair(size, offset - size));
748 size = offset + getSize(
member.data);
753 for (
const std::pair<CharUnits, CharUnits> &paddingPair : padding)
754 members.push_back(makeStorageInfo(paddingPair.first,
755 getByteArrayType(paddingPair.second),
756 cir::RecordMemberKind::Pad));
757 llvm::stable_sort(members);
760static cir::ArgPassingKind
764 return cir::ArgPassingKind::CanPassInRegs;
766 return cir::ArgPassingKind::CannotPassInRegs;
768 return cir::ArgPassingKind::CanNeverPassInRegs;
770 llvm_unreachable(
"unknown RecordArgPassingKind");
775[[maybe_unused]]
static bool
782std::unique_ptr<CIRGenRecordLayout>
784 CIRRecordLowering lowering(*
this, rd,
false);
785 assert(ty->
isIncomplete() &&
"recomputing record layout?");
786 lowering.lower(
false);
798 if (llvm::isa<CXXRecordDecl>(rd)) {
807 lowering.astRecordLayout.
getSize()) {
808 CIRRecordLowering baseLowering(*
this, rd, lowering.packed);
809 baseLowering.lower(
true);
811 baseTy = builder.getCompleteNamedRecordType(
812 baseLowering.getFieldTypes(), baseLowering.packed, baseIdentifier,
813 baseLowering.getFieldKinds());
822 assert((rd->
isUnion() || lowering.packed == baseLowering.packed) &&
823 "Non-virtual and complete types must agree on packedness");
828 cgm.getDiags().hasErrorOccurred()) &&
829 "base subobject member kinds must reproduce its ABI emptiness");
837 ty->
complete(lowering.getFieldTypes(), lowering.packed, lowering.unionPadding,
838 lowering.getFieldKinds());
845 cgm.getDiags().hasErrorOccurred()) &&
846 "member kinds must reproduce the ABI emptiness of the record");
850 mlir::MLIRContext *mlirCtx = ty->getContext();
851 cir::ArgPassingKind apk =
854 bool hasTrivialDestructor =
true;
855 if (
auto *cxxRD = dyn_cast<CXXRecordDecl>(rd))
856 hasTrivialDestructor = cxxRD->hasTrivialDestructor();
857 const auto &astLayout = astContext.getASTRecordLayout(rd);
858 uint64_t recordAlignInBytes = astLayout.getAlignment().getQuantity();
860 cgm.addRecordLayout(ty->
getName(), cir::RecordLayoutAttr::get(
861 mlirCtx, apk, hasTrivialDestructor,
862 recordAlignInBytes));
865 auto rl = std::make_unique<CIRGenRecordLayout>(
867 (bool)lowering.zeroInitializable, (bool)lowering.zeroInitializableAsBase);
869 rl->nonVirtualBases.swap(lowering.nonVirtualBases);
870 rl->completeObjectVirtualBases.swap(lowering.virtualBases);
873 rl->fieldIdxMap.swap(lowering.fieldIdxMap);
875 rl->bitFields.swap(lowering.bitFields);
879 llvm::outs() <<
"\n*** Dumping CIRgen Record Layout\n";
880 llvm::outs() <<
"Record: ";
881 rd->
dump(llvm::outs());
882 llvm::outs() <<
"\nLayout: ";
883 rl->print(llvm::outs());
891 os <<
"<CIRecordLayout\n";
892 os <<
" CIR Type:" << completeObjectType <<
"\n";
893 if (baseSubobjectType)
894 os <<
" NonVirtualBaseCIRType:" << baseSubobjectType <<
"\n";
895 os <<
" IsZeroInitializable:" << zeroInitializable <<
"\n";
896 os <<
" BitFields:[\n";
897 std::vector<std::pair<unsigned, const CIRGenBitFieldInfo *>> bitInfo;
898 for (
auto &[
decl, info] : bitFields) {
903 bitInfo.push_back(std::make_pair(
index, &info));
905 llvm::array_pod_sort(bitInfo.begin(), bitInfo.end());
906 for (std::pair<unsigned, const CIRGenBitFieldInfo *> &info : bitInfo) {
908 info.second->print(os);
915 os <<
"<CIRBitFieldInfo" <<
" name:" <<
name <<
" offset:" <<
offset
928void CIRRecordLowering::lowerUnion(
bool nonVirtualBaseType) {
940 mlir::Type fieldType;
941 if (field->isBitField()) {
942 if (field->isZeroLengthBitField())
944 fieldType = getBitfieldStorageType(field->getBitWidthValue());
947 fieldType = getStorageType(field);
950 fieldIdxMap[field->getCanonicalDecl()] = 0;
952 ? cir::RecordMemberKind::Empty
953 : cir::RecordMemberKind::Data);
961 auto hasNamedMember = [](
const FieldDecl *curField) ->
bool {
962 const auto *rd = curField->getType()->getAsRecordDecl();
968 auto isNamedMember = [hasNamedMember](
const FieldDecl *curField) ->
bool {
969 if (curField->isZeroLengthBitField())
971 return curField->getIdentifier() || hasNamedMember(curField);
973 auto firstNamedMemberItr = llvm::find_if(
recordDecl->fields(), isNamedMember);
975 if (firstNamedMemberItr !=
recordDecl->fields().end() &&
976 !isZeroInitializable(*firstNamedMemberItr))
977 zeroInitializable = zeroInitializableAsBase =
false;
980 if (getFieldTypes().empty()) {
981 appendPaddingBytes(layoutSize);
985 mlir::Type storageType =
986 cir::UnionType::getUnionStorageType(dataLayout.
layout, getFieldTypes());
990 if (layoutSize < getSize(storageType))
991 storageType = getByteArrayType(layoutSize);
996 if (nonVirtualBaseType) {
999 const cir::RecordMemberKind storageKind =
1000 llvm::is_contained(getFieldKinds(), cir::RecordMemberKind::Data)
1001 ? cir::RecordMemberKind::Data
1002 : cir::RecordMemberKind::Empty;
1004 addField(storageType, storageKind);
1005 CharUnits padding = layoutSize - getSize(storageType);
1007 addField(getByteArrayType(padding), cir::RecordMemberKind::Pad);
1010 appendPaddingBytes(layoutSize - getSize(storageType));
1012 packed = !layoutSize.
isMultipleOf(getAlignment(storageType));
1015bool CIRRecordLowering::hasOwnStorage(
const CXXRecordDecl *
decl,
1016 const CXXRecordDecl *query) {
1020 for (
const auto &base :
decl->bases())
1021 if (!hasOwnStorage(base.getType()->getAsCXXRecordDecl(), query))
1039void CIRRecordLowering::computeVolatileBitfields() {
1044 for (
auto &[field, info] : bitFields) {
1048 getSizeInBits(resLTy).getQuantity())
1056 const unsigned oldOffset =
1057 isBigEndian() ?
info.storageSize - (
info.offset +
info.size)
1060 const unsigned absoluteOffset =
1061 astContext.
toBits(
info.storageOffset) + oldOffset;
1064 const unsigned storageSize = getSizeInBits(resLTy).getQuantity();
1067 if (
info.storageSize == storageSize && (oldOffset % storageSize == 0))
1071 unsigned offset = absoluteOffset & (storageSize - 1);
1076 if (offset +
info.size > storageSize)
1081 offset = storageSize - (offset +
info.size);
1083 const CharUnits storageOffset =
1085 const CharUnits end = storageOffset +
1089 const ASTRecordLayout &layout =
1092 const CharUnits recordSize = layout.
getSize();
1093 if (end >= recordSize)
1097 bool conflict =
false;
1100 if (f->isBitField() && !f->isZeroLengthBitField())
1110 if (f->isZeroLengthBitField()) {
1111 if (end > fOffset && storageOffset < fOffset) {
1117 const CharUnits fEnd =
1124 if (end < fOffset || fEnd < storageOffset)
1137 info.volatileStorageOffset =
1140 info.volatileStorageSize = storageSize;
1141 info.volatileOffset = offset;
1145void CIRRecordLowering::accumulateBases() {
1148 const CXXRecordDecl *baseDecl = astRecordLayout.
getPrimaryBase();
1149 members.push_back(MemberInfo(
CharUnits::Zero(), MemberInfo::InfoKind::Base,
1150 getStorageType(baseDecl),
1151 getBaseMemberKind(baseDecl), baseDecl));
1156 if (base.isVirtual())
1160 const CXXRecordDecl *baseDecl = base.getType()->getAsCXXRecordDecl();
1164 MemberInfo::InfoKind::Base,
1165 getStorageType(baseDecl),
1166 getBaseMemberKind(baseDecl), baseDecl));
1171void CIRRecordLowering::accumulateVBases() {
1173 const CXXRecordDecl *baseDecl = base.getType()->getAsCXXRecordDecl();
1179 if (isOverlappingVBaseABI() && astContext.
isNearlyEmpty(baseDecl) &&
1181 members.push_back(MemberInfo(offset, MemberInfo::InfoKind::VBase,
nullptr,
1182 cir::RecordMemberKind::Data, baseDecl));
1188 ->second.hasVtorDisp())
1191 cir::RecordMemberKind::Data));
1192 members.push_back(MemberInfo(offset, MemberInfo::InfoKind::VBase,
1193 getStorageType(baseDecl),
1194 getBaseMemberKind(baseDecl), baseDecl));
1198void CIRRecordLowering::accumulateVPtrs() {
1200 members.push_back(MemberInfo(
CharUnits::Zero(), MemberInfo::InfoKind::VFPtr,
1201 getVFPtrType(), cir::RecordMemberKind::Data));
1205 "accumulateVPtrs: hasOwnVBPtr");
1208mlir::Type CIRRecordLowering::getVFPtrType() {
1209 return cir::VPtrType::get(builder.getContext());
Defines the clang::ASTContext interface.
static bool isAAPCS(const TargetInfo &targetInfo)
Helper method to check if the underlying ABI is AAPCS.
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.
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.
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...
bool isValidFundamentalIntWidth(unsigned width)
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 an unnamed 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...
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.
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.