diff mbox series

OpenMP: Support acquires/release in 'omp require atomic_default_mem_order'

Message ID e15951ed-3430-46bf-9a5f-2d57c16452d0@codesourcery.com
State New
Headers show
Series OpenMP: Support acquires/release in 'omp require atomic_default_mem_order' | expand

Commit Message

Tobias Burnus Nov. 28, 2023, 11:28 a.m. UTC
I stumbled over this omission when looking at Sandra's patch. It turned out that this is
a new OpenMP 5.2 feature - probably added to simplify/unify the syntax. I guess the reason
that release/acquire wasn't added before is that it cannot be universally be used - read/write
do only accept one of them.

However, as a compilation unit might only/mostly use read (and update) or write (and update),
that can be fine - especially as overriding the default clause is still possible.

It is not quite clear to me why, but the current patch also fixes a bug regarding the
diagnostic message for gfortran.dg/gomp/requires-5.f90. (I think I could find out, but
as it changed to the better...)

Comments, suggestions?

Tobias
-----------------
Siemens Electronic Design Automation GmbH; Anschrift: Arnulfstraße 201, 80634 München; Gesellschaft mit beschränkter Haftung; Geschäftsführer: Thomas Heurung, Frank Thürauf; Sitz der Gesellschaft: München; Registergericht München, HRB 106955

Comments

Jakub Jelinek Dec. 8, 2023, 1:47 p.m. UTC | #1
On Tue, Nov 28, 2023 at 12:28:05PM +0100, Tobias Burnus wrote:
> I stumbled over this omission when looking at Sandra's patch. It turned out that this is
> a new OpenMP 5.2 feature - probably added to simplify/unify the syntax. I guess the reason
> that release/acquire wasn't added before is that it cannot be universally be used - read/write
> do only accept one of them.

I thought when this was discussed that it was meant to behave right (choose
some more appropriate memory model if one was not allowed), but reading 5.2
I think that is not what ended up in the spec, because [213:11-13] says that
atomic_default_mem_order is as if the argument appeared on any atomic
directive without explicit mem-order clause and atomic directive has the
[314:9-10] restrictions.

I'd bring this to omp-lang whether it was really meant that
#pragma omp requires atomic_default_mem_order (release)
int foo (int *p) {
  int t;
  #pragma omp atomic read
    t = *p;
  return t;
}
and
#pragma omp requires atomic_default_mem_order (acquire)
void bar (int *p) {
  #pragma omp atomic write
    *p = 0;
}
are meant to be invalid.

Another comment, atomic_default_mem_order arguments aren't handled
just in the requires parsing, but also in context selectors.
So, the additions would need to be reflected in
omp_check_context_selector and omp_context_selector_matches
as well.

	Jakub
diff mbox series

Patch

OpenMP: Support acquires/release in 'omp require atomic_default_mem_order'

This is an OpenMP 5.2 feature.

gcc/c/ChangeLog:

	* c-parser.cc (c_parser_omp_requires): Handle acquires/release
	in atomic_default_mem_order clause.
	(c_parser_omp_atomic): Update. 

gcc/cp/ChangeLog:

	* parser.cc (cp_parser_omp_requires): Handle acquires/release
	in atomic_default_mem_order clause.
	(cp_parser_omp_atomic): Update.

gcc/fortran/ChangeLog:

	* gfortran.h (enum gfc_omp_requires_kind): Add
	OMP_REQ_ATOMIC_MEM_ORDER_ACQUIRE and OMP_REQ_ATOMIC_MEM_ORDER_RELEASE.
	(gfc_namespace): Add a 7th bit to omp_requires.
	* module.cc (enum ab_attribute): Add AB_OMP_REQ_MEM_ORDER_ACQUIRE
	and AB_OMP_REQ_MEM_ORDER_RELEASE
	(mio_symbol_attribute): Handle it.
	* openmp.cc (gfc_omp_requires_add_clause): Update for acquire/release.
	(gfc_match_omp_requires): Likewise.
	(gfc_match_omp_atomic): Handle them for atomic_default_mem_order.
	* parse.cc: Likewise.

