diff mbox series

[8/9,OpenACC] Fix standalone attach for Fortran assumed-shape array pointers

Message ID 0193ff08d4a4a2b6ca86c7a891b8ff35203fa440.1592343757.git.julian@codesourcery.com
State New
Headers show
Series Refcounting and manual deep copy improvements | expand

Commit Message

Julian Brown June 16, 2020, 10:39 p.m. UTC
As mentioned in the blurb for the previous patch, an "attach" operation
for a Fortran pointer with an array descriptor must copy that array
descriptor to the target.  This patch arranges for that to be so.

OK?

Julian

ChangeLog

	gcc/fortran/
	* trans-openmp.c (gfc_trans_omp_clauses): Copy array descriptor to
	target for attach clauses when appropriate.

	libgomp/
	* testsuite/libgomp.oacc-fortran/attach-descriptor-1.f90: New test.
---
 gcc/fortran/trans-openmp.c                    | 40 ++++++++++++++-
 .../attach-descriptor-1.f90                   | 51 +++++++++++++++++++
 2 files changed, 89 insertions(+), 2 deletions(-)
 create mode 100644 libgomp/testsuite/libgomp.oacc-fortran/attach-descriptor-1.f90

Comments

Thomas Schwinge July 14, 2020, 11:43 a.m. UTC | #1
Hi Julian, Tobias!

On 2020-06-16T15:39:44-0700, Julian Brown <julian@codesourcery.com> wrote:
> As mentioned in the blurb for the previous patch, an "attach" operation
> for a Fortran pointer with an array descriptor must copy that array
> descriptor to the target.

Heh, I see -- I don't think I had read the OpenACC standard in that way,
but I think I agree your interpretation is fine.

This does not create some sort of memory leak -- everything implicitly
allocated there will eventually be deallocated again, right?

> This patch arranges for that to be so.

In response to the new OpenACC/Fortran testcase that I'd submtited in
<http://mid.mail-archive.com/87wo3co0tm.fsf@euler.schwinge.homeip.net>,
you (Julian) correctly supposed in
<http://mid.mail-archive.com/20200709223246.23a4d0e0@squid.athome>, that
this patch indeed does resolve that testcase, too.  That wasn't obvious
to me.  So, similar to
'libgomp/testsuite/libgomp.oacc-c-c++-common/pr95270-{1.2}.c', please
include my new OpenACC/Fortran testcase (if that makes sense to you), and
reference PR95270 in the commit log.

> OK?

Basically yes (for master and releases/gcc-10 branches), but please
consider the following:

> --- a/gcc/fortran/trans-openmp.c
> +++ b/gcc/fortran/trans-openmp.c
> @@ -2573,8 +2573,44 @@ gfc_trans_omp_clauses (stmtblock_t *block, gfc_omp_clauses *clauses,
>                       }
>                   }
>                 if (GFC_DESCRIPTOR_TYPE_P (TREE_TYPE (decl))
> -                   && n->u.map_op != OMP_MAP_ATTACH
> -                   && n->u.map_op != OMP_MAP_DETACH)
> +                   && (n->u.map_op == OMP_MAP_ATTACH
> +                       || n->u.map_op == OMP_MAP_DETACH))
> +                 {
> +                   tree type = TREE_TYPE (decl);
> +                   tree data = gfc_conv_descriptor_data_get (decl);
> +                   if (present)
> +                     data = gfc_build_cond_assign_expr (block, present,
> +                                                        data,
> +                                                        null_pointer_node);
> +                   tree ptr
> +                     = fold_convert (build_pointer_type (char_type_node),
> +                                     data);
> +                   ptr = build_fold_indirect_ref (ptr);
> +                   /* Standalone attach clauses used with arrays with
> +                      descriptors must copy the descriptor to the target,
> +                      else they won't have anything to perform the
> +                      attachment onto (see OpenACC 2.6, "2.6.3. Data
> +                      Structures with Pointers").  */
> +                   OMP_CLAUSE_DECL (node) = ptr;
> +                   node2 = build_omp_clause (input_location, OMP_CLAUSE_MAP);
> +                   OMP_CLAUSE_SET_MAP_KIND (node2, GOMP_MAP_TO_PSET);
> +                   OMP_CLAUSE_DECL (node2) = decl;
> +                   OMP_CLAUSE_SIZE (node2) = TYPE_SIZE_UNIT (type);
> +                   node3 = build_omp_clause (input_location, OMP_CLAUSE_MAP);
> +                   if (n->u.map_op == OMP_MAP_ATTACH)
> +                     {
> +                       OMP_CLAUSE_SET_MAP_KIND (node3, GOMP_MAP_ATTACH);
> +                       n->u.map_op = OMP_MAP_ALLOC;
> +                     }
> +                   else  /* OMP_MAP_DETACH.  */
> +                     {
> +                       OMP_CLAUSE_SET_MAP_KIND (node3, GOMP_MAP_DETACH);
> +                       n->u.map_op = OMP_MAP_RELEASE;
> +                     }
> +                   OMP_CLAUSE_DECL (node3) = data;
> +                   OMP_CLAUSE_SIZE (node3) = size_int (0);
> +                 }

So this ("case A") duplicates most of the code from...

