public inbox for fortran@gcc.gnu.org
 help / color / mirror / Atom feed
* [Patch] Fortran: OpenMP 5.0 (in_,task_)reduction clause extensions
@ 2020-11-09 23:40 Tobias Burnus
  2020-11-10 12:16 ` Jakub Jelinek
  0 siblings, 1 reply; 8+ messages in thread
From: Tobias Burnus @ 2020-11-09 23:40 UTC (permalink / raw)
  To: gcc-patches, fortran, Jakub Jelinek

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

This patch updates the OpenMP handling to support OpenMP 5.0's
reductions changes:
- add task_reduction (for taskgroup)
- add in_reduction (for task, taskloop, target)
- add 'default', 'inscan' and 'task' to 'reduction'
   - only default for teams, taskloop
   - all three for parallel, simd, do, section

When copying + converting testcases from C to Fortran,
I saw that 'schedule(monotonic' can now be mixed with static/runtime/auto,
which is also included in the patch.

OK?

Tobias

PS: I am sure, I missed something, the question is only what ...
A likely place where something might have got wrong is gfc_split_omp_clauses.

-----------------
Mentor Graphics (Deutschland) GmbH, Arnulfstraße 201, 80634 München / Germany
Registergericht München HRB 106955, Geschäftsführer: Thomas Heurung, Alexander Walter

[-- Attachment #2: omp-reduction.diff --]
[-- Type: text/x-patch, Size: 122532 bytes --]

Fortran: OpenMP 5.0 (in_,task_)reduction clause extensions

gcc/fortran/ChangeLog:

	PR fortran/95847
	* dump-parse-tree.c (show_omp_clauses): Handle new reduction enums.
	* gfortran.h (OMP_LIST_REDUCTION_INSCAN, OMP_LIST_REDUCTION_TASK,
	OMP_LIST_IN_REDUCTION, OMP_LIST_TASK_REDUCTION): Add enums.
	* openmp.c (enum omp_mask1): Add OMP_CLAUSE_REDUCTION_DEFAULT,
	OMP_CLAUSE_REDUCTION_MODIFIER, OMP_CLAUSE_IN_REDUCTION,
	and OMP_CLAUSE_TASK_REDUCTION.
	(gfc_match_omp_clause_reduction): Extend reduction handling;
	moved from ...
	(gfc_match_omp_clauses): ... here. Add calls to it.
	(OMP_PARALLEL_CLAUSES, OMP_OMP_DO_CLAUSES, OMP_SECTIONS_CLAUSES,
	OMP_SIMD_CLAUSES): Use OMP_CLAUSE_REDUCTION_MODIFIERS.
	(OMP_TASK_CLAUSES, OMP_TARGET_CLAUSES): Add OMP_CLAUSE_IN_REDUCTION.
	(OMP_TASKLOOP_CLAUSES): Likewise; add OMP_CLAUSE_REDUCTION_DEFAULT.
	(OMP_TEAMS_CLAUSES): Add OMP_CLAUSE_REDUCTION_DEFAULT.
	(gfc_match_omp_taskgroup): Add task_reduction matching.
	(resolve_omp_clauses): Update for new reduction clause changes;
	remove removed nonmonotonic-schedule restrictions.
	(gfc_resolve_omp_parallel_blocks): Add new enums to switch.
	* trans-openmp.c (gfc_omp_clause_default_ctor,
	gfc_trans_omp_reduction_list, gfc_trans_omp_clauses,
	gfc_split_omp_clauses): Handle updated reduction clause.

gcc/ChangeLog:

	PR fortran/95847
	* gimplify.c (gimplify_scan_omp_clauses, gimplify_omp_loop): Use 'do'
	instead of 'for' in error messages for Fortran.
	* omp-low.c (check_omp_nesting_restrictions): Likewise

gcc/testsuite/ChangeLog:

	PR fortran/95847
	* gfortran.dg/gomp/schedule-modifiers-2.f90: Remove some dg-error.
	* gfortran.dg/gomp/reduction4.f90: New test.
	* gfortran.dg/gomp/reduction5.f90: New test.
	* gfortran.dg/gomp/workshare-reduction-1.f90: New test.
	* gfortran.dg/gomp/workshare-reduction-2.f90: New test.
	* gfortran.dg/gomp/workshare-reduction-3.f90: New test.
	* gfortran.dg/gomp/workshare-reduction-4.f90: New test.
	* gfortran.dg/gomp/workshare-reduction-5.f90: New test.
	* gfortran.dg/gomp/workshare-reduction-6.f90: New test.
	* gfortran.dg/gomp/workshare-reduction-7.f90: New test.
	* gfortran.dg/gomp/workshare-reduction-8.f90: New test.
	* gfortran.dg/gomp/workshare-reduction-9.f90: New test.
	* gfortran.dg/gomp/workshare-reduction-10.f90: New test.
	* gfortran.dg/gomp/workshare-reduction-11.f90: New test.
	* gfortran.dg/gomp/workshare-reduction-12.f90: New test.
	* gfortran.dg/gomp/workshare-reduction-13.f90: New test.
	* gfortran.dg/gomp/workshare-reduction-14.f90: New test.
	* gfortran.dg/gomp/workshare-reduction-15.f90: New test.
	* gfortran.dg/gomp/workshare-reduction-16.f90: New test.
	* gfortran.dg/gomp/workshare-reduction-17.f90: New test.
	* gfortran.dg/gomp/workshare-reduction-18.f90: New test.
	* gfortran.dg/gomp/workshare-reduction-19.f90: New test.
	* gfortran.dg/gomp/workshare-reduction-20.f90: New test.
	* gfortran.dg/gomp/workshare-reduction-21.f90: New test.
	* gfortran.dg/gomp/workshare-reduction-22.f90: New test.
	* gfortran.dg/gomp/workshare-reduction-23.f90: New test.
	* gfortran.dg/gomp/workshare-reduction-24.f90: New test.
	* gfortran.dg/gomp/workshare-reduction-25.f90: New test.
	* gfortran.dg/gomp/workshare-reduction-26.f90: New test.
	* gfortran.dg/gomp/workshare-reduction-27.f90: New test.
	* gfortran.dg/gomp/workshare-reduction-28.f90: New test.
	* gfortran.dg/gomp/workshare-reduction-29.f90: New test.
	* gfortran.dg/gomp/workshare-reduction-30.f90: New test.
	* gfortran.dg/gomp/workshare-reduction-31.f90: New test.
	* gfortran.dg/gomp/workshare-reduction-32.f90: New test.
	* gfortran.dg/gomp/workshare-reduction-33.f90: New test.
	* gfortran.dg/gomp/workshare-reduction-34.f90: New test.
	* gfortran.dg/gomp/workshare-reduction-35.f90: New test.
	* gfortran.dg/gomp/workshare-reduction-36.f90: New test.
	* gfortran.dg/gomp/workshare-reduction-37.f90: New test.
	* gfortran.dg/gomp/workshare-reduction-38.f90: New test.
	* gfortran.dg/gomp/workshare-reduction-39.f90: New test.
	* gfortran.dg/gomp/workshare-reduction-40.f90: New test.
	* gfortran.dg/gomp/workshare-reduction-41.f90: New test.
	* gfortran.dg/gomp/workshare-reduction-42.f90: New test.
	* gfortran.dg/gomp/workshare-reduction-43.f90: New test.
	* gfortran.dg/gomp/workshare-reduction-44.f90: New test.
	* gfortran.dg/gomp/workshare-reduction-45.f90: New test.
	* gfortran.dg/gomp/workshare-reduction-46.f90: New test.
	* gfortran.dg/gomp/workshare-reduction-47.f90: New test.
	* gfortran.dg/gomp/workshare-reduction-48.f90: New test.
	* gfortran.dg/gomp/workshare-reduction-49.f90: New test.
	* gfortran.dg/gomp/workshare-reduction-50.f90: New test.
	* gfortran.dg/gomp/workshare-reduction-51.f90: New test.
	* gfortran.dg/gomp/workshare-reduction-52.f90: New test.
	* gfortran.dg/gomp/workshare-reduction-53.f90: New test.
	* gfortran.dg/gomp/workshare-reduction-54.f90: New test.
	* gfortran.dg/gomp/workshare-reduction-55.f90: New test.
	* gfortran.dg/gomp/workshare-reduction-56.f90: New test.
	* gfortran.dg/gomp/workshare-reduction-57.f90: New test.
	* gfortran.dg/gomp/workshare-reduction-58.f90: New test.

 gcc/fortran/dump-parse-tree.c                      |  10 +-
 gcc/fortran/gfortran.h                             |   4 +
 gcc/fortran/openmp.c                               | 401 +++++++++++++--------
 gcc/fortran/trans-openmp.c                         |  71 +++-
 gcc/gimplify.c                                     |   6 +-
 gcc/omp-low.c                                      |   3 +-
 gcc/testsuite/gfortran.dg/gomp/reduction4.f90      | 171 +++++++++
 gcc/testsuite/gfortran.dg/gomp/reduction5.f90      |  41 +++
 .../gfortran.dg/gomp/schedule-modifiers-2.f90      |   8 +-
 .../gfortran.dg/gomp/workshare-reduction-1.f90     |  31 ++
 .../gfortran.dg/gomp/workshare-reduction-10.f90    |  31 ++
 .../gfortran.dg/gomp/workshare-reduction-11.f90    |  31 ++
 .../gfortran.dg/gomp/workshare-reduction-12.f90    |  31 ++
 .../gfortran.dg/gomp/workshare-reduction-13.f90    |  31 ++
 .../gfortran.dg/gomp/workshare-reduction-14.f90    |  31 ++
 .../gfortran.dg/gomp/workshare-reduction-15.f90    |  31 ++
 .../gfortran.dg/gomp/workshare-reduction-16.f90    |  31 ++
 .../gfortran.dg/gomp/workshare-reduction-17.f90    |  31 ++
 .../gfortran.dg/gomp/workshare-reduction-18.f90    |  31 ++
 .../gfortran.dg/gomp/workshare-reduction-19.f90    |  31 ++
 .../gfortran.dg/gomp/workshare-reduction-2.f90     |  31 ++
 .../gfortran.dg/gomp/workshare-reduction-20.f90    |  31 ++
 .../gfortran.dg/gomp/workshare-reduction-21.f90    |  31 ++
 .../gfortran.dg/gomp/workshare-reduction-22.f90    |  31 ++
 .../gfortran.dg/gomp/workshare-reduction-23.f90    |  31 ++
 .../gfortran.dg/gomp/workshare-reduction-24.f90    |  31 ++
 .../gfortran.dg/gomp/workshare-reduction-25.f90    |  31 ++
 .../gfortran.dg/gomp/workshare-reduction-26.f90    |  31 ++
 .../gfortran.dg/gomp/workshare-reduction-27.f90    |  31 ++
 .../gfortran.dg/gomp/workshare-reduction-28.f90    |  31 ++
 .../gfortran.dg/gomp/workshare-reduction-29.f90    |  31 ++
 .../gfortran.dg/gomp/workshare-reduction-3.f90     |  31 ++
 .../gfortran.dg/gomp/workshare-reduction-30.f90    |  31 ++
 .../gfortran.dg/gomp/workshare-reduction-31.f90    |  31 ++
 .../gfortran.dg/gomp/workshare-reduction-32.f90    |  31 ++
 .../gfortran.dg/gomp/workshare-reduction-33.f90    |  31 ++
 .../gfortran.dg/gomp/workshare-reduction-34.f90    |  31 ++
 .../gfortran.dg/gomp/workshare-reduction-35.f90    |  31 ++
 .../gfortran.dg/gomp/workshare-reduction-36.f90    |  31 ++
 .../gfortran.dg/gomp/workshare-reduction-37.f90    |  31 ++
 .../gfortran.dg/gomp/workshare-reduction-38.f90    |  31 ++
 .../gfortran.dg/gomp/workshare-reduction-39.f90    |  31 ++
 .../gfortran.dg/gomp/workshare-reduction-4.f90     |  31 ++
 .../gfortran.dg/gomp/workshare-reduction-40.f90    |  31 ++
 .../gfortran.dg/gomp/workshare-reduction-41.f90    |  31 ++
 .../gfortran.dg/gomp/workshare-reduction-42.f90    |  31 ++
 .../gfortran.dg/gomp/workshare-reduction-43.f90    |  31 ++
 .../gfortran.dg/gomp/workshare-reduction-44.f90    |  31 ++
 .../gfortran.dg/gomp/workshare-reduction-45.f90    |  31 ++
 .../gfortran.dg/gomp/workshare-reduction-46.f90    |  31 ++
 .../gfortran.dg/gomp/workshare-reduction-47.f90    |  31 ++
 .../gfortran.dg/gomp/workshare-reduction-48.f90    |  31 ++
 .../gfortran.dg/gomp/workshare-reduction-49.f90    |  31 ++
 .../gfortran.dg/gomp/workshare-reduction-5.f90     |  31 ++
 .../gfortran.dg/gomp/workshare-reduction-50.f90    |  31 ++
 .../gfortran.dg/gomp/workshare-reduction-51.f90    |  35 ++
 .../gfortran.dg/gomp/workshare-reduction-52.f90    |  35 ++
 .../gfortran.dg/gomp/workshare-reduction-53.f90    |  35 ++
 .../gfortran.dg/gomp/workshare-reduction-54.f90    |  35 ++
 .../gfortran.dg/gomp/workshare-reduction-55.f90    |  35 ++
 .../gfortran.dg/gomp/workshare-reduction-56.f90    |  35 ++
 .../gfortran.dg/gomp/workshare-reduction-57.f90    |  35 ++
 .../gfortran.dg/gomp/workshare-reduction-58.f90    |  35 ++
 .../gfortran.dg/gomp/workshare-reduction-6.f90     |  31 ++
 .../gfortran.dg/gomp/workshare-reduction-7.f90     |  31 ++
 .../gfortran.dg/gomp/workshare-reduction-8.f90     |  31 ++
 .../gfortran.dg/gomp/workshare-reduction-9.f90     |  31 ++
 67 files changed, 2363 insertions(+), 182 deletions(-)

diff --git a/gcc/fortran/dump-parse-tree.c b/gcc/fortran/dump-parse-tree.c
index 43b97ba26ff..cab0fb2979f 100644
--- a/gcc/fortran/dump-parse-tree.c
+++ b/gcc/fortran/dump-parse-tree.c
@@ -1587,7 +1587,11 @@ show_omp_clauses (gfc_omp_clauses *omp_clauses)
 	  case OMP_LIST_MAP: type = "MAP"; break;
 	  case OMP_LIST_TO: type = "TO"; break;
 	  case OMP_LIST_FROM: type = "FROM"; break;
-	  case OMP_LIST_REDUCTION: type = "REDUCTION"; break;
+	  case OMP_LIST_REDUCTION:
+	  case OMP_LIST_REDUCTION_INSCAN:
+	  case OMP_LIST_REDUCTION_TASK: type = "REDUCTION"; break;
+	  case OMP_LIST_IN_REDUCTION: type = "IN_REDUCTION"; break;
+	  case OMP_LIST_TASK_REDUCTION: type = "TASK_REDUCTION"; break;
 	  case OMP_LIST_DEVICE_RESIDENT: type = "DEVICE_RESIDENT"; break;
 	  case OMP_LIST_LINK: type = "LINK"; break;
 	  case OMP_LIST_USE_DEVICE: type = "USE_DEVICE"; break;
@@ -1600,6 +1604,10 @@ show_omp_clauses (gfc_omp_clauses *omp_clauses)
 	    gcc_unreachable ();
 	  }
 	fprintf (dumpfile, " %s(", type);
+	if (list_type == OMP_LIST_REDUCTION_INSCAN)
+	  fputs ("inscan, ", dumpfile);
+	if (list_type == OMP_LIST_REDUCTION_TASK)
+	  fputs ("task, ", dumpfile);
 	show_omp_namelist (list_type, omp_clauses->lists[list_type]);
 	fputc (')', dumpfile);
       }
diff --git a/gcc/fortran/gfortran.h b/gcc/fortran/gfortran.h
index dfd7796cce0..6467985ea7f 100644
--- a/gcc/fortran/gfortran.h
+++ b/gcc/fortran/gfortran.h
@@ -1278,6 +1278,10 @@ enum
   OMP_LIST_TO,
   OMP_LIST_FROM,
   OMP_LIST_REDUCTION,
+  OMP_LIST_REDUCTION_INSCAN,
+  OMP_LIST_REDUCTION_TASK,
+  OMP_LIST_IN_REDUCTION,
+  OMP_LIST_TASK_REDUCTION,
   OMP_LIST_DEVICE_RESIDENT,
   OMP_LIST_LINK,
   OMP_LIST_USE_DEVICE,
diff --git a/gcc/fortran/openmp.c b/gcc/fortran/openmp.c
index 2270c858f39..feb82054b18 100644
--- a/gcc/fortran/openmp.c
+++ b/gcc/fortran/openmp.c
@@ -762,6 +762,10 @@ enum omp_mask1
   OMP_CLAUSE_SHARED,
   OMP_CLAUSE_COPYIN,
   OMP_CLAUSE_REDUCTION,
+  OMP_CLAUSE_REDUCTION_DEFAULT,
+  OMP_CLAUSE_REDUCTION_MODIFIER,
+  OMP_CLAUSE_IN_REDUCTION,
+  OMP_CLAUSE_TASK_REDUCTION,
   OMP_CLAUSE_IF,
   OMP_CLAUSE_NUM_THREADS,
   OMP_CLAUSE_SCHEDULE,
@@ -959,6 +963,172 @@ gfc_match_omp_map_clause (gfc_omp_namelist **list, gfc_omp_map_op map_op,
   return false;
 }
 
+/* reduction ( reduction-modifier, reduction-operator : variable-list )
+   in_reduction ( reduction-operator : variable-list )
+   task_reduction ( reduction-operator : variable-list )  */
+
+static match
+gfc_match_omp_clause_reduction (char pc, const omp_mask mask,
+				gfc_omp_clauses *c, bool openacc,
+				bool allow_derived)
+{
+  if (pc == 'r' && gfc_match ("reduction ( ") != MATCH_YES)
+    return MATCH_NO;
+  else if (pc == 'i' && gfc_match ("in_reduction ( ") != MATCH_YES)
+    return MATCH_NO;
+  else if (pc == 't' && gfc_match ("task_reduction ( ") != MATCH_YES)
+    return MATCH_NO;
+
+  locus old_loc = gfc_current_locus;
+  int list_idx = 0;
+
+  if (pc == 'r' && ((mask & OMP_CLAUSE_REDUCTION_DEFAULT)
+		    || (mask & OMP_CLAUSE_REDUCTION_MODIFIER)))
+    {
+      if (gfc_match ("inscan") == MATCH_YES)
+	list_idx = OMP_LIST_REDUCTION_INSCAN;
+      else if (gfc_match ("task") == MATCH_YES)
+	list_idx = OMP_LIST_REDUCTION_TASK;
+      else if (gfc_match ("default") == MATCH_YES)
+	list_idx = OMP_LIST_REDUCTION;
+      if (list_idx != 0 && gfc_match (", ") != MATCH_YES)
+	{
+	  gfc_error ("Comma expected at %C");
+	  gfc_current_locus = old_loc;
+	  return MATCH_NO;
+	}
+      if (list_idx == 0)
+	list_idx = OMP_LIST_REDUCTION;
+      else if (list_idx != OMP_LIST_REDUCTION
+	       && (mask & OMP_CLAUSE_REDUCTION_DEFAULT))
+	{
+	  gfc_error ("Reduction-modifier shall be %<default%> at %C");
+	  gfc_current_locus = old_loc;
+	  return MATCH_NO;
+	}
+    }
+  else if (pc == 'i')
+    list_idx = OMP_LIST_IN_REDUCTION;
+  else if (pc == 't')
+    list_idx = OMP_LIST_TASK_REDUCTION;
+  else
+    list_idx = OMP_LIST_REDUCTION;
+
+  gfc_omp_reduction_op rop = OMP_REDUCTION_NONE;
+  char buffer[GFC_MAX_SYMBOL_LEN + 3];
+  if (gfc_match_char ('+') == MATCH_YES)
+    rop = OMP_REDUCTION_PLUS;
+  else if (gfc_match_char ('*') == MATCH_YES)
+    rop = OMP_REDUCTION_TIMES;
+  else if (gfc_match_char ('-') == MATCH_YES)
+    rop = OMP_REDUCTION_MINUS;
+  else if (gfc_match (".and.") == MATCH_YES)
+    rop = OMP_REDUCTION_AND;
+  else if (gfc_match (".or.") == MATCH_YES)
+    rop = OMP_REDUCTION_OR;
+  else if (gfc_match (".eqv.") == MATCH_YES)
+    rop = OMP_REDUCTION_EQV;
+  else if (gfc_match (".neqv.") == MATCH_YES)
+    rop = OMP_REDUCTION_NEQV;
+  if (rop != OMP_REDUCTION_NONE)
+    snprintf (buffer, sizeof buffer, "operator %s",
+	      gfc_op2string ((gfc_intrinsic_op) rop));
+  else if (gfc_match_defined_op_name (buffer + 1, 1) == MATCH_YES)
+    {
+      buffer[0] = '.';
+      strcat (buffer, ".");
+    }
+  else if (gfc_match_name (buffer) == MATCH_YES)
+    {
+      gfc_symbol *sym;
+      const char *n = buffer;
+
+      gfc_find_symbol (buffer, NULL, 1, &sym);
+      if (sym != NULL)
+	{
+	  if (sym->attr.intrinsic)
+	    n = sym->name;
+	  else if ((sym->attr.flavor != FL_UNKNOWN
+		    && sym->attr.flavor != FL_PROCEDURE)
+		   || sym->attr.external
+		   || sym->attr.generic
+		   || sym->attr.entry
+		   || sym->attr.result
+		   || sym->attr.dummy
+		   || sym->attr.subroutine
+		   || sym->attr.pointer
+		   || sym->attr.target
+		   || sym->attr.cray_pointer
+		   || sym->attr.cray_pointee
+		   || (sym->attr.proc != PROC_UNKNOWN
+		       && sym->attr.proc != PROC_INTRINSIC)
+		   || sym->attr.if_source != IFSRC_UNKNOWN
+		   || sym == sym->ns->proc_name)
+		{
+		  sym = NULL;
+		  n = NULL;
+		}
+	      else
+		n = sym->name;
+	    }
+	  if (n == NULL)
+	    rop = OMP_REDUCTION_NONE;
+	  else if (strcmp (n, "max") == 0)
+	    rop = OMP_REDUCTION_MAX;
+	  else if (strcmp (n, "min") == 0)
+	    rop = OMP_REDUCTION_MIN;
+	  else if (strcmp (n, "iand") == 0)
+	    rop = OMP_REDUCTION_IAND;
+	  else if (strcmp (n, "ior") == 0)
+	    rop = OMP_REDUCTION_IOR;
+	  else if (strcmp (n, "ieor") == 0)
+	    rop = OMP_REDUCTION_IEOR;
+	  if (rop != OMP_REDUCTION_NONE
+	      && sym != NULL
+	      && ! sym->attr.intrinsic
+	      && ! sym->attr.use_assoc
+	      && ((sym->attr.flavor == FL_UNKNOWN
+		   && !gfc_add_flavor (&sym->attr, FL_PROCEDURE,
+					      sym->name, NULL))
+		  || !gfc_add_intrinsic (&sym->attr, NULL)))
+	    rop = OMP_REDUCTION_NONE;
+    }
+  else
+    buffer[0] = '\0';
+  gfc_omp_udr *udr = (buffer[0] ? gfc_find_omp_udr (gfc_current_ns, buffer, NULL)
+				: NULL);
+  gfc_omp_namelist **head = NULL;
+  if (rop == OMP_REDUCTION_NONE && udr)
+    rop = OMP_REDUCTION_USER;
+
+  if (gfc_match_omp_variable_list (" :", &c->lists[list_idx], false, NULL,
+				   &head, openacc, allow_derived) != MATCH_YES)
+    {
+      gfc_current_locus = old_loc;
+      return MATCH_NO;
+    }
+  gfc_omp_namelist *n;
+  if (rop == OMP_REDUCTION_NONE)
+    {
+      n = *head;
+      *head = NULL;
+      gfc_error_now ("!$OMP DECLARE REDUCTION %s not found at %L",
+		     buffer, &old_loc);
+      gfc_free_omp_namelist (n);
+    }
+  else
+    for (n = *head; n; n = n->next)
+      {
+	n->u.reduction_op = rop;
+	if (udr)
+	  {
+	    n->udr = gfc_get_omp_namelist_udr ();
+	    n->udr->udr = udr;
+	  }
+     }
+  return MATCH_YES;
+}
+
 /* Match OpenMP and OpenACC directive clauses. MASK is a bitmask of
    clauses that are allowed for a particular directive.  */
 
@@ -1379,6 +1549,10 @@ gfc_match_omp_clauses (gfc_omp_clauses **cp, const omp_mask mask,
 	      needs_space = true;
 	      continue;
 	    }
+	  if ((mask & OMP_CLAUSE_IN_REDUCTION)
+	      && gfc_match_omp_clause_reduction (pc, mask, c, openacc,
+						 allow_derived) == MATCH_YES)
+	    continue;
 	  if ((mask & OMP_CLAUSE_INBRANCH)
 	      && !c->inbranch
 	      && !c->notinbranch
@@ -1716,125 +1890,27 @@ gfc_match_omp_clauses (gfc_omp_clauses **cp, const omp_mask mask,
 	      needs_space = true;
 	      continue;
 	    }
-	  if ((mask & OMP_CLAUSE_REDUCTION)
-	      && gfc_match ("reduction ( ") == MATCH_YES)
+	  if (((mask & OMP_CLAUSE_REDUCTION)
+	       || (mask & OMP_CLAUSE_REDUCTION_DEFAULT)
+	       || (mask & OMP_CLAUSE_REDUCTION_MODIFIER))
+	      && gfc_match_omp_clause_reduction (pc, mask, c, openacc,
+						 allow_derived) == MATCH_YES)
+	    continue;
+	  if ((mask & OMP_CLAUSE_MEMORDER)
+	      && c->memorder == OMP_MEMORDER_UNSET
+	      && gfc_match ("relaxed") == MATCH_YES)
 	    {
-	      gfc_omp_reduction_op rop = OMP_REDUCTION_NONE;
-	      char buffer[GFC_MAX_SYMBOL_LEN + 3];
-	      if (gfc_match_char ('+') == MATCH_YES)
-		rop = OMP_REDUCTION_PLUS;
-	      else if (gfc_match_char ('*') == MATCH_YES)
-		rop = OMP_REDUCTION_TIMES;
-	      else if (gfc_match_char ('-') == MATCH_YES)
-		rop = OMP_REDUCTION_MINUS;
-	      else if (gfc_match (".and.") == MATCH_YES)
-		rop = OMP_REDUCTION_AND;
-	      else if (gfc_match (".or.") == MATCH_YES)
-		rop = OMP_REDUCTION_OR;
-	      else if (gfc_match (".eqv.") == MATCH_YES)
-		rop = OMP_REDUCTION_EQV;
-	      else if (gfc_match (".neqv.") == MATCH_YES)
-		rop = OMP_REDUCTION_NEQV;
-	      if (rop != OMP_REDUCTION_NONE)
-		snprintf (buffer, sizeof buffer, "operator %s",
-			  gfc_op2string ((gfc_intrinsic_op) rop));
-	      else if (gfc_match_defined_op_name (buffer + 1, 1) == MATCH_YES)
-		{
-		  buffer[0] = '.';
-		  strcat (buffer, ".");
-		}
-	      else if (gfc_match_name (buffer) == MATCH_YES)
-		{
-		  gfc_symbol *sym;
-		  const char *n = buffer;
-
-		  gfc_find_symbol (buffer, NULL, 1, &sym);
-		  if (sym != NULL)
-		    {
-		      if (sym->attr.intrinsic)
-			n = sym->name;
-		      else if ((sym->attr.flavor != FL_UNKNOWN
-				&& sym->attr.flavor != FL_PROCEDURE)
-			       || sym->attr.external
-			       || sym->attr.generic
-			       || sym->attr.entry
-			       || sym->attr.result
-			       || sym->attr.dummy
-			       || sym->attr.subroutine
-			       || sym->attr.pointer
-			       || sym->attr.target
-			       || sym->attr.cray_pointer
-			       || sym->attr.cray_pointee
-			       || (sym->attr.proc != PROC_UNKNOWN
-				   && sym->attr.proc != PROC_INTRINSIC)
-			       || sym->attr.if_source != IFSRC_UNKNOWN
-			       || sym == sym->ns->proc_name)
-			{
-			  sym = NULL;
-			  n = NULL;
-			}
-		      else
-			n = sym->name;
-		    }
-		  if (n == NULL)
-		    rop = OMP_REDUCTION_NONE;
-		  else if (strcmp (n, "max") == 0)
-		    rop = OMP_REDUCTION_MAX;
-		  else if (strcmp (n, "min") == 0)
-		    rop = OMP_REDUCTION_MIN;
-		  else if (strcmp (n, "iand") == 0)
-		    rop = OMP_REDUCTION_IAND;
-		  else if (strcmp (n, "ior") == 0)
-		    rop = OMP_REDUCTION_IOR;
-		  else if (strcmp (n, "ieor") == 0)
-		    rop = OMP_REDUCTION_IEOR;
-		  if (rop != OMP_REDUCTION_NONE
-		      && sym != NULL
-		      && ! sym->attr.intrinsic
-		      && ! sym->attr.use_assoc
-		      && ((sym->attr.flavor == FL_UNKNOWN
-			  && !gfc_add_flavor (&sym->attr, FL_PROCEDURE,
-					      sym->name, NULL))
-			  || !gfc_add_intrinsic (&sym->attr, NULL)))
-		    rop = OMP_REDUCTION_NONE;
-		}
-	      else
-		buffer[0] = '\0';
-	      gfc_omp_udr *udr
-		= (buffer[0]
-		   ? gfc_find_omp_udr (gfc_current_ns, buffer, NULL) : NULL);
-	      gfc_omp_namelist **head = NULL;
-	      if (rop == OMP_REDUCTION_NONE && udr)
-		rop = OMP_REDUCTION_USER;
-
-	      if (gfc_match_omp_variable_list (" :",
-					       &c->lists[OMP_LIST_REDUCTION],
-					       false, NULL, &head, openacc,
-					       allow_derived) == MATCH_YES)
-		{
-		  gfc_omp_namelist *n;
-		  if (rop == OMP_REDUCTION_NONE)
-		    {
-		      n = *head;
-		      *head = NULL;
-		      gfc_error_now ("!$OMP DECLARE REDUCTION %s not found "
-				     "at %L", buffer, &old_loc);
-		      gfc_free_omp_namelist (n);
-		    }
-		  else
-		    for (n = *head; n; n = n->next)
-		      {
-			n->u.reduction_op = rop;
-			if (udr)
-			  {
-			    n->udr = gfc_get_omp_namelist_udr ();
-			    n->udr->udr = udr;
-			  }
-		      }
-		  continue;
-		}
-	      else
-		gfc_current_locus = old_loc;
+	      c->memorder = OMP_MEMORDER_RELAXED;
+	      needs_space = true;
+	      continue;
+	    }
+	  if ((mask & OMP_CLAUSE_MEMORDER)
+	      && c->memorder == OMP_MEMORDER_UNSET
+	      && gfc_match ("release") == MATCH_YES)
+	    {
+	      c->memorder = OMP_MEMORDER_RELEASE;
+	      needs_space = true;
+	      continue;
 	    }
 	  if ((mask & OMP_CLAUSE_MEMORDER)
 	      && c->memorder == OMP_MEMORDER_UNSET
@@ -1962,6 +2038,10 @@ gfc_match_omp_clauses (gfc_omp_clauses **cp, const omp_mask mask,
 	    }
 	  break;
 	case 't':
+	  if ((mask & OMP_CLAUSE_TASK_REDUCTION)
+	      && gfc_match_omp_clause_reduction (pc, mask, c, openacc,
+						 allow_derived) == MATCH_YES)
+	    continue;
 	  if ((mask & OMP_CLAUSE_THREAD_LIMIT)
 	      && c->thread_limit == NULL
 	      && gfc_match ("thread_limit ( %e )",
@@ -2672,42 +2752,44 @@ cleanup:
 
 #define OMP_PARALLEL_CLAUSES \
   (omp_mask (OMP_CLAUSE_PRIVATE) | OMP_CLAUSE_FIRSTPRIVATE		\
-   | OMP_CLAUSE_SHARED | OMP_CLAUSE_COPYIN | OMP_CLAUSE_REDUCTION	\
-   | OMP_CLAUSE_IF | OMP_CLAUSE_NUM_THREADS | OMP_CLAUSE_DEFAULT	\
-   | OMP_CLAUSE_PROC_BIND)
+   | OMP_CLAUSE_SHARED | OMP_CLAUSE_COPYIN | OMP_CLAUSE_IF		\
+   | OMP_CLAUSE_NUM_THREADS | OMP_CLAUSE_DEFAULT | OMP_CLAUSE_PROC_BIND \
+   | OMP_CLAUSE_REDUCTION_MODIFIER)
 #define OMP_DECLARE_SIMD_CLAUSES \
   (omp_mask (OMP_CLAUSE_SIMDLEN) | OMP_CLAUSE_LINEAR			\
    | OMP_CLAUSE_UNIFORM	| OMP_CLAUSE_ALIGNED | OMP_CLAUSE_INBRANCH	\
    | OMP_CLAUSE_NOTINBRANCH)
 #define OMP_DO_CLAUSES \
   (omp_mask (OMP_CLAUSE_PRIVATE) | OMP_CLAUSE_FIRSTPRIVATE		\
-   | OMP_CLAUSE_LASTPRIVATE | OMP_CLAUSE_REDUCTION			\
+   | OMP_CLAUSE_LASTPRIVATE | OMP_CLAUSE_REDUCTION_MODIFIER		\
    | OMP_CLAUSE_SCHEDULE | OMP_CLAUSE_ORDERED | OMP_CLAUSE_COLLAPSE	\
    | OMP_CLAUSE_LINEAR | OMP_CLAUSE_ORDER)
 #define OMP_SECTIONS_CLAUSES \
   (omp_mask (OMP_CLAUSE_PRIVATE) | OMP_CLAUSE_FIRSTPRIVATE		\
-   | OMP_CLAUSE_LASTPRIVATE | OMP_CLAUSE_REDUCTION)
+   | OMP_CLAUSE_LASTPRIVATE | OMP_CLAUSE_REDUCTION_MODIFIER)
 #define OMP_SIMD_CLAUSES \
   (omp_mask (OMP_CLAUSE_PRIVATE) | OMP_CLAUSE_LASTPRIVATE		\
-   | OMP_CLAUSE_REDUCTION | OMP_CLAUSE_COLLAPSE | OMP_CLAUSE_SAFELEN	\
-   | OMP_CLAUSE_LINEAR | OMP_CLAUSE_ALIGNED | OMP_CLAUSE_SIMDLEN	\
-   | OMP_CLAUSE_IF | OMP_CLAUSE_ORDER | OMP_CLAUSE_NOTEMPORAL)
+   | OMP_CLAUSE_REDUCTION_MODIFIER | OMP_CLAUSE_COLLAPSE		\
+   | OMP_CLAUSE_SAFELEN | OMP_CLAUSE_LINEAR | OMP_CLAUSE_ALIGNED	\
+   | OMP_CLAUSE_SIMDLEN	| OMP_CLAUSE_IF | OMP_CLAUSE_ORDER		\
+   | OMP_CLAUSE_NOTEMPORAL)
 #define OMP_TASK_CLAUSES \
   (omp_mask (OMP_CLAUSE_PRIVATE) | OMP_CLAUSE_FIRSTPRIVATE		\
    | OMP_CLAUSE_SHARED | OMP_CLAUSE_IF | OMP_CLAUSE_DEFAULT		\
    | OMP_CLAUSE_UNTIED | OMP_CLAUSE_FINAL | OMP_CLAUSE_MERGEABLE	\
-   | OMP_CLAUSE_DEPEND | OMP_CLAUSE_PRIORITY)
+   | OMP_CLAUSE_DEPEND | OMP_CLAUSE_PRIORITY | OMP_CLAUSE_IN_REDUCTION)
 #define OMP_TASKLOOP_CLAUSES \
   (omp_mask (OMP_CLAUSE_PRIVATE) | OMP_CLAUSE_FIRSTPRIVATE		\
    | OMP_CLAUSE_LASTPRIVATE | OMP_CLAUSE_SHARED | OMP_CLAUSE_IF		\
    | OMP_CLAUSE_DEFAULT | OMP_CLAUSE_UNTIED | OMP_CLAUSE_FINAL		\
    | OMP_CLAUSE_MERGEABLE | OMP_CLAUSE_PRIORITY | OMP_CLAUSE_GRAINSIZE	\
-   | OMP_CLAUSE_NUM_TASKS | OMP_CLAUSE_COLLAPSE | OMP_CLAUSE_NOGROUP)
+   | OMP_CLAUSE_NUM_TASKS | OMP_CLAUSE_COLLAPSE | OMP_CLAUSE_NOGROUP	\
+   | OMP_CLAUSE_REDUCTION_DEFAULT | OMP_CLAUSE_IN_REDUCTION)
 #define OMP_TARGET_CLAUSES \
   (omp_mask (OMP_CLAUSE_DEVICE) | OMP_CLAUSE_MAP | OMP_CLAUSE_IF	\
    | OMP_CLAUSE_DEPEND | OMP_CLAUSE_NOWAIT | OMP_CLAUSE_PRIVATE		\
    | OMP_CLAUSE_FIRSTPRIVATE | OMP_CLAUSE_DEFAULTMAP			\
-   | OMP_CLAUSE_IS_DEVICE_PTR)
+   | OMP_CLAUSE_IS_DEVICE_PTR | OMP_CLAUSE_IN_REDUCTION)
 #define OMP_TARGET_DATA_CLAUSES \
   (omp_mask (OMP_CLAUSE_DEVICE) | OMP_CLAUSE_MAP | OMP_CLAUSE_IF	\
    | OMP_CLAUSE_USE_DEVICE_PTR | OMP_CLAUSE_USE_DEVICE_ADDR)
@@ -2723,7 +2805,7 @@ cleanup:
 #define OMP_TEAMS_CLAUSES \
   (omp_mask (OMP_CLAUSE_NUM_TEAMS) | OMP_CLAUSE_THREAD_LIMIT		\
    | OMP_CLAUSE_DEFAULT | OMP_CLAUSE_PRIVATE | OMP_CLAUSE_FIRSTPRIVATE	\
-   | OMP_CLAUSE_SHARED | OMP_CLAUSE_REDUCTION)
+   | OMP_CLAUSE_SHARED | OMP_CLAUSE_REDUCTION_DEFAULT)
 #define OMP_DISTRIBUTE_CLAUSES \
   (omp_mask (OMP_CLAUSE_PRIVATE) | OMP_CLAUSE_FIRSTPRIVATE		\
    | OMP_CLAUSE_LASTPRIVATE | OMP_CLAUSE_COLLAPSE | OMP_CLAUSE_DIST_SCHEDULE)
@@ -4228,12 +4310,12 @@ gfc_match_omp_barrier (void)
 match
 gfc_match_omp_taskgroup (void)
 {
-  if (gfc_match_omp_eos () != MATCH_YES)
-    {
-      gfc_error ("Unexpected junk after $OMP TASKGROUP statement at %C");
-      return MATCH_ERROR;
-    }
+  gfc_omp_clauses *c;
+  if (gfc_match_omp_clauses (&c, OMP_CLAUSE_TASK_REDUCTION, true, true)
+      != MATCH_YES)
+    return MATCH_ERROR;
   new_st.op = EXEC_OMP_TASKGROUP;
+  new_st.ext.omp_clauses = c;
   return MATCH_YES;
 }
 
@@ -4560,7 +4642,9 @@ resolve_omp_clauses (gfc_code *code, gfc_omp_clauses *omp_clauses,
   static const char *clause_names[]
     = { "PRIVATE", "FIRSTPRIVATE", "LASTPRIVATE", "COPYPRIVATE", "SHARED",
 	"COPYIN", "UNIFORM", "ALIGNED", "LINEAR", "DEPEND", "MAP",
-	"TO", "FROM", "REDUCTION", "DEVICE_RESIDENT", "LINK", "USE_DEVICE",
+	"TO", "FROM", "REDUCTION", "REDUCTION" /*inscan*/, "REDUCTION" /*task*/,
+	"IN_REDUCTION", "TASK_REDUCTION",
+	"DEVICE_RESIDENT", "LINK", "USE_DEVICE",
 	"CACHE", "IS_DEVICE_PTR", "USE_DEVICE_PTR", "USE_DEVICE_ADDR",
 	"NONTEMPORAL" };
   STATIC_ASSERT (ARRAY_SIZE (clause_names) == OMP_LIST_NUM);
@@ -4727,21 +4811,7 @@ resolve_omp_clauses (gfc_code *code, gfc_omp_clauses *omp_clauses,
   if (omp_clauses->sched_kind != OMP_SCHED_NONE
       && omp_clauses->sched_nonmonotonic)
     {
-      if (omp_clauses->sched_kind != OMP_SCHED_DYNAMIC
-	  && omp_clauses->sched_kind != OMP_SCHED_GUIDED)
-	{
-	  const char *p;
-	  switch (omp_clauses->sched_kind)
-	    {
-	    case OMP_SCHED_STATIC: p = "STATIC"; break;
-	    case OMP_SCHED_RUNTIME: p = "RUNTIME"; break;
-	    case OMP_SCHED_AUTO: p = "AUTO"; break;
-	    default: gcc_unreachable ();
-	    }
-	  gfc_error ("NONMONOTONIC modifier specified for %s schedule kind "
-		     "at %L", p, &code->loc);
-	}
-      else if (omp_clauses->sched_monotonic)
+      if (omp_clauses->sched_monotonic)
 	gfc_error ("Both MONOTONIC and NONMONOTONIC schedule modifiers "
 		   "specified at %L", &code->loc);
       else if (omp_clauses->ordered)
@@ -4818,7 +4888,11 @@ resolve_omp_clauses (gfc_code *code, gfc_omp_clauses *omp_clauses,
 	&& (list != OMP_LIST_MAP || openacc)
 	&& list != OMP_LIST_FROM
 	&& list != OMP_LIST_TO
-	&& (list != OMP_LIST_REDUCTION || !openacc))
+	&& (list != OMP_LIST_REDUCTION || !openacc)
+	&& list != OMP_LIST_REDUCTION_INSCAN
+	&& list != OMP_LIST_REDUCTION_TASK
+	&& list != OMP_LIST_IN_REDUCTION
+	&& list != OMP_LIST_TASK_REDUCTION)
       for (n = omp_clauses->lists[list]; n; n = n->next)
 	{
 	  bool component_ref_p = false;
@@ -5224,6 +5298,11 @@ resolve_omp_clauses (gfc_code *code, gfc_omp_clauses *omp_clauses,
 	    for (; n != NULL; n = n->next)
 	      {
 		bool bad = false;
+		bool is_reduction = (list == OMP_LIST_REDUCTION
+				     || list == OMP_LIST_REDUCTION_INSCAN
+				     || list == OMP_LIST_REDUCTION_TASK
+				     || list == OMP_LIST_IN_REDUCTION
+				     || list == OMP_LIST_TASK_REDUCTION);
 		if (n->sym->attr.threadprivate)
 		  gfc_error ("THREADPRIVATE object %qs in %s clause at %L",
 			     n->sym->name, name, &n->where);
@@ -5233,15 +5312,15 @@ resolve_omp_clauses (gfc_code *code, gfc_omp_clauses *omp_clauses,
 		if (n->sym->attr.associate_var)
 		  gfc_error ("ASSOCIATE name %qs in %s clause at %L",
 			     n->sym->name, name, &n->where);
-		if (list != OMP_LIST_PRIVATE)
+		if (list != OMP_LIST_PRIVATE && is_reduction)
 		  {
-		    if (n->sym->attr.proc_pointer && list == OMP_LIST_REDUCTION)
+		    if (n->sym->attr.proc_pointer)
 		      gfc_error ("Procedure pointer %qs in %s clause at %L",
 				 n->sym->name, name, &n->where);
-		    if (n->sym->attr.pointer && list == OMP_LIST_REDUCTION)
+		    if (n->sym->attr.pointer)
 		      gfc_error ("POINTER object %qs in %s clause at %L",
 				 n->sym->name, name, &n->where);
-		    if (n->sym->attr.cray_pointer && list == OMP_LIST_REDUCTION)
+		    if (n->sym->attr.cray_pointer)
 		      gfc_error ("Cray pointer %qs in %s clause at %L",
 				 n->sym->name, name, &n->where);
 		  }
@@ -5253,7 +5332,7 @@ resolve_omp_clauses (gfc_code *code, gfc_omp_clauses *omp_clauses,
 		else if (n->sym->as && n->sym->as->type == AS_ASSUMED_SIZE)
 		  gfc_error ("Assumed size array %qs in %s clause at %L",
 			     n->sym->name, name, &n->where);
-		if (n->sym->attr.in_namelist && list != OMP_LIST_REDUCTION)
+		if (n->sym->attr.in_namelist && !is_reduction)
 		  gfc_error ("Variable %qs in %s clause is used in "
 			     "NAMELIST statement at %L",
 			     n->sym->name, name, &n->where);
@@ -5274,6 +5353,10 @@ resolve_omp_clauses (gfc_code *code, gfc_omp_clauses *omp_clauses,
 		switch (list)
 		  {
 		  case OMP_LIST_REDUCTION:
+		  case OMP_LIST_REDUCTION_INSCAN:
+		  case OMP_LIST_REDUCTION_TASK:
+		  case OMP_LIST_IN_REDUCTION:
+		  case OMP_LIST_TASK_REDUCTION:
 		    switch (n->u.reduction_op)
 		      {
 		      case OMP_REDUCTION_PLUS:
@@ -6102,6 +6185,10 @@ gfc_resolve_omp_parallel_blocks (gfc_code *code, gfc_namespace *ns)
       case OMP_LIST_FIRSTPRIVATE:
       case OMP_LIST_LASTPRIVATE:
       case OMP_LIST_REDUCTION:
+      case OMP_LIST_REDUCTION_INSCAN:
+      case OMP_LIST_REDUCTION_TASK:
+      case OMP_LIST_IN_REDUCTION:
+      case OMP_LIST_TASK_REDUCTION:
       case OMP_LIST_LINEAR:
 	for (n = omp_clauses->lists[list]; n; n = n->next)
 	  ctx.sharing_clauses->add (n->sym);
diff --git a/gcc/fortran/trans-openmp.c b/gcc/fortran/trans-openmp.c
index 1d652a09f9d..d2559bd0c0a 100644
--- a/gcc/fortran/trans-openmp.c
+++ b/gcc/fortran/trans-openmp.c
@@ -626,6 +626,8 @@ gfc_omp_clause_default_ctor (tree clause, tree decl, tree outer)
     case OMP_CLAUSE_LASTPRIVATE:
     case OMP_CLAUSE_LINEAR:
     case OMP_CLAUSE_REDUCTION:
+    case OMP_CLAUSE_IN_REDUCTION:
+    case OMP_CLAUSE_TASK_REDUCTION:
       break;
     default:
       gcc_unreachable ();
@@ -699,7 +701,9 @@ gfc_omp_clause_default_ctor (tree clause, tree decl, tree outer)
   then_b = gfc_finish_block (&cond_block);
 
   /* Reduction clause requires allocated ALLOCATABLE.  */
-  if (OMP_CLAUSE_CODE (clause) != OMP_CLAUSE_REDUCTION)
+  if (OMP_CLAUSE_CODE (clause) != OMP_CLAUSE_REDUCTION
+      && OMP_CLAUSE_CODE (clause) != OMP_CLAUSE_IN_REDUCTION
+      && OMP_CLAUSE_CODE (clause) != OMP_CLAUSE_TASK_REDUCTION)
     {
       gfc_init_block (&cond_block);
       if (GFC_DESCRIPTOR_TYPE_P (type))
@@ -2029,9 +2033,25 @@ gfc_trans_omp_array_reduction_or_udr (tree c, gfc_omp_namelist *n, locus where)
 }
 
 static tree
-gfc_trans_omp_reduction_list (gfc_omp_namelist *namelist, tree list,
+gfc_trans_omp_reduction_list (int kind, gfc_omp_namelist *namelist, tree list,
 			      locus where, bool mark_addressable)
 {
+  omp_clause_code clause = OMP_CLAUSE_REDUCTION;
+  switch (kind)
+    {
+    case OMP_LIST_REDUCTION:
+    case OMP_LIST_REDUCTION_INSCAN:
+    case OMP_LIST_REDUCTION_TASK:
+      break;
+    case OMP_LIST_IN_REDUCTION:
+      clause = OMP_CLAUSE_IN_REDUCTION;
+      break;
+    case OMP_LIST_TASK_REDUCTION:
+      clause = OMP_CLAUSE_TASK_REDUCTION;
+      break;
+    default:
+      gcc_unreachable ();
+    }
   for (; namelist != NULL; namelist = namelist->next)
     if (namelist->sym->attr.referenced)
       {
@@ -2039,10 +2059,14 @@ gfc_trans_omp_reduction_list (gfc_omp_namelist *namelist, tree list,
 	if (t != error_mark_node)
 	  {
 	    tree node = build_omp_clause (gfc_get_location (&namelist->where),
-					  OMP_CLAUSE_REDUCTION);
+					  clause);
 	    OMP_CLAUSE_DECL (node) = t;
 	    if (mark_addressable)
 	      TREE_ADDRESSABLE (t) = 1;
+	    if (kind == OMP_LIST_REDUCTION_INSCAN)
+	      OMP_CLAUSE_REDUCTION_INSCAN (node) = 1;
+	    if (kind == OMP_LIST_REDUCTION_TASK)
+	      OMP_CLAUSE_REDUCTION_TASK (node) = 1;
 	    switch (namelist->u.reduction_op)
 	      {
 	      case OMP_REDUCTION_PLUS:
@@ -2267,10 +2291,14 @@ gfc_trans_omp_clauses (stmtblock_t *block, gfc_omp_clauses *clauses,
       switch (list)
 	{
 	case OMP_LIST_REDUCTION:
+	case OMP_LIST_REDUCTION_INSCAN:
+	case OMP_LIST_REDUCTION_TASK:
+	case OMP_LIST_IN_REDUCTION:
+	case OMP_LIST_TASK_REDUCTION:
 	  /* An OpenACC async clause indicates the need to set reduction
 	     arguments addressable, to allow asynchronous copy-out.  */
-	  omp_clauses = gfc_trans_omp_reduction_list (n, omp_clauses, where,
-						      clauses->async);
+	  omp_clauses = gfc_trans_omp_reduction_list (list, n, omp_clauses,
+						      where, clauses->async);
 	  break;
 	case OMP_LIST_PRIVATE:
 	  clause_code = OMP_CLAUSE_PRIVATE;
@@ -5207,18 +5235,27 @@ gfc_split_omp_clauses (gfc_code *code,
       /* Reduction is allowed on simd, do, parallel and teams.
 	 Duplicate it on all of them, but omit on do if
 	 parallel is present.  */
-      if (mask & GFC_OMP_MASK_TEAMS)
-	clausesa[GFC_OMP_SPLIT_TEAMS].lists[OMP_LIST_REDUCTION]
-	  = code->ext.omp_clauses->lists[OMP_LIST_REDUCTION];
-      if (mask & GFC_OMP_MASK_PARALLEL)
-	clausesa[GFC_OMP_SPLIT_PARALLEL].lists[OMP_LIST_REDUCTION]
-	  = code->ext.omp_clauses->lists[OMP_LIST_REDUCTION];
-      else if (mask & GFC_OMP_MASK_DO)
-	clausesa[GFC_OMP_SPLIT_DO].lists[OMP_LIST_REDUCTION]
-	  = code->ext.omp_clauses->lists[OMP_LIST_REDUCTION];
-      if (mask & GFC_OMP_MASK_SIMD)
-	clausesa[GFC_OMP_SPLIT_SIMD].lists[OMP_LIST_REDUCTION]
-	  = code->ext.omp_clauses->lists[OMP_LIST_REDUCTION];
+      for (int i = OMP_LIST_REDUCTION; i <= OMP_LIST_REDUCTION_TASK; i++)
+	{
+	  if (mask & GFC_OMP_MASK_TEAMS)
+	    clausesa[GFC_OMP_SPLIT_TEAMS].lists[i]
+	      = code->ext.omp_clauses->lists[i];
+	  if (mask & GFC_OMP_MASK_PARALLEL)
+	    clausesa[GFC_OMP_SPLIT_PARALLEL].lists[i]
+	      = code->ext.omp_clauses->lists[i];
+	  else if (mask & GFC_OMP_MASK_DO)
+	    clausesa[GFC_OMP_SPLIT_DO].lists[i]
+	      = code->ext.omp_clauses->lists[i];
+	  if (mask & GFC_OMP_MASK_SIMD)
+	    clausesa[GFC_OMP_SPLIT_SIMD].lists[i]
+	      = code->ext.omp_clauses->lists[i];
+	}
+      if (mask & GFC_OMP_MASK_TARGET)
+	clausesa[GFC_OMP_SPLIT_TARGET].lists[OMP_LIST_IN_REDUCTION]
+	  = code->ext.omp_clauses->lists[OMP_LIST_IN_REDUCTION];
+      if (mask & GFC_OMP_MASK_TASKLOOP)
+	clausesa[GFC_OMP_SPLIT_TASKLOOP].lists[OMP_LIST_IN_REDUCTION]
+	  = code->ext.omp_clauses->lists[OMP_LIST_IN_REDUCTION];
       /* Linear clause is supported on do and simd,
 	 put it on the innermost one.  */
       clausesa[innermost].lists[OMP_LIST_LINEAR]
diff --git a/gcc/gimplify.c b/gcc/gimplify.c
index aa3b914f6e5..23892d58666 100644
--- a/gcc/gimplify.c
+++ b/gcc/gimplify.c
@@ -8559,7 +8559,8 @@ gimplify_scan_omp_clauses (tree *list_p, gimple_seq *pre_p,
 		{
 		  error_at (OMP_CLAUSE_LOCATION (c),
 			    "invalid %<task%> reduction modifier on construct "
-			    "other than %<parallel%>, %<for%> or %<sections%>");
+			    "other than %<parallel%>, %qs or %<sections%>",
+			    lang_GNU_Fortran () ? "do" : "for");
 		  OMP_CLAUSE_REDUCTION_TASK (c) = 0;
 		}
 	    }
@@ -12521,7 +12522,8 @@ gimplify_omp_loop (tree *expr_p, gimple_seq *pre_p)
 	  {
 	    error_at (OMP_CLAUSE_LOCATION (*pc),
 		      "invalid %<task%> reduction modifier on construct "
-		      "other than %<parallel%>, %<for%> or %<sections%>");
+		      "other than %<parallel%>, %qs or %<sections%>",
+		      lang_GNU_Fortran () ? "do" : "for");
 	    OMP_CLAUSE_REDUCTION_TASK (*pc) = 0;
 	  }
 	pc = &OMP_CLAUSE_CHAIN (*pc);
diff --git a/gcc/omp-low.c b/gcc/omp-low.c
index ea9008b61c4..71277968ee3 100644
--- a/gcc/omp-low.c
+++ b/gcc/omp-low.c
@@ -2881,7 +2881,8 @@ check_omp_nesting_restrictions (gimple *stmt, omp_context *ctx)
 		    {
 		      error_at (gimple_location (stmt),
 				"%<ordered simd threads%> must be closely "
-				"nested inside of %<for simd%> region");
+				"nested inside of %<%s simd%> region",
+				lang_GNU_Fortran () ? "do" : "for");
 		      return false;
 		    }
 		  return true;
diff --git a/gcc/testsuite/gfortran.dg/gomp/reduction4.f90 b/gcc/testsuite/gfortran.dg/gomp/reduction4.f90
new file mode 100644
index 00000000000..af8c91b2a87
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/gomp/reduction4.f90
@@ -0,0 +1,171 @@
+! { dg-do compile }
+! { dg-additional-options "-fdump-tree-original" }
+!
+! (in_)reduction clause
+! Test all in-principle valid combinations, even if
+! not valid in this context (some fail at ME level)
+!
+implicit none
+integer :: a, b, i
+a = 0
+
+! ------------ parallel ------------
+!$omp parallel reduction(+:a)
+do i=1,10
+  a = a + 1
+end do
+!$omp end parallel
+
+!$omp parallel reduction(default,+:a)
+do i=1,10
+  a = a + 1
+end do
+!$omp end parallel
+
+!$omp parallel reduction(task,+:a)
+do i=1,10
+  a = a + 1
+end do
+!$omp end parallel
+
+!$omp parallel reduction(inscan,+:a)  ! { dg-error "'inscan' 'reduction' clause on 'parallel' construct" }
+do i=1,10
+  a = a + 1
+end do
+!$omp end parallel
+
+! ------------ simd ------------
+!$omp simd reduction(+:a)
+do i=1,10
+  a = a + 1
+end do
+
+!$omp simd reduction(default,+:a)
+do i=1,10
+  a = a + 1
+end do
+
+!$omp simd reduction(task,+:a)  ! { dg-error "invalid 'task' reduction modifier on construct other than 'parallel', 'do' or 'sections'" }
+do i=1,10
+  a = a + 1
+end do
+
+!$omp simd reduction(inscan,+:a)  ! { dg-error "'inscan' 'reduction' clause but not in 'scan' directive clause" }
+do i=1,10
+  a = a + 1
+end do
+
+! ------------ do ------------
+!$omp parallel
+!$omp do reduction(+:a)
+do i=1,10
+  a = a + 1
+end do
+!$omp end parallel
+
+!$omp parallel
+!$omp do reduction(default,+:a)
+do i=1,10
+  a = a + 1
+end do
+!$omp end parallel
+
+!$omp parallel
+!$omp do reduction(task,+:a)
+do i=1,10
+  a = a + 1
+end do
+!$omp end parallel
+
+!$omp parallel
+!$omp do reduction(inscan,+:a)  ! { dg-error "'a' specified in 'inscan' 'reduction' clause but not in 'scan' directive clause" }
+do i=1,10
+  a = a + 1
+end do
+!$omp end parallel
+
+! ------------ section ------------
+!$omp parallel
+!$omp sections reduction(+:a)
+  !$omp section
+  a = a + 1
+!$omp end sections
+!$omp end parallel
+
+!$omp parallel
+!$omp sections reduction(default,+:a)
+  !$omp section
+  a = a + 1
+!$omp end sections
+!$omp end parallel
+
+!$omp parallel
+!$omp sections reduction(task,+:a)
+  !$omp section
+  a = a + 1
+!$omp end sections
+!$omp end parallel
+
+!$omp parallel
+!$omp sections reduction(inscan,+:a)  ! { dg-error "'inscan' 'reduction' clause on 'sections' construct" }
+  !$omp section
+  a = a + 1
+!$omp end sections
+!$omp end parallel
+
+! ------------ task ------------
+!$omp task in_reduction(+:a)
+  a = a + 1
+!$omp end task
+
+! ------------ taskloop ------------
+!$omp taskloop reduction(+:a) in_reduction(+:b)
+do i=1,10
+  a = a + 1
+end do
+
+!$omp taskloop reduction(default,+:a) in_reduction(+:b)
+do i=1,10
+  a = a + 1
+end do
+
+! ------------ target ------------
+!$omp target in_reduction(+:b)
+  a = a + 1
+!$omp end target
+
+! ------------ teams ------------
+!$omp teams reduction(+:b)
+  a = a + 1
+!$omp end teams
+
+!$omp teams reduction(default, +:b)
+  a = a + 1
+!$omp end teams
+
+! ------------ taskgroup --------
+
+!$omp taskgroup task_reduction(+:b)
+  a = a + 1
+!$omp end taskgroup
+
+end
+
+! { dg-final { scan-tree-dump-times "#pragma omp for reduction\\(\\\+:a\\)" 2 "original" } }
+! { dg-final { scan-tree-dump-times "#pragma omp for reduction\\(inscan,\\\+:a\\)" 1 "original" } }
+! { dg-final { scan-tree-dump-times "#pragma omp for reduction\\(task,\\\+:a\\)" 1 "original" } }
+! { dg-final { scan-tree-dump-times "#pragma omp parallel\[\n\r\]" 8 "original" } }
+! { dg-final { scan-tree-dump-times "#pragma omp parallel private\\(i\\) reduction\\(\\\+:a\\)" 2 "original" } }
+! { dg-final { scan-tree-dump-times "#pragma omp parallel private\\(i\\) reduction\\(inscan,\\\+:a\\)" 1 "original" } }
+! { dg-final { scan-tree-dump-times "#pragma omp parallel private\\(i\\) reduction\\(task,\\\+:a\\)" 1 "original" } }
+! { dg-final { scan-tree-dump-times "#pragma omp section\[\n\r\]" 4 "original" } }
+! { dg-final { scan-tree-dump-times "#pragma omp sections reduction\\(\\\+:a\\)" 2 "original" } }
+! { dg-final { scan-tree-dump-times "#pragma omp sections reduction\\(inscan,\\\+:a\\)" 1 "original" } }
+! { dg-final { scan-tree-dump-times "#pragma omp sections reduction\\(task,\\\+:a\\)" 1 "original" } }
+! { dg-final { scan-tree-dump-times "#pragma omp simd linear\\(i:1\\) reduction\\(\\\+:a\\)" 2 "original" } }
+! { dg-final { scan-tree-dump-times "#pragma omp simd linear\\(i:1\\) reduction\\(inscan,\\\+:a\\)" 1 "original" } }
+! { dg-final { scan-tree-dump-times "#pragma omp simd linear\\(i:1\\) reduction\\(task,\\\+:a\\)" 1 "original" } }
+! { dg-final { scan-tree-dump-times "#pragma omp target in_reduction\\(\\\+:b\\)" 1 "original" } }
+! { dg-final { scan-tree-dump-times "#pragma omp task in_reduction\\(\\\+:a\\)" 1 "original" } }
+! { dg-final { scan-tree-dump-times "#pragma omp teams reduction\\(\\\+:b\\)" 2 "original" } }
+! { dg-final { scan-tree-dump-times "#pragma omp taskloop reduction\\(\\\+:a\\) in_reduction\\(\\\+:b\\)" 2 "original" } }
diff --git a/gcc/testsuite/gfortran.dg/gomp/reduction5.f90 b/gcc/testsuite/gfortran.dg/gomp/reduction5.f90
new file mode 100644
index 00000000000..e8c2c5f017d
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/gomp/reduction5.f90
@@ -0,0 +1,41 @@
+! { dg-do compile }
+!
+implicit none
+integer :: a, b, i
+a = 0
+
+!$omp parallel reduction(foo,+:a)  ! { dg-error "26: Failed to match clause" }
+do i=1,10
+  a = a + 1
+end do
+!$omp end parallel  ! { dg-error "Unexpected !.OMP END PARALLEL statement" }
+
+!$omp parallel reduction(task +:a) ! { dg-error "30: Comma expected at" }
+do i=1,10
+  a = a + 1
+end do
+!$omp end parallel  ! { dg-error "Unexpected !.OMP END PARALLEL statement" }
+
+!$omp task in_reduction(foo,+:a)  ! { dg-error "25: Failed to match clause" }
+  a = a + 1
+!$omp end task  ! { dg-error "Unexpected !.OMP END TASK statement" }
+
+!$omp taskloop reduction(inscan,+:a) in_reduction(+:b) ! { dg-error "33: Reduction-modifier shall be 'default'" }
+do i=1,10
+  a = a + 1
+end do
+
+!$omp taskloop reduction(task,+:a) in_reduction(+:b) ! { dg-error "31: Reduction-modifier shall be 'default'" }
+do i=1,10
+  a = a + 1
+end do
+
+!$omp teams reduction(inscan,+:b) ! { dg-error "30: Reduction-modifier shall be 'default'" }
+  a = a + 1
+!$omp end teams  ! { dg-error "Unexpected !.OMP END TEAMS statement" }
+
+!$omp teams reduction(task, +:b) ! { dg-error "29: Reduction-modifier shall be 'default'" }
+  a = a + 1
+!$omp end teams  ! { dg-error "Unexpected !.OMP END TEAMS statement" }
+
+end
diff --git a/gcc/testsuite/gfortran.dg/gomp/schedule-modifiers-2.f90 b/gcc/testsuite/gfortran.dg/gomp/schedule-modifiers-2.f90
index 0be53cc71a5..537fba23c11 100644
--- a/gcc/testsuite/gfortran.dg/gomp/schedule-modifiers-2.f90
+++ b/gcc/testsuite/gfortran.dg/gomp/schedule-modifiers-2.f90
@@ -3,16 +3,16 @@
 
 subroutine foo
   integer :: i
-  !$omp do schedule (nonmonotonic: static, 2)	! { dg-error "NONMONOTONIC modifier specified for STATIC schedule kind" }
+  !$omp do schedule (nonmonotonic: static, 2)
   do i = 0, 64
   end do
-  !$omp do schedule (nonmonotonic : static)	! { dg-error "NONMONOTONIC modifier specified for STATIC schedule kind" }
+  !$omp do schedule (nonmonotonic : static)
   do i = 0, 64
   end do
-  !$omp do schedule (nonmonotonic : runtime)	! { dg-error "NONMONOTONIC modifier specified for RUNTIME schedule kind" }
+  !$omp do schedule (nonmonotonic : runtime)
   do i = 0, 64
   end do
-  !$omp do schedule (nonmonotonic : auto)	! { dg-error "NONMONOTONIC modifier specified for AUTO schedule kind" }
+  !$omp do schedule (nonmonotonic : auto)
   do i = 0, 64
   end do
   !$omp do schedule (nonmonotonic : dynamic) ordered	! { dg-error "NONMONOTONIC schedule modifier specified with ORDERED clause" }
diff --git a/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-1.f90 b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-1.f90
new file mode 100644
index 00000000000..3e639d2e74b
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-1.f90
@@ -0,0 +1,31 @@
+! { dg-do compile }
+! { dg-options "-O2 -fopenmp -fdump-tree-optimized" }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_start \[^\n\r]*, 0, 0, " 1 "optimized" } }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_end " 1 "optimized" } }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_maybe_nonmonotonic_runtime_next " 1 "optimized" } }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_workshare_task_reduction_unregister \\(0\\)" 1 "optimized" } }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_parallel " 1 "optimized" } }
+
+module m
+  implicit none (type, external)
+  integer :: j
+  interface
+    subroutine bar(i)
+      integer :: i
+    end subroutine
+  end interface
+end module m
+
+subroutine foo(a, b, c)
+  use m
+  implicit none (type, external)
+  integer :: a, b ,c
+  integer :: i
+  !$omp parallel
+  !$omp do reduction (task, *: j) schedule (runtime)
+  do i = a, b, c
+    j = j + 1
+    call bar (j)
+  end do
+  !$omp end parallel
+end
diff --git a/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-10.f90 b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-10.f90
new file mode 100644
index 00000000000..e71ac3f41a7
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-10.f90
@@ -0,0 +1,31 @@
+! { dg-do compile }
+! { dg-options "-O2 -fopenmp -fdump-tree-optimized" }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_start \[^\n\r]*, (?:2147483649|-2147483647), 0, 0B, 0B, " 1 "optimized" } }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_end " 1 "optimized" } }
+! { dg-final { scan-tree-dump-not "__builtin_GOMP_loop\[^\n\r]*_next " "optimized" } }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_workshare_task_reduction_unregister \\(0\\)" 1 "optimized" } }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_parallel " 1 "optimized" } }
+
+module m
+  implicit none (type, external)
+  integer :: j
+  interface
+    subroutine bar(i)
+      integer :: i
+    end subroutine
+  end interface
+end module m
+
+subroutine foo(a, b, c)
+  use m
+  implicit none (type, external)
+  integer :: a, b ,c
+  integer :: i
+  !$omp parallel
+  !$omp do reduction (task, *: j) schedule (nonmonotonic: static, 2)
+  do i = a, b, c
+    j = j + 1
+    call bar (j)
+  end do
+  !$omp end parallel
+end
diff --git a/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-11.f90 b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-11.f90
new file mode 100644
index 00000000000..94202200ca1
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-11.f90
@@ -0,0 +1,31 @@
+! { dg-do compile }
+! { dg-options "-O2 -fopenmp -fdump-tree-optimized" }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_start \[^\n\r]*, 2, 1, " 1 "optimized" } }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_end " 1 "optimized" } }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_nonmonotonic_dynamic_next " 1 "optimized" } }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_workshare_task_reduction_unregister \\(0\\)" 1 "optimized" } }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_parallel " 1 "optimized" } }
+
+module m
+  implicit none (type, external)
+  integer :: j
+  interface
+    subroutine bar(i)
+      integer :: i
+    end subroutine
+  end interface
+end module m
+
+subroutine foo(a, b, c)
+  use m
+  implicit none (type, external)
+  integer :: a, b ,c
+  integer :: i
+  !$omp parallel
+  !$omp do reduction (task, *: j) schedule (dynamic)
+  do i = a, b, c
+    j = j + 1
+    call bar (j)
+  end do
+  !$omp end parallel
+end
diff --git a/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-12.f90 b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-12.f90
new file mode 100644
index 00000000000..66c6eb1cae0
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-12.f90
@@ -0,0 +1,31 @@
+! { dg-do compile }
+! { dg-options "-O2 -fopenmp -fdump-tree-optimized" }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_start \[^\n\r]*, (?:2147483650|-2147483646), 1, " 1 "optimized" } }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_end " 1 "optimized" } }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_dynamic_next " 1 "optimized" } }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_workshare_task_reduction_unregister \\(0\\)" 1 "optimized" } }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_parallel " 1 "optimized" } }
+
+module m
+  implicit none (type, external)
+  integer :: j
+  interface
+    subroutine bar(i)
+      integer :: i
+    end subroutine
+  end interface
+end module m
+
+subroutine foo(a, b, c)
+  use m
+  implicit none (type, external)
+  integer :: a, b ,c
+  integer :: i
+  !$omp parallel
+  !$omp do reduction (task, *: j) schedule (monotonic: dynamic)
+  do i = a, b, c
+    j = j + 1
+    call bar (j)
+  end do
+  !$omp end parallel
+end
diff --git a/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-13.f90 b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-13.f90
new file mode 100644
index 00000000000..89782d299fd
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-13.f90
@@ -0,0 +1,31 @@
+! { dg-do compile }
+! { dg-options "-O2 -fopenmp -fdump-tree-optimized" }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_start \[^\n\r]*, 2, 1, " 1 "optimized" } }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_end " 1 "optimized" } }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_nonmonotonic_dynamic_next " 1 "optimized" } }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_workshare_task_reduction_unregister \\(0\\)" 1 "optimized" } }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_parallel " 1 "optimized" } }
+
+module m
+  implicit none (type, external)
+  integer :: j
+  interface
+    subroutine bar(i)
+      integer :: i
+    end subroutine
+  end interface
+end module m
+
+subroutine foo(a, b, c)
+  use m
+  implicit none (type, external)
+  integer :: a, b ,c
+  integer :: i
+  !$omp parallel
+  !$omp do reduction (task, *: j) schedule (nonmonotonic: dynamic)
+  do i = a, b, c
+    j = j + 1
+    call bar (j)
+  end do
+  !$omp end parallel
+end
diff --git a/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-14.f90 b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-14.f90
new file mode 100644
index 00000000000..16b3e01b891
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-14.f90
@@ -0,0 +1,31 @@
+! { dg-do compile }
+! { dg-options "-O2 -fopenmp -fdump-tree-optimized" }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_start \[^\n\r]*, 2, 3, " 1 "optimized" } }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_end " 1 "optimized" } }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_nonmonotonic_dynamic_next " 1 "optimized" } }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_workshare_task_reduction_unregister \\(0\\)" 1 "optimized" } }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_parallel " 1 "optimized" } }
+
+module m
+  implicit none (type, external)
+  integer :: j
+  interface
+    subroutine bar(i)
+      integer :: i
+    end subroutine
+  end interface
+end module m
+
+subroutine foo(a, b, c)
+  use m
+  implicit none (type, external)
+  integer :: a, b ,c
+  integer :: i
+  !$omp parallel
+  !$omp do reduction (task, *: j) schedule (dynamic, 3)
+  do i = a, b, c
+    j = j + 1
+    call bar (j)
+  end do
+  !$omp end parallel
+end
diff --git a/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-15.f90 b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-15.f90
new file mode 100644
index 00000000000..8bf126c5ea7
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-15.f90
@@ -0,0 +1,31 @@
+! { dg-do compile }
+! { dg-options "-O2 -fopenmp -fdump-tree-optimized" }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_start \[^\n\r]*, (?:2147483650|-2147483646), 3, " 1 "optimized" } }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_end " 1 "optimized" } }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_dynamic_next " 1 "optimized" } }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_workshare_task_reduction_unregister \\(0\\)" 1 "optimized" } }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_parallel " 1 "optimized" } }
+
+module m
+  implicit none (type, external)
+  integer :: j
+  interface
+    subroutine bar(i)
+      integer :: i
+    end subroutine
+  end interface
+end module m
+
+subroutine foo(a, b, c)
+  use m
+  implicit none (type, external)
+  integer :: a, b ,c
+  integer :: i
+  !$omp parallel
+  !$omp do reduction (task, *: j) schedule (monotonic: dynamic, 3)
+  do i = a, b, c
+    j = j + 1
+    call bar (j)
+  end do
+  !$omp end parallel
+end
diff --git a/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-16.f90 b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-16.f90
new file mode 100644
index 00000000000..fe8d1ae2124
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-16.f90
@@ -0,0 +1,31 @@
+! { dg-do compile }
+! { dg-options "-O2 -fopenmp -fdump-tree-optimized" }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_start \[^\n\r]*, 2, 3, " 1 "optimized" } }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_end " 1 "optimized" } }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_nonmonotonic_dynamic_next " 1 "optimized" } }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_workshare_task_reduction_unregister \\(0\\)" 1 "optimized" } }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_parallel " 1 "optimized" } }
+
+module m
+  implicit none (type, external)
+  integer :: j
+  interface
+    subroutine bar(i)
+      integer :: i
+    end subroutine
+  end interface
+end module m
+
+subroutine foo(a, b, c)
+  use m
+  implicit none (type, external)
+  integer :: a, b ,c
+  integer :: i
+  !$omp parallel
+  !$omp do reduction (task, *: j) schedule (nonmonotonic: dynamic, 3)
+  do i = a, b, c
+    j = j + 1
+    call bar (j)
+  end do
+  !$omp end parallel
+end
diff --git a/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-17.f90 b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-17.f90
new file mode 100644
index 00000000000..1f2823dd724
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-17.f90
@@ -0,0 +1,31 @@
+! { dg-do compile }
+! { dg-options "-O2 -fopenmp -fdump-tree-optimized" }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_start \[^\n\r]*, 3, 1, " 1 "optimized" } }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_end " 1 "optimized" } }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_nonmonotonic_guided_next " 1 "optimized" } }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_workshare_task_reduction_unregister \\(0\\)" 1 "optimized" } }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_parallel " 1 "optimized" } }
+
+module m
+  implicit none (type, external)
+  integer :: j
+  interface
+    subroutine bar(i)
+      integer :: i
+    end subroutine
+  end interface
+end module m
+
+subroutine foo(a, b, c)
+  use m
+  implicit none (type, external)
+  integer :: a, b ,c
+  integer :: i
+  !$omp parallel
+  !$omp do reduction (task, *: j) schedule (guided)
+  do i = a, b, c
+    j = j + 1
+    call bar (j)
+  end do
+  !$omp end parallel
+end
diff --git a/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-18.f90 b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-18.f90
new file mode 100644
index 00000000000..ad0856a6fe7
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-18.f90
@@ -0,0 +1,31 @@
+! { dg-do compile }
+! { dg-options "-O2 -fopenmp -fdump-tree-optimized" }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_start \[^\n\r]*, (?:2147483651|-2147483645), 1, " 1 "optimized" } }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_end " 1 "optimized" } } 
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_guided_next " 1 "optimized" } }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_workshare_task_reduction_unregister \\(0\\)" 1 "optimized" } }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_parallel " 1 "optimized" } }
+
+module m
+  implicit none (type, external)
+  integer :: j
+  interface
+    subroutine bar(i)
+      integer :: i
+    end subroutine
+  end interface
+end module m
+
+subroutine foo(a, b, c)
+  use m
+  implicit none (type, external)
+  integer :: a, b ,c
+  integer :: i
+  !$omp parallel
+  !$omp do reduction (task, *: j) schedule (monotonic: guided)
+  do i = a, b, c
+    j = j + 1
+    call bar (j)
+  end do
+  !$omp end parallel
+end
diff --git a/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-19.f90 b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-19.f90
new file mode 100644
index 00000000000..e884dbf037c
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-19.f90
@@ -0,0 +1,31 @@
+! { dg-do compile }
+! { dg-options "-O2 -fopenmp -fdump-tree-optimized" }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_start \[^\n\r]*, 3, 1, " 1 "optimized" } }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_end " 1 "optimized" } }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_nonmonotonic_guided_next " 1 "optimized" } }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_workshare_task_reduction_unregister \\(0\\)" 1 "optimized" } }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_parallel " 1 "optimized" } }
+
+module m
+  implicit none (type, external)
+  integer :: j
+  interface
+    subroutine bar(i)
+      integer :: i
+    end subroutine
+  end interface
+end module m
+
+subroutine foo(a, b, c)
+  use m
+  implicit none (type, external)
+  integer :: a, b ,c
+  integer :: i
+  !$omp parallel
+  !$omp do reduction (task, *: j) schedule (nonmonotonic: guided)
+  do i = a, b, c
+    j = j + 1
+    call bar (j)
+  end do
+  !$omp end parallel
+end
diff --git a/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-2.f90 b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-2.f90
new file mode 100644
index 00000000000..2f78c0be4b3
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-2.f90
@@ -0,0 +1,31 @@
+! { dg-do compile }
+! { dg-options "-O2 -fopenmp -fdump-tree-optimized" }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_start \[^\n\r]*, (?:2147483648|-2147483648), 0, " 1 "optimized" } }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_end " 1 "optimized" } }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_runtime_next " 1 "optimized" } }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_workshare_task_reduction_unregister \\(0\\)" 1 "optimized" } }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_parallel " 1 "optimized" } }
+
+module m
+  implicit none (type, external)
+  integer :: j
+  interface
+    subroutine bar(i)
+      integer :: i
+    end subroutine
+  end interface
+end module m
+
+subroutine foo(a, b, c)
+  use m
+  implicit none (type, external)
+  integer :: a, b ,c
+  integer :: i
+  !$omp parallel
+  !$omp do reduction (task, *: j) schedule (monotonic: runtime)
+  do i = a, b, c
+    j = j + 1
+    call bar (j)
+  end do
+  !$omp end parallel
+end
diff --git a/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-20.f90 b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-20.f90
new file mode 100644
index 00000000000..8a4d6dfe4df
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-20.f90
@@ -0,0 +1,31 @@
+! { dg-do compile }
+! { dg-options "-O2 -fopenmp -fdump-tree-optimized" }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_start \[^\n\r]*, 3, 3, " 1 "optimized" } }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_end " 1 "optimized" } }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_nonmonotonic_guided_next " 1 "optimized" } }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_workshare_task_reduction_unregister \\(0\\)" 1 "optimized" } }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_parallel " 1 "optimized" } }
+
+module m
+  implicit none (type, external)
+  integer :: j
+  interface
+    subroutine bar(i)
+      integer :: i
+    end subroutine
+  end interface
+end module m
+
+subroutine foo(a, b, c)
+  use m
+  implicit none (type, external)
+  integer :: a, b ,c
+  integer :: i
+  !$omp parallel
+  !$omp do reduction (task, *: j) schedule (guided, 3)
+  do i = a, b, c
+    j = j + 1
+    call bar (j)
+  end do
+  !$omp end parallel
+end
diff --git a/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-21.f90 b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-21.f90
new file mode 100644
index 00000000000..2d9362b751f
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-21.f90
@@ -0,0 +1,31 @@
+! { dg-do compile }
+! { dg-options "-O2 -fopenmp -fdump-tree-optimized" }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_start \[^\n\r]*, (?:2147483651|-2147483645), 3, " 1 "optimized" } }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_end " 1 "optimized" } }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_guided_next " 1 "optimized" } }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_workshare_task_reduction_unregister \\(0\\)" 1 "optimized" } }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_parallel " 1 "optimized" } }
+
+module m
+  implicit none (type, external)
+  integer :: j
+  interface
+    subroutine bar(i)
+      integer :: i
+    end subroutine
+  end interface
+end module m
+
+subroutine foo(a, b, c)
+  use m
+  implicit none (type, external)
+  integer :: a, b ,c
+  integer :: i
+  !$omp parallel
+  !$omp do reduction (task, *: j) schedule (monotonic: guided, 3)
+  do i = a, b, c
+    j = j + 1
+    call bar (j)
+  end do
+  !$omp end parallel
+end
diff --git a/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-22.f90 b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-22.f90
new file mode 100644
index 00000000000..485171fd481
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-22.f90
@@ -0,0 +1,31 @@
+! { dg-do compile }
+! { dg-options "-O2 -fopenmp -fdump-tree-optimized" }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_start \[^\n\r]*, 3, 3, " 1 "optimized" } }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_end " 1 "optimized" } }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_nonmonotonic_guided_next " 1 "optimized" } }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_workshare_task_reduction_unregister \\(0\\)" 1 "optimized" } }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_parallel " 1 "optimized" } }
+
+module m
+  implicit none (type, external)
+  integer :: j
+  interface
+    subroutine bar(i)
+      integer :: i
+    end subroutine
+  end interface
+end module m
+
+subroutine foo(a, b, c)
+  use m
+  implicit none (type, external)
+  integer :: a, b ,c
+  integer :: i
+  !$omp parallel
+  !$omp do reduction (task, *: j) schedule (nonmonotonic: guided, 3)
+  do i = a, b, c
+    j = j + 1
+    call bar (j)
+  end do
+  !$omp end parallel
+end
diff --git a/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-23.f90 b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-23.f90
new file mode 100644
index 00000000000..45dc0002b92
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-23.f90
@@ -0,0 +1,31 @@
+! { dg-do compile }
+! { dg-options "-O2 -fopenmp -fdump-tree-optimized" }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_start \[^\n\r]*, (?:2147483649|-2147483647), 0, 0B, 0B, " 1 "optimized" } }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_end " 1 "optimized" } }
+! { dg-final { scan-tree-dump-not "__builtin_GOMP_loop\[^\n\r]*_next " "optimized" } }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_workshare_task_reduction_unregister \\(0\\)" 1 "optimized" } }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_parallel " 1 "optimized" } }
+
+module m
+  implicit none (type, external)
+  integer :: j
+  interface
+    subroutine bar(i)
+      integer :: i
+    end subroutine
+  end interface
+end module m
+
+subroutine foo(a, b, c)
+  use m
+  implicit none (type, external)
+  integer :: a, b ,c
+  integer :: i
+  !$omp parallel
+  !$omp do reduction (task, *: j) schedule (auto)
+  do i = a, b, c
+    j = j + 1
+    call bar (j)
+  end do
+  !$omp end parallel
+end
diff --git a/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-24.f90 b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-24.f90
new file mode 100644
index 00000000000..e7fbe922f3e
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-24.f90
@@ -0,0 +1,31 @@
+! { dg-do compile }
+! { dg-options "-O2 -fopenmp -fdump-tree-optimized" }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_start \[^\n\r]*, (?:2147483649|-2147483647), 0, 0B, 0B, " 1 "optimized" } }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_end " 1 "optimized" } }
+! { dg-final { scan-tree-dump-not "__builtin_GOMP_loop\[^\n\r]*_next " "optimized" } }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_workshare_task_reduction_unregister \\(0\\)" 1 "optimized" } }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_parallel " 1 "optimized" } }
+
+module m
+  implicit none (type, external)
+  integer :: j
+  interface
+    subroutine bar(i)
+      integer :: i
+    end subroutine
+  end interface
+end module m
+
+subroutine foo(a, b, c)
+  use m
+  implicit none (type, external)
+  integer :: a, b ,c
+  integer :: i
+  !$omp parallel
+  !$omp do reduction (task, *: j) schedule (monotonic: auto)
+  do i = a, b, c
+    j = j + 1
+    call bar (j)
+  end do
+  !$omp end parallel
+end
diff --git a/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-25.f90 b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-25.f90
new file mode 100644
index 00000000000..d5554c49962
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-25.f90
@@ -0,0 +1,31 @@
+! { dg-do compile }
+! { dg-options "-O2 -fopenmp -fdump-tree-optimized" }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_start \[^\n\r]*, (?:2147483649|-2147483647), 0, 0B, 0B, " 1 "optimized" } }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_end " 1 "optimized" } }
+! { dg-final { scan-tree-dump-not "__builtin_GOMP_loop\[^\n\r]*_next " "optimized" } }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_workshare_task_reduction_unregister \\(0\\)" 1 "optimized" } }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_parallel " 1 "optimized" } }
+
+module m
+  implicit none (type, external)
+  integer :: j
+  interface
+    subroutine bar(i)
+      integer :: i
+    end subroutine
+  end interface
+end module m
+
+subroutine foo(a, b, c)
+  use m
+  implicit none (type, external)
+  integer :: a, b ,c
+  integer :: i
+  !$omp parallel
+  !$omp do reduction (task, *: j) schedule (nonmonotonic: auto)
+  do i = a, b, c
+    j = j + 1
+    call bar (j)
+  end do
+  !$omp end parallel
+end
diff --git a/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-26.f90 b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-26.f90
new file mode 100644
index 00000000000..28267902914
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-26.f90
@@ -0,0 +1,31 @@
+! { dg-do compile }
+! { dg-options "-O2 -fopenmp -fdump-tree-optimized" }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_start \[^\n\r]*, 0, 0, " 1 "optimized" } }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_end " 1 "optimized" } }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_maybe_nonmonotonic_runtime_next " 1 "optimized" } }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_workshare_task_reduction_unregister \\(0\\)" 1 "optimized" } }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_parallel " 1 "optimized" } }
+
+module m
+  implicit none (type, external)
+  integer(8) :: j
+  interface
+    subroutine bar(i)
+      integer(8) :: i
+    end subroutine
+  end interface
+end module m
+
+subroutine foo(a, b, c)
+  use m
+  implicit none (type, external)
+  integer(8) :: a, b ,c
+  integer(8) :: i
+  !$omp parallel
+  !$omp do reduction (task, *: j) schedule (runtime)
+  do i = a, b, c
+    j = j + 1
+    call bar (j)
+  end do
+  !$omp end parallel
+end
diff --git a/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-27.f90 b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-27.f90
new file mode 100644
index 00000000000..2ee047d4e8c
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-27.f90
@@ -0,0 +1,31 @@
+! { dg-do compile }
+! { dg-options "-O2 -fopenmp -fdump-tree-optimized" }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_start \[^\n\r]*, (?:2147483648|-2147483648), 0, " 1 "optimized" } }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_end " 1 "optimized" } }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_runtime_next " 1 "optimized" } }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_workshare_task_reduction_unregister \\(0\\)" 1 "optimized" } }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_parallel " 1 "optimized" } }
+
+module m
+  implicit none (type, external)
+  integer(8) :: j
+  interface
+    subroutine bar(i)
+      integer(8) :: i
+    end subroutine
+  end interface
+end module m
+
+subroutine foo(a, b, c)
+  use m
+  implicit none (type, external)
+  integer(8) :: a, b ,c
+  integer(8) :: i
+  !$omp parallel
+  !$omp do reduction (task, *: j) schedule (monotonic: runtime)
+  do i = a, b, c
+    j = j + 1
+    call bar (j)
+  end do
+  !$omp end parallel
+end
diff --git a/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-28.f90 b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-28.f90
new file mode 100644
index 00000000000..6c9d49be13c
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-28.f90
@@ -0,0 +1,31 @@
+! { dg-do compile }
+! { dg-options "-O2 -fopenmp -fdump-tree-optimized" }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_start \[^\n\r]*, 4, 0, " 1 "optimized" } }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_end " 1 "optimized" } }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_nonmonotonic_runtime_next " 1 "optimized" } }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_workshare_task_reduction_unregister \\(0\\)" 1 "optimized" } }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_parallel " 1 "optimized" } }
+
+module m
+  implicit none (type, external)
+  integer(8) :: j
+  interface
+    subroutine bar(i)
+      integer(8) :: i
+    end subroutine
+  end interface
+end module m
+
+subroutine foo(a, b, c)
+  use m
+  implicit none (type, external)
+  integer(8) :: a, b ,c
+  integer(8) :: i
+  !$omp parallel
+  !$omp do reduction (task, *: j) schedule (nonmonotonic: runtime)
+  do i = a, b, c
+    j = j + 1
+    call bar (j)
+  end do
+  !$omp end parallel
+end
diff --git a/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-29.f90 b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-29.f90
new file mode 100644
index 00000000000..316b72e1d2e
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-29.f90
@@ -0,0 +1,31 @@
+! { dg-do compile }
+! { dg-options "-O2 -fopenmp -fdump-tree-optimized" }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_start \[^\n\r]*, (?:2147483649|-2147483647), 0, 0B, 0B, " 1 "optimized" } }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_end " 1 "optimized" } }
+! { dg-final { scan-tree-dump-not "__builtin_GOMP_loop_ull\[^\n\r]*_next " "optimized" } }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_workshare_task_reduction_unregister \\(0\\)" 1 "optimized" } }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_parallel " 1 "optimized" } }
+
+module m
+  implicit none (type, external)
+  integer(8) :: j
+  interface
+    subroutine bar(i)
+      integer(8) :: i
+    end subroutine
+  end interface
+end module m
+
+subroutine foo(a, b, c)
+  use m
+  implicit none (type, external)
+  integer(8) :: a, b ,c
+  integer(8) :: i
+  !$omp parallel
+  !$omp do reduction (task, *: j)
+  do i = a, b, c
+    j = j + 1
+    call bar (j)
+  end do
+  !$omp end parallel
+end
diff --git a/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-3.f90 b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-3.f90
new file mode 100644
index 00000000000..6c9d49be13c
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-3.f90
@@ -0,0 +1,31 @@
+! { dg-do compile }
+! { dg-options "-O2 -fopenmp -fdump-tree-optimized" }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_start \[^\n\r]*, 4, 0, " 1 "optimized" } }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_end " 1 "optimized" } }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_nonmonotonic_runtime_next " 1 "optimized" } }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_workshare_task_reduction_unregister \\(0\\)" 1 "optimized" } }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_parallel " 1 "optimized" } }
+
+module m
+  implicit none (type, external)
+  integer(8) :: j
+  interface
+    subroutine bar(i)
+      integer(8) :: i
+    end subroutine
+  end interface
+end module m
+
+subroutine foo(a, b, c)
+  use m
+  implicit none (type, external)
+  integer(8) :: a, b ,c
+  integer(8) :: i
+  !$omp parallel
+  !$omp do reduction (task, *: j) schedule (nonmonotonic: runtime)
+  do i = a, b, c
+    j = j + 1
+    call bar (j)
+  end do
+  !$omp end parallel
+end
diff --git a/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-30.f90 b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-30.f90
new file mode 100644
index 00000000000..b9406d6b236
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-30.f90
@@ -0,0 +1,31 @@
+! { dg-do compile }
+! { dg-options "-O2 -fopenmp -fdump-tree-optimized" }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_start \[^\n\r]*, (?:2147483649|-2147483647), 0, 0B, 0B, " 1 "optimized" } }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_end " 1 "optimized" } }
+! { dg-final { scan-tree-dump-not "__builtin_GOMP_loop_ull\[^\n\r]*_next " "optimized" } }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_workshare_task_reduction_unregister \\(0\\)" 1 "optimized" } }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_parallel " 1 "optimized" } }
+
+module m
+  implicit none (type, external)
+  integer(8) :: j
+  interface
+    subroutine bar(i)
+      integer(8) :: i
+    end subroutine
+  end interface
+end module m
+
+subroutine foo(a, b, c)
+  use m
+  implicit none (type, external)
+  integer(8) :: a, b ,c
+  integer(8) :: i
+  !$omp parallel
+  !$omp do reduction (task, *: j) schedule (static)
+  do i = a, b, c
+    j = j + 1
+    call bar (j)
+  end do
+  !$omp end parallel
+end
diff --git a/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-31.f90 b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-31.f90
new file mode 100644
index 00000000000..4a246045c1b
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-31.f90
@@ -0,0 +1,31 @@
+! { dg-do compile }
+! { dg-options "-O2 -fopenmp -fdump-tree-optimized" }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_start \[^\n\r]*, (?:2147483649|-2147483647), 0, 0B, 0B, " 1 "optimized" } }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_end " 1 "optimized" } }
+! { dg-final { scan-tree-dump-not "__builtin_GOMP_loop_ull\[^\n\r]*_next " "optimized" } }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_workshare_task_reduction_unregister \\(0\\)" 1 "optimized" } }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_parallel " 1 "optimized" } }
+
+module m
+  implicit none (type, external)
+  integer(8) :: j
+  interface
+    subroutine bar(i)
+      integer(8) :: i
+    end subroutine
+  end interface
+end module m
+
+subroutine foo(a, b, c)
+  use m
+  implicit none (type, external)
+  integer(8) :: a, b ,c
+  integer(8) :: i
+  !$omp parallel
+  !$omp do reduction (task, *: j) schedule (monotonic: static)
+  do i = a, b, c
+    j = j + 1
+    call bar (j)
+  end do
+  !$omp end parallel
+end
diff --git a/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-32.f90 b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-32.f90
new file mode 100644
index 00000000000..a7062d9eaae
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-32.f90
@@ -0,0 +1,31 @@
+! { dg-do compile }
+! { dg-options "-O2 -fopenmp -fdump-tree-optimized" }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_start \[^\n\r]*, (?:2147483649|-2147483647), 0, 0B, 0B, " 1 "optimized" } }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_end " 1 "optimized" } }
+! { dg-final { scan-tree-dump-not "__builtin_GOMP_loop_ull\[^\n\r]*_next " "optimized" } }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_workshare_task_reduction_unregister \\(0\\)" 1 "optimized" } }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_parallel " 1 "optimized" } }
+
+module m
+  implicit none (type, external)
+  integer(8) :: j
+  interface
+    subroutine bar(i)
+      integer(8) :: i
+    end subroutine
+  end interface
+end module m
+
+subroutine foo(a, b, c)
+  use m
+  implicit none (type, external)
+  integer(8) :: a, b ,c
+  integer(8) :: i
+  !$omp parallel
+  !$omp do reduction (task, *: j) schedule (nonmonotonic: static)
+  do i = a, b, c
+    j = j + 1
+    call bar (j)
+  end do
+  !$omp end parallel
+end
diff --git a/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-33.f90 b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-33.f90
new file mode 100644
index 00000000000..67c25c82ddd
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-33.f90
@@ -0,0 +1,31 @@
+! { dg-do compile }
+! { dg-options "-O2 -fopenmp -fdump-tree-optimized" }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_start \[^\n\r]*, (?:2147483649|-2147483647), 0, 0B, 0B, " 1 "optimized" } }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_end " 1 "optimized" } }
+! { dg-final { scan-tree-dump-not "__builtin_GOMP_loop_ull\[^\n\r]*_next " "optimized" } }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_workshare_task_reduction_unregister \\(0\\)" 1 "optimized" } }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_parallel " 1 "optimized" } }
+
+module m
+  implicit none (type, external)
+  integer(8) :: j
+  interface
+    subroutine bar(i)
+      integer(8) :: i
+    end subroutine
+  end interface
+end module m
+
+subroutine foo(a, b, c)
+  use m
+  implicit none (type, external)
+  integer(8) :: a, b ,c
+  integer(8) :: i
+  !$omp parallel
+  !$omp do reduction (task, *: j) schedule (static, 2)
+  do i = a, b, c
+    j = j + 1
+    call bar (j)
+  end do
+  !$omp end parallel
+end
diff --git a/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-34.f90 b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-34.f90
new file mode 100644
index 00000000000..f1e4d89adbb
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-34.f90
@@ -0,0 +1,31 @@
+! { dg-do compile }
+! { dg-options "-O2 -fopenmp -fdump-tree-optimized" }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_start \[^\n\r]*, (?:2147483649|-2147483647), 0, 0B, 0B, " 1 "optimized" } }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_end " 1 "optimized" } }
+! { dg-final { scan-tree-dump-not "__builtin_GOMP_loop_ull\[^\n\r]*_next " "optimized" } }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_workshare_task_reduction_unregister \\(0\\)" 1 "optimized" } }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_parallel " 1 "optimized" } }
+
+module m
+  implicit none (type, external)
+  integer(8) :: j
+  interface
+    subroutine bar(i)
+      integer(8) :: i
+    end subroutine
+  end interface
+end module m
+
+subroutine foo(a, b, c)
+  use m
+  implicit none (type, external)
+  integer(8) :: a, b ,c
+  integer(8) :: i
+  !$omp parallel
+  !$omp do reduction (task, *: j) schedule (monotonic: static, 2)
+  do i = a, b, c
+    j = j + 1
+    call bar (j)
+  end do
+  !$omp end parallel
+end
diff --git a/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-35.f90 b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-35.f90
new file mode 100644
index 00000000000..7d7c27118ba
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-35.f90
@@ -0,0 +1,31 @@
+! { dg-do compile }
+! { dg-options "-O2 -fopenmp -fdump-tree-optimized" }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_start \[^\n\r]*, (?:2147483649|-2147483647), 0, 0B, 0B, " 1 "optimized" } }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_end " 1 "optimized" } }
+! { dg-final { scan-tree-dump-not "__builtin_GOMP_loop_ull\[^\n\r]*_next " "optimized" } }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_workshare_task_reduction_unregister \\(0\\)" 1 "optimized" } }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_parallel " 1 "optimized" } }
+
+module m
+  implicit none (type, external)
+  integer(8) :: j
+  interface
+    subroutine bar(i)
+      integer(8) :: i
+    end subroutine
+  end interface
+end module m
+
+subroutine foo(a, b, c)
+  use m
+  implicit none (type, external)
+  integer(8) :: a, b ,c
+  integer(8) :: i
+  !$omp parallel
+  !$omp do reduction (task, *: j) schedule (nonmonotonic: static, 2)
+  do i = a, b, c
+    j = j + 1
+    call bar (j)
+  end do
+  !$omp end parallel
+end
diff --git a/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-36.f90 b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-36.f90
new file mode 100644
index 00000000000..b190e9ee87b
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-36.f90
@@ -0,0 +1,31 @@
+! { dg-do compile }
+! { dg-options "-O2 -fopenmp -fdump-tree-optimized" }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_start \[^\n\r]*, 2, 1, " 1 "optimized" } }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_end " 1 "optimized" } }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_nonmonotonic_dynamic_next " 1 "optimized" } }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_workshare_task_reduction_unregister \\(0\\)" 1 "optimized" } }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_parallel " 1 "optimized" } }
+
+module m
+  implicit none (type, external)
+  integer(8) :: j
+  interface
+    subroutine bar(i)
+      integer(8) :: i
+    end subroutine
+  end interface
+end module m
+
+subroutine foo(a, b, c)
+  use m
+  implicit none (type, external)
+  integer(8) :: a, b ,c
+  integer(8) :: i
+  !$omp parallel
+  !$omp do reduction (task, *: j) schedule (dynamic)
+  do i = a, b, c
+    j = j + 1
+    call bar (j)
+  end do
+  !$omp end parallel
+end
diff --git a/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-37.f90 b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-37.f90
new file mode 100644
index 00000000000..c541d22d6cf
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-37.f90
@@ -0,0 +1,31 @@
+! { dg-do compile }
+! { dg-options "-O2 -fopenmp -fdump-tree-optimized" }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_start \[^\n\r]*, (?:2147483650|-2147483646), 1, " 1 "optimized" } }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_end " 1 "optimized" } }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_dynamic_next " 1 "optimized" } }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_workshare_task_reduction_unregister \\(0\\)" 1 "optimized" } }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_parallel " 1 "optimized" } }
+
+module m
+  implicit none (type, external)
+  integer(8) :: j
+  interface
+    subroutine bar(i)
+      integer(8) :: i
+    end subroutine
+  end interface
+end module m
+
+subroutine foo(a, b, c)
+  use m
+  implicit none (type, external)
+  integer(8) :: a, b ,c
+  integer(8) :: i
+  !$omp parallel
+  !$omp do reduction (task, *: j) schedule (monotonic: dynamic)
+  do i = a, b, c
+    j = j + 1
+    call bar (j)
+  end do
+  !$omp end parallel
+end
diff --git a/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-38.f90 b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-38.f90
new file mode 100644
index 00000000000..46a27a0386c
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-38.f90
@@ -0,0 +1,31 @@
+! { dg-do compile }
+! { dg-options "-O2 -fopenmp -fdump-tree-optimized" }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_start \[^\n\r]*, 2, 1, " 1 "optimized" } }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_end " 1 "optimized" } }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_nonmonotonic_dynamic_next " 1 "optimized" } }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_workshare_task_reduction_unregister \\(0\\)" 1 "optimized" } }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_parallel " 1 "optimized" } }
+
+module m
+  implicit none (type, external)
+  integer(8) :: j
+  interface
+    subroutine bar(i)
+      integer(8) :: i
+    end subroutine
+  end interface
+end module m
+
+subroutine foo(a, b, c)
+  use m
+  implicit none (type, external)
+  integer(8) :: a, b ,c
+  integer(8) :: i
+  !$omp parallel
+  !$omp do reduction (task, *: j) schedule (nonmonotonic: dynamic)
+  do i = a, b, c
+    j = j + 1
+    call bar (j)
+  end do
+  !$omp end parallel
+end
diff --git a/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-39.f90 b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-39.f90
new file mode 100644
index 00000000000..6cdd9a8807b
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-39.f90
@@ -0,0 +1,31 @@
+! { dg-do compile }
+! { dg-options "-O2 -fopenmp -fdump-tree-optimized" }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_start \[^\n\r]*, 2, 3, " 1 "optimized" } }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_end " 1 "optimized" } }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_nonmonotonic_dynamic_next " 1 "optimized" } }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_workshare_task_reduction_unregister \\(0\\)" 1 "optimized" } }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_parallel " 1 "optimized" } }
+
+module m
+  implicit none (type, external)
+  integer(8) :: j
+  interface
+    subroutine bar(i)
+      integer(8) :: i
+    end subroutine
+  end interface
+end module m
+
+subroutine foo(a, b, c)
+  use m
+  implicit none (type, external)
+  integer(8) :: a, b ,c
+  integer(8) :: i
+  !$omp parallel
+  !$omp do reduction (task, *: j) schedule (dynamic, 3)
+  do i = a, b, c
+    j = j + 1
+    call bar (j)
+  end do
+  !$omp end parallel
+end
diff --git a/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-4.f90 b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-4.f90
new file mode 100644
index 00000000000..c7744277bc8
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-4.f90
@@ -0,0 +1,31 @@
+! { dg-do compile }
+! { dg-options "-O2 -fopenmp -fdump-tree-optimized" }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_start \[^\n\r]*, (?:2147483649|-2147483647), 0, 0B, 0B, " 1 "optimized" } }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_end " 1 "optimized" } }
+! { dg-final { scan-tree-dump-not "__builtin_GOMP_loop\[^\n\r]*_next " "optimized" } }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_workshare_task_reduction_unregister \\(0\\)" 1 "optimized" } }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_parallel " 1 "optimized" } }
+
+module m
+  implicit none (type, external)
+  integer :: j
+  interface
+    subroutine bar(i)
+      integer :: i
+    end subroutine
+  end interface
+end module m
+
+subroutine foo(a, b, c)
+  use m
+  implicit none (type, external)
+  integer :: a, b ,c
+  integer :: i
+  !$omp parallel
+  !$omp do reduction (task, *: j)
+  do i = a, b, c
+    j = j + 1
+    call bar (j)
+  end do
+  !$omp end parallel
+end
diff --git a/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-40.f90 b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-40.f90
new file mode 100644
index 00000000000..29da27abc5a
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-40.f90
@@ -0,0 +1,31 @@
+! { dg-do compile }
+! { dg-options "-O2 -fopenmp -fdump-tree-optimized" }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_start \[^\n\r]*, (?:2147483650|-2147483646), 3, " 1 "optimized" } }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_end " 1 "optimized" } }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_dynamic_next " 1 "optimized" } }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_workshare_task_reduction_unregister \\(0\\)" 1 "optimized" } }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_parallel " 1 "optimized" } }
+
+module m
+  implicit none (type, external)
+  integer(8) :: j
+  interface
+    subroutine bar(i)
+      integer(8) :: i
+    end subroutine
+  end interface
+end module m
+
+subroutine foo(a, b, c)
+  use m
+  implicit none (type, external)
+  integer(8) :: a, b ,c
+  integer(8) :: i
+  !$omp parallel
+  !$omp do reduction (task, *: j) schedule (monotonic: dynamic, 3)
+  do i = a, b, c
+    j = j + 1
+    call bar (j)
+  end do
+  !$omp end parallel
+end
diff --git a/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-41.f90 b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-41.f90
new file mode 100644
index 00000000000..4ed879cdd00
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-41.f90
@@ -0,0 +1,31 @@
+! { dg-do compile }
+! { dg-options "-O2 -fopenmp -fdump-tree-optimized" }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_start \[^\n\r]*, 2, 3, " 1 "optimized" } }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_end " 1 "optimized" } }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_nonmonotonic_dynamic_next " 1 "optimized" } }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_workshare_task_reduction_unregister \\(0\\)" 1 "optimized" } }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_parallel " 1 "optimized" } }
+
+module m
+  implicit none (type, external)
+  integer(8) :: j
+  interface
+    subroutine bar(i)
+      integer(8) :: i
+    end subroutine
+  end interface
+end module m
+
+subroutine foo(a, b, c)
+  use m
+  implicit none (type, external)
+  integer(8) :: a, b ,c
+  integer(8) :: i
+  !$omp parallel
+  !$omp do reduction (task, *: j) schedule (nonmonotonic: dynamic, 3)
+  do i = a, b, c
+    j = j + 1
+    call bar (j)
+  end do
+  !$omp end parallel
+end
diff --git a/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-42.f90 b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-42.f90
new file mode 100644
index 00000000000..78d02ef8035
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-42.f90
@@ -0,0 +1,31 @@
+! { dg-do compile }
+! { dg-options "-O2 -fopenmp -fdump-tree-optimized" }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_start \[^\n\r]*, 3, 1, " 1 "optimized" } }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_end " 1 "optimized" } }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_nonmonotonic_guided_next " 1 "optimized" } }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_workshare_task_reduction_unregister \\(0\\)" 1 "optimized" } }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_parallel " 1 "optimized" } }
+
+module m
+  implicit none (type, external)
+  integer(8) :: j
+  interface
+    subroutine bar(i)
+      integer(8) :: i
+    end subroutine
+  end interface
+end module m
+
+subroutine foo(a, b, c)
+  use m
+  implicit none (type, external)
+  integer(8) :: a, b ,c
+  integer(8) :: i
+  !$omp parallel
+  !$omp do reduction (task, *: j) schedule (guided)
+  do i = a, b, c
+    j = j + 1
+    call bar (j)
+  end do
+  !$omp end parallel
+end
diff --git a/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-43.f90 b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-43.f90
new file mode 100644
index 00000000000..16885c84210
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-43.f90
@@ -0,0 +1,31 @@
+! { dg-do compile }
+! { dg-options "-O2 -fopenmp -fdump-tree-optimized" }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_start \[^\n\r]*, (?:2147483651|-2147483645), 1, " 1 "optimized" } }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_end " 1 "optimized" } }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_guided_next " 1 "optimized" } }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_workshare_task_reduction_unregister \\(0\\)" 1 "optimized" } }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_parallel " 1 "optimized" } }
+
+module m
+  implicit none (type, external)
+  integer(8) :: j
+  interface
+    subroutine bar(i)
+      integer(8) :: i
+    end subroutine
+  end interface
+end module m
+
+subroutine foo(a, b, c)
+  use m
+  implicit none (type, external)
+  integer(8) :: a, b ,c
+  integer(8) :: i
+  !$omp parallel
+  !$omp do reduction (task, *: j) schedule (monotonic: guided)
+  do i = a, b, c
+    j = j + 1
+    call bar (j)
+  end do
+  !$omp end parallel
+end
diff --git a/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-44.f90 b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-44.f90
new file mode 100644
index 00000000000..0db9be6854c
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-44.f90
@@ -0,0 +1,31 @@
+! { dg-do compile }
+! { dg-options "-O2 -fopenmp -fdump-tree-optimized" }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_start \[^\n\r]*, 3, 1, " 1 "optimized" } }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_end " 1 "optimized" } }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_nonmonotonic_guided_next " 1 "optimized" } }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_workshare_task_reduction_unregister \\(0\\)" 1 "optimized" } }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_parallel " 1 "optimized" } }
+
+module m
+  implicit none (type, external)
+  integer(8) :: j
+  interface
+    subroutine bar(i)
+      integer(8) :: i
+    end subroutine
+  end interface
+end module m
+
+subroutine foo(a, b, c)
+  use m
+  implicit none (type, external)
+  integer(8) :: a, b ,c
+  integer(8) :: i
+  !$omp parallel
+  !$omp do reduction (task, *: j) schedule (nonmonotonic: guided)
+  do i = a, b, c
+    j = j + 1
+    call bar (j)
+  end do
+  !$omp end parallel
+end
diff --git a/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-45.f90 b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-45.f90
new file mode 100644
index 00000000000..40b12755414
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-45.f90
@@ -0,0 +1,31 @@
+! { dg-do compile }
+! { dg-options "-O2 -fopenmp -fdump-tree-optimized" }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_start \[^\n\r]*, 3, 3, " 1 "optimized" } }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_end " 1 "optimized" } }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_nonmonotonic_guided_next " 1 "optimized" } }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_workshare_task_reduction_unregister \\(0\\)" 1 "optimized" } }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_parallel " 1 "optimized" } }
+
+module m
+  implicit none (type, external)
+  integer(8) :: j
+  interface
+    subroutine bar(i)
+      integer(8) :: i
+    end subroutine
+  end interface
+end module m
+
+subroutine foo(a, b, c)
+  use m
+  implicit none (type, external)
+  integer(8) :: a, b ,c
+  integer(8) :: i
+  !$omp parallel
+  !$omp do reduction (task, *: j) schedule (guided, 3)
+  do i = a, b, c
+    j = j + 1
+    call bar (j)
+  end do
+  !$omp end parallel
+end
diff --git a/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-46.f90 b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-46.f90
new file mode 100644
index 00000000000..57c74023d8d
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-46.f90
@@ -0,0 +1,31 @@
+! { dg-do compile }
+! { dg-options "-O2 -fopenmp -fdump-tree-optimized" }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_start \[^\n\r]*, (?:2147483651|-2147483645), 3, " 1 "optimized" } }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_end " 1 "optimized" } }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_guided_next " 1 "optimized" } }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_workshare_task_reduction_unregister \\(0\\)" 1 "optimized" } }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_parallel " 1 "optimized" } }
+
+module m
+  implicit none (type, external)
+  integer(8) :: j
+  interface
+    subroutine bar(i)
+      integer(8) :: i
+    end subroutine
+  end interface
+end module m
+
+subroutine foo(a, b, c)
+  use m
+  implicit none (type, external)
+  integer(8) :: a, b ,c
+  integer(8) :: i
+  !$omp parallel
+  !$omp do reduction (task, *: j) schedule (monotonic: guided, 3)
+  do i = a, b, c
+    j = j + 1
+    call bar (j)
+  end do
+  !$omp end parallel
+end
diff --git a/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-47.f90 b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-47.f90
new file mode 100644
index 00000000000..b4564300b50
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-47.f90
@@ -0,0 +1,31 @@
+! { dg-do compile }
+! { dg-options "-O2 -fopenmp -fdump-tree-optimized" }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_start \[^\n\r]*, 3, 3, " 1 "optimized" } }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_end " 1 "optimized" } }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_nonmonotonic_guided_next " 1 "optimized" } }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_workshare_task_reduction_unregister \\(0\\)" 1 "optimized" } }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_parallel " 1 "optimized" } }
+
+module m
+  implicit none (type, external)
+  integer(8) :: j
+  interface
+    subroutine bar(i)
+      integer(8) :: i
+    end subroutine
+  end interface
+end module m
+
+subroutine foo(a, b, c)
+  use m
+  implicit none (type, external)
+  integer(8) :: a, b ,c
+  integer(8) :: i
+  !$omp parallel
+  !$omp do reduction (task, *: j) schedule (nonmonotonic: guided, 3)
+  do i = a, b, c
+    j = j + 1
+    call bar (j)
+  end do
+  !$omp end parallel
+end
diff --git a/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-48.f90 b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-48.f90
new file mode 100644
index 00000000000..1370010ac60
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-48.f90
@@ -0,0 +1,31 @@
+! { dg-do compile }
+! { dg-options "-O2 -fopenmp -fdump-tree-optimized" }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_start \[^\n\r]*, (?:2147483649|-2147483647), 0, 0B, 0B, " 1 "optimized" } }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_end " 1 "optimized" } }
+! { dg-final { scan-tree-dump-not "__builtin_GOMP_loop_ull\[^\n\r]*_next " "optimized" } }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_workshare_task_reduction_unregister \\(0\\)" 1 "optimized" } }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_parallel " 1 "optimized" } }
+
+module m
+  implicit none (type, external)
+  integer(8) :: j
+  interface
+    subroutine bar(i)
+      integer(8) :: i
+    end subroutine
+  end interface
+end module m
+
+subroutine foo(a, b, c)
+  use m
+  implicit none (type, external)
+  integer(8) :: a, b ,c
+  integer(8) :: i
+  !$omp parallel
+  !$omp do reduction (task, *: j) schedule (auto)
+  do i = a, b, c
+    j = j + 1
+    call bar (j)
+  end do
+  !$omp end parallel
+end
diff --git a/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-49.f90 b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-49.f90
new file mode 100644
index 00000000000..ab2591f3acf
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-49.f90
@@ -0,0 +1,31 @@
+! { dg-do compile }
+! { dg-options "-O2 -fopenmp -fdump-tree-optimized" }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_start \[^\n\r]*, (?:2147483649|-2147483647), 0, 0B, 0B, " 1 "optimized" } }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_end " 1 "optimized" } }
+! { dg-final { scan-tree-dump-not "__builtin_GOMP_loop_ull\[^\n\r]*_next " "optimized" } }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_workshare_task_reduction_unregister \\(0\\)" 1 "optimized" } }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_parallel " 1 "optimized" } }
+
+module m
+  implicit none (type, external)
+  integer(8) :: j
+  interface
+    subroutine bar(i)
+      integer(8) :: i
+    end subroutine
+  end interface
+end module m
+
+subroutine foo(a, b, c)
+  use m
+  implicit none (type, external)
+  integer(8) :: a, b ,c
+  integer(8) :: i
+  !$omp parallel
+  !$omp do reduction (task, *: j) schedule (monotonic: auto)
+  do i = a, b, c
+    j = j + 1
+    call bar (j)
+  end do
+  !$omp end parallel
+end
diff --git a/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-5.f90 b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-5.f90
new file mode 100644
index 00000000000..ce3db0fa903
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-5.f90
@@ -0,0 +1,31 @@
+! { dg-do compile }
+! { dg-options "-O2 -fopenmp -fdump-tree-optimized" }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_start \[^\n\r]*, (?:2147483649|-2147483647), 0, 0B, 0B, " 1 "optimized" } }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_end " 1 "optimized" } }
+! { dg-final { scan-tree-dump-not "__builtin_GOMP_loop\[^\n\r]*_next " "optimized" } }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_workshare_task_reduction_unregister \\(0\\)" 1 "optimized" } }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_parallel " 1 "optimized" } }
+
+module m
+  implicit none (type, external)
+  integer :: j
+  interface
+    subroutine bar(i)
+      integer :: i
+    end subroutine
+  end interface
+end module m
+
+subroutine foo(a, b, c)
+  use m
+  implicit none (type, external)
+  integer :: a, b ,c
+  integer :: i
+  !$omp parallel
+  !$omp do reduction (task, *: j) schedule (static)
+  do i = a, b, c
+    j = j + 1
+    call bar (j)
+  end do
+  !$omp end parallel
+end
diff --git a/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-50.f90 b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-50.f90
new file mode 100644
index 00000000000..8b8942709a5
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-50.f90
@@ -0,0 +1,31 @@
+! { dg-do compile }
+! { dg-options "-O2 -fopenmp -fdump-tree-optimized" }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_start \[^\n\r]*, (?:2147483649|-2147483647), 0, 0B, 0B, " 1 "optimized" } }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_end " 1 "optimized" } }
+! { dg-final { scan-tree-dump-not "__builtin_GOMP_loop_ull\[^\n\r]*_next " "optimized" } }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_workshare_task_reduction_unregister \\(0\\)" 1 "optimized" } }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_parallel " 1 "optimized" } }
+
+module m
+  implicit none (type, external)
+  integer(8) :: j
+  interface
+    subroutine bar(i)
+      integer(8) :: i
+    end subroutine
+  end interface
+end module m
+
+subroutine foo(a, b, c)
+  use m
+  implicit none (type, external)
+  integer(8) :: a, b ,c
+  integer(8) :: i
+  !$omp parallel
+  !$omp do reduction (task, *: j) schedule (nonmonotonic: auto)
+  do i = a, b, c
+    j = j + 1
+    call bar (j)
+  end do
+  !$omp end parallel
+end
diff --git a/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-51.f90 b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-51.f90
new file mode 100644
index 00000000000..13bde3aabeb
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-51.f90
@@ -0,0 +1,35 @@
+! { dg-do compile }
+! { dg-options "-O2 -fopenmp -fdump-tree-optimized" }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_ordered_start \[^\n\r]*, (?:2147483648|-2147483648), 0, " 1 "optimized" } }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_end " 1 "optimized" } }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_ordered_start " 1 "optimized" } }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_ordered_end " 1 "optimized" } }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_ordered_runtime_next " 1 "optimized" } }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_workshare_task_reduction_unregister \\(0\\)" 1 "optimized" } }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_parallel " 1 "optimized" } }
+
+module m
+  implicit none (type, external)
+  integer :: j
+  interface
+    subroutine bar(i)
+      integer :: i
+    end subroutine
+  end interface
+end module m
+
+subroutine foo(a, b, c)
+  use m
+  implicit none (type, external)
+  integer :: a, b ,c
+  integer :: i
+  !$omp parallel
+  !$omp do ordered reduction (task, *: j) schedule (runtime)
+  do i = a, b, c
+    call bar (j)
+    !$omp ordered
+    j = j + 1
+    !$omp end ordered
+  end do
+  !$omp end parallel
+end
diff --git a/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-52.f90 b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-52.f90
new file mode 100644
index 00000000000..50dce3dccf9
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-52.f90
@@ -0,0 +1,35 @@
+! { dg-do compile }
+! { dg-options "-O2 -fopenmp -fdump-tree-optimized" }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_ordered_start \[^\n\r]*, (?:2147483649|-2147483647), 0, " 1 "optimized" } }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_end " 1 "optimized" } }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_ordered_start " 1 "optimized" } }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_ordered_end " 1 "optimized" } }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_ordered_static_next " 1 "optimized" } }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_workshare_task_reduction_unregister \\(0\\)" 1 "optimized" } }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_parallel " 1 "optimized" } }
+
+module m
+  implicit none (type, external)
+  integer :: j
+  interface
+    subroutine bar(i)
+      integer :: i
+    end subroutine
+  end interface
+end module m
+
+subroutine foo(a, b, c)
+  use m
+  implicit none (type, external)
+  integer :: a, b ,c
+  integer :: i
+  !$omp parallel
+  !$omp do ordered reduction (task, *: j)
+  do i = a, b, c
+    call bar (j)
+    !$omp ordered
+    j = j + 1
+    !$omp end ordered
+  end do
+  !$omp end parallel
+end
diff --git a/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-53.f90 b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-53.f90
new file mode 100644
index 00000000000..018420946cb
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-53.f90
@@ -0,0 +1,35 @@
+! { dg-do compile }
+! { dg-options "-O2 -fopenmp -fdump-tree-optimized" }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_ordered_start \[^\n\r]*, (?:2147483650|-2147483646), 4, " 1 "optimized" } }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_end " 1 "optimized" } }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_ordered_start " 1 "optimized" } }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_ordered_end " 1 "optimized" } }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_ordered_dynamic_next " 1 "optimized" } }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_workshare_task_reduction_unregister \\(0\\)" 1 "optimized" } }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_parallel " 1 "optimized" } }
+
+module m
+  implicit none (type, external)
+  integer :: j
+  interface
+    subroutine bar(i)
+      integer :: i
+    end subroutine
+  end interface
+end module m
+
+subroutine foo(a, b, c)
+  use m
+  implicit none (type, external)
+  integer :: a, b ,c
+  integer :: i
+  !$omp parallel
+  !$omp do ordered reduction (task, *: j) schedule (dynamic, 4)
+  do i = a, b, c
+    call bar (j)
+    !$omp ordered
+    j = j + 1
+    !$omp end ordered
+  end do
+  !$omp end parallel
+end
diff --git a/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-54.f90 b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-54.f90
new file mode 100644
index 00000000000..0681e43863c
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-54.f90
@@ -0,0 +1,35 @@
+! { dg-do compile }
+! { dg-options "-O2 -fopenmp -fdump-tree-optimized" }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_ordered_start \[^\n\r]*, (?:2147483651|-2147483645), 6, " 1 "optimized" } }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_end " 1 "optimized" } }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_ordered_start " 1 "optimized" } }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_ordered_end " 1 "optimized" } }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_ordered_guided_next " 1 "optimized" } }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_workshare_task_reduction_unregister \\(0\\)" 1 "optimized" } }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_parallel " 1 "optimized" } }
+
+module m
+  implicit none (type, external)
+  integer :: j
+  interface
+    subroutine bar(i)
+      integer :: i
+    end subroutine
+  end interface
+end module m
+
+subroutine foo(a, b, c)
+  use m
+  implicit none (type, external)
+  integer :: a, b ,c
+  integer :: i
+  !$omp parallel
+  !$omp do ordered reduction (task, *: j) schedule (guided, 6)
+  do i = a, b, c
+    call bar (j)
+    !$omp ordered
+    j = j + 1
+    !$omp end ordered
+  end do
+  !$omp end parallel
+end
diff --git a/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-55.f90 b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-55.f90
new file mode 100644
index 00000000000..4d2e1e509ef
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-55.f90
@@ -0,0 +1,35 @@
+! { dg-do compile }
+! { dg-options "-O2 -fopenmp -fdump-tree-optimized" }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_doacross_start \[^\n\r]*, (?:2147483648|-2147483648), 0, " 1 "optimized" } }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_end " 1 "optimized" } }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_doacross_post " 1 "optimized" } }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_doacross_wait " 1 "optimized" } }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_runtime_next " 1 "optimized" } }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_workshare_task_reduction_unregister \\(0\\)" 1 "optimized" } }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_parallel " 1 "optimized" } }
+
+module m
+  implicit none (type, external)
+  integer :: j
+  interface
+    subroutine bar(i)
+      integer :: i
+    end subroutine
+  end interface
+end module m
+
+subroutine foo(a, b, c)
+  use m
+  implicit none (type, external)
+  integer :: a, b ,c
+  integer :: i
+  !$omp parallel
+  !$omp do ordered(1) reduction (task, *: j) schedule (runtime)
+  do i = a, b, c
+    call bar (j)
+    !$omp ordered depend(sink: i - 1)
+    j = j + 1
+    !$omp ordered depend(source)
+  end do
+  !$omp end parallel
+end
diff --git a/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-56.f90 b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-56.f90
new file mode 100644
index 00000000000..dc5ddafa0e5
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-56.f90
@@ -0,0 +1,35 @@
+! { dg-do compile }
+! { dg-options "-O2 -fopenmp -fdump-tree-optimized" }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_doacross_start \[^\n\r]*, (?:2147483649|-2147483647), 0, " 1 "optimized" } }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_end " 1 "optimized" } }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_doacross_post " 1 "optimized" } }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_doacross_wait " 1 "optimized" } }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_static_next " 1 "optimized" } }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_workshare_task_reduction_unregister \\(0\\)" 1 "optimized" } }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_parallel " 1 "optimized" } }
+
+module m
+  implicit none (type, external)
+  integer(8) :: j
+  interface
+    subroutine bar(i)
+      integer(8) :: i
+    end subroutine
+  end interface
+end module m
+
+subroutine foo(a, b, c)
+  use m
+  implicit none (type, external)
+  integer(8) :: a, b ,c
+  integer(8) :: i
+  !$omp parallel
+  !$omp do ordered(1) reduction (task, *: j)
+  do i = a, b, c
+    call bar (j)
+    !$omp ordered depend(sink: i - 1)
+    j = j + 1
+    !$omp ordered depend(source)
+  end do
+  !$omp end parallel
+end
diff --git a/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-57.f90 b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-57.f90
new file mode 100644
index 00000000000..80424882d2c
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-57.f90
@@ -0,0 +1,35 @@
+! { dg-do compile }
+! { dg-options "-O2 -fopenmp -fdump-tree-optimized" }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_doacross_start \[^\n\r]*, (?:2147483650|-2147483646), 1, " 1 "optimized" } }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_end " 1 "optimized" } }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_doacross_post " 1 "optimized" } }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_doacross_wait " 1 "optimized" } }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_dynamic_next " 1 "optimized" } }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_workshare_task_reduction_unregister \\(0\\)" 1 "optimized" } }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_parallel " 1 "optimized" } }
+
+module m
+  implicit none (type, external)
+  integer(8) :: j
+  interface
+    subroutine bar(i)
+      integer(8) :: i
+    end subroutine
+  end interface
+end module m
+
+subroutine foo(a, b, c)
+  use m
+  implicit none (type, external)
+  integer(8) :: a, b ,c
+  integer(8) :: i
+  !$omp parallel
+  !$omp do ordered(1) reduction (task, *: j) schedule (dynamic)
+  do i = a, b, c
+    call bar (j)
+    !$omp ordered depend(sink: i - 1)
+    j = j + 1
+    !$omp ordered depend(source)
+  end do
+  !$omp end parallel
+end
diff --git a/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-58.f90 b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-58.f90
new file mode 100644
index 00000000000..ae4f8bc5ef8
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-58.f90
@@ -0,0 +1,35 @@
+! { dg-do compile }
+! { dg-options "-O2 -fopenmp -fdump-tree-optimized" }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_doacross_start \[^\n\r]*, (?:2147483651|-2147483645), 1, " 1 "optimized" } }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_end " 1 "optimized" } }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_doacross_post " 1 "optimized" } }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_doacross_wait " 1 "optimized" } }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_guided_next " 1 "optimized" } }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_workshare_task_reduction_unregister \\(0\\)" 1 "optimized" } }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_parallel " 1 "optimized" } }
+
+module m
+  implicit none (type, external)
+  integer :: j
+  interface
+    subroutine bar(i)
+      integer :: i
+    end subroutine
+  end interface
+end module m
+
+subroutine foo(a, b, c)
+  use m
+  implicit none (type, external)
+  integer :: a, b ,c
+  integer :: i
+  !$omp parallel
+  !$omp do ordered(1) reduction (task, *: j) schedule (guided)
+  do i = a, b, c
+    call bar (j)
+    !$omp ordered depend(sink: i - 1)
+    j = j + 1
+    !$omp ordered depend(source)
+  end do
+  !$omp end parallel
+end
diff --git a/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-6.f90 b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-6.f90
new file mode 100644
index 00000000000..147f14a2a35
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-6.f90
@@ -0,0 +1,31 @@
+! { dg-do compile }
+! { dg-options "-O2 -fopenmp -fdump-tree-optimized" }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_start \[^\n\r]*, (?:2147483649|-2147483647), 0, 0B, 0B, " 1 "optimized" } }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_end " 1 "optimized" } }
+! { dg-final { scan-tree-dump-not "__builtin_GOMP_loop\[^\n\r]*_next " "optimized" } }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_workshare_task_reduction_unregister \\(0\\)" 1 "optimized" } }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_parallel " 1 "optimized" } }
+
+module m
+  implicit none (type, external)
+  integer :: j
+  interface
+    subroutine bar(i)
+      integer :: i
+    end subroutine
+  end interface
+end module m
+
+subroutine foo(a, b, c)
+  use m
+  implicit none (type, external)
+  integer :: a, b ,c
+  integer :: i
+  !$omp parallel
+  !$omp do reduction (task, *: j) schedule (monotonic: static)
+  do i = a, b, c
+    j = j + 1
+    call bar (j)
+  end do
+  !$omp end parallel
+end
diff --git a/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-7.f90 b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-7.f90
new file mode 100644
index 00000000000..dc99a7512ce
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-7.f90
@@ -0,0 +1,31 @@
+! { dg-do compile }
+! { dg-options "-O2 -fopenmp -fdump-tree-optimized" }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_start \[^\n\r]*, (?:2147483649|-2147483647), 0, 0B, 0B, " 1 "optimized" } }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_end " 1 "optimized" } }
+! { dg-final { scan-tree-dump-not "__builtin_GOMP_loop\[^\n\r]*_next " "optimized" } }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_workshare_task_reduction_unregister \\(0\\)" 1 "optimized" } }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_parallel " 1 "optimized" } }
+
+module m
+  implicit none (type, external)
+  integer :: j
+  interface
+    subroutine bar(i)
+      integer :: i
+    end subroutine
+  end interface
+end module m
+
+subroutine foo(a, b, c)
+  use m
+  implicit none (type, external)
+  integer :: a, b ,c
+  integer :: i
+  !$omp parallel
+  !$omp do reduction (task, *: j) schedule (nonmonotonic: static)
+  do i = a, b, c
+    j = j + 1
+    call bar (j)
+  end do
+  !$omp end parallel
+end
diff --git a/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-8.f90 b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-8.f90
new file mode 100644
index 00000000000..9d0a1ce95f9
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-8.f90
@@ -0,0 +1,31 @@
+! { dg-do compile }
+! { dg-options "-O2 -fopenmp -fdump-tree-optimized" }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_start \[^\n\r]*, (?:2147483649|-2147483647), 0, 0B, 0B, " 1 "optimized" } }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_end " 1 "optimized" } }
+! { dg-final { scan-tree-dump-not "__builtin_GOMP_loop\[^\n\r]*_next " "optimized" } }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_workshare_task_reduction_unregister \\(0\\)" 1 "optimized" } }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_parallel " 1 "optimized" } }
+
+module m
+  implicit none (type, external)
+  integer :: j
+  interface
+    subroutine bar(i)
+      integer :: i
+    end subroutine
+  end interface
+end module m
+
+subroutine foo(a, b, c)
+  use m
+  implicit none (type, external)
+  integer :: a, b ,c
+  integer :: i
+  !$omp parallel
+  !$omp do reduction (task, *: j) schedule (static, 2)
+  do i = a, b, c
+    j = j + 1
+    call bar (j)
+  end do
+  !$omp end parallel
+end
diff --git a/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-9.f90 b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-9.f90
new file mode 100644
index 00000000000..c61374613be
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/gomp/workshare-reduction-9.f90
@@ -0,0 +1,31 @@
+! { dg-do compile }
+! { dg-options "-O2 -fopenmp -fdump-tree-optimized" }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_start \[^\n\r]*, (?:2147483649|-2147483647), 0, 0B, 0B, " 1 "optimized" } }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_loop_end " 1 "optimized" } }
+! { dg-final { scan-tree-dump-not "__builtin_GOMP_loop\[^\n\r]*_next " "optimized" } }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_workshare_task_reduction_unregister \\(0\\)" 1 "optimized" } }
+! { dg-final { scan-tree-dump-times "__builtin_GOMP_parallel " 1 "optimized" } }
+
+module m
+  implicit none (type, external)
+  integer :: j
+  interface
+    subroutine bar(i)
+      integer :: i
+    end subroutine
+  end interface
+end module m
+
+subroutine foo(a, b, c)
+  use m
+  implicit none (type, external)
+  integer :: a, b ,c
+  integer :: i
+  !$omp parallel
+  !$omp do reduction (task, *: j) schedule (monotonic: static, 2)
+  do i = a, b, c
+    j = j + 1
+    call bar (j)
+  end do
+  !$omp end parallel
+end

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

end of thread, other threads:[~2020-11-11 15:16 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-11-09 23:40 [Patch] Fortran: OpenMP 5.0 (in_,task_)reduction clause extensions Tobias Burnus
2020-11-10 12:16 ` Jakub Jelinek
2020-11-10 16:46   ` Tobias Burnus
2020-11-10 17:23     ` Jakub Jelinek
2020-11-11  8:25     ` [committed] gfortran.dg/gomp/workshare-reduction-*.f90: Fix dumps for -m32 (was: Re: [Patch] Fortran: OpenMP 5.0 (in_, task_)reduction clause extensions) Tobias Burnus
2020-11-11  9:39       ` Jakub Jelinek
2020-11-11 13:40       ` Thomas Schwinge
2020-11-11 15:16         ` [committed] testsuite: Fix up scan-tree-dump-times regexps for 64-bit targets 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).