gcc/testsuite/ChangeLog:

	* c-c++-common/gomp/requires-3.c: Update for now valid code.
	* gfortran.dg/gomp/requires-3.f90: Likewise.
	* gfortran.dg/gomp/requires-2.f90: Update dg-error.
	* gfortran.dg/gomp/requires-5.f90: Likewise.
	* c-c++-common/gomp/requires-5.c: New test.
	* c-c++-common/gomp/requires-6.c: New test.
	* c-c++-common/gomp/requires-7.c: New test.
	* c-c++-common/gomp/requires-8.c: New test.
	* gfortran.dg/gomp/requires-10.f90: New test.
	* gfortran.dg/gomp/requires-11.f90: New test.

 gcc/c/c-parser.cc                              | 32 +++++++++++++++-
 gcc/cp/parser.cc                               | 32 +++++++++++++++-
 gcc/fortran/gfortran.h                         | 22 ++++++-----
 gcc/fortran/module.cc                          | 19 +++++++++
 gcc/fortran/openmp.cc                          | 53 +++++++++++++++++++++-----
 gcc/fortran/parse.cc                           |  8 ++++
 gcc/testsuite/c-c++-common/gomp/requires-3.c   |  8 ++--
 gcc/testsuite/c-c++-common/gomp/requires-5.c   | 23 +++++++++++
 gcc/testsuite/c-c++-common/gomp/requires-6.c   | 23 +++++++++++
 gcc/testsuite/c-c++-common/gomp/requires-7.c   | 11 ++++++
 gcc/testsuite/c-c++-common/gomp/requires-8.c   | 14 +++++++
 gcc/testsuite/gfortran.dg/gomp/requires-10.f90 | 36 +++++++++++++++++
 gcc/testsuite/gfortran.dg/gomp/requires-11.f90 | 31 +++++++++++++++
 gcc/testsuite/gfortran.dg/gomp/requires-2.f90  |  2 +-
 gcc/testsuite/gfortran.dg/gomp/requires-3.f90  |  7 ++--
 gcc/testsuite/gfortran.dg/gomp/requires-5.f90  |  2 +-
 16 files changed, 291 insertions(+), 32 deletions(-)

diff --git a/gcc/c/c-parser.cc b/gcc/c/c-parser.cc
index df9a07928b5..5700ccccc49 100644
--- a/gcc/c/c-parser.cc
+++ b/gcc/c/c-parser.cc
@@ -20896,6 +20896,28 @@  c_parser_omp_atomic (location_t loc, c_parser *parser, bool openacc)
 	case OMP_MEMORY_ORDER_SEQ_CST:
 	  memory_order = OMP_MEMORY_ORDER_SEQ_CST;
 	  break;