> +               else if (GFC_DESCRIPTOR_TYPE_P (TREE_TYPE (decl)))
>                   {
>                     [...]

... this existing case here ("case B").  It's not clear to me if these
two cases really still need to be handled separately, and a little bit
differently (regarding 'if (present)' handling, for example), or if they
could/should (?) be merged?  Tobias, do you have an opinion?

Do we have sufficient testsuite coverage?  (For example,
'attach'/'detach' with 'present == false', if that makes sense, or any
other thing that case A is doing differently from case B?)  Shouldn't
this get '-fdump-tree-original' and/or '-fdump-tree-gimple' testcases,
similar to 'gfortran.dg/goacc/finalize-1.f', so that we verify/document
what we generate here?


> --- /dev/null
> +++ b/libgomp/testsuite/libgomp.oacc-fortran/attach-descriptor-1.f90
> @@ -0,0 +1,51 @@
> +program att

Please add 'dg-do run', and...

> +  use openacc
> +  implicit none
> +  type t
> +    integer :: arr1(10)
> +    integer, allocatable :: arr2(:)
> +  end type t
> +  integer :: i
> +  type(t) :: myvar
> +  integer, target :: tarr(10)
> +  integer, pointer :: myptr(:)
> +
> +  allocate(myvar%arr2(10))
> +
> +  do i=1,10
> +    myvar%arr1(i) = 0
> +    myvar%arr2(i) = 0
> +    tarr(i) = 0
> +  end do
> +
> +  call acc_copyin(myvar)
> +  call acc_copyin(myvar%arr2)
> +  call acc_copyin(tarr)
> +
> +  myptr => tarr
> +
> +  !$acc enter data attach(myvar%arr2, myptr)
> +
> +  ! FIXME: This warning is emitted on the wrong line number.
> +  ! { dg-warning "using vector_length \\(32\\), ignoring 1" "" { target openacc_nvidia_accel_selected } 36 }

... don't forget to adjust "36" here.  ;-)

> +  !$acc serial present(myvar%arr2)
> +  do i=1,10
> +    myvar%arr1(i) = i
> +    myvar%arr2(i) = i
> +  end do
> +  myptr(3) = 99
> +  !$acc end serial
> +
> +  !$acc exit data detach(myvar%arr2, myptr)
> +
> +  call acc_copyout(myvar%arr2)
> +  call acc_copyout(myvar)
> +  call acc_copyout(tarr)
> +
> +  do i=1,10
> +    if (myvar%arr1(i) .ne. i) stop 1
> +    if (myvar%arr2(i) .ne. i) stop 2
> +  end do
> +  if (tarr(3) .ne. 99) stop 3
> +
> +end program att


Grüße
 Thomas
-----------------
Mentor Graphics (Deutschland) GmbH, Arnulfstraße 201, 80634 München / Germany
Registergericht München HRB 106955, Geschäftsführer: Thomas Heurung, Alexander Walter
Thomas Schwinge July 15, 2020, 10:28 a.m. UTC | #2
Hi Julian, Tobias!

On 2020-07-14T13:43:37+0200, I wrote:
> On 2020-06-16T15:39:44-0700, Julian Brown <julian@codesourcery.com> wrote:
>> As mentioned in the blurb for the previous patch, an "attach" operation
>> for a Fortran pointer with an array descriptor must copy that array
>> descriptor to the target.
>
> Heh, I see -- I don't think I had read the OpenACC standard in that way,
> but I think I agree your interpretation is fine.
>
> This does not create some sort of memory leak -- everything implicitly
> allocated there will eventually be deallocated again, right?
>
>> This patch arranges for that to be so.
>
> In response to the new OpenACC/Fortran testcase that I'd submtited in
> <http://mid.mail-archive.com/87wo3co0tm.fsf@euler.schwinge.homeip.net>,
> you (Julian) correctly supposed in
> <http://mid.mail-archive.com/20200709223246.23a4d0e0@squid.athome>, that
> this patch indeed does resolve that testcase, too.  That wasn't obvious
> to me.  So, similar to
> 'libgomp/testsuite/libgomp.oacc-c-c++-common/pr95270-{1.2}.c', please
> include my new OpenACC/Fortran testcase (if that makes sense to you), and
> reference PR95270 in the commit log.

My new OpenACC/Fortran testcase got again broken ('libgomp: pointer
target not mapped for attach') by Tobias' commit
102502e32ea4e8a75d6b252ba319d09d735d9aa7 "[OpenMP, Fortran] Add
structure/derived-type element mapping",
<http://mid.mail-archive.com/c5b43e02-d1d5-e7cf-c11c-6daf1e8f33c5@codesourcery.com>.

Similar ('libgomp: attempt to attach null pointer') for your new
'libgomp.oacc-fortran/attach-descriptor-1.f90'.

(Whether or not 'attach'ing 'NULL' should actually be allowed, is a
separate topic for discussion.)

So this patch here will (obviously) need to be adapted to what Tobias
changed.  (Plus my more general questions quoted above and below.)


Grüße
 Thomas


>> OK?
>
> Basically yes (for master and releases/gcc-10 branches), but please
> consider the following:
>
>> --- a/gcc/fortran/trans-openmp.c
>> +++ b/gcc/fortran/trans-openmp.c
>> @@ -2573,8 +2573,44 @@ gfc_trans_omp_clauses (stmtblock_t *block, gfc_omp_clauses *clauses,
>>                      }
>>                  }
>>                if (GFC_DESCRIPTOR_TYPE_P (TREE_TYPE (decl))
>> -                  && n->u.map_op != OMP_MAP_ATTACH
>> -                  && n->u.map_op != OMP_MAP_DETACH)
>> +                  && (n->u.map_op == OMP_MAP_ATTACH
>> +                      || n->u.map_op == OMP_MAP_DETACH))
>> +                {
>> +                  tree type = TREE_TYPE (decl);
>> +                  tree data = gfc_conv_descriptor_data_get (decl);
>> +                  if (present)
>> +                    data = gfc_build_cond_assign_expr (block, present,
>> +                                                       data,
>> +                                                       null_pointer_node);
>> +                  tree ptr
>> +                    = fold_convert (build_pointer_type (char_type_node),
>> +                                    data);
>> +                  ptr = build_fold_indirect_ref (ptr);
>> +                  /* Standalone attach clauses used with arrays with
>> +                     descriptors must copy the descriptor to the target,
>> +                     else they won't have anything to perform the
>> +                     attachment onto (see OpenACC 2.6, "2.6.3. Data
>> +                     Structures with Pointers").  */
>> +                  OMP_CLAUSE_DECL (node) = ptr;
>> +                  node2 = build_omp_clause (input_location, OMP_CLAUSE_MAP);
>> +                  OMP_CLAUSE_SET_MAP_KIND (node2, GOMP_MAP_TO_PSET);
>> +                  OMP_CLAUSE_DECL (node2) = decl;
>> +                  OMP_CLAUSE_SIZE (node2) = TYPE_SIZE_UNIT (type);
>> +                  node3 = build_omp_clause (input_location, OMP_CLAUSE_MAP);
>> +                  if (n->u.map_op == OMP_MAP_ATTACH)
>> +                    {
>> +                      OMP_CLAUSE_SET_MAP_KIND (node3, GOMP_MAP_ATTACH);
>> +                      n->u.map_op = OMP_MAP_ALLOC;
>> +                    }
>> +                  else  /* OMP_MAP_DETACH.  */
>> +                    {
>> +                      OMP_CLAUSE_SET_MAP_KIND (node3, GOMP_MAP_DETACH);
>> +                      n->u.map_op = OMP_MAP_RELEASE;
>> +                    }
>> +                  OMP_CLAUSE_DECL (node3) = data;
>> +                  OMP_CLAUSE_SIZE (node3) = size_int (0);
>> +                }
>
> So this ("case A") duplicates most of the code from...
>
>> +              else if (GFC_DESCRIPTOR_TYPE_P (TREE_TYPE (decl)))
>>                  {
>>                    [...]
>
> ... this existing case here ("case B").  It's not clear to me if these
> two cases really still need to be handled separately, and a little bit
> differently (regarding 'if (present)' handling, for example), or if they
> could/should (?) be merged?  Tobias, do you have an opinion?
>
> Do we have sufficient testsuite coverage?  (For example,
> 'attach'/'detach' with 'present == false', if that makes sense, or any
> other thing that case A is doing differently from case B?)  Shouldn't
> this get '-fdump-tree-original' and/or '-fdump-tree-gimple' testcases,
> similar to 'gfortran.dg/goacc/finalize-1.f', so that we verify/document
> what we generate here?
>
>
>> --- /dev/null
>> +++ b/libgomp/testsuite/libgomp.oacc-fortran/attach-descriptor-1.f90
>> @@ -0,0 +1,51 @@
>> +program att
>
> Please add 'dg-do run', and...
>
>> +  use openacc
>> +  implicit none
>> +  type t
>> +    integer :: arr1(10)
>> +    integer, allocatable :: arr2(:)
>> +  end type t
>> +  integer :: i
>> +  type(t) :: myvar
>> +  integer, target :: tarr(10)
>> +  integer, pointer :: myptr(:)
>> +
>> +  allocate(myvar%arr2(10))
>> +
>> +  do i=1,10
>> +    myvar%arr1(i) = 0
>> +    myvar%arr2(i) = 0
>> +    tarr(i) = 0
>> +  end do
>> +
>> +  call acc_copyin(myvar)
>> +  call acc_copyin(myvar%arr2)
>> +  call acc_copyin(tarr)
>> +
>> +  myptr => tarr
>> +
>> +  !$acc enter data attach(myvar%arr2, myptr)
>> +
>> +  ! FIXME: This warning is emitted on the wrong line number.
>> +  ! { dg-warning "using vector_length \\(32\\), ignoring 1" "" { target openacc_nvidia_accel_selected } 36 }
>
> ... don't forget to adjust "36" here.  ;-)
>
>> +  !$acc serial present(myvar%arr2)
>> +  do i=1,10
>> +    myvar%arr1(i) = i
>> +    myvar%arr2(i) = i
>> +  end do
>> +  myptr(3) = 99
>> +  !$acc end serial
>> +
>> +  !$acc exit data detach(myvar%arr2, myptr)
>> +
>> +  call acc_copyout(myvar%arr2)
>> +  call acc_copyout(myvar)
>> +  call acc_copyout(tarr)
>> +
>> +  do i=1,10
>> +    if (myvar%arr1(i) .ne. i) stop 1
>> +    if (myvar%arr2(i) .ne. i) stop 2
>> +  end do
>> +  if (tarr(3) .ne. 99) stop 3
>> +
>> +end program att
>
>
> Grüße
>  Thomas
-----------------
Mentor Graphics (Deutschland) GmbH, Arnulfstraße 201, 80634 München / Germany
Registergericht München HRB 106955, Geschäftsführer: Thomas Heurung, Alexander Walter
Thomas Schwinge July 17, 2020, 11:16 a.m. UTC | #3
Hi Julian, Tobias!

On 2020-07-15T12:28:42+0200, Thomas Schwinge <thomas@codesourcery.com> wrote:
> On 2020-07-14T13:43:37+0200, I wrote:
>> On 2020-06-16T15:39:44-0700, Julian Brown <julian@codesourcery.com> wrote:
>>> As mentioned in the blurb for the previous patch, an "attach" operation
>>> for a Fortran pointer with an array descriptor must copy that array
>>> descriptor to the target.
>>
>> Heh, I see -- I don't think I had read the OpenACC standard in that way,
>> but I think I agree your interpretation is fine.
>>
>> This does not create some sort of memory leak -- everything implicitly
>> allocated there will eventually be deallocated again, right?

Unanswered -- but I may now have found this problem, and also found "the
reverse problem" ('finalize'); see below.

>>> This patch arranges for that to be so.
>>
>> In response to the new OpenACC/Fortran testcase that I'd submtited in
>> <http://mid.mail-archive.com/87wo3co0tm.fsf@euler.schwinge.homeip.net>,
>> you (Julian) correctly supposed in
>> <http://mid.mail-archive.com/20200709223246.23a4d0e0@squid.athome>, that
>> this patch indeed does resolve that testcase, too.  That wasn't obvious
>> to me.  So, similar to
>> 'libgomp/testsuite/libgomp.oacc-c-c++-common/pr95270-{1.2}.c', please
>> include my new OpenACC/Fortran testcase (if that makes sense to you), and
>> reference PR95270 in the commit log.
>
> My new OpenACC/Fortran testcase got again broken ('libgomp: pointer
> target not mapped for attach') by Tobias' commit
> 102502e32ea4e8a75d6b252ba319d09d735d9aa7 "[OpenMP, Fortran] Add
> structure/derived-type element mapping",
> <http://mid.mail-archive.com/c5b43e02-d1d5-e7cf-c11c-6daf1e8f33c5@codesourcery.com>.
>
> Similar ('libgomp: attempt to attach null pointer') for your new
> 'libgomp.oacc-fortran/attach-descriptor-1.f90'.
>
> (Whether or not 'attach'ing 'NULL' should actually be allowed, is a
> separate topic for discussion.)
>
> So this patch here will (obviously) need to be adapted to what Tobias
> changed.

I see what you pushed in commit 39dda0020801045d9a604575b2a2593c05310015
"openacc: Fix standalone attach for Fortran assumed-shape array pointers"
indeed has become much smaller/simpler.  :-)

(But, (parts of?) Tobias' commit mentioned above (plus commit
524862db444b6544c6dc87c5f06f351100ecf50d "Fix goacc/finalize-1.f tree
dump-scanning for -m32", if applicable) will then also need to be
backported to releases/gcc-10 branch (once un-frozen).)

> (Plus my more general questions quoted above and below.)

>>> OK?
>>
>> Basically yes (for master and releases/gcc-10 branches), but please
>> consider the following:
>>
>>> --- a/gcc/fortran/trans-openmp.c
>>> +++ b/gcc/fortran/trans-openmp.c
>>> @@ -2573,8 +2573,44 @@ gfc_trans_omp_clauses (stmtblock_t *block, gfc_omp_clauses *clauses,
>>>                     }
>>>                 }
>>>               if (GFC_DESCRIPTOR_TYPE_P (TREE_TYPE (decl))
>>> -                 && n->u.map_op != OMP_MAP_ATTACH
>>> -                 && n->u.map_op != OMP_MAP_DETACH)
>>> +                 && (n->u.map_op == OMP_MAP_ATTACH
>>> +                     || n->u.map_op == OMP_MAP_DETACH))
>>> +               {
>>> +                 tree type = TREE_TYPE (decl);
>>> +                 tree data = gfc_conv_descriptor_data_get (decl);
>>> +                 if (present)
>>> +                   data = gfc_build_cond_assign_expr (block, present,
>>> +                                                      data,
>>> +                                                      null_pointer_node);
>>> +                 tree ptr
>>> +                   = fold_convert (build_pointer_type (char_type_node),
>>> +                                   data);
>>> +                 ptr = build_fold_indirect_ref (ptr);
>>> +                 /* Standalone attach clauses used with arrays with
>>> +                    descriptors must copy the descriptor to the target,
>>> +                    else they won't have anything to perform the
>>> +                    attachment onto (see OpenACC 2.6, "2.6.3. Data
>>> +                    Structures with Pointers").  */
>>> +                 OMP_CLAUSE_DECL (node) = ptr;
>>> +                 node2 = build_omp_clause (input_location, OMP_CLAUSE_MAP);
>>> +                 OMP_CLAUSE_SET_MAP_KIND (node2, GOMP_MAP_TO_PSET);
>>> +                 OMP_CLAUSE_DECL (node2) = decl;
>>> +                 OMP_CLAUSE_SIZE (node2) = TYPE_SIZE_UNIT (type);
>>> +                 node3 = build_omp_clause (input_location, OMP_CLAUSE_MAP);
>>> +                 if (n->u.map_op == OMP_MAP_ATTACH)
>>> +                   {
>>> +                     OMP_CLAUSE_SET_MAP_KIND (node3, GOMP_MAP_ATTACH);
>>> +                     n->u.map_op = OMP_MAP_ALLOC;
>>> +                   }
>>> +                 else  /* OMP_MAP_DETACH.  */
>>> +                   {
>>> +                     OMP_CLAUSE_SET_MAP_KIND (node3, GOMP_MAP_DETACH);
>>> +                     n->u.map_op = OMP_MAP_RELEASE;
>>> +                   }
>>> +                 OMP_CLAUSE_DECL (node3) = data;
>>> +                 OMP_CLAUSE_SIZE (node3) = size_int (0);
>>> +               }
>>
>> So this ("case A") duplicates most of the code from...
>>
>>> +             else if (GFC_DESCRIPTOR_TYPE_P (TREE_TYPE (decl)))
>>>                 {
>>>                   [...]
>>
>> ... this existing case here ("case B").  It's not clear to me if these
>> two cases really still need to be handled separately, and a little bit
>> differently (regarding 'if (present)' handling, for example), or if they
>> could/should (?) be merged?  Tobias, do you have an opinion?

(These have been merged.)

>> Do we have sufficient testsuite coverage?  (For example,
>> 'attach'/'detach' with 'present == false', if that makes sense, or any
>> other thing that case A is doing differently from case B?)

(I'm not sure we're actually testing all relevant cases.)

>> Shouldn't
>> this get '-fdump-tree-original' and/or '-fdump-tree-gimple' testcases,
>> similar to 'gfortran.dg/goacc/finalize-1.f', so that we verify/document
>> what we generate here?

So I guess I had -- unconsciously? ;-) -- mentioned -fdump-tree-gimple'
and 'gfortran.dg/goacc/finalize-1.f' for a reason.  That displays how the
'finalize' clause is implemented (see WIP patch attached,
'gfortran.dg/goacc/attach-descriptor.f90'), and...

