@@ -112,9 +112,34 @@ void CIRDialect::printType(Type type, DialectAsmPrinter &os) const {
112112// /
113113// / Recurses into union members never returning a union as the largest member.
114114Type 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;
118143}
119144
120145Type RecordType::parse (mlir::AsmParser &parser) {
@@ -385,117 +410,137 @@ cir::VectorType::getABIAlignment(const ::mlir::DataLayout &dataLayout,
385410 return llvm::NextPowerOf2 (dataLayout.getTypeSizeInBits (*this ));
386411}
387412
413+ // TODO(cir): Implement a way to cache the datalayout info calculated below.
414+
388415llvm::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 );
395422}
396423
397424uint64_t
398425RecordType::getABIAlignment (const ::mlir::DataLayout &dataLayout,
399426 ::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 ;
404430
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);
413434}
414435
415- void RecordType::computeSizeAndAlignment (
416- const :: mlir::DataLayout &dataLayout) const {
436+ unsigned
437+ RecordType::computeUnionSize ( const mlir::DataLayout &dataLayout) const {
417438 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" );
421440
422441 // This is a similar algorithm to LLVM's StructLayout.
423442 unsigned recordSize = 0 ;
424443 llvm::Align recordAlignment{1 };
425- bool isPadded = false ;
426444 unsigned numElements = getNumElements ();
427445 auto members = getMembers ();
428- mlir::Type largestMember;
429446 unsigned largestMemberSize = 0 ;
430- llvm::SmallVector<mlir::Attribute, 4 > memberOffsets;
431447
432- bool dontCountLastElt = isUnion () && getPadded ();
433- if (dontCountLastElt)
434- numElements--;
448+ auto largestMember = getLargestMember (dataLayout);
449+ recordSize = dataLayout.getTypeSize (largestMember);
435450
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+ }
438456
439- for ( unsigned i = 0 , e = numElements; i != e; ++i) {
440- auto ty = members[i];
457+ return recordSize;
458+ }
441459
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];
452531
453532 // This matches LLVM since it uses the ABI instead of preferred alignment.
454533 const llvm::Align tyAlign =
455534 llvm::Align (getPacked () ? 1 : dataLayout.getTypeABIAlignment (ty));
456535
457536 // 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);
469538
470539 // 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);
493541 }
494542
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;
499544}
500545
501546// ===----------------------------------------------------------------------===//
0 commit comments