[flang-commits] [flang] [flang] Fix `getTypeSizeAndAlignment` for packed/tail-padded `RecordType` and `TRANSFER` gate (PR #220377)
Daniel Chen via flang-commits
flang-commits at lists.llvm.org
Thu Sep 3 14:58:29 PDT 2026
================
@@ -8972,22 +8972,64 @@ IntrinsicLibrary::genTransfer(mlir::Type resultType,
(fir::isa_trivial(sourceType) ||
mlir::isa<fir::RecordType>(sourceType)) &&
fir::isa_trivial(moldType)) {
+ // Compare store sizes (data bytes, no tail padding) because Fortran
+ // TRANSFER is defined over STORAGE_SIZE data bits. For a RecordType
+ // source, storeSizeOnly=true strips the tail padding that the compiler
+ // adds for alignment but that is not part of the type's data.
+ // Note: the runtime (TransferImpl) copies source.ElementBytes() bytes,
+ // which is the allocation size and may include tail padding. The store-
+ // size comparison here is therefore *not* about matching the runtime's
+ // copy width; it is about selecting the correct inline path according to
+ // the standard's data-bit definition.
+ //
+ // Alignment is a separate concern: when the source alignment is less
+ // than the result type's alignment, the RecordType path below copies
+ // into a result-aligned alloca rather than loading directly from the
+ // source pointer.
auto sourceSizeAndAlign = fir::getTypeSizeAndAlignment(
- loc, sourceType, builder.getDataLayout(), builder.getKindMap());
+ loc, sourceType, builder.getDataLayout(), builder.getKindMap(),
+ /*storeSizeOnly=*/true);
auto resultSizeAndAlign = fir::getTypeSizeAndAlignment(
- loc, resultType, builder.getDataLayout(), builder.getKindMap());
+ loc, resultType, builder.getDataLayout(), builder.getKindMap(),
+ /*storeSizeOnly=*/true);
if (sourceSizeAndAlign && resultSizeAndAlign &&
sourceSizeAndAlign->first == resultSizeAndAlign->first) {
- if (sourceType.isSignlessIntOrFloat() &&
- resultType.isSignlessIntOrFloat()) {
- mlir::Value val = fir::LoadOp::create(builder, loc, sourceBase);
- if (sourceType != resultType)
- val = mlir::arith::BitcastOp::create(builder, loc, resultType, val);
- return val;
+ if (fir::isa_trivial(sourceType)) {
+ // Both source and result are trivial scalars of the same store
+ // size. Use arith.bitcast for signless integer/float pairs;
+ // for other trivial types (e.g. unsigned integers) arith.bitcast
+ // is not available, so cast the source address and load.
+ if (sourceType.isSignlessIntOrFloat() &&
+ resultType.isSignlessIntOrFloat()) {
+ mlir::Value val = fir::LoadOp::create(builder, loc, sourceBase);
+ if (sourceType != resultType)
+ val =
+ mlir::arith::BitcastOp::create(builder, loc, resultType, val);
+ return val;
+ }
+ mlir::Type refTy = builder.getRefType(resultType);
+ mlir::Value cast = builder.createConvert(loc, refTy, sourceBase);
+ return fir::LoadOp::create(builder, loc, cast);
+ }
+ // The source is a RecordType. When the source ABI alignment is
+ // sufficient for resultType, a direct address cast and load is safe.
+ // When sourceAlign < resultAlign (e.g. {i64,i16} is 8-byte aligned
+ // while x86_fp80 requires 16-byte alignment), loading resultType
+ // directly from sourceBase would claim an over-aligned address,
+ // producing undefined behaviour. In that case copy the bytes into
+ // a result-typed alloca (which receives resultType's natural
+ // alignment) and load from there.
+ if (sourceSizeAndAlign->second >= resultSizeAndAlign->second) {
+ mlir::Type refTy = builder.getRefType(resultType);
+ mlir::Value cast = builder.createConvert(loc, refTy, sourceBase);
+ return fir::LoadOp::create(builder, loc, cast);
}
- mlir::Type refTy = builder.getRefType(resultType);
- mlir::Value cast = builder.createConvert(loc, refTy, sourceBase);
- return fir::LoadOp::create(builder, loc, cast);
+ mlir::Value tmp = fir::AllocaOp::create(builder, loc, resultType);
+ mlir::Value srcLoad = fir::LoadOp::create(builder, loc, sourceBase);
+ mlir::Type srcRefTy = builder.getRefType(sourceType);
+ mlir::Value tmpAsSrc = builder.createConvert(loc, srcRefTy, tmp);
+ fir::StoreOp::create(builder, loc, srcLoad, tmpAsSrc);
----------------
DanielCChen wrote:
Updated `TRANSFER` to use a byte-wise `fir.copy` into aligned storage, preserving internal padding bytes.
Added regression coverage for a padded `BIND(C)` record transferred to `INTEGER(16)`.
https://github.com/llvm/llvm-project/pull/220377
More information about the flang-commits
mailing list