[gcc/devel/omp/gcc-16] OpenMP, Fortran: Enable 'declare mapper' mappers for 'target update' directives

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

commit 0ae115b2c2faa7cc98132d4369b456be21eb4a71
Author: Julian Brown <[email protected]>
Date:   Tue Jul 7 17:43:08 2026 +0000

    OpenMP, Fortran: Enable 'declare mapper' mappers for 'target update' directives
    
    This patch enables use of 'declare mapper' for 'target update'
    directives for Fortran.  It is based on OG15 commit 6ffe14f3198;
    the C and C++ support was previously upstreamed as commit
    r17-680-g09e74059bdb12c, so only the Fortran parts are left here.
    
    2023-08-10  Julian Brown  <[email protected]>
    
    gcc/fortran/
            * openmp.cc (gfc_match_motion_var_list): Add parsing for mapper
            modifier.
            (gfc_match_omp_clauses): Adjust error handling for changes to
            gfc_match_motion_var_list.
            (gfc_omp_instantiate_mapper): Add code argument to get proper
            location for diagnostic.
            (gfc_omp_instantiate_mappers): Adjust for above change.
            * trans-openmp.cc (gfc_trans_omp_clauses): Use correct ref for update
            operations.
            (gfc_trans_omp_target_update): Instantiate mappers.
    
    gcc/testsuite/
            * gfortran.dg/gomp/declare-mapper-24.f90: New test.
            * gfortran.dg/gomp/declare-mapper-26.f90: Uncomment 'target update'
            part of test.
            * gfortran.dg/gomp/declare-mapper-27.f90: New test.
    
    libgomp/
            * testsuite/libgomp.fortran/declare-mapper-25.f90: New test.
            * testsuite/libgomp.fortran/declare-mapper-28.f90: New test.
    
    Co-Authored-By: Andrew Stubbs  <[email protected]>
    Co-Authored-By: Kwok Cheung Yeung <[email protected]>
    Co-Authored-By: Sandra Loosemore <[email protected]>

Diff:
---
 gcc/fortran/openmp.cc                              | 67 +++++++++++++++++-----
 gcc/fortran/trans-openmp.cc                        | 30 +++++++---
 .../gfortran.dg/gomp/declare-mapper-24.f90         | 43 ++++++++++++++
 .../gfortran.dg/gomp/declare-mapper-26.f90         |  4 +-
 .../gfortran.dg/gomp/declare-mapper-27.f90         | 25 ++++++++
 .../libgomp.fortran/declare-mapper-25.f90          | 44 ++++++++++++++
 .../libgomp.fortran/declare-mapper-28.f90          | 38 ++++++++++++
 7 files changed, 225 insertions(+), 26 deletions(-)