+	case OMP_MEMORY_ORDER_ACQUIRE:
+	  if (code == NOP_EXPR)  /* atomic write */
+	    {
+	      error_at (loc, "%<#pragma omp atomic write%> incompatible with "
+			     "%<acquire%> clause implicitly provided by a "
+			     "%<requires%> directive");
+	      memory_order = OMP_MEMORY_ORDER_SEQ_CST;
+	    }
+	  else
+	    memory_order = OMP_MEMORY_ORDER_ACQUIRE;
+	  break;
+	case OMP_MEMORY_ORDER_RELEASE:
+	  if (code == OMP_ATOMIC_READ)
+	    {
+	      error_at (loc, "%<#pragma omp atomic read%> incompatible with "
+			     "%<release%> clause implicitly provided by a "
+			     "%<requires%> directive");
+	      memory_order = OMP_MEMORY_ORDER_SEQ_CST;
+	    }
+	  else
+	    memory_order = OMP_MEMORY_ORDER_RELEASE;
+	  break;
 	case OMP_MEMORY_ORDER_ACQ_REL:
 	  switch (code)
 	    {
@@ -25724,15 +25746,21 @@  c_parser_omp_requires (c_parser *parser)
 		      else if (!strcmp (p, "relaxed"))
 			this_req
 			  = (enum omp_requires) OMP_MEMORY_ORDER_RELAXED;
+		      else if (!strcmp (p, "release"))
+			this_req
+			  = (enum omp_requires) OMP_MEMORY_ORDER_RELEASE;
 		      else if (!strcmp (p, "acq_rel"))
 			this_req
 			  = (enum omp_requires) OMP_MEMORY_ORDER_ACQ_REL;
+		      else if (!strcmp (p, "acquire"))
+			this_req
+			  = (enum omp_requires) OMP_MEMORY_ORDER_ACQUIRE;
 		    }
 		  if (this_req == 0)
 		    {
 		      error_at (c_parser_peek_token (parser)->location,
-				"expected %<seq_cst%>, %<relaxed%> or "
-				"%<acq_rel%>");
+				"expected %<acq_rel%>, %<acquire%>, "
+				"%<relaxed%>, %<release%> or %<seq_cst%>");
 		      switch (c_parser_peek_token (parser)->type)
 			{
 			case CPP_EOF:
diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc
index 2464d1a0783..93bd7f112a2 100644
--- a/gcc/cp/parser.cc
+++ b/gcc/cp/parser.cc
@@ -42436,6 +42436,28 @@  cp_parser_omp_atomic (cp_parser *parser, cp_token *pragma_tok, bool openacc)
 	case OMP_MEMORY_ORDER_SEQ_CST:
 	  memory_order = OMP_MEMORY_ORDER_SEQ_CST;
 	  break;
+	case OMP_MEMORY_ORDER_ACQUIRE:
+	  if (code == NOP_EXPR)  /* atomic write */
+	    {
+	      error_at (loc, "%<#pragma omp atomic write%> incompatible with "
+			     "%<acquire%> clause implicitly provided by a "
+			     "%<requires%> directive");
+	      memory_order = OMP_MEMORY_ORDER_SEQ_CST;
+	    }
+	  else
+	    memory_order = OMP_MEMORY_ORDER_ACQUIRE;
+	  break;
+	case OMP_MEMORY_ORDER_RELEASE:
+	  if (code == OMP_ATOMIC_READ)
+	    {
+	      error_at (loc, "%<#pragma omp atomic read%> incompatible with "
+			     "%<release%> clause implicitly provided by a "
+			     "%<requires%> directive");
+	      memory_order = OMP_MEMORY_ORDER_SEQ_CST;
+	    }
+	  else
+	    memory_order = OMP_MEMORY_ORDER_RELEASE;
+	  break;
 	case OMP_MEMORY_ORDER_ACQ_REL:
 	  switch (code)
 	    {
@@ -49126,15 +49148,21 @@  cp_parser_omp_requires (cp_parser *parser, cp_token *pragma_tok)
 		      else if (!strcmp (p, "relaxed"))
 			this_req
 			  = (enum omp_requires) OMP_MEMORY_ORDER_RELAXED;
+		      else if (!strcmp (p, "release"))
+			this_req
+			  = (enum omp_requires) OMP_MEMORY_ORDER_RELEASE;
 		      else if (!strcmp (p, "acq_rel"))
 			this_req
 			  = (enum omp_requires) OMP_MEMORY_ORDER_ACQ_REL;
+		      else if (!strcmp (p, "acquire"))
+			this_req
+			  = (enum omp_requires) OMP_MEMORY_ORDER_ACQUIRE;
 		    }
 		  if (this_req == 0)
 		    {
 		      error_at (cp_lexer_peek_token (parser->lexer)->location,
-				"expected %<seq_cst%>, %<relaxed%> or "
-				"%<acq_rel%>");
+				"expected %<acq_rel%>, %<acquire%>, "
+				"%<relaxed%>, %<release%> or %<seq_cst%>");
 		      switch (cp_lexer_peek_token (parser->lexer)->type)
 			{
 			case CPP_EOF:
diff --git a/gcc/fortran/gfortran.h b/gcc/fortran/gfortran.h
index aa3f6cb70b4..5477c3d2966 100644
--- a/gcc/fortran/gfortran.h
+++ b/gcc/fortran/gfortran.h
@@ -1496,19 +1496,23 @@  enum gfc_omp_atomic_op
 enum gfc_omp_requires_kind
 {
   /* Keep in sync with gfc_namespace, esp. with omp_req_mem_order.  */
-  OMP_REQ_ATOMIC_MEM_ORDER_SEQ_CST = 1,  /* 01 */
-  OMP_REQ_ATOMIC_MEM_ORDER_ACQ_REL = 2,  /* 10 */
-  OMP_REQ_ATOMIC_MEM_ORDER_RELAXED = 3,  /* 11 */
-  OMP_REQ_REVERSE_OFFLOAD = (1 << 2),
-  OMP_REQ_UNIFIED_ADDRESS = (1 << 3),
-  OMP_REQ_UNIFIED_SHARED_MEMORY = (1 << 4),
-  OMP_REQ_DYNAMIC_ALLOCATORS = (1 << 5),
+  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 */
+  OMP_REQ_ATOMIC_MEM_ORDER_ACQUIRE = 4,  /* 100 */
+  OMP_REQ_ATOMIC_MEM_ORDER_RELEASE = 5,  /* 101 */
+  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_TARGET_MASK = (OMP_REQ_REVERSE_OFFLOAD
 			 | OMP_REQ_UNIFIED_ADDRESS
 			 | OMP_REQ_UNIFIED_SHARED_MEMORY),
   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)
+				   | OMP_REQ_ATOMIC_MEM_ORDER_RELAXED
+				   | OMP_REQ_ATOMIC_MEM_ORDER_ACQUIRE
+				   | OMP_REQ_ATOMIC_MEM_ORDER_RELEASE)
 };
 
 enum gfc_omp_memorder
