24#include "llvm/Support/Casting.h"
37struct CIRRecordLowering final {
42 struct MemberInfo final {
50 MemberInfo(
CharUnits offset, InfoKind kind, mlir::Type data,
53 MemberInfo(
CharUnits offset, InfoKind kind, mlir::Type data,
57 bool operator<(
const MemberInfo &other)
const {
58 return offset < other.offset;
66 MemberInfo makeStorageInfo(
CharUnits offset, mlir::Type data) {
67 return MemberInfo(offset, MemberInfo::InfoKind::Field, data);
72 mlir::Type storageType);
74 void lower(
bool NonVirtualBaseType);
78 void determinePacked(
bool nvBaseType);
82 void computeVolatileBitfields();
83 void accumulateBases();
84 void accumulateVPtrs();
85 void accumulateVBases();
86 void accumulateFields();
91 mlir::Type getVFPtrType();
94 return astContext.getTargetInfo().getABI().starts_with(
"aapcs");
98 bool isBigEndian()
const {
return astContext.getTargetInfo().isBigEndian(); }
104 bool isOverlappingVBaseABI() {
105 return !astContext.getTargetInfo().getCXXABI().isMicrosoft();
111 CharUnits bitsToCharUnits(uint64_t bitOffset) {
112 return astContext.toCharUnitsFromBits(bitOffset);
115 void calculateZeroInit();
127 bool isZeroInitializable(
const FieldDecl *fd) {
128 return cirGenTypes.isZeroInitializable(fd->
getType());
130 bool isZeroInitializable(
const RecordDecl *rd) {
131 return cirGenTypes.isZeroInitializable(rd);
135 mlir::Type getUIntNType(uint64_t numBits) {
136 unsigned alignedBits = llvm::PowerOf2Ceil(numBits);
137 alignedBits = std::max(8u, alignedBits);
138 return cir::IntType::get(&cirGenTypes.getMLIRContext(), alignedBits,
142 mlir::Type getCharType() {
143 return cir::IntType::get(&cirGenTypes.getMLIRContext(),
144 astContext.getCharWidth(),
148 mlir::Type getByteArrayType(
CharUnits numberOfChars) {
149 assert(!numberOfChars.
isZero() &&
"Empty byte arrays aren't allowed.");
150 mlir::Type
type = getCharType();
158 return cirGenTypes.getCIRGenRecordLayout(RD).getBaseSubobjectCIRType();
163 mlir::Type getBitfieldStorageType(
unsigned numBits) {
164 unsigned alignedBits = llvm::alignTo(numBits, astContext.getCharWidth());
166 return builder.getUIntNTy(alignedBits);
168 mlir::Type
type = getCharType();
169 return cir::ArrayType::get(
type, alignedBits / astContext.getCharWidth());
173 mlir::Type
type = cirGenTypes.convertTypeForMem(
fieldDecl->getType());
175 cirGenTypes.getCGModule().errorNYI(
recordDecl->getSourceRange(),
176 "getStorageType for bitfields");
182 return astRecordLayout.getFieldOffset(
fieldDecl->getFieldIndex());
186 void fillOutputFields();
188 void appendPaddingBytes(
CharUnits size) {
190 fieldTypes.push_back(getByteArrayType(size));
202 std::vector<MemberInfo> members;
205 llvm::DenseMap<const FieldDecl *, CIRGenBitFieldInfo> bitFields;
206 llvm::DenseMap<const FieldDecl *, unsigned> fieldIdxMap;
207 llvm::DenseMap<const CXXRecordDecl *, unsigned> nonVirtualBases;
208 llvm::DenseMap<const CXXRecordDecl *, unsigned> virtualBases;
211 LLVM_PREFERRED_TYPE(
bool)
212 unsigned zeroInitializable : 1;
213 LLVM_PREFERRED_TYPE(
bool)
214 unsigned zeroInitializableAsBase : 1;
215 LLVM_PREFERRED_TYPE(
bool)
217 LLVM_PREFERRED_TYPE(
bool)
221 CIRRecordLowering(
const CIRRecordLowering &) =
delete;
222 void operator=(
const CIRRecordLowering &) =
delete;
226CIRRecordLowering::CIRRecordLowering(
CIRGenTypes &cirGenTypes,
228 : cirGenTypes{cirGenTypes}, builder{cirGenTypes.getBuilder()},
232 cirGenTypes.getASTContext().getASTRecordLayout(
recordDecl)},
233 dataLayout{cirGenTypes.getCGModule().getModule()},
234 zeroInitializable{
true}, zeroInitializableAsBase{
true}, packed{packed},
237void CIRRecordLowering::setBitFieldInfo(
const FieldDecl *fd,
239 mlir::Type storageType) {
243 (
unsigned)(getFieldBitOffset(fd) - astContext.toBits(startOffset));
245 info.
storageSize = getSizeInBits(storageType).getQuantity();
256 if (dataLayout.isBigEndian())
264void CIRRecordLowering::lower(
bool nonVirtualBaseType) {
267 computeVolatileBitfields();
271 CharUnits size = nonVirtualBaseType ? astRecordLayout.getNonVirtualSize()
272 : astRecordLayout.getSize();
279 if (members.empty()) {
280 appendPaddingBytes(size);
281 computeVolatileBitfields();
284 if (!nonVirtualBaseType)
288 llvm::stable_sort(members);
293 members.push_back(makeStorageInfo(size, getUIntNType(8)));
294 determinePacked(nonVirtualBaseType);
300 computeVolatileBitfields();
303void CIRRecordLowering::fillOutputFields() {
304 for (
const MemberInfo &member : members) {
306 fieldTypes.push_back(
member.data);
307 if (
member.kind == MemberInfo::InfoKind::Field) {
309 fieldIdxMap[
member.fieldDecl->getCanonicalDecl()] =
310 fieldTypes.size() - 1;
314 setBitFieldInfo(
member.fieldDecl,
member.offset, fieldTypes.back());
315 }
else if (
member.kind == MemberInfo::InfoKind::Base) {
316 nonVirtualBases[
member.cxxRecordDecl] = fieldTypes.size() - 1;
317 }
else if (
member.kind == MemberInfo::InfoKind::VBase) {
318 virtualBases[
member.cxxRecordDecl] = fieldTypes.size() - 1;
329 bitsToCharUnits(astContext.getTargetInfo().getRegisterWidth());
330 unsigned charBits = astContext.getCharWidth();
356 bool atAlignedBoundary =
false;
358 if (field != fieldEnd && field->isBitField()) {
359 uint64_t bitOffset = getFieldBitOffset(*field);
360 if (begin == fieldEnd) {
365 assert((bitOffset % charBits) == 0 &&
"Not at start of char");
366 beginOffset = bitsToCharUnits(bitOffset);
367 bitSizeSinceBegin = 0;
368 }
else if ((bitOffset % charBits) != 0) {
376 astContext.toBits(beginOffset) + bitSizeSinceBegin &&
377 "Concatenating non-contiguous bitfields");
382 if (field->isZeroLengthBitField())
384 atAlignedBoundary =
true;
389 if (begin == fieldEnd)
393 atAlignedBoundary =
true;
399 bool installBest =
false;
400 if (atAlignedBoundary) {
406 CharUnits accessSize = bitsToCharUnits(bitSizeSinceBegin + charBits - 1);
407 if (bestEnd == begin) {
411 bestEndOffset = beginOffset + accessSize;
414 if (!bitSizeSinceBegin)
418 }
else if (accessSize > regSize) {
427 mlir::Type
type = getUIntNType(astContext.toBits(accessSize));
428 if (!astContext.getTargetInfo().hasCheapUnalignedBitFieldAccess())
429 cirGenTypes.getCGModule().errorNYI(
430 field->getSourceRange(),
"NYI CheapUnalignedBitFieldAccess");
438 for (
auto probe = field; probe != fieldEnd; ++probe)
441 assert((getFieldBitOffset(*probe) % charBits) == 0 &&
442 "Next storage is not byte-aligned");
443 limitOffset = bitsToCharUnits(getFieldBitOffset(*probe));
446 limitOffset =
cxxRecordDecl ? astRecordLayout.getNonVirtualSize()
447 : astRecordLayout.getDataSize();
451 if (beginOffset + typeSize <= limitOffset) {
454 bestEndOffset = beginOffset + typeSize;
461 }
else if (cirGenTypes.getCGModule()
463 .FineGrainedBitfieldAccesses) {
469 bitSizeSinceBegin = astContext.toBits(limitOffset - beginOffset);
476 assert((field == fieldEnd || !field->isBitField() ||
477 (getFieldBitOffset(*field) % charBits) == 0) &&
478 "Installing but not at an aligned bitfield or limit");
479 CharUnits accessSize = bestEndOffset - beginOffset;
480 if (!accessSize.
isZero()) {
486 assert(getSize(getUIntNType(astContext.toBits(accessSize))) >
488 "Clipped access need not be clipped");
489 type = getByteArrayType(accessSize);
491 type = getUIntNType(astContext.toBits(accessSize));
492 assert(getSize(
type) == accessSize &&
493 "Unclipped access must be clipped");
495 members.push_back(makeStorageInfo(beginOffset,
type));
496 for (; begin != bestEnd; ++begin)
497 if (!begin->isZeroLengthBitField())
498 members.push_back(MemberInfo(
499 beginOffset, MemberInfo::InfoKind::Field,
nullptr, *begin));
505 assert(field != fieldEnd && field->isBitField() &&
506 "Accumulating past end of bitfields");
507 assert(!
barrier &&
"Accumulating across barrier");
509 bitSizeSinceBegin += field->getBitWidthValue();
517void CIRRecordLowering::accumulateFields() {
520 field != fieldEnd;) {
521 if (field->isBitField()) {
522 field = accumulateBitFields(field, fieldEnd);
523 assert((field == fieldEnd || !field->isBitField()) &&
524 "Failed to accumulate all the bitfields");
525 }
else if (!field->isZeroSize(astContext)) {
526 members.push_back(MemberInfo(bitsToCharUnits(getFieldBitOffset(*field)),
527 MemberInfo::InfoKind::Field,
528 getStorageType(*field), *field));
538void CIRRecordLowering::calculateZeroInit() {
539 for (
const MemberInfo &member : members) {
540 if (
member.kind == MemberInfo::InfoKind::Field) {
541 if (!
member.fieldDecl || isZeroInitializable(
member.fieldDecl))
543 zeroInitializable = zeroInitializableAsBase =
false;
545 }
else if (
member.kind == MemberInfo::InfoKind::Base ||
546 member.kind == MemberInfo::InfoKind::VBase) {
547 if (isZeroInitializable(
member.cxxRecordDecl))
549 zeroInitializable =
false;
550 if (
member.kind == MemberInfo::InfoKind::Base)
551 zeroInitializableAsBase =
false;
556void CIRRecordLowering::determinePacked(
bool nvBaseType) {
562 ? astRecordLayout.getNonVirtualSize()
565 for (
const MemberInfo &member : members) {
572 if (
member.offset < nvSize)
573 nvAlignment = std::max(nvAlignment, getAlignment(
member.data));
574 alignment = std::max(alignment, getAlignment(
member.data));
578 if (members.back().offset % alignment)
583 if (nvSize % nvAlignment)
587 members.back().data = getUIntNType(astContext.toBits(alignment));
590void CIRRecordLowering::insertPadding() {
591 std::vector<std::pair<CharUnits, CharUnits>> padding;
593 for (
const MemberInfo &member : members) {
597 assert(offset >= size);
601 padding.push_back(std::make_pair(size, offset - size));
602 size = offset + getSize(
member.data);
608 for (
const std::pair<CharUnits, CharUnits> &paddingPair : padding)
609 members.push_back(makeStorageInfo(paddingPair.first,
610 getByteArrayType(paddingPair.second)));
611 llvm::stable_sort(members);
614std::unique_ptr<CIRGenRecordLayout>
616 CIRRecordLowering lowering(*
this, rd,
false);
617 assert(ty->isIncomplete() &&
"recomputing record layout?");
618 lowering.lower(
false);
621 cir::RecordType baseTy;
622 if (llvm::isa<CXXRecordDecl>(rd) && !rd->
isUnion() &&
625 if (lowering.astRecordLayout.getNonVirtualSize() !=
626 lowering.astRecordLayout.getSize()) {
627 CIRRecordLowering baseLowering(*
this, rd, lowering.packed);
628 baseLowering.lower(
true);
632 baseLowering.packed, baseLowering.padded);
637 assert(lowering.packed == baseLowering.packed &&
638 "Non-virtual and complete types must agree on packedness");
646 ty->complete(lowering.fieldTypes, lowering.packed, lowering.padded);
648 auto rl = std::make_unique<CIRGenRecordLayout>(
649 ty ? *ty : cir::RecordType{}, baseTy ? baseTy : cir::RecordType{},
650 (
bool)lowering.zeroInitializable, (
bool)lowering.zeroInitializableAsBase);
654 rl->nonVirtualBases.swap(lowering.nonVirtualBases);
655 rl->completeObjectVirtualBases.swap(lowering.virtualBases);
660 rl->fieldIdxMap.swap(lowering.fieldIdxMap);
662 rl->bitFields.swap(lowering.bitFields);
666 llvm::outs() <<
"\n*** Dumping CIRgen Record Layout\n";
667 llvm::outs() <<
"Record: ";
668 rd->
dump(llvm::outs());
669 llvm::outs() <<
"\nLayout: ";
670 rl->print(llvm::outs());
678 os <<
"<CIRecordLayout\n";
679 os <<
" CIR Type:" << completeObjectType <<
"\n";
680 if (baseSubobjectType)
681 os <<
" NonVirtualBaseCIRType:" << baseSubobjectType <<
"\n";
682 os <<
" IsZeroInitializable:" << zeroInitializable <<
"\n";
683 os <<
" BitFields:[\n";
684 std::vector<std::pair<unsigned, const CIRGenBitFieldInfo *>> bitInfo;
685 for (
auto &[
decl, info] : bitFields) {
690 bitInfo.push_back(std::make_pair(index, &info));
692 llvm::array_pod_sort(bitInfo.begin(), bitInfo.end());
693 for (std::pair<unsigned, const CIRGenBitFieldInfo *> &info : bitInfo) {
695 info.second->
print(os);
702 os <<
"<CIRBitFieldInfo" <<
" name:" <<
name <<
" offset:" <<
offset
715void CIRRecordLowering::lowerUnion() {
716 CharUnits layoutSize = astRecordLayout.getSize();
717 mlir::Type storageType =
nullptr;
718 bool seenNamedMember =
false;
723 mlir::Type fieldType;
724 if (field->isBitField()) {
725 if (field->isZeroLengthBitField())
727 fieldType = getBitfieldStorageType(field->getBitWidthValue());
730 fieldType = getStorageType(field);
734 fieldIdxMap[field->getCanonicalDecl()] = 0;
742 if (!seenNamedMember) {
743 seenNamedMember = field->getIdentifier();
744 if (!seenNamedMember)
745 if (
const RecordDecl *fieldRD = field->getType()->getAsRecordDecl())
746 seenNamedMember = fieldRD->findFirstNamedDataMember();
747 if (seenNamedMember && !isZeroInitializable(field)) {
748 zeroInitializable = zeroInitializableAsBase =
false;
749 storageType = fieldType;
755 if (!zeroInitializable)
759 if (!storageType || getAlignment(fieldType) > getAlignment(storageType) ||
760 (getAlignment(fieldType) == getAlignment(storageType) &&
761 getSize(fieldType) > getSize(storageType)))
762 storageType = fieldType;
766 fieldTypes.push_back(fieldType);
770 cirGenTypes.getCGModule().errorNYI(
recordDecl->getSourceRange(),
771 "No-storage Union NYI");
773 if (layoutSize < getSize(storageType))
774 storageType = getByteArrayType(layoutSize);
776 appendPaddingBytes(layoutSize - getSize(storageType));
779 if (layoutSize % getAlignment(storageType))
788 for (
const auto &base :
decl->bases())
789 if (!hasOwnStorage(base.getType()->getAsCXXRecordDecl(), query))
807void CIRRecordLowering::computeVolatileBitfields() {
809 !cirGenTypes.getCGModule().getCodeGenOpts().AAPCSBitfieldWidth)
812 for (
auto &[field, info] : bitFields) {
813 mlir::Type resLTy = cirGenTypes.convertTypeForMem(field->getType());
815 if (astContext.toBits(astRecordLayout.getAlignment()) <
816 getSizeInBits(resLTy).getQuantity())
824 const unsigned oldOffset =
828 const unsigned absoluteOffset =
832 const unsigned storageSize = getSizeInBits(resLTy).getQuantity();
835 if (info.
storageSize == storageSize && (oldOffset % storageSize == 0))
839 unsigned offset = absoluteOffset & (storageSize - 1);
844 if (offset + info.
size > storageSize)
849 offset = storageSize - (offset + info.
size);
852 astContext.toCharUnitsFromBits(absoluteOffset & ~(storageSize - 1));
854 astContext.toCharUnitsFromBits(storageSize) -
858 astContext.getASTRecordLayout(field->getParent());
861 if (end >= recordSize)
865 bool conflict =
false;
868 if (f->isBitField() && !f->isZeroLengthBitField())
871 const CharUnits fOffset = astContext.toCharUnitsFromBits(
878 if (f->isZeroLengthBitField()) {
879 if (end > fOffset && storageOffset < fOffset) {
887 astContext.toCharUnitsFromBits(
888 getSizeInBits(cirGenTypes.convertTypeForMem(f->getType()))
892 if (end < fOffset || fEnd < storageOffset)
907 astContext.toCharUnitsFromBits(storageSize).
getQuantity();
913void CIRRecordLowering::accumulateBases() {
915 if (astRecordLayout.isPrimaryBaseVirtual()) {
916 cirGenTypes.getCGModule().errorNYI(
recordDecl->getSourceRange(),
917 "accumulateBases: primary virtual base");
922 if (base.isVirtual())
926 const CXXRecordDecl *baseDecl = base.getType()->getAsCXXRecordDecl();
928 !astContext.getASTRecordLayout(baseDecl).getNonVirtualSize().isZero()) {
929 members.push_back(MemberInfo(astRecordLayout.getBaseClassOffset(baseDecl),
930 MemberInfo::InfoKind::Base,
931 getStorageType(baseDecl), baseDecl));
936void CIRRecordLowering::accumulateVBases() {
938 const CXXRecordDecl *baseDecl = base.getType()->getAsCXXRecordDecl();
941 CharUnits offset = astRecordLayout.getVBaseClassOffset(baseDecl);
944 if (isOverlappingVBaseABI() && astContext.isNearlyEmpty(baseDecl) &&
947 MemberInfo(offset, MemberInfo::InfoKind::VBase,
nullptr, baseDecl));
951 if (astRecordLayout.getVBaseOffsetsMap()
953 ->second.hasVtorDisp())
956 members.push_back(MemberInfo(offset, MemberInfo::InfoKind::VBase,
957 getStorageType(baseDecl), baseDecl));
961void CIRRecordLowering::accumulateVPtrs() {
962 if (astRecordLayout.hasOwnVFPtr())
963 members.push_back(MemberInfo(
CharUnits::Zero(), MemberInfo::InfoKind::VFPtr,
966 if (astRecordLayout.hasOwnVBPtr())
967 cirGenTypes.getCGModule().errorNYI(
recordDecl->getSourceRange(),
968 "accumulateVPtrs: hasOwnVBPtr");
971mlir::Type CIRRecordLowering::getVFPtrType() {
972 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.
Defines the C++ Decl subclasses, other than those for templates (found in DeclTemplate....
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
ASTRecordLayout - This class contains layout information for one RecordDecl, which is a struct/union/...
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.
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.
cir::RecordType getCompleteRecordTy(llvm::ArrayRef< mlir::Type > members, llvm::StringRef name, bool packed, bool padded)
Get a CIR named record type.
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.
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)
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.
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.
specific_decl_iterator - Iterates over a subrange of declarations stored in a DeclContext,...
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.
specific_decl_iterator< FieldDecl > field_iterator
field_iterator field_begin() const
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 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.
unsigned kind
All of the diagnostics that can be emitted by the frontend.
The JSON file list parser is used to communicate input to InstallAPI.
bool operator<(DeclarationName LHS, DeclarationName RHS)
Ordering on two declaration names.
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 isDiscreteBitFieldABI()
static bool zeroSizeRecordMembers()
static bool astRecordDeclAttr()
static bool recordZeroInit()
Record with information about how a bitfield should be accessed.
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.