>>> --- /dev/null
>>> +++ b/libgomp/testsuite/libgomp.oacc-fortran/attach-descriptor-1.f90
>>> @@ -0,0 +1,51 @@
>>> +program att
>>
>> Please add 'dg-do run', and...
>>
>>> +  use openacc
>>> +  implicit none
>>> +  type t
>>> +    integer :: arr1(10)
>>> +    integer, allocatable :: arr2(:)
>>> +  end type t
>>> +  integer :: i
>>> +  type(t) :: myvar
>>> +  integer, target :: tarr(10)
>>> +  integer, pointer :: myptr(:)
>>> +
>>> +  allocate(myvar%arr2(10))
>>> +
>>> +  do i=1,10
>>> +    myvar%arr1(i) = 0
>>> +    myvar%arr2(i) = 0
>>> +    tarr(i) = 0
>>> +  end do
>>> +
>>> +  call acc_copyin(myvar)
>>> +  call acc_copyin(myvar%arr2)
>>> +  call acc_copyin(tarr)
>>> +
>>> +  myptr => tarr
>>> +
>>> +  !$acc enter data attach(myvar%arr2, myptr)
>>> +
>>> +  ! FIXME: This warning is emitted on the wrong line number.
>>> +  ! { dg-warning "using vector_length \\(32\\), ignoring 1" "" { target openacc_nvidia_accel_selected } 36 }
>>
>> ... don't forget to adjust "36" here.  ;-)
>>
>>> +  !$acc serial present(myvar%arr2)
>>> +  do i=1,10
>>> +    myvar%arr1(i) = i
>>> +    myvar%arr2(i) = i
>>> +  end do
>>> +  myptr(3) = 99
>>> +  !$acc end serial
>>> +
>>> +  !$acc exit data detach(myvar%arr2, myptr)

..., if we here 'detach' with 'finalize' added, that will turn into a
'delete' (instead of 'release') of 'myptr => tarr', and thus...

>>> +
>>> +  call acc_copyout(myvar%arr2)
>>> +  call acc_copyout(myvar)
>>> +  call acc_copyout(tarr)
>>> +
>>> +  do i=1,10
>>> +    if (myvar%arr1(i) .ne. i) stop 1
>>> +    if (myvar%arr2(i) .ne. i) stop 2
>>> +  end do
>>> +  if (tarr(3) .ne. 99) stop 3

..., here we won't see the updated 'tarr(3) == 99', and fail.

>>> +
>>> +end program att

