[flang-commits] [flang] [flang] Fix ignore_tkr(c) passing descriptor instead of base address for non-descriptor dummies (PR #186894)

Valentin Clement バレンタイン クレメン via flang-commits flang-commits at lists.llvm.org
Mon Mar 16 17:02:09 PDT 2026


https://github.com/clementval updated https://github.com/llvm/llvm-project/pull/186894

>From 179b89bd5bd13b258a8ad86ee7c2fcff3085462e Mon Sep 17 00:00:00 2001
From: Valentin Clement <clementval at gmail.com>
Date: Mon, 16 Mar 2026 14:50:48 -0700
Subject: [PATCH 1/3] [flang] Fix ignore_tkr(c) passing descriptor instead of
 base address for non-descriptor dummies

---
 flang/lib/Lower/ConvertCall.cpp               |  2 +-
 .../Lower/HLFIR/ignore-tkr-c-base-addr.f90    | 40 +++++++++++++++++++
 2 files changed, 41 insertions(+), 1 deletion(-)
 create mode 100644 flang/test/Lower/HLFIR/ignore-tkr-c-base-addr.f90

diff --git a/flang/lib/Lower/ConvertCall.cpp b/flang/lib/Lower/ConvertCall.cpp
index d72f74b440c53..ae9d1733d053d 100644
--- a/flang/lib/Lower/ConvertCall.cpp
+++ b/flang/lib/Lower/ConvertCall.cpp
@@ -1349,7 +1349,7 @@ static PreparedDummyArgument preparePresentUserCallActualArgument(
   hlfir::Entity actual = preparedActual.getActual(loc, builder);
 
   if (arg.testTKR(Fortran::common::IgnoreTKR::Contiguous) &&
-      actual.isBoxAddress()) {
+      actual.isBoxAddress() && fir::isBoxAddressOrValue(dummyType)) {
     // With ignore_tkr(c), pointer to a descriptor should be passed as is
     return PreparedDummyArgument{actual, /*cleanups=*/{}};
   }
diff --git a/flang/test/Lower/HLFIR/ignore-tkr-c-base-addr.f90 b/flang/test/Lower/HLFIR/ignore-tkr-c-base-addr.f90
new file mode 100644
index 0000000000000..fc9905a49c83b
--- /dev/null
+++ b/flang/test/Lower/HLFIR/ignore-tkr-c-base-addr.f90
@@ -0,0 +1,40 @@
+! RUN: bbc -emit-hlfir -o - %s | FileCheck %s
+
+! Test that ignore_tkr(c) with a non-descriptor dummy (assumed-size) extracts
+! the base address from allocatable/pointer actual arguments instead of passing
+! the descriptor. This pattern is used by CUDA library interfaces like cuFFT.
+
+module m_ignore_tkr_c_base_addr
+  interface
+    subroutine pass_assumed_size(a) bind(c, name="pass_assumed_size")
+      !dir$ ignore_tkr(c) a
+      real :: a(*)
+    end subroutine
+  end interface
+contains
+  ! CHECK-LABEL: func.func @_QMm_ignore_tkr_c_base_addrPtest_allocatable(
+  ! CHECK-SAME: %[[ARR:.*]]: !fir.ref<!fir.box<!fir.heap<!fir.array<?xf32>>>>
+  subroutine test_allocatable(arr)
+    real, allocatable :: arr(:)
+    ! CHECK: %[[DECL:.*]]:2 = hlfir.declare %[[ARR]]
+    ! CHECK: %[[LOAD:.*]] = fir.load %[[DECL]]#0 : !fir.ref<!fir.box<!fir.heap<!fir.array<?xf32>>>>
+    ! CHECK: %[[ADDR:.*]] = fir.box_addr %[[LOAD]] : (!fir.box<!fir.heap<!fir.array<?xf32>>>) -> !fir.heap<!fir.array<?xf32>>
+    ! CHECK: %[[CONV:.*]] = fir.convert %[[ADDR]] : (!fir.heap<!fir.array<?xf32>>) -> !fir.ref<!fir.array<?xf32>>
+    ! CHECK: fir.call @pass_assumed_size(%[[CONV]]) {{.*}} : (!fir.ref<!fir.array<?xf32>>) -> ()
+    call pass_assumed_size(arr)
+  end subroutine
+
+  ! CHECK-LABEL: func.func @_QMm_ignore_tkr_c_base_addrPtest_pointer(
+  ! CHECK-SAME: %[[ARR:.*]]: !fir.ref<!fir.box<!fir.ptr<!fir.array<?xf32>>>>
+  subroutine test_pointer(arr)
+    real, pointer :: arr(:)
+    ! CHECK: %[[DECL:.*]]:2 = hlfir.declare %[[ARR]]
+    ! CHECK: %[[LOAD:.*]] = fir.load %[[DECL]]#0 : !fir.ref<!fir.box<!fir.ptr<!fir.array<?xf32>>>>
+    ! CHECK: %[[ADDR:.*]] = fir.box_addr %[[LOAD]] : (!fir.box<!fir.ptr<!fir.array<?xf32>>>) -> !fir.ptr<!fir.array<?xf32>>
+    ! CHECK: %[[CONV:.*]] = fir.convert %[[ADDR]] : (!fir.ptr<!fir.array<?xf32>>) -> !fir.ref<!fir.array<?xf32>>
+    ! CHECK: fir.call @pass_assumed_size(%[[CONV]]) {{.*}} : (!fir.ref<!fir.array<?xf32>>) -> ()
+    call pass_assumed_size(arr)
+  end subroutine
+
+  ! CHECK: func.func private @pass_assumed_size(!fir.ref<!fir.array<?xf32>>)
+end module

>From 44b0a50e94b7d5bebb85f42d3bfdf52b2491c85e Mon Sep 17 00:00:00 2001
From: Valentin Clement <clementval at gmail.com>
Date: Mon, 16 Mar 2026 16:59:54 -0700
Subject: [PATCH 2/3] Remove bind c as it is not necessary

---
 flang/test/Lower/HLFIR/ignore-tkr-c-base-addr.f90 | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/flang/test/Lower/HLFIR/ignore-tkr-c-base-addr.f90 b/flang/test/Lower/HLFIR/ignore-tkr-c-base-addr.f90
index fc9905a49c83b..e04e8d1a2140f 100644
--- a/flang/test/Lower/HLFIR/ignore-tkr-c-base-addr.f90
+++ b/flang/test/Lower/HLFIR/ignore-tkr-c-base-addr.f90
@@ -6,7 +6,7 @@
 
 module m_ignore_tkr_c_base_addr
   interface
-    subroutine pass_assumed_size(a) bind(c, name="pass_assumed_size")
+    subroutine pass_assumed_size(a)
       !dir$ ignore_tkr(c) a
       real :: a(*)
     end subroutine
@@ -20,7 +20,7 @@ subroutine test_allocatable(arr)
     ! CHECK: %[[LOAD:.*]] = fir.load %[[DECL]]#0 : !fir.ref<!fir.box<!fir.heap<!fir.array<?xf32>>>>
     ! CHECK: %[[ADDR:.*]] = fir.box_addr %[[LOAD]] : (!fir.box<!fir.heap<!fir.array<?xf32>>>) -> !fir.heap<!fir.array<?xf32>>
     ! CHECK: %[[CONV:.*]] = fir.convert %[[ADDR]] : (!fir.heap<!fir.array<?xf32>>) -> !fir.ref<!fir.array<?xf32>>
-    ! CHECK: fir.call @pass_assumed_size(%[[CONV]]) {{.*}} : (!fir.ref<!fir.array<?xf32>>) -> ()
+    ! CHECK: fir.call @_QPpass_assumed_size(%[[CONV]]) {{.*}} : (!fir.ref<!fir.array<?xf32>>) -> ()
     call pass_assumed_size(arr)
   end subroutine
 
@@ -32,9 +32,9 @@ subroutine test_pointer(arr)
     ! CHECK: %[[LOAD:.*]] = fir.load %[[DECL]]#0 : !fir.ref<!fir.box<!fir.ptr<!fir.array<?xf32>>>>
     ! CHECK: %[[ADDR:.*]] = fir.box_addr %[[LOAD]] : (!fir.box<!fir.ptr<!fir.array<?xf32>>>) -> !fir.ptr<!fir.array<?xf32>>
     ! CHECK: %[[CONV:.*]] = fir.convert %[[ADDR]] : (!fir.ptr<!fir.array<?xf32>>) -> !fir.ref<!fir.array<?xf32>>
-    ! CHECK: fir.call @pass_assumed_size(%[[CONV]]) {{.*}} : (!fir.ref<!fir.array<?xf32>>) -> ()
+    ! CHECK: fir.call @_QPpass_assumed_size(%[[CONV]]) {{.*}} : (!fir.ref<!fir.array<?xf32>>) -> ()
     call pass_assumed_size(arr)
   end subroutine
 
-  ! CHECK: func.func private @pass_assumed_size(!fir.ref<!fir.array<?xf32>>)
+  ! CHECK: func.func private @_QPpass_assumed_size(!fir.ref<!fir.array<?xf32>>)
 end module

>From 8322861b0189477b3c7105ace442cb4aa90ef034 Mon Sep 17 00:00:00 2001
From: Valentin Clement <clementval at gmail.com>
Date: Mon, 16 Mar 2026 17:01:55 -0700
Subject: [PATCH 3/3] Update doc

---
 flang/docs/Directives.md | 19 +++++++++++--------
 1 file changed, 11 insertions(+), 8 deletions(-)

diff --git a/flang/docs/Directives.md b/flang/docs/Directives.md
index 7080e5c5cf543..07ba5c25a1a78 100644
--- a/flang/docs/Directives.md
+++ b/flang/docs/Directives.md
@@ -18,15 +18,18 @@ A list of non-standard directives supported by Flang
   directive allow actual arguments that would otherwise be diagnosed as
   incompatible in type (T), kind (K), rank (R), CUDA device (D), or managed (M)
   status. The letter (A) is a shorthand for (TKRDM), and is the default when no
-  letters appear. The letter (C) checks for contiguity, for example allowing an
-  element of an assumed-shape array to be passed as a dummy argument. It also
-  specifies that dummy arguments passed by descriptor should not have their
-  descriptor copied or reboxed, allowing the original descriptor to be passed
+  letters appear.   The letter (C) checks for contiguity, for example allowing
+  an element of an assumed-shape array to be passed as a dummy argument. When
+  the dummy argument is passed by descriptor, (C) specifies that the descriptor
+  should not be copied or reboxed, allowing the original descriptor to be passed
   directly even if attributes like ALLOCATABLE or POINTER don't match exactly.
-  The letter (P) ignores pointer and allocatable matching, so that one can pass an
-  allocatable array to routine with pointer array argument and vice versa. For
-  example, if one wanted to call a "set all bytes to zero" utility that could
-  be applied to arrays of any type or rank:
+  When the dummy argument is not passed by descriptor (e.g., an assumed-size
+  array in a BIND(C) interface), the base address is extracted from the actual
+  argument's descriptor and passed as a raw pointer.
+  The letter (P) ignores pointer and allocatable matching, so that one can pass
+  an allocatable array to routine with pointer array argument and vice versa.
+  For example, if one wanted to call a "set all bytes to zero" utility that
+  could be applied to arrays of any type or rank:
 ```
   interface
     subroutine clear(arr,bytes)



More information about the flang-commits mailing list