[gcc/devel/omp/gcc-16] openmp, fortran: Add support for iterators in OpenMP 'target update' constructs (Fortran)

Sandra Loosemore via Gcc-cvs <[email protected]>
Newsgroups gmane.comp.gcc.cvs
Message-ID <[email protected]>
https://gcc.gnu.org/g:378fcd14d2c3ac0207b873ff32b159398e43a07a

commit 378fcd14d2c3ac0207b873ff32b159398e43a07a
Author: Kwok Cheung Yeung <[email protected]>
Date:   Sun Jun 7 01:37:16 2026 +0000

    openmp, fortran: Add support for iterators in OpenMP 'target update' constructs (Fortran)
    
    This adds Fortran support for iterators in 'to' and 'from' clauses in the
    'target update' OpenMP directive.
    
    gcc/fortran/
    
            * dump-parse-tree.cc (show_omp_namelist): Add iterator support for
            OMP_LIST_TO and OMP_LIST_FROM.
            * match.cc (gfc_free_omp_namelist): Free namespace for OMP_LIST_TO
            and OMP_LIST_FROM.
            * openmp.cc (gfc_match_motion_var_list): Parse 'iterator' modifier.
            (resolve_omp_clauses): Resolve iterators for OMP_LIST_TO and
            OMP_LIST_FROM.
            * trans-openmp.cc (gfc_trans_omp_clauses): Handle iterators in
            OMP_LIST_TO and OMP_LIST_FROM clauses.  Add expressions to
            iter_block rather than block.
    
    gcc/testsuite/
    
            * gfortran.dg/gomp/target-update-iterators-1.f90: New.
            * gfortran.dg/gomp/target-update-iterators-2.f90: New.
            * gfortran.dg/gomp/target-update-iterators-3.f90: New.
    
    libgomp/
    
            * testsuite/libgomp.fortran/target-update-iterators-1.f90: New.
            * testsuite/libgomp.fortran/target-update-iterators-2.f90: New.
            * testsuite/libgomp.fortran/target-update-iterators-3.f90: New.
    
    Co-authored-by: Andrew Stubbs  <[email protected]>
    Co-authored-by: Sandra Loosemore <[email protected]>
    (cherry picked from commit 97c640c1136c7af180c6063f4706cf7cbf23b1b4)

Diff:
---
 gcc/fortran/dump-parse-tree.cc                     |  7 +-
 gcc/fortran/match.cc                               |  3 +-
 gcc/fortran/openmp.cc                              | 83 ++++++++++++++++++++--
 gcc/fortran/trans-openmp.cc                        | 49 +++++++++++--
 .../gfortran.dg/gomp/target-update-iterators-1.f90 | 33 +++++++++
 .../gfortran.dg/gomp/target-update-iterators-2.f90 | 25 +++++++
 .../gfortran.dg/gomp/target-update-iterators-3.f90 | 23 ++++++
 .../libgomp.fortran/target-update-iterators-1.f90  | 68 ++++++++++++++++++
 .../libgomp.fortran/target-update-iterators-2.f90  | 63 ++++++++++++++++
 .../libgomp.fortran/target-update-iterators-3.f90  | 78 ++++++++++++++++++++
 10 files changed, 420 insertions(+), 12 deletions(-)

diff --git a/gcc/fortran/dump-parse-tree.cc b/gcc/fortran/dump-parse-tree.cc
index 2263f0a8bd01..6233e96524c8 100644
--- a/gcc/fortran/dump-parse-tree.cc
+++ b/gcc/fortran/dump-parse-tree.cc
@@ -1484,7 +1484,8 @@ show_omp_namelist (int list_type, gfc_omp_namelist *n)
     {
       gfc_current_ns = ns_curr;
       if (list_type == OMP_LIST_AFFINITY || list_type == OMP_LIST_DEPEND
-	  || list_type == OMP_LIST_MAP)
+	  || list_type == OMP_LIST_MAP
+	  || list_type == OMP_LIST_TO || list_type == OMP_LIST_FROM)
 	{
 	  gfc_current_ns = n->u2.ns ? n->u2.ns : ns_curr;
 	  if (n->u2.ns != ns_iter)
@@ -1500,6 +1501,10 @@ show_omp_namelist (int list_type, gfc_omp_namelist *n)
 		    fputs ("DEPEND (", dumpfile);
 		  else if (list_type == OMP_LIST_MAP)
 		    fputs ("MAP (", dumpfile);
+		  else if (list_type == OMP_LIST_TO)
+		    fputs ("TO (", dumpfile);
+		  else if (list_type == OMP_LIST_FROM)
+		    fputs ("FROM (", dumpfile);
 		  else
 		    gcc_unreachable ();
 		}