@@ -2257,7 +2261,7 @@  typedef struct gfc_namespace
   unsigned implicit_interface_calls:1;
 
   /* OpenMP requires. */
-  unsigned omp_requires:6;
+  unsigned omp_requires:7;
   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 c07e9dc9ba2..3c07818e2cf 100644
--- a/gcc/fortran/module.cc
+++ b/gcc/fortran/module.cc
@@ -2093,6 +2093,7 @@  enum ab_attribute
   AB_OMP_REQ_REVERSE_OFFLOAD, AB_OMP_REQ_UNIFIED_ADDRESS,
   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,
   AB_OMP_REQ_MEM_ORDER_RELAXED, AB_OMP_DEVICE_TYPE_NOHOST,
   AB_OMP_DEVICE_TYPE_HOST, AB_OMP_DEVICE_TYPE_ANY
 };
@@ -2175,7 +2176,9 @@  static const mstring attr_bits[] =
     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),
+    minit ("OMP_REQ_MEM_ORDER_ACQUIRE", AB_OMP_REQ_MEM_ORDER_ACQUIRE),
     minit ("OMP_REQ_MEM_ORDER_RELAXED", AB_OMP_REQ_MEM_ORDER_RELAXED),
+    minit ("OMP_REQ_MEM_ORDER_RELEASE", AB_OMP_REQ_MEM_ORDER_RELEASE),
     minit ("OMP_DEVICE_TYPE_HOST", AB_OMP_DEVICE_TYPE_HOST),
     minit ("OMP_DEVICE_TYPE_NOHOST", AB_OMP_DEVICE_TYPE_NOHOST),
     minit ("OMP_DEVICE_TYPE_ANYHOST", AB_OMP_DEVICE_TYPE_ANY),
@@ -2442,9 +2445,15 @@  mio_symbol_attribute (symbol_attribute *attr)
 	  if ((gfc_current_ns->omp_requires & OMP_REQ_ATOMIC_MEM_ORDER_MASK)
 	      == OMP_REQ_ATOMIC_MEM_ORDER_ACQ_REL)
 	    MIO_NAME (ab_attribute) (AB_OMP_REQ_MEM_ORDER_ACQ_REL, attr_bits);
+	  if ((gfc_current_ns->omp_requires & OMP_REQ_ATOMIC_MEM_ORDER_MASK)
+	      == OMP_REQ_ATOMIC_MEM_ORDER_ACQUIRE)
+	    MIO_NAME (ab_attribute) (AB_OMP_REQ_MEM_ORDER_ACQUIRE, attr_bits);
 	  if ((gfc_current_ns->omp_requires & OMP_REQ_ATOMIC_MEM_ORDER_MASK)
 	      == OMP_REQ_ATOMIC_MEM_ORDER_RELAXED)
 	    MIO_NAME (ab_attribute) (AB_OMP_REQ_MEM_ORDER_RELAXED, attr_bits);
+	  if ((gfc_current_ns->omp_requires & OMP_REQ_ATOMIC_MEM_ORDER_MASK)
+	      == OMP_REQ_ATOMIC_MEM_ORDER_RELEASE)
+	    MIO_NAME (ab_attribute) (AB_OMP_REQ_MEM_ORDER_RELEASE, attr_bits);
 	}
       switch (attr->omp_device_type)
 	{
@@ -2724,11 +2733,21 @@  mio_symbol_attribute (symbol_attribute *attr)
 					   "acq_rel", &gfc_current_locus,
 					   module_name);
 	      break;
+	    case AB_OMP_REQ_MEM_ORDER_ACQUIRE:
+	      gfc_omp_requires_add_clause (OMP_REQ_ATOMIC_MEM_ORDER_ACQUIRE,
+					   "acquires", &gfc_current_locus,
+					   module_name);
+	      break;
 	    case AB_OMP_REQ_MEM_ORDER_RELAXED:
 	      gfc_omp_requires_add_clause (OMP_REQ_ATOMIC_MEM_ORDER_RELAXED,
 					   "relaxed", &gfc_current_locus,
 					   module_name);
 	      break;
