Add support of the 'self_maps' clause in 'omp requires',
an OpenMP 6 feature but added here mostly as part of the
on-going improvement of the unified-shared memory (USM) handling.

Comments, remarks concerns before I commit it?

* * *

Regarding USM, there is on one hand the hardware:

- some hardware cannot access the host memory at all
- other hardware can access it, but either only through
  an interconnect or via page migration on page fault
- on the third time of hardware, a host and device share
  the same memory controller

For the latter, a 'map' never does make sense, but for
the second case, it depends on the details whether it is
better to do mapping or directly accessing the memory
(i.e. via interconnect or page migration).

On the compile-time side, the user can demand:
- no requirement
- 'requires unified_shared_memory' (= memory has to be accessible
  but the implementation can still do mapping for explicit maps)
- 'requires shared_memory' - mapping is strictly not permitted.
- other hints using compiler flags

And for the runtime, the result depends on the actual hardware,
the compile-time wishes, environment variables what is done.

* * *

Currently, the runtime never maps with USM, i.e. both act the same.
At least using an environment variable, I would consider enabling
mapping - one could also consider to have it always do mappings,
except for self_maps.

On the compile side, we need to handle implicit 'declare target'
better - as it currently leads to separate memory. Using 'link',
we could point to the host memory (at least for 'self_maps').

And before we can enable USM by default for integrated/APU devices,
we need to solve some issues with 'link' (→ posted link) and for
those, 'map' has to be honored.

Those are 5.x follow up tasks, but having 'self_maps' available,
completes the what-does-the-user-want part.

Tobias

PS: There is also the 'self' modifier to the map clause, working
on a per-variable granularity. However, this like several other
6.0 items is completely out of scope of the current USM work.

PPS: See also 
https://gcc.gnu.org/pipermail/gcc-patches/2024-September/663209.html
and the patch associated set, posted
at https://gcc.gnu.org/pipermail/gcc-patches/2024-June/655946.html
OpenMP: Add support for 'self_maps' to the 'require' directive

'self_maps' implies 'unified_shared_memory', except that the latter
also permits that explicit maps copy data to device memory while
self_maps does not. In GCC, currently, both are handled identical.

gcc/c/ChangeLog:

	* c-parser.cc (c_parser_omp_requires): Handle self_maps clause.

gcc/cp/ChangeLog:

	* parser.cc (cp_parser_omp_requires): Handle self_maps clause.

gcc/fortran/ChangeLog:

	* gfortran.h (enum gfc_omp_requires_kind): Add OMP_REQ_SELF_MAPS.
	(gfc_namespace): Enlarge omp_requires bitfield.
	* module.cc (enum ab_attribute, attr_bits): Add AB_OMP_REQ_SELF_MAPS.
	(mio_symbol_attribute): Handle it.
	* openmp.cc (gfc_check_omp_requires, gfc_match_omp_requires): Handle
	self_maps clause.
	* parse.cc (gfc_parse_file): Handle self_maps clause.

gcc/ChangeLog:

	* lto-cgraph.cc (output_offload_tables, omp_requires_to_name): Handle
	self_maps clause.
	* omp-general.cc (struct omp_ts_info, omp_context_selector_matches):
	Likewise for the associated trait.
	* omp-general.h (enum omp_requires): Add OMP_REQUIRES_SELF_MAPS.
	* omp-selectors.h (enum omp_ts_code): Add
	OMP_TRAIT_IMPLEMENTATION_SELF_MAPS.

include/ChangeLog:

	* gomp-constants.h (GOMP_REQUIRES_SELF_MAPS): #define.

libgomp/ChangeLog:

	* plugin/plugin-gcn.c (GOMP_OFFLOAD_get_num_devices):
	Accept self_maps clause.
	* plugin/plugin-nvptx.c (GOMP_OFFLOAD_get_num_devices):
	Likewise.
	* libgomp.texi (TR13 Impl. Status): Set to 'Y'.
	* target.c (gomp_requires_to_name, GOMP_offload_register_ver,
	gomp_target_init): Handle self_maps clause.
	* testsuite/libgomp.fortran/self_maps.f90: New test.

gcc/testsuite/ChangeLog:

	* c-c++-common/gomp/declare-variant-1.c: Add self_maps test.
	* c-c++-common/gomp/requires-4.c: Likewise.
	* gfortran.dg/gomp/declare-variant-3.f90:  Likewise.
	* c-c++-common/gomp/requires-2.c: Update dg-error msg.
	* gfortran.dg/gomp/requires-2.f90: Likewie.

 gcc/c/c-parser.cc                                  |  3 ++
 gcc/cp/parser.cc                                   |  3 ++
 gcc/fortran/gfortran.h                             | 10 +++--
 gcc/fortran/module.cc                              | 11 ++++-
 gcc/fortran/openmp.cc                              | 30 ++++++++-----
 gcc/fortran/parse.cc                               |  3 ++
 gcc/lto-cgraph.cc                                  |  4 ++
 gcc/omp-general.cc                                 | 21 ++++++++++
 gcc/omp-general.h                                  |  1 +
 gcc/omp-selectors.h                                |  1 +
 .../c-c++-common/gomp/declare-variant-1.c          |  6 +++
 gcc/testsuite/c-c++-common/gomp/requires-2.c       |  2 +-
 gcc/testsuite/c-c++-common/gomp/requires-4.c       |  1 +
 .../gfortran.dg/gomp/declare-variant-3.f90         |  3 ++
 gcc/testsuite/gfortran.dg/gomp/requires-2.f90      |  2 +-
 include/gomp-constants.h                           |  4 ++
 libgomp/libgomp.texi                               |  2 +-
 libgomp/plugin/plugin-gcn.c                        |  4 +-
 libgomp/plugin/plugin-nvptx.c                      |  4 +-
 libgomp/target.c                                   | 10 +++--
 libgomp/testsuite/libgomp.fortran/self_maps.f90    | 49 ++++++++++++++++++++++
 21 files changed, 150 insertions(+), 24 deletions(-)

