[flang-commits] [flang] [flang][cuda] Keep length parameters when boxing in data transfer conversion (PR #227883)

Valentin Clement バレンタイン クレメン via flang-commits flang-commits at lists.llvm.org
Wed Sep 30 14:48:11 PDT 2026


https://github.com/clementval created https://github.com/llvm/llvm-project/pull/227883

When lowering cuf.data_transfer, CUFOpConversion creates descriptors for
non-descriptor operands in emboxSrc, emboxDst and asHLFIREntity. The shape
was taken from the defining fir.declare/hlfir.declare, but the length type
parameters were dropped. For a character entity with a non-constant length
(e.g. an automatic `character(len=l) :: str(n)` assigned to a managed or
device array), this produced a fir.embox of !fir.char<1,?> without
typeparams, which later hit the `!lenParams.empty()` assertion in
EmboxCommonConversion::getCharacterByteSize during FIR to LLVM codegen.

Retrieve the type parameters from the declare alongside the shape and pass
them when creating the box. Lengths already present in the type are elided,
matching FirOpBuilder::createBox.

>From a1be843cbff2961fd129f73abbabb396b570e995 Mon Sep 17 00:00:00 2001
From: Valentin Clement <clementval at gmail.com>
Date: Wed, 30 Sep 2026 14:46:37 -0700
Subject: [PATCH] [flang][cuda] Keep length parameters when boxing in data
 transfer conversion

---
 .../Transforms/CUDA/CUFOpConversion.cpp       | 17 ++++++++++---
 .../Fir/CUDA/cuda-data-transfer-char-len.fir  | 24 +++++++++++++++++++
 2 files changed, 38 insertions(+), 3 deletions(-)
 create mode 100644 flang/test/Fir/CUDA/cuda-data-transfer-char-len.fir

diff --git a/flang/lib/Optimizer/Transforms/CUDA/CUFOpConversion.cpp b/flang/lib/Optimizer/Transforms/CUDA/CUFOpConversion.cpp
index 596368d94e434..b277dffee3ec0 100644
--- a/flang/lib/Optimizer/Transforms/CUDA/CUFOpConversion.cpp
+++ b/flang/lib/Optimizer/Transforms/CUDA/CUFOpConversion.cpp
@@ -161,6 +161,14 @@ static mlir::Value getShapeFromDecl(mlir::Value src) {
   return mlir::Value{};
 }
 
+static llvm::SmallVector<mlir::Value> getTypeParamsFromDecl(mlir::Value val) {
+  if (auto declareOp = val.getDefiningOp<fir::DeclareOp>())
+    return declareOp.getTypeparams();
+  if (auto declareOp = val.getDefiningOp<hlfir::DeclareOp>())
+    return declareOp.getTypeparams();
+  return {};
+}
+
 // hlfir.assign rejects a raw !fir.ref<!fir.array<?xT>> because a dynamic-size
 // array is not an HLFIR variable unless it is boxed. Use the transfer shape
 // (or a declare's shape) to build a descriptor.
@@ -173,7 +181,10 @@ static mlir::Value asHLFIREntity(mlir::PatternRewriter &rewriter,
   if (!shape)
     shape = getShapeFromDecl(val);
   auto boxTy = fir::BoxType::get(unwrapped);
-  return fir::EmboxOp::create(rewriter, loc, boxTy, val, shape);
+  return fir::EmboxOp::create(rewriter, loc, boxTy, val, shape,
+                              /*slice=*/mlir::Value{},
+                              fir::factory::elideLengthsAlreadyInType(
+                                  unwrapped, getTypeParamsFromDecl(val)));
 }
 
 static mlir::Value emboxSrc(mlir::PatternRewriter &rewriter,
@@ -212,7 +223,7 @@ static mlir::Value emboxSrc(mlir::PatternRewriter &rewriter,
   } else {
     addr = op.getSrc();
   }
-  llvm::SmallVector<mlir::Value> lenParams;
+  llvm::SmallVector<mlir::Value> lenParams = getTypeParamsFromDecl(op.getSrc());
   mlir::Type boxTy = fir::BoxType::get(srcTy);
   mlir::Value box =
       builder.createBox(loc, boxTy, addr, getShapeFromDecl(op.getSrc()),
@@ -232,7 +243,7 @@ static mlir::Value emboxDst(mlir::PatternRewriter &rewriter,
   mlir::Type dstTy = fir::unwrapRefType(op.getDst().getType());
   mlir::Value dstAddr = op.getDst();
   mlir::Type dstBoxTy = fir::BoxType::get(dstTy);
-  llvm::SmallVector<mlir::Value> lenParams;
+  llvm::SmallVector<mlir::Value> lenParams = getTypeParamsFromDecl(op.getDst());
   mlir::Value dstBox =
       builder.createBox(loc, dstBoxTy, dstAddr, getShapeFromDecl(op.getDst()),
                         /*slice=*/nullptr, lenParams,
diff --git a/flang/test/Fir/CUDA/cuda-data-transfer-char-len.fir b/flang/test/Fir/CUDA/cuda-data-transfer-char-len.fir
new file mode 100644
index 0000000000000..26d80e2013140
--- /dev/null
+++ b/flang/test/Fir/CUDA/cuda-data-transfer-char-len.fir
@@ -0,0 +1,24 @@
+// RUN: fir-opt --cuf-convert %s | FileCheck %s
+
+// Transfer from a dynamic-length character array into a descriptor. The
+// descriptor built for the source must carry the length parameter.
+
+module attributes {dlti.dl_spec = #dlti.dl_spec<#dlti.dl_entry<!llvm.ptr, dense<64> : vector<4xi64>>, #dlti.dl_entry<i64, dense<64> : vector<2xi64>>, #dlti.dl_entry<"dlti.endianness", "little">>, llvm.target_triple = "x86_64-unknown-linux-gnu"} {
+  func.func @_QPs(%arg0: !fir.ref<!fir.box<!fir.ptr<!fir.array<?x!fir.char<1,64>>>>> {cuf.data_attr = #cuf.cuda<managed>, fir.bindc_name = "p"}, %n: index, %l: i32) {
+    %c64 = arith.constant 64 : index
+    %p = fir.declare %arg0 typeparams %c64 {data_attr = #cuf.cuda<managed>, fortran_attrs = #fir.var_attrs<pointer>, uniq_name = "_QFsEp"} : (!fir.ref<!fir.box<!fir.ptr<!fir.array<?x!fir.char<1,64>>>>>, index) -> !fir.ref<!fir.box<!fir.ptr<!fir.array<?x!fir.char<1,64>>>>>
+    %mem = fir.allocmem !fir.array<?x!fir.char<1,?>>(%l : i32), %n {uniq_name = "_QFsEstr"}
+    %ref = fir.convert %mem : (!fir.heap<!fir.array<?x!fir.char<1,?>>>) -> !fir.ref<!fir.array<?x!fir.char<1,?>>>
+    %shape = fir.shape %n : (index) -> !fir.shape<1>
+    %str = fir.declare %ref(%shape) typeparams %l {uniq_name = "_QFsEstr"} : (!fir.ref<!fir.array<?x!fir.char<1,?>>>, !fir.shape<1>, i32) -> !fir.ref<!fir.array<?x!fir.char<1,?>>>
+    cuf.data_transfer %str to %p, %shape : !fir.shape<1> {transfer_kind = #cuf.cuda_transfer<host_device>} : !fir.ref<!fir.array<?x!fir.char<1,?>>>, !fir.ref<!fir.box<!fir.ptr<!fir.array<?x!fir.char<1,64>>>>>
+    fir.freemem %mem : !fir.heap<!fir.array<?x!fir.char<1,?>>>
+    return
+  }
+}
+
+// CHECK-LABEL: func.func @_QPs(
+// CHECK-SAME:    %{{.*}}: !fir.ref<!fir.box<!fir.ptr<!fir.array<?x!fir.char<1,64>>>>> {{.*}}, %{{.*}}: index, %[[L:.*]]: i32)
+// CHECK:         %[[STR:.*]] = fir.declare %{{.*}}(%[[SHAPE:.*]]) typeparams %[[L]]
+// CHECK:         fir.embox %[[STR]](%[[SHAPE]]) typeparams %[[L]] : (!fir.ref<!fir.array<?x!fir.char<1,?>>>, !fir.shape<1>, i32) -> !fir.box<!fir.array<?x!fir.char<1,?>>>
+// CHECK:         fir.call @_FortranACUFDataTransferDescDesc



More information about the flang-commits mailing list