Skip to content

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

Open
clementval wants to merge 3 commits intollvm:mainfrom
clementval:ignore_c_bindc
Open

[flang] Fix ignore_tkr(c) passing descriptor instead of base address for non-descriptor dummies#186894
clementval wants to merge 3 commits intollvm:mainfrom
clementval:ignore_c_bindc

Conversation

@clementval
Copy link
Contributor

When ignore_tkr(c) is set and the actual argument is an allocatable or pointer (stored as a descriptor), the lowering code was unconditionally returning the descriptor pointer as-is, regardless of whether the dummy argument expects a descriptor. For bind(c) interfaces with assumed-size dummies (e.g., cuFFT), the dummy expects a raw pointer, not a descriptor. Passing the descriptor caused the C function to receive the wrong address, leading to silent data corruption and invalid descriptor crashes at deallocation.

The fix adds a check that the early return for ignore_tkr(c) only applies when the dummy type is itself a descriptor type. When the dummy expects a base address, the normal path is taken, which correctly extracts the base address from the descriptor via fir.box_addr.

@llvmbot llvmbot added flang Flang issues not falling into any other category flang:fir-hlfir labels Mar 16, 2026
@llvmbot
Copy link
Member

llvmbot commented Mar 16, 2026

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

Author: Valentin Clement (バレンタイン クレメン) (clementval)

Changes

When ignore_tkr(c) is set and the actual argument is an allocatable or pointer (stored as a descriptor), the lowering code was unconditionally returning the descriptor pointer as-is, regardless of whether the dummy argument expects a descriptor. For bind(c) interfaces with assumed-size dummies (e.g., cuFFT), the dummy expects a raw pointer, not a descriptor. Passing the descriptor caused the C function to receive the wrong address, leading to silent data corruption and invalid descriptor crashes at deallocation.

The fix adds a check that the early return for ignore_tkr(c) only applies when the dummy type is itself a descriptor type. When the dummy expects a base address, the normal path is taken, which correctly extracts the base address from the descriptor via fir.box_addr.


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

2 Files Affected:

  • (modified) flang/lib/Lower/ConvertCall.cpp (+1-1)
  • (added) flang/test/Lower/HLFIR/ignore-tkr-c-base-addr.f90 (+40)
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

@vzakhari vzakhari requested a review from eugeneepshteyn March 16, 2026 22:00
Copy link
Contributor

@vzakhari vzakhari left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, but please wait for Eugene's review.

@eugeneepshteyn
Copy link
Contributor

You would also need to modify https://github.com/llvm/llvm-project/blob/main/flang/docs/Directives.md to describe the behavior change.

Copy link
Contributor

@eugeneepshteyn eugeneepshteyn left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Requesting a test tweak to remove bind(c) and documentation update, otherwise LGTM.

@clementval
Copy link
Contributor Author

Requesting a test tweak to remove bind(c) and documentation update, otherwise LGTM.

Done

Copy link
Contributor

@eugeneepshteyn eugeneepshteyn left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM. Thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

flang:fir-hlfir flang Flang issues not falling into any other category

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants