public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [committed] openmp: Partial OpenMP 5.2 doacross and omp_cur_iteration support
@ 2022-09-03  8:07 Jakub Jelinek
  2022-09-05 12:28 ` [PATCH] openmp: Introduce gimple_omp_ordered_standalone_p Jakub Jelinek
  2022-09-05 13:01 ` [committed] openmp: Partial OpenMP 5.2 doacross and omp_cur_iteration support Tobias Burnus
  0 siblings, 2 replies; 4+ messages in thread
From: Jakub Jelinek @ 2022-09-03  8:07 UTC (permalink / raw)
  To: gcc-patches; +Cc: Tobias Burnus

Hi!

The following patch implements part of the OpenMP 5.2 changes related
to ordered loops and with the assumed resolution of
https://github.com/OpenMP/spec/issues/3302 issues.

The changes are:
1) the depend clause on stand-alone ordered constructs has been renamed
   to doacross (because depend clause has different syntax on other
   constructs) with some syntax changes below, depend clause is deprecated
   (we'll deprecate stuff on the GCC side only when we have everything else
   from 5.2 implemented)
   depend(source) -> doacross(source:) or doacross(source:omp_cur_iteration)
   depend(sink:vec) -> doacross(sink:vec) (where vec has the same syntax
					   as before)
2) in 5.1 and before it has been significant whether ordered clause has or
   doesn't have an argument, if it didn't, only block-associated ordered
   could appear in the body, if it did, only stand-alone ordered could appear
   in the body, all loops had to be perfectly nested, no associated
   range-based for loops, no linear clause on work-sharing loop and ordered
   clause with an argument wasn't allowed on composite for simd.
   In 5.2, whether ordered clause has or doesn't have an argument is
   insignificant (except for bugs in the standard, #3302 mentions those),
   if the argument is missing, it is simply treated as equal to collapse
   argument (if any, otherwise 1).  The implementation better should be able
   to differentiate between ordered and doacross loops at compile time
   which previously was through the absence or presence of the argument,
   now it is done through looking at the body of the construct lexically
   and looking for stand-alone ordered constructs.  If there are any,
   it is to be handled as doacross loop, otherwise it is ordered loop
   (but in that case ordered argument if present must be equal to collapse
   argument - 5.2 says instead it must be one, but that is clearly wrong
   and mentioned in #3302) - stand-alone ordered constructs must appear
   lexically in the body (and had to before as well).  For the restrictions
   mentioned above, the for simd restriction is gone (stand-alone ordered
   can't appear in simd construct, so that is enough), and the other rules
   are expected to be changed into something related to presence of
   stand-alone ordered constructs in the body
3) 5.2 allows a new syntax, doacross(sink:omp_cur_iteration-1), which
   means wait for previous iteration in the iteration space of all the
   associated loops

The following patch implements that, except that we sorry for now
on the doacross(sink:omp_cur_iteration-1) syntax during omp expansion
because library side isn't done yet for it.  It doesn't implement it for
the Fortran FE either.
Incrementally, I'd like to change the way we differentiate between
stand-alone and block-associated ordered constructs, because the current
way of looking for presence of doacross clause doesn't work well if those
clauses are removed because they had been invalid (wrong syntax or
unknown variables in it etc.) and of course implement
doacross(sink:omp_cur_iteration-1).

Bootstrapped/regtested on x86_64-linux and i686-linux, committed to trunk.

2022-09-03  Jakub Jelinek  <jakub@redhat.com>

gcc/
	* tree-core.h (enum omp_clause_code): Add OMP_CLAUSE_DOACROSS.
	(enum omp_clause_depend_kind): Remove OMP_CLAUSE_DEPEND_SOURCE
	and OMP_CLAUSE_DEPEND_SINK, add OMP_CLAUSE_DEPEND_INVALID.
	(enum omp_clause_doacross_kind): New type.
	(struct tree_omp_clause): Add subcode.doacross_kind member.
	* tree.h (OMP_CLAUSE_DEPEND_SINK_NEGATIVE): Remove.
	(OMP_CLAUSE_DOACROSS_KIND): Define.
	(OMP_CLAUSE_DOACROSS_SINK_NEGATIVE): Define.
	(OMP_CLAUSE_DOACROSS_DEPEND): Define.
	(OMP_CLAUSE_ORDERED_DOACROSS): Define.
	* tree.cc (omp_clause_num_ops, omp_clause_code_name): Add
	OMP_CLAUSE_DOACROSS entries.
	* tree-nested.cc (convert_nonlocal_omp_clauses,
	convert_local_omp_clauses): Handle OMP_CLAUSE_DOACROSS.
	* tree-pretty-print.cc (dump_omp_clause): Don't handle
	OMP_CLAUSE_DEPEND_SOURCE and OMP_CLAUSE_DEPEND_SINK.  Handle
	OMP_CLAUSE_DOACROSS.
	* gimplify.cc (gimplify_omp_depend): Don't handle
	OMP_CLAUSE_DEPEND_SOURCE and OMP_CLAUSE_DEPEND_SINK.
	(gimplify_scan_omp_clauses): Likewise.  Handle OMP_CLAUSE_DOACROSS.
	(gimplify_adjust_omp_clauses): Handle OMP_CLAUSE_DOACROSS.
	(find_standalone_omp_ordered): New function.
	(gimplify_omp_for): When OMP_CLAUSE_ORDERED is present, search
	body for OMP_ORDERED with OMP_CLAUSE_DOACROSS and if found,
	set OMP_CLAUSE_ORDERED_DOACROSS.
	(gimplify_omp_ordered): Don't handle OMP_CLAUSE_DEPEND_SINK or
	OMP_CLAUSE_DEPEND_SOURCE, instead check OMP_CLAUSE_DOACROSS, adjust
	diagnostics that presence or absence of ordered clause parameter
	is irrelevant.  Handle doacross(sink:omp_cur_iteration-1).  Use
	actual user name of the clause - doacross or depend - in diagnostics.
	* omp-general.cc (omp_extract_for_data): Don't set fd->ordered
	if !OMP_CLAUSE_ORDERED_DOACROSS (t).  If
	OMP_CLAUSE_ORDERED_DOACROSS (t) but !OMP_CLAUSE_ORDERED_EXPR (t),
	set fd->ordered to -1 and set it after the loop in that case to
	fd->collapse.
	* omp-low.cc (check_omp_nesting_restrictions): Don't handle
	OMP_CLAUSE_DEPEND_SOURCE nor OMP_CLAUSE_DEPEND_SINK, instead check
	OMP_CLAUSE_DOACROSS.  Use actual user name of the clause - doacross
	or depend - in diagnostics.  Diagnose mixing of stand-alone and
	block associated ordered constructs binding to the same loop.
	(lower_omp_ordered_clauses): Don't handle OMP_CLAUSE_DEPEND_SINK,
	instead handle OMP_CLAUSE_DOACROSS.
	(lower_omp_ordered): Look for OMP_CLAUSE_DOACROSS instead of
	OMP_CLAUSE_DEPEND.
	(lower_depend_clauses): Don't handle OMP_CLAUSE_DEPEND_SOURCE and
	OMP_CLAUSE_DEPEND_SINK.
	* omp-expand.cc (expand_omp_ordered_sink): Emit a sorry for
	doacross(sink:omp_cur_iteration-1).
	(expand_omp_ordered_source_sink): Use
	OMP_CLAUSE_DOACROSS_SINK_NEGATIVE instead of
	OMP_CLAUSE_DEPEND_SINK_NEGATIVE.  Use actual user name of the clause
	- doacross or depend - in diagnostics.
	(expand_omp): Look for OMP_CLAUSE_DOACROSS clause instead of
	OMP_CLAUSE_DEPEND.
	(build_omp_regions_1): Likewise.
	(omp_make_gimple_edges): Likewise.
	* lto-streamer-out.cc (hash_tree): Handle OMP_CLAUSE_DOACROSS.
	* tree-streamer-in.cc (unpack_ts_omp_clause_value_fields): Likewise.
	* tree-streamer-out.cc (pack_ts_omp_clause_value_fields): Likewise.
gcc/c-family/
	* c-pragma.h (enum pragma_omp_clause): Add PRAGMA_OMP_CLAUSE_DOACROSS.
	* c-omp.cc (c_finish_omp_depobj): Check also for OMP_CLAUSE_DOACROSS
	clause and diagnose it.  Don't handle OMP_CLAUSE_DEPEND_SOURCE and
	OMP_CLAUSE_DEPEND_SINK.  Assert kind is not OMP_CLAUSE_DEPEND_INVALID.
gcc/c/
	* c-parser.cc (c_parser_omp_clause_name): Handle doacross.
	(c_parser_omp_clause_depend_sink): Renamed to ...
	(c_parser_omp_clause_doacross_sink): ... this.  Add depend_p argument.
	Handle parsing of doacross(sink:omp_cur_iteration-1).  Use
	OMP_CLAUSE_DOACROSS_SINK_NEGATIVE instead of
	OMP_CLAUSE_DEPEND_SINK_NEGATIVE, build OMP_CLAUSE_DOACROSS instead
	of OMP_CLAUSE_DEPEND and set OMP_CLAUSE_DOACROSS_DEPEND flag on it.
	(c_parser_omp_clause_depend): Use OMP_CLAUSE_DOACROSS_SINK and
	OMP_CLAUSE_DOACROSS_SOURCE instead of OMP_CLAUSE_DEPEND_SINK and
	OMP_CLAUSE_DEPEND_SOURCE, build OMP_CLAUSE_DOACROSS for depend(source)
	and set OMP_CLAUSE_DOACROSS_DEPEND on it.
	(c_parser_omp_clause_doacross): New function.
	(c_parser_omp_all_clauses): Handle PRAGMA_OMP_CLAUSE_DOACROSS.
	(c_parser_omp_depobj): Use OMP_CLAUSE_DEPEND_INVALID instead of
	OMP_CLAUSE_DEPEND_SOURCE.
	(c_parser_omp_for_loop): Don't diagnose here linear clause together
	with ordered with argument.
	(c_parser_omp_simd): Don't diagnose ordered clause with argument on
	for simd.
	(OMP_ORDERED_DEPEND_CLAUSE_MASK): Add PRAGMA_OMP_CLAUSE_DOACROSS.
	(c_parser_omp_ordered): Handle also doacross and adjust for it
	diagnostic wording.
	* c-typeck.cc (c_finish_omp_clauses): Handle OMP_CLAUSE_DOACROSS.
	Don't handle OMP_CLAUSE_DEPEND_SOURCE and OMP_CLAUSE_DEPEND_SINK.
gcc/cp/
	* parser.cc (cp_parser_omp_clause_name): Handle doacross.
	(cp_parser_omp_clause_depend_sink): Renamed to ...
	(cp_parser_omp_clause_doacross_sink): ... this.  Add depend_p
	argument.  Handle parsing of doacross(sink:omp_cur_iteration-1).  Use
	OMP_CLAUSE_DOACROSS_SINK_NEGATIVE instead of
	OMP_CLAUSE_DEPEND_SINK_NEGATIVE, build OMP_CLAUSE_DOACROSS instead
	of OMP_CLAUSE_DEPEND and set OMP_CLAUSE_DOACROSS_DEPEND flag on it.
	(cp_parser_omp_clause_depend): Use OMP_CLAUSE_DOACROSS_SINK and
	OMP_CLAUSE_DOACROSS_SOURCE instead of OMP_CLAUSE_DEPEND_SINK and
	OMP_CLAUSE_DEPEND_SOURCE, build OMP_CLAUSE_DOACROSS for depend(source)
	and set OMP_CLAUSE_DOACROSS_DEPEND on it.
	(cp_parser_omp_clause_doacross): New function.
	(cp_parser_omp_all_clauses): Handle PRAGMA_OMP_CLAUSE_DOACROSS.
	(cp_parser_omp_depobj): Use OMP_CLAUSE_DEPEND_INVALID instead of
	OMP_CLAUSE_DEPEND_SOURCE.
	(cp_parser_omp_for_loop): Don't diagnose here linear clause together
	with ordered with argument.
	(cp_parser_omp_simd): Don't diagnose ordered clause with argument on
	for simd.
	(OMP_ORDERED_DEPEND_CLAUSE_MASK): Add PRAGMA_OMP_CLAUSE_DOACROSS.
	(cp_parser_omp_ordered): Handle also doacross and adjust for it
	diagnostic wording.
	* pt.cc (tsubst_omp_clause_decl): Use
	OMP_CLAUSE_DOACROSS_SINK_NEGATIVE instead of
	OMP_CLAUSE_DEPEND_SINK_NEGATIVE.
	(tsubst_omp_clauses): Handle OMP_CLAUSE_DOACROSS.
	(tsubst_expr): Use OMP_CLAUSE_DEPEND_INVALID instead of
	OMP_CLAUSE_DEPEND_SOURCE.
	* semantics.cc (cp_finish_omp_clause_depend_sink): Rename to ...
	(cp_finish_omp_clause_doacross_sink): ... this.
	(finish_omp_clauses): Handle OMP_CLAUSE_DOACROSS.  Don't handle
	OMP_CLAUSE_DEPEND_SOURCE and OMP_CLAUSE_DEPEND_SINK.
gcc/fortran/
	* trans-openmp.cc (gfc_trans_omp_clauses): Use
	OMP_CLAUSE_DOACROSS_SINK_NEGATIVE instead of
	OMP_CLAUSE_DEPEND_SINK_NEGATIVE, build OMP_CLAUSE_DOACROSS
	clause instead of OMP_CLAUSE_DEPEND and set OMP_CLAUSE_DOACROSS_DEPEND
	on it.
gcc/testsuite/
	* c-c++-common/gomp/doacross-2.c: Adjust expected diagnostics.
	* c-c++-common/gomp/doacross-5.c: New test.
	* c-c++-common/gomp/doacross-6.c: New test.
	* c-c++-common/gomp/nesting-2.c: Adjust expected diagnostics.
	* c-c++-common/gomp/ordered-3.c: Likewise.
	* c-c++-common/gomp/sink-3.c: Likewise.
	* gfortran.dg/gomp/nesting-2.f90: Likewise.

--- gcc/tree-core.h.jj	2022-08-30 12:29:00.055159930 +0200
+++ gcc/tree-core.h	2022-09-01 17:05:21.271096253 +0200
@@ -345,6 +345,9 @@ enum omp_clause_code {
   /* OpenMP clause: has_device_addr (variable-list).  */
   OMP_CLAUSE_HAS_DEVICE_ADDR,
 
+  /* OpenMP clause: doacross ({source,sink}:vec).  */
+  OMP_CLAUSE_DOACROSS,
+
   /* Internal structure to hold OpenACC cache directive's variable-list.
      #pragma acc cache (variable-list).  */
   OMP_CLAUSE__CACHE_,
@@ -1525,12 +1527,18 @@ enum omp_clause_depend_kind
   OMP_CLAUSE_DEPEND_INOUT,
   OMP_CLAUSE_DEPEND_MUTEXINOUTSET,
   OMP_CLAUSE_DEPEND_INOUTSET,
-  OMP_CLAUSE_DEPEND_SOURCE,
-  OMP_CLAUSE_DEPEND_SINK,
   OMP_CLAUSE_DEPEND_DEPOBJ,
+  OMP_CLAUSE_DEPEND_INVALID,
   OMP_CLAUSE_DEPEND_LAST
 };
 
+enum omp_clause_doacross_kind
+{
+  OMP_CLAUSE_DOACROSS_SOURCE,
+  OMP_CLAUSE_DOACROSS_SINK,
+  OMP_CLAUSE_DOACROSS_LAST
+};
+
 enum omp_clause_proc_bind_kind
 {
   /* Numbers should match omp_proc_bind_t enum in omp.h.  */
@@ -1620,6 +1628,7 @@ struct GTY(()) tree_omp_clause {
     enum omp_clause_default_kind   default_kind;
     enum omp_clause_schedule_kind  schedule_kind;
     enum omp_clause_depend_kind    depend_kind;
+    enum omp_clause_doacross_kind  doacross_kind;
     /* See include/gomp-constants.h for enum gomp_map_kind's values.  */
     unsigned int		   map_kind;
     enum omp_clause_proc_bind_kind proc_bind_kind;
--- gcc/tree.h.jj	2022-08-30 12:29:00.109159197 +0200
+++ gcc/tree.h	2022-09-02 16:25:55.137047019 +0200
@@ -1722,9 +1722,16 @@ class auto_suppress_location_wrappers
 #define OMP_CLAUSE_DEPEND_KIND(NODE) \
   (OMP_CLAUSE_SUBCODE_CHECK (NODE, OMP_CLAUSE_DEPEND)->omp_clause.subcode.depend_kind)
 
-#define OMP_CLAUSE_DEPEND_SINK_NEGATIVE(NODE) \
+#define OMP_CLAUSE_DOACROSS_KIND(NODE) \
+  (OMP_CLAUSE_SUBCODE_CHECK (NODE, OMP_CLAUSE_DOACROSS)->omp_clause.subcode.doacross_kind)
+
+#define OMP_CLAUSE_DOACROSS_SINK_NEGATIVE(NODE) \
   TREE_PUBLIC (TREE_LIST_CHECK (NODE))
 
+/* True if DOACROSS clause is spelled as DEPEND.  */
+#define OMP_CLAUSE_DOACROSS_DEPEND(NODE) \
+  TREE_PROTECTED (OMP_CLAUSE_SUBCODE_CHECK (NODE, OMP_CLAUSE_DOACROSS))
+
 #define OMP_CLAUSE_MAP_KIND(NODE) \
   ((enum gomp_map_kind) OMP_CLAUSE_SUBCODE_CHECK (NODE, OMP_CLAUSE_MAP)->omp_clause.subcode.map_kind)
 #define OMP_CLAUSE_SET_MAP_KIND(NODE, MAP_KIND) \
@@ -1786,6 +1793,11 @@ class auto_suppress_location_wrappers
 #define OMP_CLAUSE_ORDERED_EXPR(NODE) \
   OMP_CLAUSE_OPERAND (OMP_CLAUSE_SUBCODE_CHECK (NODE, OMP_CLAUSE_ORDERED), 0)
 
+/* True on an OMP_CLAUSE_ORDERED if stand-alone ordered construct is nested
+   inside of work-sharing loop the clause is on.  */
+#define OMP_CLAUSE_ORDERED_DOACROSS(NODE) \
+  (OMP_CLAUSE_SUBCODE_CHECK (NODE, OMP_CLAUSE_ORDERED)->base.public_flag)
+
 /* True for unconstrained modifier on order(concurrent) clause.  */
 #define OMP_CLAUSE_ORDER_UNCONSTRAINED(NODE) \
   (OMP_CLAUSE_SUBCODE_CHECK (NODE, OMP_CLAUSE_ORDER)->base.public_flag)
--- gcc/tree.cc.jj	2022-08-26 09:18:25.403152829 +0200
+++ gcc/tree.cc	2022-09-01 17:06:13.675388950 +0200
@@ -294,6 +294,7 @@ unsigned const char omp_clause_num_ops[]
   2, /* OMP_CLAUSE_TO  */
   2, /* OMP_CLAUSE_MAP  */
   1, /* OMP_CLAUSE_HAS_DEVICE_ADDR  */
+  1, /* OMP_CLAUSE_DOACROSS  */
   2, /* OMP_CLAUSE__CACHE_  */
   2, /* OMP_CLAUSE_GANG  */
   1, /* OMP_CLAUSE_ASYNC  */
@@ -384,6 +385,7 @@ const char * const omp_clause_code_name[
   "to",
   "map",
   "has_device_addr",
+  "doacross",
   "_cache_",
   "gang",
   "async",
--- gcc/tree-nested.cc.jj	2022-05-27 12:48:40.468486805 +0200
+++ gcc/tree-nested.cc	2022-09-01 16:33:36.866753040 +0200
@@ -1368,6 +1368,7 @@ convert_nonlocal_omp_clauses (tree *pcla
 	case OMP_CLAUSE_IF:
 	case OMP_CLAUSE_NUM_THREADS:
 	case OMP_CLAUSE_DEPEND:
+	case OMP_CLAUSE_DOACROSS:
 	case OMP_CLAUSE_DEVICE:
 	case OMP_CLAUSE_NUM_TEAMS:
 	case OMP_CLAUSE_THREAD_LIMIT:
@@ -2157,6 +2158,7 @@ convert_local_omp_clauses (tree *pclause
 	case OMP_CLAUSE_IF:
 	case OMP_CLAUSE_NUM_THREADS:
 	case OMP_CLAUSE_DEPEND:
+	case OMP_CLAUSE_DOACROSS:
 	case OMP_CLAUSE_DEVICE:
 	case OMP_CLAUSE_NUM_TEAMS:
 	case OMP_CLAUSE_THREAD_LIMIT:
--- gcc/tree-pretty-print.cc.jj	2022-08-30 12:29:00.073159685 +0200
+++ gcc/tree-pretty-print.cc	2022-09-02 10:18:32.740423679 +0200
@@ -831,34 +831,9 @@ dump_omp_clause (pretty_printer *pp, tre
 	case OMP_CLAUSE_DEPEND_INOUTSET:
 	  name = "inoutset";
 	  break;
-	case OMP_CLAUSE_DEPEND_SOURCE:
-	  pp_string (pp, "source)");
-	  return;
 	case OMP_CLAUSE_DEPEND_LAST:
 	  name = "__internal__";
 	  break;
-	case OMP_CLAUSE_DEPEND_SINK:
-	  pp_string (pp, "sink:");
-	  for (tree t = OMP_CLAUSE_DECL (clause); t; t = TREE_CHAIN (t))
-	    if (TREE_CODE (t) == TREE_LIST)
-	      {
-		dump_generic_node (pp, TREE_VALUE (t), spc, flags, false);
-		if (TREE_PURPOSE (t) != integer_zero_node)
-		  {
-		    if (OMP_CLAUSE_DEPEND_SINK_NEGATIVE (t))
-		      pp_minus (pp);
-		    else
-		      pp_plus (pp);
-		    dump_generic_node (pp, TREE_PURPOSE (t), spc, flags,
-				       false);
-		  }
-		if (TREE_CHAIN (t))
-		  pp_comma (pp);
-	      }
-	    else
-	      gcc_unreachable ();
-	  pp_right_paren (pp);
-	  return;
 	default:
 	  gcc_unreachable ();
 	}
@@ -885,6 +860,49 @@ dump_omp_clause (pretty_printer *pp, tre
       }
       break;
 
+    case OMP_CLAUSE_DOACROSS:
+      pp_string (pp, OMP_CLAUSE_DOACROSS_DEPEND (clause)
+		     ? "depend(" : "doacross(");
+      switch (OMP_CLAUSE_DOACROSS_KIND (clause))
+	{
+	case OMP_CLAUSE_DOACROSS_SOURCE:
+	  if (OMP_CLAUSE_DOACROSS_DEPEND (clause))
+	    pp_string (pp, "source)");
+	  else
+	    pp_string (pp, "source:)");
+	  break;
+	case OMP_CLAUSE_DOACROSS_SINK:
+	  pp_string (pp, "sink:");
+	  if (OMP_CLAUSE_DECL (clause) == NULL_TREE)
+	    {
+	      pp_string (pp, "omp_cur_iteration-1)");
+	      break;
+	    }
+	  for (tree t = OMP_CLAUSE_DECL (clause); t; t = TREE_CHAIN (t))
+	    if (TREE_CODE (t) == TREE_LIST)
+	      {
+		dump_generic_node (pp, TREE_VALUE (t), spc, flags, false);
+		if (TREE_PURPOSE (t) != integer_zero_node)
+		  {
+		    if (OMP_CLAUSE_DOACROSS_SINK_NEGATIVE (t))
+		      pp_minus (pp);
+		    else
+		      pp_plus (pp);
+		    dump_generic_node (pp, TREE_PURPOSE (t), spc, flags,
+				       false);
+		  }
+		if (TREE_CHAIN (t))
+		  pp_comma (pp);
+	      }
+	    else
+	      gcc_unreachable ();
+	  pp_right_paren (pp);
+	  break;
+	default:
+	  gcc_unreachable ();
+	}
+      break;
+
     case OMP_CLAUSE_MAP:
       pp_string (pp, "map(");
       switch (OMP_CLAUSE_MAP_KIND (clause))
--- gcc/gimplify.cc.jj	2022-08-30 12:28:59.986160866 +0200
+++ gcc/gimplify.cc	2022-09-02 16:45:27.083153954 +0200
@@ -8319,9 +8319,6 @@ gimplify_omp_depend (tree *list_p, gimpl
 	  case OMP_CLAUSE_DEPEND_INOUTSET:
 	    i = 4;
 	    break;
-	  case OMP_CLAUSE_DEPEND_SOURCE:
-	  case OMP_CLAUSE_DEPEND_SINK:
-	    continue;
 	  default:
 	    gcc_unreachable ();
 	  }
@@ -8560,9 +8557,6 @@ gimplify_omp_depend (tree *list_p, gimpl
 	  case OMP_CLAUSE_DEPEND_INOUTSET:
 	    i = 4;
 	    break;
-	  case OMP_CLAUSE_DEPEND_SOURCE:
-	  case OMP_CLAUSE_DEPEND_SINK:
-	    continue;
 	  default:
 	    gcc_unreachable ();
 	  }
@@ -10406,8 +10400,8 @@ gimplify_scan_omp_clauses (tree *list_p,
 	  gimplify_omp_affinity (list_p, pre_p);
 	  remove = true;
 	  break;
-	case OMP_CLAUSE_DEPEND:
-	  if (OMP_CLAUSE_DEPEND_KIND (c) == OMP_CLAUSE_DEPEND_SINK)
+	case OMP_CLAUSE_DOACROSS:
+	  if (OMP_CLAUSE_DOACROSS_KIND (c) == OMP_CLAUSE_DOACROSS_SINK)
 	    {
 	      tree deps = OMP_CLAUSE_DECL (c);
 	      while (deps && TREE_CODE (deps) == TREE_LIST)
@@ -10418,10 +10412,12 @@ gimplify_scan_omp_clauses (tree *list_p,
 				   pre_p, NULL, is_gimple_val, fb_rvalue);
 		  deps = TREE_CHAIN (deps);
 		}
-	      break;
 	    }
-	  else if (OMP_CLAUSE_DEPEND_KIND (c) == OMP_CLAUSE_DEPEND_SOURCE)
-	    break;
+	  else
+	    gcc_assert (OMP_CLAUSE_DOACROSS_KIND (c)
+			== OMP_CLAUSE_DOACROSS_SOURCE);
+	  break;
+	case OMP_CLAUSE_DEPEND:
 	  if (handled_depend_iterators == -1)
 	    handled_depend_iterators = gimplify_omp_depend (list_p, pre_p);
 	  if (handled_depend_iterators)
@@ -11946,6 +11942,7 @@ gimplify_adjust_omp_clauses (gimple_seq
 	case OMP_CLAUSE_SAFELEN:
 	case OMP_CLAUSE_SIMDLEN:
 	case OMP_CLAUSE_DEPEND:
+	case OMP_CLAUSE_DOACROSS:
 	case OMP_CLAUSE_PRIORITY:
 	case OMP_CLAUSE_GRAINSIZE:
 	case OMP_CLAUSE_NUM_TASKS:
@@ -12429,6 +12426,29 @@ gimplify_omp_taskloop_expr (tree type, t
   OMP_FOR_CLAUSES (orig_for_stmt) = c;
 }
 
+/* Helper function of gimplify_omp_for, find OMP_ORDERED with
+   OMP_CLAUSE_DOACROSS clause inside of OMP_FOR's body.  */
+
+static tree
+find_standalone_omp_ordered (tree *tp, int *walk_subtrees, void *)
+{
+  switch (TREE_CODE (*tp))
+    {
+    case OMP_ORDERED:
+      if (omp_find_clause (OMP_ORDERED_CLAUSES (*tp), OMP_CLAUSE_DOACROSS))
+	return *tp;
+      break;
+    case OMP_SIMD:
+    case OMP_PARALLEL:
+    case OMP_TARGET:
+      *walk_subtrees = 0;
+      break;
+    default:
+      break;
+    }
+  return NULL_TREE;
+}
+
 /* Gimplify the gross structure of an OMP_FOR statement.  */
 
 static enum gimplify_status
@@ -12804,12 +12824,24 @@ gimplify_omp_for (tree *expr_p, gimple_s
 
   tree c = omp_find_clause (OMP_FOR_CLAUSES (for_stmt), OMP_CLAUSE_ORDERED);
   bool is_doacross = false;
-  if (c && OMP_CLAUSE_ORDERED_EXPR (c))
+  if (c && walk_tree_without_duplicates (&OMP_FOR_BODY (for_stmt),
+					 find_standalone_omp_ordered, NULL))
     {
+      OMP_CLAUSE_ORDERED_DOACROSS (c) = 1;
       is_doacross = true;
-      gimplify_omp_ctxp->loop_iter_var.create (TREE_VEC_LENGTH
-						 (OMP_FOR_INIT (for_stmt))
-					       * 2);
+      int len = TREE_VEC_LENGTH (OMP_FOR_INIT (for_stmt));
+      gimplify_omp_ctxp->loop_iter_var.create (len * 2);
+      for (tree *pc = &OMP_FOR_CLAUSES (for_stmt); *pc; )
+	if (OMP_CLAUSE_CODE (*pc) == OMP_CLAUSE_LINEAR)
+	  {
+	    error_at (OMP_CLAUSE_LOCATION (*pc),
+		      "%<linear%> clause may not be specified together "
+		      "with %<ordered%> clause if stand-alone %<ordered%> "
+		      "construct is nested in it");
+	    *pc = OMP_CLAUSE_CHAIN (*pc);
+	  }
+	else
+	  pc = &OMP_CLAUSE_CHAIN (*pc);
     }
   int collapse = 1, tile = 0;
   c = omp_find_clause (OMP_FOR_CLAUSES (for_stmt), OMP_CLAUSE_COLLAPSE);
@@ -14882,21 +14914,22 @@ gimplify_omp_ordered (tree expr, gimple_
   if (gimplify_omp_ctxp)
     {
       for (c = OMP_ORDERED_CLAUSES (expr); c; c = OMP_CLAUSE_CHAIN (c))
-	if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_DEPEND
-	    && gimplify_omp_ctxp->loop_iter_var.is_empty ()
-	    && (OMP_CLAUSE_DEPEND_KIND (c) == OMP_CLAUSE_DEPEND_SINK
-		|| OMP_CLAUSE_DEPEND_KIND (c) == OMP_CLAUSE_DEPEND_SOURCE))
+	if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_DOACROSS
+	    && gimplify_omp_ctxp->loop_iter_var.is_empty ())
 	  {
 	    error_at (OMP_CLAUSE_LOCATION (c),
-		      "%<ordered%> construct with %<depend%> clause must be "
-		      "closely nested inside a loop with %<ordered%> clause "
-		      "with a parameter");
+		      "%<ordered%> construct with %qs clause must be "
+		      "closely nested inside a loop with %<ordered%> clause",
+		      OMP_CLAUSE_DOACROSS_DEPEND (c) ? "depend" : "doacross");
 	    failures++;
 	  }
-	else if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_DEPEND
-		 && OMP_CLAUSE_DEPEND_KIND (c) == OMP_CLAUSE_DEPEND_SINK)
+	else if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_DOACROSS
+		 && OMP_CLAUSE_DOACROSS_KIND (c) == OMP_CLAUSE_DOACROSS_SINK)
 	  {
 	    bool fail = false;
+	    sink_c = c;
+	    if (OMP_CLAUSE_DECL (c) == NULL_TREE)
+	      continue;  /* omp_cur_iteration - 1 */
 	    for (decls = OMP_CLAUSE_DECL (c), i = 0;
 		 decls && TREE_CODE (decls) == TREE_LIST;
 		 decls = TREE_CHAIN (decls), ++i)
@@ -14919,21 +14952,24 @@ gimplify_omp_ordered (tree expr, gimple_
 	    if (!fail && i != gimplify_omp_ctxp->loop_iter_var.length () / 2)
 	      {
 		error_at (OMP_CLAUSE_LOCATION (c),
-			  "number of variables in %<depend%> clause with "
+			  "number of variables in %qs clause with "
 			  "%<sink%> modifier does not match number of "
-			  "iteration variables");
+			  "iteration variables",
+			  OMP_CLAUSE_DOACROSS_DEPEND (c)
+			  ? "depend" : "doacross");
 		failures++;
 	      }
-	    sink_c = c;
 	  }
-	else if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_DEPEND
-		 && OMP_CLAUSE_DEPEND_KIND (c) == OMP_CLAUSE_DEPEND_SOURCE)
+	else if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_DOACROSS
+		 && OMP_CLAUSE_DOACROSS_KIND (c) == OMP_CLAUSE_DOACROSS_SOURCE)
 	  {
 	    if (source_c)
 	      {
 		error_at (OMP_CLAUSE_LOCATION (c),
-			  "more than one %<depend%> clause with %<source%> "
-			  "modifier on an %<ordered%> construct");
+			  "more than one %qs clause with %<source%> "
+			  "modifier on an %<ordered%> construct",
+			  OMP_CLAUSE_DOACROSS_DEPEND (source_c)
+			  ? "depend" : "doacross");
 		failures++;
 	      }
 	    else
@@ -14943,9 +14979,11 @@ gimplify_omp_ordered (tree expr, gimple_
   if (source_c && sink_c)
     {
       error_at (OMP_CLAUSE_LOCATION (source_c),
-		"%<depend%> clause with %<source%> modifier specified "
-		"together with %<depend%> clauses with %<sink%> modifier "
-		"on the same construct");
+		"%qs clause with %<source%> modifier specified "
+		"together with %qs clauses with %<sink%> modifier "
+		"on the same construct",
+		OMP_CLAUSE_DOACROSS_DEPEND (source_c) ? "depend" : "doacross",
+		OMP_CLAUSE_DOACROSS_DEPEND (sink_c) ? "depend" : "doacross");
       failures++;
     }
 
--- gcc/omp-general.cc.jj	2022-08-17 16:59:09.128546118 +0200
+++ gcc/omp-general.cc	2022-09-02 17:14:13.064761612 +0200
@@ -241,8 +241,13 @@ omp_extract_for_data (gomp_for *for_stmt
 	break;
       case OMP_CLAUSE_ORDERED:
 	fd->have_ordered = true;
-	if (OMP_CLAUSE_ORDERED_EXPR (t))
-	  fd->ordered = tree_to_shwi (OMP_CLAUSE_ORDERED_EXPR (t));
+	if (OMP_CLAUSE_ORDERED_DOACROSS (t))
+	  {
+	    if (OMP_CLAUSE_ORDERED_EXPR (t))
+	      fd->ordered = tree_to_shwi (OMP_CLAUSE_ORDERED_EXPR (t));
+	    else
+	      fd->ordered = -1;
+	  }
 	break;
       case OMP_CLAUSE_SCHEDULE:
 	gcc_assert (!distribute && !taskloop);
@@ -301,6 +306,9 @@ omp_extract_for_data (gomp_for *for_stmt
 	break;
       }
 
+  if (fd->ordered == -1)
+    fd->ordered = fd->collapse;
+
   /* For order(reproducible:concurrent) schedule ({dynamic,guided,runtime})
      we have either the option to expensively remember at runtime how we've
      distributed work from first loop and reuse that in following loops with
--- gcc/omp-low.cc.jj	2022-08-30 12:29:00.039160147 +0200
+++ gcc/omp-low.cc	2022-09-02 18:33:16.041450721 +0200
@@ -3636,14 +3636,13 @@ check_omp_nesting_restrictions (gimple *
       break;
     case GIMPLE_OMP_TASK:
       for (c = gimple_omp_task_clauses (stmt); c; c = OMP_CLAUSE_CHAIN (c))
-	if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_DEPEND
-	    && (OMP_CLAUSE_DEPEND_KIND (c) == OMP_CLAUSE_DEPEND_SOURCE
-		|| OMP_CLAUSE_DEPEND_KIND (c) == OMP_CLAUSE_DEPEND_SINK))
+	if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_DOACROSS)
 	  {
-	    enum omp_clause_depend_kind kind = OMP_CLAUSE_DEPEND_KIND (c);
+	    enum omp_clause_doacross_kind kind = OMP_CLAUSE_DOACROSS_KIND (c);
 	    error_at (OMP_CLAUSE_LOCATION (c),
-		      "%<depend(%s)%> is only allowed in %<omp ordered%>",
-		      kind == OMP_CLAUSE_DEPEND_SOURCE ? "source" : "sink");
+		      "%<%s(%s)%> is only allowed in %<omp ordered%>",
+		      OMP_CLAUSE_DOACROSS_DEPEND (c) ? "depend" : "doacross",
+		      kind == OMP_CLAUSE_DOACROSS_SOURCE ? "source" : "sink");
 	    return false;
 	  }
       break;
@@ -3651,43 +3650,30 @@ check_omp_nesting_restrictions (gimple *
       for (c = gimple_omp_ordered_clauses (as_a <gomp_ordered *> (stmt));
 	   c; c = OMP_CLAUSE_CHAIN (c))
 	{
-	  if (OMP_CLAUSE_CODE (c) != OMP_CLAUSE_DEPEND)
+	  if (OMP_CLAUSE_CODE (c) != OMP_CLAUSE_DOACROSS)
 	    {
-	      gcc_assert (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_THREADS
-			  || OMP_CLAUSE_CODE (c) == OMP_CLAUSE_SIMD);
-	      continue;
-	    }
-	  enum omp_clause_depend_kind kind = OMP_CLAUSE_DEPEND_KIND (c);
-	  if (kind == OMP_CLAUSE_DEPEND_SOURCE
-	      || kind == OMP_CLAUSE_DEPEND_SINK)
-	    {
-	      tree oclause;
-	      /* Look for containing ordered(N) loop.  */
-	      if (ctx == NULL
-		  || gimple_code (ctx->stmt) != GIMPLE_OMP_FOR
-		  || (oclause
-			= omp_find_clause (gimple_omp_for_clauses (ctx->stmt),
-					   OMP_CLAUSE_ORDERED)) == NULL_TREE)
-		{
-		  error_at (OMP_CLAUSE_LOCATION (c),
-			    "%<ordered%> construct with %<depend%> clause "
-			    "must be closely nested inside an %<ordered%> "
-			    "loop");
-		  return false;
-		}
-	      else if (OMP_CLAUSE_ORDERED_EXPR (oclause) == NULL_TREE)
+	      if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_DEPEND)
 		{
 		  error_at (OMP_CLAUSE_LOCATION (c),
-			    "%<ordered%> construct with %<depend%> clause "
-			    "must be closely nested inside a loop with "
-			    "%<ordered%> clause with a parameter");
+			    "invalid depend kind in omp %<ordered%> %<depend%>");
 		  return false;
 		}
+	      gcc_assert (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_THREADS
+			  || OMP_CLAUSE_CODE (c) == OMP_CLAUSE_SIMD);
+	      continue;
 	    }
-	  else
+
+	  tree oclause;
+	  /* Look for containing ordered(N) loop.  */
+	  if (ctx == NULL
+	      || gimple_code (ctx->stmt) != GIMPLE_OMP_FOR
+	      || (oclause
+		  = omp_find_clause (gimple_omp_for_clauses (ctx->stmt),
+				     OMP_CLAUSE_ORDERED)) == NULL_TREE)
 	    {
 	      error_at (OMP_CLAUSE_LOCATION (c),
-			"invalid depend kind in omp %<ordered%> %<depend%>");
+			"%<ordered%> construct with %<depend%> clause "
+			"must be closely nested inside an %<ordered%> loop");
 	      return false;
 	    }
 	}
