@@ -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;
@@ -136,6 +148,8 @@ struct CIRRecordLowering final {
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
@@ -306,3 +320,71 @@ CIRGenTypes::computeRecordLayout(const RecordDecl *rd, cir::RecordType *ty) {
306320 // TODO: implement verification
307321 return rl;
308322}
323+
324+ void CIRRecordLowering::lowerUnion () {
325+ CharUnits layoutSize = astRecordLayout.getSize ();
326+ mlir::Type storageType = nullptr ;
327+ bool seenNamedMember = false ;
328+
329+ // Iterate through the fields setting bitFieldInfo and the Fields array. Also
330+ // locate the "most appropriate" storage type. The heuristic for finding the
331+ // storage type isn't necessary, the first (non-0-length-bitfield) field's
332+ // type would work fine and be simpler but would be different than what we've
333+ // been doing and cause lit tests to change.
334+ for (const FieldDecl *field : recordDecl->fields ()) {
335+ mlir::Type fieldType;
336+ if (field->isBitField ())
337+ cirGenTypes.getCGModule ().errorNYI (recordDecl->getSourceRange (),
338+ " bitfields in lowerUnion" );
339+ else
340+ fieldType = getStorageType (field);
341+
342+ fields[field->getCanonicalDecl ()] = 0 ;
343+
344+ // Compute zero-initializable status.
345+ // This union might not be zero initialized: it may contain a pointer to
346+ // data member which might have some exotic initialization sequence.
347+ // If this is the case, then we aught not to try and come up with a "better"
348+ // type, it might not be very easy to come up with a Constant which
349+ // correctly initializes it.
350+ if (!seenNamedMember) {
351+ seenNamedMember = field->getIdentifier ();
352+ if (!seenNamedMember)
353+ if (const RecordDecl *fieldRD = field->getType ()->getAsRecordDecl ())
354+ seenNamedMember = fieldRD->findFirstNamedDataMember ();
355+ if (seenNamedMember && !isZeroInitializable (field)) {
356+ zeroInitializable = zeroInitializableAsBase = false ;
357+ storageType = fieldType;
358+ }
359+ }
360+
361+ // Because our union isn't zero initializable, we won't be getting a better
362+ // storage type.
363+ if (!zeroInitializable)
364+ continue ;
365+
366+ // Conditionally update our storage type if we've got a new "better" one.
367+ if (!storageType || getAlignment (fieldType) > getAlignment (storageType) ||
368+ (getAlignment (fieldType) == getAlignment (storageType) &&
369+ getSize (fieldType) > getSize (storageType)))
370+ storageType = fieldType;
371+
372+ // NOTE(cir): Track all union member's types, not just the largest one. It
373+ // allows for proper type-checking and retain more info for analisys.
374+ fieldTypes.push_back (fieldType);
375+ }
376+
377+ if (!storageType)
378+ cirGenTypes.getCGModule ().errorNYI (recordDecl->getSourceRange (),
379+ " No-storage Union NYI" );
380+
381+ if (layoutSize < getSize (storageType))
382+ storageType = getByteArrayType (layoutSize);
383+
384+ // NOTE(cir): Defer padding calculations to the lowering process.
385+ appendPaddingBytes (layoutSize - getSize (storageType));
386+
387+ // Set packed if we need it.
388+ if (layoutSize % getAlignment (storageType))
389+ packed = true ;
390+ }
0 commit comments