@@ -108,6 +108,16 @@ struct CIRRecordLowering final {
108
108
// not the primary vbase of some base class.
109
109
bool hasOwnStorage (const CXXRecordDecl *decl, const CXXRecordDecl *query);
110
110
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
+
111
121
CharUnits bitsToCharUnits (uint64_t bitOffset) {
112
122
return astContext.toCharUnitsFromBits (bitOffset);
113
123
}
@@ -323,7 +333,45 @@ void CIRRecordLowering::fillOutputFields() {
323
333
RecordDecl::field_iterator
324
334
CIRRecordLowering::accumulateBitFields (RecordDecl::field_iterator field,
325
335
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
+ }
327
375
328
376
CharUnits regSize =
329
377
bitsToCharUnits (astContext.getTargetInfo ().getRegisterWidth ());
0 commit comments