+	    case AB_OMP_REQ_MEM_ORDER_RELEASE:
+	      gfc_omp_requires_add_clause (OMP_REQ_ATOMIC_MEM_ORDER_RELEASE,
+					   "release", &gfc_current_locus,
+					   module_name);
+	      break;
 	    case AB_OMP_DEVICE_TYPE_HOST:
 	      attr->omp_device_type = OMP_DEVICE_TYPE_HOST;
 	      break;
diff --git a/gcc/fortran/openmp.cc b/gcc/fortran/openmp.cc
index 794df19a4d1..19995708c23 100644
--- a/gcc/fortran/openmp.cc
+++ b/gcc/fortran/openmp.cc
@@ -6251,14 +6251,15 @@  gfc_omp_requires_add_clause (gfc_omp_requires_kind clause,
 	 != (int) clause)
     {
       const char *other;
-      if (prog_unit->omp_requires & OMP_REQ_ATOMIC_MEM_ORDER_SEQ_CST)
-	other = "seq_cst";
-      else if (prog_unit->omp_requires & OMP_REQ_ATOMIC_MEM_ORDER_ACQ_REL)
-	other = "acq_rel";
-      else if (prog_unit->omp_requires & OMP_REQ_ATOMIC_MEM_ORDER_RELAXED)
-	other = "relaxed";
-      else
-	gcc_unreachable ();
+      switch (prog_unit->omp_requires & OMP_REQ_ATOMIC_MEM_ORDER_MASK)
+	{
+	case OMP_REQ_ATOMIC_MEM_ORDER_SEQ_CST: other = "seq_cst"; break;
+	case OMP_REQ_ATOMIC_MEM_ORDER_ACQ_REL: other = "acq_rel"; break;
+	case OMP_REQ_ATOMIC_MEM_ORDER_ACQUIRE: other = "acquire"; break;
+	case OMP_REQ_ATOMIC_MEM_ORDER_RELAXED: other = "relaxed"; break;
+	case OMP_REQ_ATOMIC_MEM_ORDER_RELEASE: other = "release"; break;
+	default: gcc_unreachable ();
+	}
 
       if (module_name)
 	gfc_error ("!$OMP REQUIRES clause %<atomic_default_mem_order(%s)%> "
@@ -6372,15 +6373,25 @@  gfc_match_omp_requires (void)
 	      clause = "acq_rel";
 	      requires_clause = OMP_REQ_ATOMIC_MEM_ORDER_ACQ_REL;
 	    }
+	  else if (gfc_match (" acquire )") == MATCH_YES)
+	    {
+	      clause = "acquire";
+	      requires_clause = OMP_REQ_ATOMIC_MEM_ORDER_ACQUIRE;
+	    }
 	  else if (gfc_match (" relaxed )") == MATCH_YES)
 	    {
 	      clause = "relaxed";
 	      requires_clause = OMP_REQ_ATOMIC_MEM_ORDER_RELAXED;
 	    }
+	  else if (gfc_match (" release )") == MATCH_YES)
+	    {
+	      clause = "release";
+	      requires_clause = OMP_REQ_ATOMIC_MEM_ORDER_RELEASE;
+	    }
 	  else
 	    {
-	      gfc_error ("Expected SEQ_CST, ACQ_REL or RELAXED for "
-			 "ATOMIC_DEFAULT_MEM_ORDER clause at %C");
+	      gfc_error ("Expected ACQ_REL, ACQUIRE, RELAXED, RELEASE or "
+			 "SEQ_CST for ATOMIC_DEFAULT_MEM_ORDER clause at %C");
 	      goto error;
 	    }
 	}
@@ -6827,6 +6838,28 @@  gfc_match_omp_atomic (void)
 	  else
 	    c->memorder = OMP_MEMORDER_RELEASE;
 	  break;