diff --git a/gcc/fortran/openmp.cc b/gcc/fortran/openmp.cc
index ccc65dda7b79..a7a67814a93b 100644
--- a/gcc/fortran/openmp.cc
+++ b/gcc/fortran/openmp.cc
@@ -1441,12 +1441,15 @@ gfc_match_motion_var_list (const char *str, gfc_omp_namelist **list,
 
   gfc_namespace *ns_iter = NULL, *ns_curr = gfc_current_ns;
   locus old_loc = gfc_current_locus;
+  int mapper_modifier = 0;
   int present_modifier = 0;
   int iterator_modifier = 0;
+  locus second_mapper_locus = old_loc;
   locus second_present_locus = old_loc;
   locus second_iterator_locus = old_loc;
   bool saw_modifier = false;
-
+  char mapper_id[GFC_MAX_SYMBOL_LEN + 1] = { '\0' };
+ 
   for (;;)
     {
       locus current_locus = gfc_current_locus;
@@ -1455,6 +1458,16 @@ gfc_match_motion_var_list (const char *str, gfc_omp_namelist **list,
 	  if (present_modifier++ == 1)
 	    second_present_locus = current_locus;
 	}
+      else if (gfc_match ("mapper ( ") == MATCH_YES)
+	{
+	  if (mapper_modifier++ == 1)
+	    second_mapper_locus = current_locus;
+	  m = gfc_match (" %n ) ", mapper_id);
+	  if (m != MATCH_YES)
+	    return m;
+	  if (strcmp (mapper_id, "default") == 0)
+	    mapper_id[0] = '\0';
+	}
       else if (gfc_match_iterator (&ns_iter, true) == MATCH_YES)
 	{
 	  if (iterator_modifier++ == 1)
@@ -1489,6 +1502,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;
     }
 
@@ -1497,6 +1511,11 @@ gfc_match_motion_var_list (const char *str, gfc_omp_namelist **list,
       gfc_error ("Too many %<present%> modifiers at %L", &second_present_locus);
       return MATCH_ERROR;
     }
+  if (mapper_modifier > 1)
+    {
+      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",
@@ -1516,6 +1535,11 @@ gfc_match_motion_var_list (const char *str, gfc_omp_namelist **list,
     {
       if (present_modifier)
 	n->u.present_modifier = true;
+      if (mapper_id[0] != '\0')
+	{
+	  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;
@@ -3343,10 +3367,15 @@ gfc_match_omp_clauses (gfc_omp_clauses **cp, const omp_mask mask,
 					      &c->lists[OMP_LIST_FIRSTPRIVATE],
 					      true) == MATCH_YES)
 	    continue;
-	  if ((mask & OMP_CLAUSE_FROM)
-	      && gfc_match_motion_var_list ("from (", &c->lists[OMP_LIST_FROM],
-					     &head) == MATCH_YES)
-	    continue;
+	  if (mask & OMP_CLAUSE_FROM)
+	    {
+	      m = gfc_match_motion_var_list ("from (", &c->lists[OMP_LIST_FROM],
+					     &head);
+	      if (m == MATCH_YES)
+		continue;
+	      else if (m == MATCH_ERROR)
+		goto error;
+	    }
 	  if ((mask & OMP_CLAUSE_FULL)
 	      && (m = gfc_match_dupl_check (!c->full, "full")) != MATCH_NO)
 	    {
@@ -4558,10 +4587,15 @@ gfc_match_omp_clauses (gfc_omp_clauses **cp, const omp_mask mask,
 		  continue;
 		}
 	    }
-	  else if ((mask & OMP_CLAUSE_TO)
-		   && gfc_match_motion_var_list ("to (", &c->lists[OMP_LIST_TO],
-						 &head) == MATCH_YES)
-	    continue;
+	  else if (mask & OMP_CLAUSE_TO)
+	    {
+	      m = gfc_match_motion_var_list ("to (", &c->lists[OMP_LIST_TO],
+						 &head);
+	      if (m == MATCH_YES)
+		continue;
+	      else if (m == MATCH_ERROR)
+		goto error;
+	    }
 	  break;
 	case 'u':
 	  if ((mask & OMP_CLAUSE_UNIFORM)
@@ -14471,7 +14505,7 @@ gfc_subst_mapper_var (gfc_symbol **out_sym, gfc_expr **out_expr,
 }
 
 static gfc_omp_namelist **
-gfc_omp_instantiate_mapper (gfc_omp_namelist **outlistp,
+gfc_omp_instantiate_mapper (gfc_code *code, gfc_omp_namelist **outlistp,
 			    gfc_omp_namelist *clause,
 			    gfc_omp_map_op outer_map_op, gfc_omp_udm *udm,
 			    toc_directive cd, int list)
@@ -14577,8 +14611,10 @@ gfc_omp_instantiate_mapper (gfc_omp_namelist **outlistp,
 		  = omp_split_map_op (map_clause_op, &force_p, &always_p,
 				      &present_p);
 		free (new_clause);
-		gfc_warning (0, "Dropping incompatible %qs mapper clause at %C",
-			     omp_basic_map_kind_name (basic_kind));
+		gfc_warning (OPT_Wopenmp,
+			     "Dropping incompatible %qs mapper clause at %L",
+			     omp_basic_map_kind_name (basic_kind),
+			     &code->loc);
 		inform (gfc_get_location (&mapper_clause->where),
 			"Defined here");
 		continue;
@@ -14594,7 +14630,7 @@ gfc_omp_instantiate_mapper (gfc_omp_namelist **outlistp,
 	  && mapper_clause->u3.udm->udm != udm)
 	{
 	  gfc_omp_udm *inner_udm = mapper_clause->u3.udm->udm;
-	  outlistp = gfc_omp_instantiate_mapper (outlistp, new_clause,
+	  outlistp = gfc_omp_instantiate_mapper (code, outlistp, new_clause,
 						 outer_map_op, inner_udm, cd,
 						 list);
 	}
@@ -14612,7 +14648,7 @@ gfc_omp_instantiate_mapper (gfc_omp_namelist **outlistp,
    false if errors were diagnosed.  This function is invoked from the
    translation phase so callers need to handle passing up the error.  */
 bool
-gfc_omp_instantiate_mappers (gfc_code *code ATTRIBUTE_UNUSED, gfc_omp_clauses *clauses,
+gfc_omp_instantiate_mappers (gfc_code *code, gfc_omp_clauses *clauses,
 			     toc_directive cd, int list)
 {
   gfc_omp_namelist *clause = clauses->lists[list];
@@ -14643,7 +14679,8 @@ gfc_omp_instantiate_mappers (gfc_code *code ATTRIBUTE_UNUSED, gfc_omp_clauses *c
 	    default:
 	      gcc_unreachable ();
 	    }
-	  clausep = gfc_omp_instantiate_mapper (clausep, clause, outer_map_op,
+	  clausep = gfc_omp_instantiate_mapper (code, clausep, clause,
+						outer_map_op,
 						clause->u3.udm->udm, cd, list);
 	  *clausep = clause->next;
 	  invoked_mappers = true;
diff --git a/gcc/fortran/trans-openmp.cc b/gcc/fortran/trans-openmp.cc
index c517a22e0415..3549d2737379 100644
--- a/gcc/fortran/trans-openmp.cc
+++ b/gcc/fortran/trans-openmp.cc
@@ -6059,14 +6059,17 @@ gfc_trans_omp_clauses (stmtblock_t *block, gfc_omp_clauses *clauses,
 		  gcc_unreachable ();
 		}
 
+	      gfc_ref *lastref = NULL;
+	      if (n->expr)
+		for (gfc_ref *ref = n->expr->ref; ref; ref = ref->next)
+		  if (ref->type == REF_COMPONENT || ref->type == REF_ARRAY)
+		    lastref = ref;
+
 	      /* FIXME: Currently no support for strided target updates with
 		 iterators.  */
 	      if ((list == OMP_LIST_TO || list == OMP_LIST_FROM)
 		  && !iterator
-		  && (!n->expr
-		       || (n->expr
-			   && n->expr->ref
-			   && n->expr->ref->type == REF_ARRAY))
+		  && (!n->expr || (lastref && lastref->type == REF_ARRAY))
 		  && !gfc_omp_contiguous_update_p (n))
 		{
 		  int ndims;
@@ -6088,7 +6091,7 @@ gfc_trans_omp_clauses (stmtblock_t *block, gfc_omp_clauses *clauses,
 			 or other data between elements, e.g. of a derived-type
 			 array).  */
 		      span = gfc_get_array_span (desc, n->expr);
-		      ndims = n->expr->ref->u.ar.dimen;
+		      ndims = lastref->u.ar.dimen;
 		    }
 		  else
 		    {
@@ -10624,10 +10627,19 @@ gfc_trans_omp_target_update (gfc_code *code)
   tree stmt, omp_clauses;
 
   gfc_start_block (&block);
-  omp_clauses = gfc_trans_omp_clauses (&block, code->ext.omp_clauses,
-				       code->loc);
-  stmt = build1_loc (input_location, OMP_TARGET_UPDATE, void_type_node,
-		     omp_clauses);
+  gfc_omp_clauses *target_update_clauses = code->ext.omp_clauses;
+  if (gfc_omp_instantiate_mappers (code, target_update_clauses, TOC_OPENMP,
+				   OMP_LIST_TO)
+      && gfc_omp_instantiate_mappers (code, target_update_clauses, TOC_OPENMP,
+				      OMP_LIST_FROM))
+    {
+      omp_clauses = gfc_trans_omp_clauses (&block, target_update_clauses,
+					   code->loc);
+      stmt = build1_loc (input_location, OMP_TARGET_UPDATE, void_type_node,
+			 omp_clauses);
+    }
+  else
+    stmt = error_mark_node;
   gfc_add_expr_to_block (&block, stmt);
   return gfc_finish_block (&block);
 }
diff --git a/gcc/testsuite/gfortran.dg/gomp/declare-mapper-24.f90 b/gcc/testsuite/gfortran.dg/gomp/declare-mapper-24.f90
new file mode 100644
index 000000000000..9555a94badab
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/gomp/declare-mapper-24.f90
@@ -0,0 +1,43 @@
+! { dg-do compile }
+! { dg-additional-options "-fdump-tree-original" }
+
+type t
+integer :: a, b, c, d
+end type t
+
+type(t) :: tvar
+
+!$omp declare mapper (T :: t) map(alloc: t%a) map(to: t%b) map(from: t%c) &
+!$omp & map(tofrom: t%d)
+
+!$omp declare mapper (updatey: T :: t) map(t%a) map(t%b) map(t%c) map(t%d)
+
+!$omp target update to(tvar)
+! { dg-warning "Dropping incompatible .ALLOC. mapper clause" "" { target *-*-* } .-1 }
+! { dg-warning "Dropping incompatible .FROM. mapper clause" "" { target *-*-* } .-2 }
+! { dg-final { scan-tree-dump-times {(?n)update to\(tvar\.b \[len: [0-9]+\]\) to\(tvar\.d \[len: [0-9]+\]\)$} 1 "original" } }
+!$omp target update from(tvar)
+! { dg-warning "Dropping incompatible .ALLOC. mapper clause" "" { target *-*-* } .-1 }
+! { dg-warning "Dropping incompatible .TO. mapper clause" "" { target *-*-* } .-2 }
+! { dg-final { scan-tree-dump-times {(?n)update from\(tvar\.c \[len: [0-9]+\]\) from\(tvar\.d \[len: [0-9]+\]\)$} 1 "original" } }
+
+!$omp target update to(present: tvar)
+! { dg-warning "Dropping incompatible .ALLOC. mapper clause" "" { target *-*-* } .-1 }
+! { dg-warning "Dropping incompatible .FROM. mapper clause" "" { target *-*-* } .-2 }
+! { dg-final { scan-tree-dump-times {(?n)update to\(present:tvar\.b \[len: [0-9]+\]\) to\(present:tvar\.d \[len: [0-9]+\]\)$} 1 "original" } }
+!$omp target update from(present: tvar)
+! { dg-warning "Dropping incompatible .ALLOC. mapper clause" "" { target *-*-* } .-1 }
+! { dg-warning "Dropping incompatible .TO. mapper clause" "" { target *-*-* } .-2 }
+! { dg-final { scan-tree-dump-times {(?n)update from\(present:tvar\.c \[len: [0-9]+\]\) from\(present:tvar\.d \[len: [0-9]+\]\)$} 1 "original" } }
+
+!$omp target update to(mapper(updatey): tvar)
+! { dg-final { scan-tree-dump-times {(?n)update to\(tvar\.a \[len: [0-9]+\]\) to\(tvar\.b \[len: [0-9]+\]\) to\(tvar\.c \[len: [0-9]+\]\) to\(tvar\.d \[len: [0-9]+\]\)$} 1 "original" } }
+!$omp target update from(mapper(updatey): tvar)
+! { dg-final { scan-tree-dump-times {(?n)update from\(tvar\.a \[len: [0-9]+\]\) from\(tvar\.b \[len: [0-9]+\]\) from\(tvar\.c \[len: [0-9]+\]\) from\(tvar\.d \[len: [0-9]+\]\)$} 1 "original" } }
+
+!$omp target update to(present, mapper(updatey): tvar)
+! { dg-final { scan-tree-dump-times {(?n)update to\(present:tvar\.a \[len: [0-9]+\]\) to\(present:tvar\.b \[len: [0-9]+\]\) to\(present:tvar\.c \[len: [0-9]+\]\) to\(present:tvar\.d \[len: [0-9]+\]\)$} 1 "original" } }
+!$omp target update from(present, mapper(updatey): tvar)
+! { dg-final { scan-tree-dump-times {(?n)update from\(present:tvar\.a \[len: [0-9]+\]\) from\(present:tvar\.b \[len: [0-9]+\]\) from\(present:tvar\.c \[len: [0-9]+\]\) from\(present:tvar\.d \[len: [0-9]+\]\)$} 1 "original" } }
+
+end
diff --git a/gcc/testsuite/gfortran.dg/gomp/declare-mapper-26.f90 b/gcc/testsuite/gfortran.dg/gomp/declare-mapper-26.f90
index c408b37f5a97..16afb51f48a5 100644
--- a/gcc/testsuite/gfortran.dg/gomp/declare-mapper-26.f90
+++ b/gcc/testsuite/gfortran.dg/gomp/declare-mapper-26.f90
@@ -18,8 +18,8 @@ var%arr = 0
 
 var%arr = 1
 
-! But this is fine.  (Re-enabled by later patch.)
-!!$omp target update to(mapper(even): var)
+! But this is fine.
+!$omp target update to(mapper(even): var)
 
 ! As 'enter data'.
 !$omp target exit data map(mapper(even), delete: var)
diff --git a/gcc/testsuite/gfortran.dg/gomp/declare-mapper-27.f90 b/gcc/testsuite/gfortran.dg/gomp/declare-mapper-27.f90
new file mode 100644
index 000000000000..6b3a181acaa5
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/gomp/declare-mapper-27.f90
@@ -0,0 +1,25 @@
+! { dg-do compile }
+
+type t
+integer :: x
+end type t
+
+type(t) :: var
+
+! Error on attempt to use missing named mapper.
+!$omp target update to(mapper(boo): var)
+! { dg-error {User-defined mapper .boo. not found} "" { target *-*-* } .-1 }
+
+var%x = 0
+
+!$omp target map(mapper(boo), tofrom: var)
+! { dg-error {User-defined mapper .boo. not found} "" { target *-*-* } .-1 }
+var%x = 5
+!$omp end target
+
+! These should be fine though...
+!$omp target enter data map(mapper(default), to: var)
+
+!$omp target exit data map(from: var)
+
+end
diff --git a/libgomp/testsuite/libgomp.fortran/declare-mapper-25.f90 b/libgomp/testsuite/libgomp.fortran/declare-mapper-25.f90
new file mode 100644
index 000000000000..dc1f5272a261
--- /dev/null
+++ b/libgomp/testsuite/libgomp.fortran/declare-mapper-25.f90
@@ -0,0 +1,44 @@
+! { dg-do run }
+! { dg-require-effective-target offload_device_nonshared_as }
+
+type t
+integer, allocatable :: arr(:)
+end type t
+
+!$omp declare mapper(odd: T :: tv) map(tv%arr(1::2))
+!$omp declare mapper(even: T :: tv) map(tv%arr(2::2))
+
+type(t) :: var
+integer :: i
+
+allocate(var%arr(100))
+
+var%arr = 0
+
+!$omp target enter data map(to: var)
+
+var%arr = 1
+
+!$omp target update to(mapper(odd): var)
+
+!$omp target
+do i=1,100
+  if (mod(i,2).eq.0.and.var%arr(i).ne.0) stop 1
+  if (mod(i,2).eq.1.and.var%arr(i).ne.1) stop 2
+end do
+!$omp end target
+
+var%arr = 2
+
+!$omp target update to(mapper(even): var)
+
+!$omp target
+do i=1,100
+  if (mod(i,2).eq.0.and.var%arr(i).ne.2) stop 3
+  if (mod(i,2).eq.1.and.var%arr(i).ne.1) stop 4
+end do
+!$omp end target
+
+!$omp target exit data map(delete: var)
+
+end
diff --git a/libgomp/testsuite/libgomp.fortran/declare-mapper-28.f90 b/libgomp/testsuite/libgomp.fortran/declare-mapper-28.f90
new file mode 100644
index 000000000000..6561decc49a9
--- /dev/null
+++ b/libgomp/testsuite/libgomp.fortran/declare-mapper-28.f90
@@ -0,0 +1,38 @@
+! { dg-do run }
+
+program p
+
+type t
+integer :: x, y
+end type t
+
+type(t) :: var
+
+var%x = 0
+var%y = 0
+
+var = sub(7)
+
+contains
+
+type(t) function sub(arg)
+integer :: arg
+
+!$omp declare mapper (t :: tvar) map(tvar%x, tvar%y)
+
+!$omp target enter data map(alloc: sub)
+
+sub%x = 5
+sub%y = arg
+
+!$omp target update to(sub)
+
+!$omp target
+if (sub%x.ne.5) stop 1
+if (sub%y.ne.7) stop 2
+!$omp end target
+
+!$omp target exit data map(release: sub)
+
+end function sub
+end program p
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.