On Fri, 5 Feb 2021 17:25:10 +0100
Tobias Burnus <tob...@codesourcery.com> wrote:

> (CC fortran@)
> 
> Hi Julian,
> 
> not doing an extensive review yet, but the following gives an ICE
> with this patch applied. (I believe the others are already in, aren't
> they?)
> 
> type t
>   integer :: i, j
> end type t
> type t2
>   type(t) :: b(4)
> end type
> type(t2) :: var(10)
> !$acc update host(var(3)%b(:)%j)
> !$acc update host(var(3)%b%j)
> end
> 
> That's a noncontiguous array – which is permitted for 'update'
> and it gives an ICE via:
> 
> 0x9b0c59 gfc_conv_scalarized_array_ref
>          ../../repos/gcc/gcc/fortran/trans-array.c:3570
> 0x9b2134 gfc_conv_array_ref(gfc_se*, gfc_array_ref*, gfc_expr*,
> locus*) ../../repos/gcc/gcc/fortran/trans-array.c:3721
> 0x9e9cc6 gfc_conv_variable
>          ../../repos/gcc/gcc/fortran/trans-expr.c:2998
> 0xa22682 gfc_trans_omp_clauses
>          ../../repos/gcc/gcc/fortran/trans-openmp.c:2963

I think the attached patch fixes that. (This could be merged into the
parent patch or kept separate, not sure which is better.)

Re-tested with offloading to AMD GCN. OK?

> > +         bool allocatable = false, pointer = false;
> > +
> > +         if (lastref && lastref->type == REF_COMPONENT)
> > +           {
> > +             gfc_component *c = lastref->u.c.component;
> > +
> > +             if (c->ts.type == BT_CLASS)
> > +               {
> > +                 pointer = CLASS_DATA (c)->attr.class_pointer;
> > +                 allocatable = CLASS_DATA
> > (c)->attr.allocatable;
> > +               }
> > +             else
> > +               {
> > +                 pointer = c->attr.pointer;
> > +                 allocatable = c->attr.allocatable;
> > +               }
> > +           }
> > +  
> 
> I am not sure how the rest will change, but I was wondering
> whether the following helps. I see that 'lastref' is used
> elsewhere – hence, I am not sure whether it is indeed better.
>   
> symbol_attribute attr = {};
> if (n->expr)
>    attr = gfc_expr_attr (n->expr);

Ah, I didn't know about that one! But yeah, not sure if it's better
here.

Thanks for (pre-)review!

Julian
>From adf4221bf5b5ab01ce1ed264226f1799d8aa0b05 Mon Sep 17 00:00:00 2001
From: Julian Brown <jul...@codesourcery.com>
Date: Sat, 6 Feb 2021 02:34:30 -0800
Subject: [PATCH] Handle discontinuous ranges with derived types

OpenACC "update" allows discontiguous ranges to be specified, e.g. by
selecting an array slice in the middle of a derived type selector list:

  !$acc update host(mytype%arraymember(:)%foo)

We handle this by transferring the whole of the slice and ignoring the
"foo" part.

gcc/fortran/
	* trans-openmp.c (gfc_trans_omp_clauses): Handle discontiguous
	ranges specified by arrays or array slices with trailing
	derived-type selectors.

gcc/testsuite/
	* gfortran.dg/goacc/array-with-dt-6.f90: New test.

libgomp/
	* testsuite/gfortran.dg/update-dt-array-2.f90: New test.
---
 gcc/fortran/trans-openmp.c                    | 26 +++++++-
 .../gfortran.dg/goacc/array-with-dt-6.f90     | 10 ++++
 .../update-dt-array-2.f90                     | 59 +++++++++++++++++++
 3 files changed, 93 insertions(+), 2 deletions(-)
 create mode 100644 gcc/testsuite/gfortran.dg/goacc/array-with-dt-6.f90
 create mode 100644 libgomp/testsuite/libgomp.oacc-fortran/update-dt-array-2.f90