@@ -3732,14 +3718,37 @@ check_omp_nesting_restrictions (gimple *
 			  "a loop region with an %<ordered%> clause");
 		return false;
 	      }
-	    if (OMP_CLAUSE_ORDERED_EXPR (o) != NULL_TREE
-		&& omp_find_clause (c, OMP_CLAUSE_DEPEND) == NULL_TREE)
+	    if (omp_find_clause (c, OMP_CLAUSE_DOACROSS) == NULL_TREE)
 	      {
-		error_at (gimple_location (stmt),
-			  "%<ordered%> region without %<depend%> clause may "
-			  "not be closely nested inside a loop region with "
-			  "an %<ordered%> clause with a parameter");
-		return false;
+		if (OMP_CLAUSE_ORDERED_DOACROSS (o))
+		  {
+		    error_at (gimple_location (stmt),
+			      "%<ordered%> construct without %<doacross%> or "
+			      "%<depend%> clauses must not have the same "
+			      "binding region as %<ordered%> construct with "
+			      "those clauses");
+		    return false;
+		  }
+		else if (OMP_CLAUSE_ORDERED_EXPR (o))
+		  {
+		    tree co
+		      = omp_find_clause (gimple_omp_for_clauses (ctx->stmt),
+					 OMP_CLAUSE_COLLAPSE);
+		    HOST_WIDE_INT
+		      o_n = tree_to_shwi (OMP_CLAUSE_ORDERED_EXPR (o));
+		    HOST_WIDE_INT c_n = 1;
+		    if (co)
+		      c_n = tree_to_shwi (OMP_CLAUSE_COLLAPSE_EXPR (co));
+		    if (o_n != c_n)
+		      {
+			error_at (gimple_location (stmt),
+				  "%<ordered%> construct without %<doacross%> "
+				  "or %<depend%> clauses binds to loop where "
+				  "%<collapse%> argument %wd is different from "
+				  "%<ordered%> argument %wd", c_n, o_n);
+			return false;
+		      }
+		  }
 	      }
 	    return true;
 	  case GIMPLE_OMP_TARGET:
@@ -3793,14 +3802,12 @@ check_omp_nesting_restrictions (gimple *
       break;
     case GIMPLE_OMP_TARGET:
       for (c = gimple_omp_target_clauses (stmt); c; c = OMP_CLAUSE_CHAIN (c))
-	if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_DEPEND
-	    && (OMP_CLAUSE_DEPEND_KIND (c) == OMP_CLAUSE_DEPEND_SOURCE
-		|| OMP_CLAUSE_DEPEND_KIND (c) == OMP_CLAUSE_DEPEND_SINK))
+	if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_DOACROSS)
 	  {
-	    enum omp_clause_depend_kind kind = OMP_CLAUSE_DEPEND_KIND (c);
+	    enum omp_clause_doacross_kind kind = OMP_CLAUSE_DOACROSS_KIND (c);
 	    error_at (OMP_CLAUSE_LOCATION (c),
 		      "%<depend(%s)%> is only allowed in %<omp ordered%>",
-		      kind == OMP_CLAUSE_DEPEND_SOURCE ? "source" : "sink");
+		      kind == OMP_CLAUSE_DOACROSS_SOURCE ? "source" : "sink");
 	    return false;
 	  }
       if (is_gimple_omp_offloaded (stmt)
@@ -9743,8 +9750,8 @@ lower_omp_ordered_clauses (gimple_stmt_i
 
   tree *list_p = gimple_omp_ordered_clauses_ptr (ord_stmt);
   tree c = gimple_omp_ordered_clauses (ord_stmt);
-  if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_DEPEND
-      && OMP_CLAUSE_DEPEND_KIND (c) == OMP_CLAUSE_DEPEND_SINK)
+  if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_DOACROSS
+      && OMP_CLAUSE_DOACROSS_KIND (c) == OMP_CLAUSE_DOACROSS_SINK)
     {
       /* Merge depend clauses from multiple adjacent
 	 #pragma omp ordered depend(sink:...) constructs
@@ -9766,8 +9773,8 @@ lower_omp_ordered_clauses (gimple_stmt_i
 	  gomp_ordered *ord_stmt2 = as_a <gomp_ordered *> (stmt);
 	  c = gimple_omp_ordered_clauses (ord_stmt2);
 	  if (c == NULL_TREE
-	      || OMP_CLAUSE_CODE (c) != OMP_CLAUSE_DEPEND
-	      || OMP_CLAUSE_DEPEND_KIND (c) != OMP_CLAUSE_DEPEND_SINK)
+	      || OMP_CLAUSE_CODE (c) != OMP_CLAUSE_DOACROSS
+	      || OMP_CLAUSE_DOACROSS_KIND (c) != OMP_CLAUSE_DOACROSS_SINK)
 	    break;
 	  while (*list_p)
 	    list_p = &OMP_CLAUSE_CHAIN (*list_p);
@@ -9834,8 +9841,8 @@ lower_omp_ordered_clauses (gimple_stmt_i
     {
       bool remove = false;
 
-      gcc_assert (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_DEPEND);
-      if (OMP_CLAUSE_DEPEND_KIND (c) != OMP_CLAUSE_DEPEND_SINK)
+      gcc_assert (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_DOACROSS);
+      if (OMP_CLAUSE_DOACROSS_KIND (c) != OMP_CLAUSE_DOACROSS_SINK)
 	goto next_ordered_clause;
 
       tree vec;
@@ -9986,7 +9993,7 @@ lower_omp_ordered (gimple_stmt_iterator
 				  OMP_CLAUSE_THREADS);
 
   if (omp_find_clause (gimple_omp_ordered_clauses (ord_stmt),
-		       OMP_CLAUSE_DEPEND))
+		       OMP_CLAUSE_DOACROSS))
     {
       /* FIXME: This is needs to be moved to the expansion to verify various
 	 conditions only testable on cfg with dominators computed, and also
@@ -12362,9 +12369,6 @@ lower_depend_clauses (tree *pclauses, gi
 	case OMP_CLAUSE_DEPEND_INOUTSET:
 	  cnt[4]++;
 	  break;
-	case OMP_CLAUSE_DEPEND_SOURCE:
-	case OMP_CLAUSE_DEPEND_SINK:
-	  /* FALLTHRU */
 	default:
 	  gcc_unreachable ();
 	}