diff --git a/gcc/fortran/match.cc b/gcc/fortran/match.cc
index 0c5e21338f93..850425e7f5fe 100644
--- a/gcc/fortran/match.cc
+++ b/gcc/fortran/match.cc
@@ -6540,7 +6540,8 @@ void
 gfc_free_omp_namelist (gfc_omp_namelist *name, enum gfc_omp_list_type list)
 {
   bool free_ns = (list == OMP_LIST_AFFINITY || list == OMP_LIST_DEPEND
-		  || list == OMP_LIST_MAP);
+		  || list == OMP_LIST_MAP
+		  || list == OMP_LIST_TO || list == OMP_LIST_FROM);
   bool free_align_allocator = (list == OMP_LIST_ALLOCATE);
   bool free_mem_traits_space = (list == OMP_LIST_USES_ALLOCATORS);
   bool free_init = (list == OMP_LIST_INIT);
diff --git a/gcc/fortran/openmp.cc b/gcc/fortran/openmp.cc
index 6fd4fb6ec1d6..c4289abaf851 100644
--- a/gcc/fortran/openmp.cc
+++ b/gcc/fortran/openmp.cc
@@ -1426,16 +1426,88 @@ gfc_match_motion_var_list (const char *str, gfc_omp_namelist **list,
   if (m != MATCH_YES)
     return m;
 
-  match m_present = gfc_match (" present : ");
+  gfc_namespace *ns_iter = NULL, *ns_curr = gfc_current_ns;
+  locus old_loc = gfc_current_locus;
+  int present_modifier = 0;
+  int iterator_modifier = 0;
+  locus second_present_locus = old_loc;
+  locus second_iterator_locus = old_loc;
+  bool saw_modifier = false;
+
+  for (;;)
+    {
+      locus current_locus = gfc_current_locus;
+      if (gfc_match ("present ") == MATCH_YES)
+	{
+	  if (present_modifier++ == 1)
+	    second_present_locus = current_locus;
+	}
+      else if (gfc_match_iterator (&ns_iter, true) == MATCH_YES)
+	{
+	  if (iterator_modifier++ == 1)
+	    second_iterator_locus = current_locus;
+	}
+      else if (!saw_modifier)
+	break;
+      else
+	{
+	  gfc_error ("Expected clause modifier at %C");
+	  return MATCH_ERROR;
+	}
+
+      /* OpenMP 5.1 syntax mistakenly allowed commas to be optional
+	 between and after modifiers in a clause.  This was corrected
+	 in 5.2 and later specifications: they're now required between
+	 modifiers and a trailing comma is not permitted.  We implement
+	 the 5.2 syntax here.  */
+      saw_modifier = true;
+      if (gfc_match (" : ") == MATCH_YES)
+	break;
+      else if (gfc_match (", ") == MATCH_YES)
+	continue;
+      else
+	{
+	  gfc_error ("Expected %<,%> or %<:%> after clause modifier at %C");
+	  return MATCH_ERROR;
+	}
+    }
+
+  if (!saw_modifier)
+    {
+      gfc_current_locus = old_loc;
+      present_modifier = 0;
+      iterator_modifier = 0;
+    }
+
+  if (present_modifier > 1)
+    {
+      gfc_error ("Too many %<present%> modifiers at %L", &second_present_locus);
+      return MATCH_ERROR;
+    }
+  if (iterator_modifier > 1)
+    {
+      gfc_error ("Too many %<iterator%> modifiers at %L",
+		 &second_iterator_locus);
+      return MATCH_ERROR;
+    }
+
+  if (ns_iter)
+    gfc_current_ns = ns_iter;
 
   m = gfc_match_omp_variable_list ("", list, false, NULL, headp, true, true);
+  gfc_current_ns = ns_curr;
   if (m != MATCH_YES)
     return m;
-  if (m_present == MATCH_YES)
+  gfc_omp_namelist *n;
+  for (n = **headp; n; n = n->next)
     {
-      gfc_omp_namelist *n;
-      for (n = **headp; n; n = n->next)
+      if (present_modifier)
 	n->u.present_modifier = true;
+      if (iterator_modifier)
+	{
+	  n->u2.ns = ns_iter;
+	  ns_iter->refs++;
+	}
     }
   return MATCH_YES;
 }