Alternativly, we can show the problem with 'acc_is_present', as in my WIP
patch attached, 'libgomp.oacc-fortran/attach-descriptor-1__.f90'.  (But
when experimenting with 'acc_is_present' and Fortran 'pointer's, beware
of PR96080 "OpenACC/Fortran runtime library routines vs. Fortran
'pointer'".)

What should happen in this case?  Do we agree that 'exit data
detach(myptr)' should *never* unmap 'myptr => tarr', but really should
just unmap the 'myptr' array descriptor?

We can add special handling so that for standalone 'detach', a 'finalize'
doesn't turn 'release' into 'delete', but that doesn't feel like the
correct solution.

Also, we have a different -- bigger? -- problem: if we, for example,
'attach(myptr)' twice, that operation will include twice times
incrementing the reference count of 'myptr => tarr', and that'll then
conflict with a 'copyout(myptr)', as that one then sees unexpected
reference counts.  That's a different variant of the "[OpenACC] Deep copy
attach/detach should not affect reference counts" problem?

Basically (see WIP patch attached,
'libgomp.oacc-fortran/attach-descriptor-1_.f90'):

    call acc_copyin(tarr) ! 'rc(tarr) == 1'
    myptr => tarr
    !$acc enter data attach(myptr) ! 'rc(tarr) == 2'! (not intended by the user)
    !$acc enter data attach(myptr) ! 'rc(tarr) == 3'! (not intended by the user)
    [...]
    call acc_copyout(tarr) ! won't copyout, because still 'rc(tarr) = 2'! (not intended by the user)
    if (acc_is_present(tarr)) stop 12 ! fails

Ugh.  :-( Or am I confused now?


Grüße
 Thomas


-----------------
Mentor Graphics (Deutschland) GmbH, Arnulfstraße 201, 80634 München / Germany
Registergericht München HRB 106955, Geschäftsführer: Thomas Heurung, Alexander Walter
Julian Brown July 27, 2020, 2:33 p.m. UTC | #4
On Fri, 17 Jul 2020 13:16:11 +0200
Thomas Schwinge <thomas@codesourcery.com> wrote:

> Hi Julian, Tobias!
> 
> On 2020-07-15T12:28:42+0200, Thomas Schwinge
> <thomas@codesourcery.com> wrote:
> > On 2020-07-14T13:43:37+0200, I wrote:  
> >> On 2020-06-16T15:39:44-0700, Julian Brown
> >> <julian@codesourcery.com> wrote:  
> >>> As mentioned in the blurb for the previous patch, an "attach"
> >>> operation for a Fortran pointer with an array descriptor must
> >>> copy that array descriptor to the target.  
> >>
> >> Heh, I see -- I don't think I had read the OpenACC standard in
> >> that way, but I think I agree your interpretation is fine.
> >>
> >> This does not create some sort of memory leak -- everything
> >> implicitly allocated there will eventually be deallocated again,
> >> right?  
> 
> Unanswered -- but I may now have found this problem, and also found
> "the reverse problem" ('finalize'); see below.

Sorry, I didn't answer this explicitly -- the idea was to pair alloc
(present) and release mappings for the pointed-to data. In that way,
the idea was for the release mapping to perform that deallocation. That
was partly done so that the existing handling in gfc_trans_omp_clauses
could be used for this case without too much disruption to the code --
but actually, after Tobias's reorganisation of that function, that's
not really so much of an issue any more.

You can still get a "leak" if you try to attach a synthesized/temporary
array descriptor that goes out of scope before the pointed-to data it
refers to does -- that's a problem I've mentioned earlier, and is
kind-of unavoidable unless we do some more sophisticated analysis to
diagnose it as user error.

> >>> This patch arranges for that to be so.  
> >>
> >> In response to the new OpenACC/Fortran testcase that I'd submtited
> >> in
> >> <http://mid.mail-archive.com/87wo3co0tm.fsf@euler.schwinge.homeip.net>,
> >> you (Julian) correctly supposed in
> >> <http://mid.mail-archive.com/20200709223246.23a4d0e0@squid.athome>,
> >> that this patch indeed does resolve that testcase, too.  That
> >> wasn't obvious to me.  So, similar to
> >> 'libgomp/testsuite/libgomp.oacc-c-c++-common/pr95270-{1.2}.c',
> >> please include my new OpenACC/Fortran testcase (if that makes
> >> sense to you), and reference PR95270 in the commit log.  
> >
> > My new OpenACC/Fortran testcase got again broken ('libgomp: pointer
> > target not mapped for attach') by Tobias' commit
> > 102502e32ea4e8a75d6b252ba319d09d735d9aa7 "[OpenMP, Fortran] Add
> > structure/derived-type element mapping",
> > <http://mid.mail-archive.com/c5b43e02-d1d5-e7cf-c11c-6daf1e8f33c5@codesourcery.com>.
> >
> > Similar ('libgomp: attempt to attach null pointer') for your new
> > 'libgomp.oacc-fortran/attach-descriptor-1.f90'.
> >
> > (Whether or not 'attach'ing 'NULL' should actually be allowed, is a
> > separate topic for discussion.)
> >
> > So this patch here will (obviously) need to be adapted to what
> > Tobias changed.  
> 
> I see what you pushed in commit
> 39dda0020801045d9a604575b2a2593c05310015 "openacc: Fix standalone
> attach for Fortran assumed-shape array pointers" indeed has become
> much smaller/simpler.  :-)

Yes, thank you.

> (But, (parts of?) Tobias' commit mentioned above (plus commit
> 524862db444b6544c6dc87c5f06f351100ecf50d "Fix goacc/finalize-1.f tree
> dump-scanning for -m32", if applicable) will then also need to be
> backported to releases/gcc-10 branch (once un-frozen).)
> 
> > (Plus my more general questions quoted above and below.)  
> 
> >>> OK?  
> >>
> >> Basically yes (for master and releases/gcc-10 branches), but please
> >> consider the following:
> >>  
> >>> --- a/gcc/fortran/trans-openmp.c
> >>> +++ b/gcc/fortran/trans-openmp.c
> >>> @@ -2573,8 +2573,44 @@ gfc_trans_omp_clauses (stmtblock_t *block,
> >>> gfc_omp_clauses *clauses, }
> >>>  		    }
> >>>  		  if (GFC_DESCRIPTOR_TYPE_P (TREE_TYPE (decl))
> >>> -		      && n->u.map_op != OMP_MAP_ATTACH
> >>> -		      && n->u.map_op != OMP_MAP_DETACH)
> >>> +		      && (n->u.map_op == OMP_MAP_ATTACH
> >>> +			  || n->u.map_op == OMP_MAP_DETACH))
> >>> +		    {
> >>> +		      tree type = TREE_TYPE (decl);
> >>> +		      tree data = gfc_conv_descriptor_data_get
> >>> (decl);
> >>> +		      if (present)
> >>> +			data = gfc_build_cond_assign_expr
> >>> (block, present,
> >>> +							   data,
> >>> +
> >>> null_pointer_node);
> >>> +		      tree ptr
> >>> +			= fold_convert (build_pointer_type
> >>> (char_type_node),
> >>> +					data);
> >>> +		      ptr = build_fold_indirect_ref (ptr);
> >>> +		      /* Standalone attach clauses used with
> >>> arrays with
> >>> +			 descriptors must copy the descriptor to
> >>> the target,
> >>> +			 else they won't have anything to
> >>> perform the
> >>> +			 attachment onto (see OpenACC 2.6,
> >>> "2.6.3. Data
> >>> +			 Structures with Pointers").  */
> >>> +		      OMP_CLAUSE_DECL (node) = ptr;
> >>> +		      node2 = build_omp_clause (input_location,
> >>> OMP_CLAUSE_MAP);
> >>> +		      OMP_CLAUSE_SET_MAP_KIND (node2,
> >>> GOMP_MAP_TO_PSET);
> >>> +		      OMP_CLAUSE_DECL (node2) = decl;
> >>> +		      OMP_CLAUSE_SIZE (node2) = TYPE_SIZE_UNIT
> >>> (type);
> >>> +		      node3 = build_omp_clause (input_location,
> >>> OMP_CLAUSE_MAP);
> >>> +		      if (n->u.map_op == OMP_MAP_ATTACH)
> >>> +			{
> >>> +			  OMP_CLAUSE_SET_MAP_KIND (node3,
> >>> GOMP_MAP_ATTACH);
> >>> +			  n->u.map_op = OMP_MAP_ALLOC;
> >>> +			}
> >>> +		      else  /* OMP_MAP_DETACH.  */
> >>> +			{
> >>> +			  OMP_CLAUSE_SET_MAP_KIND (node3,
> >>> GOMP_MAP_DETACH);
> >>> +			  n->u.map_op = OMP_MAP_RELEASE;
> >>> +			}
> >>> +		      OMP_CLAUSE_DECL (node3) = data;
> >>> +		      OMP_CLAUSE_SIZE (node3) = size_int (0);
> >>> +		    }  
> >>
> >> So this ("case A") duplicates most of the code from...
> >>  
> >>> +		  else if (GFC_DESCRIPTOR_TYPE_P (TREE_TYPE
> >>> (decl))) {
> >>>  		      [...]  
> >>
> >> ... this existing case here ("case B").  It's not clear to me if
> >> these two cases really still need to be handled separately, and a
> >> little bit differently (regarding 'if (present)' handling, for
> >> example), or if they could/should (?) be merged?  Tobias, do you
> >> have an opinion?  
> 
> (These have been merged.)
> 
> >> Do we have sufficient testsuite coverage?  (For example,
> >> 'attach'/'detach' with 'present == false', if that makes sense, or
> >> any other thing that case A is doing differently from case B?)  
> 
> (I'm not sure we're actually testing all relevant cases.)

...probably still not, sorry... more tests can be added later though of
course.

> >> Shouldn't
> >> this get '-fdump-tree-original' and/or '-fdump-tree-gimple'
> >> testcases, similar to 'gfortran.dg/goacc/finalize-1.f', so that we
> >> verify/document what we generate here?  
> 
> So I guess I had -- unconsciously? ;-) -- mentioned
> -fdump-tree-gimple' and 'gfortran.dg/goacc/finalize-1.f' for a
> reason.  That displays how the 'finalize' clause is implemented (see
> WIP patch attached, 'gfortran.dg/goacc/attach-descriptor.f90'), and...
[snip]
> What should happen in this case?  Do we agree that 'exit data
> detach(myptr)' should *never* unmap 'myptr => tarr', but really should
> just unmap the 'myptr' array descriptor?
> 
> We can add special handling so that for standalone 'detach', a
> 'finalize' doesn't turn 'release' into 'delete', but that doesn't
> feel like the correct solution.

