@@ -56,14 +56,15 @@ struct CIRRecordLowering final {
5656 };
5757 // The constructor.
5858 CIRRecordLowering (CIRGenTypes &cirGenTypes, const RecordDecl *recordDecl,
59- bool isPacked );
59+ bool packed );
6060
6161 // / Constructs a MemberInfo instance from an offset and mlir::Type.
6262 MemberInfo makeStorageInfo (CharUnits offset, mlir::Type data) {
6363 return MemberInfo (offset, MemberInfo::InfoKind::Field, data);
6464 }
6565
6666 void lower ();
67+ void lowerUnion ();
6768
6869 // / Determines if we need a packed llvm struct.
6970 void determinePacked ();
@@ -83,6 +84,10 @@ struct CIRRecordLowering final {
8384 return CharUnits::fromQuantity (dataLayout.layout .getTypeABIAlignment (Ty));
8485 }
8586
87+ bool isZeroInitializable (const FieldDecl *fd) {
88+ return cirGenTypes.isZeroInitializable (fd->getType ());
89+ }
90+
8691 // / Wraps cir::IntType with some implicit arguments.
8792 mlir::Type getUIntNType (uint64_t numBits) {
8893 unsigned alignedBits = llvm::PowerOf2Ceil (numBits);
@@ -121,6 +126,13 @@ struct CIRRecordLowering final {
121126 // / Fills out the structures that are ultimately consumed.
122127 void fillOutputFields ();
123128
129+ void appendPaddingBytes (CharUnits size) {
130+ if (!size.isZero ()) {
131+ fieldTypes.push_back (getByteArrayType (size));
132+ padded = true ;
133+ }
134+ }
135+
124136 CIRGenTypes &cirGenTypes;
125137 CIRGenBuilderTy &builder;
126138 const ASTContext &astContext;
@@ -130,12 +142,14 @@ struct CIRRecordLowering final {
130142 std::vector<MemberInfo> members;
131143 // Output fields, consumed by CIRGenTypes::computeRecordLayout
132144 llvm::SmallVector<mlir::Type, 16 > fieldTypes;
133- llvm::DenseMap<const FieldDecl *, unsigned > fields ;
145+ llvm::DenseMap<const FieldDecl *, unsigned > fieldIdxMap ;
134146 cir::CIRDataLayout dataLayout;
135147
136148 LLVM_PREFERRED_TYPE (bool )
137149 unsigned zeroInitializable : 1 ;
138150 LLVM_PREFERRED_TYPE (bool )
151+ unsigned zeroInitializableAsBase : 1 ;
152+ LLVM_PREFERRED_TYPE (bool )
139153 unsigned packed : 1 ;
140154 LLVM_PREFERRED_TYPE (bool )
141155 unsigned padded : 1 ;
@@ -147,19 +161,19 @@ struct CIRRecordLowering final {
147161} // namespace
148162
149163CIRRecordLowering::CIRRecordLowering (CIRGenTypes &cirGenTypes,
150- const RecordDecl *recordDecl,
151- bool isPacked)
164+ const RecordDecl *recordDecl, bool packed)
152165 : cirGenTypes(cirGenTypes), builder(cirGenTypes.getBuilder()),
153166 astContext(cirGenTypes.getASTContext()), recordDecl(recordDecl),
154167 astRecordLayout(
155168 cirGenTypes.getASTContext().getASTRecordLayout(recordDecl)),
156169 dataLayout(cirGenTypes.getCGModule().getModule()),
157- zeroInitializable(true ), packed(isPacked), padded(false ) {}
170+ zeroInitializable(true ), zeroInitializableAsBase(true ), packed(packed),
171+ padded(false ) {}
158172
159173void CIRRecordLowering::lower () {
160174 if (recordDecl->isUnion ()) {
161- cirGenTypes. getCGModule (). errorNYI (recordDecl-> getSourceRange (),
162- " lower: union " );
175+ lowerUnion ();
176+ assert (! cir::MissingFeatures::bitfields () );
163177 return ;
164178 }
165179
@@ -194,7 +208,8 @@ void CIRRecordLowering::fillOutputFields() {
194208 fieldTypes.push_back (member.data );
195209 if (member.kind == MemberInfo::InfoKind::Field) {
196210 if (member.fieldDecl )
197- fields[member.fieldDecl ->getCanonicalDecl ()] = fieldTypes.size () - 1 ;
211+ fieldIdxMap[member.fieldDecl ->getCanonicalDecl ()] =
212+ fieldTypes.size () - 1 ;
198213 // A field without storage must be a bitfield.
199214 assert (!cir::MissingFeatures::bitfields ());
200215 }
@@ -296,7 +311,7 @@ CIRGenTypes::computeRecordLayout(const RecordDecl *rd, cir::RecordType *ty) {
296311 assert (!cir::MissingFeatures::bitfields ());
297312
298313 // Add all the field numbers.
299- rl->fieldInfo .swap (lowering.fields );
314+ rl->fieldIdxMap .swap (lowering.fieldIdxMap );
300315
301316 // Dump the layout, if requested.
302317 if (getASTContext ().getLangOpts ().DumpRecordLayouts ) {
@@ -306,3 +321,68 @@ CIRGenTypes::computeRecordLayout(const RecordDecl *rd, cir::RecordType *ty) {
306321 // TODO: implement verification
307322 return rl;
308323}
324+
325+ void CIRRecordLowering::lowerUnion () {
326+ CharUnits layoutSize = astRecordLayout.getSize ();
327+ mlir::Type storageType = nullptr ;
328+ bool seenNamedMember = false ;
329+
330+ // Iterate through the fields setting bitFieldInfo and the Fields array. Also
331+ // locate the "most appropriate" storage type.
332+ for (const FieldDecl *field : recordDecl->fields ()) {
333+ mlir::Type fieldType;
334+ if (field->isBitField ())
335+ cirGenTypes.getCGModule ().errorNYI (recordDecl->getSourceRange (),
336+ " bitfields in lowerUnion" );
337+ else
338+ fieldType = getStorageType (field);
339+
340+ // This maps a field to its index. For unions, the index is always 0.
341+ fieldIdxMap[field->getCanonicalDecl ()] = 0 ;
342+
343+ // Compute zero-initializable status.
344+ // This union might not be zero initialized: it may contain a pointer to
345+ // data member which might have some exotic initialization sequence.
346+ // If this is the case, then we ought not to try and come up with a "better"
347+ // type, it might not be very easy to come up with a Constant which
348+ // correctly initializes it.
349+ if (!seenNamedMember) {
350+ seenNamedMember = field->getIdentifier ();
351+ if (!seenNamedMember)
352+ if (const RecordDecl *fieldRD = field->getType ()->getAsRecordDecl ())
353+ seenNamedMember = fieldRD->findFirstNamedDataMember ();
354+ if (seenNamedMember && !isZeroInitializable (field)) {
355+ zeroInitializable = zeroInitializableAsBase = false ;
356+ storageType = fieldType;
357+ }
358+ }
359+
360+ // Because our union isn't zero initializable, we won't be getting a better
361+ // storage type.
362+ if (!zeroInitializable)
363+ continue ;
364+
365+ // Conditionally update our storage type if we've got a new "better" one.
366+ if (!storageType || getAlignment (fieldType) > getAlignment (storageType) ||
367+ (getAlignment (fieldType) == getAlignment (storageType) &&
368+ getSize (fieldType) > getSize (storageType)))
369+ storageType = fieldType;
370+
371+ // NOTE(cir): Track all union member's types, not just the largest one. It
372+ // allows for proper type-checking and retain more info for analisys.
373+ fieldTypes.push_back (fieldType);
374+ }
375+
376+ if (!storageType)
377+ cirGenTypes.getCGModule ().errorNYI (recordDecl->getSourceRange (),
378+ " No-storage Union NYI" );
379+
380+ if (layoutSize < getSize (storageType))
381+ storageType = getByteArrayType (layoutSize);
382+ else
383+ appendPaddingBytes (layoutSize - getSize (storageType));
384+
385+ // Set packed if we need it.
386+ if (layoutSize % getAlignment (storageType))
387+ packed = true ;
388+ }
0 commit comments