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

Reply via email to