I don't think we actually need the alloc/release (with the latter turned
into "delete" for finalize) at all -- we just need to map the array
descriptor and perform the attach (or detach) as necessary. That's what
the attached patch does. Then, the pointed-to data's reference counts,
etc. will not be modified by attach/detach operations at all.

> Also, we have a different -- bigger? -- problem: if we, for example,
> 'attach(myptr)' twice, that operation will include twice times
> incrementing the reference count of 'myptr => tarr', and that'll then
> conflict with a 'copyout(myptr)', as that one then sees unexpected
> reference counts.  That's a different variant of the "[OpenACC] Deep
> copy attach/detach should not affect reference counts" problem?
> 
> Basically (see WIP patch attached,
> 'libgomp.oacc-fortran/attach-descriptor-1_.f90'):

Hmm, yes -- FWIW, this is caught by the "Refuse update/copyout for
blocks with attached pointers" patch. (In fact the attached patch
assumes that patch is already committed -- else the
attach-descriptor-4.f90 test should be XFAILed or omitted). So if we
want that one, this problem is sidestepped, I think.

Tested with offloading to NVPTX. OK?

Thanks,

Julian
Thomas Schwinge July 30, 2020, 9:53 a.m. UTC | #5
Hi Julian, Tobias!

On 2020-07-27T15:33:41+0100, Julian Brown <julian@codesourcery.com> wrote:
> On Fri, 17 Jul 2020 13:16:11 +0200
> Thomas Schwinge <thomas@codesourcery.com> wrote:
>> On 2020-07-15T12:28:42+0200, Thomas Schwinge
>> <thomas@codesourcery.com> wrote:
>> > On 2020-07-14T13:43:37+0200, I wrote:
>> >> On 2020-06-16T15:39:44-0700, Julian Brown
>> >> <julian@codesourcery.com> wrote:
>> >>> As mentioned in the blurb for the previous patch, an "attach"
>> >>> operation for a Fortran pointer with an array descriptor must
>> >>> copy that array descriptor to the target.
>> >>
>> >> Heh, I see -- I don't think I had read the OpenACC standard in
>> >> that way, but I think I agree your interpretation is fine.
>> >>
>> >> This does not create some sort of memory leak -- everything
>> >> implicitly allocated there will eventually be deallocated again,
>> >> right?
>>
>> Unanswered -- but I may now have found this problem, and also found
>> "the reverse problem" ('finalize'); see below.
>
> Sorry, I didn't answer this explicitly -- the idea was to pair alloc
> (present) and release mappings for the pointed-to data. In that way,
> the idea was for the release mapping to perform that deallocation. That
> was partly done so that the existing handling in gfc_trans_omp_clauses
> could be used for this case without too much disruption to the code --
> but actually, after Tobias's reorganisation of that function, that's
> not really so much of an issue any more.
>
> You can still get a "leak" if you try to attach a synthesized/temporary
> array descriptor that goes out of scope before the pointed-to data it
> refers to does -- that's a problem I've mentioned earlier, and is
> kind-of unavoidable unless we do some more sophisticated analysis to
> diagnose it as user error.

ACK.  Do you remember if you already had a testcase (conceptual, or
actual) to demonstrate that problem?

>> >>> This patch arranges for that to be so.
>> >>
>> >> In response to the new OpenACC/Fortran testcase that I'd submtited
>> >> in
>> >> <http://mid.mail-archive.com/87wo3co0tm.fsf@euler.schwinge.homeip.net>,
>> >> you (Julian) correctly supposed in
>> >> <http://mid.mail-archive.com/20200709223246.23a4d0e0@squid.athome>,
>> >> that this patch indeed does resolve that testcase, too.  That
>> >> wasn't obvious to me.  So, similar to
>> >> 'libgomp/testsuite/libgomp.oacc-c-c++-common/pr95270-{1.2}.c',
>> >> please include my new OpenACC/Fortran testcase (if that makes
>> >> sense to you), and reference PR95270 in the commit log.
>> >
>> > My new OpenACC/Fortran testcase got again broken ('libgomp: pointer
>> > target not mapped for attach') by Tobias' commit
>> > 102502e32ea4e8a75d6b252ba319d09d735d9aa7 "[OpenMP, Fortran] Add
>> > structure/derived-type element mapping",
>> > <http://mid.mail-archive.com/c5b43e02-d1d5-e7cf-c11c-6daf1e8f33c5@codesourcery.com>.
>> >
>> > Similar ('libgomp: attempt to attach null pointer') for your new
>> > 'libgomp.oacc-fortran/attach-descriptor-1.f90'.
>> >
>> > (Whether or not 'attach'ing 'NULL' should actually be allowed, is a
>> > separate topic for discussion.)
>> >
>> > So this patch here will (obviously) need to be adapted to what
>> > Tobias changed.
>>
>> I see what you pushed in commit
>> 39dda0020801045d9a604575b2a2593c05310015 "openacc: Fix standalone
>> attach for Fortran assumed-shape array pointers" indeed has become
>> much smaller/simpler.  :-)
>
> Yes, thank you.
>
>> (But, (parts of?) Tobias' commit mentioned above (plus commit
>> 524862db444b6544c6dc87c5f06f351100ecf50d "Fix goacc/finalize-1.f tree
>> dump-scanning for -m32", if applicable) will then also need to be
>> backported to releases/gcc-10 branch (once un-frozen).)
>>
>> > (Plus my more general questions quoted above and below.)
>>
>> >>> OK?
>> >>
>> >> Basically yes (for master and releases/gcc-10 branches), but please
>> >> consider the following:
>> >>
>> >>> --- a/gcc/fortran/trans-openmp.c
>> >>> +++ b/gcc/fortran/trans-openmp.c
>> >>> @@ -2573,8 +2573,44 @@ gfc_trans_omp_clauses (stmtblock_t *block,
>> >>> gfc_omp_clauses *clauses, }
>> >>>                      }
>> >>>                    if (GFC_DESCRIPTOR_TYPE_P (TREE_TYPE (decl))
>> >>> -                      && n->u.map_op != OMP_MAP_ATTACH
>> >>> -                      && n->u.map_op != OMP_MAP_DETACH)
>> >>> +                      && (n->u.map_op == OMP_MAP_ATTACH
>> >>> +                          || n->u.map_op == OMP_MAP_DETACH))
>> >>> +                    {
>> >>> +                      tree type = TREE_TYPE (decl);
>> >>> +                      tree data = gfc_conv_descriptor_data_get (decl);
>> >>> +                      if (present)
>> >>> +                        data = gfc_build_cond_assign_expr (block, present,
>> >>> +                                                           data,
>> >>> + null_pointer_node);
>> >>> +                      tree ptr
>> >>> +                        = fold_convert (build_pointer_type (char_type_node),
>> >>> +                                        data);
>> >>> +                      ptr = build_fold_indirect_ref (ptr);
>> >>> +                      /* Standalone attach clauses used with arrays with
>> >>> +                         descriptors must copy the descriptor to the target,
>> >>> +                         else they won't have anything to perform the
>> >>> +                         attachment onto (see OpenACC 2.6, "2.6.3. Data
>> >>> +                         Structures with Pointers").  */
>> >>> +                      OMP_CLAUSE_DECL (node) = ptr;
>> >>> +                      node2 = build_omp_clause (input_location, OMP_CLAUSE_MAP);
>> >>> +                      OMP_CLAUSE_SET_MAP_KIND (node2, GOMP_MAP_TO_PSET);
>> >>> +                      OMP_CLAUSE_DECL (node2) = decl;
>> >>> +                      OMP_CLAUSE_SIZE (node2) = TYPE_SIZE_UNIT (type);
>> >>> +                      node3 = build_omp_clause (input_location, OMP_CLAUSE_MAP);
>> >>> +                      if (n->u.map_op == OMP_MAP_ATTACH)
>> >>> +                        {
>> >>> +                          OMP_CLAUSE_SET_MAP_KIND (node3, GOMP_MAP_ATTACH);
>> >>> +                          n->u.map_op = OMP_MAP_ALLOC;
>> >>> +                        }
>> >>> +                      else  /* OMP_MAP_DETACH.  */
>> >>> +                        {
>> >>> +                          OMP_CLAUSE_SET_MAP_KIND (node3, GOMP_MAP_DETACH);
>> >>> +                          n->u.map_op = OMP_MAP_RELEASE;
>> >>> +                        }
>> >>> +                      OMP_CLAUSE_DECL (node3) = data;
>> >>> +                      OMP_CLAUSE_SIZE (node3) = size_int (0);
>> >>> +                    }
>> >>
>> >> So this ("case A") duplicates most of the code from...
>> >>
>> >>> +                  else if (GFC_DESCRIPTOR_TYPE_P (TREE_TYPE
>> >>> (decl))) {
>> >>>                        [...]
>> >>
>> >> ... this existing case here ("case B").  It's not clear to me if
>> >> these two cases really still need to be handled separately, and a
>> >> little bit differently (regarding 'if (present)' handling, for
>> >> example), or if they could/should (?) be merged?  Tobias, do you
>> >> have an opinion?
>>
>> (These have been merged.)
>>
>> >> Do we have sufficient testsuite coverage?  (For example,
>> >> 'attach'/'detach' with 'present == false', if that makes sense, or
>> >> any other thing that case A is doing differently from case B?)
>>
>> (I'm not sure we're actually testing all relevant cases.)
>
> ...probably still not, sorry... more tests can be added later though of
> course.

(Just remains the question who's going to do that, "later"...)  ;-\

>> >> Shouldn't
>> >> this get '-fdump-tree-original' and/or '-fdump-tree-gimple'
>> >> testcases, similar to 'gfortran.dg/goacc/finalize-1.f', so that we
>> >> verify/document what we generate here?
>>
>> So I guess I had -- unconsciously? ;-) -- mentioned
>> -fdump-tree-gimple' and 'gfortran.dg/goacc/finalize-1.f' for a
>> reason.  That displays how the 'finalize' clause is implemented (see
>> WIP patch attached, 'gfortran.dg/goacc/attach-descriptor.f90'), and...
> [snip]
>> What should happen in this case?  Do we agree that 'exit data
>> detach(myptr)' should *never* unmap 'myptr => tarr', but really should
>> just unmap the 'myptr' array descriptor?
>>
>> We can add special handling so that for standalone 'detach', a
>> 'finalize' doesn't turn 'release' into 'delete', but that doesn't
>> feel like the correct solution.
>
> I don't think we actually need the alloc/release (with the latter turned
> into "delete" for finalize) at all -- we just need to map the array
> descriptor and perform the attach (or detach) as necessary. That's what
> the attached patch does. Then, the pointed-to data's reference counts,
> etc. will not be modified by attach/detach operations at all.