+	case OMP_REQ_ATOMIC_MEM_ORDER_ACQUIRE:
+	  if (c->atomic_op == GFC_OMP_ATOMIC_WRITE)
+	    {
+	      gfc_error ("!$OMP ATOMIC WRITE at %L incompatible with "
+			 "ACQUIRES clause implicitly provided by a "
+			 "REQUIRES directive", &loc);
+	      c->memorder = OMP_MEMORDER_SEQ_CST;
+	    }
+	  else
+	    c->memorder = OMP_MEMORDER_ACQUIRE;
+	  break;
+	case OMP_REQ_ATOMIC_MEM_ORDER_RELEASE:
+	  if (c->atomic_op == GFC_OMP_ATOMIC_READ)
+	    {
+	      gfc_error ("!$OMP ATOMIC READ at %L incompatible with "
+			 "RELEASE clause implicitly provided by a "
+			 "REQUIRES directive", &loc);
+	      c->memorder = OMP_MEMORDER_SEQ_CST;
+	    }
+	  else
+	    c->memorder = OMP_MEMORDER_RELEASE;
+	  break;
 	default:
 	  gcc_unreachable ();
 	}
diff --git a/gcc/fortran/parse.cc b/gcc/fortran/parse.cc
index abd3a424f38..c0e80b1a9c3 100644
--- a/gcc/fortran/parse.cc
+++ b/gcc/fortran/parse.cc
@@ -7269,10 +7269,18 @@  done:
       omp_requires_mask
 	= (enum omp_requires) (omp_requires_mask | OMP_MEMORY_ORDER_ACQ_REL);
       break;
+    case OMP_REQ_ATOMIC_MEM_ORDER_ACQUIRE:
+      omp_requires_mask
+	= (enum omp_requires) (omp_requires_mask | OMP_MEMORY_ORDER_ACQUIRE);
+      break;
     case OMP_REQ_ATOMIC_MEM_ORDER_RELAXED:
       omp_requires_mask
 	= (enum omp_requires) (omp_requires_mask | OMP_MEMORY_ORDER_RELAXED);
       break;
+    case OMP_REQ_ATOMIC_MEM_ORDER_RELEASE:
+      omp_requires_mask
+	= (enum omp_requires) (omp_requires_mask | OMP_MEMORY_ORDER_RELEASE);
+      break;
     }
 
   if (omp_target_seen)
diff --git a/gcc/testsuite/c-c++-common/gomp/requires-3.c b/gcc/testsuite/c-c++-common/gomp/requires-3.c
index bd2479ba8ff..2fd601acefa 100644
--- a/gcc/testsuite/c-c++-common/gomp/requires-3.c
+++ b/gcc/testsuite/c-c++-common/gomp/requires-3.c
@@ -1,6 +1,6 @@ 
-#pragma omp requires atomic_default_mem_order(acquire)	/* { dg-error "expected 'seq_cst', 'relaxed' or 'acq_rel'" } */
-#pragma omp requires atomic_default_mem_order(release)	/* { dg-error "expected 'seq_cst', 'relaxed' or 'acq_rel'" } */
-#pragma omp requires atomic_default_mem_order(foobar)	/* { dg-error "expected 'seq_cst', 'relaxed' or 'acq_rel'" } */
-#pragma omp requires atomic_default_mem_order (	/* { dg-error "expected 'seq_cst', 'relaxed' or 'acq_rel'" } */
+#pragma omp requires atomic_default_mem_order(foobar)	/* { dg-error "expected 'acq_rel', 'acquire', 'relaxed', 'release' or 'seq_cst'" } */
+#pragma omp requires atomic_default_mem_order (	/* { dg-error "expected 'acq_rel', 'acquire', 'relaxed', 'release' or 'seq_cst'" } */
 /* { dg-error "expected '\\\)' before end of line" "" { target *-*-* } .-1 } */
 #pragma omp requires atomic_default_mem_order(seq_cst),	/* { dg-error "expected end of line before ',' token" } */
