@@ -82,8 +82,9 @@ struct CIRRecordLowering final {
8282 void accumulateBases (const CXXRecordDecl *cxxRecordDecl);
8383 void accumulateVPtrs ();
8484 void accumulateFields ();
85- void accumulateBitFields (RecordDecl::field_iterator field,
86- RecordDecl::field_iterator fieldEnd);
85+ RecordDecl::field_iterator
86+ accumulateBitFields (RecordDecl::field_iterator field,
87+ RecordDecl::field_iterator fieldEnd);
8788
8889 CharUnits bitsToCharUnits (uint64_t bitOffset) {
8990 return astContext.toCharUnitsFromBits (bitOffset);
@@ -290,87 +291,199 @@ void CIRRecordLowering::fillOutputFields() {
290291 }
291292}
292293
293- void CIRRecordLowering::accumulateBitFields (
294- RecordDecl::field_iterator field, RecordDecl::field_iterator fieldEnd) {
295- // 'run' stores the first element of the current run of bitfields. 'fieldEnd'
296- // is used as a special value to note that we don't have a current run. A
297- // bitfield run is a contiguous collection of bitfields that can be stored in
298- // the same storage block. Zero-sized bitfields and bitfields that would
299- // cross an alignment boundary break a run and start a new one.
300- RecordDecl::field_iterator run = fieldEnd;
301- // 'tail' is the offset of the first bit off the end of the current run. It's
302- // used to determine if the ASTRecordLayout is treating these two bitfields as
303- // contiguous. 'startBitOffset' is offset of the beginning of the run.
304- uint64_t startBitOffset, tail = 0 ;
294+ RecordDecl::field_iterator
295+ CIRRecordLowering::accumulateBitFields (RecordDecl::field_iterator field,
296+ RecordDecl::field_iterator fieldEnd) {
305297 assert (!cir::MissingFeatures::isDiscreteBitFieldABI ());
306298
307- // Check if 'offsetInRecord' (the size in bits of the current run) is better
308- // as a single field run. When OffsetInRecord has legal integer width, and
309- // its bitfield offset is naturally aligned, it is better to make the
310- // bitfield a separate storage component so as it can be accessed directly
311- // with lower cost.
312- assert (!cir::MissingFeatures::nonFineGrainedBitfields ());
299+ CharUnits regSize =
300+ bitsToCharUnits (astContext.getTargetInfo ().getRegisterWidth ());
301+ unsigned charBits = astContext.getCharWidth ();
302+
303+ // Data about the start of the span we're accumulating to create an access
304+ // unit from. 'Begin' is the first bitfield of the span. If 'begin' is
305+ // 'fieldEnd', we've not got a current span. The span starts at the
306+ // 'beginOffset' character boundary. 'bitSizeSinceBegin' is the size (in bits)
307+ // of the span -- this might include padding when we've advanced to a
308+ // subsequent bitfield run.
309+ RecordDecl::field_iterator begin = fieldEnd;
310+ CharUnits beginOffset;
311+ uint64_t bitSizeSinceBegin;
312+
313+ // The (non-inclusive) end of the largest acceptable access unit we've found
314+ // since 'begin'. If this is 'begin', we're gathering the initial set of
315+ // bitfields of a new span. 'bestEndOffset' is the end of that acceptable
316+ // access unit -- it might extend beyond the last character of the bitfield
317+ // run, using available padding characters.
318+ RecordDecl::field_iterator bestEnd = begin;
319+ CharUnits bestEndOffset;
320+ bool bestClipped; // Whether the representation must be in a byte array.
313321
314322 for (;;) {
315- // Check to see if we need to start a new run.
316- if (run == fieldEnd) {
317- // If we're out of fields, return.
318- if (field == fieldEnd)
323+ // atAlignedBoundary is true if 'field' is the (potential) start of a new
324+ // span (or the end of the bitfields). When true, limitOffset is the
325+ // character offset of that span and barrier indicates whether the new
326+ // span cannot be merged into the current one.
327+ bool atAlignedBoundary = false ;
328+ bool barrier = false ; // a barrier can be a zero Bit Width or non bit member
329+ if (field != fieldEnd && field->isBitField ()) {
330+ uint64_t bitOffset = getFieldBitOffset (*field);
331+ if (begin == fieldEnd) {
332+ // Beginning a new span.
333+ begin = field;
334+ bestEnd = begin;
335+
336+ assert ((bitOffset % charBits) == 0 && " Not at start of char" );
337+ beginOffset = bitsToCharUnits (bitOffset);
338+ bitSizeSinceBegin = 0 ;
339+ } else if ((bitOffset % charBits) != 0 ) {
340+ // Bitfield occupies the same character as previous bitfield, it must be
341+ // part of the same span. This can include zero-length bitfields, should
342+ // the target not align them to character boundaries. Such non-alignment
343+ // is at variance with the standards, which require zero-length
344+ // bitfields be a barrier between access units. But of course we can't
345+ // achieve that in the middle of a character.
346+ assert (bitOffset ==
347+ astContext.toBits (beginOffset) + bitSizeSinceBegin &&
348+ " Concatenating non-contiguous bitfields" );
349+ } else {
350+ // Bitfield potentially begins a new span. This includes zero-length
351+ // bitfields on non-aligning targets that lie at character boundaries
352+ // (those are barriers to merging).
353+ if (field->isZeroLengthBitField ())
354+ barrier = true ;
355+ atAlignedBoundary = true ;
356+ }
357+ } else {
358+ // We've reached the end of the bitfield run. Either we're done, or this
359+ // is a barrier for the current span.
360+ if (begin == fieldEnd)
319361 break ;
320- // Any non-zero-length bitfield can start a new run.
321- if (!field->isZeroLengthBitField ()) {
322- run = field;
323- startBitOffset = getFieldBitOffset (*field);
324- tail = startBitOffset + field->getBitWidthValue ();
325- assert (!cir::MissingFeatures::nonFineGrainedBitfields ());
362+
363+ barrier = true ;
364+ atAlignedBoundary = true ;
365+ }
366+
367+ // 'installBest' indicates whether we should create an access unit for the
368+ // current best span: fields ['begin', 'bestEnd') occupying characters
369+ // ['beginOffset', 'bestEndOffset').
370+ bool installBest = false ;
371+ if (atAlignedBoundary) {
372+ // 'field' is the start of a new span or the end of the bitfields. The
373+ // just-seen span now extends to 'bitSizeSinceBegin'.
374+
375+ // Determine if we can accumulate that just-seen span into the current
376+ // accumulation.
377+ CharUnits accessSize = bitsToCharUnits (bitSizeSinceBegin + charBits - 1 );
378+ if (bestEnd == begin) {
379+ // This is the initial run at the start of a new span. By definition,
380+ // this is the best seen so far.
381+ bestEnd = field;
382+ bestEndOffset = beginOffset + accessSize;
383+ // Assume clipped until proven not below.
384+ bestClipped = true ;
385+ if (!bitSizeSinceBegin)
386+ // A zero-sized initial span -- this will install nothing and reset
387+ // for another.
388+ installBest = true ;
389+ } else if (accessSize > regSize) {
390+ // Accumulating the just-seen span would create a multi-register access
391+ // unit, which would increase register pressure.
392+ installBest = true ;
393+ }
394+
395+ if (!installBest) {
396+ // Determine if accumulating the just-seen span will create an expensive
397+ // access unit or not.
398+ mlir::Type type = getUIntNType (astContext.toBits (accessSize));
399+ if (!astContext.getTargetInfo ().hasCheapUnalignedBitFieldAccess ())
400+ cirGenTypes.getCGModule ().errorNYI (
401+ field->getSourceRange (), " NYI CheapUnalignedBitFieldAccess" );
402+
403+ if (!installBest) {
404+ // Find the next used storage offset to determine what the limit of
405+ // the current span is. That's either the offset of the next field
406+ // with storage (which might be field itself) or the end of the
407+ // non-reusable tail padding.
408+ CharUnits limitOffset;
409+ for (auto probe = field; probe != fieldEnd; ++probe)
410+ if (!isEmptyFieldForLayout (astContext, *probe)) {
411+ // A member with storage sets the limit.
412+ assert ((getFieldBitOffset (*probe) % charBits) == 0 &&
413+ " Next storage is not byte-aligned" );
414+ limitOffset = bitsToCharUnits (getFieldBitOffset (*probe));
415+ goto FoundLimit;
416+ }
417+ assert (!cir::MissingFeatures::cxxSupport ());
418+ limitOffset = astRecordLayout.getDataSize ();
419+ FoundLimit:
420+ CharUnits typeSize = getSize (type);
421+ if (beginOffset + typeSize <= limitOffset) {
422+ // There is space before limitOffset to create a naturally-sized
423+ // access unit.
424+ bestEndOffset = beginOffset + typeSize;
425+ bestEnd = field;
426+ bestClipped = false ;
427+ }
428+ if (barrier) {
429+ // The next field is a barrier that we cannot merge across.
430+ installBest = true ;
431+ } else if (cirGenTypes.getCGModule ()
432+ .getCodeGenOpts ()
433+ .FineGrainedBitfieldAccesses ) {
434+ assert (!cir::MissingFeatures::nonFineGrainedBitfields ());
435+ cirGenTypes.getCGModule ().errorNYI (field->getSourceRange (),
436+ " NYI FineGrainedBitfield" );
437+ } else {
438+ // Otherwise, we're not installing. Update the bit size
439+ // of the current span to go all the way to limitOffset, which is
440+ // the (aligned) offset of next bitfield to consider.
441+ bitSizeSinceBegin = astContext.toBits (limitOffset - beginOffset);
442+ }
443+ }
326444 }
327- ++field;
328- continue ;
329445 }
330446
331- // Decide whether to continue extending the current bitfield run.
332- //
333- // Skip the block below and go directly to emitting storage if any of the
334- // following is true:
335- // - 1. The first field in the run is better treated as its own run.
336- // - 2. We have reached the end of the fields.
337- // - 3. The current field (or set of fields) is better as its own run.
338- // - 4. The current field is a zero-width bitfield or:
339- // - Zero-length bitfield alignment is enabled, and
340- // - Bitfield type alignment is enabled.
341- // - 5. The current field's offset doesn't match the expected tail (i.e.,
342- // layout isn't contiguous).
343- //
344- // If none of the above conditions are met, add the current field to the
345- // current run.
346- uint64_t nextTail = tail;
347- if (field != fieldEnd)
348- nextTail += field->getBitWidthValue ();
349-
350- // TODO: add condition 1 and 3
351- assert (!cir::MissingFeatures::nonFineGrainedBitfields ());
352- if (field != fieldEnd &&
353- (!field->isZeroLengthBitField () ||
354- (!astContext.getTargetInfo ().useZeroLengthBitfieldAlignment () &&
355- !astContext.getTargetInfo ().useBitFieldTypeAlignment ())) &&
356- tail == getFieldBitOffset (*field)) {
357- tail = nextTail;
447+ if (installBest) {
448+ assert ((field == fieldEnd || !field->isBitField () ||
449+ (getFieldBitOffset (*field) % charBits) == 0 ) &&
450+ " Installing but not at an aligned bitfield or limit" );
451+ CharUnits accessSize = bestEndOffset - beginOffset;
452+ if (!accessSize.isZero ()) {
453+ // Add the storage member for the access unit to the record. The
454+ // bitfields get the offset of their storage but come afterward and
455+ // remain there after a stable sort.
456+ mlir::Type type;
457+ if (bestClipped) {
458+ assert (getSize (getUIntNType (astContext.toBits (accessSize))) >
459+ accessSize &&
460+ " Clipped access need not be clipped" );
461+ type = getByteArrayType (accessSize);
462+ } else {
463+ type = getUIntNType (astContext.toBits (accessSize));
464+ assert (getSize (type) == accessSize &&
465+ " Unclipped access must be clipped" );
466+ }
467+ members.push_back (makeStorageInfo (beginOffset, type));
468+ for (; begin != bestEnd; ++begin)
469+ if (!begin->isZeroLengthBitField ())
470+ members.push_back (MemberInfo (
471+ beginOffset, MemberInfo::InfoKind::Field, nullptr , *begin));
472+ }
473+ // Reset to start a new span.
474+ field = bestEnd;
475+ begin = fieldEnd;
476+ } else {
477+ assert (field != fieldEnd && field->isBitField () &&
478+ " Accumulating past end of bitfields" );
479+ assert (!barrier && " Accumulating across barrier" );
480+ // Accumulate this bitfield into the current (potential) span.
481+ bitSizeSinceBegin += field->getBitWidthValue ();
358482 ++field;
359- continue ;
360483 }
361-
362- // We've hit a break-point in the run and need to emit a storage field.
363- mlir::Type type = getBitfieldStorageType (tail - startBitOffset);
364-
365- // Add the storage member to the record and set the bitfield info for all of
366- // the bitfields in the run. Bitfields get the offset of their storage but
367- // come afterward and remain there after a stable sort.
368- members.push_back (makeStorageInfo (bitsToCharUnits (startBitOffset), type));
369- for (; run != field; ++run)
370- members.push_back (MemberInfo (bitsToCharUnits (startBitOffset),
371- MemberInfo::InfoKind::Field, nullptr , *run));
372- run = fieldEnd;
373484 }
485+
486+ return field;
374487}
375488
376489void CIRRecordLowering::accumulateFields () {
@@ -382,7 +495,9 @@ void CIRRecordLowering::accumulateFields() {
382495 // Iterate to gather the list of bitfields.
383496 for (++field; field != fieldEnd && field->isBitField (); ++field)
384497 ;
385- accumulateBitFields (start, field);
498+ field = accumulateBitFields (start, field);
499+ assert ((field == fieldEnd || !field->isBitField ()) &&
500+ " Failed to accumulate all the bitfields" );
386501 } else if (!field->isZeroSize (astContext)) {
387502 members.push_back (MemberInfo (bitsToCharUnits (getFieldBitOffset (*field)),
388503 MemberInfo::InfoKind::Field,
0 commit comments