ACK -- good to hear that this is the actual solution here.

>> Also, we have a different -- bigger? -- problem: if we, for example,
>> 'attach(myptr)' twice, that operation will include twice times
>> incrementing the reference count of 'myptr => tarr', and that'll then
>> conflict with a 'copyout(myptr)', as that one then sees unexpected
>> reference counts.  That's a different variant of the "[OpenACC] Deep
>> copy attach/detach should not affect reference counts" problem?
>>
>> Basically (see WIP patch attached,
>> 'libgomp.oacc-fortran/attach-descriptor-1_.f90'):
>
> Hmm, yes -- FWIW, this is caught by the "Refuse update/copyout for
> blocks with attached pointers" patch. (In fact the attached patch
> assumes that patch is already committed -- else the
> attach-descriptor-4.f90 test should be XFAILed or omitted). So if we
> want that one, this problem is sidestepped, I think.

I'm attaching an incremental patch (I have tested that) to merge the
testcases into one file, and make it work on current master branch
without the pending "Refuse update/copyout for blocks with attached
pointers" changes.  (We then later have to adjust the testcase here as
part of these changes.)

> Tested with offloading to NVPTX. OK?

Thanks.  OK for master and releases/gcc-10 branches from my point of
view, but maybe Tobias can also have a look, please; two
comments/suggestions:

> From d53e4f1cd450062163e7e96a469c2f56cfac65ee Mon Sep 17 00:00:00 2001
> From: Julian Brown <julian@codesourcery.com>
> Date: Mon, 27 Jul 2020 06:29:02 -0700
> Subject: [PATCH] openacc: No attach/detach present/release mappings for array
>  descriptors
>
> Standalone attach and detach clauses should not create present/release
> mappings for Fortran array descriptors (e.g. used when we have a pointer
> to an array), both because it is unnecessary and because those mappings
> will be incorrectly subject to reference counting. Simply omitting the
> mappings means we just use GOMP_MAP_TO_PSET and GOMP_MAP_{ATTACH,DETACH}
> mappings for array descriptors.
>
> That requires a tweak in gimplify.c, since we may now see GOMP_MAP_TO_PSET
> without a preceding data-movement mapping.
>
> The new attach-descriptor-4.f90 test relies on the checking performed
> by the patch "Refuse update/copyout for blocks with attached pointers".

(Need to remove that last sentence.)

