@@ -112,9 +112,34 @@ void CIRDialect::printType(Type type, DialectAsmPrinter &os) const {
112
112
// /
113
113
// / Recurses into union members never returning a union as the largest member.
114
114
Type RecordType::getLargestMember (const ::mlir::DataLayout &dataLayout) const {
115
- if (!layoutInfo)
116
- computeSizeAndAlignment (dataLayout);
117
- return mlir::cast<cir::RecordLayoutAttr>(layoutInfo).getLargestMember ();
115
+ assert (isUnion () && " getLargetMember called for non-union record" );
116
+
117
+ // This is a similar algorithm to LLVM's StructLayout.
118
+ unsigned numElements = getNumElements ();
119
+ auto members = getMembers ();
120
+ mlir::Type largestMember;
121
+ unsigned largestMemberSize = 0 ;
122
+
123
+ // Ignore the last member if this is a padded union.
124
+ if (getPadded ())
125
+ --numElements;
126
+
127
+ for (unsigned i = 0 , e = numElements; i != e; ++i) {
128
+ auto ty = members[i];
129
+
130
+ // Found a nested union: recurse into it to fetch its largest member.
131
+ if (!largestMember ||
132
+ dataLayout.getTypeABIAlignment (ty) >
133
+ dataLayout.getTypeABIAlignment (largestMember) ||
134
+ (dataLayout.getTypeABIAlignment (ty) ==
135
+ dataLayout.getTypeABIAlignment (largestMember) &&
136
+ dataLayout.getTypeSize (ty) > largestMemberSize)) {
137
+ largestMember = ty;
138
+ largestMemberSize = dataLayout.getTypeSize (largestMember);
139
+ }
140
+ }
141
+
142
+ return largestMember;
118
143
}
119
144
120
145
Type RecordType::parse (mlir::AsmParser &parser) {
@@ -385,117 +410,137 @@ cir::VectorType::getABIAlignment(const ::mlir::DataLayout &dataLayout,
385
410
return llvm::NextPowerOf2 (dataLayout.getTypeSizeInBits (*this ));
386
411
}
387
412
413
+ // TODO(cir): Implement a way to cache the datalayout info calculated below.
414
+
388
415
llvm::TypeSize
389
- RecordType::getTypeSizeInBits (const :: mlir::DataLayout &dataLayout,
390
- :: mlir::DataLayoutEntryListRef params) const {
391
- if (!layoutInfo )
392
- computeSizeAndAlignment ( dataLayout);
393
- return llvm::TypeSize::getFixed (
394
- mlir::cast<cir::RecordLayoutAttr>(layoutInfo). getSize ( ) * 8 );
416
+ RecordType::getTypeSizeInBits (const mlir::DataLayout &dataLayout,
417
+ mlir::DataLayoutEntryListRef params) const {
418
+ if (isUnion () )
419
+ return llvm::TypeSize::getFixed ( computeUnionSize ( dataLayout) * 8 );
420
+
421
+ return llvm::TypeSize::getFixed ( computeStructSize (dataLayout ) * 8 );
395
422
}
396
423
397
424
uint64_t
398
425
RecordType::getABIAlignment (const ::mlir::DataLayout &dataLayout,
399
426
::mlir::DataLayoutEntryListRef params) const {
400
- if (!layoutInfo)
401
- computeSizeAndAlignment (dataLayout);
402
- return mlir::cast<cir::RecordLayoutAttr>(layoutInfo).getAlignment ();
403
- }
427
+ // Packed structures always have an ABI alignment of 1.
428
+ if (getPacked ())
429
+ return 1 ;
404
430
405
- uint64_t RecordType::getElementOffset (const ::mlir::DataLayout &dataLayout,
406
- unsigned idx) const {
407
- assert (idx < getMembers ().size () && " access not valid" );
408
- if (!layoutInfo)
409
- computeSizeAndAlignment (dataLayout);
410
- auto offsets = mlir::cast<cir::RecordLayoutAttr>(layoutInfo).getOffsets ();
411
- auto intAttr = mlir::cast<mlir::IntegerAttr>(offsets[idx]);
412
- return intAttr.getInt ();
431
+ if (isUnion ())
432
+ return computeUnionAlignment (dataLayout);
433
+ return computeStructAlignment (dataLayout);
413
434
}
414
435
415
- void RecordType::computeSizeAndAlignment (
416
- const :: mlir::DataLayout &dataLayout) const {
436
+ unsigned
437
+ RecordType::computeUnionSize ( const mlir::DataLayout &dataLayout) const {
417
438
assert (isComplete () && " Cannot get layout of incomplete records" );
418
- // Do not recompute.
419
- if (layoutInfo)
420
- return ;
439
+ assert (isUnion () && " computeUnionSize called for non-union record" );
421
440
422
441
// This is a similar algorithm to LLVM's StructLayout.
423
442
unsigned recordSize = 0 ;
424
443
llvm::Align recordAlignment{1 };
425
- bool isPadded = false ;
426
444
unsigned numElements = getNumElements ();
427
445
auto members = getMembers ();
428
- mlir::Type largestMember;
429
446
unsigned largestMemberSize = 0 ;
430
- llvm::SmallVector<mlir::Attribute, 4 > memberOffsets;
431
447
432
- bool dontCountLastElt = isUnion () && getPadded ();
433
- if (dontCountLastElt)
434
- numElements--;
448
+ auto largestMember = getLargestMember (dataLayout);
449
+ recordSize = dataLayout.getTypeSize (largestMember);
435
450
436
- // Loop over each of the elements, placing them in memory.
437
- memberOffsets.reserve (numElements);
451
+ // If the union is padded, add the padding to the size.
452
+ if (getPadded ()) {
453
+ auto ty = getMembers ()[numElements - 1 ];
454
+ recordSize += dataLayout.getTypeSize (ty);
455
+ }
438
456
439
- for ( unsigned i = 0 , e = numElements; i != e; ++i) {
440
- auto ty = members[i];
457
+ return recordSize;
458
+ }
441
459
442
- // Found a nested union: recurse into it to fetch its largest member.
443
- if (!largestMember ||
444
- dataLayout.getTypeABIAlignment (ty) >
445
- dataLayout.getTypeABIAlignment (largestMember) ||
446
- (dataLayout.getTypeABIAlignment (ty) ==
447
- dataLayout.getTypeABIAlignment (largestMember) &&
448
- dataLayout.getTypeSize (ty) > largestMemberSize)) {
449
- largestMember = ty;
450
- largestMemberSize = dataLayout.getTypeSize (largestMember);
451
- }
460
+ unsigned
461
+ RecordType::computeStructSize (const mlir::DataLayout &dataLayout) const {
462
+ assert (isComplete () && " Cannot get layout of incomplete records" );
463
+
464
+ // This is a similar algorithm to LLVM's StructLayout.
465
+ unsigned recordSize = 0 ;
466
+ uint64_t recordAlignment = 1 ;
467
+
468
+ // We can't use a range-based for loop here because we might be ignoring the
469
+ // last element.
470
+ for (mlir::Type ty : getMembers ()) {
471
+ // This assumes that we're calculating size based on the ABI alignment, not
472
+ // the preferred alignment for each type.
473
+ const uint64_t tyAlign =
474
+ (getPacked () ? 1 : dataLayout.getTypeABIAlignment (ty));
475
+
476
+ // Add padding to the struct size to align it to the abi alignment of the
477
+ // element type before than adding the size of the element.
478
+ recordSize = llvm::alignTo (recordSize, tyAlign);
479
+ recordSize += dataLayout.getTypeSize (ty);
480
+
481
+ // The alignment requirement of a struct is equal to the strictest alignment
482
+ // requirement of its elements.
483
+ recordAlignment = std::max (tyAlign, recordAlignment);
484
+ }
485
+
486
+ // At the end, add padding to the struct to satisfy its own alignment
487
+ // requirement. Otherwise structs inside of arrays would be misaligned.
488
+ recordSize = llvm::alignTo (recordSize, recordAlignment);
489
+ return recordSize;
490
+ }
491
+
492
+ // We also compute the alignment as part of computeStructSize, but this is more
493
+ // efficient. Ideally, we'd like to compute both at once and cache the result,
494
+ // but that's implemented yet.
495
+ // TODO(CIR): Implement a way to cache the result.
496
+ uint64_t
497
+ RecordType::computeStructAlignment (const mlir::DataLayout &dataLayout) const {
498
+ assert (isComplete () && " Cannot get layout of incomplete records" );
499
+
500
+ // This is a similar algorithm to LLVM's StructLayout.
501
+ uint64_t recordAlignment = 1 ;
502
+ for (mlir::Type ty : getMembers ())
503
+ recordAlignment =
504
+ std::max (dataLayout.getTypeABIAlignment (ty), recordAlignment);
505
+
506
+ return recordAlignment;
507
+ }
508
+
509
+ uint64_t
510
+ RecordType::computeUnionAlignment (const mlir::DataLayout &dataLayout) const {
511
+ auto largestMember = getLargestMember (dataLayout);
512
+ return dataLayout.getTypeABIAlignment (largestMember);
513
+ }
514
+
515
+ uint64_t RecordType::getElementOffset (const ::mlir::DataLayout &dataLayout,
516
+ unsigned idx) const {
517
+ assert (idx < getMembers ().size () && " access not valid" );
518
+
519
+ // All union elements are at offset zero.
520
+ if (isUnion () || idx == 0 )
521
+ return 0 ;
522
+
523
+ assert (isComplete () && " Cannot get layout of incomplete records" );
524
+ assert (idx < getNumElements ());
525
+ auto members = getMembers ();
526
+
527
+ unsigned offset = 0 ;
528
+
529
+ for (unsigned i = 0 , e = idx; i != e; ++i) {
530
+ auto ty = members[i];
452
531
453
532
// This matches LLVM since it uses the ABI instead of preferred alignment.
454
533
const llvm::Align tyAlign =
455
534
llvm::Align (getPacked () ? 1 : dataLayout.getTypeABIAlignment (ty));
456
535
457
536
// Add padding if necessary to align the data element properly.
458
- if (!llvm::isAligned (tyAlign, recordSize)) {
459
- isPadded = true ;
460
- recordSize = llvm::alignTo (recordSize, tyAlign);
461
- }
462
-
463
- // Keep track of maximum alignment constraint.
464
- recordAlignment = std::max (tyAlign, recordAlignment);
465
-
466
- // Record size up to each element is the element offset.
467
- memberOffsets.push_back (mlir::IntegerAttr::get (
468
- mlir::IntegerType::get (getContext (), 32 ), isUnion () ? 0 : recordSize));
537
+ offset = llvm::alignTo (offset, tyAlign);
469
538
470
539
// Consume space for this data item
471
- recordSize += dataLayout.getTypeSize (ty);
472
- }
473
-
474
- // For unions, the size and aligment is that of the largest element.
475
- if (isUnion ()) {
476
- recordSize = largestMemberSize;
477
- if (getPadded ()) {
478
- memberOffsets.push_back (mlir::IntegerAttr::get (
479
- mlir::IntegerType::get (getContext (), 32 ), recordSize));
480
- auto ty = getMembers ()[numElements];
481
- recordSize += dataLayout.getTypeSize (ty);
482
- isPadded = true ;
483
- } else {
484
- isPadded = false ;
485
- }
486
- } else {
487
- // Add padding to the end of the record so that it could be put in an array
488
- // and all array elements would be aligned correctly.
489
- if (!llvm::isAligned (recordAlignment, recordSize)) {
490
- isPadded = true ;
491
- recordSize = llvm::alignTo (recordSize, recordAlignment);
492
- }
540
+ offset += dataLayout.getTypeSize (ty);
493
541
}
494
542
495
- auto offsets = mlir::ArrayAttr::get (getContext (), memberOffsets);
496
- layoutInfo = cir::RecordLayoutAttr::get (getContext (), recordSize,
497
- recordAlignment.value (), isPadded,
498
- largestMember, offsets);
543
+ return offset;
499
544
}
500
545
501
546
// ===----------------------------------------------------------------------===//
0 commit comments