diff --git a/gcc/c/c-parser.cc b/gcc/c/c-parser.cc
index aff5af17430..6a46577f511 100644
--- a/gcc/c/c-parser.cc
+++ b/gcc/c/c-parser.cc
@@ -26208,6 +26208,8 @@ c_parser_omp_requires (c_parser *parser)
 	    this_req = OMP_REQUIRES_UNIFIED_ADDRESS;
 	  else if (!strcmp (p, "unified_shared_memory"))
 	    this_req = OMP_REQUIRES_UNIFIED_SHARED_MEMORY;
+	  else if (!strcmp (p, "self_maps"))
+	    this_req = OMP_REQUIRES_SELF_MAPS;
 	  else if (!strcmp (p, "dynamic_allocators"))
 	    this_req = OMP_REQUIRES_DYNAMIC_ALLOCATORS;
 	  else if (!strcmp (p, "reverse_offload"))
@@ -26274,6 +26276,7 @@ c_parser_omp_requires (c_parser *parser)
 	    {
 	      error_at (cloc, "expected %<unified_address%>, "
 			      "%<unified_shared_memory%>, "
+			      "%<self_maps%>, "
 			      "%<dynamic_allocators%>, "
 			       "%<reverse_offload%> "
 			       "or %<atomic_default_mem_order%> clause");
diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc
index 4dd9474cf60..c8bb166ce06 100644
--- a/gcc/cp/parser.cc
+++ b/gcc/cp/parser.cc
@@ -50239,6 +50239,8 @@ cp_parser_omp_requires (cp_parser *parser, cp_token *pragma_tok)
 	    this_req = OMP_REQUIRES_UNIFIED_ADDRESS;
 	  else if (!strcmp (p, "unified_shared_memory"))
 	    this_req = OMP_REQUIRES_UNIFIED_SHARED_MEMORY;
+	  else if (!strcmp (p, "self_maps"))
+	    this_req = OMP_REQUIRES_SELF_MAPS;
 	  else if (!strcmp (p, "dynamic_allocators"))
 	    this_req = OMP_REQUIRES_DYNAMIC_ALLOCATORS;
 	  else if (!strcmp (p, "reverse_offload"))
@@ -50311,6 +50313,7 @@ cp_parser_omp_requires (cp_parser *parser, cp_token *pragma_tok)
 	    {
 	      error_at (cloc, "expected %<unified_address%>, "
 			      "%<unified_shared_memory%>, "
+			      "%<self_maps%>, "
 			      "%<dynamic_allocators%>, "
 			       "%<reverse_offload%> "
 			       "or %<atomic_default_mem_order%> clause");
diff --git a/gcc/fortran/gfortran.h b/gcc/fortran/gfortran.h
index 37c28691f41..66c9736122a 100644
--- a/gcc/fortran/gfortran.h
+++ b/gcc/fortran/gfortran.h
@@ -1521,7 +1521,7 @@ enum gfc_omp_atomic_op
 
 enum gfc_omp_requires_kind
 {
-  /* Keep in sync with gfc_namespace, esp. with omp_req_mem_order.  */
+  /* Keep gfc_namespace's omp_requires bitfield size in sync.  */
   OMP_REQ_ATOMIC_MEM_ORDER_SEQ_CST = 1,  /* 001 */
   OMP_REQ_ATOMIC_MEM_ORDER_ACQ_REL = 2,  /* 010 */
   OMP_REQ_ATOMIC_MEM_ORDER_RELAXED = 3,  /* 011 */
@@ -1530,10 +1530,12 @@ enum gfc_omp_requires_kind
   OMP_REQ_REVERSE_OFFLOAD = (1 << 3),
   OMP_REQ_UNIFIED_ADDRESS = (1 << 4),
   OMP_REQ_UNIFIED_SHARED_MEMORY = (1 << 5),
-  OMP_REQ_DYNAMIC_ALLOCATORS = (1 << 6),
+  OMP_REQ_SELF_MAPS = (1 << 6),
+  OMP_REQ_DYNAMIC_ALLOCATORS = (1 << 7),
   OMP_REQ_TARGET_MASK = (OMP_REQ_REVERSE_OFFLOAD
 			 | OMP_REQ_UNIFIED_ADDRESS
-			 | OMP_REQ_UNIFIED_SHARED_MEMORY),
+			 | OMP_REQ_UNIFIED_SHARED_MEMORY
+			 | OMP_REQ_SELF_MAPS),
   OMP_REQ_ATOMIC_MEM_ORDER_MASK = (OMP_REQ_ATOMIC_MEM_ORDER_SEQ_CST
 				   | OMP_REQ_ATOMIC_MEM_ORDER_ACQ_REL
 				   | OMP_REQ_ATOMIC_MEM_ORDER_RELAXED
@@ -2290,7 +2292,7 @@ typedef struct gfc_namespace
   unsigned implicit_interface_calls:1;
 
   /* OpenMP requires. */
-  unsigned omp_requires:7;
+  unsigned omp_requires:8;
   unsigned omp_target_seen:1;
 
   /* Set to 1 if this is an implicit OMP structured block.  */
diff --git a/gcc/fortran/module.cc b/gcc/fortran/module.cc
index 8cf58ff5142..bf38127d213 100644
--- a/gcc/fortran/module.cc
+++ b/gcc/fortran/module.cc
@@ -2095,7 +2095,7 @@ enum ab_attribute
   AB_OACC_ROUTINE_LOP_GANG, AB_OACC_ROUTINE_LOP_WORKER,
   AB_OACC_ROUTINE_LOP_VECTOR, AB_OACC_ROUTINE_LOP_SEQ,
   AB_OACC_ROUTINE_NOHOST,
-  AB_OMP_REQ_REVERSE_OFFLOAD, AB_OMP_REQ_UNIFIED_ADDRESS,
+  AB_OMP_REQ_REVERSE_OFFLOAD, AB_OMP_REQ_UNIFIED_ADDRESS, AB_OMP_REQ_SELF_MAPS,
   AB_OMP_REQ_UNIFIED_SHARED_MEMORY, AB_OMP_REQ_DYNAMIC_ALLOCATORS,
   AB_OMP_REQ_MEM_ORDER_SEQ_CST, AB_OMP_REQ_MEM_ORDER_ACQ_REL,
   AB_OMP_REQ_MEM_ORDER_ACQUIRE, AB_OMP_REQ_MEM_ORDER_RELEASE,
@@ -2178,6 +2178,7 @@ static const mstring attr_bits[] =
     minit ("OMP_REQ_REVERSE_OFFLOAD", AB_OMP_REQ_REVERSE_OFFLOAD),
     minit ("OMP_REQ_UNIFIED_ADDRESS", AB_OMP_REQ_UNIFIED_ADDRESS),
     minit ("OMP_REQ_UNIFIED_SHARED_MEMORY", AB_OMP_REQ_UNIFIED_SHARED_MEMORY),
+    minit ("OMP_REQ_SELF_MAPS", AB_OMP_REQ_SELF_MAPS),
     minit ("OMP_REQ_DYNAMIC_ALLOCATORS", AB_OMP_REQ_DYNAMIC_ALLOCATORS),
     minit ("OMP_REQ_MEM_ORDER_SEQ_CST", AB_OMP_REQ_MEM_ORDER_SEQ_CST),
     minit ("OMP_REQ_MEM_ORDER_ACQ_REL", AB_OMP_REQ_MEM_ORDER_ACQ_REL),
@@ -2442,6 +2443,8 @@ mio_symbol_attribute (symbol_attribute *attr)
 	    MIO_NAME (ab_attribute) (AB_OMP_REQ_UNIFIED_ADDRESS, attr_bits);
 	  if (gfc_current_ns->omp_requires & OMP_REQ_UNIFIED_SHARED_MEMORY)
 	    MIO_NAME (ab_attribute) (AB_OMP_REQ_UNIFIED_SHARED_MEMORY, attr_bits);
+	  if (gfc_current_ns->omp_requires & OMP_REQ_SELF_MAPS)
+	    MIO_NAME (ab_attribute) (AB_OMP_REQ_SELF_MAPS, attr_bits);
 	  if (gfc_current_ns->omp_requires & OMP_REQ_DYNAMIC_ALLOCATORS)
 	    MIO_NAME (ab_attribute) (AB_OMP_REQ_DYNAMIC_ALLOCATORS, attr_bits);
 	  if ((gfc_current_ns->omp_requires & OMP_REQ_ATOMIC_MEM_ORDER_MASK)
@@ -2722,6 +2725,12 @@ mio_symbol_attribute (symbol_attribute *attr)
 					   &gfc_current_locus,
 					   module_name);
 	      break;
+	    case AB_OMP_REQ_SELF_MAPS:
+	      gfc_omp_requires_add_clause (OMP_REQ_SELF_MAPS,
+					   "self_maps",
+					   &gfc_current_locus,
+					   module_name);
+	      break;
 	    case AB_OMP_REQ_DYNAMIC_ALLOCATORS:
 	      gfc_omp_requires_add_clause (OMP_REQ_DYNAMIC_ALLOCATORS,
 					   "dynamic_allocators",
diff --git a/gcc/fortran/openmp.cc b/gcc/fortran/openmp.cc
index 050409e00a0..2d5c4305d2a 100644
--- a/gcc/fortran/openmp.cc
+++ b/gcc/fortran/openmp.cc
@@ -6759,6 +6759,9 @@ gfc_match_omp_parallel_workshare (void)
 void
 gfc_check_omp_requires (gfc_namespace *ns, int ref_omp_requires)
 {
+  const char *msg = G_("Program unit at %L has OpenMP device "
+		       "constructs/routines but does not set !$OMP REQUIRES %s "
+		       "but other program units do");
   if (ns->omp_target_seen
       && (ns->omp_requires & OMP_REQ_TARGET_MASK)
 	 != (ref_omp_requires & OMP_REQ_TARGET_MASK))
@@ -6766,19 +6769,16 @@ gfc_check_omp_requires (gfc_namespace *ns, int ref_omp_requires)
       gcc_assert (ns->proc_name);
       if ((ref_omp_requires & OMP_REQ_REVERSE_OFFLOAD)
 	  && !(ns->omp_requires & OMP_REQ_REVERSE_OFFLOAD))
-	gfc_error ("Program unit at %L has OpenMP device constructs/routines "
-		   "but does not set !$OMP REQUIRES REVERSE_OFFLOAD but other "
-		   "program units do", &ns->proc_name->declared_at);
+	gfc_error (msg, &ns->proc_name->declared_at, "REVERSE_OFFLOAD");
       if ((ref_omp_requires & OMP_REQ_UNIFIED_ADDRESS)
 	  && !(ns->omp_requires & OMP_REQ_UNIFIED_ADDRESS))
-	gfc_error ("Program unit at %L has OpenMP device constructs/routines "
-		   "but does not set !$OMP REQUIRES UNIFIED_ADDRESS but other "
-		   "program units do", &ns->proc_name->declared_at);
+	gfc_error (msg, &ns->proc_name->declared_at, "UNIFIED_ADDRESS");
       if ((ref_omp_requires & OMP_REQ_UNIFIED_SHARED_MEMORY)
 	  && !(ns->omp_requires & OMP_REQ_UNIFIED_SHARED_MEMORY))
-	gfc_error ("Program unit at %L has OpenMP device constructs/routines "
-		   "but does not set !$OMP REQUIRES UNIFIED_SHARED_MEMORY but "
-		   "other program units do", &ns->proc_name->declared_at);
+	gfc_error (msg, &ns->proc_name->declared_at, "UNIFIED_SHARED_MEMORY");
+      if ((ref_omp_requires & OMP_REQ_SELF_MAPS)
+	  && !(ns->omp_requires & OMP_REQ_UNIFIED_SHARED_MEMORY))
+	gfc_error (msg, &ns->proc_name->declared_at, "SELF_MAPS");
     }
 }
 
@@ -6868,6 +6868,7 @@ gfc_match_omp_requires (void)
   static const char *clauses[] = {"reverse_offload",
 				  "unified_address",
 				  "unified_shared_memory",
+				  "self_maps",
 				  "dynamic_allocators",
 				  "atomic_default"};
   const char *clause = NULL;
@@ -6921,13 +6922,20 @@ gfc_match_omp_requires (void)
       else if (gfc_match (clauses[3]) == MATCH_YES)
 	{
 	  clause = clauses[3];
+	  requires_clause = OMP_REQ_SELF_MAPS;
+	  if (requires_clauses & OMP_REQ_SELF_MAPS)
+	    goto duplicate_clause;
+	}
+      else if (gfc_match (clauses[4]) == MATCH_YES)
+	{
+	  clause = clauses[4];
 	  requires_clause = OMP_REQ_DYNAMIC_ALLOCATORS;
 	  if (requires_clauses & OMP_REQ_DYNAMIC_ALLOCATORS)
 	    goto duplicate_clause;
 	}
       else if (gfc_match ("atomic_default_mem_order (") == MATCH_YES)
 	{
-	  clause = clauses[4];
+	  clause = clauses[5];
 	  if (requires_clauses & OMP_REQ_ATOMIC_MEM_ORDER_MASK)
 	    goto duplicate_clause;
 	  if (gfc_match (" seq_cst )") == MATCH_YES)
@@ -6982,7 +6990,7 @@ duplicate_clause:
   gfc_error ("%qs clause at %L specified more than once", clause, &old_loc);
 error:
   if (!gfc_error_flag_test ())
-    gfc_error ("Expected UNIFIED_ADDRESS, UNIFIED_SHARED_MEMORY, "
+    gfc_error ("Expected UNIFIED_ADDRESS, UNIFIED_SHARED_MEMORY, SELF_MAPS, "
 	       "DYNAMIC_ALLOCATORS, REVERSE_OFFLOAD, or "
 	       "ATOMIC_DEFAULT_MEM_ORDER clause at %L", &old_loc);
   return MATCH_ERROR;
diff --git a/gcc/fortran/parse.cc b/gcc/fortran/parse.cc
index c506e18233e..532bdbadc09 100644
--- a/gcc/fortran/parse.cc
+++ b/gcc/fortran/parse.cc
@@ -7415,6 +7415,9 @@ done:
     omp_requires_mask
 	  = (enum omp_requires) (omp_requires_mask
 				 | OMP_REQUIRES_UNIFIED_SHARED_MEMORY);
+  if (omp_requires & OMP_REQ_SELF_MAPS)
+    omp_requires_mask
+	  = (enum omp_requires) (omp_requires_mask | OMP_REQUIRES_SELF_MAPS);
   if (omp_requires & OMP_REQ_DYNAMIC_ALLOCATORS)
     omp_requires_mask = (enum omp_requires) (omp_requires_mask
 					     | OMP_REQUIRES_DYNAMIC_ALLOCATORS);
diff --git a/gcc/lto-cgraph.cc b/gcc/lto-cgraph.cc
index 1492409427c..1d4311a8832 100644
--- a/gcc/lto-cgraph.cc
+++ b/gcc/lto-cgraph.cc
@@ -1129,6 +1129,7 @@ output_offload_tables (void)
       HOST_WIDE_INT val = ((HOST_WIDE_INT) omp_requires_mask
 			   & (OMP_REQUIRES_UNIFIED_ADDRESS
 			      | OMP_REQUIRES_UNIFIED_SHARED_MEMORY
+			      | OMP_REQUIRES_SELF_MAPS
 			      | OMP_REQUIRES_REVERSE_OFFLOAD
 			      | OMP_REQUIRES_TARGET_USED));
       /* (Mis)use LTO_symtab_edge for this variable.  */
@@ -1808,6 +1809,9 @@ omp_requires_to_name (char *buf, size_t size, HOST_WIDE_INT requires_mask)
   if (requires_mask & GOMP_REQUIRES_UNIFIED_SHARED_MEMORY)
     p += snprintf (p, end - p, "%sunified_shared_memory",
 		   (p == buf ? "" : ", "));
+  if (requires_mask & GOMP_REQUIRES_SELF_MAPS)
+    p += snprintf (p, end - p, "%sself_maps",
+		   (p == buf ? "" : ", "));
   if (requires_mask & GOMP_REQUIRES_REVERSE_OFFLOAD)
     p += snprintf (p, end - p, "%sreverse_offload",
 		   (p == buf ? "" : ", "));
diff --git a/gcc/omp-general.cc b/gcc/omp-general.cc
index 12788ad0249..0a2cb98922e 100644
--- a/gcc/omp-general.cc
+++ b/gcc/omp-general.cc
@@ -1207,6 +1207,11 @@ struct omp_ts_info omp_ts_map[] =
      OMP_TRAIT_PROPERTY_NONE, true,
      NULL
    },
+   { "self_maps",
+     (1 << OMP_TRAIT_SET_IMPLEMENTATION),
+     OMP_TRAIT_PROPERTY_NONE, true,
+     NULL
+   },
    { "dynamic_allocators",
      (1 << OMP_TRAIT_SET_IMPLEMENTATION),
      OMP_TRAIT_PROPERTY_NONE, true,
@@ -1654,6 +1659,22 @@ omp_context_selector_matches (tree ctx)
 		    }
 		}
 	      break;
+	    case OMP_TRAIT_IMPLEMENTATION_SELF_MAPS:
+	      if (set == OMP_TRAIT_SET_IMPLEMENTATION)
+		{
+		  if (cfun && (cfun->curr_properties & PROP_gimple_any) != 0)
+		    break;
+
+		  if ((omp_requires_mask
+		       & OMP_REQUIRES_SELF_MAPS) == 0)
+		    {
+		      if (symtab->state == PARSING)
+			ret = -1;
+		      else
+			return 0;
+		    }
+		}
+	      break;
 	    case OMP_TRAIT_IMPLEMENTATION_DYNAMIC_ALLOCATORS:
 	      if (set == OMP_TRAIT_SET_IMPLEMENTATION)
 		{
diff --git a/gcc/omp-general.h b/gcc/omp-general.h
index 37f0548befd..891f467556e 100644
--- a/gcc/omp-general.h
+++ b/gcc/omp-general.h
@@ -195,6 +195,7 @@ enum omp_requires {
   OMP_REQUIRES_REVERSE_OFFLOAD = GOMP_REQUIRES_REVERSE_OFFLOAD,
   OMP_REQUIRES_ATOMIC_DEFAULT_MEM_ORDER_USED = 0x100,
   OMP_REQUIRES_TARGET_USED = GOMP_REQUIRES_TARGET_USED,
+  OMP_REQUIRES_SELF_MAPS = GOMP_REQUIRES_SELF_MAPS
 };
 
 extern GTY(()) enum omp_requires omp_requires_mask;
diff --git a/gcc/omp-selectors.h b/gcc/omp-selectors.h
index c61808ec0ad..730021ea747 100644
--- a/gcc/omp-selectors.h
+++ b/gcc/omp-selectors.h
@@ -47,6 +47,7 @@ enum omp_ts_code {
   OMP_TRAIT_IMPLEMENTATION_REQUIRES,
   OMP_TRAIT_IMPLEMENTATION_UNIFIED_ADDRESS,
   OMP_TRAIT_IMPLEMENTATION_UNIFIED_SHARED_MEMORY,
+  OMP_TRAIT_IMPLEMENTATION_SELF_MAPS,
   OMP_TRAIT_IMPLEMENTATION_DYNAMIC_ALLOCATORS,
   OMP_TRAIT_IMPLEMENTATION_REVERSE_OFFLOAD,
   OMP_TRAIT_USER_CONDITION,
diff --git a/gcc/testsuite/c-c++-common/gomp/declare-variant-1.c b/gcc/testsuite/c-c++-common/gomp/declare-variant-1.c
index 75fcb7bf0e7..c4e38966034 100644
--- a/gcc/testsuite/c-c++-common/gomp/declare-variant-1.c
+++ b/gcc/testsuite/c-c++-common/gomp/declare-variant-1.c
@@ -1,10 +1,16 @@
 int foo (int, int, int *);
 int bar (int, int, int *);
+int foobar (int, int, int *);
 #pragma omp declare variant (foo) \
   match (construct={parallel,for},\
 	 device={isa(avx512f,avx512vl),kind(host,cpu)},\
 	 implementation={vendor(score(0):gnu),unified_shared_memory},\
 	 user={condition(score(0):0)})
+#pragma omp declare variant (foo) \
+  match (construct={parallel,for},\
+	 device={isa(avx512f,avx512vl),kind(host,cpu)},\
+	 implementation={vendor(score(0):gnu),self_map},\
+	 user={condition(score(0):0)})
 #pragma omp declare variant (bar) \
   match (device={arch(x86_64,powerpc64),isa(avx512f,popcntb)}, \
 	 implementation={atomic_default_mem_order(seq_cst),made_up_selector("foo", 13, "bar")}, \
diff --git a/gcc/testsuite/c-c++-common/gomp/requires-2.c b/gcc/testsuite/c-c++-common/gomp/requires-2.c
index d7430b1b1a4..d29729fe555 100644
--- a/gcc/testsuite/c-c++-common/gomp/requires-2.c
+++ b/gcc/testsuite/c-c++-common/gomp/requires-2.c
@@ -2,7 +2,7 @@
 #pragma omp requires unified_shared_memory,unified_shared_memory	/* { dg-error "too many 'unified_shared_memory' clauses" } */
 #pragma omp requires unified_address	unified_address	/* { dg-error "too many 'unified_address' clauses" } */
 #pragma omp requires reverse_offload reverse_offload	/* { dg-error "too many 'reverse_offload' clauses" } */
-#pragma omp requires foobarbaz	/* { dg-error "expected 'unified_address', 'unified_shared_memory', 'dynamic_allocators', 'reverse_offload' or 'atomic_default_mem_order' clause" } */
+#pragma omp requires foobarbaz	/* { dg-error "expected 'unified_address', 'unified_shared_memory', 'self_maps', 'dynamic_allocators', 'reverse_offload' or 'atomic_default_mem_order' clause" } */
 #pragma omp requires dynamic_allocators , dynamic_allocators	/* { dg-error "too many 'dynamic_allocators' clauses" } */
 #pragma omp requires atomic_default_mem_order(seq_cst) atomic_default_mem_order(seq_cst)	/* { dg-error "too many 'atomic_default_mem_order' clauses" } */
 #pragma omp requires atomic_default_mem_order (seq_cst)	/* { dg-error "more than one 'atomic_default_mem_order' clause in a single compilation unit" } */
diff --git a/gcc/testsuite/c-c++-common/gomp/requires-4.c b/gcc/testsuite/c-c++-common/gomp/requires-4.c
index 8f45d83ea6e..0b61fa905bb 100644
--- a/gcc/testsuite/c-c++-common/gomp/requires-4.c
+++ b/gcc/testsuite/c-c++-common/gomp/requires-4.c
@@ -9,3 +9,4 @@ foo (void)
 #pragma omp requires unified_shared_memory	/* { dg-error "'unified_shared_memory' clause used lexically after first target construct or offloading API" } */
 #pragma omp requires unified_address	/* { dg-error "'unified_address' clause used lexically after first target construct or offloading API" } */
 #pragma omp requires reverse_offload	/* { dg-error "'reverse_offload' clause used lexically after first target construct or offloading API" } */
+#pragma omp requires self_maps	/* { dg-error "'self_maps' clause used lexically after first target construct or offloading API" } */
diff --git a/gcc/testsuite/gfortran.dg/gomp/declare-variant-3.f90 b/gcc/testsuite/gfortran.dg/gomp/declare-variant-3.f90
index 6b23d40e410..90674281f22 100644
--- a/gcc/testsuite/gfortran.dg/gomp/declare-variant-3.f90
+++ b/gcc/testsuite/gfortran.dg/gomp/declare-variant-3.f90
@@ -129,6 +129,9 @@ contains
   subroutine f45 ()
     !$omp declare variant (f13) match (implementation={unified_shared_memory})
   end subroutine
+  subroutine f45a ()
+    !$omp declare variant (f13) match (implementation={self_maps})
+  end subroutine
   subroutine f46 ()
     !$omp declare variant (f13) match (implementation={unified_address})
   end subroutine
diff --git a/gcc/testsuite/gfortran.dg/gomp/requires-2.f90 b/gcc/testsuite/gfortran.dg/gomp/requires-2.f90
index f144d391034..ed9f8ea352a 100644
--- a/gcc/testsuite/gfortran.dg/gomp/requires-2.f90
+++ b/gcc/testsuite/gfortran.dg/gomp/requires-2.f90
@@ -2,7 +2,7 @@
 !$omp requires unified_shared_memory,unified_shared_memory	! { dg-error "specified more than once" }
 !$omp requires unified_address	unified_address	! { dg-error "specified more than once" }
 !$omp requires reverse_offload reverse_offload	! { dg-error "specified more than once" }
-!$omp requires foobarbaz	! { dg-error "Expected UNIFIED_ADDRESS, UNIFIED_SHARED_MEMORY, DYNAMIC_ALLOCATORS, REVERSE_OFFLOAD, or ATOMIC_DEFAULT_MEM_ORDER clause" }
+!$omp requires foobarbaz	! { dg-error "Expected UNIFIED_ADDRESS, UNIFIED_SHARED_MEMORY, SELF_MAPS, DYNAMIC_ALLOCATORS, REVERSE_OFFLOAD, or ATOMIC_DEFAULT_MEM_ORDER clause" }
 !$omp requires dynamic_allocators , dynamic_allocators	! { dg-error "specified more than once" }
 !$omp requires atomic_default_mem_order(seq_cst) atomic_default_mem_order(seq_cst)	! { dg-error "specified more than once" }
 !$omp requires atomic_default_mem_order (seq_cst)
diff --git a/include/gomp-constants.h b/include/gomp-constants.h
index 0fae337f9d6..9618727888d 100644
--- a/include/gomp-constants.h
+++ b/include/gomp-constants.h
@@ -383,10 +383,14 @@ enum gomp_map_kind
 #define GOMP_DEPEND_INOUTSET		5
 
 /* Flag values for OpenMP 'requires' directive features.  */
+// compiler use only: OMP_REQUIRES_ATOMIC_DEFAULT_MEM_ORDER  0xf
 #define GOMP_REQUIRES_UNIFIED_ADDRESS       0x10
 #define GOMP_REQUIRES_UNIFIED_SHARED_MEMORY 0x20
+// compiler use only: OMP_REQUIRES_DYNAMIC_ALLOCATORS 0x40
 #define GOMP_REQUIRES_REVERSE_OFFLOAD       0x80
+// compiler use only: OMP_REQUIRES_ATOMIC_DEFAULT_MEM_ORDER_USED 0x100
 #define GOMP_REQUIRES_TARGET_USED           0x200
+#define GOMP_REQUIRES_SELF_MAPS             0x400
 
 /* Interop foreign-runtime data.  */
 #define GOMP_INTEROP_IFR_LAST	7
diff --git a/libgomp/libgomp.texi b/libgomp/libgomp.texi
index 936d3f4e2e4..29f5419cd0f 100644
--- a/libgomp/libgomp.texi
+++ b/libgomp/libgomp.texi
@@ -539,7 +539,7 @@ Technical Report (TR) 13 is the third preview for OpenMP 6.0.
 @item Scope requirement changes for @code{declare_target} @tab N @tab
 @item @code{message} and @code{severity} clauses to @code{parallel} directive
       @tab N @tab
-@item @code{self_maps} clause to @code{requires} directive @tab N @tab
+@item @code{self_maps} clause to @code{requires} directive @tab Y @tab
 @item @code{no_openmp_constructs} assumptions clause @tab N @tab
 @item Restriction for @code{ordered} regarding loop-transforming directives
       @tab N @tab
diff --git a/libgomp/plugin/plugin-gcn.c b/libgomp/plugin/plugin-gcn.c
index bf6ad371ea2..8f9aec57a7a 100644
--- a/libgomp/plugin/plugin-gcn.c
+++ b/libgomp/plugin/plugin-gcn.c
@@ -3372,13 +3372,15 @@ GOMP_OFFLOAD_get_num_devices (unsigned int omp_requires_mask)
       && ((omp_requires_mask
 	   & ~(GOMP_REQUIRES_UNIFIED_ADDRESS
 	       | GOMP_REQUIRES_UNIFIED_SHARED_MEMORY
+	       | GOMP_REQUIRES_SELF_MAPS
 	       | GOMP_REQUIRES_REVERSE_OFFLOAD)) != 0))
     return -1;
   /* Check whether host page access is supported; this is per system level
      (all GPUs supported by HSA).  While intrinsically true for APUs, it
      requires XNACK support for discrete GPUs.  */
   if (hsa_context.agent_count > 0
-      && (omp_requires_mask & GOMP_REQUIRES_UNIFIED_SHARED_MEMORY))
+      && (omp_requires_mask
+	  & (GOMP_REQUIRES_UNIFIED_SHARED_MEMORY | GOMP_REQUIRES_SELF_MAPS)))
     {
       bool b;
       hsa_system_info_t type = HSA_AMD_SYSTEM_INFO_SVM_ACCESSIBLE_BY_DEFAULT;
diff --git a/libgomp/plugin/plugin-nvptx.c b/libgomp/plugin/plugin-nvptx.c
index a8b85bd9fd0..733dffb9f5e 100644
--- a/libgomp/plugin/plugin-nvptx.c
+++ b/libgomp/plugin/plugin-nvptx.c
@@ -1298,6 +1298,7 @@ GOMP_OFFLOAD_get_num_devices (unsigned int omp_requires_mask)
   if (num_devices > 0
       && ((omp_requires_mask
 	   & ~(GOMP_REQUIRES_UNIFIED_ADDRESS
+	       | GOMP_REQUIRES_SELF_MAPS
 	       | GOMP_REQUIRES_UNIFIED_SHARED_MEMORY
 	       | GOMP_REQUIRES_REVERSE_OFFLOAD)) != 0))
     return -1;
@@ -1305,7 +1306,8 @@ GOMP_OFFLOAD_get_num_devices (unsigned int omp_requires_mask)
      if so, enable USM.  Currently, capabilities is per device type, hence,
      check all devices.  */
   if (num_devices > 0
-      && (omp_requires_mask & GOMP_REQUIRES_UNIFIED_SHARED_MEMORY))
+      && (omp_requires_mask
+	  & (GOMP_REQUIRES_UNIFIED_SHARED_MEMORY | GOMP_REQUIRES_SELF_MAPS)))
     for (int dev = 0; dev < num_devices; dev++)
       {
 	int pi;
diff --git a/libgomp/target.c b/libgomp/target.c
index f9aa1789f0b..3ed955b16ae 100644
--- a/libgomp/target.c
+++ b/libgomp/target.c
@@ -2587,6 +2587,9 @@ gomp_requires_to_name (char *buf, size_t size, int requires_mask)
   if (requires_mask & GOMP_REQUIRES_UNIFIED_SHARED_MEMORY)
     p += snprintf (p, end - p, "%sunified_shared_memory",
 		   (p == buf ? "" : ", "));
+  if (requires_mask & GOMP_REQUIRES_SELF_MAPS)
+    p += snprintf (p, end - p, "%sself_maps",
+		   (p == buf ? "" : ", "));
   if (requires_mask & GOMP_REQUIRES_REVERSE_OFFLOAD)
     p += snprintf (p, end - p, "%sreverse_offload",
 		   (p == buf ? "" : ", "));
@@ -2624,9 +2627,9 @@ GOMP_offload_register_ver (unsigned version, const void *host_table,
   if (omp_req && omp_requires_mask && omp_requires_mask != omp_req)
     {
       char buf1[sizeof ("unified_address, unified_shared_memory, "
-			"reverse_offload")];
+			"self_maps, reverse_offload")];
       char buf2[sizeof ("unified_address, unified_shared_memory, "
-			"reverse_offload")];
+			"self_maps, reverse_offload")];
       gomp_requires_to_name (buf2, sizeof (buf2),
 			     omp_req != GOMP_REQUIRES_TARGET_USED
 			     ? omp_req : omp_requires_mask);
@@ -5490,7 +5493,8 @@ gomp_target_init (void)
 
 		/* If USM has been requested and is supported by all devices
 		   of this type, set the capability accordingly.  */
-		if (omp_requires_mask & GOMP_REQUIRES_UNIFIED_SHARED_MEMORY)
+		if (omp_requires_mask
+		    & (GOMP_REQUIRES_UNIFIED_SHARED_MEMORY | GOMP_REQUIRES_SELF_MAPS))
 		  current_device.capabilities |= GOMP_OFFLOAD_CAP_SHARED_MEM;
 
 		devs = realloc (devs, (num_devs + new_num_devs)
diff --git a/libgomp/testsuite/libgomp.fortran/self_maps.f90 b/libgomp/testsuite/libgomp.fortran/self_maps.f90
new file mode 100644
index 00000000000..208fd1c71d5
--- /dev/null
+++ b/libgomp/testsuite/libgomp.fortran/self_maps.f90
@@ -0,0 +1,49 @@
+! Basic test whether self_maps work
+
+module m
+  !$omp requires self_maps
+  implicit none (type, external)
+  type t
+    integer :: val
+    type(t), pointer :: next
+  end type t
+contains
+  subroutine init(p)
+    integer :: i
+    type(t), pointer :: p, x
+    allocate(x)
+    p => x
+    do i = 1, 5
+      x%val = i
+      if (i < 5) then
+        allocate(x%next)
+        x => x%next
+      end if
+    end do
+  end subroutine
+
+  subroutine check(p)
+    !$omp declare target enter(check)
+    integer :: i
+    type(t), pointer :: p, x
+    x => p
+    do i = 1, 5
+      if (x%val /= i) stop 1
+       x => x%next
+    end do
+end subroutine
+end module
+
+use omp_lib
+use m
+implicit none (type, external)
+type(t), pointer :: linked
+integer :: i
+
+call init(linked)
+do i = 0, omp_get_num_devices()
+  !$omp target device(i)
+    call check(linked)
+  !$omp end target
+end do
+end

Reply via email to