diff --git a/gcc/fortran/trans-openmp.c b/gcc/fortran/trans-openmp.c
index 67e370f8b57..758485e0c7d 100644
--- a/gcc/fortran/trans-openmp.c
+++ b/gcc/fortran/trans-openmp.c
@@ -2676,12 +2676,32 @@ gfc_trans_omp_clauses (stmtblock_t *block, gfc_omp_clauses *clauses,
 	      if (DECL_P (decl))
 		TREE_ADDRESSABLE (decl) = 1;
 
-	      gfc_ref *lastref = NULL;
+	      gfc_ref *lastref = NULL, *lastslice = NULL;
 
 	      if (n->expr)
 		for (gfc_ref *ref = n->expr->ref; ref; ref = ref->next)
-		  if (ref->type == REF_COMPONENT || ref->type == REF_ARRAY)
+		  if (ref->type == REF_COMPONENT)
 		    lastref = ref;
+		  else if (ref->type == REF_ARRAY)
+		    {
+		      if (ref->u.ar.type == AR_FULL
+			  || ref->u.ar.type == AR_SECTION)
+			lastslice = ref;
+
+		      lastref = ref;
+		    }
+
+	      /* If a slice is specified but it is not the last ref, this
+		 might be an update operation that allows discontiguous
+		 regions, like:
+
+		   myvar%slice(:)%foo
+
+		 in that case, we will ignore the %foo part and transfer the
+		 whole of the slice as a single block.  */
+
+	      if (lastslice)
+		lastref = lastslice;
 
 	      bool allocatable = false, pointer = false;
 
@@ -3023,6 +3043,8 @@ gfc_trans_omp_clauses (stmtblock_t *block, gfc_omp_clauses *clauses,
 			  if (ref->u.ar.type == AR_ELEMENT && ref->next)
 			    gfc_conv_array_ref (&se, &ref->u.ar, n->expr,
 						&n->expr->where);
+			  else if (ref == lastslice)
+			    break;
 			  else
 			    gcc_assert (!ref->next);
 			}
diff --git a/gcc/testsuite/gfortran.dg/goacc/array-with-dt-6.f90 b/gcc/testsuite/gfortran.dg/goacc/array-with-dt-6.f90
new file mode 100644
index 00000000000..260db6602f4
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/goacc/array-with-dt-6.f90
@@ -0,0 +1,10 @@
+type t
+  integer :: i, j
+end type t
+type t2
+  type(t) :: b(4)
+end type
+type(t2) :: var(10)
+!$acc update host(var(3)%b(:)%j)
+!$acc update host(var(3)%b%j)
+end
diff --git a/libgomp/testsuite/libgomp.oacc-fortran/update-dt-array-2.f90 b/libgomp/testsuite/libgomp.oacc-fortran/update-dt-array-2.f90
new file mode 100644
index 00000000000..8e0ed338d39
--- /dev/null
+++ b/libgomp/testsuite/libgomp.oacc-fortran/update-dt-array-2.f90
@@ -0,0 +1,59 @@
+! { dg-do run }
+
+program myprog
+
+  type mt2
+    integer :: p, q, r
+  end type mt2
+
+  type mytype
+    type(mt2), allocatable :: myarr(:,:)
+  end type mytype
+  integer :: i
+
+  type(mytype), allocatable :: typearr(:)
+
+  allocate(typearr(1:100))
+
+  do i=1,100
+    allocate(typearr(i)%myarr(1:100,1:100))
+  end do
+
+  do i=1,100
+    typearr(i)%myarr(:,:)%p = 0
+    typearr(i)%myarr(:,:)%q = 0
+    typearr(i)%myarr(:,:)%r = 0
+  end do
+
+  !$acc enter data copyin(typearr)
+
+  do i=1,100
+    !$acc enter data copyin(typearr(i)%myarr)
+  end do
+
+  i=33
+  typearr(i)%myarr(:,:)%q = 50
+
+  !$acc update device(typearr(i)%myarr(:,:)%q)
+
+  do i=1,100
+    !$acc exit data copyout(typearr(i)%myarr)
+  end do
+
+  !$acc exit data delete(typearr)
+
+  do i=1,100
+    if (i.eq.33) then
+      if (any(typearr(i)%myarr(:,:)%q.ne.50)) stop 1
+    else
+      if (any(typearr(i)%myarr(:,:)%q.ne.0)) stop 2
+    end if
+  end do
+
+  do i=1,100
+    deallocate(typearr(i)%myarr)
+  end do
+
+  deallocate(typearr)
+
+end program myprog
-- 
2.29.2

Reply via email to