--- gcc/omp-expand.cc.jj	2022-08-30 12:29:00.016160459 +0200
+++ gcc/omp-expand.cc	2022-09-02 18:18:37.253370510 +0200
@@ -3298,6 +3298,11 @@ expand_omp_ordered_sink (gimple_stmt_ite
   gimple_stmt_iterator gsi2 = *gsi;
   bool warned_step = false;
 
+  if (deps == NULL)
+    {
+      sorry_at (loc, "%<doacross(sink:omp_cur_iteration-1)%> not supported yet");
+      return;
+    }
   for (i = 0; i < fd->ordered; i++)
     {
       tree step = NULL_TREE;
@@ -3321,9 +3326,11 @@ expand_omp_ordered_sink (gimple_stmt_ite
 		break;
 	      forward = tree_int_cst_sgn (step) != -1;
 	    }
-	  if (forward ^ OMP_CLAUSE_DEPEND_SINK_NEGATIVE (deps))
-	    warning_at (loc, 0, "%<depend%> clause with %<sink%> modifier "
-				"waiting for lexically later iteration");
+	  if (forward ^ OMP_CLAUSE_DOACROSS_SINK_NEGATIVE (deps))
+	    warning_at (loc, 0, "%qs clause with %<sink%> modifier "
+				"waiting for lexically later iteration",
+			OMP_CLAUSE_DOACROSS_DEPEND (c)
+			? "depend" : "doacross");
 	  break;
 	}
       deps = TREE_CHAIN (deps);
@@ -3377,13 +3384,13 @@ expand_omp_ordered_sink (gimple_stmt_ite
 	  tree co = fold_convert_loc (loc, itype, off);
 	  if (POINTER_TYPE_P (TREE_TYPE (fd->loops[i].v)))
 	    {
-	      if (OMP_CLAUSE_DEPEND_SINK_NEGATIVE (deps))
+	      if (OMP_CLAUSE_DOACROSS_SINK_NEGATIVE (deps))
 		co = fold_build1_loc (loc, NEGATE_EXPR, itype, co);
 	      a = fold_build2_loc (loc, POINTER_PLUS_EXPR,
 				   TREE_TYPE (fd->loops[i].v), fd->loops[i].v,
 				   co);
 	    }
-	  else if (OMP_CLAUSE_DEPEND_SINK_NEGATIVE (deps))
+	  else if (OMP_CLAUSE_DOACROSS_SINK_NEGATIVE (deps))
 	    a = fold_build2_loc (loc, MINUS_EXPR, TREE_TYPE (fd->loops[i].v),
 				 fd->loops[i].v, co);
 	  else
@@ -3392,13 +3399,13 @@ expand_omp_ordered_sink (gimple_stmt_ite
 	  if (step)
 	    {
 	      tree t1, t2;
-	      if (OMP_CLAUSE_DEPEND_SINK_NEGATIVE (deps))
+	      if (OMP_CLAUSE_DOACROSS_SINK_NEGATIVE (deps))
 		t1 = fold_build2_loc (loc, GE_EXPR, boolean_type_node, a,
 				      fd->loops[i].n1);
 	      else
 		t1 = fold_build2_loc (loc, LT_EXPR, boolean_type_node, a,
 				      fd->loops[i].n2);
-	      if (OMP_CLAUSE_DEPEND_SINK_NEGATIVE (deps))
+	      if (OMP_CLAUSE_DOACROSS_SINK_NEGATIVE (deps))
 		t2 = fold_build2_loc (loc, LT_EXPR, boolean_type_node, a,
 				      fd->loops[i].n2);
 	      else
@@ -3420,14 +3427,14 @@ expand_omp_ordered_sink (gimple_stmt_ite
 	    }
 	  else if (fd->loops[i].cond_code == LT_EXPR)
 	    {
-	      if (OMP_CLAUSE_DEPEND_SINK_NEGATIVE (deps))
+	      if (OMP_CLAUSE_DOACROSS_SINK_NEGATIVE (deps))
 		t = fold_build2_loc (loc, GE_EXPR, boolean_type_node, a,
 				     fd->loops[i].n1);
 	      else
 		t = fold_build2_loc (loc, LT_EXPR, boolean_type_node, a,
 				     fd->loops[i].n2);
 	    }
-	  else if (OMP_CLAUSE_DEPEND_SINK_NEGATIVE (deps))
+	  else if (OMP_CLAUSE_DOACROSS_SINK_NEGATIVE (deps))
 	    t = fold_build2_loc (loc, GT_EXPR, boolean_type_node, a,
 				 fd->loops[i].n2);
 	  else
@@ -3459,9 +3466,11 @@ expand_omp_ordered_sink (gimple_stmt_ite
 			       build_int_cst (itype, 0));
 	  if (integer_zerop (t) && !warned_step)
 	    {
-	      warning_at (loc, 0, "%<depend%> clause with %<sink%> modifier "
+	      warning_at (loc, 0, "%qs clause with %<sink%> modifier "
 				  "refers to iteration never in the iteration "
-				  "space");
+				  "space",
+			  OMP_CLAUSE_DOACROSS_DEPEND (c)
+			  ? "depend" : "doacross");
 	      warned_step = true;
 	    }
 	  cond = fold_build2_loc (loc, BIT_AND_EXPR, boolean_type_node,
@@ -3486,7 +3495,7 @@ expand_omp_ordered_sink (gimple_stmt_ite
 						s));
       else
 	off = fold_build2_loc (loc, TRUNC_DIV_EXPR, itype, off, s);
-      if (OMP_CLAUSE_DEPEND_SINK_NEGATIVE (deps))
+      if (OMP_CLAUSE_DOACROSS_SINK_NEGATIVE (deps))
 	off = fold_build1_loc (loc, NEGATE_EXPR, itype, off);
       off = fold_convert_loc (loc, fd->iter_type, off);
       if (i <= fd->collapse - 1 && fd->collapse > 1)
@@ -3559,13 +3568,13 @@ expand_omp_ordered_source_sink (struct o
 	tree c;
 	for (c = gimple_omp_ordered_clauses (ord_stmt);
 	     c; c = OMP_CLAUSE_CHAIN (c))
-	  if (OMP_CLAUSE_DEPEND_KIND (c) == OMP_CLAUSE_DEPEND_SOURCE)
+	  if (OMP_CLAUSE_DOACROSS_KIND (c) == OMP_CLAUSE_DOACROSS_SOURCE)
 	    break;
 	if (c)
 	  expand_omp_ordered_source (&gsi, fd, counts, loc);
 	for (c = gimple_omp_ordered_clauses (ord_stmt);
 	     c; c = OMP_CLAUSE_CHAIN (c))
-	  if (OMP_CLAUSE_DEPEND_KIND (c) == OMP_CLAUSE_DEPEND_SINK)
+	  if (OMP_CLAUSE_DOACROSS_KIND (c) == OMP_CLAUSE_DOACROSS_SINK)
 	    expand_omp_ordered_sink (&gsi, fd, counts, c, loc);
 	gsi_remove (&gsi, true);
       }
@@ -10479,7 +10488,7 @@ expand_omp (struct omp_region *region)
 	    gomp_ordered *ord_stmt
 	      = as_a <gomp_ordered *> (last_stmt (region->entry));
 	    if (omp_find_clause (gimple_omp_ordered_clauses (ord_stmt),
-				 OMP_CLAUSE_DEPEND))
+				 OMP_CLAUSE_DOACROSS))
 	      {
 		/* We'll expand these when expanding corresponding
 		   worksharing region with ordered(n) clause.  */
@@ -10609,7 +10618,7 @@ build_omp_regions_1 (basic_block bb, str
 	  else if (code == GIMPLE_OMP_ORDERED
 		   && omp_find_clause (gimple_omp_ordered_clauses
 					 (as_a <gomp_ordered *> (stmt)),
-				       OMP_CLAUSE_DEPEND))
+				       OMP_CLAUSE_DOACROSS))
 	    /* #pragma omp ordered depend is also just a stand-alone
 	       directive.  */
 	    region = NULL;
@@ -10835,7 +10844,7 @@ omp_make_gimple_edges (basic_block bb, s
       fallthru = true;
       if (omp_find_clause (gimple_omp_ordered_clauses
 			     (as_a <gomp_ordered *> (last)),
-			   OMP_CLAUSE_DEPEND))
+			   OMP_CLAUSE_DOACROSS))
 	cur_region = cur_region->outer;
       break;
 
--- gcc/lto-streamer-out.cc.jj	2022-01-18 11:58:59.686980571 +0100
+++ gcc/lto-streamer-out.cc	2022-09-01 16:35:03.823584108 +0200
@@ -1553,6 +1553,9 @@ hash_tree (struct streamer_tree_cache_d
 	case OMP_CLAUSE_DEPEND:
 	  val = OMP_CLAUSE_DEPEND_KIND (t);
 	  break;
+	case OMP_CLAUSE_DOACROSS:
+	  val = OMP_CLAUSE_DOACROSS_KIND (t);
+	  break;
 	case OMP_CLAUSE_MAP:
 	  val = OMP_CLAUSE_MAP_KIND (t);
 	  break;
--- gcc/tree-streamer-in.cc.jj	2022-05-09 09:09:20.817466314 +0200
+++ gcc/tree-streamer-in.cc	2022-09-01 16:32:09.156932116 +0200
@@ -453,6 +453,11 @@ unpack_ts_omp_clause_value_fields (class
       OMP_CLAUSE_DEPEND_KIND (expr)
 	= bp_unpack_enum (bp, omp_clause_depend_kind, OMP_CLAUSE_DEPEND_LAST);
       break;
+    case OMP_CLAUSE_DOACROSS:
+      OMP_CLAUSE_DOACROSS_KIND (expr)
+	= bp_unpack_enum (bp, omp_clause_doacross_kind,
+			  OMP_CLAUSE_DOACROSS_LAST);
+      break;
     case OMP_CLAUSE_MAP:
       OMP_CLAUSE_SET_MAP_KIND (expr, bp_unpack_enum (bp, gomp_map_kind,
 						     GOMP_MAP_LAST));
--- gcc/tree-streamer-out.cc.jj	2022-02-04 14:36:56.342586625 +0100
+++ gcc/tree-streamer-out.cc	2022-09-01 16:32:38.916532065 +0200
@@ -419,6 +419,10 @@ pack_ts_omp_clause_value_fields (struct
       bp_pack_enum (bp, omp_clause_depend_kind, OMP_CLAUSE_DEPEND_LAST,
 		    OMP_CLAUSE_DEPEND_KIND (expr));
       break;
+    case OMP_CLAUSE_DOACROSS:
+      bp_pack_enum (bp, omp_clause_doacross_kind, OMP_CLAUSE_DOACROSS_LAST,
+		    OMP_CLAUSE_DOACROSS_KIND (expr));
+      break;
     case OMP_CLAUSE_MAP:
       bp_pack_enum (bp, gomp_map_kind, GOMP_MAP_LAST,
 		    OMP_CLAUSE_MAP_KIND (expr));
--- gcc/c-family/c-pragma.h.jj	2022-08-30 12:28:59.909161910 +0200
+++ gcc/c-family/c-pragma.h	2022-09-01 14:34:17.356367234 +0200
@@ -108,6 +108,7 @@ enum pragma_omp_clause {
   PRAGMA_OMP_CLAUSE_DEVICE,
   PRAGMA_OMP_CLAUSE_DEVICE_TYPE,
   PRAGMA_OMP_CLAUSE_DIST_SCHEDULE,
+  PRAGMA_OMP_CLAUSE_DOACROSS,
   PRAGMA_OMP_CLAUSE_ENTER,
   PRAGMA_OMP_CLAUSE_FILTER,
   PRAGMA_OMP_CLAUSE_FINAL,
--- gcc/c-family/c-omp.cc.jj	2022-08-30 12:28:59.874162385 +0200
+++ gcc/c-family/c-omp.cc	2022-09-01 17:39:13.733664070 +0200
@@ -714,8 +714,17 @@ c_finish_omp_depobj (location_t loc, tre
 
   if (clause)
     {
-      gcc_assert (TREE_CODE (clause) == OMP_CLAUSE
-		  && OMP_CLAUSE_CODE (clause) == OMP_CLAUSE_DEPEND);
+      gcc_assert (TREE_CODE (clause) == OMP_CLAUSE);
+      if (OMP_CLAUSE_CODE (clause) == OMP_CLAUSE_DOACROSS)
+	{
+	  error_at (OMP_CLAUSE_LOCATION (clause),
+		    "%<depend(%s)%> is only allowed in %<omp ordered%>",
+		    OMP_CLAUSE_DOACROSS_KIND (clause)
+		    == OMP_CLAUSE_DOACROSS_SOURCE
+		    ? "source" : "sink");
+	  return;
+	}
+      gcc_assert (OMP_CLAUSE_CODE (clause) == OMP_CLAUSE_DEPEND);
       if (OMP_CLAUSE_CHAIN (clause))
 	error_at (OMP_CLAUSE_LOCATION (clause),
 		  "more than one locator in %<depend%> clause on %<depobj%> "
@@ -727,13 +736,6 @@ c_finish_omp_depobj (location_t loc, tre
 		    "%<depobj%> dependence type specified in %<depend%> "
 		    "clause on %<depobj%> construct");
 	  return;
-	case OMP_CLAUSE_DEPEND_SOURCE:
-	case OMP_CLAUSE_DEPEND_SINK:
-	  error_at (OMP_CLAUSE_LOCATION (clause),
-		    "%<depend(%s)%> is only allowed in %<omp ordered%>",
-		    OMP_CLAUSE_DEPEND_KIND (clause) == OMP_CLAUSE_DEPEND_SOURCE
-		    ? "source" : "sink");
-	  return;
 	case OMP_CLAUSE_DEPEND_IN:
 	case OMP_CLAUSE_DEPEND_OUT:
 	case OMP_CLAUSE_DEPEND_INOUT:
@@ -764,8 +766,8 @@ c_finish_omp_depobj (location_t loc, tre
 	  gcc_unreachable ();
 	}
     }
   else
-    gcc_assert (kind != OMP_CLAUSE_DEPEND_SOURCE);
+    gcc_assert (kind != OMP_CLAUSE_DEPEND_INVALID);
 
   if (depobj == error_mark_node)
     return;
--- gcc/c/c-parser.cc.jj	2022-09-01 09:37:58.008630749 +0200
+++ gcc/c/c-parser.cc	2022-09-02 15:52:03.948221268 +0200
@@ -12814,6 +12814,8 @@ c_parser_omp_clause_name (c_parser *pars
 	    result = PRAGMA_OMP_CLAUSE_DEVICE_TYPE;
 	  else if (!strcmp ("dist_schedule", p))
 	    result = PRAGMA_OMP_CLAUSE_DIST_SCHEDULE;
+	  else if (!strcmp ("doacross", p))
+	    result = PRAGMA_OMP_CLAUSE_DOACROSS;
 	  break;
 	case 'e':
 	  if (!strcmp ("enter", p))
@@ -15962,8 +15964,8 @@ c_parser_omp_clause_simdlen (c_parser *p
 */
 
 static tree
-c_parser_omp_clause_depend_sink (c_parser *parser, location_t clause_loc,
-				 tree list)
+c_parser_omp_clause_doacross_sink (c_parser *parser, location_t clause_loc,
+				   tree list, bool depend_p)
 {
   tree vec = NULL;
   if (c_parser_next_token_is_not (parser, CPP_NAME)
@@ -15973,6 +15975,31 @@ c_parser_omp_clause_depend_sink (c_parse
       return list;
     }
 
+  if (!depend_p)
+    {
+      const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value);
+      if (strcmp (p, "omp_cur_iteration") == 0
+	  && c_parser_peek_2nd_token (parser)->type == CPP_MINUS
+	  && c_parser_peek_nth_token (parser, 3)->type == CPP_NUMBER
+	  && c_parser_peek_nth_token (parser, 4)->type == CPP_CLOSE_PAREN)
+	{
+	  tree val = c_parser_peek_nth_token (parser, 3)->value;
+	  if (integer_onep (val)
+	      && comptypes (TREE_TYPE (val), integer_type_node))
+	    {
+	      c_parser_consume_token (parser);
+	      c_parser_consume_token (parser);
+	      c_parser_consume_token (parser);
+	      tree u = build_omp_clause (clause_loc, OMP_CLAUSE_DOACROSS);
+	      OMP_CLAUSE_DOACROSS_KIND (u) = OMP_CLAUSE_DOACROSS_SINK;
+	      OMP_CLAUSE_CHAIN (u) = list;
+	      return u;
+	    }
+	}
+    }
+
+
+
   while (c_parser_next_token_is (parser, CPP_NAME)
 	 && c_parser_peek_token (parser)->id_kind == C_ID_ID)
     {
@@ -16018,7 +16045,7 @@ c_parser_omp_clause_depend_sink (c_parse
 	{
 	  vec = tree_cons (addend, t, vec);
 	  if (neg)
-	    OMP_CLAUSE_DEPEND_SINK_NEGATIVE (vec) = 1;
+	    OMP_CLAUSE_DOACROSS_SINK_NEGATIVE (vec) = 1;
 	}
 
       if (c_parser_next_token_is_not (parser, CPP_COMMA)
@@ -16032,8 +16059,9 @@ c_parser_omp_clause_depend_sink (c_parse
   if (vec == NULL_TREE)
     return list;
 
-  tree u = build_omp_clause (clause_loc, OMP_CLAUSE_DEPEND);
-  OMP_CLAUSE_DEPEND_KIND (u) = OMP_CLAUSE_DEPEND_SINK;
+  tree u = build_omp_clause (clause_loc, OMP_CLAUSE_DOACROSS);
+  OMP_CLAUSE_DOACROSS_KIND (u) = OMP_CLAUSE_DOACROSS_SINK;
+  OMP_CLAUSE_DOACROSS_DEPEND (u) = depend_p;
   OMP_CLAUSE_DECL (u) = nreverse (vec);
   OMP_CLAUSE_CHAIN (u) = list;
   return u;
@@ -16225,6 +16253,7 @@ c_parser_omp_clause_depend (c_parser *pa
 {
   location_t clause_loc = c_parser_peek_token (parser)->location;
   enum omp_clause_depend_kind kind = OMP_CLAUSE_DEPEND_LAST;
+  enum omp_clause_doacross_kind dkind = OMP_CLAUSE_DOACROSS_LAST;
   tree nl, c, iterators = NULL_TREE;
 
   matching_parens parens;
@@ -16256,9 +16285,9 @@ c_parser_omp_clause_depend (c_parser *pa
       else if (strcmp ("depobj", p) == 0)
 	kind = OMP_CLAUSE_DEPEND_DEPOBJ;
       else if (strcmp ("sink", p) == 0)
-	kind = OMP_CLAUSE_DEPEND_SINK;
+	dkind = OMP_CLAUSE_DOACROSS_SINK;
       else if (strcmp ("source", p) == 0)
-	kind = OMP_CLAUSE_DEPEND_SOURCE;
+	dkind = OMP_CLAUSE_DOACROSS_SOURCE;
       else
 	goto invalid_kind;
       break;
@@ -16268,18 +16297,20 @@ c_parser_omp_clause_depend (c_parser *pa
   c_parser_consume_token (parser);
 
   if (iterators
-      && (kind == OMP_CLAUSE_DEPEND_SOURCE || kind == OMP_CLAUSE_DEPEND_SINK))
+      && (dkind == OMP_CLAUSE_DOACROSS_SOURCE
+	  || dkind == OMP_CLAUSE_DOACROSS_SINK))
     {
       pop_scope ();
       error_at (clause_loc, "%<iterator%> modifier incompatible with %qs",
-		kind == OMP_CLAUSE_DEPEND_SOURCE ? "source" : "sink");
+		dkind == OMP_CLAUSE_DOACROSS_SOURCE ? "source" : "sink");
       iterators = NULL_TREE;
     }
 
-  if (kind == OMP_CLAUSE_DEPEND_SOURCE)
+  if (dkind == OMP_CLAUSE_DOACROSS_SOURCE)
     {
-      c = build_omp_clause (clause_loc, OMP_CLAUSE_DEPEND);
-      OMP_CLAUSE_DEPEND_KIND (c) = kind;
+      c = build_omp_clause (clause_loc, OMP_CLAUSE_DOACROSS);
+      OMP_CLAUSE_DOACROSS_KIND (c) = dkind;
+      OMP_CLAUSE_DOACROSS_DEPEND (c) = 1;
       OMP_CLAUSE_DECL (c) = NULL_TREE;
       OMP_CLAUSE_CHAIN (c) = list;
       parens.skip_until_found_close (parser);
@@ -16289,8 +16320,8 @@ c_parser_omp_clause_depend (c_parser *pa
   if (!c_parser_require (parser, CPP_COLON, "expected %<:%>"))
     goto resync_fail;
 
-  if (kind == OMP_CLAUSE_DEPEND_SINK)
-    nl = c_parser_omp_clause_depend_sink (parser, clause_loc, list);
+  if (dkind == OMP_CLAUSE_DOACROSS_SINK)
+    nl = c_parser_omp_clause_doacross_sink (parser, clause_loc, list, true);
   else
     {
       nl = c_parser_omp_variable_list (parser, clause_loc,
@@ -16326,6 +16357,65 @@ c_parser_omp_clause_depend (c_parser *pa
   return list;
 }
 
+/* OpenMP 5.2:
+   doacross ( source : )
+   doacross ( source : omp_cur_iteration )
+
+   doacross ( sink : vec )
+   doacross ( sink : omp_cur_iteration - logical_iteration )  */
+
+static tree
+c_parser_omp_clause_doacross (c_parser *parser, tree list)
+{
+  location_t clause_loc = c_parser_peek_token (parser)->location;
+  enum omp_clause_doacross_kind kind = OMP_CLAUSE_DOACROSS_LAST;
+  tree nl;
+  const char *p;
+
+  matching_parens parens;
+  if (!parens.require_open (parser))
+    return list;
+
+  if (c_parser_next_token_is_not (parser, CPP_NAME))
+    goto invalid_kind;
+
+  p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value);
+  if (strcmp ("sink", p) == 0)
+    kind = OMP_CLAUSE_DOACROSS_SINK;
+  else if (strcmp ("source", p) == 0)
+    kind = OMP_CLAUSE_DOACROSS_SOURCE;
+  else
+    goto invalid_kind;
+
+  c_parser_consume_token (parser);
+
+  if (!c_parser_require (parser, CPP_COLON, "expected %<:%>"))
+    goto resync_fail;
+
+  if (kind == OMP_CLAUSE_DOACROSS_SOURCE)
+    {
+      if (c_parser_next_token_is (parser, CPP_NAME)
+	  && strcmp (IDENTIFIER_POINTER (c_parser_peek_token (parser)->value),
+		     "omp_cur_iteration") == 0)
+	c_parser_consume_token (parser);
+      nl = build_omp_clause (clause_loc, OMP_CLAUSE_DOACROSS);
+      OMP_CLAUSE_DOACROSS_KIND (nl) = OMP_CLAUSE_DOACROSS_SOURCE;
+      OMP_CLAUSE_DECL (nl) = NULL_TREE;
+      OMP_CLAUSE_CHAIN (nl) = list;
+    }
+  else
+    nl = c_parser_omp_clause_doacross_sink (parser, clause_loc, list, false);
+
+  parens.skip_until_found_close (parser);
+  return nl;
+
+ invalid_kind:
+  c_parser_error (parser, "invalid doacross kind");
+ resync_fail:
+  parens.skip_until_found_close (parser);
+  return list;
+}
+
 /* OpenMP 4.0:
    map ( map-kind: variable-list )
    map ( variable-list )
@@ -17243,6 +17333,10 @@ c_parser_omp_all_clauses (c_parser *pars
 	  clauses = c_parser_omp_clause_depend (parser, clauses);
 	  c_name = "depend";
 	  break;
+	case PRAGMA_OMP_CLAUSE_DOACROSS:
+	  clauses = c_parser_omp_clause_doacross (parser, clauses);
+	  c_name = "doacross";
+	  break;
 	case PRAGMA_OMP_CLAUSE_MAP:
 	  clauses = c_parser_omp_clause_map (parser, clauses);
 	  c_name = "map";
@@ -19187,7 +19281,7 @@ c_parser_omp_depobj (c_parser *parser)
 
   parens.skip_until_found_close (parser);
   tree clause = NULL_TREE;
-  enum omp_clause_depend_kind kind = OMP_CLAUSE_DEPEND_SOURCE;
+  enum omp_clause_depend_kind kind = OMP_CLAUSE_DEPEND_INVALID;
   location_t c_loc = c_parser_peek_token (parser)->location;
   if (c_parser_next_token_is (parser, CPP_NAME))
     {
@@ -19226,7 +19320,7 @@ c_parser_omp_depobj (c_parser *parser)
 		  else if (!strcmp ("inoutset", p2))
 		    kind = OMP_CLAUSE_DEPEND_INOUTSET;
 		}
-	      if (kind == OMP_CLAUSE_DEPEND_SOURCE)
+	      if (kind == OMP_CLAUSE_DEPEND_INVALID)
 		{
 		  clause = error_mark_node;
 		  error_at (c2_loc, "expected %<in%>, %<out%>, %<inout%>, "
@@ -19238,7 +19332,7 @@ c_parser_omp_depobj (c_parser *parser)
 	    clause = error_mark_node;
 	}
     }
-  if (!clause && kind == OMP_CLAUSE_DEPEND_SOURCE)
+  if (!clause && kind == OMP_CLAUSE_DEPEND_INVALID)
     {
       clause = error_mark_node;
       error_at (c_loc, "expected %<depend%>, %<destroy%> or %<update%> clause");
@@ -19437,19 +19531,6 @@ c_parser_omp_for_loop (location_t loc, c
 	= build_int_cst (NULL_TREE, collapse);
       ordered = collapse;
     }
-  if (ordered)
-    {
-      for (tree *pc = &clauses; *pc; )
-	if (OMP_CLAUSE_CODE (*pc) == OMP_CLAUSE_LINEAR)
-	  {
-	    error_at (OMP_CLAUSE_LOCATION (*pc),
-		      "%<linear%> clause may not be specified together "
-		      "with %<ordered%> clause with a parameter");
-	    *pc = OMP_CLAUSE_CHAIN (*pc);
-	  }
-	else
-	  pc = &OMP_CLAUSE_CHAIN (*pc);
-    }
 
   gcc_assert (tiling || (collapse >= 1 && ordered >= 0));
   count = ordered ? ordered : collapse;
@@ -19887,15 +19968,6 @@ c_parser_omp_simd (location_t loc, c_par
     {
       omp_split_clauses (loc, OMP_SIMD, mask, clauses, cclauses);
       clauses = cclauses[C_OMP_CLAUSE_SPLIT_SIMD];
-      tree c = omp_find_clause (cclauses[C_OMP_CLAUSE_SPLIT_FOR],
-				OMP_CLAUSE_ORDERED);
-      if (c && OMP_CLAUSE_ORDERED_EXPR (c))
-	{
-	  error_at (OMP_CLAUSE_LOCATION (c),
-		    "%<ordered%> clause with parameter may not be specified "
-		    "on %qs construct", p_name);
-	  OMP_CLAUSE_ORDERED_EXPR (c) = NULL_TREE;
-	}
     }
 
   block = c_begin_compound_stmt (true);
@@ -20134,14 +20206,18 @@ c_parser_omp_masked (location_t loc, c_p
    # pragma omp ordered ordered-clauses new-line
      structured-block
 
-   # pragma omp ordered depend-clauses new-line  */
+   # pragma omp ordered depend-clauses new-line
+
+   OpenMP 5.2
+   # pragma omp ordered doacross-clauses new-line  */
 
 #define OMP_ORDERED_CLAUSE_MASK					\
 	( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_THREADS)	\
 	| (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_SIMD))
 
 #define OMP_ORDERED_DEPEND_CLAUSE_MASK				\
-	(OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEPEND)
+	( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEPEND)	\
+	| (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DOACROSS))
 
 static bool
 c_parser_omp_ordered (c_parser *parser, enum pragma_context context,
@@ -20161,7 +20237,7 @@ c_parser_omp_ordered (c_parser *parser,
     {
       const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value);
 
-      if (!strcmp ("depend", p))
+      if (!strcmp ("depend", p) || !strcmp ("doacross", p))
 	{
 	  if (!flag_openmp)	/* flag_openmp_simd  */
 	    {
@@ -20171,8 +20247,8 @@ c_parser_omp_ordered (c_parser *parser,
 	  if (context == pragma_stmt)
 	    {
 	      error_at (loc,
-			"%<#pragma omp ordered%> with %<depend%> clause may "
-			"only be used in compound statements");
+			"%<#pragma omp ordered%> with %qs clause may "
+			"only be used in compound statements", p);
 	      c_parser_skip_to_pragma_eol (parser, false);
 	      return true;
 	    }
--- gcc/c/c-typeck.cc.jj	2022-09-01 09:37:58.014630667 +0200
+++ gcc/c/c-typeck.cc	2022-09-02 10:17:07.680560840 +0200
@@ -14834,15 +14834,11 @@ c_finish_omp_clauses (tree clauses, enum
 	    }
 	  break;
 
-	case OMP_CLAUSE_DEPEND:
+	case OMP_CLAUSE_DOACROSS:
 	  t = OMP_CLAUSE_DECL (c);
 	  if (t == NULL_TREE)
-	    {
-	      gcc_assert (OMP_CLAUSE_DEPEND_KIND (c)
-			  == OMP_CLAUSE_DEPEND_SOURCE);
-	      break;
-	    }
-	  if (OMP_CLAUSE_DEPEND_KIND (c) == OMP_CLAUSE_DEPEND_SINK)
+	    break;
+	  if (OMP_CLAUSE_DOACROSS_KIND (c) == OMP_CLAUSE_DOACROSS_SINK)
 	    {
 	      gcc_assert (TREE_CODE (t) == TREE_LIST);
 	      for (; t; t = TREE_CHAIN (t))
@@ -14870,7 +14866,8 @@ c_finish_omp_clauses (tree clauses, enum
 		}
 	      break;
 	    }
-	  /* FALLTHRU */
+	  gcc_unreachable ();
+	case OMP_CLAUSE_DEPEND:
 	case OMP_CLAUSE_AFFINITY:
 	  t = OMP_CLAUSE_DECL (c);
 	  if (TREE_CODE (t) == TREE_LIST
--- gcc/cp/parser.cc.jj	2022-08-26 09:18:25.255154767 +0200
+++ gcc/cp/parser.cc	2022-09-02 15:51:28.675690445 +0200
@@ -11979,14 +11979,18 @@ cp_parser_handle_statement_omp_attribute
 	    if (dir->id == PRAGMA_OMP_ORDERED)
 	      {
 		/* ordered is C_OMP_DIR_CONSTRUCT only if it doesn't contain
-		   depend clause.  */
-		if (directive[1] && strcmp (directive[1], "depend") == 0)
+		   depend/doacross clause.  */
+		if (directive[1]
+		    && (strcmp (directive[1], "depend") == 0
+			|| strcmp (directive[1], "doacross") == 0))
 		  kind = C_OMP_DIR_STANDALONE;
 		else if (first + 2 < last
 			 && first[1].type == CPP_COMMA
 			 && first[2].type == CPP_NAME
-			 && strcmp (IDENTIFIER_POINTER (first[2].u.value),
-				    "depend") == 0)
+			 && (strcmp (IDENTIFIER_POINTER (first[2].u.value),
+				     "depend") == 0
+			     || strcmp (IDENTIFIER_POINTER (first[2].u.value),
+					"doacross") == 0))
 		  kind = C_OMP_DIR_STANDALONE;
 	      }
 	    else if (dir->id == PRAGMA_OMP_ERROR)
@@ -36587,6 +36591,8 @@ cp_parser_omp_clause_name (cp_parser *pa
 	    result = PRAGMA_OMP_CLAUSE_DEVICE_TYPE;
 	  else if (!strcmp ("dist_schedule", p))
 	    result = PRAGMA_OMP_CLAUSE_DIST_SCHEDULE;
+	  else if (!strcmp ("doacross", p))
+	    result = PRAGMA_OMP_CLAUSE_DOACROSS;
 	  break;
 	case 'e':
 	  if (!strcmp ("enter", p))
@@ -39314,8 +39320,8 @@ cp_parser_omp_clause_simdlen (cp_parser
 */
 
 static tree
-cp_parser_omp_clause_depend_sink (cp_parser *parser, location_t clause_loc,
-				  tree list)
+cp_parser_omp_clause_doacross_sink (cp_parser *parser, location_t clause_loc,
+				    tree list, bool depend_p)
 {
   tree vec = NULL;
 
@@ -39325,6 +39331,29 @@ cp_parser_omp_clause_depend_sink (cp_par
       return list;
     }
 
+  if (!depend_p)
+    {
+      tree id = cp_lexer_peek_token (parser->lexer)->u.value;
+      if (strcmp (IDENTIFIER_POINTER (id), "omp_cur_iteration") == 0
+	  && cp_lexer_nth_token_is (parser->lexer, 2, CPP_MINUS)
+	  && cp_lexer_nth_token_is (parser->lexer, 3, CPP_NUMBER)
+	  && cp_lexer_nth_token_is (parser->lexer, 4, CPP_CLOSE_PAREN))
+	{
+	  tree val = cp_lexer_peek_nth_token (parser->lexer, 3)->u.value;
+	  if (integer_onep (val)
+	      && same_type_p (TREE_TYPE (val), integer_type_node))
+	    {
+	      cp_lexer_consume_token (parser->lexer);
+	      cp_lexer_consume_token (parser->lexer);
+	      cp_lexer_consume_token (parser->lexer);
+	      tree u = build_omp_clause (clause_loc, OMP_CLAUSE_DOACROSS);
+	      OMP_CLAUSE_DOACROSS_KIND (u) = OMP_CLAUSE_DOACROSS_SINK;
+	      OMP_CLAUSE_CHAIN (u) = list;
+	      return u;
+	    }
+	}
+    }
+
   while (cp_lexer_next_token_is (parser->lexer, CPP_NAME))
     {
       location_t id_loc = cp_lexer_peek_token (parser->lexer)->location;
@@ -39372,7 +39401,7 @@ cp_parser_omp_clause_depend_sink (cp_par
 	{
 	  vec = tree_cons (addend, t, vec);
 	  if (neg)
-	    OMP_CLAUSE_DEPEND_SINK_NEGATIVE (vec) = 1;
+	    OMP_CLAUSE_DOACROSS_SINK_NEGATIVE (vec) = 1;
 	}
 
       if (cp_lexer_next_token_is_not (parser->lexer, CPP_COMMA)
@@ -39384,8 +39413,9 @@ cp_parser_omp_clause_depend_sink (cp_par
 
   if (vec)
     {
-      tree u = build_omp_clause (clause_loc, OMP_CLAUSE_DEPEND);
-      OMP_CLAUSE_DEPEND_KIND (u) = OMP_CLAUSE_DEPEND_SINK;
+      tree u = build_omp_clause (clause_loc, OMP_CLAUSE_DOACROSS);
+      OMP_CLAUSE_DOACROSS_KIND (u) = OMP_CLAUSE_DOACROSS_SINK;
+      OMP_CLAUSE_DOACROSS_DEPEND (u) = depend_p;
       OMP_CLAUSE_DECL (u) = nreverse (vec);
       OMP_CLAUSE_CHAIN (u) = list;
       return u;
@@ -39634,6 +39664,7 @@ cp_parser_omp_clause_depend (cp_parser *
 {
   tree nlist, c, iterators = NULL_TREE;
   enum omp_clause_depend_kind kind = OMP_CLAUSE_DEPEND_LAST;
+  enum omp_clause_doacross_kind dkind = OMP_CLAUSE_DOACROSS_LAST;
 
   matching_parens parens;
   if (!parens.require_open (parser))
@@ -39667,9 +39698,9 @@ cp_parser_omp_clause_depend (cp_parser *
       else if (strcmp ("depobj", p) == 0)
 	kind = OMP_CLAUSE_DEPEND_DEPOBJ;
       else if (strcmp ("sink", p) == 0)
-	kind = OMP_CLAUSE_DEPEND_SINK;
+	dkind = OMP_CLAUSE_DOACROSS_SINK;
       else if (strcmp ("source", p) == 0)
-	kind = OMP_CLAUSE_DEPEND_SOURCE;
+	dkind = OMP_CLAUSE_DOACROSS_SOURCE;
       else
 	goto invalid_kind;
       break;
@@ -39679,18 +39710,20 @@ cp_parser_omp_clause_depend (cp_parser *
   cp_lexer_consume_token (parser->lexer);
 
   if (iterators
-      && (kind == OMP_CLAUSE_DEPEND_SOURCE || kind == OMP_CLAUSE_DEPEND_SINK))
+      && (dkind == OMP_CLAUSE_DOACROSS_SOURCE
+	  || dkind == OMP_CLAUSE_DOACROSS_SINK))
     {
       poplevel (0, 1, 0);
       error_at (loc, "%<iterator%> modifier incompatible with %qs",
-		kind == OMP_CLAUSE_DEPEND_SOURCE ? "source" : "sink");
+		dkind == OMP_CLAUSE_DOACROSS_SOURCE ? "source" : "sink");
       iterators = NULL_TREE;
     }
 
-  if (kind == OMP_CLAUSE_DEPEND_SOURCE)
+  if (dkind == OMP_CLAUSE_DOACROSS_SOURCE)
     {
-      c = build_omp_clause (loc, OMP_CLAUSE_DEPEND);
-      OMP_CLAUSE_DEPEND_KIND (c) = kind;
+      c = build_omp_clause (loc, OMP_CLAUSE_DOACROSS);
+      OMP_CLAUSE_DOACROSS_KIND (c) = dkind;
+      OMP_CLAUSE_DOACROSS_DEPEND (c) = 1;
       OMP_CLAUSE_DECL (c) = NULL_TREE;
       OMP_CLAUSE_CHAIN (c) = list;
       if (!parens.require_close (parser))
@@ -39703,9 +39736,9 @@ cp_parser_omp_clause_depend (cp_parser *
   if (!cp_parser_require (parser, CPP_COLON, RT_COLON))
     goto resync_fail;
 
-  if (kind == OMP_CLAUSE_DEPEND_SINK)
+  if (dkind == OMP_CLAUSE_DOACROSS_SINK)
     {
-      nlist = cp_parser_omp_clause_depend_sink (parser, loc, list);
+      nlist = cp_parser_omp_clause_doacross_sink (parser, loc, list, true);
       if (!parens.require_close (parser))
 	cp_parser_skip_to_closing_parenthesis (parser, /*recovering=*/true,
 					       /*or_comma=*/false,
@@ -39746,6 +39779,73 @@ cp_parser_omp_clause_depend (cp_parser *
   return list;
 }
 
+/* OpenMP 5.2:
+   doacross ( source : )
+   doacross ( source : omp_cur_iteration )
+
+   doacross ( sink : vec )
+   doacross ( sink : omp_cur_iteration - logical_iteration )  */
+
+static tree
+cp_parser_omp_clause_doacross (cp_parser *parser, tree list, location_t loc)
+{
+  tree nlist;
+  enum omp_clause_doacross_kind kind = OMP_CLAUSE_DOACROSS_LAST;
+
+  matching_parens parens;
+  if (!parens.require_open (parser))
+    return list;
+
+  if (cp_lexer_next_token_is_not (parser->lexer, CPP_NAME))
+    {
+    invalid_kind:
+      cp_parser_error (parser, "invalid doacross kind");
+    resync_fail:
+      cp_parser_skip_to_closing_parenthesis (parser, /*recovering=*/true,
+					     /*or_comma=*/false,
+					     /*consume_paren=*/true);
+      return list;
+    }
+
+  tree id = cp_lexer_peek_token (parser->lexer)->u.value;
+  const char *p = IDENTIFIER_POINTER (id);
+
+  if (strcmp ("sink", p) == 0)
+    kind = OMP_CLAUSE_DOACROSS_SINK;
+  else if (strcmp ("source", p) == 0)
+    kind = OMP_CLAUSE_DOACROSS_SOURCE;
+  else
+    goto invalid_kind;
+
+  cp_lexer_consume_token (parser->lexer);
+
+  if (!cp_parser_require (parser, CPP_COLON, RT_COLON))
+    goto resync_fail;
+
+  if (kind == OMP_CLAUSE_DOACROSS_SOURCE)
+    {
+      if (cp_lexer_next_token_is (parser->lexer, CPP_NAME))
+	{
+	  id = cp_lexer_peek_token (parser->lexer)->u.value;
+	  p = IDENTIFIER_POINTER (id);
+	  if (strcmp (p, "omp_cur_iteration") == 0)
+	    cp_lexer_consume_token (parser->lexer);
+	}
+      nlist = build_omp_clause (loc, OMP_CLAUSE_DOACROSS);
+      OMP_CLAUSE_DOACROSS_KIND (nlist) = OMP_CLAUSE_DOACROSS_SOURCE;
+      OMP_CLAUSE_DECL (nlist) = NULL_TREE;
+      OMP_CLAUSE_CHAIN (nlist) = list;
+    }
+  else
+    nlist = cp_parser_omp_clause_doacross_sink (parser, loc, list, false);
+
+  if (!parens.require_close (parser))
+    cp_parser_skip_to_closing_parenthesis (parser, /*recovering=*/true,
+					   /*or_comma=*/false,
+					   /*consume_paren=*/true);
+  return nlist;
+}
+
 /* OpenMP 4.0:
    map ( map-kind : variable-list )
    map ( variable-list )
@@ -40688,6 +40788,11 @@ cp_parser_omp_all_clauses (cp_parser *pa
 						 token->location);
 	  c_name = "depend";
 	  break;
+	case PRAGMA_OMP_CLAUSE_DOACROSS:
+	  clauses = cp_parser_omp_clause_doacross (parser, clauses,
+						   token->location);
+	  c_name = "doacross";
+	  break;
 	case PRAGMA_OMP_CLAUSE_DETACH:
 	  clauses = cp_parser_omp_clause_detach (parser, clauses);
 	  c_name = "detach";
@@ -41926,7 +42031,7 @@ cp_parser_omp_depobj (cp_parser *parser,
 					   /*consume_paren=*/true);
 
   tree clause = NULL_TREE;
-  enum omp_clause_depend_kind kind = OMP_CLAUSE_DEPEND_SOURCE;
+  enum omp_clause_depend_kind kind = OMP_CLAUSE_DEPEND_INVALID;
   location_t c_loc = cp_lexer_peek_token (parser->lexer)->location;
   /* For now only in C++ attributes, do it always for OpenMP 5.1.  */
   if (parser->lexer->in_omp_attribute_pragma
@@ -41974,7 +42079,7 @@ cp_parser_omp_depobj (cp_parser *parser,
 		  else if (!strcmp ("inoutset", p2))
 		    kind = OMP_CLAUSE_DEPEND_INOUTSET;
 		}
-	      if (kind == OMP_CLAUSE_DEPEND_SOURCE)
+	      if (kind == OMP_CLAUSE_DEPEND_INVALID)
 		{
 		  clause = error_mark_node;
 		  error_at (c2_loc, "expected %<in%>, %<out%>, %<inout%>, "
@@ -41990,7 +42095,7 @@ cp_parser_omp_depobj (cp_parser *parser,
 	    clause = error_mark_node;
 	}
     }
-  if (!clause && kind == OMP_CLAUSE_DEPEND_SOURCE)
+  if (!clause && kind == OMP_CLAUSE_DEPEND_INVALID)
     {
       clause = error_mark_node;
       error_at (c_loc, "expected %<depend%>, %<destroy%> or %<update%> clause");
@@ -42822,19 +42927,6 @@ cp_parser_omp_for_loop (cp_parser *parse
 	= build_int_cst (NULL_TREE, collapse);
       ordered = collapse;
     }
-  if (ordered)
-    {
-      for (tree *pc = &clauses; *pc; )
-	if (OMP_CLAUSE_CODE (*pc) == OMP_CLAUSE_LINEAR)
-	  {
-	    error_at (OMP_CLAUSE_LOCATION (*pc),
-		      "%<linear%> clause may not be specified together "
-		      "with %<ordered%> clause with a parameter");
-	    *pc = OMP_CLAUSE_CHAIN (*pc);
-	  }
-	else
-	  pc = &OMP_CLAUSE_CHAIN (*pc);
-    }
 
   gcc_assert (tiling || (collapse >= 1 && ordered >= 0));
   count = ordered ? ordered : collapse;
@@ -43286,15 +43378,6 @@ cp_parser_omp_simd (cp_parser *parser, c
     {
       cp_omp_split_clauses (loc, OMP_SIMD, mask, clauses, cclauses);
       clauses = cclauses[C_OMP_CLAUSE_SPLIT_SIMD];
-      tree c = omp_find_clause (cclauses[C_OMP_CLAUSE_SPLIT_FOR],
-				OMP_CLAUSE_ORDERED);
-      if (c && OMP_CLAUSE_ORDERED_EXPR (c))
-	{
-	  error_at (OMP_CLAUSE_LOCATION (c),
-		    "%<ordered%> clause with parameter may not be specified "
-		    "on %qs construct", p_name);
-	  OMP_CLAUSE_ORDERED_EXPR (c) = NULL_TREE;
-	}
     }
 
   keep_next_level (true);
@@ -43556,7 +43639,8 @@ cp_parser_omp_masked (cp_parser *parser,
 	| (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_SIMD))
 
 #define OMP_ORDERED_DEPEND_CLAUSE_MASK				\
-	(OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEPEND)
+	( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEPEND)	\
+	| (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DOACROSS))
 
 static bool
 cp_parser_omp_ordered (cp_parser *parser, cp_token *pragma_tok,
@@ -43575,7 +43659,7 @@ cp_parser_omp_ordered (cp_parser *parser
       tree id = cp_lexer_peek_nth_token (parser->lexer, n)->u.value;
       const char *p = IDENTIFIER_POINTER (id);
 
-      if (strcmp (p, "depend") == 0)
+      if (strcmp (p, "depend") == 0 || strcmp (p, "doacross") == 0)
 	{
 	  if (!flag_openmp)	/* flag_openmp_simd */
 	    {
@@ -43585,8 +43669,8 @@ cp_parser_omp_ordered (cp_parser *parser
 	  if (context == pragma_stmt)
 	    {
 	      error_at (pragma_tok->location, "%<#pragma omp ordered%> with "
-			"%<depend%> clause may only be used in compound "
-			"statements");
+			"%qs clause may only be used in compound "
+			"statements", p);
 	      cp_parser_skip_to_pragma_eol (parser, pragma_tok);
 	      return true;
 	    }
--- gcc/cp/pt.cc.jj	2022-08-18 09:05:49.937120132 +0200
+++ gcc/cp/pt.cc	2022-09-01 18:35:47.558830758 +0200
@@ -17830,8 +17830,8 @@ tsubst_omp_clause_decl (tree decl, tree
     }
 
   /* Handle an OpenMP array section represented as a TREE_LIST (or
-     OMP_CLAUSE_DEPEND_KIND).  An OMP_CLAUSE_DEPEND (with a depend
-     kind of OMP_CLAUSE_DEPEND_SINK) can also be represented as a
+     OMP_CLAUSE_DOACROSS_KIND).  An OMP_CLAUSE_DOACROSS (with a depend
+     kind of OMP_CLAUSE_DOACROSS_SINK) can also be represented as a
      TREE_LIST.  We can handle it exactly the same as an array section
      (purpose, value, and a chain), even though the nomenclature
      (low_bound, length, etc) is different.  */
@@ -17849,8 +17849,8 @@ tsubst_omp_clause_decl (tree decl, tree
 	  && TREE_CHAIN (decl) == chain)
 	return decl;
       tree ret = tree_cons (low_bound, length, chain);
-      OMP_CLAUSE_DEPEND_SINK_NEGATIVE (ret)
-	= OMP_CLAUSE_DEPEND_SINK_NEGATIVE (decl);
+      OMP_CLAUSE_DOACROSS_SINK_NEGATIVE (ret)
+	= OMP_CLAUSE_DOACROSS_SINK_NEGATIVE (decl);
       return ret;
     }
   tree ret = tsubst_expr (decl, args, complain, in_decl,
@@ -17898,6 +17898,7 @@ tsubst_omp_clauses (tree clauses, enum c
 	case OMP_CLAUSE_COPYPRIVATE:
 	case OMP_CLAUSE_UNIFORM:
 	case OMP_CLAUSE_DEPEND:
+	case OMP_CLAUSE_DOACROSS:
 	case OMP_CLAUSE_AFFINITY:
 	case OMP_CLAUSE_FROM:
 	case OMP_CLAUSE_TO:
@@ -19414,7 +19415,7 @@ tsubst_expr (tree t, tree args, tsubst_f
       r = RECUR (OMP_DEPOBJ_DEPOBJ (t));
       if (OMP_DEPOBJ_CLAUSES (t) && OMP_DEPOBJ_CLAUSES (t) != error_mark_node)
 	{
-	  enum omp_clause_depend_kind kind = OMP_CLAUSE_DEPEND_SOURCE;
+	  enum omp_clause_depend_kind kind = OMP_CLAUSE_DEPEND_INVALID;
 	  if (TREE_CODE (OMP_DEPOBJ_CLAUSES (t)) == OMP_CLAUSE)
 	    {
 	      tmp = tsubst_omp_clauses (OMP_DEPOBJ_CLAUSES (t), C_ORT_OMP,
@@ -19432,7 +19433,7 @@ tsubst_expr (tree t, tree args, tsubst_f
 	}
       else
 	finish_omp_depobj (EXPR_LOCATION (t), r,
-			   OMP_CLAUSE_DEPEND_SOURCE,
+			   OMP_CLAUSE_DEPEND_INVALID,
 			   OMP_DEPOBJ_CLAUSES (t));
       break;
 
--- gcc/cp/semantics.cc.jj	2022-08-17 16:59:08.920548779 +0200
+++ gcc/cp/semantics.cc	2022-09-02 10:17:28.258285744 +0200
@@ -6477,13 +6477,13 @@ finish_omp_declare_simd_methods (tree t)
     }
 }
 
-/* Adjust sink depend clause to take into account pointer offsets.
+/* Adjust sink depend/doacross clause to take into account pointer offsets.
 
    Return TRUE if there was a problem processing the offset, and the
    whole clause should be removed.  */
 
 static bool
-cp_finish_omp_clause_depend_sink (tree sink_clause)
+cp_finish_omp_clause_doacross_sink (tree sink_clause)
 {
   tree t = OMP_CLAUSE_DECL (sink_clause);
   gcc_assert (TREE_CODE (t) == TREE_LIST);
@@ -7795,21 +7795,18 @@ finish_omp_clauses (tree clauses, enum c
 	    }
 	  goto handle_field_decl;
 
-	case OMP_CLAUSE_DEPEND:
+	case OMP_CLAUSE_DOACROSS:
 	  t = OMP_CLAUSE_DECL (c);
 	  if (t == NULL_TREE)
+	    break;
+	  if (OMP_CLAUSE_DOACROSS_KIND (c) == OMP_CLAUSE_DOACROSS_SINK)
 	    {
-	      gcc_assert (OMP_CLAUSE_DEPEND_KIND (c)
-			  == OMP_CLAUSE_DEPEND_SOURCE);
-	      break;
-	    }
-	  if (OMP_CLAUSE_DEPEND_KIND (c) == OMP_CLAUSE_DEPEND_SINK)
-	    {
-	      if (cp_finish_omp_clause_depend_sink (c))
+	      if (cp_finish_omp_clause_doacross_sink (c))
 		remove = true;
 	      break;
 	    }
-	  /* FALLTHRU */
+	  gcc_unreachable ();
+	case OMP_CLAUSE_DEPEND:
 	case OMP_CLAUSE_AFFINITY:
 	  t = OMP_CLAUSE_DECL (c);
 	  if (TREE_CODE (t) == TREE_LIST
--- gcc/fortran/trans-openmp.cc.jj	2022-07-26 10:32:23.799270266 +0200
+++ gcc/fortran/trans-openmp.cc	2022-09-01 16:28:06.688191566 +0200
@@ -2897,7 +2897,7 @@ gfc_trans_omp_clauses (stmtblock_t *bloc
 			    }
 			  vec = tree_cons (addend, t, vec);
 			  if (neg)
-			    OMP_CLAUSE_DEPEND_SINK_NEGATIVE (vec) = 1;
+			    OMP_CLAUSE_DOACROSS_SINK_NEGATIVE (vec) = 1;
 			}
 		      if (n->next == NULL
 			  || n->next->u.depend_op != OMP_DEPEND_SINK)
@@ -2908,8 +2908,9 @@ gfc_trans_omp_clauses (stmtblock_t *bloc
 		    continue;
 
 		  tree node = build_omp_clause (input_location,
-						OMP_CLAUSE_DEPEND);
-		  OMP_CLAUSE_DEPEND_KIND (node) = OMP_CLAUSE_DEPEND_SINK;
+						OMP_CLAUSE_DOACROSS);
+		  OMP_CLAUSE_DOACROSS_KIND (node) = OMP_CLAUSE_DOACROSS_SINK;
+		  OMP_CLAUSE_DOACROSS_DEPEND (node) = 1;
 		  OMP_CLAUSE_DECL (node) = nreverse (vec);
 		  omp_clauses = gfc_trans_add_clause (node, omp_clauses);
 		  continue;
@@ -4254,8 +4255,9 @@ gfc_trans_omp_clauses (stmtblock_t *bloc
 
   if (clauses->depend_source)
     {
-      c = build_omp_clause (gfc_get_location (&where), OMP_CLAUSE_DEPEND);
-      OMP_CLAUSE_DEPEND_KIND (c) = OMP_CLAUSE_DEPEND_SOURCE;
+      c = build_omp_clause (gfc_get_location (&where), OMP_CLAUSE_DOACROSS);
+      OMP_CLAUSE_DOACROSS_KIND (c) = OMP_CLAUSE_DOACROSS_SOURCE;
+      OMP_CLAUSE_DOACROSS_DEPEND (c) = 1;
       omp_clauses = gfc_trans_add_clause (c, omp_clauses);
     }
 
--- gcc/testsuite/c-c++-common/gomp/doacross-2.c.jj	2020-01-12 11:54:37.013404356 +0100
+++ gcc/testsuite/c-c++-common/gomp/doacross-2.c	2022-09-02 18:13:24.093620768 +0200
@@ -7,13 +7,13 @@ foo (void)
   #pragma omp for ordered(1)
   for (i = 0; i < 64; i++)
     {
-      #pragma omp ordered			/* { dg-error "'ordered' region without 'depend' clause may not be closely nested inside a loop region with an 'ordered' clause with a parameter" } */
+      #pragma omp ordered
       ;
     }
   #pragma omp for ordered(1)
   for (i = 0; i < 64; i++)
     {
-      #pragma omp ordered threads		/* { dg-error "'ordered' region without 'depend' clause may not be closely nested inside a loop region with an 'ordered' clause with a parameter" } */
+      #pragma omp ordered threads
       ;
     }
 }
@@ -25,14 +25,20 @@ bar (void)
   #pragma omp for ordered
   for (i = 0; i < 64; i++)
     {
-      #pragma omp ordered depend(source)	/* { dg-error "'ordered' construct with 'depend' clause must be closely nested inside a loop with 'ordered' clause with a parameter" } */
-      #pragma omp ordered depend(sink: i - 1)	/* { dg-error "'ordered' construct with 'depend' clause must be closely nested inside a loop with 'ordered' clause with a parameter" } */
+      #pragma omp ordered depend(source)
+      #pragma omp ordered depend(sink: i - 1)
+    }
+  #pragma omp for ordered
+  for (i = 0; i < 64; i++)
+    {
+      #pragma omp ordered doacross(source:)
+      #pragma omp ordered doacross(sink: i - 1)
     }
   #pragma omp for
   for (i = 0; i < 64; i++)
     {
-      #pragma omp ordered depend(source)	/* { dg-error "'ordered' construct with 'depend' clause must be closely nested inside a loop with 'ordered' clause with a parameter" } */
-      #pragma omp ordered depend(sink: i - 1)	/* { dg-error "'ordered' construct with 'depend' clause must be closely nested inside a loop with 'ordered' clause with a parameter" } */
+      #pragma omp ordered depend(source)	/* { dg-error "'ordered' construct with 'depend' clause must be closely nested inside a loop with 'ordered' clause" } */
+      #pragma omp ordered depend(sink: i - 1)	/* { dg-error "'ordered' construct with 'depend' clause must be closely nested inside a loop with 'ordered' clause" } */
     }
   #pragma omp for
   for (i = 0; i < 64; i++)
--- gcc/testsuite/c-c++-common/gomp/doacross-5.c.jj	2022-09-02 18:22:03.664570763 +0200
+++ gcc/testsuite/c-c++-common/gomp/doacross-5.c	2022-09-02 18:51:07.090930910 +0200
@@ -0,0 +1,94 @@
+void
+foo (int n)
+{
+  int i;
+  #pragma omp for ordered
+  for (i = 0; i < 8; i += n)
+    {
+      #pragma omp ordered doacross(source:)
+      #pragma omp ordered doacross(sink: i - 2)
+    }
+}
+
+void
+bar (int n)
+{
+  int i, j;
+  #pragma omp for collapse(2) ordered(2)
+  for (i = 0; i < 8; i += n)
+    for (j = 0; j < 8; j += n)
+      {
+	#pragma omp ordered doacross(source:omp_cur_iteration)
+	#pragma omp ordered doacross(sink: i - 2, j + 2)
+      }
+}
+
+void
+baz (void)
+{
+  int i, j;
+  #pragma omp for ordered(1)
+  for (i = 0; i < 64; i++)
+    {
+      #pragma omp ordered			/* { dg-error "'ordered' construct without 'doacross' or 'depend' clauses must not have the same binding region as 'ordered' construct with those clauses" } */
+      ;
+      #pragma omp ordered doacross(source:)
+      #pragma omp ordered doacross(sink: i - 1)
+    }
+  #pragma omp for ordered
+  for (i = 0; i < 64; i++)
+    {
+      #pragma omp ordered doacross(source: omp_cur_iteration )
+      #pragma omp ordered doacross(sink: i - 1)
+      #pragma omp ordered threads		/* { dg-error "'ordered' construct without 'doacross' or 'depend' clauses must not have the same binding region as 'ordered' construct with those clauses" } */
+      ;
+    }
+  #pragma omp for ordered(2)
+  for (i = 0; i < 8; i++)
+    for (j = 0; j < 8; j++)
+      {
+	#pragma omp ordered			/* { dg-error "'ordered' construct without 'doacross' or 'depend' clauses binds to loop where 'collapse' argument 1 is different from 'ordered' argument 2" } */
+	;
+      }
+  #pragma omp for ordered(2) collapse(1)
+  for (i = 0; i < 8; i++)
+    for (j = 0; j < 8; j++)
+      {
+	#pragma omp ordered threads		/* { dg-error "'ordered' construct without 'doacross' or 'depend' clauses binds to loop where 'collapse' argument 1 is different from 'ordered' argument 2" } */
+	;
+      }
+}
+
+void
+qux (void)
+{
+  int i, j = 0;
+  #pragma omp for ordered linear(j)
+  for (i = 0; i < 64; i++)
+    {
+      ++j;
+      #pragma omp ordered
+      ;
+    }
+  #pragma omp for ordered linear(j)		/* { dg-error "'linear' clause may not be specified together with 'ordered' clause if stand-alone 'ordered' construct is nested in it" } */
+  for (i = 0; i < 64; i++)
+    {
+      ++j;
+      #pragma omp ordered doacross(source:)
+      #pragma omp ordered doacross(sink:i-1)
+    }
+  #pragma omp for ordered(1) linear(j)
+  for (i = 0; i < 64; i++)
+    {
+      ++j;
+      #pragma omp ordered
+      ;
+    }
+  #pragma omp for ordered(1) linear(j)		/* { dg-error "'linear' clause may not be specified together with 'ordered' clause if stand-alone 'ordered' construct is nested in it" } */
+  for (i = 0; i < 64; i++)
+    {
+      ++j;
+      #pragma omp ordered doacross(source:)
+      #pragma omp ordered doacross(sink:i-1)
+    }
+}
--- gcc/testsuite/c-c++-common/gomp/doacross-6.c.jj	2022-09-02 18:38:41.584036829 +0200
+++ gcc/testsuite/c-c++-common/gomp/doacross-6.c	2022-09-02 19:04:38.568922196 +0200
@@ -0,0 +1,74 @@
+void
+foo (int n)
+{
+  int i;
+  #pragma omp for ordered
+  for (i = 0; i < 8; i += n)
+    {
+      #pragma omp ordered doacross(source)		/* { dg-error "expected ':' before '\\\)' token" } */
+    }
+  #pragma omp for ordered
+  for (i = 0; i < 8; i += n)
+    {
+      #pragma omp ordered doacross(source:omp_current_iteration)	/* { dg-error "expected '\\\)' before 'omp_current_iteration'" } */
+    }
+  #pragma omp for ordered
+  for (i = 0; i < 8; i += n)
+    {
+      #pragma omp ordered doacross(source:i - 2)	/* { dg-error "expected '\\\)' before 'i'" } */
+    }
+  #pragma omp for ordered
+  for (i = 0; i < 8; i += n)
+    {
+      #pragma omp ordered doacross(sink)		/* { dg-error "expected ':' before '\\\)' token" } */
+    }
+}
+
+void
+bar (int n)
+{
+  int i;
+  #pragma omp for ordered
+  for (i = 0; i < 8; i += n)
+    {
+      #pragma omp ordered doacross(sink:omp_current_iteration - 1)	/* { dg-error "'omp_current_iteration' undeclared \\\(first use in this function\\\)" "" { target c } } */
+    }									/* { dg-error "'omp_current_iteration' has not been declared" "" { target c++ } .-1 } */
+  #pragma omp for ordered
+  for (i = 0; i < 8; i += n)
+    {
+      #pragma omp ordered doacross(sink:omp_cur_iteration)	/* { dg-error "'omp_cur_iteration' undeclared \\\(first use in this function\\\)" "" { target c } } */
+    }								/* { dg-error "'omp_cur_iteration' has not been declared" "" { target c++ } .-1 } */
+}
+
+void
+baz (int n)
+{
+  int i;
+  #pragma omp for ordered
+  for (i = 0; i < 8; i += n)
+    {
+      #pragma omp ordered doacross(sink:omp_cur_iteration + 1)	/* { dg-error "'omp_cur_iteration' undeclared \\\(first use in this function\\\)" "" { target c } } */
+    }								/* { dg-error "'omp_cur_iteration' has not been declared" "" { target c++ } .-1 } */
+}
+
+void
+qux (int n)
+{
+  int i;
+  #pragma omp for ordered
+  for (i = 0; i < 8; i += n)
+    {
+      #pragma omp ordered doacross(sink:omp_cur_iteration - (2 - 1))	/* { dg-error "'omp_cur_iteration' undeclared \\\(first use in this function\\\)" "" { target c } } */
+    }								/* { dg-error "expected integer before '\\\(' token" "" { target *-*-* } .-1 } */
+}								/* { dg-error "'omp_cur_iteration' has not been declared" "" { target c++ } .-2 } */
+								/* { dg-error "expected '\\\)' before '\\\(' token" "" { target c++ } .-3 } */
+void
+corge (int n)
+{
+  int i;
+  #pragma omp for ordered
+  for (i = 0; i < 8; i += n)
+    {
+      #pragma omp ordered doacross(sink:omp_cur_iteration - 1LL)	/* { dg-error "'omp_cur_iteration' undeclared \\\(first use in this function\\\)" "" { target c } } */
+    }									/* { dg-error "'omp_cur_iteration' has not been declared" "" { target c++ } .-1 } */
+}
--- gcc/testsuite/c-c++-common/gomp/nesting-2.c.jj	2021-08-17 09:29:41.408204898 +0200
+++ gcc/testsuite/c-c++-common/gomp/nesting-2.c	2022-09-02 17:37:47.252606491 +0200
@@ -160,7 +160,14 @@ foo (void)
   for (i = 0; i < 64; i++)
     #pragma omp parallel
     {
-      #pragma omp ordered depend(source)	/* { dg-error ".ordered. construct with .depend. clause must be closely nested inside a loop with .ordered. clause with a parameter" } */
-      #pragma omp ordered depend(sink: i - 1)	/* { dg-error ".ordered. construct with .depend. clause must be closely nested inside a loop with .ordered. clause with a parameter" } */
+      #pragma omp ordered depend(source)	/* { dg-error ".ordered. construct with .depend. clause must be closely nested inside a loop with .ordered. clause" } */
+      #pragma omp ordered depend(sink: i - 1)	/* { dg-error ".ordered. construct with .depend. clause must be closely nested inside a loop with .ordered. clause" } */
+    }
+  #pragma omp for ordered(1)
+  for (i = 0; i < 64; i++)
+    #pragma omp parallel
+    {
+      #pragma omp ordered doacross(source:)	/* { dg-error ".ordered. construct with .doacross. clause must be closely nested inside a loop with .ordered. clause" } */
+      #pragma omp ordered doacross(sink: i - 1)	/* { dg-error ".ordered. construct with .doacross. clause must be closely nested inside a loop with .ordered. clause" } */
     }
 }
--- gcc/testsuite/c-c++-common/gomp/ordered-3.c.jj	2020-01-12 11:54:37.014404341 +0100
+++ gcc/testsuite/c-c++-common/gomp/ordered-3.c	2022-09-02 17:47:30.751700196 +0200
@@ -47,29 +47,53 @@ foo (void)
       #pragma omp ordered threads, simd, threads, simd	/* { dg-error "too many .threads. clauses" } */
       ;	/* { dg-error "too many .simd. clauses" "" { target *-*-* } .-1 } */
     }
-  #pragma omp for simd ordered(1)	/* { dg-error ".ordered. clause with parameter may not be specified on .#pragma omp for simd. construct" } */
+  #pragma omp for simd ordered(1)
   for (i = 0; i < 64; i++)
     {
-      #pragma omp ordered depend(sink: i - 1)	/* { dg-error "clause must be closely nested inside a loop with .ordered. clause with a parameter" } */
-      #pragma omp ordered depend(source)	/* { dg-error "clause must be closely nested inside a loop with .ordered. clause with a parameter" } */
+      #pragma omp ordered depend(sink: i - 1)	/* { dg-error "clause must be closely nested inside a loop with .ordered. clause" } */
+      #pragma omp ordered depend(source)	/* { dg-error "clause must be closely nested inside a loop with .ordered. clause" } */
     }
-  #pragma omp parallel for simd ordered(1)	/* { dg-error ".ordered. clause with parameter may not be specified on .#pragma omp parallel for simd. construct" } */
+  #pragma omp for simd ordered(1)
   for (i = 0; i < 64; i++)
     {
-      #pragma omp ordered depend(sink: i - 1)	/* { dg-error "clause must be closely nested inside a loop with .ordered. clause with a parameter" } */
-      #pragma omp ordered depend(source)	/* { dg-error "clause must be closely nested inside a loop with .ordered. clause with a parameter" } */
+      #pragma omp ordered doacross(sink: i - 1)	/* { dg-error "clause must be closely nested inside a loop with .ordered. clause" } */
+      #pragma omp ordered doacross(source:omp_cur_iteration)	/* { dg-error "clause must be closely nested inside a loop with .ordered. clause" } */
+    }
+  #pragma omp parallel for simd ordered(1)
+  for (i = 0; i < 64; i++)
+    {
+      #pragma omp ordered depend(sink: i - 1)	/* { dg-error "clause must be closely nested inside a loop with .ordered. clause" } */
+      #pragma omp ordered depend(source)	/* { dg-error "clause must be closely nested inside a loop with .ordered. clause" } */
+    }
+  #pragma omp parallel for simd ordered(1)
+  for (i = 0; i < 64; i++)
+    {
+      #pragma omp ordered doacross(sink: i - 1)	/* { dg-error "clause must be closely nested inside a loop with .ordered. clause" } */
+      #pragma omp ordered doacross(source:)	/* { dg-error "clause must be closely nested inside a loop with .ordered. clause" } */
+    }
+  #pragma omp parallel for ordered
+  for (i = 0; i < 64; i++)
+    {
+      #pragma omp ordered depend(sink: i - 1)
+      #pragma omp ordered depend(source)
     }
   #pragma omp parallel for ordered
   for (i = 0; i < 64; i++)
     {
-      #pragma omp ordered depend(sink: i - 1)	/* { dg-error "clause must be closely nested inside a loop with .ordered. clause with a parameter" } */
-      #pragma omp ordered depend(source)	/* { dg-error "clause must be closely nested inside a loop with .ordered. clause with a parameter" } */
+      #pragma omp ordered doacross(sink: i - 1)
+      #pragma omp ordered doacross(source:)
+    }
+  #pragma omp parallel for
+  for (i = 0; i < 64; i++)
+    {
+      #pragma omp ordered depend(sink: i - 1)	/* { dg-error "clause must be closely nested inside a loop with .ordered. clause" } */
+      #pragma omp ordered depend(source)	/* { dg-error "clause must be closely nested inside a loop with .ordered. clause" } */
     }
   #pragma omp parallel for
   for (i = 0; i < 64; i++)
     {
-      #pragma omp ordered depend(sink: i - 1)	/* { dg-error "clause must be closely nested inside a loop with .ordered. clause with a parameter" } */
-      #pragma omp ordered depend(source)	/* { dg-error "clause must be closely nested inside a loop with .ordered. clause with a parameter" } */
+      #pragma omp ordered doacross(sink: i - 1)	/* { dg-error "clause must be closely nested inside a loop with .ordered. clause" } */
+      #pragma omp ordered doacross(source:)	/* { dg-error "clause must be closely nested inside a loop with .ordered. clause" } */
     }
 }
 
--- gcc/testsuite/c-c++-common/gomp/sink-3.c.jj	2020-01-12 11:54:37.016404311 +0100
+++ gcc/testsuite/c-c++-common/gomp/sink-3.c	2022-09-02 18:09:01.480185433 +0200
@@ -14,7 +14,7 @@ foo ()
   for (i=0; i < 100; ++i)
     {
 #pragma omp ordered depend(sink:poo-1,paa+1) /* { dg-error "poo.*declared.*paa.*declared" } */
-    bar(&i);				     /* { dg-error "may not be closely nested" "" { target *-*-* } .-1 } */
+    bar(&i);				     /* { dg-error "must not have the same binding region" "" { target *-*-* } .-1 } */
 #pragma omp ordered depend(source)
     }
 }
--- gcc/testsuite/gfortran.dg/gomp/nesting-2.f90.jj	2021-08-17 16:34:31.610102996 +0200
+++ gcc/testsuite/gfortran.dg/gomp/nesting-2.f90	2022-09-02 18:15:10.209180367 +0200
@@ -158,8 +158,8 @@ subroutine foo
   !$omp do ordered(1)
   do i = 0, 63
     !$omp parallel
-      !$omp ordered depend(source)	! { dg-error ".ordered. construct with .depend. clause must be closely nested inside a loop with .ordered. clause with a parameter" }
-      !$omp ordered depend(sink: i - 1)	! { dg-error ".ordered. construct with .depend. clause must be closely nested inside a loop with .ordered. clause with a parameter" }
+      !$omp ordered depend(source)	! { dg-error ".ordered. construct with .depend. clause must be closely nested inside a loop with .ordered. clause" }
+      !$omp ordered depend(sink: i - 1)	! { dg-error ".ordered. construct with .depend. clause must be closely nested inside a loop with .ordered. clause" }
     !$omp end parallel
   end do
 end

	Jakub


^ permalink raw reply	[flat|nested] 4+ messages in thread

* [PATCH] openmp: Introduce gimple_omp_ordered_standalone_p
  2022-09-03  8:07 [committed] openmp: Partial OpenMP 5.2 doacross and omp_cur_iteration support Jakub Jelinek
@ 2022-09-05 12:28 ` Jakub Jelinek
  2022-09-05 13:01 ` [committed] openmp: Partial OpenMP 5.2 doacross and omp_cur_iteration support Tobias Burnus
  1 sibling, 0 replies; 4+ messages in thread
From: Jakub Jelinek @ 2022-09-05 12:28 UTC (permalink / raw)
  To: gcc-patches, Tobias Burnus

Hi!

On Sat, Sep 03, 2022 at 10:07:27AM +0200, Jakub Jelinek via Gcc-patches wrote:
> Incrementally, I'd like to change the way we differentiate between
> stand-alone and block-associated ordered constructs, because the current
> way of looking for presence of doacross clause doesn't work well if those
> clauses are removed because they had been invalid (wrong syntax or
> unknown variables in it etc.)

The following, so far only lightly tested, patch implements that.

Will commit if it passes full bootstrap/regtest on x86_64-linux and
i686-linux overnight.

2022-09-05  Jakub Jelinek  <jakub@redhat.com>

gcc/
	* gimple.h (enum gf_mask): Add GF_OMP_ORDERED_STANDALONE enumerator.
	(gimple_omp_subcode):  Use GIMPLE_OMP_ORDERED instead of
	GIMPLE_OMP_TEAMS as upper bound.
	(gimple_omp_ordered_standalone_p, gimple_omp_ordered_standalone): New
	inline functions.
	* gimplify.cc (find_standalone_omp_ordered): Look for OMP_ORDERED with
	NULL OMP_ORDERED_BODY rather than with OMP_DOACROSS clause.
	(gimplify_expr): Call gimple_omp_ordered_standalone for OMP_ORDERED
	with NULL OMP_ORDERED_BODY.
	* omp-low.cc (check_omp_nesting_restrictions): Use
	gimple_omp_ordered_standalone_p test instead of
	omp_find_clause (..., OMP_CLAUSE_DOACROSS).
	(lower_omp_ordered): Likewise.
	* omp-expand.cc (expand_omp, build_omp_regions_1,
	omp_make_gimple_edges): Likewise.
gcc/cp/
	* pt.cc (tsubst_expr) <case OMP_ORDERED>: If OMP_BODY was NULL, keep
	it NULL after instantiation too.
gcc/testsuite/
	* c-c++-common/gomp/sink-3.c: Don't expect a superfluous error during
	error recovery.
	* c-c++-common/gomp/doacross-6.c (foo): Add further tests.

--- gcc/gimple.h.jj	2022-06-27 11:18:02.682058403 +0200
+++ gcc/gimple.h	2022-09-05 13:47:21.009761168 +0200
@@ -194,6 +194,7 @@ enum gf_mask {
     GF_OMP_RETURN_NOWAIT	= 1 << 0,
 
     GF_OMP_SECTION_LAST		= 1 << 0,
+    GF_OMP_ORDERED_STANDALONE   = 1 << 0,
     GF_OMP_ATOMIC_MEMORY_ORDER  = (1 << 6) - 1,
     GF_OMP_ATOMIC_NEED_VALUE	= 1 << 6,
     GF_OMP_ATOMIC_WEAK		= 1 << 7,
@@ -2312,7 +2313,7 @@ static inline unsigned
 gimple_omp_subcode (const gimple *s)
 {
   gcc_gimple_checking_assert (gimple_code (s) >= GIMPLE_OMP_ATOMIC_LOAD
-			      && gimple_code (s) <= GIMPLE_OMP_TEAMS);
+			      && gimple_code (s) <= GIMPLE_OMP_ORDERED);
   return s->subcode;
 }
 
@@ -2402,6 +2403,27 @@ gimple_omp_section_set_last (gimple *g)
 }
 
 
+/* Return true if OMP ordered construct is stand-alone
+   (G has the GF_OMP_ORDERED_STANDALONE flag set).  */
+
+static inline bool
+gimple_omp_ordered_standalone_p (const gimple *g)
+{
+  GIMPLE_CHECK (g, GIMPLE_OMP_ORDERED);
+  return (gimple_omp_subcode (g) & GF_OMP_ORDERED_STANDALONE) != 0;
+}
+
+
+/* Set the GF_OMP_ORDERED_STANDALONE flag on G.  */
+
+static inline void
+gimple_omp_ordered_standalone (gimple *g)
+{
+  GIMPLE_CHECK (g, GIMPLE_OMP_ORDERED);
+  g->subcode |= GF_OMP_ORDERED_STANDALONE;
+}
+
+
 /* Return true if OMP parallel statement G has the
    GF_OMP_PARALLEL_COMBINED flag set.  */
 
--- gcc/gimplify.cc.jj	2022-09-03 09:41:34.823006434 +0200
+++ gcc/gimplify.cc	2022-09-05 13:37:00.158143869 +0200
@@ -12427,7 +12427,7 @@ gimplify_omp_taskloop_expr (tree type, t
 }
 
 /* Helper function of gimplify_omp_for, find OMP_ORDERED with
-   OMP_CLAUSE_DOACROSS clause inside of OMP_FOR's body.  */
+   null OMP_ORDERED_BODY inside of OMP_FOR's body.  */
 
 static tree
 find_standalone_omp_ordered (tree *tp, int *walk_subtrees, void *)
@@ -12435,7 +12435,7 @@ find_standalone_omp_ordered (tree *tp, i
   switch (TREE_CODE (*tp))
     {
     case OMP_ORDERED:
-      if (omp_find_clause (OMP_ORDERED_CLAUSES (*tp), OMP_CLAUSE_DOACROSS))
+      if (OMP_ORDERED_BODY (*tp) == NULL_TREE)
 	return *tp;
       break;
     case OMP_SIMD:
@@ -15839,6 +15839,9 @@ gimplify_expr (tree *expr_p, gimple_seq
 		break;
 	      case OMP_ORDERED:
 		g = gimplify_omp_ordered (*expr_p, body);
+		if (OMP_BODY (*expr_p) == NULL_TREE
+		    && gimple_code (g) == GIMPLE_OMP_ORDERED)
+		  gimple_omp_ordered_standalone (g);
 		break;
 	      case OMP_MASKED:
 		gimplify_scan_omp_clauses (&OMP_MASKED_CLAUSES (*expr_p),
--- gcc/omp-low.cc.jj	2022-09-03 09:41:34.827006378 +0200
+++ gcc/omp-low.cc	2022-09-05 13:24:30.796236971 +0200
@@ -3718,7 +3718,7 @@ check_omp_nesting_restrictions (gimple *
 			  "a loop region with an %<ordered%> clause");
 		return false;
 	      }
-	    if (omp_find_clause (c, OMP_CLAUSE_DOACROSS) == NULL_TREE)
+	    if (!gimple_omp_ordered_standalone_p (stmt))
 	      {
 		if (OMP_CLAUSE_ORDERED_DOACROSS (o))
 		  {
@@ -9989,8 +9989,7 @@ lower_omp_ordered (gimple_stmt_iterator
   bool threads = omp_find_clause (gimple_omp_ordered_clauses (ord_stmt),
 				  OMP_CLAUSE_THREADS);
 
-  if (omp_find_clause (gimple_omp_ordered_clauses (ord_stmt),
-		       OMP_CLAUSE_DOACROSS))
+  if (gimple_omp_ordered_standalone_p (ord_stmt))
     {
       /* FIXME: This is needs to be moved to the expansion to verify various
 	 conditions only testable on cfg with dominators computed, and also
--- gcc/omp-expand.cc.jj	2022-09-03 09:41:34.829006350 +0200
+++ gcc/omp-expand.cc	2022-09-05 13:25:39.328317824 +0200
@@ -10487,8 +10487,7 @@ expand_omp (struct omp_region *region)
 	  {
 	    gomp_ordered *ord_stmt
 	      = as_a <gomp_ordered *> (last_stmt (region->entry));
-	    if (omp_find_clause (gimple_omp_ordered_clauses (ord_stmt),
-				 OMP_CLAUSE_DOACROSS))
+	    if (gimple_omp_ordered_standalone_p (ord_stmt))
 	      {
 		/* We'll expand these when expanding corresponding
 		   worksharing region with ordered(n) clause.  */
@@ -10616,9 +10615,7 @@ build_omp_regions_1 (basic_block bb, str
 		}
 	    }
 	  else if (code == GIMPLE_OMP_ORDERED
-		   && omp_find_clause (gimple_omp_ordered_clauses
-					 (as_a <gomp_ordered *> (stmt)),
-				       OMP_CLAUSE_DOACROSS))
+		   && gimple_omp_ordered_standalone_p (stmt))
 	    /* #pragma omp ordered depend is also just a stand-alone
 	       directive.  */
 	    region = NULL;
@@ -10842,9 +10839,7 @@ omp_make_gimple_edges (basic_block bb, s
     case GIMPLE_OMP_ORDERED:
       cur_region = new_omp_region (bb, code, cur_region);
       fallthru = true;
-      if (omp_find_clause (gimple_omp_ordered_clauses
-			     (as_a <gomp_ordered *> (last)),
-			   OMP_CLAUSE_DOACROSS))
+      if (gimple_omp_ordered_standalone_p (last))
 	cur_region = cur_region->outer;
       break;
 
--- gcc/cp/pt.cc.jj	2022-09-03 09:41:34.866005829 +0200
+++ gcc/cp/pt.cc	2022-09-05 14:16:25.584362892 +0200
@@ -19526,9 +19526,14 @@ tsubst_expr (tree t, tree args, tsubst_f
     case OMP_ORDERED:
       tmp = tsubst_omp_clauses (OMP_ORDERED_CLAUSES (t), C_ORT_OMP, args,
 				complain, in_decl);
-      stmt = push_stmt_list ();
-      RECUR (OMP_BODY (t));
-      stmt = pop_stmt_list (stmt);
+      if (OMP_BODY (t))
+	{
+	  stmt = push_stmt_list ();
+	  RECUR (OMP_BODY (t));
+	  stmt = pop_stmt_list (stmt);
+	}
+      else
+	stmt = NULL_TREE;
 
       t = copy_node (t);
       OMP_BODY (t) = stmt;
--- gcc/testsuite/c-c++-common/gomp/sink-3.c.jj	2022-09-03 09:41:34.928004956 +0200
+++ gcc/testsuite/c-c++-common/gomp/sink-3.c	2022-09-05 14:07:04.580887813 +0200
@@ -14,7 +14,7 @@ foo ()
   for (i=0; i < 100; ++i)
     {
 #pragma omp ordered depend(sink:poo-1,paa+1) /* { dg-error "poo.*declared.*paa.*declared" } */
-    bar(&i);				     /* { dg-error "must not have the same binding region" "" { target *-*-* } .-1 } */
+    bar(&i);
 #pragma omp ordered depend(source)
     }
 }
--- gcc/testsuite/c-c++-common/gomp/doacross-6.c.jj	2022-09-03 09:41:34.914005153 +0200
+++ gcc/testsuite/c-c++-common/gomp/doacross-6.c	2022-09-05 13:34:20.545312759 +0200
@@ -22,6 +22,18 @@ foo (int n)
     {
       #pragma omp ordered doacross(sink)		/* { dg-error "expected ':' before '\\\)' token" } */
     }
+  #pragma omp for ordered
+  for (i = 0; i < 8; i += n)
+    {
+      #pragma omp ordered doacross(source)		/* { dg-error "expected ':' before '\\\)' token" } */
+      #pragma omp ordered doacross(sink:i-1)
+    }
+  #pragma omp for ordered
+  for (i = 0; i < 8; i += n)
+    {
+      #pragma omp ordered doacross(source:)
+      #pragma omp ordered doacross(sink)		/* { dg-error "expected ':' before '\\\)' token" } */
+    }
 }
 
 void


	Jakub


^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [committed] openmp: Partial OpenMP 5.2 doacross and omp_cur_iteration support
  2022-09-03  8:07 [committed] openmp: Partial OpenMP 5.2 doacross and omp_cur_iteration support Jakub Jelinek
  2022-09-05 12:28 ` [PATCH] openmp: Introduce gimple_omp_ordered_standalone_p Jakub Jelinek
@ 2022-09-05 13:01 ` Tobias Burnus
  2022-09-05 16:00   ` Jakub Jelinek
  1 sibling, 1 reply; 4+ messages in thread
From: Tobias Burnus @ 2022-09-05 13:01 UTC (permalink / raw)
  To: Jakub Jelinek, gcc-patches; +Cc: Tobias Burnus

[-- Attachment #1: Type: text/plain, Size: 470 bytes --]

On 03.09.22 10:07, Jakub Jelinek wrote:
> The following patch implements part of the OpenMP 5.2 changes related
> to ordered loops ...

Fortran bits to it attached.

OK for mainline?

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

[-- Attachment #2: doacross-f90.diff --]
[-- Type: text/x-patch, Size: 34052 bytes --]

Fortran/openmp: Partial OpenMP 5.2 doacross and omp_cur_iteration support

Add the Fortran support to the ME/C/C++ commit
r13-2388-ga651e6d59188da8992f8bfae2df1cb4e6316f9e6

gcc/fortran/ChangeLog:

	* dump-parse-tree.cc (show_omp_namelist, show_omp_clauses): Handle
	omp_cur_iteration and distinguish doacross/depend:
	* gfortran.h (enum gfc_omp_depend_doacross_op): Renamed from
	gfc_omp_depend_op.
	(enum gfc_omp_depend_doacross_op): Add OMP_DOACROSS_SINK_FIRST,
	Rename OMP_DEPEND_SINK to OMP_DOACROSS_SINK.
	(gfc_omp_namelist) Handle renaming, rename depend_op to
	depend_doacross_op.
	(struct gfc_omp_clauses): Add doacross_source.
	* openmp.cc (gfc_match_omp_depend_sink): Renamed to ...
	(gfc_match_omp_doacross_sink): ... this; handle omp_all_memory.
	(enum omp_mask2): Add OMP_CLAUSE_DOACROSS.
	(gfc_match_omp_clauses): Handle 'doacross' and syntax changes to
	depend.
	(gfc_match_omp_depobj): Simplify as sink/source are now impossible.
	(gfc_match_omp_ordered_depend): Request OMP_CLAUSE_DOACROSS.
	(resolve_omp_clauses): Update sink/source checks.
	(gfc_resolve_omp_directive): Resolve EXEC_OMP_ORDERED clauses.
	* parse.cc (decode_omp_directive): Handle 'ordered doacross'.
	* trans-openmp.cc (gfc_trans_omp_clauses): Handle doacross.
	(gfc_trans_omp_do): Fix OMP_FOR_ORIG_DECLS handling if 'ordered'
	clause is present.
	(gfc_trans_omp_depobj): Update for member name change.

libgomp/ChangeLog:

	* libgomp.texi (OpenMP 5.2): Update doacross/omp_cur_iteration status.

gcc/testsuite/ChangeLog:

	* gfortran.dg/gomp/all-memory-1.f90: Update dg-error.
	* gfortran.dg/gomp/depend-iterator-2.f90: Likewise.
	* gfortran.dg/gomp/depobj-2.f90: Likewise.
	* gfortran.dg/gomp/doacross-5.f90: New test.
	* gfortran.dg/gomp/doacross-6.f90: New test.

 gcc/fortran/dump-parse-tree.cc                     |  38 +++-
 gcc/fortran/gfortran.h                             |  13 +-
 gcc/fortran/openmp.cc                              | 218 +++++++++++++--------
 gcc/fortran/parse.cc                               |   3 +-
 gcc/fortran/trans-openmp.cc                        |  35 ++--
 gcc/testsuite/gfortran.dg/gomp/all-memory-1.f90    |   2 +-
 .../gfortran.dg/gomp/depend-iterator-2.f90         |   2 +-
 gcc/testsuite/gfortran.dg/gomp/depobj-2.f90        |   6 +-
 gcc/testsuite/gfortran.dg/gomp/doacross-5.f90      |  88 +++++++++
 gcc/testsuite/gfortran.dg/gomp/doacross-6.f90      |  77 ++++++++
 libgomp/libgomp.texi                               |   5 +-
 11 files changed, 370 insertions(+), 117 deletions(-)

diff --git a/gcc/fortran/dump-parse-tree.cc b/gcc/fortran/dump-parse-tree.cc
index 5352008a63d..40c690c9ae8 100644
--- a/gcc/fortran/dump-parse-tree.cc
+++ b/gcc/fortran/dump-parse-tree.cc
@@ -1337,8 +1337,15 @@ show_omp_namelist (int list_type, gfc_omp_namelist *n)
 	  if (n->u2.ns != ns_iter)
 	    {
 	      if (n != n2)
-		fputs (list_type == OMP_LIST_AFFINITY
-		       ? ") AFFINITY(" : ") DEPEND(", dumpfile);
+		{
+		  fputs (") ", dumpfile);
+		  if (list_type == OMP_LIST_AFFINITY)
+		    fputs ("AFFINITY (", dumpfile);
+		  else if (n->u.depend_doacross_op == OMP_DOACROSS_SINK_FIRST)
+		    fputs ("DOACROSS (", dumpfile);
+		  else
+		    fputs ("DEPEND (", dumpfile);
+		}
 	      if (n->u2.ns)
 		{
 		  fputs ("ITERATOR(", dumpfile);
@@ -1374,7 +1381,7 @@ show_omp_namelist (int list_type, gfc_omp_namelist *n)
 	  default: break;
 	  }
       else if (list_type == OMP_LIST_DEPEND)
-	switch (n->u.depend_op)
+	switch (n->u.depend_doacross_op)
 	  {
 	  case OMP_DEPEND_IN: fputs ("in:", dumpfile); break;
 	  case OMP_DEPEND_OUT: fputs ("out:", dumpfile); break;
@@ -1385,10 +1392,14 @@ show_omp_namelist (int list_type, gfc_omp_namelist *n)
 	    fputs ("mutexinoutset:", dumpfile);
 	    break;
 	  case OMP_DEPEND_SINK_FIRST:
+	  case OMP_DOACROSS_SINK_FIRST:
 	    fputs ("sink:", dumpfile);
 	    while (1)
 	      {
-		fprintf (dumpfile, "%s", n->sym->name);
+		if (!n->sym)
+		  fputs ("omp_cur_iteration", dumpfile);
+		else
+		  fprintf (dumpfile, "%s", n->sym->name);
 		if (n->expr)
 		  {
 		    fputc ('+', dumpfile);
@@ -1396,9 +1407,13 @@ show_omp_namelist (int list_type, gfc_omp_namelist *n)
 		  }
 		if (n->next == NULL)
 		  break;
-		else if (n->next->u.depend_op != OMP_DEPEND_SINK)
+		else if (n->next->u.depend_doacross_op != OMP_DOACROSS_SINK)
 		  {
-		    fputs (") DEPEND(", dumpfile);
+		    if (n->next->u.depend_doacross_op
+			== OMP_DOACROSS_SINK_FIRST)
+		      fputs (") DOACROSS(", dumpfile);
+		    else
+		      fputs (") DEPEND(", dumpfile);
 		    break;
 		  }
 		fputc (',', dumpfile);
@@ -1674,7 +1689,14 @@ show_omp_clauses (gfc_omp_clauses *omp_clauses)
 	  case OMP_LIST_AFFINITY: type = "AFFINITY"; break;
 	  case OMP_LIST_ALIGNED: type = "ALIGNED"; break;
 	  case OMP_LIST_LINEAR: type = "LINEAR"; break;
-	  case OMP_LIST_DEPEND: type = "DEPEND"; break;
+	  case OMP_LIST_DEPEND:
+	    if (omp_clauses->lists[list_type]
+		&& (omp_clauses->lists[list_type]->u.depend_doacross_op
+		    == OMP_DOACROSS_SINK_FIRST))
+	      type = "DOACROSS";
+	    else
+	      type = "DEPEND";
+	    break;
 	  case OMP_LIST_MAP: type = "MAP"; break;
 	  case OMP_LIST_TO: type = "TO"; break;
 	  case OMP_LIST_FROM: type = "FROM"; break;
@@ -1894,6 +1916,8 @@ show_omp_clauses (gfc_omp_clauses *omp_clauses)
     fputs (" DESTROY", dumpfile);
   if (omp_clauses->depend_source)
     fputs (" DEPEND(source)", dumpfile);
+  if (omp_clauses->doacross_source)
+    fputs (" DOACROSS(source:)", dumpfile);
   if (omp_clauses->capture)
     fputs (" CAPTURE", dumpfile);
   if (omp_clauses->depobj_update != OMP_DEPEND_UNSET)
diff --git a/gcc/fortran/gfortran.h b/gcc/fortran/gfortran.h
index 696aadd7db6..4babd77924b 100644
--- a/gcc/fortran/gfortran.h
+++ b/gcc/fortran/gfortran.h
@@ -1265,7 +1265,7 @@ enum gfc_omp_reduction_op
   OMP_REDUCTION_USER
 };
 
-enum gfc_omp_depend_op
+enum gfc_omp_depend_doacross_op
 {
   OMP_DEPEND_UNSET,
   OMP_DEPEND_IN,
@@ -1275,7 +1275,8 @@ enum gfc_omp_depend_op
   OMP_DEPEND_MUTEXINOUTSET,
   OMP_DEPEND_DEPOBJ,
   OMP_DEPEND_SINK_FIRST,
-  OMP_DEPEND_SINK
+  OMP_DOACROSS_SINK_FIRST,
+  OMP_DOACROSS_SINK
 };
 
 enum gfc_omp_map_op
@@ -1343,7 +1344,7 @@ typedef struct gfc_omp_namelist
   union
     {
       gfc_omp_reduction_op reduction_op;
-      gfc_omp_depend_op depend_op;
+      gfc_omp_depend_doacross_op depend_doacross_op;
       gfc_omp_map_op map_op;
       struct
 	{
@@ -1536,17 +1537,17 @@ typedef struct gfc_omp_clauses
   unsigned nowait:1, ordered:1, untied:1, mergeable:1, ancestor:1;
   unsigned inbranch:1, notinbranch:1, nogroup:1;
   unsigned sched_simd:1, sched_monotonic:1, sched_nonmonotonic:1;
-  unsigned simd:1, threads:1, depend_source:1, destroy:1, order_concurrent:1;
+  unsigned simd:1, threads:1, doacross_source:1, depend_source:1, destroy:1;
   unsigned order_unconstrained:1, order_reproducible:1, capture:1;
   unsigned grainsize_strict:1, num_tasks_strict:1, compare:1, weak:1;
-  unsigned non_rectangular:1;
+  unsigned non_rectangular:1, order_concurrent:1;
   ENUM_BITFIELD (gfc_omp_sched_kind) sched_kind:3;
   ENUM_BITFIELD (gfc_omp_device_type) device_type:2;
   ENUM_BITFIELD (gfc_omp_memorder) memorder:3;
   ENUM_BITFIELD (gfc_omp_memorder) fail:3;
   ENUM_BITFIELD (gfc_omp_cancel_kind) cancel:3;
   ENUM_BITFIELD (gfc_omp_proc_bind_kind) proc_bind:3;
-  ENUM_BITFIELD (gfc_omp_depend_op) depobj_update:4;
+  ENUM_BITFIELD (gfc_omp_depend_doacross_op) depobj_update:4;
   ENUM_BITFIELD (gfc_omp_bind_type) bind:2;
   ENUM_BITFIELD (gfc_omp_at_type) at:2;
   ENUM_BITFIELD (gfc_omp_severity_type) severity:2;
diff --git a/gcc/fortran/openmp.cc b/gcc/fortran/openmp.cc
index 594907714ff..5142fd7c608 100644
--- a/gcc/fortran/openmp.cc
+++ b/gcc/fortran/openmp.cc
@@ -575,11 +575,13 @@ syntax_error:
 
 }
 
-/* Match depend(sink : ...) construct a namelist from it.  */
+/* Match doacross(sink : ...) construct a namelist from it;
+   if depend is true, match legacy 'depend(sink : ...)'.  */
 
 static match
-gfc_match_omp_depend_sink (gfc_omp_namelist **list)
+gfc_match_omp_doacross_sink (gfc_omp_namelist **list, bool depend)
 {
+  char n[GFC_MAX_SYMBOL_LEN+1];
   gfc_omp_namelist *head, *tail, *p;
   locus old_loc, cur_loc;
   gfc_symbol *sym;
@@ -591,49 +593,51 @@ gfc_match_omp_depend_sink (gfc_omp_namelist **list)
   for (;;)
     {
       cur_loc = gfc_current_locus;
-      switch (gfc_match_symbol (&sym, 1))
+
+      if (gfc_match_name (n) != MATCH_YES)
+	goto syntax;
+      if (UNLIKELY (strcmp (n, "omp_all_memory") == 0))
 	{
-	case MATCH_YES:
-	  gfc_set_sym_referenced (sym);
-	  p = gfc_get_omp_namelist ();
-	  if (head == NULL)
-	    {
-	      head = tail = p;
-	      head->u.depend_op = OMP_DEPEND_SINK_FIRST;
-	    }
-	  else
-	    {
-	      tail->next = p;
-	      tail = tail->next;
-	      tail->u.depend_op = OMP_DEPEND_SINK;
-	    }
-	  tail->sym = sym;
-	  tail->expr = NULL;
-	  tail->where = cur_loc;
-	  if (UNLIKELY (strcmp (sym->name, "omp_all_memory") == 0))
-	    {
-	      gfc_error ("%<omp_all_memory%> used with DEPEND kind "
-			 "other than OUT or INOUT at %C");
-	      goto cleanup;
-	    }
-	  if (gfc_match_char ('+') == MATCH_YES)
-	    {
-	      if (gfc_match_literal_constant (&tail->expr, 0) != MATCH_YES)
-		goto syntax;
-	    }
-	  else if (gfc_match_char ('-') == MATCH_YES)
-	    {
-	      if (gfc_match_literal_constant (&tail->expr, 0) != MATCH_YES)
-		goto syntax;
-	      tail->expr = gfc_uminus (tail->expr);
-	    }
-	  break;
-	case MATCH_NO:
-	  goto syntax;
-	case MATCH_ERROR:
+	  gfc_error ("%<omp_all_memory%> used with dependence-type "
+		     "other than OUT or INOUT at %C");
 	  goto cleanup;
 	}
-
+      sym = NULL;
+      if (!(strcmp (n, "omp_cur_iteration") == 0))
+	{
+	  gfc_symtree *st;
+	  if (gfc_get_ha_sym_tree (n, &st))
+	    goto syntax;
+	  sym = st->n.sym;
+	  gfc_set_sym_referenced (sym);
+	}
+      p = gfc_get_omp_namelist ();
+      if (head == NULL)
+	{
+	  head = tail = p;
+	  head->u.depend_doacross_op = (depend ? OMP_DEPEND_SINK_FIRST
+					       : OMP_DOACROSS_SINK_FIRST);
+	}
+      else
+	{
+	  tail->next = p;
+	  tail = tail->next;
+	  tail->u.depend_doacross_op = OMP_DOACROSS_SINK;
+	}
+      tail->sym = sym;
+      tail->expr = NULL;
+      tail->where = cur_loc;
+      if (gfc_match_char ('+') == MATCH_YES)
+	{
+	  if (gfc_match_literal_constant (&tail->expr, 0) != MATCH_YES)
+	    goto syntax;
+	}
+      else if (gfc_match_char ('-') == MATCH_YES)
+	{
+	  if (gfc_match_literal_constant (&tail->expr, 0) != MATCH_YES)
+	    goto syntax;
+	  tail->expr = gfc_uminus (tail->expr);
+	}
       if (gfc_match_char (')') == MATCH_YES)
 	break;
       if (gfc_match_char (',') != MATCH_YES)
@@ -647,7 +651,7 @@ gfc_match_omp_depend_sink (gfc_omp_namelist **list)
   return MATCH_YES;
 
 syntax:
-  gfc_error ("Syntax error in OpenMP DEPEND SINK list at %C");
+  gfc_error ("Syntax error in OpenMP SINK dependence-type list at %C");
 
 cleanup:
   gfc_free_omp_namelist (head, false);
@@ -987,6 +991,7 @@ enum omp_mask2
   OMP_CLAUSE_NOHOST,
   OMP_CLAUSE_HAS_DEVICE_ADDR,  /* OpenMP 5.1  */
   OMP_CLAUSE_ENTER, /* OpenMP 5.2 */
+  OMP_CLAUSE_DOACROSS, /* OpenMP 5.2 */
   /* This must come last.  */
   OMP_MASK2_LAST
 };
@@ -1903,18 +1908,26 @@ gfc_match_omp_clauses (gfc_omp_clauses **cp, const omp_mask mask,
 					   OMP_MAP_RELEASE, true,
 					   allow_derived))
 	    continue;
-	  if ((mask & OMP_CLAUSE_DEPEND)
-	      && gfc_match ("depend ( ") == MATCH_YES)
+	  /* DOACROSS: match 'doacross' and 'depend' with sink/source.
+	     DEPEND: match 'depend' but not sink/source.  */
+	  m = MATCH_NO;
+	  if (((mask & OMP_CLAUSE_DOACROSS)
+	       && gfc_match ("doacross ( ") == MATCH_YES)
+	      || (((mask & OMP_CLAUSE_DEPEND) || (mask & OMP_CLAUSE_DOACROSS))
+		  && (m = gfc_match ("depend ( ")) == MATCH_YES))
 	    {
 	      bool has_omp_all_memory;
+	      bool is_depend = m == MATCH_YES;
 	      gfc_namespace *ns_iter = NULL, *ns_curr = gfc_current_ns;
-	      match m_it = gfc_match_iterator (&ns_iter, false);
+	      match m_it = MATCH_NO;
+	      if (is_depend)
+		m_it = gfc_match_iterator (&ns_iter, false);
 	      if (m_it == MATCH_ERROR)
 		break;
 	      if (m_it == MATCH_YES && gfc_match (" , ") != MATCH_YES)
 		break;
 	      m = MATCH_YES;
-	      gfc_omp_depend_op depend_op = OMP_DEPEND_OUT;
+	      gfc_omp_depend_doacross_op depend_op = OMP_DEPEND_OUT;
 	      if (gfc_match ("inoutset") == MATCH_YES)
 		depend_op = OMP_DEPEND_INOUTSET;
 	      else if (gfc_match ("inout") == MATCH_YES)
@@ -1927,34 +1940,77 @@ gfc_match_omp_clauses (gfc_omp_clauses **cp, const omp_mask mask,
 		depend_op = OMP_DEPEND_MUTEXINOUTSET;
 	      else if (gfc_match ("depobj") == MATCH_YES)
 		depend_op = OMP_DEPEND_DEPOBJ;
-	      else if (!c->depend_source
-		       && gfc_match ("source )") == MATCH_YES)
+	      else if (gfc_match ("source") == MATCH_YES)
 		{
 		  if (m_it == MATCH_YES)
 		    {
 		      gfc_error ("ITERATOR may not be combined with SOURCE "
 				 "at %C");
-		      gfc_free_omp_clauses (c);
-		      return MATCH_ERROR;
+		      goto error;
+		    }
+		  if (!(mask & OMP_CLAUSE_DOACROSS))
+		    {
+		      gfc_error ("SOURCE at %C not permitted as dependence-type"
+				 " for this directive");
+		      goto error;
+		    }
+		  if (c->doacross_source)
+		    {
+		      gfc_error ("Duplicated clause with SOURCE dependence-type"
+				 " at %C");
+		      goto error;
+		    }
+		  gfc_gobble_whitespace ();
+		  m = gfc_match (": ");
+		  if (m != MATCH_YES && !is_depend)
+		    {
+		      gfc_error ("Expected %<:%> at %C");
+		      goto error;
 		    }
-		  c->depend_source = true;
+		  if (gfc_match (")") != MATCH_YES
+		      && !(m == MATCH_YES
+			   && gfc_match ("omp_cur_iteration )") == MATCH_YES))
+		    {
+		      gfc_error ("Expected %<)%> or %<omp_cur_iteration)%> "
+				 "at %C");
+		      goto error;
+		    }
+		  c->doacross_source = true;
+		  c->depend_source = is_depend;
 		  continue;
 		}
-	      else if (gfc_match ("sink : ") == MATCH_YES)
+	      else if (gfc_match ("sink ") == MATCH_YES)
 		{
+		  if (!(mask & OMP_CLAUSE_DOACROSS))
+		    {
+		      gfc_error ("SINK at %C not permitted as dependence-type "
+				 "for this directive");
+		      goto error;
+		    }
+		  if (gfc_match (": ") != MATCH_YES)
+		    {
+		      gfc_error ("Expected %<:%> at %C");
+		      goto error;
+		    }
 		  if (m_it == MATCH_YES)
 		    {
 		      gfc_error ("ITERATOR may not be combined with SINK "
 				 "at %C");
-		      break;
+		      goto error;
 		    }
-		  if (gfc_match_omp_depend_sink (&c->lists[OMP_LIST_DEPEND])
-		      == MATCH_YES)
+		  m = gfc_match_omp_doacross_sink (&c->lists[OMP_LIST_DEPEND],
+						   is_depend);
+		  if (m == MATCH_YES)
 		    continue;
-		  m = MATCH_NO;
+		  goto error;
 		}
 	      else
 		m = MATCH_NO;
+	      if (!(mask & OMP_CLAUSE_DEPEND))
+		{
+		  gfc_error ("Expected dependence-type SINK or SOURCE at %C");
+		  goto error;
+		}
 	      head = NULL;
 	      if (ns_iter)
 		gfc_current_ns = ns_iter;
@@ -1976,7 +2032,7 @@ gfc_match_omp_clauses (gfc_omp_clauses **cp, const omp_mask mask,
 	      gfc_omp_namelist *n;
 	      for (n = *head; n; n = n->next)
 		{
-		  n->u.depend_op = depend_op;
+		  n->u.depend_doacross_op = depend_op;
 		  n->u2.ns = ns_iter;
 		  if (ns_iter)
 		    ns_iter->refs++;
@@ -3971,18 +4027,15 @@ gfc_match_omp_depobj (void)
 
   if (c->depobj_update == OMP_DEPEND_UNSET && !c->destroy)
     {
-      if (!c->depend_source && !c->lists[OMP_LIST_DEPEND])
+      if (!c->doacross_source && !c->lists[OMP_LIST_DEPEND])
 	{
 	  gfc_error ("Expected DEPEND, UPDATE, or DESTROY clause at %C");
 	  goto error;
 	}
-      if (c->depend_source
-	  || c->lists[OMP_LIST_DEPEND]->u.depend_op == OMP_DEPEND_SINK_FIRST
-	  || c->lists[OMP_LIST_DEPEND]->u.depend_op == OMP_DEPEND_SINK
-	  || c->lists[OMP_LIST_DEPEND]->u.depend_op == OMP_DEPEND_DEPOBJ)
+      if (c->lists[OMP_LIST_DEPEND]->u.depend_doacross_op == OMP_DEPEND_DEPOBJ)
 	{
 	  gfc_error ("DEPEND clause at %L of OMP DEPOBJ construct shall not "
-		     "have dependence-type SOURCE, SINK or DEPOBJ",
+		     "have dependence-type DEPOBJ",
 		     c->lists[OMP_LIST_DEPEND]
 		     ? &c->lists[OMP_LIST_DEPEND]->where : &gfc_current_locus);
 	  goto error;
@@ -5988,7 +6041,7 @@ gfc_match_omp_nothing (void)
 match
 gfc_match_omp_ordered_depend (void)
 {
-  return match_omp (EXEC_OMP_ORDERED, omp_mask (OMP_CLAUSE_DEPEND));
+  return match_omp (EXEC_OMP_ORDERED, omp_mask (OMP_CLAUSE_DOACROSS));
 }
 
 
@@ -7057,18 +7110,16 @@ resolve_omp_clauses (gfc_code *code, gfc_omp_clauses *omp_clauses,
 
 		if (list == OMP_LIST_DEPEND)
 		  {
-		    if (n->u.depend_op == OMP_DEPEND_SINK_FIRST
-			|| n->u.depend_op == OMP_DEPEND_SINK)
+		    if (n->u.depend_doacross_op == OMP_DEPEND_SINK_FIRST
+			|| n->u.depend_doacross_op == OMP_DOACROSS_SINK_FIRST
+			|| n->u.depend_doacross_op == OMP_DOACROSS_SINK)
 		      {
-			if (code->op != EXEC_OMP_ORDERED)
-			  gfc_error ("SINK dependence type only allowed "
-				     "on ORDERED directive at %L", &n->where);
-			else if (omp_clauses->depend_source)
+			if (omp_clauses->doacross_source)
 			  {
-			    gfc_error ("DEPEND SINK used together with "
-				       "DEPEND SOURCE on the same construct "
-				       "at %L", &n->where);
-			    omp_clauses->depend_source = false;
+			    gfc_error ("Dependence-type SINK used together with"
+				       " SOURCE on the same construct at %L",
+				       &n->where);
+			    omp_clauses->doacross_source = false;
 			  }
 			else if (n->expr)
 			  {
@@ -7078,13 +7129,14 @@ resolve_omp_clauses (gfc_code *code, gfc_omp_clauses *omp_clauses,
 			      gfc_error ("SINK addend not a constant integer "
 					 "at %L", &n->where);
 			  }
+			if (n->sym == NULL
+			    && (n->expr == NULL
+				|| mpz_cmp_si (n->expr->value.integer, -1) != 0))
+			  gfc_error ("omp_cur_iteration at %L requires %<-1%> "
+				     "as logical offset", &n->where);
 			continue;
 		      }
-		    else if (code->op == EXEC_OMP_ORDERED)
-		      gfc_error ("Only SOURCE or SINK dependence types "
-				 "are allowed on ORDERED directive at %L",
-				 &n->where);
-		    else if (n->u.depend_op == OMP_DEPEND_DEPOBJ
+		    else if (n->u.depend_doacross_op == OMP_DEPEND_DEPOBJ
 			     && !n->expr
 			     && (n->sym->ts.type != BT_INTEGER
 				 || n->sym->ts.kind
@@ -7094,7 +7146,7 @@ resolve_omp_clauses (gfc_code *code, gfc_omp_clauses *omp_clauses,
 				 "type shall be a scalar integer of "
 				 "OMP_DEPEND_KIND kind", n->sym->name,
 				 &n->where);
-		    else if (n->u.depend_op == OMP_DEPEND_DEPOBJ
+		    else if (n->u.depend_doacross_op == OMP_DEPEND_DEPOBJ
 			     && n->expr
 			     && (!gfc_resolve_expr (n->expr)
 				 || n->expr->ts.type != BT_INTEGER
@@ -7760,9 +7812,6 @@ resolve_omp_clauses (gfc_code *code, gfc_omp_clauses *omp_clauses,
     resolve_scalar_int_expr (el->expr, "WAIT");
   if (omp_clauses->collapse && omp_clauses->tile_list)
     gfc_error ("Incompatible use of TILE and COLLAPSE at %L", &code->loc);
-  if (omp_clauses->depend_source && code->op != EXEC_OMP_ORDERED)
-    gfc_error ("SOURCE dependence type only allowed "
-	       "on ORDERED directive at %L", &code->loc);
   if (omp_clauses->message)
     {
       gfc_expr *expr = omp_clauses->message;
@@ -9565,6 +9614,7 @@ gfc_resolve_omp_directive (gfc_code *code, gfc_namespace *ns)
     case EXEC_OMP_CANCEL:
     case EXEC_OMP_ERROR:
     case EXEC_OMP_MASKED:
+    case EXEC_OMP_ORDERED:
     case EXEC_OMP_PARALLEL_WORKSHARE:
     case EXEC_OMP_PARALLEL:
     case EXEC_OMP_PARALLEL_MASKED:
diff --git a/gcc/fortran/parse.cc b/gcc/fortran/parse.cc
index 80492c952aa..5b13441912a 100644
--- a/gcc/fortran/parse.cc
+++ b/gcc/fortran/parse.cc
@@ -1026,7 +1026,8 @@ decode_omp_directive (void)
       matcho ("loop", gfc_match_omp_loop, ST_OMP_LOOP);
       break;
     case 'o':
-      if (gfc_match ("ordered depend (") == MATCH_YES)
+      if (gfc_match ("ordered depend (") == MATCH_YES
+	  || gfc_match ("ordered doacross (") == MATCH_YES)
 	{
 	  gfc_current_locus = old_locus;
 	  if (!flag_openmp)
diff --git a/gcc/fortran/trans-openmp.cc b/gcc/fortran/trans-openmp.cc
index 82c1079bc28..1be7d23f86b 100644
--- a/gcc/fortran/trans-openmp.cc
+++ b/gcc/fortran/trans-openmp.cc
@@ -2864,15 +2864,18 @@ gfc_trans_omp_clauses (stmtblock_t *block, gfc_omp_clauses *clauses,
 		gfc_init_block (&iter_block);
 	      prev = n;
 	      if (list == OMP_LIST_DEPEND
-		  && n->u.depend_op == OMP_DEPEND_SINK_FIRST)
+		  && (n->u.depend_doacross_op == OMP_DOACROSS_SINK_FIRST
+		      || n->u.depend_doacross_op == OMP_DEPEND_SINK_FIRST))
 		{
 		  tree vec = NULL_TREE;
 		  unsigned int i;
+		  bool is_depend
+		    = n->u.depend_doacross_op == OMP_DEPEND_SINK_FIRST;
 		  for (i = 0; ; i++)
 		    {
 		      tree addend = integer_zero_node, t;
 		      bool neg = false;
-		      if (n->expr)
+		      if (n->sym && n->expr)
 			{
 			  addend = gfc_conv_constant_to_tree (n->expr);
 			  if (TREE_CODE (addend) == INTEGER_CST
@@ -2883,7 +2886,11 @@ gfc_trans_omp_clauses (stmtblock_t *block, gfc_omp_clauses *clauses,
 						   TREE_TYPE (addend), addend);
 			    }
 			}
-		      t = gfc_trans_omp_variable (n->sym, false);
+
+		      if (n->sym == NULL)
+			t = null_pointer_node;  /* "omp_cur_iteration - 1".  */
+		      else
+			t = gfc_trans_omp_variable (n->sym, false);
 		      if (t != error_mark_node)
 			{
 			  if (i < vec_safe_length (doacross_steps)
@@ -2900,7 +2907,7 @@ gfc_trans_omp_clauses (stmtblock_t *block, gfc_omp_clauses *clauses,
 			    OMP_CLAUSE_DOACROSS_SINK_NEGATIVE (vec) = 1;
 			}
 		      if (n->next == NULL
-			  || n->next->u.depend_op != OMP_DEPEND_SINK)
+			  || n->next->u.depend_doacross_op != OMP_DOACROSS_SINK)
 			break;
 		      n = n->next;
 		    }
@@ -2910,7 +2917,7 @@ gfc_trans_omp_clauses (stmtblock_t *block, gfc_omp_clauses *clauses,
 		  tree node = build_omp_clause (input_location,
 						OMP_CLAUSE_DOACROSS);
 		  OMP_CLAUSE_DOACROSS_KIND (node) = OMP_CLAUSE_DOACROSS_SINK;
-		  OMP_CLAUSE_DOACROSS_DEPEND (node) = 1;
+		  OMP_CLAUSE_DOACROSS_DEPEND (node) = is_depend;
 		  OMP_CLAUSE_DECL (node) = nreverse (vec);
 		  omp_clauses = gfc_trans_add_clause (node, omp_clauses);
 		  continue;
@@ -2962,7 +2969,7 @@ gfc_trans_omp_clauses (stmtblock_t *block, gfc_omp_clauses *clauses,
 		  OMP_CLAUSE_DECL (node) = build_fold_indirect_ref (ptr);
 		}
 	      if (list == OMP_LIST_DEPEND)
-		switch (n->u.depend_op)
+		switch (n->u.depend_doacross_op)
 		  {
 		  case OMP_DEPEND_IN:
 		    OMP_CLAUSE_DEPEND_KIND (node) = OMP_CLAUSE_DEPEND_IN;
@@ -4253,11 +4260,11 @@ gfc_trans_omp_clauses (stmtblock_t *block, gfc_omp_clauses *clauses,
       omp_clauses = gfc_trans_add_clause (c, omp_clauses);
     }
 
-  if (clauses->depend_source)
+  if (clauses->doacross_source)
     {
       c = build_omp_clause (gfc_get_location (&where), OMP_CLAUSE_DOACROSS);
       OMP_CLAUSE_DOACROSS_KIND (c) = OMP_CLAUSE_DOACROSS_SOURCE;
-      OMP_CLAUSE_DOACROSS_DEPEND (c) = 1;
+      OMP_CLAUSE_DOACROSS_DEPEND (c) = clauses->depend_source;
       omp_clauses = gfc_trans_add_clause (c, omp_clauses);
     }
 
@@ -5119,7 +5126,7 @@ gfc_trans_omp_do (gfc_code *code, gfc_exec_op op, stmtblock_t *pblock,
   init = make_tree_vec (collapse);
   cond = make_tree_vec (collapse);
   incr = make_tree_vec (collapse);
-  orig_decls = clauses->orderedc ? make_tree_vec (collapse) : NULL_TREE;
+  orig_decls = clauses->ordered ? make_tree_vec (collapse) : NULL_TREE;
 
   if (pblock == NULL)
     {
@@ -5219,6 +5226,10 @@ gfc_trans_omp_do (gfc_code *code, gfc_exec_op op, stmtblock_t *pblock,
 						    MODIFY_EXPR,
 						    type, dovar,
 						    TREE_VEC_ELT (incr, i));
+	  if (orig_decls && !clauses->orderedc)
+	    orig_decls = NULL;
+	  else if (orig_decls)
+	    TREE_VEC_ELT (orig_decls, i) = dovar_decl;
 	}
       else
 	{
@@ -5259,9 +5270,9 @@ gfc_trans_omp_do (gfc_code *code, gfc_exec_op op, stmtblock_t *pblock,
 		vec_safe_grow_cleared (doacross_steps, clauses->orderedc, true);
 	      (*doacross_steps)[i] = step;
 	    }
+	  if (orig_decls)
+	    TREE_VEC_ELT (orig_decls, i) = dovar_decl;
 	}
-      if (orig_decls)
-	TREE_VEC_ELT (orig_decls, i) = dovar_decl;
 
       if (dovar_found == 3
 	  && op == EXEC_OMP_SIMD
@@ -5628,7 +5639,7 @@ gfc_trans_omp_depobj (gfc_code *code)
   int k = -1; /* omp_clauses->destroy */
   if (!code->ext.omp_clauses->destroy)
     switch (code->ext.omp_clauses->depobj_update != OMP_DEPEND_UNSET
-	    ? code->ext.omp_clauses->depobj_update : n->u.depend_op)
+	    ? code->ext.omp_clauses->depobj_update : n->u.depend_doacross_op)
       {
       case OMP_DEPEND_IN: k = GOMP_DEPEND_IN; break;
       case OMP_DEPEND_OUT: k = GOMP_DEPEND_OUT; break;
diff --git a/gcc/testsuite/gfortran.dg/gomp/all-memory-1.f90 b/gcc/testsuite/gfortran.dg/gomp/all-memory-1.f90
index f8f34f0c887..51b5633adba 100644
--- a/gcc/testsuite/gfortran.dg/gomp/all-memory-1.f90
+++ b/gcc/testsuite/gfortran.dg/gomp/all-memory-1.f90
@@ -50,5 +50,5 @@ subroutine f6
   !$omp target depend ( depobj : omp_all_memory)  ! { dg-error "'omp_all_memory' used with DEPEND kind other than OUT or INOUT" }
   !!$omp end target
 
-  !$omp ordered depend ( sink : omp_all_memory)  ! { dg-error "'omp_all_memory' used with DEPEND kind other than OUT or INOUT" }
+  !$omp ordered depend ( sink : omp_all_memory)  ! { dg-error "used with dependence-type other than OUT or INOUT" }
 end
diff --git a/gcc/testsuite/gfortran.dg/gomp/depend-iterator-2.f90 b/gcc/testsuite/gfortran.dg/gomp/depend-iterator-2.f90
index 21fc3272974..cadd9a06cfe 100644
--- a/gcc/testsuite/gfortran.dg/gomp/depend-iterator-2.f90
+++ b/gcc/testsuite/gfortran.dg/gomp/depend-iterator-2.f90
@@ -34,7 +34,7 @@ program main
       !!$omp end task
     !$omp task depend(iterator(i=1:5), source )  ! { dg-error "ITERATOR may not be combined with SOURCE" }
   !!$omp end task
-  !$omp task affinity (iterator(i=1:5): a) depend(iterator(i=1:5), sink : x) ! { dg-error "ITERATOR may not be combined with SINK" }
+  !$omp task affinity (iterator(i=1:5): a) depend(iterator(i=1:5), sink : x) ! { dg-error "SINK at .1. not permitted as dependence-type for this directive" }
   !!$omp end task
 
     end do
diff --git a/gcc/testsuite/gfortran.dg/gomp/depobj-2.f90 b/gcc/testsuite/gfortran.dg/gomp/depobj-2.f90
index cb67c3ce9d1..6e7441d8d00 100644
--- a/gcc/testsuite/gfortran.dg/gomp/depobj-2.f90
+++ b/gcc/testsuite/gfortran.dg/gomp/depobj-2.f90
@@ -21,13 +21,13 @@ subroutine f1
   !$omp depobj(d) depend( inout : a)                 ! { dg-error "DEPOBJ in DEPOBJ construct at .1. shall be a scalar integer of OMP_DEPEND_KIND kind" }
   !$omp depobj(depobj) depend( inout : a, b)         ! { dg-error "DEPEND clause at .1. of OMP DEPOBJ construct shall have only a single locator" }
   !$omp depobj(depobj) depend(mutexinoutset : a)     ! OK
-  !$omp depobj(depobj) depend(source)                ! { dg-error "DEPEND clause at .1. of OMP DEPOBJ construct shall not have dependence-type SOURCE, SINK or DEPOBJ" }
-  !$omp depobj(depobj) depend(sink : i + 1)          ! { dg-error "DEPEND clause at .1. of OMP DEPOBJ construct shall not have dependence-type SOURCE, SINK or DEPOBJ" }
+  !$omp depobj(depobj) depend(source)                ! { dg-error "SOURCE at .1. not permitted as dependence-type for this directive" }
+  !$omp depobj(depobj) depend(sink : i + 1)          ! { dg-error "SINK at .1. not permitted as dependence-type for this directive" }
   !$omp depobj(depobj) update(source)                ! { dg-error "Expected IN, OUT, INOUT, INOUTSET or MUTEXINOUTSET followed by '\\)'" }
   !$omp depobj(depobj) update(sink)                  ! { dg-error "Expected IN, OUT, INOUT, INOUTSET or MUTEXINOUTSET followed by '\\)'" }
   !$omp depobj(depobj) update(depobj)                ! { dg-error "Expected IN, OUT, INOUT, INOUTSET or MUTEXINOUTSET followed by '\\)'" }
 
   ! Valid in OpenMP 5.1:
-  !$omp depobj(depobj5) depend(depobj: depobj3)      ! { dg-error "DEPEND clause at .1. of OMP DEPOBJ construct shall not have dependence-type SOURCE, SINK or DEPOBJ" }
+  !$omp depobj(depobj5) depend(depobj: depobj3)      ! { dg-error "DEPEND clause at .1. of OMP DEPOBJ construct shall not have dependence-type DEPOBJ" }
 end subroutine f1
 
diff --git a/gcc/testsuite/gfortran.dg/gomp/doacross-5.f90 b/gcc/testsuite/gfortran.dg/gomp/doacross-5.f90
new file mode 100644
index 00000000000..3a1679a1eec
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/gomp/doacross-5.f90
@@ -0,0 +1,88 @@
+subroutine foo (n)
+  integer i, n
+
+  !$omp do ordered
+  do i = 1, 8, n
+    !$omp ordered doacross(source:)
+    !$omp ordered doacross(sink: i - 2)
+  end do
+end
+
+subroutine bar (n)
+  integer :: i, j, n
+
+  !$omp do collapse(2) ordered(2)
+  do i = 1, 8, n
+    do j = 1, 8, n
+      !$omp ordered doacross(source:omp_cur_iteration)
+      !$omp ordered doacross(sink: i - 2, j + 2)
+    end do
+  end do
+end
+
+subroutine baz ()
+  integer :: i, j
+
+  !$omp do ordered(1)
+  do i = 1, 64
+    !$omp ordered			! { dg-error "'ordered' construct without 'doacross' or 'depend' clauses must not have the same binding region as 'ordered' construct with those clauses" }
+    !$omp end ordered
+
+    !$omp ordered doacross(source:)
+
+    !$omp ordered doacross(sink: i - 1)
+  end do
+
+  !$omp do ordered
+  do i = 1, 64
+    !$omp ordered doacross(source: omp_cur_iteration )
+
+    !$omp ordered doacross(sink: i - 1)
+
+    !$omp ordered threads		! { dg-error "'ordered' construct without 'doacross' or 'depend' clauses must not have the same binding region as 'ordered' construct with those clauses" }
+    !$omp end ordered
+  end do
+  !$omp do ordered(2)
+  do i = 1, 64
+    do j = 1, 64
+	!$omp ordered			! { dg-error "'ordered' construct without 'doacross' or 'depend' clauses binds to loop where 'collapse' argument 1 is different from 'ordered' argument 2" }
+	!$omp end ordered
+    end do
+  end do
+  !$omp do ordered(2) collapse(1)
+  do i = 1, 8
+    do j = 1, 8
+      !$omp ordered threads		! { dg-error "'ordered' construct without 'doacross' or 'depend' clauses binds to loop where 'collapse' argument 1 is different from 'ordered' argument 2" }
+      !$omp end ordered
+    end do
+  end do
+end
+
+subroutine qux ()
+  integer :: i, j
+  j = 0
+  !$omp do ordered linear(j)
+  do i = 1, 64
+    j = j + 1
+    !$omp ordered
+    !$omp end ordered
+  end do
+  !$omp do ordered linear(j)		! { dg-error "'linear' clause may not be specified together with 'ordered' clause if stand-alone 'ordered' construct is nested in it" }
+  do i = 1, 64
+    j = j + 1
+    !$omp ordered doacross(source:)
+    !$omp ordered doacross(sink:i-1)
+  end do
+  !$omp do ordered(1) linear(j)
+  do i = 1, 64
+    j = j + 1
+    !$omp ordered
+    !$omp end ordered
+  end do
+  !$omp do ordered(1) linear(j)		! { dg-error "'linear' clause may not be specified together with 'ordered' clause if stand-alone 'ordered' construct is nested in it" }
+  do i = 1, 64
+    j = j + 1
+    !$omp ordered doacross(source:)
+    !$omp ordered doacross(sink:i-1)
+  end do
+end
diff --git a/gcc/testsuite/gfortran.dg/gomp/doacross-6.f90 b/gcc/testsuite/gfortran.dg/gomp/doacross-6.f90
new file mode 100644
index 00000000000..a45e1c9386c
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/gomp/doacross-6.f90
@@ -0,0 +1,77 @@
+subroutine foo (n)
+  integer :: i, n
+  !$omp do ordered
+  do i = 1, 8, n
+    !$omp ordered doacross(source)		! { dg-error "Expected ':'" }
+  end do
+
+  !$omp do ordered
+  do i = 1, 8, n
+    !$omp ordered doacross(source:omp_current_iteration)	! { dg-error "Expected '\\\)' or 'omp_cur_iteration\\\)'" }
+  end do
+
+  !$omp do ordered
+  do i = 1, 8, n
+    !$omp ordered doacross(source:i - 2)	! { dg-error "Expected '\\\)' or 'omp_cur_iteration\\\)'" }
+  end do
+
+  !$omp do ordered
+  do i = 1, 8, n
+    !$omp ordered doacross(sink)		! { dg-error "Expected ':'" }
+  end do
+
+  !$omp do ordered
+  do i = 1, 8, n
+    !$omp ordered doacross(sink:)		! { dg-error "Syntax error in OpenMP SINK dependence-type list" }
+  end do
+end
+
+subroutine bar (n)
+  implicit none
+  integer i, n
+
+  !$omp do ordered
+  do i = 1, 8, n
+    !$omp ordered doacross(sink:omp_current_iteration - 1)	! { dg-error "Symbol 'omp_current_iteration' at .1. has no IMPLICIT type" }
+  end do
+
+  !$omp do ordered
+  do i = 1, 8, n
+    !$omp ordered doacross(sink:omp_cur_iteration)	! { dg-error "omp_cur_iteration at .1. requires '-1' as logical offset" }
+  end do
+end
+
+subroutine baz (n)
+  implicit none
+  integer i, n
+
+  !$omp do ordered
+  do i = 1, 8, n
+    !$omp ordered doacross(sink:omp_cur_iteration + 1)	! { dg-error "omp_cur_iteration at .1. requires '-1' as logical offset" }
+  end do
+end
+
+subroutine qux (n)
+  implicit none
+  integer i, n
+
+  !$omp do ordered
+  do i = 1, 8, n
+    !$omp ordered doacross(sink:omp_cur_iteration - (2 - 1))	! { dg-error "Syntax error in OpenMP SINK dependence-type list" }
+  end do
+end
+
+subroutine corge (n)
+  implicit none
+  integer i, n
+
+  !$omp do ordered
+  do i = 1, 8, n
+    !$omp ordered doacross(sink:omp_cur_iteration - 1)
+  end do
+
+  !$omp do ordered
+  do i = 1, 8, n
+    !$omp ordered doacross(sink:omp_cur_iteration - 1_8)
+  end do
+end
diff --git a/libgomp/libgomp.texi b/libgomp/libgomp.texi
index 0f2998cf8f1..3df979e170b 100644
--- a/libgomp/libgomp.texi
+++ b/libgomp/libgomp.texi
@@ -394,10 +394,11 @@ to address of matching mapped list item per 5.1, Sect. 2.21.7.2 @tab N @tab
 @item Default map-type for @code{map} clause in @code{target enter/exit data}
       @tab Y @tab
 @item New @code{doacross} clause as alias for @code{depend} with
-      @code{source}/@code{sink} modifier @tab N @tab
+      @code{source}/@code{sink} modifier @tab Y @tab
 @item Deprecation of @code{depend} with @code{source}/@code{sink} modifier
       @tab N @tab
-@item @code{omp_cur_iteration} keyword @tab N @tab
+@item @code{omp_cur_iteration} keyword @tab P
+      @tab @code{sink: omp_cur_iteration - 1} unsupported
 @end multitable
 
 @unnumberedsubsec Other new OpenMP 5.2 features

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [committed] openmp: Partial OpenMP 5.2 doacross and omp_cur_iteration support
  2022-09-05 13:01 ` [committed] openmp: Partial OpenMP 5.2 doacross and omp_cur_iteration support Tobias Burnus
@ 2022-09-05 16:00   ` Jakub Jelinek
  0 siblings, 0 replies; 4+ messages in thread
From: Jakub Jelinek @ 2022-09-05 16:00 UTC (permalink / raw)
  To: Tobias Burnus; +Cc: gcc-patches

On Mon, Sep 05, 2022 at 03:01:07PM +0200, Tobias Burnus wrote:
> On 03.09.22 10:07, Jakub Jelinek wrote:
> > The following patch implements part of the OpenMP 5.2 changes related
> > to ordered loops ...
> 
> Fortran bits to it attached.
> 
> OK for mainline?
> 
> 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

> Fortran/openmp: Partial OpenMP 5.2 doacross and omp_cur_iteration support
> 
> Add the Fortran support to the ME/C/C++ commit
> r13-2388-ga651e6d59188da8992f8bfae2df1cb4e6316f9e6
> 
> gcc/fortran/ChangeLog:
> 
> 	* dump-parse-tree.cc (show_omp_namelist, show_omp_clauses): Handle
> 	omp_cur_iteration and distinguish doacross/depend:

s/:/./

> 	* gfortran.h (enum gfc_omp_depend_doacross_op): Renamed from
> 	gfc_omp_depend_op.
> 	(enum gfc_omp_depend_doacross_op): Add OMP_DOACROSS_SINK_FIRST,
> 	Rename OMP_DEPEND_SINK to OMP_DOACROSS_SINK.
> 	(gfc_omp_namelist) Handle renaming, rename depend_op to
> 	depend_doacross_op.
> 	(struct gfc_omp_clauses): Add doacross_source.
> 	* openmp.cc (gfc_match_omp_depend_sink): Renamed to ...
> 	(gfc_match_omp_doacross_sink): ... this; handle omp_all_memory.
> 	(enum omp_mask2): Add OMP_CLAUSE_DOACROSS.
> 	(gfc_match_omp_clauses): Handle 'doacross' and syntax changes to
> 	depend.
> 	(gfc_match_omp_depobj): Simplify as sink/source are now impossible.
> 	(gfc_match_omp_ordered_depend): Request OMP_CLAUSE_DOACROSS.
> 	(resolve_omp_clauses): Update sink/source checks.
> 	(gfc_resolve_omp_directive): Resolve EXEC_OMP_ORDERED clauses.
> 	* parse.cc (decode_omp_directive): Handle 'ordered doacross'.
> 	* trans-openmp.cc (gfc_trans_omp_clauses): Handle doacross.
> 	(gfc_trans_omp_do): Fix OMP_FOR_ORIG_DECLS handling if 'ordered'
> 	clause is present.
> 	(gfc_trans_omp_depobj): Update for member name change.
> 
> libgomp/ChangeLog:
> 
> 	* libgomp.texi (OpenMP 5.2): Update doacross/omp_cur_iteration status.
> 
> gcc/testsuite/ChangeLog:
> 
> 	* gfortran.dg/gomp/all-memory-1.f90: Update dg-error.
> 	* gfortran.dg/gomp/depend-iterator-2.f90: Likewise.
> 	* gfortran.dg/gomp/depobj-2.f90: Likewise.
> 	* gfortran.dg/gomp/doacross-5.f90: New test.
> 	* gfortran.dg/gomp/doacross-6.f90: New test.

Otherwise LGTM.

	Jakub


^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2022-09-05 16:00 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-09-03  8:07 [committed] openmp: Partial OpenMP 5.2 doacross and omp_cur_iteration support Jakub Jelinek
2022-09-05 12:28 ` [PATCH] openmp: Introduce gimple_omp_ordered_standalone_p Jakub Jelinek
2022-09-05 13:01 ` [committed] openmp: Partial OpenMP 5.2 doacross and omp_cur_iteration support Tobias Burnus
2022-09-05 16:00   ` Jakub Jelinek

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).