]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
openmp, fortran: Add support for iterators in OpenMP 'target update' constructs ...
authorKwok Cheung Yeung <kcyeung@baylibre.com>
Wed, 27 Nov 2024 21:56:08 +0000 (21:56 +0000)
committerKwok Cheung Yeung <kcyeung@baylibre.com>
Thu, 17 Apr 2025 22:30:04 +0000 (23:30 +0100)
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_namelist): Free namespace for OMP_LIST_TO and
OMP_LIST_FROM.
* openmp.cc (gfc_free_omp_clauses): Free namespace for OMP_LIST_TO
and OMP_LIST_FROM.
(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 <ams@baylibre.com>
13 files changed:
gcc/fortran/ChangeLog.omp
gcc/fortran/dump-parse-tree.cc
gcc/fortran/match.cc
gcc/fortran/openmp.cc
gcc/fortran/trans-openmp.cc
gcc/testsuite/ChangeLog.omp
gcc/testsuite/gfortran.dg/gomp/target-update-iterators-1.f90 [new file with mode: 0644]
gcc/testsuite/gfortran.dg/gomp/target-update-iterators-2.f90 [new file with mode: 0644]
gcc/testsuite/gfortran.dg/gomp/target-update-iterators-3.f90 [new file with mode: 0644]
libgomp/ChangeLog.omp
libgomp/testsuite/libgomp.fortran/target-update-iterators-1.f90 [new file with mode: 0644]
libgomp/testsuite/libgomp.fortran/target-update-iterators-2.f90 [new file with mode: 0644]
libgomp/testsuite/libgomp.fortran/target-update-iterators-3.f90 [new file with mode: 0644]

index c652ec1775a9daf1daadf62f73998756f72a68d4..ebbdf3d149e7195dce61e6578bdee9a22ed73db0 100644 (file)
@@ -1,3 +1,18 @@
+2025-04-17  Kwok Cheung Yeung  <kcyeung@baylibre.com>
+
+       * dump-parse-tree.cc (show_omp_namelist): Add iterator support for
+       OMP_LIST_TO and OMP_LIST_FROM.
+       * match.cc (gfc_free_namelist): Free namespace for OMP_LIST_TO and
+       OMP_LIST_FROM.
+       * openmp.cc (gfc_free_omp_clauses): Free namespace for OMP_LIST_TO
+       and OMP_LIST_FROM.
+       (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.
+
 2025-04-17  Kwok Cheung Yeung  <kcyeung@baylibre.com>
 
        * dump-parse-tree.cc (show_omp_namelist): Add iterator support for
index 9fce015598e2526ea7b09cb5f44c7ad5a37d9da0..1ac1d632031ade5a0485500484d1be8e6ead299d 100644 (file)
@@ -1354,7 +1354,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)
@@ -1370,6 +1371,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 ();
                }