@@ -9799,7 +9871,8 @@ resolve_omp_clauses (gfc_code *code, gfc_omp_clauses *omp_clauses,
 	    for (; n != NULL; n = n->next)
 	      {
 		if ((list == OMP_LIST_DEPEND || list == OMP_LIST_AFFINITY
-		     || list == OMP_LIST_MAP)
+		     || list == OMP_LIST_MAP
+		     || list == OMP_LIST_TO || list == OMP_LIST_FROM)
 		    && n->u2.ns && !n->u2.ns->resolved)
 		  {
 		    n->u2.ns->resolved = 1;
diff --git a/gcc/fortran/trans-openmp.cc b/gcc/fortran/trans-openmp.cc
index 5f2673bb2e19..6fe5c0f33393 100644
--- a/gcc/fortran/trans-openmp.cc
+++ b/gcc/fortran/trans-openmp.cc
@@ -5270,12 +5270,40 @@ gfc_trans_omp_clauses (stmtblock_t *block, gfc_omp_clauses *clauses,
 	case OMP_LIST_TO:
 	case OMP_LIST_FROM:
 	case OMP_LIST_CACHE:
+	  iterator = NULL_TREE;
+	  prev = NULL;
+	  prev_clauses = omp_clauses;
 	  for (; n != NULL; n = n->next)
 	    {
 	      if (!n->sym->attr.referenced
 		  && n->sym->attr.flavor != FL_PARAMETER)
 		continue;
 
+	      if (iterator && prev->u2.ns != n->u2.ns)
+		{
+		  /* Finish previous iterator group.  */
+		  BLOCK_SUBBLOCKS (tree_block) = gfc_finish_block (&iter_block);
+		  TREE_VEC_ELT (iterator, 5) = tree_block;
+		  for (tree c = omp_clauses; c != prev_clauses;
+		       c = OMP_CLAUSE_CHAIN (c))
+		    OMP_CLAUSE_ITERATORS (c) = iterator;
+		  prev_clauses = omp_clauses;
+		  iterator = NULL_TREE;
+		}
+	      if (n->u2.ns && (!prev || prev->u2.ns != n->u2.ns))
+		{
+		  /* Start a new iterator group.  */
+		  gfc_init_block (&iter_block);
+		  tree_block = make_node (BLOCK);
+		  TREE_USED (tree_block) = 1;
+		  BLOCK_VARS (tree_block) = NULL_TREE;
+		  prev_clauses = omp_clauses;
+		  iterator = handle_iterator (n->u2.ns, block, tree_block);
+		}
+	      if (!iterator)
+		gfc_init_block (&iter_block);
+	      prev = n;
+
 	      switch (list)
 		{
 		case OMP_LIST_TO:
@@ -5314,7 +5342,7 @@ gfc_trans_omp_clauses (stmtblock_t *block, gfc_omp_clauses *clauses,
 		      ptr = build_fold_indirect_ref (ptr);
 		      OMP_CLAUSE_DECL (node) = ptr;
 		      OMP_CLAUSE_SIZE (node)
-			= gfc_full_array_size (block, decl,
+			= gfc_full_array_size (&iter_block, decl,
 					       GFC_TYPE_ARRAY_RANK (type));
 		      tree elemsz
 			= TYPE_SIZE_UNIT (gfc_get_element_type (type));
@@ -5339,7 +5367,7 @@ gfc_trans_omp_clauses (stmtblock_t *block, gfc_omp_clauses *clauses,
 		    {
 		      gfc_conv_expr_reference (&se, n->expr);
 		      ptr = se.expr;
-		      gfc_add_block_to_block (block, &se.pre);
+		      gfc_add_block_to_block (&iter_block, &se.pre);
 		      OMP_CLAUSE_SIZE (node)
 			= TYPE_SIZE_UNIT (TREE_TYPE (TREE_TYPE (ptr)));
 		    }
@@ -5348,9 +5376,9 @@ gfc_trans_omp_clauses (stmtblock_t *block, gfc_omp_clauses *clauses,
 		      gfc_conv_expr_descriptor (&se, n->expr);
 		      ptr = gfc_conv_array_data (se.expr);
 		      tree type = TREE_TYPE (se.expr);
-		      gfc_add_block_to_block (block, &se.pre);
+		      gfc_add_block_to_block (&iter_block, &se.pre);
 		      OMP_CLAUSE_SIZE (node)
-			= gfc_full_array_size (block, se.expr,
+			= gfc_full_array_size (&iter_block, se.expr,
 					       GFC_TYPE_ARRAY_RANK (type));
 		      tree elemsz
 			= TYPE_SIZE_UNIT (gfc_get_element_type (type));
@@ -5359,7 +5387,7 @@ gfc_trans_omp_clauses (stmtblock_t *block, gfc_omp_clauses *clauses,
 			= fold_build2 (MULT_EXPR, gfc_array_index_type,
 				       OMP_CLAUSE_SIZE (node), elemsz);
 		    }
-		  gfc_add_block_to_block (block, &se.post);
+		  gfc_add_block_to_block (&iter_block, &se.post);
 		  gcc_assert (POINTER_TYPE_P (TREE_TYPE (ptr)));
 		  OMP_CLAUSE_DECL (node) = build_fold_indirect_ref (ptr);
 		}
@@ -5367,8 +5395,19 @@ gfc_trans_omp_clauses (stmtblock_t *block, gfc_omp_clauses *clauses,
 		OMP_CLAUSE_MOTION_PRESENT (node) = 1;
 	      if (list == OMP_LIST_CACHE && n->u.map.readonly)
 		OMP_CLAUSE__CACHE__READONLY (node) = 1;
+	      if (!iterator)
+		gfc_add_block_to_block (block, &iter_block);
 	      omp_clauses = gfc_trans_add_clause (node, omp_clauses);
 	    }
+	  if (iterator)
+	    {
+	      /* Finish last iterator group.  */
+	      BLOCK_SUBBLOCKS (tree_block) = gfc_finish_block (&iter_block);
+	      TREE_VEC_ELT (iterator, 5) = tree_block;
+	      for (tree c = omp_clauses; c != prev_clauses;
+		   c = OMP_CLAUSE_CHAIN (c))
+		OMP_CLAUSE_ITERATORS (c) = iterator;
+	    }
 	  break;
 	case OMP_LIST_USES_ALLOCATORS:
 	  /* Ignore omp_null_allocator and pre-defined allocators as no
diff --git a/gcc/testsuite/gfortran.dg/gomp/target-update-iterators-1.f90 b/gcc/testsuite/gfortran.dg/gomp/target-update-iterators-1.f90
new file mode 100644
index 000000000000..e9dc5a7de36c
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/gomp/target-update-iterators-1.f90
@@ -0,0 +1,33 @@
+! { dg-do compile }
+! { dg-options "-fopenmp" }
+
+program test
+  implicit none
+
+  integer, parameter :: DIM1 = 17
+  integer, parameter :: DIM2 = 39
+
+  type :: array_ptr
+    integer, pointer :: ptr(:)
+  end type
+
+  type (array_ptr) :: x(DIM1), y(DIM1)
+
+  !$omp target update to (iterator(i=1:DIM1): x(i)%ptr(:))
+
+  !$omp target update to (iterator(i=1:DIM1): x(i)%ptr(:DIM2), y(i)%ptr(:))
+
+  !$omp target update to (iterator(i=1:DIM1), present: x(i)%ptr(:))
+
+  !$omp target update to (, iterator(i=1:DIM1), present: x(i)%ptr(:))  ! { dg-error "Syntax error in OpenMP variable list at .1." }
+
+  !$omp target update to (iterator(i=1:DIM1) present: x(i)%ptr(:))  ! { dg-error "Expected ',' or ':' after clause modifier at .1." }
+
+  !$omp target update to (iterator(i=1:DIM1), present x(i)%ptr(:))  ! { dg-error "Expected ',' or ':' after clause modifier at .1." }
+
+  !$omp target update to (iterator(i=1:DIM1), present, : x(i)%ptr(:))  ! { dg-error "Expected clause modifier at .1." }
+
+  !$omp target update to (iterator(i=1:DIM1), iterator(j=i:DIM2): x(i)%ptr(j)) ! { dg-error "Too many 'iterator' modifiers at .1." }
+
+  !$omp target update to (iterator(i=1:DIM1), something: x(i, j)) ! { dg-error "Expected clause modifier at .1." }
+end program
diff --git a/gcc/testsuite/gfortran.dg/gomp/target-update-iterators-2.f90 b/gcc/testsuite/gfortran.dg/gomp/target-update-iterators-2.f90
new file mode 100644
index 000000000000..91d07ef8fb72
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/gomp/target-update-iterators-2.f90
@@ -0,0 +1,25 @@
+! { dg-do compile }
+! { dg-options "-fopenmp -fdump-tree-gimple" }
+
+program test
+  implicit none
+
+  integer, parameter :: DIM1 = 100
+
+  type :: array_ptr
+    integer, pointer :: ptr(:)
+  end type
+
+  type (array_ptr) :: x(DIM1), y(DIM1), z(DIM1)
+
+  !$omp target update to(iterator(i=1:10): x)
+  !$omp target update from(iterator(i2=1:10, j2=1:20): x(i2))
+  !$omp target update to(iterator(i3=1:10, j3=1:20, k3=1:30): x(i3+j3), y(j3+k3), z(k3+i3))
+end program
+
+! { dg-final { scan-tree-dump-times "update to\\\(x " 1 "gimple" } }
+! { dg-final { scan-tree-dump-times "update from\\\(iterator\\\(integer\\\(kind=4\\\) i2=1:10:1, loop_label=" 1 "gimple" } }
+! { dg-final { scan-tree-dump-times "to\\\(iterator\\\(integer\\\(kind=4\\\) j3=1:20:1, integer\\\(kind=4\\\) i3=1:10:1, loop_label=" 1 "gimple" } }
+! { dg-final { scan-tree-dump-times "to\\\(iterator\\\(integer\\\(kind=4\\\) k3=1:30:1, integer\\\(kind=4\\\) j3=1:20:1, loop_label=" 1 "gimple" } }
+! { dg-final { scan-tree-dump-times "to\\\(iterator\\\(integer\\\(kind=4\\\) k3=1:30:1, integer\\\(kind=4\\\) i3=1:10:1, loop_label=" 1 "gimple" } }
+ 
\ No newline at end of file
diff --git a/gcc/testsuite/gfortran.dg/gomp/target-update-iterators-3.f90 b/gcc/testsuite/gfortran.dg/gomp/target-update-iterators-3.f90
new file mode 100644
index 000000000000..d9c92cf46790
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/gomp/target-update-iterators-3.f90
@@ -0,0 +1,23 @@
+! { dg-do compile }
+! { dg-options "-fopenmp -fdump-tree-gimple" }
+
+program test
+  implicit none
+
+  integer, parameter :: DIM1 = 17
+  integer, parameter :: DIM2 = 39
+
+  type :: array_ptr
+    integer, pointer :: ptr(:)
+  end type
+
+  type (array_ptr) :: x(DIM1, DIM2), y(DIM1, DIM2), z(DIM1)
+
+  !$omp target update to (iterator(i=1:DIM1, j=1:DIM2): x(i, j)%ptr(:), y(i, j)%ptr(:))
+  !$omp target update from (iterator(i=1:DIM1): z(i)%ptr(:))
+end program
+
+! { dg-final { scan-tree-dump-times "if \\(i <= 17\\) goto <D\\\.\[0-9\]+>; else goto <D\\\.\[0-9\]+>;" 2 "gimple" } }
+! { dg-final { scan-tree-dump-times "if \\(j <= 39\\) goto <D\\\.\[0-9\]+>; else goto <D\\\.\[0-9\]+>;" 1 "gimple" } }
+! { dg-final { scan-tree-dump-times "to\\(iterator\\(integer\\(kind=4\\) j=1:39:1, integer\\(kind=4\\) i=1:17:1, loop_label=<D\\\.\[0-9\]+>, elems=omp_iter_data\\\.\[0-9\]+, index=D\\\.\[0-9\]+\\):MEM <\[^>\]+> \\\[\\\(\[^ \]+ \\\*\\\)D\\\.\[0-9\]+\\\]" 2 "gimple" } }
+! { dg-final { scan-tree-dump-times "from\\(iterator\\(integer\\(kind=4\\) i=1:17:1, loop_label=<D\\\.\[0-9\]+>, elems=omp_iter_data\\\.\[0-9\]+, index=D\\\.\[0-9\]+\\):MEM <\[^>\]+> \\\[\\\(\[^ \]+ \\\*\\\)D\\\.\[0-9\]+\\\]" 1 "gimple" } }
diff --git a/libgomp/testsuite/libgomp.fortran/target-update-iterators-1.f90 b/libgomp/testsuite/libgomp.fortran/target-update-iterators-1.f90
new file mode 100644
index 000000000000..e9a13a3c737d
--- /dev/null
+++ b/libgomp/testsuite/libgomp.fortran/target-update-iterators-1.f90
@@ -0,0 +1,68 @@
+! { dg-do run }
+
+! Test target enter data and target update to the target using map
+! iterators.
+
+program test
+  integer, parameter :: DIM1 = 8
+  integer, parameter :: DIM2 = 15
+
+  type :: array_ptr
+    integer, pointer :: arr(:)
+  end type
+
+  type (array_ptr) :: x(DIM1)
+  integer :: expected, sum, i, j
+
+  expected = mkarray (x)
+
+  !$omp target enter data map(to: x)
+  !$omp target enter data map(iterator(i=1:DIM1), to: x(i)%arr(:))
+  !$omp target map(from: sum)
+    sum = 0
+    do i = 1, DIM1
+      do j = 1, DIM2
+	sum = sum + x(i)%arr(j)
+      end do
+    end do
+  !$omp end target
+
+  print *, sum, expected
+  if (sum .ne. expected) stop 1
+
+  expected = 0
+  do i = 1, DIM1
+    do j = 1, DIM2
+      x(i)%arr(j) = x(i)%arr(j) * i * j
+      expected = expected + x(i)%arr(j)
+    end do
+  end do
+
+  !$omp target update to(iterator(i=1:DIM1): x(i)%arr(:))
+
+  !$omp target map(from: sum)
+    sum = 0
+    do i = 1, DIM1
+      do j = 1, DIM2
+	sum = sum + x(i)%arr(j)
+      end do
+    end do
+  !$omp end target
+
+  if (sum .ne. expected) stop 2
+contains
+  integer function mkarray (x)
+    type (array_ptr), intent(inout) :: x(DIM1)
+    integer :: exp = 0
+
+    do i = 1, DIM1
+      allocate (x(i)%arr(DIM2))
+      do j = 1, DIM2
+	x(i)%arr(j) = i * j
+	exp = exp + x(i)%arr(j)
+      end do
+    end do
+
+    mkarray = exp
+  end function
+end program
diff --git a/libgomp/testsuite/libgomp.fortran/target-update-iterators-2.f90 b/libgomp/testsuite/libgomp.fortran/target-update-iterators-2.f90
new file mode 100644
index 000000000000..2e982bc032c9
--- /dev/null
+++ b/libgomp/testsuite/libgomp.fortran/target-update-iterators-2.f90
@@ -0,0 +1,63 @@
+! { dg-do run }
+! { dg-require-effective-target offload_device_nonshared_as }
+
+! Test target enter data and target update from the target using map
+! iterators.
+
+program test
+  integer, parameter :: DIM1 = 8
+  integer, parameter :: DIM2 = 15
+
+  type :: array_ptr
+    integer, pointer :: arr(:)
+  end type
+
+  type (array_ptr) :: x(DIM1)
+  integer :: sum, expected
+
+  call mkarray (x)
+
+  !$omp target enter data map(to: x(:DIM1))
+  !$omp target enter data map(iterator(i=1:DIM1), to: x(i)%arr(:))
+  !$omp target map(from: expected)
+    expected = 0
+    do i = 1, DIM1
+      do j = 1, DIM2
+	x(i)%arr(j) = (i + 1) * (j + 2)
+	expected = expected + x(i)%arr(j)
+      end do
+    end do
+  !$omp end target
+
+  ! Host copy of x should remain unchanged.
+  sum = 0
+  do i = 1, DIM1
+    do j = 1, DIM2
+      sum = sum + x(i)%arr(j)
+    end do
+  end do
+  if (sum .ne. 0) stop 1
+
+  !$omp target update from(iterator(i=1:DIM1): x(i)%arr(:))
+
+  ! Host copy should now be updated.
+  sum = 0
+  do i = 1, DIM1
+    do j = 1, DIM2
+      sum = sum + x(i)%arr(j)
+    end do
+  end do
+
+  if (sum .ne. expected) stop 2
+contains
+  subroutine mkarray (x)
+    type (array_ptr), intent(inout) :: x(DIM1)
+
+    do i = 1, DIM1
+      allocate (x(i)%arr(DIM2))
+      do j = 1, DIM2
+	x(i)%arr(j) = 0
+      end do
+    end do
+  end subroutine
+end program
diff --git a/libgomp/testsuite/libgomp.fortran/target-update-iterators-3.f90 b/libgomp/testsuite/libgomp.fortran/target-update-iterators-3.f90
new file mode 100644
index 000000000000..54b2a6c37c18
--- /dev/null
+++ b/libgomp/testsuite/libgomp.fortran/target-update-iterators-3.f90
@@ -0,0 +1,78 @@
+! { dg-do run }
+! { dg-require-effective-target offload_device_nonshared_as }
+
+! Test target enter data and target update to the target using map
+! iterators with a function.
+
+program test
+  implicit none
+
+  integer, parameter :: DIM1 = 8
+  integer, parameter :: DIM2 = 15
+
+  type :: array_ptr
+    integer, pointer :: arr(:)
+  end type
+
+  type (array_ptr) :: x(DIM1)
+  integer :: x_new(DIM1, DIM2)
+  integer :: expected, sum, i, j
+
+  call mkarray (x)
+
+  !$omp target enter data map(to: x(:DIM1))
+  !$omp target enter data map(iterator(i=1:DIM1), to: x(i)%arr(:))
+
+  ! Update x on host.
+  do i = 1, DIM1
+    do j = 1, DIM2
+      x_new(i, j) = x(i)%arr(j)
+      x(i)%arr(j) = (i + 1) * (j + 2);
+    end do
+  end do
+
+  ! Update a subset of x on target.
+  !$omp target update to(iterator(i=1:DIM1/2): x(f (i))%arr(:))
+
+  !$omp target map(from: sum)
+    sum = 0
+    do i = 1, DIM1
+      do j = 1, DIM2
+	sum = sum + x(i)%arr(j)
+      end do
+    end do
+  !$omp end target
+
+  ! Calculate expected value on host.
+  do i = 1, DIM1/2
+    do j = 1, DIM2
+      x_new(f (i), j) = x(f (i))%arr(j)
+    end do
+  end do
+
+  expected = 0
+  do i = 1, DIM1
+    do j = 1, DIM2
+      expected = expected + x_new(i, j)
+    end do
+  end do
+
+  if (sum .ne. expected) stop 1
+contains
+  subroutine mkarray (x)
+    type (array_ptr), intent(inout) :: x(DIM1)
+
+    do i = 1, DIM1
+      allocate (x(i)%arr(DIM2))
+      do j = 1, DIM2
+	x(i)%arr(j) = i * j
+      end do
+    end do
+  end subroutine
+
+  integer function f (i)
+    integer, intent(in) :: i
+
+    f = i * 2
+  end function
+end program
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.