Hi,
Paul-Antoine Arras wrote:
This patch adds support for the `dispatch` construct and the
`adjust_args` clause to the Fortran front-end.
Handling of `adjust_args` across translation units is missing due
to PR115271.
First, can you add a run-time test?
[I think it helps to have at least one run-time test feature for every
major feature - as we had in the past e.g. C runtime tests and Fortran
compile time tests - but it turned out that some flags was not set,
causing the middle to ignore the feature completely ...]
* * *
The following gives an ICE after printing the error (error recovery):
module m
use iso_c_binding
implicit none (type, external)
contains
subroutine foo(x,y)
!$omp declare variant(bar) match ( construct = { dispatch } )
type(C_ptr), value :: x, y
end
subroutine bar(a,b)
type(C_ptr), value :: a, b
end
end
use m
! integer, target :: y, z ! OK
integer :: y, z ! ERROR shown but then gives an ICE in
resolve_omp_dispatch
!$omp dispatch device(5)
call foo(c_loc(y),c_loc(z))
end
* * *
The following seems to be valid but gives an error:
Error: argument list item ‘y’ in ‘need_device_ptr’ at (1) must be of
TYPE(C_PTR)
module m
use iso_c_binding
implicit none (type, external)
contains
subroutine foo(x,y)
!$omp declare variant(bar) match ( construct = { dispatch } )
adjust_args(nothing : x ) adjust_args(need_device_ptr : y )
type(C_ptr), value :: x, y
end
subroutine bar(a,b)
type(C_ptr), value :: a, b
end
end
It looks as if the type check is already done during parsing instead
of later during resolve_*.
* * *
A duplicate-argument error is missing for 'adjust_args(nothing : x ,x )'
and also for:
module m
use iso_c_binding
implicit none (type, external)
contains
subroutine foo(x,y)
type(C_ptr), value :: x, y
!$omp declare variant(bar) match ( construct = { dispatch } )
adjust_args(nothing : x ,y ) adjust_args(need_device_ptr : y )
end
subroutine bar(a,b)
type(C_ptr), value :: a, b ! OK
! integer :: a, b ! wrong type - works & diagnosed (if not ICEing)
end
end
I think you want to add a flag to 'u' in 'typedef struct
gfc_omp_namelist' - to set whether an OMP_ LIST_ADJUST_ARGS
is a needs-pointer one or (e.g. unset) a 'nothing' one.
And then also add 'nothing' items to the list.
* * *
The attached testcase shows that you mishandle Fortran calling
conventions (optional, value).
It works for the host (device == -1) but with real offloading,
it segfaults.
(There might be some lang hooks inside trans-openmp* to help
with this; best that you cross check what omp-low.cc does for
'use_device_ptr'.)
* * *
TODO: We need to handle 'type(C), dimension(:)' - but I wonder
whether that shouldn't be handled as part of 'use_device_addr'
and we need to check whether the spec has to be updated.
I filed the OpenMP lang-spec Issue #4443.
* * *
Just a side - no action needed:
We discussed that 'match' is required while 'adjust_args' is
optional.
In C, we had crashes because of a missing 'match' clause;
here it works:
7 | !$omp declare variant(bar) adjust_args(nothing : x ,x )
| 1
Error: an ‘adjust_args’ clause at (1) can only be specified if the
‘dispatch’ selector of the construct selector set appears in the ‘match’
clause
Likewise, I think the following error is fine:
7 | !$omp declare variant(bar)
| 1
Error: expected ‘match’ or ‘adjust_args’ at (1)
* * *
Otherwise it seems to be okay, but I need to reread it.
Thanks,
Tobias
module m
use iso_c_binding
implicit none (type, external)
type(c_ptr) :: ref1, ref2, ref3, ref4
contains
subroutine foo(v, w, x, y)
type(C_ptr) :: v, w, x, y
value :: w, y
optional :: x, y
!$omp declare variant(bar) match ( construct = { dispatch } ) &
!$omp& adjust_args(need_device_ptr : v, w, x, y )
stop 1 ! should not get called
end
subroutine bar(a, b, c, d)
type(C_ptr) :: a, b, c, d
value :: b, d
optional :: c, d
if (.not. c_associated (a, ref1)) stop 2
if (.not. c_associated (b, ref2)) stop 3
if (.not. c_associated (c, ref3)) stop 3
if (.not. c_associated (d, ref4)) stop 3
end
end
program main
use omp_lib
use m
implicit none (type, external)
integer, target :: a, b, c, d
type(c_ptr) :: v, w, y, z
integer :: dev
do dev = -1, omp_get_num_devices ()
print *, 'dev ', dev
! Cross check (1)
ref1 = omp_target_alloc (32_c_size_t, dev)
ref2 = omp_target_alloc (32_c_size_t, dev)
ref3 = omp_target_alloc (32_c_size_t, dev)
ref4 = omp_target_alloc (32_c_size_t, dev)
call bar (ref1, ref2, ref3, ref4)
call omp_target_free (ref1, dev)
call omp_target_free (ref2, dev)
call omp_target_free (ref3, dev)
call omp_target_free (ref4, dev)
v = c_loc(a)
w = c_loc(b)
y = c_loc(b)
z = c_loc(b)
!$omp target enter data device(dev) map(a, b, c, d)
! Cross check (2)
! This should be effectively identical to 'dispatch'
!$omp target data device(dev) use_device_ptr(v, w, y, z)
ref1 = v
ref2 = w
ref3 = y
ref4 = z
call bar (v, w, y, z)
!$omp end target data
!$omp dispatch device(dev)
call foo (v, w, y, z)
!$omp target exit data device(dev) map(a, b, c, d)
end do
end