diff mbox series

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

Message ID 50dd6d9f-d646-8475-14a9-da2d283ebbb6@codesourcery.com
State New
Headers show
Series Fortran: OpenMP 5.0 (in_,task_)reduction clause extensions | expand

Commit Message

Tobias Burnus Nov. 9, 2020, 11:40 p.m. UTC
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

Comments

Jakub Jelinek Nov. 10, 2020, 12:16 p.m. UTC | #1
On Tue, Nov 10, 2020 at 12:40:08AM +0100, Tobias Burnus wrote:
> --- 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,

I don't understand the need for OMP_CLAUSE_REDUCTION_DEFAULT,
default modifier is allowed in all OpenMP reduction clauses and
your gfc_match_omp_clause_reduction function has the openacc argument.
So why can't you keep using OMP_CLAUSE_REDUCTION in place where
you use OMP_CLAUSE_REDUCTION_DEFAULT now and just decide based on !openacc
whether to parse any reduction modifiers?

One could probably get away even without OMP_CLAUSE_REDUCTION_MODIFIER,
just allow all the modifiers first and during resolving complain if
[OMP_LIST_REDUCTION_INSCAN] and/or [OMP_LIST_REDUCTION_TASK] is non-NULL
on constructs where it shouldn't.

When splitting clauses, OMP_LIST_REDUCTION_TASK applies only on the innermost
construct that accepts it (others should treat it as OMP_LIST_REDUCTION),
and inscan is severely limited to which constructs it can appear on.
For task modifier, do you diagnose somewhere what c_split_omp_clauses
diagnoses?
E.g. if task modifier appears with innermost combined construct simd/loop,
or if task modifier appears and not combined with parallel/do/sections?
Inscan is allowed only on do, simd, do simd, parallel do and parallel do sim.d

Also, I think there should be an error or sorry on the inscan modifier
somewhere until the rest of the scan support is implemented (in particular
the changes in the parsing of do/simd body with inscan reductions
including the parsing of the inclusive/exclusive directives in there).

>  #define OMP_DECLARE_SIMD_CLAUSES \
>    (omp_mask (OMP_CLAUSE_SIMDLEN) | OMP_CLAUSE_LINEAR			\
>     | OMP_CLAUSE_UNIFORM	| OMP_CLAUSE_ALIGNED | OMP_CLAUSE_INBRANCH	\

I wonder why we have the occassional tabs in the middle of the OMP_*_CLAUSES
defines.
> +   | OMP_CLAUSE_SAFELEN | OMP_CLAUSE_LINEAR | OMP_CLAUSE_ALIGNED	\
> +   | OMP_CLAUSE_SIMDLEN	| OMP_CLAUSE_IF | OMP_CLAUSE_ORDER		\

Here too.

> +      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];
> +	}

Seems in the middle-end we just ignore OMP_CLAUSE_REDUCTION_TASK on anything
but parallel/{for,do}/sections, so guess this is ok.

	Jakub
Tobias Burnus Nov. 10, 2020, 4:46 p.m. UTC | #2
Hi Jakub,

thanks for the comments. I have now removed
OMP_CLAUSE_REDUCTION{_DEFAULT,_MODIFIER} and use 'openacc' as flag for OpenACC.
The only 'default:' check is now moved to resolution stage.

If I gathered it correctly, the splitting is complex but the
way it is implemented, it happens to be fine.

We discussed that the _LIST part gets too long (but that's something
for later) and that 'omp scan' best get implemented during stage1.
(Additionally, I believe that the ME always complains about 'inscan'
not being in 'omp scan' – and it can't as 'omp scan' is not yet
supported.)

On 10.11.20 13:16, Jakub Jelinek wrote:

>> +      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];
>> +    }
> Seems in the middle-end we just ignore OMP_CLAUSE_REDUCTION_TASK on anything
> but parallel/{for,do}/sections, so guess this is ok.


Tobias

-----------------
Mentor Graphics (Deutschland) GmbH, Arnulfstraße 201, 80634 München / Germany
Registergericht München HRB 106955, Geschäftsführer: Thomas Heurung, Alexander Walter
Jakub Jelinek Nov. 10, 2020, 5:23 p.m. UTC | #3
On Tue, Nov 10, 2020 at 05:46:17PM +0100, Tobias Burnus wrote:
> 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_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_TASK_CLAUSES, OMP_TARGET_CLAUSES, OMP_TASKLOOP_CLAUSES):
> 	Add OMP_CLAUSE_IN_REDUCTION.
> 	(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.

Ok, thanks.

	Jakub
diff mbox series

Patch

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