@@ -82,8 +82,9 @@ struct CIRRecordLowering final {
82
82
void accumulateBases (const CXXRecordDecl *cxxRecordDecl);
83
83
void accumulateVPtrs ();
84
84
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);
87
88
88
89
CharUnits bitsToCharUnits (uint64_t bitOffset) {
89
90
return astContext.toCharUnitsFromBits (bitOffset);
@@ -290,87 +291,199 @@ void CIRRecordLowering::fillOutputFields() {
290
291
}
291
292
}
292
293
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) {
305
297
assert (!cir::MissingFeatures::isDiscreteBitFieldABI ());
306
298
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.
313
321
314
322
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)
319
361
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
+ }
326
444
}
327
- ++field;
328
- continue ;
329
445
}
330
446
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 ();
358
482
++field;
359
- continue ;
360
483
}
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;
373
484
}
485
+
486
+ return field;
374
487
}
375
488
376
489
void CIRRecordLowering::accumulateFields () {
@@ -382,7 +495,9 @@ void CIRRecordLowering::accumulateFields() {
382
495
// Iterate to gather the list of bitfields.
383
496
for (++field; field != fieldEnd && field->isBitField (); ++field)
384
497
;
385
- accumulateBitFields (start, field);
498
+ field = accumulateBitFields (start, field);
499
+ assert ((field == fieldEnd || !field->isBitField ()) &&
500
+ " Failed to accumulate all the bitfields" );
386
501
} else if (!field->isZeroSize (astContext)) {
387
502
members.push_back (MemberInfo (bitsToCharUnits (getFieldBitOffset (*field)),
388
503
MemberInfo::InfoKind::Field,
0 commit comments