[flang-commits] [flang] [flang] Fix TRANSFER into derived type with tail padding zeroing pad bytes (PR #223814)

via flang-commits flang-commits at lists.llvm.org
Wed Sep 16 20:37:05 PDT 2026


================
@@ -1552,15 +1472,24 @@ void fir::factory::genRecordAssignment(fir::FirOpBuilder &builder,
     return;
   }
 
-  // Otherwise, the derived type has compile time constant size and for which
-  // the component by component assignment can be replaced by a memory copy.
-  // Since we do not know the size of the derived type in lowering, do a
-  // component by component assignment. Note that a single fir.load/fir.store
-  // could be used on "small" record types, but as the type size grows, this
-  // leads to issues in LLVM (long compile times, long IR files, and even
-  // asserts at some point). Since there is no good size boundary, just always
-  // use component by component assignment here.
-  genComponentByComponentAssignment(builder, loc, lhs, rhs, isTemporaryLHS);
+  // Otherwise, the derived type has compile time constant size, no
+  // allocatable components, and no user-defined assignment. The size of the
+  // type is not known at this point in lowering, but fir.copy defers the size
+  // computation to codegen where the LLVM data layout is available. That allows
+  // it to copy the full allocated storage including any ABI tail-padding bytes,
+  // which a field-by-field copy would silently skip. Preserving those bytes
+  // matters for SEQUENCE types whose storage is reinterpreted via EQUIVALENCE
+  // or TRANSFER.
+  mlir::Value fromAddr = fir::getBase(rhs);
+  mlir::Value toAddr = fir::getBase(lhs);
+  // Ensure we have raw ref<RecordType> pointers for fir.copy.
+  auto refTy = builder.getRefType(recTy);
+  if (fromAddr.getType() != refTy)
+    fromAddr = builder.createConvert(loc, refTy, fromAddr);
+  if (toAddr.getType() != refTy)
+    toAddr = builder.createConvert(loc, refTy, toAddr);
+  // disjoint == true at this point (guaranteed by the condition above).
+  fir::CopyOp::create(builder, loc, fromAddr, toAddr, /*noOverlap=*/true);
----------------
MattPD wrote:

`fir.copy` doesn't implement `FirAliasTagOpInterface` and its lowering doesn't pass alignment, so every simple derived-type assignment loses its TBAA tags and its alignment. `FIROps.td` records the missing interface as a TODO. For `type(t) :: x, y; x = y` between dummies at `-O2`, the parent emits `load i32, ptr %1, align 4, !tbaa !2` and `store ... align 4, !tbaa !8` with the per-dummy tags `dummy arg data/_QFs2Ey` and `dummy arg data/_QFs2Ex`. This branch emits `align 1` on both and the root `any data access` tag. Both losses are conservative, so the code is still correct. They also affect the OpenACC and OpenMP recipes and the CUDA paths changed by the patch. Do you have measurements of the two forms? If not, the description could list the TBAA and alignment loss as a known follow-up.

https://github.com/llvm/llvm-project/pull/223814


More information about the flang-commits mailing list