@@ -108,6 +108,16 @@ struct CIRRecordLowering final {
108108 // not the primary vbase of some base class.
109109 bool hasOwnStorage (const CXXRecordDecl *decl, const CXXRecordDecl *query);
110110
111+ // / The Microsoft bitfield layout rule allocates discrete storage
112+ // / units of the field's formal type and only combines adjacent
113+ // / fields of the same formal type. We want to emit a layout with
114+ // / these discrete storage units instead of combining them into a
115+ // / continuous run.
116+ bool isDiscreteBitFieldABI () {
117+ return astContext.getTargetInfo ().getCXXABI ().isMicrosoft () ||
118+ recordDecl->isMsStruct (astContext);
119+ }
120+
111121 CharUnits bitsToCharUnits (uint64_t bitOffset) {
112122 return astContext.toCharUnitsFromBits (bitOffset);
113123 }
@@ -323,7 +333,45 @@ void CIRRecordLowering::fillOutputFields() {
323333RecordDecl::field_iterator
324334CIRRecordLowering::accumulateBitFields (RecordDecl::field_iterator field,
325335 RecordDecl::field_iterator fieldEnd) {
326- assert (!cir::MissingFeatures::isDiscreteBitFieldABI ());
336+ if (isDiscreteBitFieldABI ()) {
337+ // run stores the first element of the current run of bitfields. fieldEnd is
338+ // used as a special value to note that we don't have a current run. A
339+ // bitfield run is a contiguous collection of bitfields that can be stored
340+ // in the same storage block. Zero-sized bitfields and bitfields that would
341+ // cross an alignment boundary break a run and start a new one.
342+ RecordDecl::field_iterator run = fieldEnd;
343+ // tail is the offset of the first bit off the end of the current run. It's
344+ // used to determine if the ASTRecordLayout is treating these two bitfields
345+ // as contiguous. StartBitOffset is offset of the beginning of the Run.
346+ uint64_t startBitOffset, tail = 0 ;
347+ for (; field != fieldEnd && field->isBitField (); ++field) {
348+ // Zero-width bitfields end runs.
349+ if (field->isZeroLengthBitField ()) {
350+ run = fieldEnd;
351+ continue ;
352+ }
353+ uint64_t bitOffset = getFieldBitOffset (*field);
354+ mlir::Type type = cirGenTypes.convertTypeForMem (field->getType ());
355+ // If we don't have a run yet, or don't live within the previous run's
356+ // allocated storage then we allocate some storage and start a new run.
357+ if (run == fieldEnd || bitOffset >= tail) {
358+ run = field;
359+ startBitOffset = bitOffset;
360+ tail = startBitOffset + dataLayout.getTypeAllocSizeInBits (type);
361+ // Add the storage member to the record. This must be added to the
362+ // record before the bitfield members so that it gets laid out before
363+ // the bitfields it contains get laid out.
364+ members.push_back (
365+ makeStorageInfo (bitsToCharUnits (startBitOffset), type));
366+ }
367+ // Bitfields get the offset of their storage but come afterward and remain
368+ // there after a stable sort.
369+ members.push_back (MemberInfo (bitsToCharUnits (startBitOffset),
370+ MemberInfo::InfoKind::Field, nullptr ,
371+ *field));
372+ }
373+ return field;
374+ }
327375
328376 CharUnits regSize =
329377 bitsToCharUnits (astContext.getTargetInfo ().getRegisterWidth ());
0 commit comments