Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 11 additions & 8 deletions flang/docs/Directives.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
2 changes: 1 addition & 1 deletion flang/lib/Lower/ConvertCall.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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=*/{}};
}
Expand Down
40 changes: 40 additions & 0 deletions flang/test/Lower/HLFIR/ignore-tkr-c-base-addr.f90
Original file line number Diff line number Diff line change
@@ -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)
!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 @_QPpass_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 @_QPpass_assumed_size(%[[CONV]]) {{.*}} : (!fir.ref<!fir.array<?xf32>>) -> ()
call pass_assumed_size(arr)
end subroutine

! CHECK: func.func private @_QPpass_assumed_size(!fir.ref<!fir.array<?xf32>>)
end module