[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:47:00 PDT 2026


llvmorg-github-actions[bot] wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-flang-fir-hlfir

Author: Matsu (khaki3)

<details>
<summary>Changes</summary>

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.

---
Full diff: https://github.com/llvm/llvm-project/pull/217076.diff


2 Files Affected:

- (modified) flang/lib/Lower/Bridge.cpp (+9-1) 
- (modified) flang/test/Lower/CUDA/cuda-managed-assign.cuf (+21) 


``````````diff
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

``````````

</details>


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


More information about the flang-commits mailing list