index 2bf1a7f583b260f710c3ed5efc4fd5ff9a4df92e..1986803bbeac4f1f80d6734ec3bdd68586395091 100644 (file)
@@ -5540,7 +5540,8 @@ void
 gfc_free_omp_namelist (gfc_omp_namelist *name, int 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_mapper = (list == OMP_LIST_MAP
                      || list == OMP_LIST_TO
                      || list == OMP_LIST_FROM);
index bb67ee8a2b695cea0e0e420b0c3a842ffc436254..99029d63059d9e13a31a599f89035381ef013e2e 100644 (file)
@@ -1415,11 +1415,14 @@ gfc_match_motion_var_list (const char *str, gfc_omp_namelist **list,
   if (m != MATCH_YES)
     return m;
 
+  gfc_namespace *ns_iter = NULL, *ns_curr = gfc_current_ns;
   locus old_loc = gfc_current_locus;
   int present_modifier = 0;
   int mapper_modifier = 0;
+  int iterator_modifier = 0;
   locus second_mapper_locus = old_loc;
   locus second_present_locus = old_loc;
+  locus second_iterator_locus = old_loc;
   char mapper_id[GFC_MAX_SYMBOL_LEN + 1] = { '\0' };
 
   for (;;)
@@ -1440,6 +1443,11 @@ gfc_match_motion_var_list (const char *str, gfc_omp_namelist **list,
          if (strcmp (mapper_id, "default") == 0)
            mapper_id[0] = '\0';
        }
+      else if (gfc_match_iterator (&ns_iter, true) == MATCH_YES)
+       {
+         if (iterator_modifier++ == 1)
+           second_iterator_locus = current_locus;
+       }
       else
        break;
       gfc_match (", ");
@@ -1450,6 +1458,7 @@ gfc_match_motion_var_list (const char *str, gfc_omp_namelist **list,
       gfc_current_locus = old_loc;
       present_modifier = 0;
       mapper_modifier = 0;
+      iterator_modifier = 0;
     }
 
   if (present_modifier > 1)
@@ -1462,8 +1471,18 @@ gfc_match_motion_var_list (const char *str, gfc_omp_namelist **list,
       gfc_error ("too many %<mapper%> modifiers at %L", &second_mapper_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;
   gfc_omp_namelist *n;
@@ -1477,6 +1496,12 @@ gfc_match_motion_var_list (const char *str, gfc_omp_namelist **list,
          n->u3.udm = gfc_get_omp_namelist_udm ();
          n->u3.udm->mapper_id = gfc_get_string ("%s", mapper_id);
        }
+
+      if (iterator_modifier)
+       {
+         n->u2.ns = ns_iter;
+         ns_iter->refs++;
+       }
     }
   return MATCH_YES;
 }
@@ -10112,7 +10137,8 @@ resolve_omp_clauses (gfc_code *code, gfc_omp_clauses *omp_clauses,
                      }
                  }
                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;
index 974092c4ebad829d554c33c7eeb3b3f6306dd38e..5d62ea396df316d0396bf99cf833780e3182ce23 100644 (file)
@@ -6411,11 +6411,39 @@ 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)
                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:
@@ -6612,7 +6640,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));
@@ -6637,7 +6665,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)));
                    }
@@ -6646,9 +6674,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));
@@ -6657,7 +6685,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);
                }
@@ -6665,8 +6693,20 @@ 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:
          for (; n != NULL; n = n->next)
index e25ef2000693844eaf2072317ee9048cc2b58b7b..08a3f26046eff188f22dd95206ea42e57f184b8f 100644 (file)
@@ -1,3 +1,9 @@
+2025-04-17  Kwok Cheung Yeung  <kcyeung@baylibre.com>
+
+       * 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.
+
 2025-04-17  Kwok Cheung Yeung  <kcyeung@baylibre.com>
 
        * gfortran.dg/gomp/target-map-iterators-1.f90: New.
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 (file)
index 0000000..d3acd84
--- /dev/null
@@ -0,0 +1,25 @@
+! { 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), 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 "Syntax error in OpenMP variable list 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 (file)
index 0000000..c57b87c
--- /dev/null
@@ -0,0 +1,28 @@
+! { 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) ! { dg-warning "iterator variable .i. not used in clause expression" }
+  !$omp target update from(iterator(i2=1:10, j2=1:20): x(i2)) ! { dg-warning "iterator variable .j2. not used in clause expression" }
+  !$omp target update to(iterator(i3=1:10, j3=1:20, k3=1:30): x(i3+j3), y(j3+k3), z(k3+i3))
+  ! { dg-warning "iterator variable .i3. not used in clause expression" "" { target *-*-* } .-1 }
+  ! { dg-warning "iterator variable .j3. not used in clause expression" "" { target *-*-* } .-2 }
+  ! { dg-warning "iterator variable .k3. not used in clause expression" "" { target *-*-* } .-3 }
+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 (file)
index 0000000..d9c92cf
--- /dev/null
@@ -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" } }
index 82ae5f87666377c954022b8b1e3e62bf00b4931f..3d6163db85ed6d51bea3669e237a43e2194f3e6a 100644 (file)
@@ -1,3 +1,9 @@
+2025-04-17  Kwok Cheung Yeung  <kcyeung@baylibre.com>
+
+       * 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.
+
 2025-04-17  Kwok Cheung Yeung  <kcyeung@baylibre.com>
 
        * target.c (kind_to_name): Handle GOMP_MAP_STRUCT and
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 (file)
index 0000000..e9a13a3
--- /dev/null
@@ -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 (file)
index 0000000..2e982bc
--- /dev/null
@@ -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 (file)
index 0000000..54b2a6c
--- /dev/null
@@ -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