+/* Valid since since 5.2, but ... */
+#pragma omp requires atomic_default_mem_order(acquire)	/* { 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-5.c b/gcc/testsuite/c-c++-common/gomp/requires-5.c
new file mode 100644
index 00000000000..53e0b75f1b7
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/gomp/requires-5.c
@@ -0,0 +1,23 @@ 
+/* { dg-additional-options "-fdump-tree-original" }  */
+
+#pragma omp requires atomic_default_mem_order(release)
+
+int
+foo (int x, int y)
+{
+  int z;
+
+  #pragma omp atomic write
+    x = y;
+
+  #pragma omp atomic update
+    x += 1;
+
+  #pragma omp atomic read acquire
+    z = x;
+  return z;
+}
+
+/* { dg-final { scan-tree-dump "#pragma omp atomic release" "original" } } */
+/* { dg-final { scan-tree-dump "#pragma omp atomic release" "original" } } */
+/* { dg-final { scan-tree-dump "z = #pragma omp atomic read acquire" "original" } } */
diff --git a/gcc/testsuite/c-c++-common/gomp/requires-6.c b/gcc/testsuite/c-c++-common/gomp/requires-6.c
new file mode 100644
index 00000000000..4470c8cae1a
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/gomp/requires-6.c
@@ -0,0 +1,23 @@ 
+/* { dg-additional-options "-fdump-tree-original" }  */
+
+#pragma omp requires atomic_default_mem_order(acquire)
+
+int
+bar (int a, int b)
+{
+  int c;
+
+  #pragma omp atomic write release
+    a = b;
+
+  #pragma omp atomic update
+    a += 1;
+
+  #pragma omp atomic read
+    c = a;
+  return c;
+}
+
+/* { dg-final { scan-tree-dump "#pragma omp atomic release" "original" } } */
+/* { dg-final { scan-tree-dump "#pragma omp atomic acquire" "original" } } */
+/* { dg-final { scan-tree-dump "c = #pragma omp atomic read acquire" "original" } } */
diff --git a/gcc/testsuite/c-c++-common/gomp/requires-7.c b/gcc/testsuite/c-c++-common/gomp/requires-7.c
new file mode 100644
index 00000000000..4735ef2a6e0
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/gomp/requires-7.c
@@ -0,0 +1,11 @@ 
+#pragma omp requires atomic_default_mem_order(release)
+
+int
+foo (int x)
+{
+  int z;
+
+  #pragma omp atomic read /* { dg-error "'#pragma omp atomic read' incompatible with 'release' clause implicitly provided by a 'requires' directive" } */
+    z = x;
+  return z;
+}
diff --git a/gcc/testsuite/c-c++-common/gomp/requires-8.c b/gcc/testsuite/c-c++-common/gomp/requires-8.c
new file mode 100644
index 00000000000..4d56e7d33e9
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/gomp/requires-8.c
@@ -0,0 +1,14 @@ 
+#pragma omp requires atomic_default_mem_order(acquire)
+
+int
+bar (int a, int b)
+{
+  int c;
+
+  #pragma omp atomic write /* { dg-error "'#pragma omp atomic write' incompatible with 'acquire' clause implicitly provided by a 'requires' directive" } */
+    a = b;
+
+  #pragma omp atomic read
+    c = a;
+  return c;
+}
diff --git a/gcc/testsuite/gfortran.dg/gomp/requires-10.f90 b/gcc/testsuite/gfortran.dg/gomp/requires-10.f90
new file mode 100644
index 00000000000..e912e3e867f
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/gomp/requires-10.f90
@@ -0,0 +1,36 @@ 
+! { dg-additional-options "-fdump-tree-original" }
+
+function foo (x, y) result (z)
+  !$omp requires atomic_default_mem_order(release)
+  implicit none
+  real :: x, y, z
+
+  !$omp atomic write
+    x = y
+
+  !$omp atomic update
+    x = x + 1
+
+  !$omp atomic read acquire
+    z = x
+end
+
+function bar (a, b) result (c)
+  !$omp requires atomic_default_mem_order(acquire)
+  implicit none
+  real :: a, b, c
+
+  !$omp atomic write release
+    a = b
+
+  !$omp atomic update
+    a = a + 1
+
+  !$omp atomic read
+    c = a
+end
+
+! { dg-final { scan-tree-dump-times "#pragma omp atomic release" 3 "original" } } */
+! { dg-final { scan-tree-dump-times "#pragma omp atomic acquire" 1 "original" } } */
+! { dg-final { scan-tree-dump-times "z = #pragma omp atomic read acquire" 1 "original" } } */
+! { dg-final { scan-tree-dump-times "c = #pragma omp atomic read acquire" 1 "original" } } */
diff --git a/gcc/testsuite/gfortran.dg/gomp/requires-11.f90 b/gcc/testsuite/gfortran.dg/gomp/requires-11.f90
new file mode 100644
index 00000000000..c55009d5d26
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/gomp/requires-11.f90
@@ -0,0 +1,31 @@ 
+function foo (x, y) result (z)
+  !$omp requires atomic_default_mem_order(release)
+  implicit none
+  real :: x, y, z
+
+  !$omp atomic write
+    x = y
+
+  !$omp atomic update
+    x = x + 1
+
+  !$omp atomic read  ! { dg-error "!.OMP ATOMIC READ at .1. incompatible with RELEASE clause implicitly provided by a REQUIRES directive" }
+    z = x
+end
+
+function bar (a, b) result (c)
+  !$omp requires atomic_default_mem_order(acquire)
+  implicit none
+  real :: a, b, c
+
+  !$omp atomic write  ! { dg-error "!.OMP ATOMIC WRITE at .1. incompatible with ACQUIRES clause implicitly provided by a REQUIRES directive" }
+    a = b
+
+  !$omp atomic update
+    a = a + 1
+
+  !$omp atomic read
+    c = a
+end
+
+
diff --git a/gcc/testsuite/gfortran.dg/gomp/requires-2.f90 b/gcc/testsuite/gfortran.dg/gomp/requires-2.f90
index 7b63d4a8b3b..5f11a7bfb2a 100644
--- a/gcc/testsuite/gfortran.dg/gomp/requires-2.f90
+++ b/gcc/testsuite/gfortran.dg/gomp/requires-2.f90
@@ -8,7 +8,7 @@ 
 !$omp requires atomic_default_mem_order (seq_cst)
 !$omp requires atomic_default_mem_order (seq_cst)
 !$omp requires atomic_default_mem_order (acq_rel) ! { dg-error "overrides a previous 'atomic_default_mem_order\\(seq_cst\\)'" }