> --- a/gcc/fortran/trans-openmp.c
> +++ b/gcc/fortran/trans-openmp.c
> @@ -2718,23 +2718,6 @@ gfc_trans_omp_clauses (stmtblock_t *block, gfc_omp_clauses *clauses,
>                     OMP_CLAUSE_SIZE (node2) = TYPE_SIZE_UNIT (type);
>                     node3 = build_omp_clause (input_location,
>                                               OMP_CLAUSE_MAP);
> -                   if (n->u.map_op == OMP_MAP_ATTACH)
> -                     {
> -                      /* Standalone attach clauses used with arrays with
> -                         descriptors must copy the descriptor to the target,
> -                         else they won't have anything to perform the
> -                         attachment onto (see OpenACC 2.6, "2.6.3. Data
> -                         Structures with Pointers").  */
> -                       OMP_CLAUSE_SET_MAP_KIND (node, GOMP_MAP_ALLOC);
> -                       OMP_CLAUSE_SET_MAP_KIND (node3, GOMP_MAP_ATTACH);
> -                     }
> -                   else if (n->u.map_op == OMP_MAP_DETACH)
> -                     {
> -                       OMP_CLAUSE_SET_MAP_KIND (node, GOMP_MAP_RELEASE);
> -                       OMP_CLAUSE_SET_MAP_KIND (node3, GOMP_MAP_DETACH);
> -                     }
> -                   else
> -                     OMP_CLAUSE_SET_MAP_KIND (node3, GOMP_MAP_POINTER);
>                     if (present)
>                       {
>                         ptr = gfc_conv_descriptor_data_get (decl);
> @@ -2748,6 +2731,33 @@ gfc_trans_omp_clauses (stmtblock_t *block, gfc_omp_clauses *clauses,
>                       OMP_CLAUSE_DECL (node3)
>                         = gfc_conv_descriptor_data_get (decl);
>                     OMP_CLAUSE_SIZE (node3) = size_int (0);
> +                   if (n->u.map_op == OMP_MAP_ATTACH)
> +                     {
> +                       /* Standalone attach clauses used with arrays with
> +                          descriptors must copy the descriptor to the target,
> +                          else they won't have anything to perform the
> +                          attachment onto (see OpenACC 2.6, "2.6.3. Data
> +                          Structures with Pointers").  */
> +                       OMP_CLAUSE_SET_MAP_KIND (node3, GOMP_MAP_ATTACH);
> +                       /* We don't want to map PTR at all in this case, so
> +                          delete its node and shuffle the others down.  */
> +                       node = node2;
> +                       node2 = node3;
> +                       node3 = NULL;
> +                       goto finalize_map_clause;
> +                     }
> +                   else if (n->u.map_op == OMP_MAP_DETACH)
> +                     {
> +                       OMP_CLAUSE_SET_MAP_KIND (node3, GOMP_MAP_DETACH);
> +                       /* Similarly to above, we don't want to unmap PTR
> +                          here.  */
> +                       node = node2;
> +                       node2 = node3;
> +                       node3 = NULL;
> +                       goto finalize_map_clause;
> +                     }
> +                   else
> +                     OMP_CLAUSE_SET_MAP_KIND (node3, GOMP_MAP_POINTER);
>
>                     /* We have to check for n->sym->attr.dimension because
>                        of scalar coarrays.  */

I don't understand this code good enough to be sure that 'goto
finalize_map_clause' doesn't skip anything we may actually need -- for
the many "special" cases that Fortran has.  Is it the case that it's the
correct thing to do, given that we're skipping 'node' completely.

I just had an idea how to make that clearer (maybe?) (untested, of
course): instead of the 'node', 'node2', 'node3' shuffling and 'goto
finalize_map_clause', don't do the shuffling and instead 'goto
finalize_map_clause_auxilliary' (better name maybe?):

     finalize_map_clause:

     omp_clauses = gfc_trans_add_clause (node, omp_clauses);
    +finalize_map_clause_auxilliary:
     if (node2)
       omp_clauses = gfc_trans_add_clause (node2, omp_clauses);
     if (node3)
       omp_clauses = gfc_trans_add_clause (node3, omp_clauses);
     if (node4)
       omp_clauses = gfc_trans_add_clause (node4, omp_clauses);

(Just an idea; can also be done separately, later.)

> --- a/gcc/gimplify.c
> +++ b/gcc/gimplify.c
> @@ -13013,8 +13013,9 @@ gimplify_omp_target_update (tree *expr_p, gimple_seq *pre_p)
>             OMP_CLAUSE_SET_MAP_KIND (c, GOMP_MAP_DELETE);
>             have_clause = true;
>             break;
> -         case GOMP_MAP_POINTER:
>           case GOMP_MAP_TO_PSET:
> +           break;
> +         case GOMP_MAP_POINTER:
>             /* TODO PR92929: we may see these here, but they'll always follow
>                one of the clauses above, and will be handled by libgomp as
>                one group, so no handling required here.  */

Maybe be good to add a comment why it's OK to do nothing for
'GOMP_MAP_TO_PSET'?


Grüße
 Thomas


> --- a/gcc/testsuite/gfortran.dg/goacc/attach-descriptor.f90
> +++ b/gcc/testsuite/gfortran.dg/goacc/attach-descriptor.f90
> @@ -1,4 +1,4 @@
> -! { dg-additional-options "-fdump-tree-original" }
> +! { dg-additional-options "-fdump-tree-original -fdump-tree-gimple" }
>
>  program att
>    implicit none
> @@ -11,8 +11,19 @@ program att
>    integer, pointer :: myptr(:)
>
>    !$acc enter data attach(myvar%arr2, myptr)
> -! { dg-final { scan-tree-dump-times "(?n)#pragma acc enter data map\\(attach:myvar\\.arr2 \\\[bias: 0\\\]\\) map\\(alloc:\\*\\(c_char \\*\\) myptr\\.data \\\[len: \[^\\\]\]+\\\]\\) map\\(to:myptr \\\[pointer set, len: \[0-9\]+\\\]\\) map\\(attach:\\(integer\\(kind=4\\)\\\[0:\\\] \\*\\) myptr\\.data \\\[bias: 0\\\]\\);$" 1 "original" } }
> +! { dg-final { scan-tree-dump-times "(?n)#pragma acc enter data map\\(attach:myvar\\.arr2 \\\[bias: 0\\\]\\) map\\(to:myptr \\\[pointer set, len: \[0-9\]+\\\]\\) map\\(attach:\\(integer\\(kind=4\\)\\\[0:\\\] \\*\\) myptr\\.data \\\[bias: 0\\\]\\);$" 1 "original" } }
> +! { dg-final { scan-tree-dump-times "(?n)#pragma omp target oacc_enter_exit_data map\\(attach:myvar\\.arr2 \\\[bias: 0\\\]\\) map\\(to:myptr \\\[pointer set, len: \[0-9\]+\\\]\\) map\\(attach:myptr\\.data \\\[bias: 0\\\]\\)$" 1 "gimple" } }
>
>    !$acc exit data detach(myvar%arr2, myptr)
> -! { dg-final { scan-tree-dump-times "(?n)#pragma acc exit data map\\(detach:myvar\\.arr2 \\\[bias: 0\\\]\\) map\\(release:\\*\\(c_char \\*\\) myptr\\.data \\\[len: \[^\\\]\]+\\\]\\) map\\(to:myptr \\\[pointer set, len: \[0-9\]+\\\]\\) map\\(detach:\\(integer\\(kind=4\\)\\\[0:\\\] \\*\\) myptr\\.data \\\[bias: 0\\\]\\);$" 1 "original" } }
> +! { dg-final { scan-tree-dump-times "(?n)#pragma acc exit data map\\(detach:myvar\\.arr2 \\\[bias: 0\\\]\\) map\\(to:myptr \\\[pointer set, len: \[0-9\]+\\\]\\) map\\(detach:\\(integer\\(kind=4\\)\\\[0:\\\] \\*\\) myptr\\.data \\\[bias: 0\\\]\\);$" 1 "original" } }
> +! { dg-final { scan-tree-dump-times "(?n)#pragma omp target oacc_enter_exit_data map\\(detach:myvar\\.arr2 \\\[bias: 0\\\]\\) map\\(to:myptr \\\[pointer set, len: \[0-9\]+\\\]\\) map\\(detach:myptr\\.data \\\[bias: 0\\\]\\)$" 1 "gimple" } }
> +
> +  ! Test valid usage and processing of the finalize clause.
> +  !$acc exit data detach(myvar%arr2, myptr) finalize
> +! { dg-final { scan-tree-dump-times "(?n)#pragma acc exit data map\\(detach:myvar\\.arr2 \\\[bias: 0\\\]\\) map\\(to:myptr \\\[pointer set, len: \[0-9\]+\\\]\\) map\\(detach:\\(integer\\(kind=4\\)\\\[0:\\\] \\*\\) myptr\\.data \\\[bias: 0\\\]\\) finalize;$" 1 "original" } }
> +  ! For array-descriptor detaches, we no longer generate a "release" mapping
> +  ! for the pointed-to data for gimplify.c to turn into "delete".  Make sure
> +  ! the mapping still isn't there.
> +! { dg-final { scan-tree-dump-times "(?n)#pragma omp target oacc_enter_exit_data map\\(force_detach:myvar\\.arr2 \\\[bias: 0\\\]\\) map\\(to:myptr \\\[pointer set, len: \[0-9\]+\\\]\\) map\\(force_detach:myptr\\.data \\\[bias: 0\\\]\\) finalize$" 1 "gimple" } }
> +
>  end program att
> diff --git a/libgomp/testsuite/libgomp.oacc-fortran/attach-descriptor-1.f90 b/libgomp/testsuite/libgomp.oacc-fortran/attach-descriptor-1.f90
> index 5d79cbc14fc..9f159fa3b75 100644
> --- a/libgomp/testsuite/libgomp.oacc-fortran/attach-descriptor-1.f90
> +++ b/libgomp/testsuite/libgomp.oacc-fortran/attach-descriptor-1.f90
> @@ -1,4 +1,5 @@
>  ! { dg-do run }
> +! { dg-skip-if "" { *-*-* } { "*" } { "-DACC_MEM_SHARED=0" } }
>
>  program att
>    use openacc
> @@ -29,7 +30,7 @@ program att
>    !$acc enter data attach(myvar%arr2, myptr)
>
>    ! FIXME: This warning is emitted on the wrong line number.
> -  ! { dg-warning "using vector_length \\(32\\), ignoring 1" "" { target openacc_nvidia_accel_selected } 38 }
> +  ! { dg-warning "using vector_length \\(32\\), ignoring 1" "" { target openacc_nvidia_accel_selected } 39 }
>    !$acc serial present(myvar%arr2)
>    do i=1,10
>      myvar%arr1(i) = i
> @@ -41,8 +42,11 @@ program att
>    !$acc exit data detach(myvar%arr2, myptr)
>
>    call acc_copyout(myvar%arr2)
> +  if (acc_is_present(myvar%arr2)) stop 10
>    call acc_copyout(myvar)
> +  if (acc_is_present(myvar)) stop 11
>    call acc_copyout(tarr)
> +  if (acc_is_present(tarr)) stop 12
>
>    do i=1,10
>      if (myvar%arr1(i) .ne. i) stop 1
> diff --git a/libgomp/testsuite/libgomp.oacc-fortran/attach-descriptor-3.f90 b/libgomp/testsuite/libgomp.oacc-fortran/attach-descriptor-3.f90
> new file mode 100644
> index 00000000000..f0e57b47453
> --- /dev/null
> +++ b/libgomp/testsuite/libgomp.oacc-fortran/attach-descriptor-3.f90
> @@ -0,0 +1,68 @@
> +! { dg-do run }
> +! { dg-skip-if "" { *-*-* } { "*" } { "-DACC_MEM_SHARED=0" } }
> +
> +program att
> +  use openacc
> +  implicit none
> +  type t
> +    integer :: arr1(10)
> +    integer, allocatable :: arr2(:)
> +  end type t
> +  integer :: i
> +  type(t) :: myvar
> +  integer, target :: tarr(10)
> +  integer, pointer :: myptr(:)
> +
> +  allocate(myvar%arr2(10))
> +
> +  do i=1,10
> +    myvar%arr1(i) = 0
> +    myvar%arr2(i) = 0
> +    tarr(i) = 0
> +  end do
> +
> +  call acc_copyin(myvar)
> +  call acc_copyin(myvar%arr2)
> +  call acc_copyin(tarr)
> +
> +  myptr => tarr
> +
> +  !$acc enter data attach(myvar%arr2, myptr)
> +  !$acc enter data attach(myvar%arr2, myptr)
> +
> +  ! FIXME: This warning is emitted on the wrong line number.
> +  ! { dg-warning "using vector_length \\(32\\), ignoring 1" "" { target openacc_nvidia_accel_selected } 40 }
> +  !$acc serial present(myvar%arr2)
> +  do i=1,10
> +    myvar%arr1(i) = i
> +    myvar%arr2(i) = i
> +  end do
> +  myptr(3) = 99
> +  !$acc end serial
> +
> +  !$acc exit data detach(myvar%arr2, myptr) finalize
> +
> +  if (.not. acc_is_present(myvar%arr2)) stop 10
> +  if (.not. acc_is_present(myvar)) stop 11
> +  if (.not. acc_is_present(tarr)) stop 12
> +
> +  call acc_copyout(myvar%arr2)
> +  if (acc_is_present(myvar%arr2)) stop 20
> +  if (.not. acc_is_present(myvar)) stop 21
> +  if (.not. acc_is_present(tarr)) stop 22
> +  call acc_copyout(myvar)
> +  if (acc_is_present(myvar%arr2)) stop 30
> +  if (acc_is_present(myvar)) stop 31
> +  if (.not. acc_is_present(tarr)) stop 32
> +  call acc_copyout(tarr)
> +  if (acc_is_present(myvar%arr2)) stop 40
> +  if (acc_is_present(myvar)) stop 41
> +  if (acc_is_present(tarr)) stop 42
> +
> +  do i=1,10
> +    if (myvar%arr1(i) .ne. i) stop 1
> +    if (myvar%arr2(i) .ne. i) stop 2
> +  end do
> +  if (tarr(3) .ne. 99) stop 3
> +
> +end program att
> diff --git a/libgomp/testsuite/libgomp.oacc-fortran/attach-descriptor-4.f90 b/libgomp/testsuite/libgomp.oacc-fortran/attach-descriptor-4.f90
> new file mode 100644
> index 00000000000..9dbf53d0213
> --- /dev/null
> +++ b/libgomp/testsuite/libgomp.oacc-fortran/attach-descriptor-4.f90
> @@ -0,0 +1,61 @@
> +! { dg-do run }
> +! { dg-skip-if "" { *-*-* } { "*" } { "-DACC_MEM_SHARED=0" } }
> +
> +program att
> +  use openacc
> +  implicit none
> +  type t
> +    integer :: arr1(10)
> +    integer, allocatable :: arr2(:)
> +  end type t
> +  integer :: i
> +  type(t) :: myvar
> +  integer, target :: tarr(10)
> +  integer, pointer :: myptr(:)
> +
> +  allocate(myvar%arr2(10))
> +
> +  do i=1,10
> +    myvar%arr1(i) = 0
> +    myvar%arr2(i) = 0
> +    tarr(i) = 0
> +  end do
> +
> +  call acc_copyin(myvar)
> +  call acc_copyin(myvar%arr2)
> +  call acc_copyin(tarr)
> +
> +  myptr => tarr
> +
> +  !$acc enter data attach(myvar%arr2, myptr)
> +  !$acc enter data attach(myvar%arr2, myptr)
> +
> +  ! FIXME: This warning is emitted on the wrong line number.
> +  ! { dg-warning "using vector_length \\(32\\), ignoring 1" "" { target openacc_nvidia_accel_selected } 40 }
> +  !$acc serial present(myvar%arr2)
> +  do i=1,10
> +    myvar%arr1(i) = i
> +    myvar%arr2(i) = i
> +  end do
> +  myptr(3) = 99
> +  !$acc end serial
> +
> +  !$acc exit data detach(myvar%arr2, myptr)
> +
> +  call acc_copyout(myvar%arr2)
> +  ! { dg-output ".*copyout of block \\\[0x\[0-9a-f\]+,\\+\[0-9\]+\\\] with attached pointers(\n|\r\n|\r)+" }
> +  if (acc_is_present(myvar%arr2)) stop 10
> +  call acc_copyout(myvar)
> +  if (acc_is_present(myvar)) stop 11
> +  call acc_copyout(tarr)
> +  if (acc_is_present(tarr)) stop 12
> +
> +  do i=1,10
> +    if (myvar%arr1(i) .ne. i) stop 1
> +    if (myvar%arr2(i) .ne. i) stop 2
> +  end do
> +  if (tarr(3) .ne. 99) stop 3
> +
> +end program att
> +
> +! { dg-shouldfail "" }


-----------------
Mentor Graphics (Deutschland) GmbH, Arnulfstraße 201, 80634 München / Germany
Registergericht München HRB 106955, Geschäftsführer: Thomas Heurung, Alexander Walter
Julian Brown July 30, 2020, 8:15 p.m. UTC | #6
On Thu, 30 Jul 2020 11:53:10 +0200
Thomas Schwinge <thomas@codesourcery.com> wrote:

> Hi Julian, Tobias!
> 
> On 2020-07-27T15:33:41+0100, Julian Brown <julian@codesourcery.com>
> wrote:
> > You can still get a "leak" if you try to attach a
> > synthesized/temporary array descriptor that goes out of scope
> > before the pointed-to data it refers to does -- that's a problem
> > I've mentioned earlier, and is kind-of unavoidable unless we do
> > some more sophisticated analysis to diagnose it as user error.  
> 
> ACK.  Do you remember if you already had a testcase (conceptual, or
> actual) to demonstrate that problem?

I have the attached, but it's not "clean", i.e. not really
testsuite-ready -- the breakage demonstrated depends on the stack
layout, and it only "works" at -O0.

HTH,

Julian
diff mbox series

Patch

diff --git a/gcc/fortran/trans-openmp.c b/gcc/fortran/trans-openmp.c
index 02c40fdc660..909a86795e0 100644
--- a/gcc/fortran/trans-openmp.c
+++ b/gcc/fortran/trans-openmp.c
@@ -2573,8 +2573,44 @@  gfc_trans_omp_clauses (stmtblock_t *block, gfc_omp_clauses *clauses,
 			}
 		    }
 		  if (GFC_DESCRIPTOR_TYPE_P (TREE_TYPE (decl))
-		      && n->u.map_op != OMP_MAP_ATTACH
-		      && n->u.map_op != OMP_MAP_DETACH)
+		      && (n->u.map_op == OMP_MAP_ATTACH
+			  || n->u.map_op == OMP_MAP_DETACH))
+		    {
+		      tree type = TREE_TYPE (decl);
+		      tree data = gfc_conv_descriptor_data_get (decl);
+		      if (present)
+			data = gfc_build_cond_assign_expr (block, present,
+							   data,
+							   null_pointer_node);
+		      tree ptr
+			= fold_convert (build_pointer_type (char_type_node),
+					data);
+		      ptr = build_fold_indirect_ref (ptr);
+		      /* Standalone attach clauses used with arrays with
+			 descriptors must copy the descriptor to the target,
+			 else they won't have anything to perform the
+			 attachment onto (see OpenACC 2.6, "2.6.3. Data
+			 Structures with Pointers").  */
+		      OMP_CLAUSE_DECL (node) = ptr;
+		      node2 = build_omp_clause (input_location, OMP_CLAUSE_MAP);
+		      OMP_CLAUSE_SET_MAP_KIND (node2, GOMP_MAP_TO_PSET);
+		      OMP_CLAUSE_DECL (node2) = decl;
+		      OMP_CLAUSE_SIZE (node2) = TYPE_SIZE_UNIT (type);
+		      node3 = build_omp_clause (input_location, OMP_CLAUSE_MAP);
+		      if (n->u.map_op == OMP_MAP_ATTACH)
+			{
+			  OMP_CLAUSE_SET_MAP_KIND (node3, GOMP_MAP_ATTACH);
+			  n->u.map_op = OMP_MAP_ALLOC;
+			}
+		      else  /* OMP_MAP_DETACH.  */
+			{
+			  OMP_CLAUSE_SET_MAP_KIND (node3, GOMP_MAP_DETACH);
+			  n->u.map_op = OMP_MAP_RELEASE;
+			}
+		      OMP_CLAUSE_DECL (node3) = data;
+		      OMP_CLAUSE_SIZE (node3) = size_int (0);
+		    }
+		  else if (GFC_DESCRIPTOR_TYPE_P (TREE_TYPE (decl)))
 		    {
 		      tree type = TREE_TYPE (decl);
 		      tree ptr = gfc_conv_descriptor_data_get (decl);
diff --git a/libgomp/testsuite/libgomp.oacc-fortran/attach-descriptor-1.f90 b/libgomp/testsuite/libgomp.oacc-fortran/attach-descriptor-1.f90
new file mode 100644
index 00000000000..2dd1a6fa5b6
--- /dev/null
+++ b/libgomp/testsuite/libgomp.oacc-fortran/attach-descriptor-1.f90
@@ -0,0 +1,51 @@ 
+program att
+  use openacc
+  implicit none
+  type t
+    integer :: arr1(10)
+    integer, allocatable :: arr2(:)
+  end type t
+  integer :: i
+  type(t) :: myvar
+  integer, target :: tarr(10)
+  integer, pointer :: myptr(:)
+
+  allocate(myvar%arr2(10))
+
+  do i=1,10
+    myvar%arr1(i) = 0
+    myvar%arr2(i) = 0
+    tarr(i) = 0
+  end do
+
+  call acc_copyin(myvar)
+  call acc_copyin(myvar%arr2)
+  call acc_copyin(tarr)
+
+  myptr => tarr
+
+  !$acc enter data attach(myvar%arr2, myptr)
+
+  ! FIXME: This warning is emitted on the wrong line number.
+  ! { dg-warning "using vector_length \\(32\\), ignoring 1" "" { target openacc_nvidia_accel_selected } 36 }
+  !$acc serial present(myvar%arr2)
+  do i=1,10
+    myvar%arr1(i) = i
+    myvar%arr2(i) = i
+  end do
+  myptr(3) = 99
+  !$acc end serial
+
+  !$acc exit data detach(myvar%arr2, myptr)
+
+  call acc_copyout(myvar%arr2)
+  call acc_copyout(myvar)
+  call acc_copyout(tarr)
+
+  do i=1,10
+    if (myvar%arr1(i) .ne. i) stop 1
+    if (myvar%arr2(i) .ne. i) stop 2
+  end do
+  if (tarr(3) .ne. 99) stop 3
+
+end program att