[flang-commits] [flang] [flang][cuda] Assign a scalar character function result on the host (PR #217076)
via flang-commits
flang-commits at lists.llvm.org
Tue Aug 18 09:46:19 PDT 2026
https://github.com/khaki3 created https://github.com/llvm/llvm-project/pull/217076
A managed function result makes an assignment a cuf.data_transfer:
function f() result(r)
character(len=:), allocatable :: r ! managed under -gpu=mem:managed
end function
character(len=256) :: c
c = f()
The rank-0 result r is lowered to a !fir.boxchar<1>, an {address, length}
value rather than a reference, so the non-descriptor transfer path has no
address to take:
'fir.convert' op invalid type conversion '!fir.boxchar<1>' / '!fir.llvm_ptr<i8>'
A fixed-length result does have an address, but the copy is sized by the
character kind instead of the length: one character copied, c left unpadded.
Managed and unified results are host accessible, so assign a scalar character
result on the host and get the padding rules. Array results pass by
descriptor and are unaffected.
>From 027f6e9a567dc09be1657c91ee9a518ed2547a54 Mon Sep 17 00:00:00 2001
From: Kazuaki Matsumura <kmatsumura at nvidia.com>
Date: Tue, 18 Aug 2026 07:24:03 -0700
Subject: [PATCH] [flang][cuda] Assign a scalar character function result on
the host
Example:
```fortran
function c2f_string(cstr) result(r)
character(len=:), allocatable :: r ! managed under -gpu=mem:managed
end function
...
character(len=256) :: lookup_filename
lookup_filename = c2f_string(c_filename)
```
The managed function result turns this assignment into a cuf.data_transfer.
A scalar character is lowered to a !fir.boxchar<1>, an {address, length} value
rather than a descriptor in memory, so the non-descriptor transfer path has no
address to take and cuf-convert fails with "'fir.convert' op invalid type
conversion '!fir.boxchar<1>' / '!fir.llvm_ptr<i8>'". A fixed-length result does
provide an address, but the byte count is the character element size, so only
one character is copied and the destination is never padded.
Fix: keep a scalar character result a host assignment. Character array results
are unaffected: they are passed as a descriptor, so the runtime handles the
length adjustment.
---
flang/lib/Lower/Bridge.cpp | 10 ++++++++-
flang/test/Lower/CUDA/cuda-managed-assign.cuf | 21 +++++++++++++++++++
2 files changed, 30 insertions(+), 1 deletion(-)
diff --git a/flang/lib/Lower/Bridge.cpp b/flang/lib/Lower/Bridge.cpp
index bff6b51e50e18..d6d7b1838df58 100644
--- a/flang/lib/Lower/Bridge.cpp
+++ b/flang/lib/Lower/Bridge.cpp
@@ -5284,11 +5284,19 @@ class FirConverter : public Fortran::lower::AbstractConverter {
// attribute. Such a result may be produced by an asynchronous kernel, so
// consuming it in an assignment must be a synchronizing data transfer rather
// than a plain host assignment. A whole-allocatable left-hand side is
- // excluded: it has reallocation semantics and is performed on the host.
+ // excluded: it has reallocation semantics and is performed on the host, and
+ // so is a scalar character result: it carries its length outside of a
+ // descriptor, so a transfer would copy raw bytes instead of padding or
+ // truncating the destination.
bool
isCUDAFunctionResultTransfer(const Fortran::evaluate::Assignment &assign) {
if (Fortran::evaluate::IsAllocatableDesignator(assign.lhs))
return false;
+ if (assign.rhs.Rank() == 0)
+ if (std::optional<Fortran::evaluate::DynamicType> type{
+ assign.rhs.GetType()})
+ if (type->category() == Fortran::common::TypeCategory::Character)
+ return false;
const Fortran::evaluate::ProcedureRef *procRef =
Fortran::evaluate::UnwrapProcedureRef(assign.rhs);
if (!procRef)
diff --git a/flang/test/Lower/CUDA/cuda-managed-assign.cuf b/flang/test/Lower/CUDA/cuda-managed-assign.cuf
index 694555a173cf6..09bfcd5296c89 100644
--- a/flang/test/Lower/CUDA/cuda-managed-assign.cuf
+++ b/flang/test/Lower/CUDA/cuda-managed-assign.cuf
@@ -14,6 +14,15 @@ contains
allocate(r(n))
r = 7
end function
+ function frchar(n) result(r)
+ integer, value :: n
+ character(len=:), allocatable, managed :: r
+ allocate(character(len=n) :: r)
+ end function
+ function frcharfix() result(r)
+ character(len=4), allocatable, managed :: r
+ allocate(r)
+ end function
end module
! Assignments that are data transfers.
@@ -310,3 +319,15 @@ end subroutine
! CHECK-LABEL: func.func @_QPmanaged_component_attr_section_assign()
! CHECK-NOT: cuf.data_transfer
+
+! A scalar character result carries its length outside of a descriptor, so a
+! transfer would copy raw bytes instead of padding or truncating the destination.
+subroutine managed_char_func_result()
+ use mfr
+ character(len=16) :: h
+ h = frchar(4)
+ h = frcharfix()
+end subroutine
+
+! CHECK-LABEL: func.func @_QPmanaged_char_func_result()
+! CHECK-NOT: cuf.data_transfer
More information about the flang-commits
mailing list