-!$omp requires atomic_default_mem_order (foo) ! { dg-error "Expected SEQ_CST, ACQ_REL or RELAXED for ATOMIC_DEFAULT_MEM_ORDER clause" }
+!$omp requires atomic_default_mem_order (foo) ! { dg-error "Expected ACQ_REL, ACQUIRE, RELAXED, RELEASE or SEQ_CST for ATOMIC_DEFAULT_MEM_ORDER clause" }
 end
 
 ! { dg-prune-output "not yet supported" }
diff --git a/gcc/testsuite/gfortran.dg/gomp/requires-3.f90 b/gcc/testsuite/gfortran.dg/gomp/requires-3.f90
index 4429aab2ee6..8c9d6ed3b21 100644
--- a/gcc/testsuite/gfortran.dg/gomp/requires-3.f90
+++ b/gcc/testsuite/gfortran.dg/gomp/requires-3.f90
@@ -1,4 +1,5 @@ 
-!$omp requires atomic_default_mem_order(acquire)	! { dg-error "Expected SEQ_CST, ACQ_REL or RELAXED for ATOMIC_DEFAULT_MEM_ORDER clause" }
-!$omp requires atomic_default_mem_order(release)	! { dg-error "Expected SEQ_CST, ACQ_REL or RELAXED for ATOMIC_DEFAULT_MEM_ORDER clause" }
-!$omp requires atomic_default_mem_order(foobar)	! { dg-error "Expected SEQ_CST, ACQ_REL or RELAXED for ATOMIC_DEFAULT_MEM_ORDER clause" }
+!$omp requires atomic_default_mem_order(foobar)	! { dg-error "Expected ACQ_REL, ACQUIRE, RELAXED, RELEASE or SEQ_CST for ATOMIC_DEFAULT_MEM_ORDER clause" }
+
+!$omp requires atomic_default_mem_order(acquire)	! OK since OpenMP 5.2
+!$omp requires atomic_default_mem_order(release)	! { dg-error "!.OMP REQUIRES clause 'atomic_default_mem_order\\(release\\)' specified at .1. overrides a previous 'atomic_default_mem_order\\(acquire\\)' \\(which might be through using a module\\)" }
 end
diff --git a/gcc/testsuite/gfortran.dg/gomp/requires-5.f90 b/gcc/testsuite/gfortran.dg/gomp/requires-5.f90
index ade2a3613c6..e719e929294 100644
--- a/gcc/testsuite/gfortran.dg/gomp/requires-5.f90
+++ b/gcc/testsuite/gfortran.dg/gomp/requires-5.f90
@@ -8,7 +8,7 @@  subroutine foo
 !$omp requires unified_shared_memory
 !$omp requires atomic_default_mem_order(relaxed)
 !$omp requires atomic_default_mem_order(relaxed)
-!$omp requires atomic_default_mem_order(seq_cst) ! { dg-error "overrides a previous 'atomic_default_mem_order\\(seq_cst\\)'" }
+!$omp requires atomic_default_mem_order(seq_cst) ! { dg-error "overrides a previous 'atomic_default_mem_order\\(relaxed\\)'" }
   !$omp target
   !$omp end target
 end