public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [committed] openmp: Add support for OpenMP 5.1 masked construct
@ 2021-08-12 20:48 Jakub Jelinek
  2021-08-13 14:37 ` [Patch] Fortran/OpenMP: Add support for OpenMP 5.1 masked construct (was: Re: [committed] openmp: Add support for OpenMP 5.1 masked construct) Tobias Burnus
  2021-08-13 21:05 ` [committed] openmp: Add support for OpenMP 5.1 masked construct Thomas Schwinge
  0 siblings, 2 replies; 5+ messages in thread
From: Jakub Jelinek @ 2021-08-12 20:48 UTC (permalink / raw)
  To: gcc-patches

Hi!

This construct has been introduced as a replacement for master
construct, but unlike that construct is slightly more general,
has an optional clause which allows to choose which thread
will be the one running the region, it can be some other thread
than the master (primary) thread with number 0, or it could be no
threads or multiple threads (then of course one needs to be careful
about data races).

It is way too early to deprecate the master construct though, we don't
even have OpenMP 5.0 fully implemented, it has been deprecated in 5.1,
will be also in 5.2 and removed in 6.0.  But even then it will likely
be a good idea to just -Wdeprecated warn about it and still accept it.

The patch also contains something I should have done much earlier,
for clauses that accept some integral expression where we only care
about the value, forces during gimplification that value into
either a min invariant (as before), SSA_NAME or a fresh temporary,
but never e.g. a user VAR_DECL, so that for those clauses we don't
need to worry about adjusting it.

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

2021-08-12  Jakub Jelinek  <jakub@redhat.com>

gcc/
	* tree.def (OMP_MASKED): New tree code.
	* tree-core.h (enum omp_clause_code): Add OMP_CLAUSE_FILTER.
	* tree.h (OMP_MASKED_BODY, OMP_MASKED_CLAUSES, OMP_MASKED_COMBINED,
	OMP_CLAUSE_FILTER_EXPR): Define.
	* tree.c (omp_clause_num_ops): Add OMP_CLAUSE_FILTER entry.
	(omp_clause_code_name): Likewise.
	(walk_tree_1): Handle OMP_CLAUSE_FILTER.
	* tree-nested.c (convert_nonlocal_omp_clauses,
	convert_local_omp_clauses): Handle OMP_CLAUSE_FILTER.
	(convert_nonlocal_reference_stmt, convert_local_reference_stmt,
	convert_gimple_call): Handle GIMPLE_OMP_MASTER.
	* tree-pretty-print.c (dump_omp_clause): Handle OMP_CLAUSE_FILTER.
	(dump_generic_node): Handle OMP_MASTER.
	* gimple.def (GIMPLE_OMP_MASKED): New gimple code.
	* gimple.c (gimple_build_omp_masked): New function.
	(gimple_copy): Handle GIMPLE_OMP_MASKED.
	* gimple.h (gimple_build_omp_masked): Declare.
	(gimple_has_substatements): Handle GIMPLE_OMP_MASKED.
	(gimple_omp_masked_clauses, gimple_omp_masked_clauses_ptr,
	gimple_omp_masked_set_clauses): New inline functions.
	(CASE_GIMPLE_OMP): Add GIMPLE_OMP_MASKED.
	* gimple-pretty-print.c (dump_gimple_omp_masked): New function.
	(pp_gimple_stmt_1): Handle GIMPLE_OMP_MASKED.
	* gimple-walk.c (walk_gimple_stmt): Likewise.
	* gimple-low.c (lower_stmt): Likewise.
	* gimplify.c (is_gimple_stmt): Handle OMP_MASTER.
	(gimplify_scan_omp_clauses): Handle OMP_CLAUSE_FILTER.  For clauses
	that take one expression rather than decl or constant, force
	gimplification of that into a SSA_NAME or temporary unless min
	invariant.
	(gimplify_adjust_omp_clauses): Handle OMP_CLAUSE_FILTER.
	(gimplify_expr): Handle OMP_MASKED.
	* tree-inline.c (remap_gimple_stmt): Handle GIMPLE_OMP_MASKED.
	(estimate_num_insns): Likewise.
	* omp-low.c (scan_sharing_clauses): Handle OMP_CLAUSE_FILTER.
	(check_omp_nesting_restrictions): Handle GIMPLE_OMP_MASKED.  Adjust
	diagnostics for existence of masked construct.
	(scan_omp_1_stmt, lower_omp_master, lower_omp_1, diagnose_sb_1,
	diagnose_sb_2): Handle GIMPLE_OMP_MASKED.
	* omp-expand.c (expand_omp_synch, expand_omp, omp_make_gimple_edges):
	Likewise.
gcc/c-family/
	* c-pragma.h (enum pragma_kind): Add PRAGMA_OMP_MASKED.
	(enum pragma_omp_clause): Add PRAGMA_OMP_CLAUSE_FILTER.
	* c-pragma.c (omp_pragmas_simd): Add masked construct.
	* c-common.h (enum c_omp_clause_split): Add C_OMP_CLAUSE_SPLIT_MASKED
	enumerator.
	(c_finish_omp_masked): Declare.
	* c-omp.c (c_finish_omp_masked): New function.
	(c_omp_split_clauses): Handle combined masked constructs.
gcc/c/
	* c-parser.c (c_parser_omp_clause_name): Parse filter clause name.
	(c_parser_omp_clause_filter): New function.
	(c_parser_omp_all_clauses): Handle PRAGMA_OMP_CLAUSE_FILTER.
	(OMP_MASKED_CLAUSE_MASK): Define.
	(c_parser_omp_masked): New function.
	(c_parser_omp_parallel): Handle parallel masked.
	(c_parser_omp_construct): Handle PRAGMA_OMP_MASKED.
	* c-typeck.c (c_finish_omp_clauses): Handle OMP_CLAUSE_FILTER.
gcc/cp/
	* parser.c (cp_parser_omp_clause_name): Parse filter clause name.
	(cp_parser_omp_clause_filter): New function.
	(cp_parser_omp_all_clauses): Handle PRAGMA_OMP_CLAUSE_FILTER.
	(OMP_MASKED_CLAUSE_MASK): Define.
	(cp_parser_omp_masked): New function.
	(cp_parser_omp_parallel): Handle parallel masked.
	(cp_parser_omp_construct, cp_parser_pragma): Handle PRAGMA_OMP_MASKED.
	* semantics.c (finish_omp_clauses): Handle OMP_CLAUSE_FILTER.
	* pt.c (tsubst_omp_clauses): Likewise.
	(tsubst_expr): Handle OMP_MASKED.
gcc/testsuite/
	* c-c++-common/gomp/clauses-1.c (bar): Add tests for combined masked
	constructs with clauses.
	* c-c++-common/gomp/clauses-5.c (foo): Add testcase for filter clause.
	* c-c++-common/gomp/clause-dups-1.c (f1): Likewise.
	* c-c++-common/gomp/masked-1.c: New test.
	* c-c++-common/gomp/masked-2.c: New test.
	* c-c++-common/gomp/masked-combined-1.c: New test.
	* c-c++-common/gomp/masked-combined-2.c: New test.
	* c-c++-common/goacc/uninit-if-clause.c: Remove xfails.
	* g++.dg/gomp/block-11.C: New test.
	* g++.dg/gomp/tpl-masked-1.C: New test.
	* g++.dg/gomp/attrs-1.C (bar): Add tests for masked construct and
	combined masked constructs with clauses in attribute syntax.
	* g++.dg/gomp/attrs-2.C (bar): Likewise.
	* gcc.dg/gomp/nesting-1.c (f1, f2): Add tests for masked construct
	nesting.
	* gfortran.dg/goacc/host_data-tree.f95: Allow also SSA_NAMEs in if
	clause.
	* gfortran.dg/goacc/kernels-tree.f95: Likewise.
libgomp/
	* testsuite/libgomp.c-c++-common/masked-1.c: New test.

--- gcc/tree.def.jj	2021-08-11 23:43:45.969076312 +0200
+++ gcc/tree.def	2021-08-12 12:14:07.716732122 +0200
@@ -1218,6 +1218,11 @@ DEFTREECODE (OMP_SINGLE, "omp_single", t
    Operand 1: OMP_SINGLE_CLAUSES: List of clauses.  */
 DEFTREECODE (OMP_TASKGROUP, "omp_taskgroup", tcc_statement, 2)
 
+/* OpenMP - #pragma omp masked
+   Operand 0: OMP_MASKED_BODY: Masked section body.
+   Operand 1: OMP_MASKED_CLAUSES: List of clauses.  */
+DEFTREECODE (OMP_MASKED, "omp_masked", tcc_statement, 2)
+
 /* OpenMP - #pragma omp scan
    Operand 0: OMP_SCAN_BODY: Scan body.
    Operand 1: OMP_SCAN_CLAUSES: List of clauses.  */
--- gcc/tree-core.h.jj	2021-08-11 23:43:45.965076367 +0200
+++ gcc/tree-core.h	2021-08-12 12:14:07.719732080 +0200
@@ -476,6 +476,9 @@ enum omp_clause_code {
   /* OpenMP clause: bind (binding).  */
   OMP_CLAUSE_BIND,
 
+  /* OpenMP clause: filter (integer-expression).  */
+  OMP_CLAUSE_FILTER,
+
   /* Internally used only clause, holding SIMD uid.  */
   OMP_CLAUSE__SIMDUID_,
 
--- gcc/tree.h.jj	2021-08-11 23:43:45.971076284 +0200
+++ gcc/tree.h	2021-08-12 12:14:07.706732262 +0200
@@ -1429,6 +1429,9 @@ class auto_suppress_location_wrappers
 
 #define OMP_MASTER_BODY(NODE)	   TREE_OPERAND (OMP_MASTER_CHECK (NODE), 0)
 
+#define OMP_MASKED_BODY(NODE)	   TREE_OPERAND (OMP_MASKED_CHECK (NODE), 0)
+#define OMP_MASKED_CLAUSES(NODE)   TREE_OPERAND (OMP_MASKED_CHECK (NODE), 1)
+
 #define OMP_TASKGROUP_BODY(NODE)   TREE_OPERAND (OMP_TASKGROUP_CHECK (NODE), 0)
 #define OMP_TASKGROUP_CLAUSES(NODE) \
   TREE_OPERAND (OMP_TASKGROUP_CHECK (NODE), 1)
@@ -1508,6 +1511,11 @@ class auto_suppress_location_wrappers
 #define OMP_MASTER_COMBINED(NODE) \
   (OMP_MASTER_CHECK (NODE)->base.private_flag)
 
+/* True on an OMP_MASKED statement if it represents an explicit
+   combined masked constructs.  */
+#define OMP_MASKED_COMBINED(NODE) \
+  (OMP_MASKED_CHECK (NODE)->base.private_flag)
+
 /* Memory order for OMP_ATOMIC*.  */
 #define OMP_ATOMIC_MEMORY_ORDER(NODE) \
   (TREE_RANGE_CHECK (NODE, OMP_ATOMIC, \
@@ -1592,6 +1600,8 @@ class auto_suppress_location_wrappers
   OMP_CLAUSE_OPERAND (OMP_CLAUSE_SUBCODE_CHECK (NODE, OMP_CLAUSE_NUM_TASKS), 0)
 #define OMP_CLAUSE_HINT_EXPR(NODE) \
   OMP_CLAUSE_OPERAND (OMP_CLAUSE_SUBCODE_CHECK (NODE, OMP_CLAUSE_HINT), 0)
+#define OMP_CLAUSE_FILTER_EXPR(NODE) \
+  OMP_CLAUSE_OPERAND (OMP_CLAUSE_SUBCODE_CHECK (NODE, OMP_CLAUSE_FILTER), 0)
 
 #define OMP_CLAUSE_GRAINSIZE_EXPR(NODE) \
   OMP_CLAUSE_OPERAND (OMP_CLAUSE_SUBCODE_CHECK (NODE, OMP_CLAUSE_GRAINSIZE),0)
--- gcc/tree.c.jj	2021-08-11 23:43:45.969076312 +0200
+++ gcc/tree.c	2021-08-12 12:14:07.719732080 +0200
@@ -350,6 +350,7 @@ unsigned const char omp_clause_num_ops[]
   0, /* OMP_CLAUSE_DEFAULTMAP  */
   0, /* OMP_CLAUSE_ORDER  */
   0, /* OMP_CLAUSE_BIND  */
+  1, /* OMP_CLAUSE_FILTER  */
   1, /* OMP_CLAUSE__SIMDUID_  */
   0, /* OMP_CLAUSE__SIMT_  */
   0, /* OMP_CLAUSE_INDEPENDENT  */
@@ -438,6 +439,7 @@ const char * const omp_clause_code_name[
   "defaultmap",
   "order",
   "bind",
+  "filter",
   "_simduid_",
   "_simt_",
   "independent",
@@ -11126,6 +11128,7 @@ walk_tree_1 (tree *tp, walk_tree_fn func
 	case OMP_CLAUSE_GRAINSIZE:
 	case OMP_CLAUSE_NUM_TASKS:
 	case OMP_CLAUSE_HINT:
+	case OMP_CLAUSE_FILTER:
 	case OMP_CLAUSE_TO_DECLARE:
 	case OMP_CLAUSE_LINK:
 	case OMP_CLAUSE_DETACH:
--- gcc/tree-nested.c.jj	2021-08-11 23:43:45.966076353 +0200
+++ gcc/tree-nested.c	2021-08-12 12:14:07.720732066 +0200
@@ -1376,6 +1376,7 @@ convert_nonlocal_omp_clauses (tree *pcla
 	case OMP_CLAUSE_GRAINSIZE:
 	case OMP_CLAUSE_NUM_TASKS:
 	case OMP_CLAUSE_HINT:
+	case OMP_CLAUSE_FILTER:
 	case OMP_CLAUSE_NUM_GANGS:
 	case OMP_CLAUSE_NUM_WORKERS:
 	case OMP_CLAUSE_VECTOR_LENGTH:
@@ -1785,6 +1786,7 @@ convert_nonlocal_reference_stmt (gimple_
 
     case GIMPLE_OMP_SECTION:
     case GIMPLE_OMP_MASTER:
+    case GIMPLE_OMP_MASKED:
     case GIMPLE_OMP_ORDERED:
     case GIMPLE_OMP_SCAN:
       walk_body (convert_nonlocal_reference_stmt, convert_nonlocal_reference_op,
@@ -2154,6 +2156,7 @@ convert_local_omp_clauses (tree *pclause
 	case OMP_CLAUSE_GRAINSIZE:
 	case OMP_CLAUSE_NUM_TASKS:
 	case OMP_CLAUSE_HINT:
+	case OMP_CLAUSE_FILTER:
 	case OMP_CLAUSE_NUM_GANGS:
 	case OMP_CLAUSE_NUM_WORKERS:
 	case OMP_CLAUSE_VECTOR_LENGTH:
@@ -2518,6 +2521,7 @@ convert_local_reference_stmt (gimple_stm
 
     case GIMPLE_OMP_SECTION:
     case GIMPLE_OMP_MASTER:
+    case GIMPLE_OMP_MASKED:
     case GIMPLE_OMP_ORDERED:
     case GIMPLE_OMP_SCAN:
       walk_body (convert_local_reference_stmt, convert_local_reference_op,
@@ -3028,6 +3032,7 @@ convert_gimple_call (gimple_stmt_iterato
     case GIMPLE_OMP_SECTION:
     case GIMPLE_OMP_SINGLE:
     case GIMPLE_OMP_MASTER:
+    case GIMPLE_OMP_MASKED:
     case GIMPLE_OMP_TASKGROUP:
     case GIMPLE_OMP_ORDERED:
     case GIMPLE_OMP_SCAN:
--- gcc/tree-pretty-print.c.jj	2021-08-11 23:43:45.967076340 +0200
+++ gcc/tree-pretty-print.c	2021-08-12 12:14:07.710732206 +0200
@@ -1083,6 +1083,13 @@ dump_omp_clause (pretty_printer *pp, tre
       pp_right_paren (pp);
       break;
 
+    case OMP_CLAUSE_FILTER:
+      pp_string (pp, "filter(");
+      dump_generic_node (pp, OMP_CLAUSE_FILTER_EXPR (clause),
+			 spc, flags, false);
+      pp_right_paren (pp);
+      break;
+
     case OMP_CLAUSE_DEFAULTMAP:
       pp_string (pp, "defaultmap(");
       switch (OMP_CLAUSE_DEFAULTMAP_BEHAVIOR (clause))
@@ -3584,6 +3591,11 @@ dump_generic_node (pretty_printer *pp, t
       pp_string (pp, "#pragma omp master");
       goto dump_omp_body;
 
+    case OMP_MASKED:
+      pp_string (pp, "#pragma omp masked");
+      dump_omp_clauses (pp, OMP_MASKED_CLAUSES (node), spc, flags);
+      goto dump_omp_body;
+
     case OMP_TASKGROUP:
       pp_string (pp, "#pragma omp taskgroup");
       dump_omp_clauses (pp, OMP_TASKGROUP_CLAUSES (node), spc, flags);
--- gcc/gimple.def.jj	2021-08-11 23:43:45.894077347 +0200
+++ gcc/gimple.def	2021-08-12 12:14:07.719732080 +0200
@@ -279,6 +279,10 @@ DEFGSCODE(GIMPLE_OMP_FOR, "gimple_omp_fo
    BODY is the sequence of statements to execute in the master section.  */
 DEFGSCODE(GIMPLE_OMP_MASTER, "gimple_omp_master", GSS_OMP)
 
+/* GIMPLE_OMP_MASKED <BODY, CLAUSES> represents #pragma omp masked.
+   BODY is the sequence of statements to execute in the masked section.  */
+DEFGSCODE(GIMPLE_OMP_MASKED, "gimple_omp_masked", GSS_OMP_SINGLE_LAYOUT)
+
 /* GIMPLE_OMP_TASKGROUP <BODY, CLAUSES> represents #pragma omp taskgroup.
    BODY is the sequence of statements inside the taskgroup section.
    CLAUSES is an OMP_CLAUSE chain holding the associated clauses.  */
--- gcc/gimple.c.jj	2021-08-11 23:43:45.894077347 +0200
+++ gcc/gimple.c	2021-08-12 12:14:07.712732178 +0200
@@ -1038,6 +1038,21 @@ gimple_build_omp_master (gimple_seq body
   return p;
 }
 
+/* Build a GIMPLE_OMP_MASKED statement.
+
+   BODY is the sequence of statements to be executed by the selected thread(s).  */
+
+gimple *
+gimple_build_omp_masked (gimple_seq body, tree clauses)
+{
+  gimple *p = gimple_alloc (GIMPLE_OMP_MASKED, 0);
+  gimple_omp_masked_set_clauses (p, clauses);
+  if (body)
+    gimple_omp_set_body (p, body);
+
+  return p;
+}
+
 /* Build a GIMPLE_OMP_TASKGROUP statement.
 
    BODY is the sequence of statements to be executed by the taskgroup
@@ -2031,6 +2046,11 @@ gimple_copy (gimple *stmt)
 	  gimple_omp_set_body (copy, new_seq);
 	  break;
 
+	case GIMPLE_OMP_MASKED:
+	  t = unshare_expr (gimple_omp_masked_clauses (stmt));
+	  gimple_omp_masked_set_clauses (copy, t);
+	  goto copy_omp_body;
+
 	case GIMPLE_TRANSACTION:
 	  new_seq = gimple_seq_copy (gimple_transaction_body (
 				       as_a <gtransaction *> (stmt)));
--- gcc/gimple.h.jj	2021-08-11 23:43:45.894077347 +0200
+++ gcc/gimple.h	2021-08-12 12:14:07.718732094 +0200
@@ -1560,6 +1560,7 @@ gomp_task *gimple_build_omp_task (gimple
 				       tree, tree);
 gimple *gimple_build_omp_section (gimple_seq);
 gimple *gimple_build_omp_master (gimple_seq);
+gimple *gimple_build_omp_masked (gimple_seq, tree);
 gimple *gimple_build_omp_taskgroup (gimple_seq, tree);
 gomp_continue *gimple_build_omp_continue (tree, tree);
 gomp_ordered *gimple_build_omp_ordered (gimple_seq, tree);
@@ -1836,6 +1837,7 @@ gimple_has_substatements (gimple *g)
     case GIMPLE_TRY:
     case GIMPLE_OMP_FOR:
     case GIMPLE_OMP_MASTER:
+    case GIMPLE_OMP_MASKED:
     case GIMPLE_OMP_TASKGROUP:
     case GIMPLE_OMP_ORDERED:
     case GIMPLE_OMP_SECTION:
@@ -5205,6 +5207,40 @@ gimple_omp_taskgroup_set_clauses (gimple
 }
 
 
+/* Return the clauses associated with OMP_MASTER statement GS.  */
+
+static inline tree
+gimple_omp_masked_clauses (const gimple *gs)
+{
+  GIMPLE_CHECK (gs, GIMPLE_OMP_MASKED);
+  return
+    static_cast <const gimple_statement_omp_single_layout *> (gs)->clauses;
+}
+
+
+/* Return a pointer to the clauses associated with OMP masked statement
+   GS.  */
+
+static inline tree *
+gimple_omp_masked_clauses_ptr (gimple *gs)
+{
+  GIMPLE_CHECK (gs, GIMPLE_OMP_MASKED);
+  return &static_cast <gimple_statement_omp_single_layout *> (gs)->clauses;
+}
+
+
+/* Set CLAUSES to be the clauses associated with OMP masked statement
+   GS.  */
+
+static inline void
+gimple_omp_masked_set_clauses (gimple *gs, tree clauses)
+{
+  GIMPLE_CHECK (gs, GIMPLE_OMP_MASKED);
+  static_cast <gimple_statement_omp_single_layout *> (gs)->clauses
+    = clauses;
+}
+
+
 /* Return the kind of the OMP_FOR statemement G.  */
 
 static inline int
@@ -6493,6 +6529,7 @@ gimple_return_set_retval (greturn *gs, t
     case GIMPLE_OMP_TEAMS:			\
     case GIMPLE_OMP_SECTION:			\
     case GIMPLE_OMP_MASTER:			\
+    case GIMPLE_OMP_MASKED:			\
     case GIMPLE_OMP_TASKGROUP:			\
     case GIMPLE_OMP_ORDERED:			\
     case GIMPLE_OMP_CRITICAL:			\
--- gcc/gimple-pretty-print.c.jj	2021-08-11 23:43:45.893077361 +0200
+++ gcc/gimple-pretty-print.c	2021-08-12 12:14:07.719732080 +0200
@@ -1658,6 +1658,35 @@ dump_gimple_omp_taskgroup (pretty_printe
     }
 }
 
+/* Dump a GIMPLE_OMP_MASKED tuple on the pretty_printer BUFFER.  */
+
+static void
+dump_gimple_omp_masked (pretty_printer *buffer, const gimple *gs,
+			int spc, dump_flags_t flags)
+{
+  if (flags & TDF_RAW)
+    {
+      dump_gimple_fmt (buffer, spc, flags, "%G <%+BODY <%S>%nCLAUSES <", gs,
+		       gimple_omp_body (gs));
+      dump_omp_clauses (buffer, gimple_omp_masked_clauses (gs), spc, flags);
+      dump_gimple_fmt (buffer, spc, flags, " >");
+    }
+  else
+    {
+      pp_string (buffer, "#pragma omp masked");
+      dump_omp_clauses (buffer, gimple_omp_masked_clauses (gs), spc, flags);
+      if (!gimple_seq_empty_p (gimple_omp_body (gs)))
+	{
+	  newline_and_indent (buffer, spc + 2);
+	  pp_left_brace (buffer);
+	  pp_newline (buffer);
+	  dump_gimple_seq (buffer, gimple_omp_body (gs), spc + 4, flags);
+	  newline_and_indent (buffer, spc + 2);
+	  pp_right_brace (buffer);
+	}
+    }
+}
+
 /* Dump a GIMPLE_OMP_TARGET tuple on the pretty_printer BUFFER.  */
 
 static void
@@ -2722,6 +2751,10 @@ pp_gimple_stmt_1 (pretty_printer *buffer
       dump_gimple_omp_taskgroup (buffer, gs, spc, flags);
       break;
 
+    case GIMPLE_OMP_MASKED:
+      dump_gimple_omp_masked (buffer, gs, spc, flags);
+      break;
+
     case GIMPLE_OMP_MASTER:
     case GIMPLE_OMP_SECTION:
       dump_gimple_omp_block (buffer, gs, spc, flags);
--- gcc/gimple-walk.c.jj	2021-08-11 23:43:45.893077361 +0200
+++ gcc/gimple-walk.c	2021-08-12 12:14:07.713732164 +0200
@@ -682,6 +682,7 @@ walk_gimple_stmt (gimple_stmt_iterator *
       /* FALL THROUGH.  */
     case GIMPLE_OMP_CRITICAL:
     case GIMPLE_OMP_MASTER:
+    case GIMPLE_OMP_MASKED:
     case GIMPLE_OMP_TASKGROUP:
     case GIMPLE_OMP_ORDERED:
     case GIMPLE_OMP_SCAN:
--- gcc/gimple-low.c.jj	2021-08-11 23:43:45.892077375 +0200
+++ gcc/gimple-low.c	2021-08-12 12:14:07.703732304 +0200
@@ -334,6 +334,7 @@ lower_stmt (gimple_stmt_iterator *gsi, s
     case GIMPLE_OMP_SECTION:
     case GIMPLE_OMP_SINGLE:
     case GIMPLE_OMP_MASTER:
+    case GIMPLE_OMP_MASKED:
     case GIMPLE_OMP_TASKGROUP:
     case GIMPLE_OMP_ORDERED:
     case GIMPLE_OMP_SCAN:
--- gcc/gimplify.c.jj	2021-08-11 23:43:45.897077306 +0200
+++ gcc/gimplify.c	2021-08-12 14:47:57.451971003 +0200
@@ -5632,6 +5632,7 @@ is_gimple_stmt (tree t)
     case OMP_SECTION:
     case OMP_SINGLE:
     case OMP_MASTER:
+    case OMP_MASKED:
     case OMP_TASKGROUP:
     case OMP_ORDERED:
     case OMP_CRITICAL:
@@ -10102,6 +10103,7 @@ gimplify_scan_omp_clauses (tree *list_p,
 	case OMP_CLAUSE_PRIORITY:
 	case OMP_CLAUSE_GRAINSIZE:
 	case OMP_CLAUSE_NUM_TASKS:
+	case OMP_CLAUSE_FILTER:
 	case OMP_CLAUSE_HINT:
 	case OMP_CLAUSE_ASYNC:
 	case OMP_CLAUSE_WAIT:
@@ -10110,9 +10112,20 @@ gimplify_scan_omp_clauses (tree *list_p,
 	case OMP_CLAUSE_VECTOR_LENGTH:
 	case OMP_CLAUSE_WORKER:
 	case OMP_CLAUSE_VECTOR:
-	  if (gimplify_expr (&OMP_CLAUSE_OPERAND (c, 0), pre_p, NULL,
-			     is_gimple_val, fb_rvalue) == GS_ERROR)
-	    remove = true;
+	  if (OMP_CLAUSE_OPERAND (c, 0)
+	      && !is_gimple_min_invariant (OMP_CLAUSE_OPERAND (c, 0)))
+	    {
+	      if (error_operand_p (OMP_CLAUSE_OPERAND (c, 0)))
+		{
+		  remove = true;
+		  break;
+		}
+	      /* All these clauses care about value, not a particular decl,
+		 so try to force it into a SSA_NAME or fresh temporary.  */
+	      OMP_CLAUSE_OPERAND (c, 0)
+		= get_initialized_tmp_var (OMP_CLAUSE_OPERAND (c, 0),
+					   pre_p, NULL, true);
+	    }
 	  break;
 
 	case OMP_CLAUSE_GANG:
@@ -11222,6 +11235,7 @@ gimplify_adjust_omp_clauses (gimple_seq
 	case OMP_CLAUSE_NOGROUP:
 	case OMP_CLAUSE_THREADS:
 	case OMP_CLAUSE_SIMD:
+	case OMP_CLAUSE_FILTER:
 	case OMP_CLAUSE_HINT:
 	case OMP_CLAUSE_DEFAULTMAP:
 	case OMP_CLAUSE_ORDER:
@@ -14766,6 +14780,7 @@ gimplify_expr (tree *expr_p, gimple_seq
 
 	case OMP_SECTION:
 	case OMP_MASTER:
+	case OMP_MASKED:
 	case OMP_ORDERED:
 	case OMP_CRITICAL:
 	case OMP_SCAN:
@@ -14788,6 +14803,15 @@ gimplify_expr (tree *expr_p, gimple_seq
 	      case OMP_ORDERED:
 		g = gimplify_omp_ordered (*expr_p, body);
 		break;
+	      case OMP_MASKED:
+		gimplify_scan_omp_clauses (&OMP_MASKED_CLAUSES (*expr_p),
+					   pre_p, ORT_WORKSHARE, OMP_MASKED);
+		gimplify_adjust_omp_clauses (pre_p, body,
+					     &OMP_MASKED_CLAUSES (*expr_p),
+					     OMP_MASKED);
+		g = gimple_build_omp_masked (body,
+					     OMP_MASKED_CLAUSES (*expr_p));
+		break;
 	      case OMP_CRITICAL:
 		gimplify_scan_omp_clauses (&OMP_CRITICAL_CLAUSES (*expr_p),
 					   pre_p, ORT_WORKSHARE, OMP_CRITICAL);
@@ -15161,6 +15185,7 @@ gimplify_expr (tree *expr_p, gimple_seq
 		  && code != OMP_FOR
 		  && code != OACC_LOOP
 		  && code != OMP_MASTER
+		  && code != OMP_MASKED
 		  && code != OMP_TASKGROUP
 		  && code != OMP_ORDERED
 		  && code != OMP_PARALLEL
--- gcc/tree-inline.c.jj	2021-08-11 23:43:45.966076353 +0200
+++ gcc/tree-inline.c	2021-08-12 12:14:07.706732262 +0200
@@ -1658,6 +1658,12 @@ remap_gimple_stmt (gimple *stmt, copy_bo
 	  copy = gimple_build_omp_master (s1);
 	  break;
 
+	case GIMPLE_OMP_MASKED:
+	  s1 = remap_gimple_seq (gimple_omp_body (stmt), id);
+	  copy = gimple_build_omp_masked
+		   (s1, gimple_omp_masked_clauses (stmt));
+	  break;
+
 	case GIMPLE_OMP_TASKGROUP:
 	  s1 = remap_gimple_seq (gimple_omp_body (stmt), id);
 	  copy = gimple_build_omp_taskgroup
@@ -4544,6 +4550,7 @@ estimate_num_insns (gimple *stmt, eni_we
     case GIMPLE_OMP_TASK:
     case GIMPLE_OMP_CRITICAL:
     case GIMPLE_OMP_MASTER:
+    case GIMPLE_OMP_MASKED:
     case GIMPLE_OMP_TASKGROUP:
     case GIMPLE_OMP_ORDERED:
     case GIMPLE_OMP_SCAN:
--- gcc/omp-low.c.jj	2021-08-11 23:43:45.901077251 +0200
+++ gcc/omp-low.c	2021-08-12 12:14:07.713732164 +0200
@@ -1466,6 +1466,7 @@ scan_sharing_clauses (tree clauses, omp_
 	case OMP_CLAUSE_NUM_WORKERS:
 	case OMP_CLAUSE_VECTOR_LENGTH:
 	case OMP_CLAUSE_DETACH:
+	case OMP_CLAUSE_FILTER:
 	  if (ctx->outer)
 	    scan_omp_op (&OMP_CLAUSE_OPERAND (c, 0), ctx->outer);
 	  break;
@@ -1868,6 +1869,7 @@ scan_sharing_clauses (tree clauses, omp_
 	case OMP_CLAUSE__SIMT_:
 	case OMP_CLAUSE_IF_PRESENT:
 	case OMP_CLAUSE_FINALIZE:
+	case OMP_CLAUSE_FILTER:
 	case OMP_CLAUSE__CONDTEMP_:
 	  break;
 
@@ -3426,6 +3428,7 @@ check_omp_nesting_restrictions (gimple *
 	  case GIMPLE_OMP_SINGLE:
 	  case GIMPLE_OMP_ORDERED:
 	  case GIMPLE_OMP_MASTER:
+	  case GIMPLE_OMP_MASKED:
 	  case GIMPLE_OMP_TASK:
 	  case GIMPLE_OMP_CRITICAL:
 	    if (is_gimple_call (stmt))
@@ -3436,14 +3439,15 @@ check_omp_nesting_restrictions (gimple *
 		error_at (gimple_location (stmt),
 			  "barrier region may not be closely nested inside "
 			  "of work-sharing, %<loop%>, %<critical%>, "
-			  "%<ordered%>, %<master%>, explicit %<task%> or "
-			  "%<taskloop%> region");
+			  "%<ordered%>, %<master%>, %<masked%>, explicit "
+			  "%<task%> or %<taskloop%> region");
 		return false;
 	      }
 	    error_at (gimple_location (stmt),
 		      "work-sharing region may not be closely nested inside "
 		      "of work-sharing, %<loop%>, %<critical%>, %<ordered%>, "
-		      "%<master%>, explicit %<task%> or %<taskloop%> region");
+		      "%<master%>, %<masked%>, explicit %<task%> or "
+		      "%<taskloop%> region");
 	    return false;
 	  case GIMPLE_OMP_PARALLEL:
 	  case GIMPLE_OMP_TEAMS:
@@ -3458,6 +3462,7 @@ check_omp_nesting_restrictions (gimple *
 	  }
       break;
     case GIMPLE_OMP_MASTER:
+    case GIMPLE_OMP_MASKED:
       for (; ctx != NULL; ctx = ctx->outer)
 	switch (gimple_code (ctx->stmt))
 	  {
@@ -3470,9 +3475,11 @@ check_omp_nesting_restrictions (gimple *
 	  case GIMPLE_OMP_SINGLE:
 	  case GIMPLE_OMP_TASK:
 	    error_at (gimple_location (stmt),
-		      "%<master%> region may not be closely nested inside "
+		      "%qs region may not be closely nested inside "
 		      "of work-sharing, %<loop%>, explicit %<task%> or "
-		      "%<taskloop%> region");
+		      "%<taskloop%> region",
+		      gimple_code (stmt) == GIMPLE_OMP_MASTER
+		      ? "master" : "masked");
 	    return false;
 	  case GIMPLE_OMP_PARALLEL:
 	  case GIMPLE_OMP_TEAMS:
@@ -4079,6 +4086,12 @@ scan_omp_1_stmt (gimple_stmt_iterator *g
       scan_omp (gimple_omp_body_ptr (stmt), ctx);
       break;
 
+    case GIMPLE_OMP_MASKED:
+      ctx = new_omp_context (stmt, ctx);
+      scan_sharing_clauses (gimple_omp_masked_clauses (stmt), ctx);
+      scan_omp (gimple_omp_body_ptr (stmt), ctx);
+      break;
+
     case GIMPLE_OMP_TASKGROUP:
       ctx = new_omp_context (stmt, ctx);
       scan_sharing_clauses (gimple_omp_taskgroup_clauses (stmt), ctx);
@@ -8675,7 +8688,7 @@ lower_omp_single (gimple_stmt_iterator *
 }
 
 
-/* Expand code for an OpenMP master directive.  */
+/* Expand code for an OpenMP master or masked directive.  */
 
 static void
 lower_omp_master (gimple_stmt_iterator *gsi_p, omp_context *ctx)
@@ -8685,9 +8698,20 @@ lower_omp_master (gimple_stmt_iterator *
   gbind *bind;
   location_t loc = gimple_location (stmt);
   gimple_seq tseq;
+  tree filter = integer_zero_node;
 
   push_gimplify_context ();
 
+  if (gimple_code (stmt) == GIMPLE_OMP_MASKED)
+    {
+      filter = omp_find_clause (gimple_omp_masked_clauses (stmt),
+				OMP_CLAUSE_FILTER);
+      if (filter)
+	filter = fold_convert (integer_type_node,
+			       OMP_CLAUSE_FILTER_EXPR (filter));
+      else
+	filter = integer_zero_node;
+    }
   block = make_node (BLOCK);
   bind = gimple_build_bind (NULL, NULL, block);
   gsi_replace (gsi_p, bind, true);
@@ -8695,7 +8719,7 @@ lower_omp_master (gimple_stmt_iterator *
 
   bfn_decl = builtin_decl_explicit (BUILT_IN_OMP_GET_THREAD_NUM);
   x = build_call_expr_loc (loc, bfn_decl, 0);
-  x = build2 (EQ_EXPR, boolean_type_node, x, integer_zero_node);
+  x = build2 (EQ_EXPR, boolean_type_node, x, filter);
   x = build3 (COND_EXPR, void_type_node, x, NULL, build_and_jump (&lab));
   tseq = NULL;
   gimplify_and_add (x, &tseq);
@@ -13869,6 +13893,7 @@ lower_omp_1 (gimple_stmt_iterator *gsi_p
       lower_omp_single (gsi_p, ctx);
       break;
     case GIMPLE_OMP_MASTER:
+    case GIMPLE_OMP_MASKED:
       ctx = maybe_lookup_ctx (stmt);
       gcc_assert (ctx);
       lower_omp_master (gsi_p, ctx);
@@ -14246,6 +14271,7 @@ diagnose_sb_1 (gimple_stmt_iterator *gsi
     case GIMPLE_OMP_SINGLE:
     case GIMPLE_OMP_SECTION:
     case GIMPLE_OMP_MASTER:
+    case GIMPLE_OMP_MASKED:
     case GIMPLE_OMP_ORDERED:
     case GIMPLE_OMP_SCAN:
     case GIMPLE_OMP_CRITICAL:
@@ -14307,6 +14333,7 @@ diagnose_sb_2 (gimple_stmt_iterator *gsi
     case GIMPLE_OMP_SINGLE:
     case GIMPLE_OMP_SECTION:
     case GIMPLE_OMP_MASTER:
+    case GIMPLE_OMP_MASKED:
     case GIMPLE_OMP_ORDERED:
     case GIMPLE_OMP_SCAN:
     case GIMPLE_OMP_CRITICAL:
--- gcc/omp-expand.c.jj	2021-08-11 23:43:45.899077278 +0200
+++ gcc/omp-expand.c	2021-08-12 12:14:07.711732192 +0200
@@ -8460,6 +8460,7 @@ expand_omp_synch (struct omp_region *reg
   si = gsi_last_nondebug_bb (entry_bb);
   gcc_assert (gimple_code (gsi_stmt (si)) == GIMPLE_OMP_SINGLE
 	      || gimple_code (gsi_stmt (si)) == GIMPLE_OMP_MASTER
+	      || gimple_code (gsi_stmt (si)) == GIMPLE_OMP_MASKED
 	      || gimple_code (gsi_stmt (si)) == GIMPLE_OMP_TASKGROUP
 	      || gimple_code (gsi_stmt (si)) == GIMPLE_OMP_ORDERED
 	      || gimple_code (gsi_stmt (si)) == GIMPLE_OMP_CRITICAL
@@ -9947,6 +9948,7 @@ expand_omp (struct omp_region *region)
 	  }
 	  /* FALLTHRU */
 	case GIMPLE_OMP_MASTER:
+	case GIMPLE_OMP_MASKED:
 	case GIMPLE_OMP_TASKGROUP:
 	case GIMPLE_OMP_CRITICAL:
 	case GIMPLE_OMP_TEAMS:
@@ -10266,6 +10268,7 @@ omp_make_gimple_edges (basic_block bb, s
     case GIMPLE_OMP_SINGLE:
     case GIMPLE_OMP_TEAMS:
     case GIMPLE_OMP_MASTER:
+    case GIMPLE_OMP_MASKED:
     case GIMPLE_OMP_TASKGROUP:
     case GIMPLE_OMP_CRITICAL:
     case GIMPLE_OMP_SECTION:
--- gcc/c-family/c-pragma.h.jj	2021-08-11 23:43:45.863077775 +0200
+++ gcc/c-family/c-pragma.h	2021-08-12 12:14:07.717732108 +0200
@@ -57,6 +57,7 @@ enum pragma_kind {
   PRAGMA_OMP_FLUSH,
   PRAGMA_OMP_FOR,
   PRAGMA_OMP_LOOP,
+  PRAGMA_OMP_MASKED,
   PRAGMA_OMP_MASTER,
   PRAGMA_OMP_ORDERED,
   PRAGMA_OMP_PARALLEL,
@@ -104,6 +105,7 @@ enum pragma_omp_clause {
   PRAGMA_OMP_CLAUSE_DEVICE,
   PRAGMA_OMP_CLAUSE_DEVICE_TYPE,
   PRAGMA_OMP_CLAUSE_DIST_SCHEDULE,
+  PRAGMA_OMP_CLAUSE_FILTER,
   PRAGMA_OMP_CLAUSE_FINAL,
   PRAGMA_OMP_CLAUSE_FIRSTPRIVATE,
   PRAGMA_OMP_CLAUSE_FOR,
--- gcc/c-family/c-pragma.c.jj	2021-08-11 23:43:45.863077775 +0200
+++ gcc/c-family/c-pragma.c	2021-08-12 12:14:07.717732108 +0200
@@ -1343,6 +1343,7 @@ static const struct omp_pragma_def omp_p
   { "distribute", PRAGMA_OMP_DISTRIBUTE },
   { "for", PRAGMA_OMP_FOR },
   { "loop", PRAGMA_OMP_LOOP },
+  { "masked", PRAGMA_OMP_MASKED },
   { "master", PRAGMA_OMP_MASTER },
   { "ordered", PRAGMA_OMP_ORDERED },
   { "parallel", PRAGMA_OMP_PARALLEL },
--- gcc/c-family/c-common.h.jj	2021-08-11 23:43:45.862077789 +0200
+++ gcc/c-family/c-common.h	2021-08-12 12:14:07.717732108 +0200
@@ -1201,7 +1201,8 @@ enum c_omp_clause_split
   C_OMP_CLAUSE_SPLIT_COUNT,
   C_OMP_CLAUSE_SPLIT_SECTIONS = C_OMP_CLAUSE_SPLIT_FOR,
   C_OMP_CLAUSE_SPLIT_TASKLOOP = C_OMP_CLAUSE_SPLIT_FOR,
-  C_OMP_CLAUSE_SPLIT_LOOP = C_OMP_CLAUSE_SPLIT_FOR
+  C_OMP_CLAUSE_SPLIT_LOOP = C_OMP_CLAUSE_SPLIT_FOR,
+  C_OMP_CLAUSE_SPLIT_MASKED = C_OMP_CLAUSE_SPLIT_DISTRIBUTE
 };
 
 enum c_omp_region_type
@@ -1215,6 +1216,7 @@ enum c_omp_region_type
 };
 
 extern tree c_finish_omp_master (location_t, tree);
+extern tree c_finish_omp_masked (location_t, tree, tree);
 extern tree c_finish_omp_taskgroup (location_t, tree, tree);
 extern tree c_finish_omp_critical (location_t, tree, tree, tree);
 extern tree c_finish_omp_ordered (location_t, tree, tree);
--- gcc/c-family/c-omp.c.jj	2021-08-11 23:43:45.863077775 +0200
+++ gcc/c-family/c-omp.c	2021-08-12 14:26:44.857387187 +0200
@@ -86,6 +86,20 @@ c_finish_omp_master (location_t loc, tre
   return t;
 }
 
+/* Complete a #pragma omp masked construct.  BODY is the structured-block
+   that follows the pragma.  LOC is the location of the #pragma.  */
+
+tree
+c_finish_omp_masked (location_t loc, tree body, tree clauses)
+{
+  tree stmt = make_node (OMP_MASKED);
+  TREE_TYPE (stmt) = void_type_node;
+  OMP_MASKED_BODY (stmt) = body;
+  OMP_MASKED_CLAUSES (stmt) = clauses;
+  SET_EXPR_LOCATION (stmt, loc);
+  return add_stmt (stmt);
+}
+
 /* Complete a #pragma omp taskgroup construct.  BODY is the structured-block
    that follows the pragma.  LOC is the location of the #pragma.  */
 
@@ -1542,11 +1556,16 @@ c_oacc_split_loop_clauses (tree clauses,
    #pragma omp distribute parallel for simd
    #pragma omp distribute simd
    #pragma omp for simd
+   #pragma omp masked taskloop
+   #pragma omp masked taskloop simd
    #pragma omp master taskloop
    #pragma omp master taskloop simd
    #pragma omp parallel for
    #pragma omp parallel for simd
    #pragma omp parallel loop
+   #pragma omp parallel masked
+   #pragma omp parallel masked taskloop
+   #pragma omp parallel masked taskloop simd
    #pragma omp parallel master
    #pragma omp parallel master taskloop
    #pragma omp parallel master taskloop simd
@@ -1651,6 +1670,9 @@ c_omp_split_clauses (location_t loc, enu
 	case OMP_CLAUSE_BIND:
 	  s = C_OMP_CLAUSE_SPLIT_LOOP;
 	  break;
+	case OMP_CLAUSE_FILTER:
+	  s = C_OMP_CLAUSE_SPLIT_MASKED;
+	  break;
 	/* Duplicate this to all of taskloop, distribute, for, simd and
 	   loop.  */
 	case OMP_CLAUSE_COLLAPSE:
@@ -1700,10 +1722,10 @@ c_omp_split_clauses (location_t loc, enu
 	  else
 	    s = C_OMP_CLAUSE_SPLIT_DISTRIBUTE;
 	  break;
-	/* Private clause is supported on all constructs but master,
-	   it is enough to put it on the innermost one other than master.  For
-	   #pragma omp {for,sections} put it on parallel though,
-	   as that's what we did for OpenMP 3.1.  */
+	/* Private clause is supported on all constructs but master/masked,
+	   it is enough to put it on the innermost one other than
+	   master/masked.  For #pragma omp {for,sections} put it on parallel
+	   though, as that's what we did for OpenMP 3.1.  */
 	case OMP_CLAUSE_PRIVATE:
 	  switch (code)
 	    {
@@ -1713,14 +1735,15 @@ c_omp_split_clauses (location_t loc, enu
 	    case OMP_DISTRIBUTE: s = C_OMP_CLAUSE_SPLIT_DISTRIBUTE; break;
 	    case OMP_TEAMS: s = C_OMP_CLAUSE_SPLIT_TEAMS; break;
 	    case OMP_MASTER: s = C_OMP_CLAUSE_SPLIT_PARALLEL; break;
+	    case OMP_MASKED: s = C_OMP_CLAUSE_SPLIT_PARALLEL; break;
 	    case OMP_TASKLOOP: s = C_OMP_CLAUSE_SPLIT_TASKLOOP; break;
 	    case OMP_LOOP: s = C_OMP_CLAUSE_SPLIT_LOOP; break;
 	    default: gcc_unreachable ();
 	    }
 	  break;
 	/* Firstprivate clause is supported on all constructs but
-	   simd, master and loop.  Put it on the outermost of those and
-	   duplicate on teams and parallel.  */
+	   simd, master, masked and loop.  Put it on the outermost of those
+	   and duplicate on teams and parallel.  */
 	case OMP_CLAUSE_FIRSTPRIVATE:
 	  if ((mask & (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_MAP))
 	      != 0)
@@ -1773,7 +1796,7 @@ c_omp_split_clauses (location_t loc, enu
 	      else if ((mask & (OMP_CLAUSE_MASK_1
 				<< PRAGMA_OMP_CLAUSE_NOGROUP)) != 0)
 		/* This must be
-		   #pragma omp parallel master taskloop{, simd}.  */
+		   #pragma omp parallel mas{ked,ter} taskloop{, simd}.  */
 		s = C_OMP_CLAUSE_SPLIT_TASKLOOP;
 	      else
 		/* This must be
@@ -1805,9 +1828,10 @@ c_omp_split_clauses (location_t loc, enu
 	  else if ((mask & (OMP_CLAUSE_MASK_1
 			    << PRAGMA_OMP_CLAUSE_NOGROUP)) != 0)
 	    {
-	      /* This must be #pragma omp {,{,parallel }master }taskloop simd
+	      /* This must be
+		 #pragma omp {,{,parallel }mas{ked,ter} }taskloop simd
 		 or
-		 #pragma omp {,parallel }master taskloop.  */
+		 #pragma omp {,parallel }mas{ked,ter} taskloop.  */
 	      gcc_assert (code == OMP_SIMD || code == OMP_TASKLOOP);
 	      s = C_OMP_CLAUSE_SPLIT_TASKLOOP;
 	    }
@@ -2044,7 +2068,8 @@ c_omp_split_clauses (location_t loc, enu
 	    }
 	  else if (code == OMP_SECTIONS
 		   || code == OMP_PARALLEL
-		   || code == OMP_MASTER)
+		   || code == OMP_MASTER
+		   || code == OMP_MASKED)
 	    s = C_OMP_CLAUSE_SPLIT_PARALLEL;
 	  else if (code == OMP_TASKLOOP)
 	    s = C_OMP_CLAUSE_SPLIT_TASKLOOP;
@@ -2455,7 +2480,8 @@ c_omp_split_clauses (location_t loc, enu
     gcc_assert (cclauses[C_OMP_CLAUSE_SPLIT_TARGET] == NULL_TREE);
   if ((mask & (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NUM_TEAMS)) == 0)
     gcc_assert (cclauses[C_OMP_CLAUSE_SPLIT_TEAMS] == NULL_TREE);
-  if ((mask & (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DIST_SCHEDULE)) == 0)
+  if ((mask & (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DIST_SCHEDULE)) == 0
+      && (mask & (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_FILTER)) == 0)
     gcc_assert (cclauses[C_OMP_CLAUSE_SPLIT_DISTRIBUTE] == NULL_TREE);
   if ((mask & (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NUM_THREADS)) == 0)
     gcc_assert (cclauses[C_OMP_CLAUSE_SPLIT_PARALLEL] == NULL_TREE);
@@ -2975,8 +3001,8 @@ static const struct c_omp_directive omp_
     C_OMP_DIR_STANDALONE, false },  */
   { "loop", nullptr, nullptr, PRAGMA_OMP_LOOP,
     C_OMP_DIR_CONSTRUCT, true },
-  /* { "masked", nullptr, nullptr, PRAGMA_OMP_MASKED,
-    C_OMP_DIR_CONSTRUCT, true },  */
+  { "masked", nullptr, nullptr, PRAGMA_OMP_MASKED,
+    C_OMP_DIR_CONSTRUCT, true },
   { "master", nullptr, nullptr, PRAGMA_OMP_MASTER,
     C_OMP_DIR_CONSTRUCT, true },
   /* { "metadirective", nullptr, nullptr, PRAGMA_OMP_METADIRECTIVE,
--- gcc/c/c-parser.c.jj	2021-08-11 23:43:45.867077720 +0200
+++ gcc/c/c-parser.c	2021-08-12 12:39:35.580322609 +0200
@@ -12696,7 +12696,9 @@ c_parser_omp_clause_name (c_parser *pars
 	    result = PRAGMA_OMP_CLAUSE_DIST_SCHEDULE;
 	  break;
 	case 'f':
-	  if (!strcmp ("final", p))
+	  if (!strcmp ("filter", p))
+	    result = PRAGMA_OMP_CLAUSE_FILTER;
+	  else if (!strcmp ("final", p))
 	    result = PRAGMA_OMP_CLAUSE_FINAL;
 	  else if (!strcmp ("finalize", p))
 	    result = PRAGMA_OACC_CLAUSE_FINALIZE;
@@ -13948,6 +13950,38 @@ c_parser_omp_clause_hint (c_parser *pars
   return list;
 }
 
+/* OpenMP 5.1:
+   filter ( integer-expression ) */
+
+static tree
+c_parser_omp_clause_filter (c_parser *parser, tree list)
+{
+  location_t hint_loc = c_parser_peek_token (parser)->location;
+  matching_parens parens;
+  if (parens.require_open (parser))
+    {
+      location_t expr_loc = c_parser_peek_token (parser)->location;
+      c_expr expr = c_parser_expr_no_commas (parser, NULL);
+      expr = convert_lvalue_to_rvalue (expr_loc, expr, false, true);
+      tree c, t = expr.value;
+      t = c_fully_fold (t, false, NULL);
+      if (!INTEGRAL_TYPE_P (TREE_TYPE (t)))
+	{
+	  c_parser_error (parser, "expected integer expression");
+	  return list;
+	}
+      parens.skip_until_found_close (parser);
+      check_no_duplicate_clause (list, OMP_CLAUSE_FILTER, "filter");
+
+      c = build_omp_clause (hint_loc, OMP_CLAUSE_FILTER);
+      OMP_CLAUSE_FILTER_EXPR (c) = t;
+      OMP_CLAUSE_CHAIN (c) = list;
+      list = c;
+    }
+
+  return list;
+}
+
 /* OpenMP 4.5:
    defaultmap ( tofrom : scalar )
 
@@ -16407,6 +16441,10 @@ c_parser_omp_all_clauses (c_parser *pars
 	  clauses = c_parser_omp_clause_detach (parser, clauses);
 	  c_name = "detach";
 	  break;
+	case PRAGMA_OMP_CLAUSE_FILTER:
+	  clauses = c_parser_omp_clause_filter (parser, clauses);
+	  c_name = "filter";
+	  break;
 	case PRAGMA_OMP_CLAUSE_FIRSTPRIVATE:
 	  clauses = c_parser_omp_clause_firstprivate (parser, clauses);
 	  c_name = "firstprivate";
@@ -18972,6 +19010,70 @@ c_parser_omp_master (location_t loc, c_p
 								  if_p));
 }
 
+/* OpenMP 5.1:
+   # pragma omp masked masked-clauses new-line
+     structured-block
+
+   LOC is the location of the #pragma token.
+*/
+
+#define OMP_MASKED_CLAUSE_MASK					\
+	(OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_FILTER)
+
+static tree
+c_parser_omp_masked (location_t loc, c_parser *parser,
+		     char *p_name, omp_clause_mask mask, tree *cclauses,
+		     bool *if_p)
+{
+  tree block, clauses, ret;
+
+  strcat (p_name, " masked");
+  mask |= OMP_MASKED_CLAUSE_MASK;
+
+  if (c_parser_next_token_is (parser, CPP_NAME))
+    {
+      const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value);
+
+      if (strcmp (p, "taskloop") == 0)
+	{
+	  tree cclauses_buf[C_OMP_CLAUSE_SPLIT_COUNT];
+	  if (cclauses == NULL)
+	    cclauses = cclauses_buf;
+
+	  c_parser_consume_token (parser);
+	  if (!flag_openmp)  /* flag_openmp_simd  */
+	    return c_parser_omp_taskloop (loc, parser, p_name, mask, cclauses,
+					  if_p);
+	  block = c_begin_compound_stmt (true);
+	  ret = c_parser_omp_taskloop (loc, parser, p_name, mask, cclauses,
+				       if_p);
+	  block = c_end_compound_stmt (loc, block, true);
+	  if (ret == NULL_TREE)
+	    return ret;
+	  ret = c_finish_omp_masked (loc, block,
+				     cclauses[C_OMP_CLAUSE_SPLIT_MASKED]);
+	  OMP_MASKED_COMBINED (ret) = 1;
+	  return ret;
+	}
+    }
+  if (!flag_openmp)  /* flag_openmp_simd  */
+    {
+      c_parser_skip_to_pragma_eol (parser, false);
+      return NULL_TREE;
+    }
+
+  clauses = c_parser_omp_all_clauses (parser, mask, p_name, cclauses == NULL);
+  if (cclauses)
+    {
+      omp_split_clauses (loc, OMP_MASKED, mask, clauses, cclauses);
+      clauses = cclauses[C_OMP_CLAUSE_SPLIT_MASKED];
+    }
+
+  return c_finish_omp_masked (loc, c_parser_omp_structured_block (parser,
+								  if_p),
+			      clauses);
+}
+
 /* OpenMP 2.5:
    # pragma omp ordered new-line
      structured-block
@@ -19234,7 +19336,36 @@ c_parser_omp_parallel (location_t loc, c
   else if (c_parser_next_token_is (parser, CPP_NAME))
     {
       const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value);
-      if (cclauses == NULL && strcmp (p, "master") == 0)
+      if (cclauses == NULL && strcmp (p, "masked") == 0)
+	{
+	  tree cclauses_buf[C_OMP_CLAUSE_SPLIT_COUNT];
+	  cclauses = cclauses_buf;
+
+	  c_parser_consume_token (parser);
+	  if (!flag_openmp)  /* flag_openmp_simd  */
+	    return c_parser_omp_masked (loc, parser, p_name, mask, cclauses,
+					if_p);
+	  block = c_begin_omp_parallel ();
+	  tree ret = c_parser_omp_masked (loc, parser, p_name, mask, cclauses,
+					  if_p);
+	  stmt = c_finish_omp_parallel (loc,
+					cclauses[C_OMP_CLAUSE_SPLIT_PARALLEL],
+					block);
+	  if (ret == NULL)
+	    return ret;
+	  /* masked does have just filter clause, but during gimplification
+	     isn't represented by a gimplification omp context, so for
+	     #pragma omp parallel masked don't set OMP_PARALLEL_COMBINED,
+	     so that
+	     #pragma omp parallel masked
+	     #pragma omp taskloop simd lastprivate (x)
+	     isn't confused with
+	     #pragma omp parallel masked taskloop simd lastprivate (x)  */
+	  if (OMP_MASKED_COMBINED (ret))
+	    OMP_PARALLEL_COMBINED (stmt) = 1;
+	  return stmt;
+	}
+      else if (cclauses == NULL && strcmp (p, "master") == 0)
 	{
 	  tree cclauses_buf[C_OMP_CLAUSE_SPLIT_COUNT];
 	  cclauses = cclauses_buf;
@@ -21812,6 +21943,10 @@ c_parser_omp_construct (c_parser *parser
       strcpy (p_name, "#pragma omp");
       stmt = c_parser_omp_loop (loc, parser, p_name, mask, NULL, if_p);
       break;
+    case PRAGMA_OMP_MASKED:
+      strcpy (p_name, "#pragma omp");
+      stmt = c_parser_omp_masked (loc, parser, p_name, mask, NULL, if_p);
+      break;
     case PRAGMA_OMP_MASTER:
       strcpy (p_name, "#pragma omp");
       stmt = c_parser_omp_master (loc, parser, p_name, mask, NULL, if_p);
--- gcc/c/c-typeck.c.jj	2021-08-11 23:43:45.870077679 +0200
+++ gcc/c/c-typeck.c	2021-08-12 12:14:07.714732150 +0200
@@ -15152,6 +15152,7 @@ c_finish_omp_clauses (tree clauses, enum
 	case OMP_CLAUSE_THREADS:
 	case OMP_CLAUSE_SIMD:
 	case OMP_CLAUSE_HINT:
+	case OMP_CLAUSE_FILTER:
 	case OMP_CLAUSE_DEFAULTMAP:
 	case OMP_CLAUSE_BIND:
 	case OMP_CLAUSE_NUM_GANGS:
--- gcc/cp/parser.c.jj	2021-08-12 09:34:16.823236372 +0200
+++ gcc/cp/parser.c	2021-08-12 12:51:20.201454141 +0200
@@ -36004,7 +36004,9 @@ cp_parser_omp_clause_name (cp_parser *pa
 	    result = PRAGMA_OMP_CLAUSE_DIST_SCHEDULE;
 	  break;
 	case 'f':
-	  if (!strcmp ("final", p))
+	  if (!strcmp ("filter", p))
+	    result = PRAGMA_OMP_CLAUSE_FILTER;
+	  else if (!strcmp ("final", p))
 	    result = PRAGMA_OMP_CLAUSE_FINAL;
 	  else if (!strcmp ("finalize", p))
 	    result = PRAGMA_OACC_CLAUSE_FINALIZE;
@@ -37340,6 +37342,34 @@ cp_parser_omp_clause_hint (cp_parser *pa
   return c;
 }
 
+/* OpenMP 5.1:
+   filter ( integer-expression ) */
+
+static tree
+cp_parser_omp_clause_filter (cp_parser *parser, tree list, location_t location)
+{
+  tree t, c;
+
+  matching_parens parens;
+  if (!parens.require_open (parser))
+    return list;
+
+  t = cp_parser_assignment_expression (parser);
+
+  if (t == error_mark_node
+      || !parens.require_close (parser))
+    cp_parser_skip_to_closing_parenthesis (parser, /*recovering=*/true,
+					   /*or_comma=*/false,
+					   /*consume_paren=*/true);
+  check_no_duplicate_clause (list, OMP_CLAUSE_FILTER, "filter", location);
+
+  c = build_omp_clause (location, OMP_CLAUSE_FILTER);
+  OMP_CLAUSE_FILTER_EXPR (c) = t;
+  OMP_CLAUSE_CHAIN (c) = list;
+
+  return c;
+}
+
 /* OpenMP 4.5:
    defaultmap ( tofrom : scalar )
 
@@ -39446,6 +39476,11 @@ cp_parser_omp_all_clauses (cp_parser *pa
 						  token->location, false);
 	  c_name = "default";
 	  break;
+	case PRAGMA_OMP_CLAUSE_FILTER:
+	  clauses = cp_parser_omp_clause_filter (parser, clauses,
+						 token->location);
+	  c_name = "filter";
+	  break;
 	case PRAGMA_OMP_CLAUSE_FINAL:
 	  clauses = cp_parser_omp_clause_final (parser, clauses, token->location);
 	  c_name = "final";
@@ -41982,6 +42017,73 @@ cp_parser_omp_master (cp_parser *parser,
 			      cp_parser_omp_structured_block (parser, if_p));
 }
 
+/* OpenMP 5.1:
+   # pragma omp masked masked-clauses new-line
+     structured-block  */
+
+#define OMP_MASKED_CLAUSE_MASK					\
+	(OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_FILTER)
+
+static tree
+cp_parser_omp_masked (cp_parser *parser, cp_token *pragma_tok,
+		      char *p_name, omp_clause_mask mask, tree *cclauses,
+		      bool *if_p)
+{
+  tree clauses, sb, ret;
+  unsigned int save;
+  location_t loc = cp_lexer_peek_token (parser->lexer)->location;
+
+  strcat (p_name, " masked");
+  mask |= OMP_MASKED_CLAUSE_MASK;
+
+  if (cp_lexer_next_token_is (parser->lexer, CPP_NAME))
+    {
+      tree id = cp_lexer_peek_token (parser->lexer)->u.value;
+      const char *p = IDENTIFIER_POINTER (id);
+
+      if (strcmp (p, "taskloop") == 0)
+	{
+	  tree cclauses_buf[C_OMP_CLAUSE_SPLIT_COUNT];
+	  if (cclauses == NULL)
+	    cclauses = cclauses_buf;
+
+	  cp_lexer_consume_token (parser->lexer);
+	  if (!flag_openmp)  /* flag_openmp_simd  */
+	    return cp_parser_omp_taskloop (parser, pragma_tok, p_name, mask,
+					   cclauses, if_p);
+	  sb = begin_omp_structured_block ();
+	  save = cp_parser_begin_omp_structured_block (parser);
+	  ret = cp_parser_omp_taskloop (parser, pragma_tok, p_name, mask,
+					cclauses, if_p);
+	  cp_parser_end_omp_structured_block (parser, save);
+	  tree body = finish_omp_structured_block (sb);
+	  if (ret == NULL)
+	    return ret;
+	  ret = c_finish_omp_masked (loc, body,
+				     cclauses[C_OMP_CLAUSE_SPLIT_MASKED]);
+	  OMP_MASKED_COMBINED (ret) = 1;
+	  return ret;
+	}
+    }
+  if (!flag_openmp)  /* flag_openmp_simd  */
+    {
+      cp_parser_skip_to_pragma_eol (parser, pragma_tok);
+      return NULL_TREE;
+    }
+
+  clauses = cp_parser_omp_all_clauses (parser, mask, p_name, pragma_tok,
+				       cclauses == NULL);
+  if (cclauses)
+    {
+      cp_omp_split_clauses (loc, OMP_MASTER, mask, clauses, cclauses);
+      clauses = cclauses[C_OMP_CLAUSE_SPLIT_MASKED];
+    }
+
+  return c_finish_omp_masked (loc,
+			      cp_parser_omp_structured_block (parser, if_p),
+			      clauses);
+}
+
 /* OpenMP 2.5:
    # pragma omp ordered new-line
      structured-block
@@ -42235,7 +42337,37 @@ cp_parser_omp_parallel (cp_parser *parse
     {
       tree id = cp_lexer_peek_token (parser->lexer)->u.value;
       const char *p = IDENTIFIER_POINTER (id);
-      if (cclauses == NULL && strcmp (p, "master") == 0)
+      if (cclauses == NULL && strcmp (p, "masked") == 0)
+	{
+	  tree cclauses_buf[C_OMP_CLAUSE_SPLIT_COUNT];
+	  cclauses = cclauses_buf;
+
+	  cp_lexer_consume_token (parser->lexer);
+	  if (!flag_openmp)  /* flag_openmp_simd  */
+	    return cp_parser_omp_masked (parser, pragma_tok, p_name, mask,
+					 cclauses, if_p);
+	  block = begin_omp_parallel ();
+	  save = cp_parser_begin_omp_structured_block (parser);
+	  tree ret = cp_parser_omp_masked (parser, pragma_tok, p_name, mask,
+					   cclauses, if_p);
+	  cp_parser_end_omp_structured_block (parser, save);
+	  stmt = finish_omp_parallel (cclauses[C_OMP_CLAUSE_SPLIT_PARALLEL],
+				      block);
+	  if (ret == NULL_TREE)
+	    return ret;
+	  /* masked does have just filter clause, but during gimplification
+	     isn't represented by a gimplification omp context, so for
+	     #pragma omp parallel masked don't set OMP_PARALLEL_COMBINED,
+	     so that
+	     #pragma omp parallel masked
+	     #pragma omp taskloop simd lastprivate (x)
+	     isn't confused with
+	     #pragma omp parallel masked taskloop simd lastprivate (x)  */
+	  if (OMP_MASKED_COMBINED (ret))
+	    OMP_PARALLEL_COMBINED (stmt) = 1;
+	  return stmt;
+	}
+      else if (cclauses == NULL && strcmp (p, "master") == 0)
 	{
 	  tree cclauses_buf[C_OMP_CLAUSE_SPLIT_COUNT];
 	  cclauses = cclauses_buf;
@@ -45821,6 +45953,11 @@ cp_parser_omp_construct (cp_parser *pars
       stmt = cp_parser_omp_loop (parser, pragma_tok, p_name, mask, NULL,
 				 if_p);
       break;
+    case PRAGMA_OMP_MASKED:
+      strcpy (p_name, "#pragma omp");
+      stmt = cp_parser_omp_masked (parser, pragma_tok, p_name, mask, NULL,
+				   if_p);
+      break;
     case PRAGMA_OMP_MASTER:
       strcpy (p_name, "#pragma omp");
       stmt = cp_parser_omp_master (parser, pragma_tok, p_name, mask, NULL,
@@ -46461,6 +46598,7 @@ cp_parser_pragma (cp_parser *parser, enu
     case PRAGMA_OMP_DISTRIBUTE:
     case PRAGMA_OMP_FOR:
     case PRAGMA_OMP_LOOP:
+    case PRAGMA_OMP_MASKED:
     case PRAGMA_OMP_MASTER:
     case PRAGMA_OMP_PARALLEL:
     case PRAGMA_OMP_SECTIONS:
--- gcc/cp/semantics.c.jj	2021-08-12 09:34:16.824236358 +0200
+++ gcc/cp/semantics.c	2021-08-12 12:42:13.512110486 +0200
@@ -8204,6 +8204,29 @@ finish_omp_clauses (tree clauses, enum c
 	    }
 	  break;
 
+	case OMP_CLAUSE_FILTER:
+	  t = OMP_CLAUSE_FILTER_EXPR (c);
+	  if (t == error_mark_node)
+	    remove = true;
+	  else if (!type_dependent_expression_p (t)
+		   && !INTEGRAL_TYPE_P (TREE_TYPE (t)))
+	    {
+	      error_at (OMP_CLAUSE_LOCATION (c),
+			"%<filter%> expression must be integral");
+	      remove = true;
+	    }
+	  else
+	    {
+	      t = mark_rvalue_use (t);
+	      if (!processing_template_decl)
+		{
+		  t = maybe_constant_value (t);
+		  t = fold_build_cleanup_point_expr (TREE_TYPE (t), t);
+		}
+	      OMP_CLAUSE_FILTER_EXPR (c) = t;
+	    }
+	  break;
+
 	case OMP_CLAUSE_IS_DEVICE_PTR:
 	case OMP_CLAUSE_USE_DEVICE_PTR:
 	  field_ok = (ort & C_ORT_OMP_DECLARE_SIMD) == C_ORT_OMP;
--- gcc/cp/pt.c.jj	2021-08-11 23:43:45.890077403 +0200
+++ gcc/cp/pt.c	2021-08-12 12:40:45.021349795 +0200
@@ -17394,6 +17394,7 @@ tsubst_omp_clauses (tree clauses, enum c
 	case OMP_CLAUSE_PRIORITY:
 	case OMP_CLAUSE_ORDERED:
 	case OMP_CLAUSE_HINT:
+	case OMP_CLAUSE_FILTER:
 	case OMP_CLAUSE_NUM_GANGS:
 	case OMP_CLAUSE_NUM_WORKERS:
 	case OMP_CLAUSE_VECTOR_LENGTH:
@@ -18786,6 +18787,7 @@ tsubst_expr (tree t, tree args, tsubst_f
       break;
 
     case OMP_SECTIONS:
+    case OMP_MASKED:
       omp_parallel_combined_clauses = NULL;
       /* FALLTHRU */
     case OMP_SINGLE:
--- gcc/testsuite/c-c++-common/gomp/clauses-1.c.jj	2021-06-24 11:35:08.618948506 +0200
+++ gcc/testsuite/c-c++-common/gomp/clauses-1.c	2021-08-12 13:44:18.121945498 +0200
@@ -273,6 +273,10 @@ bar (int d, int m, int i1, int i2, int i
     private (p) firstprivate (f) if (parallel: i2) default(shared) shared(s) reduction(+:r) \
     num_threads (nth) proc_bind(spread) copyin(t) allocate (f)
     ;
+  #pragma omp parallel masked \
+    private (p) firstprivate (f) if (parallel: i2) default(shared) shared(s) reduction(+:r) \
+    num_threads (nth) proc_bind(spread) copyin(t) allocate (f) filter (d)
+    ;
   #pragma omp taskgroup task_reduction (+:r2) allocate (r2)
   #pragma omp master taskloop \
     private (p) firstprivate (f) lastprivate (l) shared (s) default(shared) grainsize (g) collapse(1) untied if(taskloop: i1) final(fi) mergeable priority (pp) \
@@ -280,23 +284,47 @@ bar (int d, int m, int i1, int i2, int i
   for (int i = 0; i < 64; i++)
     ll++;
   #pragma omp taskgroup task_reduction (+:r2) allocate (r2)
+  #pragma omp masked taskloop \
+    private (p) firstprivate (f) lastprivate (l) shared (s) default(shared) grainsize (g) collapse(1) untied if(taskloop: i1) final(fi) mergeable priority (pp) \
+    reduction(default, +:r) in_reduction(+:r2) allocate (f) filter (d)
+  for (int i = 0; i < 64; i++)
+    ll++;
+  #pragma omp taskgroup task_reduction (+:r2) allocate (r2)
   #pragma omp master taskloop simd \
     private (p) firstprivate (f) lastprivate (l) shared (s) default(shared) grainsize (g) collapse(1) untied if(taskloop: i1) if(simd: i2) final(fi) mergeable priority (pp) \
     safelen(8) simdlen(4) linear(ll: 1) aligned(q: 32) reduction(default, +:r) in_reduction(+:r2) nontemporal(ntm) \
     order(concurrent) allocate (f)
   for (int i = 0; i < 64; i++)
     ll++;
+  #pragma omp taskgroup task_reduction (+:r2) allocate (r2)
+  #pragma omp masked taskloop simd \
+    private (p) firstprivate (f) lastprivate (l) shared (s) default(shared) grainsize (g) collapse(1) untied if(taskloop: i1) if(simd: i2) final(fi) mergeable priority (pp) \
+    safelen(8) simdlen(4) linear(ll: 1) aligned(q: 32) reduction(default, +:r) in_reduction(+:r2) nontemporal(ntm) \
+    order(concurrent) allocate (f) filter (d)
+  for (int i = 0; i < 64; i++)
+    ll++;
   #pragma omp parallel master taskloop \
     private (p) firstprivate (f) lastprivate (l) shared (s) default(shared) grainsize (g) collapse(1) untied if(taskloop: i1) final(fi) mergeable priority (pp) \
     reduction(default, +:r) if (parallel: i2) num_threads (nth) proc_bind(spread) copyin(t) allocate (f)
   for (int i = 0; i < 64; i++)
     ll++;
+  #pragma omp parallel masked taskloop \
+    private (p) firstprivate (f) lastprivate (l) shared (s) default(shared) grainsize (g) collapse(1) untied if(taskloop: i1) final(fi) mergeable priority (pp) \
+    reduction(default, +:r) if (parallel: i2) num_threads (nth) proc_bind(spread) copyin(t) allocate (f) filter (d)
+  for (int i = 0; i < 64; i++)
+    ll++;
   #pragma omp parallel master taskloop simd \
     private (p) firstprivate (f) lastprivate (l) shared (s) default(shared) grainsize (g) collapse(1) untied if(taskloop: i1) if(simd: i2) final(fi) mergeable priority (pp) \
     safelen(8) simdlen(4) linear(ll: 1) aligned(q: 32) reduction(default, +:r) nontemporal(ntm) if (parallel: i2) num_threads (nth) proc_bind(spread) copyin(t) \
     order(concurrent) allocate (f)
   for (int i = 0; i < 64; i++)
     ll++;
+  #pragma omp parallel masked taskloop simd \
+    private (p) firstprivate (f) lastprivate (l) shared (s) default(shared) grainsize (g) collapse(1) untied if(taskloop: i1) if(simd: i2) final(fi) mergeable priority (pp) \
+    safelen(8) simdlen(4) linear(ll: 1) aligned(q: 32) reduction(default, +:r) nontemporal(ntm) if (parallel: i2) num_threads (nth) proc_bind(spread) copyin(t) \
+    order(concurrent) allocate (f) filter (d)
+  for (int i = 0; i < 64; i++)
+    ll++;
   #pragma omp taskgroup task_reduction (+:r2) allocate (r2)
   #pragma omp master taskloop \
     private (p) firstprivate (f) lastprivate (l) shared (s) default(shared) num_tasks (nta) collapse(1) untied if(i1) final(fi) mergeable priority (pp) \
@@ -304,23 +332,47 @@ bar (int d, int m, int i1, int i2, int i
   for (int i = 0; i < 64; i++)
     ll++;
   #pragma omp taskgroup task_reduction (+:r2) allocate (r2)
+  #pragma omp mastked taskloop \
+    private (p) firstprivate (f) lastprivate (l) shared (s) default(shared) num_tasks (nta) collapse(1) untied if(i1) final(fi) mergeable priority (pp) \
+    reduction(default, +:r) in_reduction(+:r2) filter (d)
+  for (int i = 0; i < 64; i++)
+    ll++;
+  #pragma omp taskgroup task_reduction (+:r2) allocate (r2)
   #pragma omp master taskloop simd \
     private (p) firstprivate (f) lastprivate (l) shared (s) default(shared) num_tasks (nta) collapse(1) untied if(i1) final(fi) mergeable priority (pp) \
     safelen(8) simdlen(4) linear(ll: 1) aligned(q: 32) reduction(default, +:r) in_reduction(+:r2) nontemporal(ntm) \
     order(concurrent) allocate (f)
   for (int i = 0; i < 64; i++)
     ll++;
+  #pragma omp taskgroup task_reduction (+:r2) allocate (r2)
+  #pragma omp masked taskloop simd \
+    private (p) firstprivate (f) lastprivate (l) shared (s) default(shared) num_tasks (nta) collapse(1) untied if(i1) final(fi) mergeable priority (pp) \
+    safelen(8) simdlen(4) linear(ll: 1) aligned(q: 32) reduction(default, +:r) in_reduction(+:r2) nontemporal(ntm) \
+    order(concurrent) allocate (f) filter (d)
+  for (int i = 0; i < 64; i++)
+    ll++;
   #pragma omp parallel master taskloop \
     private (p) firstprivate (f) lastprivate (l) shared (s) default(shared) num_tasks (nta) collapse(1) untied if(i1) final(fi) mergeable priority (pp) \
     reduction(default, +:r) num_threads (nth) proc_bind(spread) copyin(t) allocate (f)
   for (int i = 0; i < 64; i++)
     ll++;
+  #pragma omp parallel masked taskloop \
+    private (p) firstprivate (f) lastprivate (l) shared (s) default(shared) num_tasks (nta) collapse(1) untied if(i1) final(fi) mergeable priority (pp) \
+    reduction(default, +:r) num_threads (nth) proc_bind(spread) copyin(t) allocate (f) filter (d)
+  for (int i = 0; i < 64; i++)
+    ll++;
   #pragma omp parallel master taskloop simd \
     private (p) firstprivate (f) lastprivate (l) shared (s) default(shared) num_tasks (nta) collapse(1) untied if(i1) final(fi) mergeable priority (pp) \
     safelen(8) simdlen(4) linear(ll: 1) aligned(q: 32) reduction(default, +:r) nontemporal(ntm) num_threads (nth) proc_bind(spread) copyin(t) \
     order(concurrent) allocate (f)
   for (int i = 0; i < 64; i++)
     ll++;
+  #pragma omp parallel masked taskloop simd \
+    private (p) firstprivate (f) lastprivate (l) shared (s) default(shared) num_tasks (nta) collapse(1) untied if(i1) final(fi) mergeable priority (pp) \
+    safelen(8) simdlen(4) linear(ll: 1) aligned(q: 32) reduction(default, +:r) nontemporal(ntm) num_threads (nth) proc_bind(spread) copyin(t) \
+    order(concurrent) allocate (f) filter (d)
+  for (int i = 0; i < 64; i++)
+    ll++;
   #pragma omp loop bind(thread) order(concurrent) \
     private (p) lastprivate (l) collapse(1) reduction(+:r)
   for (l = 0; l < 64; ++l)
--- gcc/testsuite/c-c++-common/gomp/clauses-5.c.jj	2020-01-12 11:54:37.012404372 +0100
+++ gcc/testsuite/c-c++-common/gomp/clauses-5.c	2021-08-12 13:45:10.401213113 +0200
@@ -49,4 +49,6 @@ foo (int *p)
   ;
   #pragma omp critical (baz) hint (2, 3)	/* { dg-error "expected" } */
   ;
+  #pragma omp masked filter (3, 4)		/* { dg-error "expected" } */
+  ;
 }
--- gcc/testsuite/c-c++-common/gomp/clause-dups-1.c.jj	2020-01-12 11:54:37.011404387 +0100
+++ gcc/testsuite/c-c++-common/gomp/clause-dups-1.c	2021-08-12 12:53:37.764527585 +0200
@@ -203,7 +203,8 @@ f1 (int *p)
   i = p[0]++;
   #pragma omp atomic capture hint(0) hint (0)			/* { dg-error "too many 'hint' clauses" } */
   i = p[0]++;
-  
+  #pragma omp masked filter (0) filter (0)			/* { dg-error "too many 'filter' clauses" } */
+  f0 ();
 }
 
 #pragma omp declare simd simdlen (4) simdlen (4)		/* { dg-error "too many 'simdlen' clauses" } */
--- gcc/testsuite/c-c++-common/gomp/masked-1.c.jj	2021-08-12 13:52:57.722669690 +0200
+++ gcc/testsuite/c-c++-common/gomp/masked-1.c	2021-08-12 13:55:14.323757971 +0200
@@ -0,0 +1,23 @@
+void bar (void);
+
+void
+foo (int x, int *a)
+{
+  #pragma omp masked
+  bar ();
+  #pragma omp masked filter (0)
+  bar ();
+  #pragma omp masked filter (7)
+  bar ();
+  #pragma omp masked filter (x)
+  bar ();
+  #pragma omp masked taskloop simd filter (x) grainsize (12) simdlen (4)
+  for (int i = 0; i < 128; i++)
+    a[i] = i;
+  #pragma omp parallel masked filter (x) firstprivate (x)
+  bar ();
+  #pragma omp masked
+  #pragma omp masked filter (0)
+  #pragma omp masked filter (x)
+  ;
+}
--- gcc/testsuite/c-c++-common/gomp/masked-2.c.jj	2021-08-12 13:53:50.468931510 +0200
+++ gcc/testsuite/c-c++-common/gomp/masked-2.c	2021-08-12 14:48:58.579161379 +0200
@@ -0,0 +1,11 @@
+void bar (void);
+struct S { int s; };
+
+void
+foo (float f, struct S s)
+{
+  #pragma omp masked filter (0.0)	/* { dg-error "integral|integer" } */
+  bar ();
+  #pragma omp masked filter (s)		/* { dg-error "integral|integer" } */
+  bar ();
+}
--- gcc/testsuite/c-c++-common/gomp/masked-combined-1.c.jj	2021-08-12 13:46:29.859099984 +0200
+++ gcc/testsuite/c-c++-common/gomp/masked-combined-1.c	2021-08-12 13:48:45.071205784 +0200
@@ -0,0 +1,37 @@
+void bar (int *);
+
+void
+foo (int *a, int f)
+{
+  int i, j, k, u = 0, v = 0, w = 0, x = 0, y = 0, z = 0;
+  #pragma omp parallel masked default(none) private (k) filter (f) firstprivate (f)
+  bar (&k);
+  #pragma omp parallel masked default(none) private (k)
+  bar (&k);
+  #pragma omp parallel default(none) firstprivate(a, f) shared(x, y, z)
+  {
+    #pragma omp masked taskloop reduction (+:x) default(none) firstprivate(a) filter (f)
+    for (i = 0; i < 64; i++)
+      x += a[i];
+    #pragma omp masked taskloop simd reduction (+:y) default(none) firstprivate(a) private (i) filter (f)
+    for (i = 0; i < 64; i++)
+      y += a[i];
+    #pragma omp masked taskloop simd reduction (+:y) default(none) firstprivate(a) private (i)
+    for (i = 0; i < 64; i++)
+      y += a[i];
+    #pragma omp masked taskloop simd collapse(2) reduction (+:z) default(none) firstprivate(a) private (i, j) filter (f)
+    for (j = 0; j < 1; j++)
+      for (i = 0; i < 64; ++i)
+	z += a[i];
+  }
+  #pragma omp parallel masked taskloop reduction (+:u) default(none) firstprivate(a, f) filter (f)
+  for (i = 0; i < 64; i++)
+    u += a[i];
+  #pragma omp parallel masked taskloop simd reduction (+:v) default(none) firstprivate(a, f) filter (f)
+  for (i = 0; i < 64; i++)
+    v += a[i];
+  #pragma omp parallel masked taskloop simd collapse(2) reduction (+:w) default(none) firstprivate(a, f) filter (f)
+  for (j = 0; j < 1; j++)
+    for (i = 0; i < 64; ++i)
+      w += a[i];
+}
--- gcc/testsuite/c-c++-common/gomp/masked-combined-2.c.jj	2021-08-12 13:49:02.089967369 +0200
+++ gcc/testsuite/c-c++-common/gomp/masked-combined-2.c	2021-08-12 13:49:29.769579981 +0200
@@ -0,0 +1,13 @@
+void
+foo (int *a)
+{
+  int i, r = 0, s = 0;
+  #pragma omp taskgroup task_reduction(+:r)
+  #pragma omp parallel masked taskloop in_reduction(+:r)	/* { dg-error "'in_reduction' is not valid for '#pragma omp parallel masked taskloop'" } */
+  for (i = 0; i < 64; i++)
+    r += a[i];
+  #pragma omp taskgroup task_reduction(+:s)
+  #pragma omp parallel masked taskloop simd in_reduction(+:s)	/* { dg-error "'in_reduction' is not valid for '#pragma omp parallel masked taskloop simd'" } */
+  for (i = 0; i < 64; i++)
+    s += a[i];
+}
--- gcc/testsuite/c-c++-common/goacc/uninit-if-clause.c.jj	2020-07-28 15:39:09.990756475 +0200
+++ gcc/testsuite/c-c++-common/goacc/uninit-if-clause.c	2021-08-12 15:01:31.299065897 +0200
@@ -1,6 +1,5 @@
 /* { dg-do compile } */
 /* { dg-additional-options "-Wuninitialized" } */
-/* { dg-excess-errors "PR70392" { xfail c++ } } */
 
 #include <stdbool.h>
 
@@ -14,25 +13,25 @@ main (void)
   #pragma acc parallel if(l) /* { dg-warning "is used uninitialized" } */
   ;
 
-  #pragma acc parallel if(b) /* { dg-warning "is used uninitialized" "" { xfail c++ } } */
+  #pragma acc parallel if(b) /* { dg-warning "is used uninitialized" } */
   ;
 
   #pragma acc kernels if(l2) /* { dg-warning "is used uninitialized" } */
   ;
 
-  #pragma acc kernels if(b2) /* { dg-warning "is used uninitialized" "" { xfail c++ } } */
+  #pragma acc kernels if(b2) /* { dg-warning "is used uninitialized" } */
   ;
 
   #pragma acc data if(l3) /* { dg-warning "is used uninitialized" } */
   ;
 
-  #pragma acc data if(b3) /* { dg-warning "is used uninitialized" "" { xfail c++ } } */
+  #pragma acc data if(b3) /* { dg-warning "is used uninitialized" } */
   ;
 
   #pragma acc update if(l4) self(i) /* { dg-warning "is used uninitialized" } */
   ;
 
-  #pragma acc update if(b4) self(i2) /* { dg-warning "is used uninitialized" "" { xfail c++ } } */
+  #pragma acc update if(b4) self(i2) /* { dg-warning "is used uninitialized" } */
   ;
 
 }
--- gcc/testsuite/g++.dg/gomp/block-11.C.jj	2021-08-12 14:59:18.646898415 +0200
+++ gcc/testsuite/g++.dg/gomp/block-11.C	2021-08-12 14:59:30.640732726 +0200
@@ -0,0 +1,18 @@
+// { dg-do compile }
+
+void foo()
+{
+  #pragma omp masked
+    {
+      goto bad1;	// { dg-message "from here" }
+    }
+
+  #pragma omp masked filter(1)
+    {
+    bad1:		// { dg-error "jump" }
+			// { dg-message "exits OpenMP" "" { target *-*-* } .-1 }
+      return;		// { dg-error "invalid exit" }
+    }
+}
+
+// { dg-message "error: invalid branch to/from OpenMP structured block" "" { target *-*-* } 7 }
--- gcc/testsuite/g++.dg/gomp/tpl-masked-1.C.jj	2021-08-12 13:56:21.174822400 +0200
+++ gcc/testsuite/g++.dg/gomp/tpl-masked-1.C	2021-08-12 13:57:40.082718092 +0200
@@ -0,0 +1,21 @@
+// { dg-do compile }
+// { dg-options "-fopenmp -fdump-tree-gimple" }
+
+int i;
+
+template <typename T> void f1 (bool p, T t)
+{
+  if (p)
+    {
+      #pragma omp masked filter (t)
+	i++;
+    }
+}
+
+void f2 ()
+{
+  f1<int> (true, 0);
+  f1<long> (true, 0L);
+}
+
+// { dg-final { scan-tree-dump-times "#pragma omp masked" 2 "gimple" } }
--- gcc/testsuite/g++.dg/gomp/attrs-1.C.jj	2021-08-10 11:22:14.441607489 +0200
+++ gcc/testsuite/g++.dg/gomp/attrs-1.C	2021-08-12 14:34:05.016263669 +0200
@@ -348,6 +348,10 @@ bar (int d, int m, int i1, int i2, int i
     private (p) firstprivate (f) if (parallel: i2) default(shared) shared(s) reduction(+:r)
     num_threads (nth) proc_bind(spread) copyin(t) allocate (f))]]
     ;
+  [[omp::directive (parallel masked
+    private (p) firstprivate (f) if (parallel: i2) default(shared) shared(s) reduction(+:r)
+    num_threads (nth) proc_bind(spread) copyin(t) allocate (f) filter (d))]]
+    ;
   [[omp::directive (parallel
     private (p) firstprivate (f) if (parallel: i2) default(shared) shared(s) reduction(+:r)
     num_threads (nth) proc_bind(spread) copyin(t) allocate (f))]]
@@ -358,7 +362,15 @@ bar (int d, int m, int i1, int i2, int i
     reduction(default, +:r) in_reduction(+:r2) allocate (f)))]]
   for (int i = 0; i < 64; i++)
     ll++;
+  [[omp::sequence (directive (taskgroup task_reduction (+:r2) allocate (r2)),
+    omp::directive (masked taskloop
+    private (p) firstprivate (f) lastprivate (l) shared (s) default(shared) grainsize (g) collapse(1) untied if(taskloop: i1) final(fi) mergeable priority (pp)
+    reduction(default, +:r) in_reduction(+:r2) allocate (f) filter (d)))]]
+  for (int i = 0; i < 64; i++)
+    ll++;
   [[omp::directive (master)]];
+  [[omp::directive (masked)]];
+  [[omp::directive (masked filter (d))]];
   [[omp::sequence (omp::directive (taskgroup task_reduction (+:r2) allocate (r2)),
     directive (master taskloop simd
     private (p) firstprivate (f) lastprivate (l) shared (s) default(shared) grainsize (g) collapse(1) untied if(taskloop: i1) if(simd: i2) final(fi) mergeable priority (pp)
@@ -366,23 +378,47 @@ bar (int d, int m, int i1, int i2, int i
     order(concurrent) allocate (f)))]]
   for (int i = 0; i < 64; i++)
     ll++;
+  [[omp::sequence (omp::directive (taskgroup task_reduction (+:r2) allocate (r2)),
+    directive (masked taskloop simd
+    private (p) firstprivate (f) lastprivate (l) shared (s) default(shared) grainsize (g) collapse(1) untied if(taskloop: i1) if(simd: i2) final(fi) mergeable priority (pp)
+    safelen(8) simdlen(4) linear(ll: 1) aligned(q: 32) reduction(default, +:r) in_reduction(+:r2) nontemporal(ntm)
+    order(concurrent) allocate (f) filter (d)))]]
+  for (int i = 0; i < 64; i++)
+    ll++;
   [[omp::directive (parallel master taskloop
     private (p) firstprivate (f) lastprivate (l) shared (s) default(shared) grainsize (g) collapse(1) untied if(taskloop: i1) final(fi) mergeable priority (pp)
     reduction(default, +:r) if (parallel: i2) num_threads (nth) proc_bind(spread) copyin(t) allocate (f))]]
   for (int i = 0; i < 64; i++)
     ll++;
+  [[omp::directive (parallel masked taskloop
+    private (p) firstprivate (f) lastprivate (l) shared (s) default(shared) grainsize (g) collapse(1) untied if(taskloop: i1) final(fi) mergeable priority (pp)
+    reduction(default, +:r) if (parallel: i2) num_threads (nth) proc_bind(spread) copyin(t) allocate (f) filter (d))]]
+  for (int i = 0; i < 64; i++)
+    ll++;
   [[omp::directive (parallel master taskloop simd
     private (p) firstprivate (f) lastprivate (l) shared (s) default(shared) grainsize (g) collapse(1) untied if(taskloop: i1) if(simd: i2) final(fi) mergeable priority (pp)
     safelen(8) simdlen(4) linear(ll: 1) aligned(q: 32) reduction(default, +:r) nontemporal(ntm) if (parallel: i2) num_threads (nth) proc_bind(spread) copyin(t)
     order(concurrent) allocate (f))]]
   for (int i = 0; i < 64; i++)
     ll++;
+  [[omp::directive (parallel masked taskloop simd
+    private (p) firstprivate (f) lastprivate (l) shared (s) default(shared) grainsize (g) collapse(1) untied if(taskloop: i1) if(simd: i2) final(fi) mergeable priority (pp)
+    safelen(8) simdlen(4) linear(ll: 1) aligned(q: 32) reduction(default, +:r) nontemporal(ntm) if (parallel: i2) num_threads (nth) proc_bind(spread) copyin(t)
+    order(concurrent) allocate (f) filter (d))]]
+  for (int i = 0; i < 64; i++)
+    ll++;
   [[omp::sequence (directive (taskgroup task_reduction (+:r2) allocate (r2)),
     directive (master taskloop
     private (p) firstprivate (f) lastprivate (l) shared (s) default(shared) num_tasks (nta) collapse(1) untied if(i1) final(fi) mergeable priority (pp)
     reduction(default, +:r) in_reduction(+:r2)))]]
   for (int i = 0; i < 64; i++)
     ll++;
+  [[omp::sequence (directive (taskgroup task_reduction (+:r2) allocate (r2)),
+    directive (masked taskloop
+    private (p) firstprivate (f) lastprivate (l) shared (s) default(shared) num_tasks (nta) collapse(1) untied if(i1) final(fi) mergeable priority (pp)
+    reduction(default, +:r) in_reduction(+:r2) filter (d)))]]
+  for (int i = 0; i < 64; i++)
+    ll++;
   [[omp::sequence (omp::directive (taskgroup task_reduction (+:r2) allocate (r2)),
     omp::directive (master taskloop simd
     private (p) firstprivate (f) lastprivate (l) shared (s) default(shared) num_tasks (nta) collapse(1) untied if(i1) final(fi) mergeable priority (pp)
@@ -390,17 +426,35 @@ bar (int d, int m, int i1, int i2, int i
     order(concurrent) allocate (f)))]]
   for (int i = 0; i < 64; i++)
     ll++;
+  [[omp::sequence (omp::directive (taskgroup task_reduction (+:r2) allocate (r2)),
+    omp::directive (masked taskloop simd
+    private (p) firstprivate (f) lastprivate (l) shared (s) default(shared) num_tasks (nta) collapse(1) untied if(i1) final(fi) mergeable priority (pp)
+    safelen(8) simdlen(4) linear(ll: 1) aligned(q: 32) reduction(default, +:r) in_reduction(+:r2) nontemporal(ntm)
+    order(concurrent) allocate (f) filter (d)))]]
+  for (int i = 0; i < 64; i++)
+    ll++;
   [[omp::directive (parallel master taskloop
     private (p) firstprivate (f) lastprivate (l) shared (s) default(shared) num_tasks (nta) collapse(1) untied if(i1) final(fi) mergeable priority (pp)
     reduction(default, +:r) num_threads (nth) proc_bind(spread) copyin(t) allocate (f))]]
   for (int i = 0; i < 64; i++)
     ll++;
+  [[omp::directive (parallel masked taskloop
+    private (p) firstprivate (f) lastprivate (l) shared (s) default(shared) num_tasks (nta) collapse(1) untied if(i1) final(fi) mergeable priority (pp)
+    reduction(default, +:r) num_threads (nth) proc_bind(spread) copyin(t) allocate (f) filter (d))]]
+  for (int i = 0; i < 64; i++)
+    ll++;
   [[omp::directive (parallel master taskloop simd
     private (p) firstprivate (f) lastprivate (l) shared (s) default(shared) num_tasks (nta) collapse(1) untied if(i1) final(fi) mergeable priority (pp)
     safelen(8) simdlen(4) linear(ll: 1) aligned(q: 32) reduction(default, +:r) nontemporal(ntm) num_threads (nth) proc_bind(spread) copyin(t)
     order(concurrent) allocate (f))]]
   for (int i = 0; i < 64; i++)
     ll++;
+  [[omp::directive (parallel masked taskloop simd
+    private (p) firstprivate (f) lastprivate (l) shared (s) default(shared) num_tasks (nta) collapse(1) untied if(i1) final(fi) mergeable priority (pp)
+    safelen(8) simdlen(4) linear(ll: 1) aligned(q: 32) reduction(default, +:r) nontemporal(ntm) num_threads (nth) proc_bind(spread) copyin(t)
+    order(concurrent) allocate (f) filter (d))]]
+  for (int i = 0; i < 64; i++)
+    ll++;
   [[omp::directive (loop bind(thread) order(concurrent)
     private (p) lastprivate (l) collapse(1) reduction(+:r))]]
   for (l = 0; l < 64; ++l)
--- gcc/testsuite/g++.dg/gomp/attrs-2.C.jj	2021-08-10 11:22:14.441607489 +0200
+++ gcc/testsuite/g++.dg/gomp/attrs-2.C	2021-08-12 14:12:14.293508450 +0200
@@ -348,6 +348,10 @@ bar (int d, int m, int i1, int i2, int i
     private (p),firstprivate (f),if (parallel: i2),default(shared),shared(s),reduction(+:r),
     num_threads (nth),proc_bind(spread),copyin(t),allocate (f))]]
     ;
+  [[omp::directive (parallel masked,
+    private (p),firstprivate (f),if (parallel: i2),default(shared),shared(s),reduction(+:r),
+    num_threads (nth),proc_bind(spread),copyin(t),allocate (f),filter(d))]]
+    ;
   [[omp::directive (parallel,
     private (p),firstprivate (f),if (parallel: i2),default(shared),shared(s),reduction(+:r),
     num_threads (nth),proc_bind(spread),copyin(t),allocate (f))]]
@@ -358,7 +362,15 @@ bar (int d, int m, int i1, int i2, int i
     reduction(default, +:r),in_reduction(+:r2),allocate (f)))]]
   for (int i = 0; i < 64; i++)
     ll++;
+  [[using omp:sequence (directive (taskgroup, task_reduction (+:r2),allocate (r2)),
+    omp::directive (masked taskloop,
+    private (p),firstprivate (f),lastprivate (l),shared (s),default(shared),grainsize (g),collapse(1),untied, if(taskloop: i1),final(fi),mergeable, priority (pp),
+    reduction(default, +:r),in_reduction(+:r2),allocate (f),filter(d)))]]
+  for (int i = 0; i < 64; i++)
+    ll++;
   [[using omp:directive (master)]];
+  [[using omp:directive (masked)]];
+  [[using omp:directive (masked,filter(d))]];
   [[omp::sequence (omp::directive (taskgroup task_reduction (+:r2),allocate (r2)),
     directive (master taskloop simd,
     private (p),firstprivate (f),lastprivate (l),shared (s),default(shared),grainsize (g),collapse(1),untied,if(taskloop: i1),if(simd: i2),final(fi),mergeable,priority (pp),
@@ -366,23 +378,47 @@ bar (int d, int m, int i1, int i2, int i
     order(concurrent),allocate (f)))]]
   for (int i = 0; i < 64; i++)
     ll++;
+  [[omp::sequence (omp::directive (taskgroup task_reduction (+:r2),allocate (r2)),
+    directive (masked taskloop simd,
+    private (p),firstprivate (f),lastprivate (l),shared (s),default(shared),grainsize (g),collapse(1),untied,if(taskloop: i1),if(simd: i2),final(fi),mergeable,priority (pp),
+    safelen(8),simdlen(4),linear(ll: 1),aligned(q: 32),reduction(default, +:r),in_reduction(+:r2),nontemporal(ntm),
+    order(concurrent),allocate (f),filter(d)))]]
+  for (int i = 0; i < 64; i++)
+    ll++;
   [[omp::directive (parallel master taskloop,
     private (p),firstprivate (f),lastprivate (l),shared (s),default(shared),grainsize (g),collapse(1),untied,if(taskloop: i1),final(fi),mergeable,priority (pp),
     reduction(default, +:r),if (parallel: i2),num_threads (nth),proc_bind(spread),copyin(t),allocate (f))]]
   for (int i = 0; i < 64; i++)
     ll++;
+  [[omp::directive (parallel masked taskloop,
+    private (p),firstprivate (f),lastprivate (l),shared (s),default(shared),grainsize (g),collapse(1),untied,if(taskloop: i1),final(fi),mergeable,priority (pp),
+    reduction(default, +:r),if (parallel: i2),num_threads (nth),proc_bind(spread),copyin(t),allocate (f),filter(d))]]
+  for (int i = 0; i < 64; i++)
+    ll++;
   [[omp::directive (parallel master taskloop simd,
     private (p),firstprivate (f),lastprivate (l),shared (s),default(shared),grainsize (g),collapse(1),untied,if(taskloop: i1),if(simd: i2),final(fi),mergeable,priority (pp),
     safelen(8),simdlen(4),linear(ll: 1),aligned(q: 32),reduction(default, +:r),nontemporal(ntm),if (parallel: i2),num_threads (nth),proc_bind(spread),copyin(t),
     order(concurrent),allocate (f))]]
   for (int i = 0; i < 64; i++)
     ll++;
+  [[omp::directive (parallel masked taskloop simd,
+    private (p),firstprivate (f),lastprivate (l),shared (s),default(shared),grainsize (g),collapse(1),untied,if(taskloop: i1),if(simd: i2),final(fi),mergeable,priority (pp),
+    safelen(8),simdlen(4),linear(ll: 1),aligned(q: 32),reduction(default, +:r),nontemporal(ntm),if (parallel: i2),num_threads (nth),proc_bind(spread),copyin(t),
+    order(concurrent),allocate (f),filter(d))]]
+  for (int i = 0; i < 64; i++)
+    ll++;
   [[omp::sequence (directive (taskgroup,task_reduction (+:r2),allocate (r2)),
     directive (master taskloop,
     private (p),firstprivate (f),lastprivate (l),shared (s),default(shared),num_tasks (nta),collapse(1),untied,if(i1),final(fi),mergeable,priority (pp),
     reduction(default, +:r),in_reduction(+:r2)))]]
   for (int i = 0; i < 64; i++)
     ll++;
+  [[omp::sequence (directive (taskgroup,task_reduction (+:r2),allocate (r2)),
+    directive (masked taskloop,
+    private (p),firstprivate (f),lastprivate (l),shared (s),default(shared),num_tasks (nta),collapse(1),untied,if(i1),final(fi),mergeable,priority (pp),
+    reduction(default, +:r),in_reduction(+:r2),filter(d)))]]
+  for (int i = 0; i < 64; i++)
+    ll++;
   [[omp::sequence (omp::directive (taskgroup,task_reduction (+:r2),allocate (r2)),
     omp::directive (master taskloop simd,
     private (p),firstprivate (f),lastprivate (l),shared (s),default(shared),num_tasks (nta),collapse(1),untied,if(i1),final(fi),mergeable,priority (pp),
@@ -390,17 +426,35 @@ bar (int d, int m, int i1, int i2, int i
     order(concurrent),allocate (f)))]]
   for (int i = 0; i < 64; i++)
     ll++;
+  [[omp::sequence (omp::directive (taskgroup,task_reduction (+:r2),allocate (r2)),
+    omp::directive (masked taskloop simd,
+    private (p),firstprivate (f),lastprivate (l),shared (s),default(shared),num_tasks (nta),collapse(1),untied,if(i1),final(fi),mergeable,priority (pp),
+    safelen(8),simdlen(4),linear(ll: 1),aligned(q: 32),reduction(default, +:r),in_reduction(+:r2),nontemporal(ntm),
+    order(concurrent),allocate (f),filter(d)))]]
+  for (int i = 0; i < 64; i++)
+    ll++;
   [[omp::directive (parallel master taskloop,
     private (p),firstprivate (f),lastprivate (l),shared (s),default(shared),num_tasks (nta),collapse(1),untied if(i1),final(fi),mergeable priority (pp),
     reduction(default, +:r),num_threads (nth),proc_bind(spread),copyin(t),allocate (f))]]
   for (int i = 0; i < 64; i++)
     ll++;
+  [[omp::directive (parallel masked taskloop,
+    private (p),firstprivate (f),lastprivate (l),shared (s),default(shared),num_tasks (nta),collapse(1),untied if(i1),final(fi),mergeable priority (pp),
+    reduction(default, +:r),num_threads (nth),proc_bind(spread),copyin(t),allocate (f),filter(d))]]
+  for (int i = 0; i < 64; i++)
+    ll++;
   [[omp::directive (parallel master taskloop simd,
     private (p),firstprivate (f),lastprivate (l),shared (s),default(shared),num_tasks (nta),collapse(1),untied if(i1),final(fi),mergeable priority (pp),
     safelen(8),simdlen(4),linear(ll: 1),aligned(q: 32),reduction(default, +:r),nontemporal(ntm),num_threads (nth),proc_bind(spread),copyin(t),
     order(concurrent),allocate (f))]]
   for (int i = 0; i < 64; i++)
     ll++;
+  [[omp::directive (parallel masked taskloop simd,
+    private (p),firstprivate (f),lastprivate (l),shared (s),default(shared),num_tasks (nta),collapse(1),untied if(i1),final(fi),mergeable priority (pp),
+    safelen(8),simdlen(4),linear(ll: 1),aligned(q: 32),reduction(default, +:r),nontemporal(ntm),num_threads (nth),proc_bind(spread),copyin(t),
+    order(concurrent),allocate (f),filter(d))]]
+  for (int i = 0; i < 64; i++)
+    ll++;
   [[omp::directive (loop, bind(thread),order(concurrent),
     private (p),lastprivate (l),collapse(1),reduction(+:r))]]
   for (l = 0; l < 64; ++l)
--- gcc/testsuite/gcc.dg/gomp/nesting-1.c.jj	2020-01-12 11:54:37.429398080 +0100
+++ gcc/testsuite/gcc.dg/gomp/nesting-1.c	2021-08-12 14:46:30.167127081 +0200
@@ -19,8 +19,10 @@ f1 (void)
       }
       #pragma omp single	/* { dg-error "may not be closely nested" } */
 	;
-    #pragma omp master		/* { dg-error "may not be closely nested" } */
-      ;
+      #pragma omp master	/* { dg-error "may not be closely nested" } */
+	;
+      #pragma omp masked	/* { dg-error "may not be closely nested" } */
+	;
       #pragma omp barrier	/* { dg-error "may not be closely nested" } */
     }
   #pragma omp sections
@@ -50,6 +52,11 @@ f1 (void)
   }
   #pragma omp sections
   {
+    #pragma omp masked		/* { dg-error "may not be closely nested" } */
+      ;
+  }
+  #pragma omp sections
+  {
     #pragma omp section
       ;
   }
@@ -81,6 +88,9 @@ f1 (void)
     #pragma omp section
     #pragma omp master		/* { dg-error "may not be closely nested" } */
       ;
+    #pragma omp section
+    #pragma omp masked		/* { dg-error "may not be closely nested" } */
+      ;
   }
   #pragma omp single
   {
@@ -97,6 +107,8 @@ f1 (void)
       ;
     #pragma omp master		/* { dg-error "may not be closely nested" } */
       ;
+    #pragma omp masked		/* { dg-error "may not be closely nested" } */
+      ;
     #pragma omp barrier		/* { dg-error "may not be closely nested" } */
   }
   #pragma omp master
@@ -116,6 +128,23 @@ f1 (void)
       ;
     #pragma omp barrier		/* { dg-error "may not be closely nested" } */
   }
+  #pragma omp masked filter (1)
+  {
+    #pragma omp for		/* { dg-error "may not be closely nested" } */
+    for (j = 0; j < 3; j++)
+      ;
+    #pragma omp sections	/* { dg-error "may not be closely nested" } */
+    {
+      ;
+    #pragma omp section
+      ;
+    }
+    #pragma omp single		/* { dg-error "may not be closely nested" } */
+      ;
+    #pragma omp master
+      ;
+    #pragma omp barrier		/* { dg-error "may not be closely nested" } */
+  }
   #pragma omp task
   {
     #pragma omp for		/* { dg-error "may not be closely nested" } */
@@ -131,6 +160,8 @@ f1 (void)
       ;
     #pragma omp master		/* { dg-error "may not be closely nested" } */
       ;
+    #pragma omp masked		/* { dg-error "may not be closely nested" } */
+      ;
     #pragma omp barrier		/* { dg-error "may not be closely nested" } */
   }
   #pragma omp parallel
@@ -148,6 +179,8 @@ f1 (void)
       ;
     #pragma omp master
       ;
+    #pragma omp masked
+      ;
     #pragma omp barrier
   }
 }
@@ -171,6 +204,8 @@ f2 (void)
       ;
     #pragma omp master
       ;
+    #pragma omp masked
+      ;
     #pragma omp barrier		/* { dg-error "may not be closely nested" } */
   }
 }
--- gcc/testsuite/gfortran.dg/goacc/host_data-tree.f95.jj	2020-01-12 11:54:38.237385890 +0100
+++ gcc/testsuite/gfortran.dg/goacc/host_data-tree.f95	2021-08-12 15:04:02.269980316 +0200
@@ -12,12 +12,12 @@ program test
   !$acc host_data use_device(p) if (p == 42)
   ! { dg-final { scan-tree-dump-times "(?n)D\\.\[0-9\]+ = \\*p == 42;$" 1 "original" } }
   ! { dg-final { scan-tree-dump-times "(?n)#pragma acc host_data use_device_ptr\\(p\\) if\\(D\\.\[0-9\]+\\)$" 1 "original" } }
-  ! { dg-final { scan-tree-dump-times "(?n)#pragma omp target oacc_host_data use_device_ptr\\(p\\) if\\(D\\.\[0-9\]+\\)$" 1 "gimple" } }
+  ! { dg-final { scan-tree-dump-times "(?n)#pragma omp target oacc_host_data use_device_ptr\\(p\\) if\\((?:D\\.|_)\[0-9\]+\\)$" 1 "gimple" } }
   !$acc end host_data
 
   !$acc host_data use_device(p) if_present if (p == 43)
   ! { dg-final { scan-tree-dump-times "(?n)D\\.\[0-9\]+ = \\*p == 43;$" 1 "original" } }
   ! { dg-final { scan-tree-dump-times "(?n)#pragma acc host_data use_device_ptr\\(p\\) if\\(D\\.\[0-9\]+\\) if_present$" 1 "original" } }
-  ! { dg-final { scan-tree-dump-times "(?n)#pragma omp target oacc_host_data use_device_ptr\\(if_present:p\\) if\\(D\\.\[0-9\]+\\) if_present$" 1 "gimple" } }
+  ! { dg-final { scan-tree-dump-times "(?n)#pragma omp target oacc_host_data use_device_ptr\\(if_present:p\\) if\\((?:D\\.|_)\[0-9\]+\\) if_present$" 1 "gimple" } }
   !$acc end host_data
 end program test
--- gcc/testsuite/gfortran.dg/goacc/kernels-tree.f95.jj	2021-04-19 17:43:20.260417067 +0200
+++ gcc/testsuite/gfortran.dg/goacc/kernels-tree.f95	2021-08-12 15:04:56.637229260 +0200
@@ -37,5 +37,5 @@ end program test
 
 ! { dg-final { scan-tree-dump-times "map\\(force_deviceptr:u\\)" 1 "original" } } 
 
-! { dg-final { scan-tree-dump-times {(?n)#pragma omp target oacc_data_kernels if\(D\.[0-9]+\)$} 1 "omp_oacc_kernels_decompose" } }
-! { dg-final { scan-tree-dump-times {(?n)#pragma omp target oacc_parallel_kernels_gang_single num_gangs\(1\) if\(D\.[0-9]+\) async\(-1\)$} 1 "omp_oacc_kernels_decompose" } }
+! { dg-final { scan-tree-dump-times {(?n)#pragma omp target oacc_data_kernels if\((?:D\.|_)[0-9]+\)$} 1 "omp_oacc_kernels_decompose" } }
+! { dg-final { scan-tree-dump-times {(?n)#pragma omp target oacc_parallel_kernels_gang_single num_gangs\(1\) if\((?:D\.|_)[0-9]+\) async\(-1\)$} 1 "omp_oacc_kernels_decompose" } }
--- libgomp/testsuite/libgomp.c-c++-common/masked-1.c.jj	2021-08-12 15:16:24.402788154 +0200
+++ libgomp/testsuite/libgomp.c-c++-common/masked-1.c	2021-08-12 15:28:54.368013743 +0200
@@ -0,0 +1,83 @@
+#include <omp.h>
+#include <stdlib.h>
+
+void
+foo (int x, int *a)
+{
+  #pragma omp masked
+  {
+    if (omp_get_thread_num () != 0)
+      abort ();
+    a[128]++;
+  }
+  #pragma omp masked filter (0)
+  {
+    if (omp_get_thread_num () != 0)
+      abort ();
+    a[129]++;
+  }
+  #pragma omp masked filter (7)
+  {
+    if (omp_get_thread_num () != 7)
+      abort ();
+    a[130]++;
+  }
+  #pragma omp masked filter (x)
+  {
+    if (omp_get_thread_num () != x)
+      abort ();
+    a[131]++;
+  }
+  #pragma omp masked taskloop simd filter (x) grainsize (12) simdlen (4)
+  for (int i = 0; i < 128; i++)
+    a[i] += i;
+}
+
+int
+main ()
+{
+  int a[136] = {};
+  #pragma omp parallel num_threads (4)
+  foo (4, a);
+  for (int i = 0; i < 128; i++)
+    if (a[i])
+      abort ();
+  if (a[128] != 1 || a[129] != 1 || a[130] || a[131])
+    abort ();
+  #pragma omp parallel num_threads (4)
+  foo (3, a);
+  for (int i = 0; i < 128; i++)
+    if (a[i] != i)
+      abort ();
+  if (a[128] != 2 || a[129] != 2 || a[130] || a[131] != 1)
+    abort ();
+  #pragma omp parallel num_threads (8)
+  foo (8, a);
+  for (int i = 0; i < 128; i++)
+    if (a[i] != i)
+      abort ();
+  if (a[128] != 3 || a[129] != 3 || a[130] != 1 || a[131] != 1)
+    abort ();
+  #pragma omp parallel num_threads (8)
+  foo (6, a);
+  for (int i = 0; i < 128; i++)
+    if (a[i] != 2 * i)
+      abort ();
+  if (a[128] != 4 || a[129] != 4 || a[130] != 2 || a[131] != 2)
+    abort ();
+  for (int i = 0; i < 8; i++)
+    a[i] = 0;
+  /* The filter expression can evaluate to different values in different threads.  */
+  #pragma omp parallel masked num_threads (8) filter (omp_get_thread_num () + 1)
+  a[omp_get_thread_num ()]++;
+  for (int i = 0; i < 8; i++)
+    if (a[i])
+      abort ();
+  /* And multiple threads can be filtered.  */
+  #pragma omp parallel masked num_threads (8) filter (omp_get_thread_num () & ~1)
+  a[omp_get_thread_num ()]++;
+  for (int i = 0; i < 8; i++)
+    if (a[i] != !(i & 1))
+      abort ();
+  return 0;
+}

	Jakub


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

* [Patch] Fortran/OpenMP: Add support for OpenMP 5.1 masked construct (was: Re: [committed] openmp: Add support for OpenMP 5.1 masked construct)
  2021-08-12 20:48 [committed] openmp: Add support for OpenMP 5.1 masked construct Jakub Jelinek
@ 2021-08-13 14:37 ` Tobias Burnus
  2021-08-13 18:52   ` Tobias Burnus
  2021-08-13 21:05 ` [committed] openmp: Add support for OpenMP 5.1 masked construct Thomas Schwinge
  1 sibling, 1 reply; 5+ messages in thread
From: Tobias Burnus @ 2021-08-13 14:37 UTC (permalink / raw)
  To: Jakub Jelinek, gcc-patches, fortran

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

Hi all, hi Jakub,

On 12.08.21 22:48, Jakub Jelinek via Gcc-patches wrote:
> This construct has been introduced as a replacement for master
> construct, but unlike that construct is slightly more general,
> has an optional clause which allows to choose which thread
> will be the one running the region, it can be some other thread
> than the master (primary) thread with number 0, or it could be no
> threads or multiple threads (then of course one needs to be careful
> about data races).

And the attached patch extends this to Fortran.

When converting the C/C++ runtime testcase to Fortran, I did run into a bug:

https://gcc.gnu.org/PR101899 (see PR or testcase; related to 'omp
taskloop'.)

Tobias

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

[-- Attachment #2: omp-masked-fortran.diff --]
[-- Type: text/x-patch, Size: 56024 bytes --]

Fortran/OpenMP: Add support for OpenMP 5.1 masked construct

Commit r12-2891-gd0befed793b94f3f407be44e6f69f81a02f5f073 added C/C++
support for the masked construct. This patch extends it to
Fortran.

gcc/fortran/ChangeLog:

	* dump-parse-tree.c (show_omp_clauses): Handle 'filter' clause.
	(show_omp_node, show_code_node): Handle (combined) omp masked construct.
	* frontend-passes.c (gfc_code_walker): Likewise.
	* gfortran.h (enum gfc_statement): Add ST_OMP_*_MASKED*.
	(enum gfc_exec_op): Add EXEC_OMP_*_MASKED*.
	* match.h (gfc_match_omp_masked, gfc_match_omp_masked_taskloop,
	gfc_match_omp_masked_taskloop_simd, gfc_match_omp_parallel_masked,
	gfc_match_omp_parallel_masked_taskloop,
	gfc_match_omp_parallel_masked_taskloop_simd): New prototypes.
	* openmp.c (enum omp_mask1): Add OMP_CLAUSE_FILTER.
	(gfc_match_omp_clauses): Match it.
	(OMP_MASKED_CLAUSES, gfc_match_omp_parallel_masked,
	gfc_match_omp_parallel_masked_taskloop,
	gfc_match_omp_parallel_masked_taskloop_simd,
	gfc_match_omp_masked, gfc_match_omp_masked_taskloop,
	gfc_match_omp_masked_taskloop_simd): New.
	(resolve_omp_clauses): Resolve filter clause. 
	(gfc_resolve_omp_parallel_blocks, resolve_omp_do,
	omp_code_to_statement, gfc_resolve_omp_directive): Handle
	omp masked constructs.
	* parse.c (decode_omp_directive, case_exec_markers,
	gfc_ascii_statement, parse_omp_do, parse_omp_structured_block,
	parse_executable): Likewise.
	* resolve.c (gfc_resolve_blocks, gfc_resolve_code): Likewise.
	* st.c (gfc_free_statement): Likewise.
	* trans-openmp.c (gfc_trans_omp_clauses): Handle filter clause.
	(GFC_OMP_SPLIT_MASKED, GFC_OMP_MASK_MASKED): New enum values.
	(gfc_trans_omp_masked): New.
	(gfc_split_omp_clauses): Handle combined masked directives.
	(gfc_trans_omp_master_taskloop): Rename to ...
	(gfc_trans_omp_master_masked_taskloop): ... this; handle also
	combined masked directives.
	(gfc_trans_omp_parallel_master): Rename to ...
	(gfc_trans_omp_parallel_master_masked): ... this; handle
	combined masked directives.
	(gfc_trans_omp_directive): Handle EXEC_OMP_*_MASKED*.
	* trans.c (trans_code): Likewise.

libgomp/ChangeLog:

	* testsuite/libgomp.fortran/masked-1.f90: New test.

gcc/testsuite/ChangeLog:

	* gfortran.dg/gomp/masked-1.f90: New test.
	* gfortran.dg/gomp/masked-2.f90: New test.
	* gfortran.dg/gomp/masked-3.f90: New test.
	* gfortran.dg/gomp/masked-combined-1.f90: New test.
	* gfortran.dg/gomp/masked-combined-2.f90: New test.

 gcc/fortran/dump-parse-tree.c                      |  24 +++
 gcc/fortran/frontend-passes.c                      |   3 +
 gcc/fortran/gfortran.h                             |  14 +-
 gcc/fortran/match.h                                |   6 +
 gcc/fortran/openmp.c                               |  98 ++++++++++++
 gcc/fortran/parse.c                                |  91 ++++++++++-
 gcc/fortran/resolve.c                              |  15 ++
 gcc/fortran/st.c                                   |   6 +
 gcc/fortran/trans-openmp.c                         | 176 +++++++++++++++++----
 gcc/fortran/trans.c                                |   6 +
 gcc/testsuite/gfortran.dg/gomp/masked-1.f90        |  94 +++++++++++
 gcc/testsuite/gfortran.dg/gomp/masked-2.f90        |  46 ++++++
 gcc/testsuite/gfortran.dg/gomp/masked-3.f90        |  12 ++
 .../gfortran.dg/gomp/masked-combined-1.f90         |  65 ++++++++
 .../gfortran.dg/gomp/masked-combined-2.f90         |  24 +++
 libgomp/testsuite/libgomp.fortran/masked-1.f90     | 141 +++++++++++++++++
 16 files changed, 788 insertions(+), 33 deletions(-)

diff --git a/gcc/fortran/dump-parse-tree.c b/gcc/fortran/dump-parse-tree.c
index 360abf18a6a..53c49fe4d6f 100644
--- a/gcc/fortran/dump-parse-tree.c
+++ b/gcc/fortran/dump-parse-tree.c
@@ -1808,6 +1808,12 @@ show_omp_clauses (gfc_omp_clauses *omp_clauses)
       show_expr (omp_clauses->grainsize);
       fputc (')', dumpfile);
     }
+  if (omp_clauses->filter)
+    {
+      fputs (" FILTER(", dumpfile);
+      show_expr (omp_clauses->filter);
+      fputc (')', dumpfile);
+    }
   if (omp_clauses->hint)
     {
       fputs (" HINT(", dumpfile);
@@ -1946,6 +1952,9 @@ show_omp_node (int level, gfc_code *c)
     case EXEC_OMP_DO_SIMD: name = "DO SIMD"; break;
     case EXEC_OMP_LOOP: name = "LOOP"; break;
     case EXEC_OMP_FLUSH: name = "FLUSH"; break;
+    case EXEC_OMP_MASKED: name = "MASKED"; break;
+    case EXEC_OMP_MASKED_TASKLOOP: name = "MASKED TASKLOOP"; break;
+    case EXEC_OMP_MASKED_TASKLOOP_SIMD: name = "MASKED TASKLOOP SIMD"; break;
     case EXEC_OMP_MASTER: name = "MASTER"; break;
     case EXEC_OMP_MASTER_TASKLOOP: name = "MASTER TASKLOOP"; break;
     case EXEC_OMP_MASTER_TASKLOOP_SIMD: name = "MASTER TASKLOOP SIMD"; break;
@@ -1956,6 +1965,11 @@ show_omp_node (int level, gfc_code *c)
     case EXEC_OMP_PARALLEL_DO_SIMD: name = "PARALLEL DO SIMD"; break;
     case EXEC_OMP_PARALLEL_LOOP: name = "PARALLEL LOOP"; break;
     case EXEC_OMP_PARALLEL_MASTER: name = "PARALLEL MASTER"; break;
+    case EXEC_OMP_PARALLEL_MASKED: name = "PARALLEL MASK"; break;
+    case EXEC_OMP_PARALLEL_MASKED_TASKLOOP:
+      name = "PARALLEL MASK TASKLOOP"; break;
+    case EXEC_OMP_PARALLEL_MASKED_TASKLOOP_SIMD:
+      name = "PARALLEL MASK TASKLOOP SIMD"; break;
     case EXEC_OMP_PARALLEL_MASTER_TASKLOOP:
       name = "PARALLEL MASTER TASKLOOP"; break;
     case EXEC_OMP_PARALLEL_MASTER_TASKLOOP_SIMD:
@@ -2032,10 +2046,14 @@ show_omp_node (int level, gfc_code *c)
     case EXEC_OMP_DO_SIMD:
     case EXEC_OMP_LOOP:
     case EXEC_OMP_ORDERED:
+    case EXEC_OMP_MASKED:
     case EXEC_OMP_PARALLEL:
     case EXEC_OMP_PARALLEL_DO:
     case EXEC_OMP_PARALLEL_DO_SIMD:
     case EXEC_OMP_PARALLEL_LOOP:
+    case EXEC_OMP_PARALLEL_MASKED:
+    case EXEC_OMP_PARALLEL_MASKED_TASKLOOP:
+    case EXEC_OMP_PARALLEL_MASKED_TASKLOOP_SIMD:
     case EXEC_OMP_PARALLEL_MASTER:
     case EXEC_OMP_PARALLEL_MASTER_TASKLOOP:
     case EXEC_OMP_PARALLEL_MASTER_TASKLOOP_SIMD:
@@ -3250,6 +3268,9 @@ show_code_node (int level, gfc_code *c)
     case EXEC_OMP_DO_SIMD:
     case EXEC_OMP_FLUSH:
     case EXEC_OMP_LOOP:
+    case EXEC_OMP_MASKED:
+    case EXEC_OMP_MASKED_TASKLOOP:
+    case EXEC_OMP_MASKED_TASKLOOP_SIMD:
     case EXEC_OMP_MASTER:
     case EXEC_OMP_MASTER_TASKLOOP:
     case EXEC_OMP_MASTER_TASKLOOP_SIMD:
@@ -3258,6 +3279,9 @@ show_code_node (int level, gfc_code *c)
     case EXEC_OMP_PARALLEL_DO:
     case EXEC_OMP_PARALLEL_DO_SIMD:
     case EXEC_OMP_PARALLEL_LOOP:
+    case EXEC_OMP_PARALLEL_MASKED:
+    case EXEC_OMP_PARALLEL_MASKED_TASKLOOP:
+    case EXEC_OMP_PARALLEL_MASKED_TASKLOOP_SIMD:
     case EXEC_OMP_PARALLEL_MASTER:
     case EXEC_OMP_PARALLEL_MASTER_TASKLOOP:
     case EXEC_OMP_PARALLEL_MASTER_TASKLOOP_SIMD:
diff --git a/gcc/fortran/frontend-passes.c b/gcc/fortran/frontend-passes.c
index 996dcc2e547..145bff50f3e 100644
--- a/gcc/fortran/frontend-passes.c
+++ b/gcc/fortran/frontend-passes.c
@@ -5556,6 +5556,9 @@ gfc_code_walker (gfc_code **c, walk_code_fn_t codefn, walk_expr_fn_t exprfn,
 	    case EXEC_OMP_PARALLEL_DO:
 	    case EXEC_OMP_PARALLEL_DO_SIMD:
 	    case EXEC_OMP_PARALLEL_LOOP:
+	    case EXEC_OMP_PARALLEL_MASKED:
+	    case EXEC_OMP_PARALLEL_MASKED_TASKLOOP:
+	    case EXEC_OMP_PARALLEL_MASKED_TASKLOOP_SIMD:
 	    case EXEC_OMP_PARALLEL_MASTER:
 	    case EXEC_OMP_PARALLEL_MASTER_TASKLOOP:
 	    case EXEC_OMP_PARALLEL_MASTER_TASKLOOP_SIMD:
diff --git a/gcc/fortran/gfortran.h b/gcc/fortran/gfortran.h
index 8f75dd95394..5fde4174a5b 100644
--- a/gcc/fortran/gfortran.h
+++ b/gcc/fortran/gfortran.h
@@ -275,7 +275,13 @@ enum gfc_statement
   ST_OMP_PARALLEL_LOOP, ST_OMP_END_PARALLEL_LOOP, ST_OMP_TEAMS_LOOP,
   ST_OMP_END_TEAMS_LOOP, ST_OMP_TARGET_PARALLEL_LOOP,
   ST_OMP_END_TARGET_PARALLEL_LOOP, ST_OMP_TARGET_TEAMS_LOOP,
-  ST_OMP_END_TARGET_TEAMS_LOOP, ST_NONE
+  ST_OMP_END_TARGET_TEAMS_LOOP, ST_OMP_MASKED, ST_OMP_END_MASKED,
+  ST_OMP_PARALLEL_MASKED, ST_OMP_END_PARALLEL_MASKED,
+  ST_OMP_PARALLEL_MASKED_TASKLOOP, ST_OMP_END_PARALLEL_MASKED_TASKLOOP,
+  ST_OMP_PARALLEL_MASKED_TASKLOOP_SIMD,
+  ST_OMP_END_PARALLEL_MASKED_TASKLOOP_SIMD, ST_OMP_MASKED_TASKLOOP,
+  ST_OMP_END_MASKED_TASKLOOP, ST_OMP_MASKED_TASKLOOP_SIMD,
+  ST_OMP_END_MASKED_TASKLOOP_SIMD, ST_NONE
 };
 
 /* Types of interfaces that we can have.  Assignment interfaces are
@@ -1466,6 +1472,7 @@ typedef struct gfc_omp_clauses
   struct gfc_expr *device;
   struct gfc_expr *thread_limit;
   struct gfc_expr *grainsize;
+  struct gfc_expr *filter;
   struct gfc_expr *hint;
   struct gfc_expr *num_tasks;
   struct gfc_expr *priority;
@@ -2758,7 +2765,10 @@ enum gfc_exec_op
   EXEC_OMP_PARALLEL_MASTER, EXEC_OMP_PARALLEL_MASTER_TASKLOOP,
   EXEC_OMP_PARALLEL_MASTER_TASKLOOP_SIMD, EXEC_OMP_MASTER_TASKLOOP,
   EXEC_OMP_MASTER_TASKLOOP_SIMD, EXEC_OMP_LOOP, EXEC_OMP_PARALLEL_LOOP,
-  EXEC_OMP_TEAMS_LOOP, EXEC_OMP_TARGET_PARALLEL_LOOP, EXEC_OMP_TARGET_TEAMS_LOOP
+  EXEC_OMP_TEAMS_LOOP, EXEC_OMP_TARGET_PARALLEL_LOOP,
+  EXEC_OMP_TARGET_TEAMS_LOOP, EXEC_OMP_MASKED, EXEC_OMP_PARALLEL_MASKED,
+  EXEC_OMP_PARALLEL_MASKED_TASKLOOP, EXEC_OMP_PARALLEL_MASKED_TASKLOOP_SIMD,
+  EXEC_OMP_MASKED_TASKLOOP, EXEC_OMP_MASKED_TASKLOOP_SIMD
 };
 
 typedef struct gfc_code
diff --git a/gcc/fortran/match.h b/gcc/fortran/match.h
index bb1f34fc444..dce650346d3 100644
--- a/gcc/fortran/match.h
+++ b/gcc/fortran/match.h
@@ -169,6 +169,9 @@ match gfc_match_omp_do (void);
 match gfc_match_omp_do_simd (void);
 match gfc_match_omp_loop (void);
 match gfc_match_omp_flush (void);
+match gfc_match_omp_masked (void);
+match gfc_match_omp_masked_taskloop (void);
+match gfc_match_omp_masked_taskloop_simd (void);
 match gfc_match_omp_master (void);
 match gfc_match_omp_master_taskloop (void);
 match gfc_match_omp_master_taskloop_simd (void);
@@ -178,6 +181,9 @@ match gfc_match_omp_parallel (void);
 match gfc_match_omp_parallel_do (void);
 match gfc_match_omp_parallel_do_simd (void);
 match gfc_match_omp_parallel_loop (void);
+match gfc_match_omp_parallel_masked (void);
+match gfc_match_omp_parallel_masked_taskloop (void);
+match gfc_match_omp_parallel_masked_taskloop_simd (void);
 match gfc_match_omp_parallel_master (void);
 match gfc_match_omp_parallel_master_taskloop (void);
 match gfc_match_omp_parallel_master_taskloop_simd (void);
diff --git a/gcc/fortran/openmp.c b/gcc/fortran/openmp.c
index ec558656602..1bce43cb33e 100644
--- a/gcc/fortran/openmp.c
+++ b/gcc/fortran/openmp.c
@@ -847,6 +847,7 @@ enum omp_mask1
   OMP_CLAUSE_DETACH,  /* OpenMP 5.0.  */
   OMP_CLAUSE_AFFINITY,  /* OpenMP 5.0.  */
   OMP_CLAUSE_BIND,  /* OpenMP 5.0.  */
+  OMP_CLAUSE_FILTER,  /* OpenMP 5.1.  */
   OMP_CLAUSE_NOWAIT,
   /* This must come last.  */
   OMP_MASK1_LAST
@@ -1772,6 +1773,10 @@ gfc_match_omp_clauses (gfc_omp_clauses **cp, const omp_mask mask,
 	    }
 	  break;
 	case 'f':
+	  if ((mask & OMP_CLAUSE_FILTER)
+	      && c->filter == NULL
+	      && gfc_match ("filter ( %e )", &c->filter) == MATCH_YES)
+	    continue;
 	  if ((mask & OMP_CLAUSE_FINAL)
 	      && c->final_expr == NULL
 	      && gfc_match ("final ( %e )", &c->final_expr) == MATCH_YES)
@@ -3199,6 +3204,8 @@ cleanup:
 #define OMP_ATOMIC_CLAUSES \
   (omp_mask (OMP_CLAUSE_ATOMIC) | OMP_CLAUSE_CAPTURE | OMP_CLAUSE_HINT	\
    | OMP_CLAUSE_MEMORDER)
+#define OMP_MASKED_CLAUSES \
+  (omp_mask (OMP_CLAUSE_FILTER))
 
 
 static match
@@ -4157,6 +4164,31 @@ gfc_match_omp_parallel_do_simd (void)
 }
 
 
+match
+gfc_match_omp_parallel_masked (void)
+{
+  return match_omp (EXEC_OMP_PARALLEL_MASKED,
+		    OMP_PARALLEL_CLAUSES | OMP_MASKED_CLAUSES);
+}
+
+match
+gfc_match_omp_parallel_masked_taskloop (void)
+{
+  return match_omp (EXEC_OMP_PARALLEL_MASKED_TASKLOOP,
+		    (OMP_PARALLEL_CLAUSES | OMP_MASKED_CLAUSES
+		     | OMP_TASKLOOP_CLAUSES)
+		    & ~(omp_mask (OMP_CLAUSE_IN_REDUCTION)));
+}
+
+match
+gfc_match_omp_parallel_masked_taskloop_simd (void)
+{
+  return match_omp (EXEC_OMP_PARALLEL_MASKED_TASKLOOP_SIMD,
+		    (OMP_PARALLEL_CLAUSES | OMP_MASKED_CLAUSES
+		     | OMP_TASKLOOP_CLAUSES | OMP_SIMD_CLAUSES)
+		    & ~(omp_mask (OMP_CLAUSE_IN_REDUCTION)));
+}
+
 match
 gfc_match_omp_parallel_master (void)
 {
@@ -4703,6 +4735,27 @@ gfc_match_omp_workshare (void)
 }
 
 
+match
+gfc_match_omp_masked (void)
+{
+  return match_omp (EXEC_OMP_MASKED, OMP_MASKED_CLAUSES);
+}
+
+match
+gfc_match_omp_masked_taskloop (void)
+{
+  return match_omp (EXEC_OMP_MASKED_TASKLOOP,
+		    OMP_MASKED_CLAUSES | OMP_TASKLOOP_CLAUSES);
+}
+
+match
+gfc_match_omp_masked_taskloop_simd (void)
+{
+  return match_omp (EXEC_OMP_MASKED_TASKLOOP_SIMD,
+		    (OMP_MASKED_CLAUSES | OMP_TASKLOOP_CLAUSES
+		     | OMP_SIMD_CLAUSES));
+}
+
 match
 gfc_match_omp_master (void)
 {
@@ -5254,6 +5307,7 @@ resolve_omp_clauses (gfc_code *code, gfc_omp_clauses *omp_clauses,
 
 	    case EXEC_OMP_PARALLEL:
 	    case EXEC_OMP_PARALLEL_DO:
+	    case EXEC_OMP_PARALLEL_MASKED:
 	    case EXEC_OMP_PARALLEL_MASTER:
 	    case EXEC_OMP_PARALLEL_SECTIONS:
 	    case EXEC_OMP_PARALLEL_WORKSHARE:
@@ -5268,10 +5322,12 @@ resolve_omp_clauses (gfc_code *code, gfc_omp_clauses *omp_clauses,
 	      ok = ifc == OMP_IF_PARALLEL || ifc == OMP_IF_SIMD;
 	      break;
 
+	    case EXEC_OMP_PARALLEL_MASKED_TASKLOOP:
 	    case EXEC_OMP_PARALLEL_MASTER_TASKLOOP:
 	      ok = ifc == OMP_IF_PARALLEL || ifc == OMP_IF_TASKLOOP;
 	      break;
 
+	    case EXEC_OMP_PARALLEL_MASKED_TASKLOOP_SIMD:
 	    case EXEC_OMP_PARALLEL_MASTER_TASKLOOP_SIMD:
 	      ok = (ifc == OMP_IF_PARALLEL
 		    || ifc == OMP_IF_TASKLOOP
@@ -5290,11 +5346,13 @@ resolve_omp_clauses (gfc_code *code, gfc_omp_clauses *omp_clauses,
 	      break;
 
 	    case EXEC_OMP_TASKLOOP:
+	    case EXEC_OMP_MASKED_TASKLOOP:
 	    case EXEC_OMP_MASTER_TASKLOOP:
 	      ok = ifc == OMP_IF_TASKLOOP;
 	      break;
 
 	    case EXEC_OMP_TASKLOOP_SIMD:
+	    case EXEC_OMP_MASKED_TASKLOOP_SIMD:
 	    case EXEC_OMP_MASTER_TASKLOOP_SIMD:
 	      ok = ifc == OMP_IF_TASKLOOP || ifc == OMP_IF_SIMD;
 	      break;
@@ -6060,9 +6118,13 @@ resolve_omp_clauses (gfc_code *code, gfc_omp_clauses *omp_clauses,
 			&& (code->op == EXEC_OMP_LOOP
 			    || code->op == EXEC_OMP_TASKLOOP
 			    || code->op == EXEC_OMP_TASKLOOP_SIMD
+			    || code->op == EXEC_OMP_MASKED_TASKLOOP
+			    || code->op == EXEC_OMP_MASKED_TASKLOOP_SIMD
 			    || code->op == EXEC_OMP_MASTER_TASKLOOP
 			    || code->op == EXEC_OMP_MASTER_TASKLOOP_SIMD
 			    || code->op == EXEC_OMP_PARALLEL_LOOP
+			    || code->op == EXEC_OMP_PARALLEL_MASKED_TASKLOOP
+			    || code->op == EXEC_OMP_PARALLEL_MASKED_TASKLOOP_SIMD
 			    || code->op == EXEC_OMP_PARALLEL_MASTER_TASKLOOP
 			    || code->op == EXEC_OMP_PARALLEL_MASTER_TASKLOOP_SIMD
 			    || code->op == EXEC_OMP_TARGET_PARALLEL_LOOP
@@ -6322,6 +6384,8 @@ resolve_omp_clauses (gfc_code *code, gfc_omp_clauses *omp_clauses,
     resolve_positive_int_expr (omp_clauses->num_teams, "NUM_TEAMS");
   if (omp_clauses->device)
     resolve_nonnegative_int_expr (omp_clauses->device, "DEVICE");
+  if (omp_clauses->filter)
+    resolve_nonnegative_int_expr (omp_clauses->filter, "FILTER");
   if (omp_clauses->hint)
     {
       resolve_scalar_int_expr (omp_clauses->hint, "HINT");
@@ -6984,8 +7048,12 @@ gfc_resolve_omp_parallel_blocks (gfc_code *code, gfc_namespace *ns)
     case EXEC_OMP_DISTRIBUTE_PARALLEL_DO_SIMD:
     case EXEC_OMP_PARALLEL_DO:
     case EXEC_OMP_PARALLEL_DO_SIMD:
+    case EXEC_OMP_PARALLEL_MASKED_TASKLOOP:
+    case EXEC_OMP_PARALLEL_MASKED_TASKLOOP_SIMD:
     case EXEC_OMP_PARALLEL_MASTER_TASKLOOP:
     case EXEC_OMP_PARALLEL_MASTER_TASKLOOP_SIMD:
+    case EXEC_OMP_MASKED_TASKLOOP:
+    case EXEC_OMP_MASKED_TASKLOOP_SIMD:
     case EXEC_OMP_MASTER_TASKLOOP:
     case EXEC_OMP_MASTER_TASKLOOP_SIMD:
     case EXEC_OMP_TARGET_PARALLEL_DO:
@@ -7133,6 +7201,13 @@ resolve_omp_do (gfc_code *code)
       is_simd = true;
       break;
     case EXEC_OMP_PARALLEL_LOOP: name = "!$OMP PARALLEL LOOP"; break;
+    case EXEC_OMP_PARALLEL_MASKED_TASKLOOP:
+      name = "!$OMP PARALLEL MASKED TASKLOOP";
+      break;
+    case EXEC_OMP_PARALLEL_MASKED_TASKLOOP_SIMD:
+      name = "!$OMP PARALLEL MASKED TASKLOOP SIMD";
+      is_simd = true;
+      break;
     case EXEC_OMP_PARALLEL_MASTER_TASKLOOP:
       name = "!$OMP PARALLEL MASTER TASKLOOP";
       break;
@@ -7140,6 +7215,11 @@ resolve_omp_do (gfc_code *code)
       name = "!$OMP PARALLEL MASTER TASKLOOP SIMD";
       is_simd = true;
       break;
+    case EXEC_OMP_MASKED_TASKLOOP: name = "!$OMP MASKED TASKLOOP"; break;
+    case EXEC_OMP_MASKED_TASKLOOP_SIMD:
+      name = "!$OMP MASKED TASKLOOP SIMD";
+      is_simd = true;
+      break;
     case EXEC_OMP_MASTER_TASKLOOP: name = "!$OMP MASTER TASKLOOP"; break;
     case EXEC_OMP_MASTER_TASKLOOP_SIMD:
       name = "!$OMP MASTER TASKLOOP SIMD";
@@ -7302,6 +7382,12 @@ omp_code_to_statement (gfc_code *code)
     {
     case EXEC_OMP_PARALLEL:
       return ST_OMP_PARALLEL;
+    case EXEC_OMP_PARALLEL_MASKED:
+      return ST_OMP_PARALLEL_MASKED;
+    case EXEC_OMP_PARALLEL_MASKED_TASKLOOP:
+      return ST_OMP_PARALLEL_MASKED_TASKLOOP;
+    case EXEC_OMP_PARALLEL_MASKED_TASKLOOP_SIMD:
+      return ST_OMP_PARALLEL_MASKED_TASKLOOP_SIMD;
     case EXEC_OMP_PARALLEL_MASTER:
       return ST_OMP_PARALLEL_MASTER;
     case EXEC_OMP_PARALLEL_MASTER_TASKLOOP:
@@ -7316,6 +7402,12 @@ omp_code_to_statement (gfc_code *code)
       return ST_OMP_ORDERED;
     case EXEC_OMP_CRITICAL:
       return ST_OMP_CRITICAL;
+    case EXEC_OMP_MASKED:
+      return ST_OMP_MASKED;
+    case EXEC_OMP_MASKED_TASKLOOP:
+      return ST_OMP_MASKED_TASKLOOP;
+    case EXEC_OMP_MASKED_TASKLOOP_SIMD:
+      return ST_OMP_MASKED_TASKLOOP_SIMD;
     case EXEC_OMP_MASTER:
       return ST_OMP_MASTER;
     case EXEC_OMP_MASTER_TASKLOOP:
@@ -7822,8 +7914,12 @@ gfc_resolve_omp_directive (gfc_code *code, gfc_namespace *ns)
     case EXEC_OMP_PARALLEL_DO:
     case EXEC_OMP_PARALLEL_DO_SIMD:
     case EXEC_OMP_PARALLEL_LOOP:
+    case EXEC_OMP_PARALLEL_MASKED_TASKLOOP:
+    case EXEC_OMP_PARALLEL_MASKED_TASKLOOP_SIMD:
     case EXEC_OMP_PARALLEL_MASTER_TASKLOOP:
     case EXEC_OMP_PARALLEL_MASTER_TASKLOOP_SIMD:
+    case EXEC_OMP_MASKED_TASKLOOP:
+    case EXEC_OMP_MASKED_TASKLOOP_SIMD:
     case EXEC_OMP_MASTER_TASKLOOP:
     case EXEC_OMP_MASTER_TASKLOOP_SIMD:
     case EXEC_OMP_SIMD:
@@ -7846,8 +7942,10 @@ gfc_resolve_omp_directive (gfc_code *code, gfc_namespace *ns)
       resolve_omp_do (code);
       break;
     case EXEC_OMP_CANCEL:
+    case EXEC_OMP_MASKED:
     case EXEC_OMP_PARALLEL_WORKSHARE:
     case EXEC_OMP_PARALLEL:
+    case EXEC_OMP_PARALLEL_MASKED:
     case EXEC_OMP_PARALLEL_MASTER:
     case EXEC_OMP_PARALLEL_SECTIONS:
     case EXEC_OMP_SECTIONS:
diff --git a/gcc/fortran/parse.c b/gcc/fortran/parse.c
index 6d7845e8517..e1d78de5d9e 100644
--- a/gcc/fortran/parse.c
+++ b/gcc/fortran/parse.c
@@ -920,6 +920,11 @@ decode_omp_directive (void)
       matchs ("end do simd", gfc_match_omp_end_nowait, ST_OMP_END_DO_SIMD);
       matcho ("end do", gfc_match_omp_end_nowait, ST_OMP_END_DO);
       matchs ("end simd", gfc_match_omp_eos_error, ST_OMP_END_SIMD);
+      matcho ("end masked taskloop simd", gfc_match_omp_eos_error,
+	      ST_OMP_END_MASKED_TASKLOOP_SIMD);
+      matcho ("end masked taskloop", gfc_match_omp_eos_error,
+	      ST_OMP_END_MASKED_TASKLOOP);
+      matcho ("end masked", gfc_match_omp_eos_error, ST_OMP_END_MASKED);
       matcho ("end master taskloop simd", gfc_match_omp_eos_error,
 	      ST_OMP_END_MASTER_TASKLOOP_SIMD);
       matcho ("end master taskloop", gfc_match_omp_eos_error,
@@ -929,6 +934,12 @@ decode_omp_directive (void)
       matchs ("end parallel do simd", gfc_match_omp_eos_error,
 	      ST_OMP_END_PARALLEL_DO_SIMD);
       matcho ("end parallel do", gfc_match_omp_eos_error, ST_OMP_END_PARALLEL_DO);
+      matcho ("end parallel masked taskloop simd", gfc_match_omp_eos_error,
+	      ST_OMP_END_PARALLEL_MASKED_TASKLOOP_SIMD);
+      matcho ("end parallel masked taskloop", gfc_match_omp_eos_error,
+	      ST_OMP_END_PARALLEL_MASKED_TASKLOOP);
+      matcho ("end parallel masked", gfc_match_omp_eos_error,
+	      ST_OMP_END_PARALLEL_MASKED);
       matcho ("end parallel master taskloop simd", gfc_match_omp_eos_error,
 	      ST_OMP_END_PARALLEL_MASTER_TASKLOOP_SIMD);
       matcho ("end parallel master taskloop", gfc_match_omp_eos_error,
@@ -982,6 +993,11 @@ decode_omp_directive (void)
       matcho ("flush", gfc_match_omp_flush, ST_OMP_FLUSH);
       break;
     case 'm':
+      matcho ("masked taskloop simd", gfc_match_omp_masked_taskloop_simd,
+	      ST_OMP_MASKED_TASKLOOP_SIMD);
+      matcho ("masked taskloop", gfc_match_omp_masked_taskloop,
+	      ST_OMP_MASKED_TASKLOOP);
+      matcho ("masked", gfc_match_omp_masked, ST_OMP_MASKED);
       matcho ("master taskloop simd", gfc_match_omp_master_taskloop_simd,
 	      ST_OMP_MASTER_TASKLOOP_SIMD);
       matcho ("master taskloop", gfc_match_omp_master_taskloop,
@@ -1009,6 +1025,14 @@ decode_omp_directive (void)
       matcho ("parallel do", gfc_match_omp_parallel_do, ST_OMP_PARALLEL_DO);
       matcho ("parallel loop", gfc_match_omp_parallel_loop,
 	      ST_OMP_PARALLEL_LOOP);
+      matcho ("parallel masked taskloop simd",
+	      gfc_match_omp_parallel_masked_taskloop_simd,
+	      ST_OMP_PARALLEL_MASKED_TASKLOOP_SIMD);
+      matcho ("parallel masked taskloop",
+	      gfc_match_omp_parallel_masked_taskloop,
+	      ST_OMP_PARALLEL_MASKED_TASKLOOP);
+      matcho ("parallel masked", gfc_match_omp_parallel_masked,
+	      ST_OMP_PARALLEL_MASKED);
       matcho ("parallel master taskloop simd",
 	      gfc_match_omp_parallel_master_taskloop_simd,
 	      ST_OMP_PARALLEL_MASTER_TASKLOOP_SIMD);
@@ -1639,11 +1663,15 @@ next_statement (void)
 #define case_exec_markers case ST_DO: case ST_FORALL_BLOCK: \
   case ST_IF_BLOCK: case ST_BLOCK: case ST_ASSOCIATE: \
   case ST_WHERE_BLOCK: case ST_SELECT_CASE: case ST_SELECT_TYPE: \
-  case ST_SELECT_RANK: case ST_OMP_PARALLEL: case ST_OMP_PARALLEL_MASTER: \
+  case ST_SELECT_RANK: case ST_OMP_PARALLEL: case ST_OMP_PARALLEL_MASKED: \
+  case ST_OMP_PARALLEL_MASKED_TASKLOOP: \
+  case ST_OMP_PARALLEL_MASKED_TASKLOOP_SIMD: case ST_OMP_PARALLEL_MASTER: \
   case ST_OMP_PARALLEL_MASTER_TASKLOOP: \
   case ST_OMP_PARALLEL_MASTER_TASKLOOP_SIMD: \
   case ST_OMP_PARALLEL_SECTIONS: case ST_OMP_SECTIONS: case ST_OMP_ORDERED: \
-  case ST_OMP_CRITICAL: case ST_OMP_MASTER: case ST_OMP_MASTER_TASKLOOP: \
+  case ST_OMP_CRITICAL: case ST_OMP_MASKED: case ST_OMP_MASKED_TASKLOOP: \
+  case ST_OMP_MASKED_TASKLOOP_SIMD: \
+  case ST_OMP_MASTER: case ST_OMP_MASTER_TASKLOOP: \
   case ST_OMP_MASTER_TASKLOOP_SIMD: case ST_OMP_SINGLE: \
   case ST_OMP_DO: case ST_OMP_PARALLEL_DO: case ST_OMP_ATOMIC: \
   case ST_OMP_WORKSHARE: case ST_OMP_PARALLEL_WORKSHARE: \
@@ -2376,6 +2404,15 @@ gfc_ascii_statement (gfc_statement st)
     case ST_OMP_END_LOOP:
       p = "!$OMP END LOOP";
       break;
+    case ST_OMP_END_MASKED:
+      p = "!$OMP END MASKED";
+      break;
+    case ST_OMP_END_MASKED_TASKLOOP:
+      p = "!$OMP END MASKED TASKLOOP";
+      break;
+    case ST_OMP_END_MASKED_TASKLOOP_SIMD:
+      p = "!$OMP END MASKED TASKLOOP SIMD";
+      break;
     case ST_OMP_END_MASTER:
       p = "!$OMP END MASTER";
       break;
@@ -2400,6 +2437,15 @@ gfc_ascii_statement (gfc_statement st)
     case ST_OMP_END_PARALLEL_LOOP:
       p = "!$OMP END PARALLEL LOOP";
       break;
+    case ST_OMP_END_PARALLEL_MASKED:
+      p = "!$OMP END PARALLEL MASKED";
+      break;
+    case ST_OMP_END_PARALLEL_MASKED_TASKLOOP:
+      p = "!$OMP END PARALLEL MASKED TASKLOOP";
+      break;
+    case ST_OMP_END_PARALLEL_MASKED_TASKLOOP_SIMD:
+      p = "!$OMP END PARALLEL MASKED TASKLOOP SIMD";
+      break;
     case ST_OMP_END_PARALLEL_MASTER:
       p = "!$OMP END PARALLEL MASTER";
       break;
@@ -2499,6 +2545,15 @@ gfc_ascii_statement (gfc_statement st)
     case ST_OMP_LOOP:
       p = "!$OMP LOOP";
       break;
+    case ST_OMP_MASKED:
+      p = "!$OMP MASKED";
+      break;
+    case ST_OMP_MASKED_TASKLOOP:
+      p = "!$OMP MASKED TASKLOOP";
+      break;
+    case ST_OMP_MASKED_TASKLOOP_SIMD:
+      p = "!$OMP MASKED TASKLOOP SIMD";
+      break;
     case ST_OMP_MASTER:
       p = "!$OMP MASTER";
       break;
@@ -2524,6 +2579,15 @@ gfc_ascii_statement (gfc_statement st)
     case ST_OMP_PARALLEL_DO_SIMD:
       p = "!$OMP PARALLEL DO SIMD";
       break;
+    case ST_OMP_PARALLEL_MASKED:
+      p = "!$OMP PARALLEL MASKED";
+      break;
+    case ST_OMP_PARALLEL_MASKED_TASKLOOP:
+      p = "!$OMP PARALLEL MASKED TASKLOOP";
+      break;
+    case ST_OMP_PARALLEL_MASKED_TASKLOOP_SIMD:
+      p = "!$OMP PARALLEL MASKED TASKLOOP SIMD";
+      break;
     case ST_OMP_PARALLEL_MASTER:
       p = "!$OMP PARALLEL MASTER";
       break;
@@ -5127,10 +5191,20 @@ parse_omp_do (gfc_statement omp_st)
       break;
     case ST_OMP_TASKLOOP: omp_end_st = ST_OMP_END_TASKLOOP; break;
     case ST_OMP_TASKLOOP_SIMD: omp_end_st = ST_OMP_END_TASKLOOP_SIMD; break;
+    case ST_OMP_MASKED_TASKLOOP: omp_end_st = ST_OMP_END_MASKED_TASKLOOP; break;
+    case ST_OMP_MASKED_TASKLOOP_SIMD:
+      omp_end_st = ST_OMP_END_MASKED_TASKLOOP_SIMD;
+      break;
     case ST_OMP_MASTER_TASKLOOP: omp_end_st = ST_OMP_END_MASTER_TASKLOOP; break;
     case ST_OMP_MASTER_TASKLOOP_SIMD:
       omp_end_st = ST_OMP_END_MASTER_TASKLOOP_SIMD;
       break;
+    case ST_OMP_PARALLEL_MASKED_TASKLOOP:
+      omp_end_st = ST_OMP_END_PARALLEL_MASKED_TASKLOOP;
+      break;
+    case ST_OMP_PARALLEL_MASKED_TASKLOOP_SIMD:
+      omp_end_st = ST_OMP_END_PARALLEL_MASKED_TASKLOOP_SIMD;
+      break;
     case ST_OMP_PARALLEL_MASTER_TASKLOOP:
       omp_end_st = ST_OMP_END_PARALLEL_MASTER_TASKLOOP;
       break;
@@ -5380,6 +5454,9 @@ parse_omp_structured_block (gfc_statement omp_st, bool workshare_stmts_only)
     case ST_OMP_PARALLEL:
       omp_end_st = ST_OMP_END_PARALLEL;
       break;
+    case ST_OMP_PARALLEL_MASKED:
+      omp_end_st = ST_OMP_END_PARALLEL_MASKED;
+      break;
     case ST_OMP_PARALLEL_MASTER:
       omp_end_st = ST_OMP_END_PARALLEL_MASTER;
       break;
@@ -5395,6 +5472,9 @@ parse_omp_structured_block (gfc_statement omp_st, bool workshare_stmts_only)
     case ST_OMP_CRITICAL:
       omp_end_st = ST_OMP_END_CRITICAL;
       break;
+    case ST_OMP_MASKED:
+      omp_end_st = ST_OMP_END_MASKED;
+      break;
     case ST_OMP_MASTER:
       omp_end_st = ST_OMP_END_MASTER;
       break;
@@ -5477,6 +5557,7 @@ parse_omp_structured_block (gfc_statement omp_st, bool workshare_stmts_only)
 		  break;
 
 		case ST_OMP_PARALLEL:
+		case ST_OMP_PARALLEL_MASKED:
 		case ST_OMP_PARALLEL_MASTER:
 		case ST_OMP_PARALLEL_SECTIONS:
 		  parse_omp_structured_block (st, false);
@@ -5679,11 +5760,13 @@ parse_executable (gfc_statement st)
 	  break;
 
 	case ST_OMP_PARALLEL:
+	case ST_OMP_PARALLEL_MASKED:
 	case ST_OMP_PARALLEL_MASTER:
 	case ST_OMP_PARALLEL_SECTIONS:
 	case ST_OMP_SECTIONS:
 	case ST_OMP_ORDERED:
 	case ST_OMP_CRITICAL:
+	case ST_OMP_MASKED:
 	case ST_OMP_MASTER:
 	case ST_OMP_SINGLE:
 	case ST_OMP_TARGET:
@@ -5711,8 +5794,12 @@ parse_executable (gfc_statement st)
 	case ST_OMP_PARALLEL_DO:
 	case ST_OMP_PARALLEL_DO_SIMD:
 	case ST_OMP_PARALLEL_LOOP:
+	case ST_OMP_PARALLEL_MASKED_TASKLOOP:
+	case ST_OMP_PARALLEL_MASKED_TASKLOOP_SIMD:
 	case ST_OMP_PARALLEL_MASTER_TASKLOOP:
 	case ST_OMP_PARALLEL_MASTER_TASKLOOP_SIMD:
+	case ST_OMP_MASKED_TASKLOOP:
+	case ST_OMP_MASKED_TASKLOOP_SIMD:
 	case ST_OMP_MASTER_TASKLOOP:
 	case ST_OMP_MASTER_TASKLOOP_SIMD:
 	case ST_OMP_SIMD:
diff --git a/gcc/fortran/resolve.c b/gcc/fortran/resolve.c
index 592364689f9..b0087be5068 100644
--- a/gcc/fortran/resolve.c
+++ b/gcc/fortran/resolve.c
@@ -10810,6 +10810,9 @@ gfc_resolve_blocks (gfc_code *b, gfc_namespace *ns)
 	case EXEC_OMP_DO:
 	case EXEC_OMP_DO_SIMD:
 	case EXEC_OMP_LOOP:
+	case EXEC_OMP_MASKED:
+	case EXEC_OMP_MASKED_TASKLOOP:
+	case EXEC_OMP_MASKED_TASKLOOP_SIMD:
 	case EXEC_OMP_MASTER:
 	case EXEC_OMP_MASTER_TASKLOOP:
 	case EXEC_OMP_MASTER_TASKLOOP_SIMD:
@@ -10818,6 +10821,9 @@ gfc_resolve_blocks (gfc_code *b, gfc_namespace *ns)
 	case EXEC_OMP_PARALLEL_DO:
 	case EXEC_OMP_PARALLEL_DO_SIMD:
 	case EXEC_OMP_PARALLEL_LOOP:
+	case EXEC_OMP_PARALLEL_MASKED:
+	case EXEC_OMP_PARALLEL_MASKED_TASKLOOP:
+	case EXEC_OMP_PARALLEL_MASKED_TASKLOOP_SIMD:
 	case EXEC_OMP_PARALLEL_MASTER:
 	case EXEC_OMP_PARALLEL_MASTER_TASKLOOP:
 	case EXEC_OMP_PARALLEL_MASTER_TASKLOOP_SIMD:
@@ -11785,6 +11791,9 @@ gfc_resolve_code (gfc_code *code, gfc_namespace *ns)
 	    case EXEC_OMP_PARALLEL:
 	    case EXEC_OMP_PARALLEL_DO:
 	    case EXEC_OMP_PARALLEL_DO_SIMD:
+	    case EXEC_OMP_PARALLEL_MASKED:
+	    case EXEC_OMP_PARALLEL_MASKED_TASKLOOP:
+	    case EXEC_OMP_PARALLEL_MASKED_TASKLOOP_SIMD:
 	    case EXEC_OMP_PARALLEL_MASTER:
 	    case EXEC_OMP_PARALLEL_MASTER_TASKLOOP:
 	    case EXEC_OMP_PARALLEL_MASTER_TASKLOOP_SIMD:
@@ -12240,6 +12249,9 @@ start:
 	case EXEC_OMP_MASTER:
 	case EXEC_OMP_MASTER_TASKLOOP:
 	case EXEC_OMP_MASTER_TASKLOOP_SIMD:
+	case EXEC_OMP_MASKED:
+	case EXEC_OMP_MASKED_TASKLOOP:
+	case EXEC_OMP_MASKED_TASKLOOP_SIMD:
 	case EXEC_OMP_ORDERED:
 	case EXEC_OMP_SCAN:
 	case EXEC_OMP_SECTIONS:
@@ -12281,6 +12293,9 @@ start:
 	case EXEC_OMP_PARALLEL_DO:
 	case EXEC_OMP_PARALLEL_DO_SIMD:
 	case EXEC_OMP_PARALLEL_LOOP:
+	case EXEC_OMP_PARALLEL_MASKED:
+	case EXEC_OMP_PARALLEL_MASKED_TASKLOOP:
+	case EXEC_OMP_PARALLEL_MASKED_TASKLOOP_SIMD:
 	case EXEC_OMP_PARALLEL_MASTER:
 	case EXEC_OMP_PARALLEL_MASTER_TASKLOOP:
 	case EXEC_OMP_PARALLEL_MASTER_TASKLOOP_SIMD:
diff --git a/gcc/fortran/st.c b/gcc/fortran/st.c
index 6ae1df612a7..f61f88adcc5 100644
--- a/gcc/fortran/st.c
+++ b/gcc/fortran/st.c
@@ -227,13 +227,19 @@ gfc_free_statement (gfc_code *p)
     case EXEC_OMP_DO_SIMD:
     case EXEC_OMP_LOOP:
     case EXEC_OMP_END_SINGLE:
+    case EXEC_OMP_MASKED_TASKLOOP:
+    case EXEC_OMP_MASKED_TASKLOOP_SIMD:
     case EXEC_OMP_MASTER_TASKLOOP:
     case EXEC_OMP_MASTER_TASKLOOP_SIMD:
     case EXEC_OMP_ORDERED:
+    case EXEC_OMP_MASKED:
     case EXEC_OMP_PARALLEL:
     case EXEC_OMP_PARALLEL_DO:
     case EXEC_OMP_PARALLEL_DO_SIMD:
     case EXEC_OMP_PARALLEL_LOOP:
+    case EXEC_OMP_PARALLEL_MASKED:
+    case EXEC_OMP_PARALLEL_MASKED_TASKLOOP:
+    case EXEC_OMP_PARALLEL_MASKED_TASKLOOP_SIMD:
     case EXEC_OMP_PARALLEL_MASTER:
     case EXEC_OMP_PARALLEL_MASTER_TASKLOOP:
     case EXEC_OMP_PARALLEL_MASTER_TASKLOOP_SIMD:
diff --git a/gcc/fortran/trans-openmp.c b/gcc/fortran/trans-openmp.c
index 3d3b35e9509..623c21fc790 100644
--- a/gcc/fortran/trans-openmp.c
+++ b/gcc/fortran/trans-openmp.c
@@ -4047,6 +4047,21 @@ gfc_trans_omp_clauses (stmtblock_t *block, gfc_omp_clauses *clauses,
       omp_clauses = gfc_trans_add_clause (c, omp_clauses);
     }
 
+  if (clauses->filter)
+    {
+      tree filter;
+
+      gfc_init_se (&se, NULL);
+      gfc_conv_expr (&se, clauses->filter);
+      gfc_add_block_to_block (block, &se.pre);
+      filter = gfc_evaluate_now (se.expr, block);
+      gfc_add_block_to_block (block, &se.post);
+
+      c = build_omp_clause (gfc_get_location (&where), OMP_CLAUSE_FILTER);
+      OMP_CLAUSE_FILTER_EXPR (c) = filter;
+      omp_clauses = gfc_trans_add_clause (c, omp_clauses);
+    }
+
   if (clauses->hint)
     {
       tree hint;
@@ -5389,6 +5404,26 @@ gfc_trans_omp_master (gfc_code *code)
   return build1_v (OMP_MASTER, stmt);
 }
 
+static tree
+gfc_trans_omp_masked (gfc_code *code, gfc_omp_clauses *clauses)
+{
+  stmtblock_t block;
+  tree body = gfc_trans_code (code->block->next);
+  if (IS_EMPTY_STMT (body))
+    return body;
+  if (!clauses)
+    clauses = code->ext.omp_clauses;
+  gfc_start_block (&block);
+  tree omp_clauses = gfc_trans_omp_clauses (&block, clauses, code->loc);
+  tree stmt = make_node (OMP_MASKED);
+  TREE_TYPE (stmt) = void_type_node;
+  OMP_MASKED_BODY (stmt) = body;
+  OMP_MASKED_CLAUSES (stmt) = omp_clauses;
+  gfc_add_expr_to_block (&block, stmt);
+  return gfc_finish_block (&block);
+}
+
+
 static tree
 gfc_trans_omp_ordered (gfc_code *code)
 {
@@ -5432,6 +5467,7 @@ enum
   GFC_OMP_SPLIT_TEAMS,
   GFC_OMP_SPLIT_TARGET,
   GFC_OMP_SPLIT_TASKLOOP,
+  GFC_OMP_SPLIT_MASKED,
   GFC_OMP_SPLIT_NUM
 };
 
@@ -5443,7 +5479,8 @@ enum
   GFC_OMP_MASK_DISTRIBUTE = (1 << GFC_OMP_SPLIT_DISTRIBUTE),
   GFC_OMP_MASK_TEAMS = (1 << GFC_OMP_SPLIT_TEAMS),
   GFC_OMP_MASK_TARGET = (1 << GFC_OMP_SPLIT_TARGET),
-  GFC_OMP_MASK_TASKLOOP = (1 << GFC_OMP_SPLIT_TASKLOOP)
+  GFC_OMP_MASK_TASKLOOP = (1 << GFC_OMP_SPLIT_TASKLOOP),
+  GFC_OMP_MASK_MASKED = (1 << GFC_OMP_SPLIT_MASKED)
 };
 
 /* If a var is in lastprivate/firstprivate/reduction but not in a
@@ -5632,10 +5669,24 @@ gfc_split_omp_clauses (gfc_code *code,
       mask = GFC_OMP_MASK_PARALLEL | GFC_OMP_MASK_DO | GFC_OMP_MASK_SIMD;
       innermost = GFC_OMP_SPLIT_SIMD;
       break;
+    case EXEC_OMP_PARALLEL_MASKED:
+      mask = GFC_OMP_MASK_PARALLEL | GFC_OMP_MASK_MASKED;
+      innermost = GFC_OMP_SPLIT_MASKED;
+      break;
+    case EXEC_OMP_PARALLEL_MASKED_TASKLOOP:
+      mask = (GFC_OMP_MASK_PARALLEL | GFC_OMP_MASK_MASKED
+	      | GFC_OMP_MASK_TASKLOOP | GFC_OMP_MASK_SIMD);
+      innermost = GFC_OMP_SPLIT_TASKLOOP;
+      break;
     case EXEC_OMP_PARALLEL_MASTER_TASKLOOP:
       mask = GFC_OMP_MASK_PARALLEL | GFC_OMP_MASK_TASKLOOP | GFC_OMP_MASK_SIMD;
       innermost = GFC_OMP_SPLIT_TASKLOOP;
       break;
+    case EXEC_OMP_PARALLEL_MASKED_TASKLOOP_SIMD:
+      mask = (GFC_OMP_MASK_PARALLEL | GFC_OMP_MASK_MASKED
+	      | GFC_OMP_MASK_TASKLOOP | GFC_OMP_MASK_SIMD);
+      innermost = GFC_OMP_SPLIT_SIMD;
+      break;
     case EXEC_OMP_PARALLEL_MASTER_TASKLOOP_SIMD:
       mask = GFC_OMP_MASK_PARALLEL | GFC_OMP_MASK_TASKLOOP | GFC_OMP_MASK_SIMD;
       innermost = GFC_OMP_SPLIT_SIMD;
@@ -5692,10 +5743,18 @@ gfc_split_omp_clauses (gfc_code *code,
       mask = GFC_OMP_MASK_TARGET | GFC_OMP_MASK_TEAMS | GFC_OMP_MASK_DO;
       innermost = GFC_OMP_SPLIT_DO;
       break;
+    case EXEC_OMP_MASKED_TASKLOOP:
+      mask = GFC_OMP_SPLIT_MASKED | GFC_OMP_SPLIT_TASKLOOP;
+      innermost = GFC_OMP_SPLIT_TASKLOOP;
+      break;
     case EXEC_OMP_MASTER_TASKLOOP:
     case EXEC_OMP_TASKLOOP:
       innermost = GFC_OMP_SPLIT_TASKLOOP;
       break;
+    case EXEC_OMP_MASKED_TASKLOOP_SIMD:
+      mask = GFC_OMP_MASK_MASKED | GFC_OMP_MASK_TASKLOOP | GFC_OMP_MASK_SIMD;
+      innermost = GFC_OMP_SPLIT_SIMD;
+      break;
     case EXEC_OMP_MASTER_TASKLOOP_SIMD:
     case EXEC_OMP_TASKLOOP_SIMD:
       mask = GFC_OMP_MASK_TASKLOOP | GFC_OMP_MASK_SIMD;
@@ -5814,6 +5873,8 @@ gfc_split_omp_clauses (gfc_code *code,
 	  clausesa[GFC_OMP_SPLIT_PARALLEL].if_expr
 	    = code->ext.omp_clauses->if_expr;
 	}
+      if (mask & GFC_OMP_MASK_MASKED)
+	clausesa[GFC_OMP_SPLIT_MASKED].filter = code->ext.omp_clauses->filter;
       if ((mask & GFC_OMP_MASK_DO) && !is_loop)
 	{
 	  /* First the clauses that are unique to some constructs.  */
@@ -5896,16 +5957,18 @@ gfc_split_omp_clauses (gfc_code *code,
 	  clausesa[GFC_OMP_SPLIT_TASKLOOP].collapse
 	    = code->ext.omp_clauses->collapse;
 	}
-      /* Private clause is supported on all constructs,
-	 it is enough to put it on the innermost one.  For
+      /* Private clause is supported on all constructs but master/masked,
+	 it is enough to put it on the innermost one except for master/masked.  For
 	 !$ omp parallel do put it on parallel though,
 	 as that's what we did for OpenMP 3.1.  */
-      clausesa[innermost == GFC_OMP_SPLIT_DO && !is_loop
+      clausesa[((innermost == GFC_OMP_SPLIT_DO && !is_loop)
+		|| code->op == EXEC_OMP_PARALLEL_MASTER
+		|| code->op == EXEC_OMP_PARALLEL_MASKED)
 	       ? (int) GFC_OMP_SPLIT_PARALLEL
 	       : innermost].lists[OMP_LIST_PRIVATE]
 	= code->ext.omp_clauses->lists[OMP_LIST_PRIVATE];
       /* Firstprivate clause is supported on all constructs but
-	 simd.  Put it on the outermost of those and duplicate
+	 simd and masked/master.  Put it on the outermost of those and duplicate
 	 on parallel and teams.  */
       if (mask & GFC_OMP_MASK_TARGET)
 	clausesa[GFC_OMP_SPLIT_TARGET].lists[OMP_LIST_FIRSTPRIVATE]
@@ -6588,43 +6651,66 @@ gfc_trans_omp_taskloop (gfc_code *code, gfc_exec_op op)
 }
 
 static tree
-gfc_trans_omp_master_taskloop (gfc_code *code, gfc_exec_op op)
+gfc_trans_omp_master_masked_taskloop (gfc_code *code, gfc_exec_op op)
 {
+  gfc_omp_clauses clausesa[GFC_OMP_SPLIT_NUM];
   stmtblock_t block;
   tree stmt;
 
-  gfc_start_block (&block);
+  if (op != EXEC_OMP_MASTER_TASKLOOP_SIMD
+      && code->op != EXEC_OMP_MASTER_TASKLOOP)
+    gfc_split_omp_clauses (code, clausesa);
+
   pushlevel ();
-  if (op == EXEC_OMP_MASTER_TASKLOOP_SIMD)
+  if (op == EXEC_OMP_MASKED_TASKLOOP_SIMD
+      || op == EXEC_OMP_MASTER_TASKLOOP_SIMD)
     stmt = gfc_trans_omp_taskloop (code, EXEC_OMP_TASKLOOP_SIMD);
   else
     {
-      gfc_omp_clauses clausesa[GFC_OMP_SPLIT_NUM];
-      gcc_assert (op == EXEC_OMP_MASTER_TASKLOOP);
-      if (op != code->op)
-	gfc_split_omp_clauses (code, clausesa);
+      gcc_assert (op == EXEC_OMP_MASKED_TASKLOOP
+		  || op == EXEC_OMP_MASTER_TASKLOOP);
       stmt = gfc_trans_omp_do (code, EXEC_OMP_TASKLOOP, NULL,
-			       op != code->op
+			       code->op != EXEC_OMP_MASTER_TASKLOOP
 			       ? &clausesa[GFC_OMP_SPLIT_TASKLOOP]
 			       : code->ext.omp_clauses, NULL);
-      if (op != code->op)
-	gfc_free_split_omp_clauses (code, clausesa);
     }
   if (TREE_CODE (stmt) != BIND_EXPR)
     stmt = build3_v (BIND_EXPR, NULL, stmt, poplevel (1, 0));
   else
     poplevel (0, 0);
-  stmt = build1_v (OMP_MASTER, stmt);
-  gfc_add_expr_to_block (&block, stmt);
+  gfc_start_block (&block);
+  if (op == EXEC_OMP_MASKED_TASKLOOP || op == EXEC_OMP_MASKED_TASKLOOP_SIMD)
+    {
+      tree clauses = gfc_trans_omp_clauses (&block,
+					    &clausesa[GFC_OMP_SPLIT_MASKED],
+					    code->loc);
+      tree msk = make_node (OMP_MASKED);
+      TREE_TYPE (msk) = void_type_node;
+      OMP_MASKED_BODY (msk) = stmt;
+      OMP_MASKED_CLAUSES (msk) = clauses;
+      OMP_MASKED_COMBINED (msk) = 1;
+      gfc_add_expr_to_block (&block, msk);
+    }
+  else
+    {
+      gcc_assert (op == EXEC_OMP_MASTER_TASKLOOP
+		  || op == EXEC_OMP_MASTER_TASKLOOP_SIMD);
+      stmt = build1_v (OMP_MASTER, stmt);
+      gfc_add_expr_to_block (&block, stmt);
+    }
+  if (op != EXEC_OMP_MASTER_TASKLOOP_SIMD
+      && code->op != EXEC_OMP_MASTER_TASKLOOP)
+    gfc_free_split_omp_clauses (code, clausesa);
   return gfc_finish_block (&block);
 }
 
 static tree
-gfc_trans_omp_parallel_master (gfc_code *code)
+gfc_trans_omp_parallel_master_masked (gfc_code *code)
 {
   stmtblock_t block;
   tree stmt, omp_clauses;
   gfc_omp_clauses clausesa[GFC_OMP_SPLIT_NUM];
+  bool parallel_combined = false;
 
   if (code->op != EXEC_OMP_PARALLEL_MASTER)
     gfc_split_omp_clauses (code, clausesa);
@@ -6635,19 +6721,33 @@ gfc_trans_omp_parallel_master (gfc_code *code)
 				       ? code->ext.omp_clauses
 				       : &clausesa[GFC_OMP_SPLIT_PARALLEL],
 				       code->loc);
-  if (code->op != EXEC_OMP_PARALLEL_MASTER)
-    gfc_free_split_omp_clauses (code, clausesa);
   pushlevel ();
   if (code->op == EXEC_OMP_PARALLEL_MASTER)
     stmt = gfc_trans_omp_master (code);
+  else if (code->op == EXEC_OMP_PARALLEL_MASKED)
+    stmt = gfc_trans_omp_masked (code, &clausesa[GFC_OMP_SPLIT_MASKED]);
   else
     {
-      gcc_assert (code->op == EXEC_OMP_PARALLEL_MASTER_TASKLOOP
-		  || code->op == EXEC_OMP_PARALLEL_MASTER_TASKLOOP_SIMD);
-      gfc_exec_op op = (code->op == EXEC_OMP_PARALLEL_MASTER_TASKLOOP
-			? EXEC_OMP_MASTER_TASKLOOP
-			: EXEC_OMP_MASTER_TASKLOOP_SIMD);
-      stmt = gfc_trans_omp_master_taskloop (code, op);
+      gfc_exec_op op;
+      switch (code->op)
+	{
+	case EXEC_OMP_PARALLEL_MASKED_TASKLOOP:
+	  op = EXEC_OMP_MASKED_TASKLOOP;
+	  break;
+	case EXEC_OMP_PARALLEL_MASKED_TASKLOOP_SIMD:
+	  op = EXEC_OMP_MASKED_TASKLOOP_SIMD;
+	  break;
+	case EXEC_OMP_PARALLEL_MASTER_TASKLOOP:
+	  op = EXEC_OMP_MASTER_TASKLOOP;
+	  break;
+	case EXEC_OMP_PARALLEL_MASTER_TASKLOOP_SIMD:
+	  op = EXEC_OMP_MASTER_TASKLOOP_SIMD;
+	  break;
+	default:
+	  gcc_unreachable ();
+	}
+      stmt = gfc_trans_omp_master_masked_taskloop (code, op);
+      parallel_combined = true;
     }
   if (TREE_CODE (stmt) != BIND_EXPR)
     stmt = build3_v (BIND_EXPR, NULL, stmt, poplevel (1, 0));
@@ -6655,8 +6755,19 @@ gfc_trans_omp_parallel_master (gfc_code *code)
     poplevel (0, 0);
   stmt = build2_loc (gfc_get_location (&code->loc), OMP_PARALLEL,
 		     void_type_node, stmt, omp_clauses);
-  OMP_PARALLEL_COMBINED (stmt) = 1;
+  /* masked does have just filter clause, but during gimplification
+     isn't represented by a gimplification omp context, so for
+       !$omp parallel masked don't set OMP_PARALLEL_COMBINED,
+     so that
+       !$omp parallel masked
+       !$omp taskloop simd lastprivate (x)
+     isn't confused with
+       !$omp parallel masked taskloop simd lastprivate (x)  */
+  if (parallel_combined)
+    OMP_PARALLEL_COMBINED (stmt) = 1;
   gfc_add_expr_to_block (&block, stmt);
+  if (code->op != EXEC_OMP_PARALLEL_MASTER)
+    gfc_free_split_omp_clauses (code, clausesa);
   return gfc_finish_block (&block);
 }
 
@@ -6969,11 +7080,15 @@ gfc_trans_omp_directive (gfc_code *code)
       return gfc_trans_omp_do_simd (code, NULL, NULL, NULL_TREE);
     case EXEC_OMP_FLUSH:
       return gfc_trans_omp_flush (code);
+    case EXEC_OMP_MASKED:
+      return gfc_trans_omp_masked (code, NULL);
     case EXEC_OMP_MASTER:
       return gfc_trans_omp_master (code);
+    case EXEC_OMP_MASKED_TASKLOOP:
+    case EXEC_OMP_MASKED_TASKLOOP_SIMD:
     case EXEC_OMP_MASTER_TASKLOOP:
     case EXEC_OMP_MASTER_TASKLOOP_SIMD:
-      return gfc_trans_omp_master_taskloop (code, code->op);
+      return gfc_trans_omp_master_masked_taskloop (code, code->op);
     case EXEC_OMP_ORDERED:
       return gfc_trans_omp_ordered (code);
     case EXEC_OMP_PARALLEL:
@@ -6984,10 +7099,13 @@ gfc_trans_omp_directive (gfc_code *code)
       return gfc_trans_omp_parallel_do (code, true, NULL, NULL);
     case EXEC_OMP_PARALLEL_DO_SIMD:
       return gfc_trans_omp_parallel_do_simd (code, NULL, NULL);
+    case EXEC_OMP_PARALLEL_MASKED:
+    case EXEC_OMP_PARALLEL_MASKED_TASKLOOP:
+    case EXEC_OMP_PARALLEL_MASKED_TASKLOOP_SIMD:
     case EXEC_OMP_PARALLEL_MASTER:
     case EXEC_OMP_PARALLEL_MASTER_TASKLOOP:
     case EXEC_OMP_PARALLEL_MASTER_TASKLOOP_SIMD:
-      return gfc_trans_omp_parallel_master (code);
+      return gfc_trans_omp_parallel_master_masked (code);
     case EXEC_OMP_PARALLEL_SECTIONS:
       return gfc_trans_omp_parallel_sections (code);
     case EXEC_OMP_PARALLEL_WORKSHARE:
diff --git a/gcc/fortran/trans.c b/gcc/fortran/trans.c
index 275d6a28f1c..ce5b2f8d594 100644
--- a/gcc/fortran/trans.c
+++ b/gcc/fortran/trans.c
@@ -2156,6 +2156,9 @@ trans_code (gfc_code * code, tree cond)
 	case EXEC_OMP_DO_SIMD:
 	case EXEC_OMP_LOOP:
 	case EXEC_OMP_FLUSH:
+	case EXEC_OMP_MASKED:
+	case EXEC_OMP_MASKED_TASKLOOP:
+	case EXEC_OMP_MASKED_TASKLOOP_SIMD:
 	case EXEC_OMP_MASTER:
 	case EXEC_OMP_MASTER_TASKLOOP:
 	case EXEC_OMP_MASTER_TASKLOOP_SIMD:
@@ -2164,6 +2167,9 @@ trans_code (gfc_code * code, tree cond)
 	case EXEC_OMP_PARALLEL_DO:
 	case EXEC_OMP_PARALLEL_DO_SIMD:
 	case EXEC_OMP_PARALLEL_LOOP:
+	case EXEC_OMP_PARALLEL_MASKED:
+	case EXEC_OMP_PARALLEL_MASKED_TASKLOOP:
+	case EXEC_OMP_PARALLEL_MASKED_TASKLOOP_SIMD:
 	case EXEC_OMP_PARALLEL_MASTER:
 	case EXEC_OMP_PARALLEL_MASTER_TASKLOOP:
 	case EXEC_OMP_PARALLEL_MASTER_TASKLOOP_SIMD:
diff --git a/gcc/testsuite/gfortran.dg/gomp/masked-1.f90 b/gcc/testsuite/gfortran.dg/gomp/masked-1.f90
new file mode 100644
index 00000000000..1bd61760ced
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/gomp/masked-1.f90
@@ -0,0 +1,94 @@
+! { dg-additional-options "-ffree-line-length-none" }
+subroutine foo (x, a)
+  implicit none
+  integer, value :: x
+  integer, contiguous :: a(0:)
+  external :: bar
+  integer :: i
+
+  !$omp masked
+   call bar ()
+  !$omp end masked
+
+  !$omp masked filter (0)
+   call bar ()
+  !$omp end masked
+
+  !$omp masked filter (7)
+   call bar ()
+  !$omp end masked
+
+  !$omp masked filter (x)
+   call bar ()
+  !$omp end masked
+
+  !$omp masked taskloop simd filter (x) grainsize (12) simdlen (4)
+    do i = 0, 127
+      a(i) = i
+    end do
+  !$omp end masked taskloop simd
+
+  !$omp parallel masked filter (x) firstprivate (x)
+    call bar ()
+  !$omp end parallel masked
+
+  !$omp masked
+    !$omp masked filter (0)
+      !$omp masked filter (x)
+      !$omp end masked
+    !$omp end masked
+  !$omp end masked
+end
+
+subroutine foobar (d, f, fi, p, s, g, i1, i2, l, ll, nth, ntm, pp, q, r, r2)
+  implicit none (type, external)
+  logical :: i1, i2, fi
+  integer :: i, d, f, p, s, g, l, ll, nth, ntm, pp, q, r, r2
+  allocatable :: q
+  integer, save :: t
+  !$omp threadprivate (t)
+
+  !$omp parallel masked &
+  !$omp&  private (p) firstprivate (f) if (parallel: i2) default(shared) shared(s) reduction(+:r) &
+  !$omp&  num_threads (nth) proc_bind(spread) copyin(t) filter (d)  ! allocate (f)
+    !
+  !$omp end parallel masked
+
+  !$omp taskgroup task_reduction (+:r2)  ! allocate (r2)
+    !$omp masked taskloop &
+    !$omp&  private (p) firstprivate (f) lastprivate (l) shared (s) default(shared) grainsize (g) collapse(1) untied if(taskloop: i1) final(fi) mergeable priority (pp) &
+    !$omp&  reduction(default, +:r) in_reduction(+:r2) filter (d)  ! allocate (f)
+    do i = 0, 63
+      ll = ll + 1
+    end do
+    !$omp end masked taskloop
+  !$omp end taskgroup
+
+  !$omp taskgroup task_reduction (+:r2)  ! allocate (r2)
+    !$omp masked taskloop simd &
+    !$omp&  private (p) firstprivate (f) lastprivate (l) shared (s) default(shared) grainsize (g) collapse(1) untied if(taskloop: i1) if(simd: i2) final(fi) mergeable priority (pp) &
+    !$omp&  safelen(8) simdlen(4) linear(ll: 1) aligned(q: 32) reduction(default, +:r) in_reduction(+:r2) nontemporal(ntm) &
+    !$omp&  order(concurrent) filter (d)  !  allocate (f)
+    do i = 0, 63
+      ll = ll + 1
+    end do
+    !$omp end masked taskloop simd
+  !$omp end taskgroup
+
+  !$omp parallel masked taskloop &
+    !$omp&  private (p) firstprivate (f) lastprivate (l) shared (s) default(shared) grainsize (g) collapse(1) untied if(taskloop: i1) final(fi) mergeable priority (pp) &
+    !$omp&  reduction(default, +:r) if (parallel: i2) num_threads (nth) proc_bind(spread) copyin(t) filter (d)  ! allocate (f)
+    do i = 0, 63
+      ll = ll + 1
+    end do
+  !$omp end parallel masked taskloop
+
+  !$omp parallel masked taskloop simd &
+    !$omp&  private (p) firstprivate (f) lastprivate (l) shared (s) default(shared) grainsize (g) collapse(1) untied if(taskloop: i1) if(simd: i2) final(fi) mergeable priority (pp) &
+    !$omp&  safelen(8) simdlen(4) linear(ll: 1) aligned(q: 32) reduction(default, +:r) nontemporal(ntm) if (parallel: i2) num_threads (nth) proc_bind(spread) copyin(t) &
+    !$omp&  order(concurrent) filter (d)  ! allocate (f)
+    do i = 0, 63
+      ll = ll + 1
+    end do
+  !$omp end parallel masked taskloop simd
+end subroutine
diff --git a/gcc/testsuite/gfortran.dg/gomp/masked-2.f90 b/gcc/testsuite/gfortran.dg/gomp/masked-2.f90
new file mode 100644
index 00000000000..95ef78c0664
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/gomp/masked-2.f90
@@ -0,0 +1,46 @@
+module m
+  implicit none (external, type)
+  type t
+  end type t
+contains
+subroutine foo (x, y, z, a)
+  external :: bar
+  type(t) :: x
+  integer :: y
+  real :: z
+  integer :: a(4)
+
+  !$omp masked filter (x)  ! { dg-error "FILTER clause at .1. requires a scalar INTEGER expression" }
+    call bar ()
+  !$omp end masked
+
+  !$omp masked filter (y)  ! OK
+    call bar ()
+  !$omp end masked
+
+  !$omp masked filter (z)  ! { dg-error "FILTER clause at .1. requires a scalar INTEGER expression" }
+    call bar ()
+  !$omp end masked
+
+  !$omp masked filter (a)  ! { dg-error "FILTER clause at .1. requires a scalar INTEGER expression" }
+    call bar ()
+  !$omp end masked
+
+  !$omp masked filter (0.0)  ! { dg-error "FILTER clause at .1. requires a scalar INTEGER expression" }
+    call bar ()
+  !$omp end masked
+
+  !$omp masked filter ([1])  ! { dg-error "FILTER clause at .1. requires a scalar INTEGER expression" }
+    call bar ()
+  !$omp end masked
+
+  !$omp masked filter (-1)  ! { dg-warning "INTEGER expression of FILTER clause at .1. must be non-negative" }
+    call bar ()
+  !$omp end masked
+end
+end module
+
+subroutine bar
+  !$omp masked filter (0) filter (0)  ! { dg-error "27: Failed to match clause" }
+    call foobar
+end
diff --git a/gcc/testsuite/gfortran.dg/gomp/masked-3.f90 b/gcc/testsuite/gfortran.dg/gomp/masked-3.f90
new file mode 100644
index 00000000000..49c633d21a5
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/gomp/masked-3.f90
@@ -0,0 +1,12 @@
+subroutine foo
+
+  !$omp masked
+     goto 55  ! { dg-error "invalid branch to/from OpenMP structured block" }
+              ! { dg-warning "Legacy Extension: Label at .1. is not in the same block as the GOTO statement" "" { target *-*-* } .-1 }
+  !$omp end masked
+
+  !$omp masked
+55  continue  ! { dg-warning "Legacy Extension: Label at .1. is not in the same block as the GOTO statement" }
+    return    ! { dg-error "invalid branch to/from OpenMP structured block" }
+  !$omp end masked
+end subroutine foo
diff --git a/gcc/testsuite/gfortran.dg/gomp/masked-combined-1.f90 b/gcc/testsuite/gfortran.dg/gomp/masked-combined-1.f90
new file mode 100644
index 00000000000..23ffb084ee1
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/gomp/masked-combined-1.f90
@@ -0,0 +1,65 @@
+subroutine foo (a, f)
+  implicit none (type, external)
+  interface
+    subroutine bar (x)
+      integer :: x
+    end subroutine
+  end interface
+
+  integer, value :: f
+  integer, contiguous :: a(0:)
+  integer :: i, j, k, u, v, w, x, y, z
+
+  !$omp parallel masked default(none) private (k) filter (f) firstprivate (f)
+    call bar (k)
+  !$omp end parallel masked
+
+  !$omp parallel masked default(none) private (k)
+    call bar (k)
+  !$omp end parallel masked
+  
+  !$omp parallel default(none) firstprivate(a, f) shared(x, y, z)
+    !$omp masked taskloop reduction (+:x) default(none) firstprivate(a) filter (f)
+      do i = 0, 63
+        x = x + a(i)
+      end do
+    !$omp end masked taskloop
+    !$omp masked taskloop simd reduction (+:y) default(none) firstprivate(a) private (i) filter (f)
+      do i = 0, 63
+        y = y + a(i)
+      end do
+    !$omp end masked taskloop simd
+    !$omp masked taskloop simd reduction (+:y) default(none) firstprivate(a) private (i)
+      do i = 0, 63
+        y = y + a(i)
+      end do
+    !$omp end masked taskloop simd
+    !$omp masked taskloop simd collapse(2) reduction (+:z) default(none) firstprivate(a) private (i, j) filter (f)
+      do j = 0, 0
+        do i = 0, 63
+          z = z + a(i)
+        end do
+      end do
+    !$omp end masked taskloop simd
+  !$omp end parallel
+
+  !$omp parallel masked taskloop reduction (+:u) default(none) firstprivate(a, f) filter (f)
+    do i = 0, 63
+      u = u + a(i)
+    end do
+  !$omp end parallel masked taskloop
+
+  !$omp parallel masked taskloop simd reduction (+:v) default(none) firstprivate(a, f) filter (f)
+    do i = 0, 63
+      v = v + a(i)
+    end do
+  !$omp end parallel masked taskloop simd
+
+  !$omp parallel masked taskloop simd collapse(2) reduction (+:w) default(none) firstprivate(a, f) filter (f)
+    do j = 0, 0
+      do i = 0, 63
+        w = w + a(i)
+      end do
+    end do
+  !$omp end parallel masked taskloop simd
+end
diff --git a/gcc/testsuite/gfortran.dg/gomp/masked-combined-2.f90 b/gcc/testsuite/gfortran.dg/gomp/masked-combined-2.f90
new file mode 100644
index 00000000000..c94425fd0bd
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/gomp/masked-combined-2.f90
@@ -0,0 +1,24 @@
+subroutine foo (a)
+  implicit none (external, type)
+  integer, contiguous :: a(0:)
+  integer :: i, r, s
+  r = 0; s = 0
+
+  ! In 'parallel masked taskloop', in_reduction is not permitted.
+
+  !$omp taskgroup task_reduction(+:r)
+    !$omp parallel masked taskloop in_reduction(+:r)  ! { dg-error "36: Failed to match clause" }
+      do i = 0, 63
+        r = r + a(i)
+      end do
+    !!$omp end parallel masked taskloop
+  !$omp end taskgroup
+
+  !$omp taskgroup task_reduction(+:s)
+    !$omp parallel masked taskloop simd in_reduction(+:s)  ! { dg-error "41: Failed to match clause" }
+      do i = 0, 63
+        s = s + a(i)
+      end do
+    !!$omp end parallel masked taskloop simd
+  !$omp end taskgroup
+end
diff --git a/libgomp/testsuite/libgomp.fortran/masked-1.f90 b/libgomp/testsuite/libgomp.fortran/masked-1.f90
new file mode 100644
index 00000000000..3ecd1aa48dc
--- /dev/null
+++ b/libgomp/testsuite/libgomp.fortran/masked-1.f90
@@ -0,0 +1,141 @@
+module m
+  use omp_lib
+  implicit none (type, external)
+contains
+  subroutine foo (x, a)
+    integer, value :: x
+    integer, contiguous :: a(0:)
+    integer :: i
+
+    !$omp masked
+      if (omp_get_thread_num () /= 0) &
+        stop 1
+      a(128) = a(128) + 1
+    !$omp end masked
+
+    !$omp masked filter (0)
+      if (omp_get_thread_num () /= 0) &
+        stop 2
+      a(129) = a(129) + 1
+    !$omp end masked
+
+    !$omp masked filter (7)
+      if (omp_get_thread_num () /= 7) &
+        stop 3
+      a(130) = a(130) + 1
+    !$omp end masked
+
+    !$omp masked filter (x)
+      if (omp_get_thread_num () /= x) &
+        stop 4
+      a(131) = a(131) + 1
+    !$omp end masked
+
+    !$omp masked taskloop !simd filter (x) grainsize (12) simdlen (4)
+      do i = 0, 127
+        a(i) = a(i) + i
+      end do
+    !$omp end masked taskloop !simd
+  end
+end
+
+program main
+  use m
+  implicit none (type, external)
+  integer :: i
+  integer :: a(0:135)
+
+  a = 0
+
+  !$omp parallel num_threads (4)
+    call foo (4, a)
+  !$omp end parallel
+  do i = 0, 127
+    if (a(i) /= 0) &
+      stop 5
+  end do
+  if (a(128) /= 1 .or. a(129) /= 1 .or. a(130) /= 0 .or. a(131) /= 0) &
+    stop 6
+
+  !$omp parallel num_threads (4)
+    call foo (3, a)
+  !$omp end parallel
+  do i = 0, 127
+    ! FIXME vvvvvvvvvvvv
+    if (a(i) /= i) then
+      print *, "WRONG RESULT (7) -> PR 101899"
+      ! fix result:
+      block
+        integer :: j
+        a(0:127) = [(j, j = 0, 127)]
+      end block
+      exit
+    end if
+    ! FIXME ^^^^^^
+    if (a(i) /= i) &
+      stop 7
+  end do
+  if (a(128) /= 2 .or. a(129) /= 2 .or. a(130) /= 0 .or. a(131) /= 1) &
+    stop 8
+
+  !$omp parallel num_threads (8)
+    call foo (8, a)
+  !$omp end parallel
+  do i = 0, 127
+    if (a(i) /= i) &
+      stop 9
+  end do
+  if (a(128) /= 3 .or. a(129) /= 3 .or. a(130) /= 1 .or. a(131) /= 1) &
+    stop 10
+
+  !$omp parallel num_threads (8)
+    call foo (6, a)
+  !$omp end parallel
+  do i = 0, 127
+    ! FIXME vvvvvvvvvvvv
+    if (a(i) /= 2*i) then
+      print *, "WRONG RESULT (11) -> PR 101899"
+      ! fix result:
+      block
+        integer :: j
+        a(0:127) = [(2*j, j = 0, 127)]
+      end block
+      exit
+    end if
+    ! FIXME ^^^^^^
+    if (a(i) /= 2 * i) &
+      stop 11
+  end do
+  if (a(128) /= 4 .or. a(129) /= 4 .or. a(130) /= 2 .or. a(131) /= 2) &
+    stop 12
+
+  do i = 0, 7
+    a(i) = 0
+  end do
+  ! The filter expression can evaluate to different values in different threads.
+  !$omp parallel masked num_threads (8) filter (omp_get_thread_num () + 1)
+    a(omp_get_thread_num ()) = a(omp_get_thread_num ()) + 1
+  !$omp end parallel masked
+  do i = 0, 7
+    if (a(i) /= 0) &
+      stop 13
+  end do
+
+  ! And multiple threads can be filtered.
+  !$omp parallel masked num_threads (8) filter (iand (omp_get_thread_num (), not(1)))
+    a(omp_get_thread_num ()) = a(omp_get_thread_num ()) + 1
+  !$omp end parallel masked
+  do i = 0, 7
+    block
+      integer :: j
+      j = iand (i, 1)
+      if (j /= 0) then
+        j = 0
+      else
+        j = 1
+      end if
+      if (a(i) /= j) &
+        stop 14
+    end block
+  end do
+end program main

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

* Re: [Patch] Fortran/OpenMP: Add support for OpenMP 5.1 masked construct (was: Re: [committed] openmp: Add support for OpenMP 5.1 masked construct)
  2021-08-13 14:37 ` [Patch] Fortran/OpenMP: Add support for OpenMP 5.1 masked construct (was: Re: [committed] openmp: Add support for OpenMP 5.1 masked construct) Tobias Burnus
@ 2021-08-13 18:52   ` Tobias Burnus
  2021-08-16  7:17     ` Jakub Jelinek
  0 siblings, 1 reply; 5+ messages in thread
From: Tobias Burnus @ 2021-08-13 18:52 UTC (permalink / raw)
  To: Jakub Jelinek, gcc-patches, fortran

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

On 13.08.21 16:37, Tobias Burnus wrote:

> When converting the C/C++ runtime testcase to Fortran, I did run into
> a bug:
> https://gcc.gnu.org/PR101899 (see PR or testcase; related to 'omp
> taskloop'.)
I am any more sure whether it is a bug or not or what is the bug (see
PR) – however, for this patch it is sufficient to add a 'shared(a)':
> +    !$omp masked taskloop simd filter (x) grainsize (12) simdlen (4)
Corrected version attached (only change is this testcase, which now works).

Tobias

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

[-- Attachment #2: omp-masked-fortran-v2.diff --]
[-- Type: text/x-patch, Size: 55516 bytes --]

Fortran/OpenMP: Add support for OpenMP 5.1 masked construct

Commit r12-2891-gd0befed793b94f3f407be44e6f69f81a02f5f073 added C/C++
support for the masked construct. This patch extends it to
Fortran.

gcc/fortran/ChangeLog:

	* dump-parse-tree.c (show_omp_clauses): Handle 'filter' clause.
	(show_omp_node, show_code_node): Handle (combined) omp masked construct.
	* frontend-passes.c (gfc_code_walker): Likewise.
	* gfortran.h (enum gfc_statement): Add ST_OMP_*_MASKED*.
	(enum gfc_exec_op): Add EXEC_OMP_*_MASKED*.
	* match.h (gfc_match_omp_masked, gfc_match_omp_masked_taskloop,
	gfc_match_omp_masked_taskloop_simd, gfc_match_omp_parallel_masked,
	gfc_match_omp_parallel_masked_taskloop,
	gfc_match_omp_parallel_masked_taskloop_simd): New prototypes.
	* openmp.c (enum omp_mask1): Add OMP_CLAUSE_FILTER.
	(gfc_match_omp_clauses): Match it.
	(OMP_MASKED_CLAUSES, gfc_match_omp_parallel_masked,
	gfc_match_omp_parallel_masked_taskloop,
	gfc_match_omp_parallel_masked_taskloop_simd,
	gfc_match_omp_masked, gfc_match_omp_masked_taskloop,
	gfc_match_omp_masked_taskloop_simd): New.
	(resolve_omp_clauses): Resolve filter clause. 
	(gfc_resolve_omp_parallel_blocks, resolve_omp_do,
	omp_code_to_statement, gfc_resolve_omp_directive): Handle
	omp masked constructs.
	* parse.c (decode_omp_directive, case_exec_markers,
	gfc_ascii_statement, parse_omp_do, parse_omp_structured_block,
	parse_executable): Likewise.
	* resolve.c (gfc_resolve_blocks, gfc_resolve_code): Likewise.
	* st.c (gfc_free_statement): Likewise.
	* trans-openmp.c (gfc_trans_omp_clauses): Handle filter clause.
	(GFC_OMP_SPLIT_MASKED, GFC_OMP_MASK_MASKED): New enum values.
	(gfc_trans_omp_masked): New.
	(gfc_split_omp_clauses): Handle combined masked directives.
	(gfc_trans_omp_master_taskloop): Rename to ...
	(gfc_trans_omp_master_masked_taskloop): ... this; handle also
	combined masked directives.
	(gfc_trans_omp_parallel_master): Rename to ...
	(gfc_trans_omp_parallel_master_masked): ... this; handle
	combined masked directives.
	(gfc_trans_omp_directive): Handle EXEC_OMP_*_MASKED*.
	* trans.c (trans_code): Likewise.

libgomp/ChangeLog:

	* testsuite/libgomp.fortran/masked-1.f90: New test.

gcc/testsuite/ChangeLog:

	* gfortran.dg/gomp/masked-1.f90: New test.
	* gfortran.dg/gomp/masked-2.f90: New test.
	* gfortran.dg/gomp/masked-3.f90: New test.
	* gfortran.dg/gomp/masked-combined-1.f90: New test.
	* gfortran.dg/gomp/masked-combined-2.f90: New test.

 gcc/fortran/dump-parse-tree.c                      |  24 +++
 gcc/fortran/frontend-passes.c                      |   3 +
 gcc/fortran/gfortran.h                             |  14 +-
 gcc/fortran/match.h                                |   6 +
 gcc/fortran/openmp.c                               |  98 ++++++++++++
 gcc/fortran/parse.c                                |  91 ++++++++++-
 gcc/fortran/resolve.c                              |  15 ++
 gcc/fortran/st.c                                   |   6 +
 gcc/fortran/trans-openmp.c                         | 176 +++++++++++++++++----
 gcc/fortran/trans.c                                |   6 +
 gcc/testsuite/gfortran.dg/gomp/masked-1.f90        |  94 +++++++++++
 gcc/testsuite/gfortran.dg/gomp/masked-2.f90        |  46 ++++++
 gcc/testsuite/gfortran.dg/gomp/masked-3.f90        |  12 ++
 .../gfortran.dg/gomp/masked-combined-1.f90         |  65 ++++++++
 .../gfortran.dg/gomp/masked-combined-2.f90         |  24 +++
 libgomp/testsuite/libgomp.fortran/masked-1.f90     | 119 ++++++++++++++
 16 files changed, 766 insertions(+), 33 deletions(-)

diff --git a/gcc/fortran/dump-parse-tree.c b/gcc/fortran/dump-parse-tree.c
index 360abf18a6a..53c49fe4d6f 100644
--- a/gcc/fortran/dump-parse-tree.c
+++ b/gcc/fortran/dump-parse-tree.c
@@ -1808,6 +1808,12 @@ show_omp_clauses (gfc_omp_clauses *omp_clauses)
       show_expr (omp_clauses->grainsize);
       fputc (')', dumpfile);
     }
+  if (omp_clauses->filter)
+    {
+      fputs (" FILTER(", dumpfile);
+      show_expr (omp_clauses->filter);
+      fputc (')', dumpfile);
+    }
   if (omp_clauses->hint)
     {
       fputs (" HINT(", dumpfile);
@@ -1946,6 +1952,9 @@ show_omp_node (int level, gfc_code *c)
     case EXEC_OMP_DO_SIMD: name = "DO SIMD"; break;
     case EXEC_OMP_LOOP: name = "LOOP"; break;
     case EXEC_OMP_FLUSH: name = "FLUSH"; break;
+    case EXEC_OMP_MASKED: name = "MASKED"; break;
+    case EXEC_OMP_MASKED_TASKLOOP: name = "MASKED TASKLOOP"; break;
+    case EXEC_OMP_MASKED_TASKLOOP_SIMD: name = "MASKED TASKLOOP SIMD"; break;
     case EXEC_OMP_MASTER: name = "MASTER"; break;
     case EXEC_OMP_MASTER_TASKLOOP: name = "MASTER TASKLOOP"; break;
     case EXEC_OMP_MASTER_TASKLOOP_SIMD: name = "MASTER TASKLOOP SIMD"; break;
@@ -1956,6 +1965,11 @@ show_omp_node (int level, gfc_code *c)
     case EXEC_OMP_PARALLEL_DO_SIMD: name = "PARALLEL DO SIMD"; break;
     case EXEC_OMP_PARALLEL_LOOP: name = "PARALLEL LOOP"; break;
     case EXEC_OMP_PARALLEL_MASTER: name = "PARALLEL MASTER"; break;
+    case EXEC_OMP_PARALLEL_MASKED: name = "PARALLEL MASK"; break;
+    case EXEC_OMP_PARALLEL_MASKED_TASKLOOP:
+      name = "PARALLEL MASK TASKLOOP"; break;
+    case EXEC_OMP_PARALLEL_MASKED_TASKLOOP_SIMD:
+      name = "PARALLEL MASK TASKLOOP SIMD"; break;
     case EXEC_OMP_PARALLEL_MASTER_TASKLOOP:
       name = "PARALLEL MASTER TASKLOOP"; break;
     case EXEC_OMP_PARALLEL_MASTER_TASKLOOP_SIMD:
@@ -2032,10 +2046,14 @@ show_omp_node (int level, gfc_code *c)
     case EXEC_OMP_DO_SIMD:
     case EXEC_OMP_LOOP:
     case EXEC_OMP_ORDERED:
+    case EXEC_OMP_MASKED:
     case EXEC_OMP_PARALLEL:
     case EXEC_OMP_PARALLEL_DO:
     case EXEC_OMP_PARALLEL_DO_SIMD:
     case EXEC_OMP_PARALLEL_LOOP:
+    case EXEC_OMP_PARALLEL_MASKED:
+    case EXEC_OMP_PARALLEL_MASKED_TASKLOOP:
+    case EXEC_OMP_PARALLEL_MASKED_TASKLOOP_SIMD:
     case EXEC_OMP_PARALLEL_MASTER:
     case EXEC_OMP_PARALLEL_MASTER_TASKLOOP:
     case EXEC_OMP_PARALLEL_MASTER_TASKLOOP_SIMD:
@@ -3250,6 +3268,9 @@ show_code_node (int level, gfc_code *c)
     case EXEC_OMP_DO_SIMD:
     case EXEC_OMP_FLUSH:
     case EXEC_OMP_LOOP:
+    case EXEC_OMP_MASKED:
+    case EXEC_OMP_MASKED_TASKLOOP:
+    case EXEC_OMP_MASKED_TASKLOOP_SIMD:
     case EXEC_OMP_MASTER:
     case EXEC_OMP_MASTER_TASKLOOP:
     case EXEC_OMP_MASTER_TASKLOOP_SIMD:
@@ -3258,6 +3279,9 @@ show_code_node (int level, gfc_code *c)
     case EXEC_OMP_PARALLEL_DO:
     case EXEC_OMP_PARALLEL_DO_SIMD:
     case EXEC_OMP_PARALLEL_LOOP:
+    case EXEC_OMP_PARALLEL_MASKED:
+    case EXEC_OMP_PARALLEL_MASKED_TASKLOOP:
+    case EXEC_OMP_PARALLEL_MASKED_TASKLOOP_SIMD:
     case EXEC_OMP_PARALLEL_MASTER:
     case EXEC_OMP_PARALLEL_MASTER_TASKLOOP:
     case EXEC_OMP_PARALLEL_MASTER_TASKLOOP_SIMD:
diff --git a/gcc/fortran/frontend-passes.c b/gcc/fortran/frontend-passes.c
index 996dcc2e547..145bff50f3e 100644
--- a/gcc/fortran/frontend-passes.c
+++ b/gcc/fortran/frontend-passes.c
@@ -5556,6 +5556,9 @@ gfc_code_walker (gfc_code **c, walk_code_fn_t codefn, walk_expr_fn_t exprfn,
 	    case EXEC_OMP_PARALLEL_DO:
 	    case EXEC_OMP_PARALLEL_DO_SIMD:
 	    case EXEC_OMP_PARALLEL_LOOP:
+	    case EXEC_OMP_PARALLEL_MASKED:
+	    case EXEC_OMP_PARALLEL_MASKED_TASKLOOP:
+	    case EXEC_OMP_PARALLEL_MASKED_TASKLOOP_SIMD:
 	    case EXEC_OMP_PARALLEL_MASTER:
 	    case EXEC_OMP_PARALLEL_MASTER_TASKLOOP:
 	    case EXEC_OMP_PARALLEL_MASTER_TASKLOOP_SIMD:
diff --git a/gcc/fortran/gfortran.h b/gcc/fortran/gfortran.h
index 8f75dd95394..5fde4174a5b 100644
--- a/gcc/fortran/gfortran.h
+++ b/gcc/fortran/gfortran.h
@@ -275,7 +275,13 @@ enum gfc_statement
   ST_OMP_PARALLEL_LOOP, ST_OMP_END_PARALLEL_LOOP, ST_OMP_TEAMS_LOOP,
   ST_OMP_END_TEAMS_LOOP, ST_OMP_TARGET_PARALLEL_LOOP,
   ST_OMP_END_TARGET_PARALLEL_LOOP, ST_OMP_TARGET_TEAMS_LOOP,
-  ST_OMP_END_TARGET_TEAMS_LOOP, ST_NONE
+  ST_OMP_END_TARGET_TEAMS_LOOP, ST_OMP_MASKED, ST_OMP_END_MASKED,
+  ST_OMP_PARALLEL_MASKED, ST_OMP_END_PARALLEL_MASKED,
+  ST_OMP_PARALLEL_MASKED_TASKLOOP, ST_OMP_END_PARALLEL_MASKED_TASKLOOP,
+  ST_OMP_PARALLEL_MASKED_TASKLOOP_SIMD,
+  ST_OMP_END_PARALLEL_MASKED_TASKLOOP_SIMD, ST_OMP_MASKED_TASKLOOP,
+  ST_OMP_END_MASKED_TASKLOOP, ST_OMP_MASKED_TASKLOOP_SIMD,
+  ST_OMP_END_MASKED_TASKLOOP_SIMD, ST_NONE
 };
 
 /* Types of interfaces that we can have.  Assignment interfaces are
@@ -1466,6 +1472,7 @@ typedef struct gfc_omp_clauses
   struct gfc_expr *device;
   struct gfc_expr *thread_limit;
   struct gfc_expr *grainsize;
+  struct gfc_expr *filter;
   struct gfc_expr *hint;
   struct gfc_expr *num_tasks;
   struct gfc_expr *priority;
@@ -2758,7 +2765,10 @@ enum gfc_exec_op
   EXEC_OMP_PARALLEL_MASTER, EXEC_OMP_PARALLEL_MASTER_TASKLOOP,
   EXEC_OMP_PARALLEL_MASTER_TASKLOOP_SIMD, EXEC_OMP_MASTER_TASKLOOP,
   EXEC_OMP_MASTER_TASKLOOP_SIMD, EXEC_OMP_LOOP, EXEC_OMP_PARALLEL_LOOP,
-  EXEC_OMP_TEAMS_LOOP, EXEC_OMP_TARGET_PARALLEL_LOOP, EXEC_OMP_TARGET_TEAMS_LOOP
+  EXEC_OMP_TEAMS_LOOP, EXEC_OMP_TARGET_PARALLEL_LOOP,
+  EXEC_OMP_TARGET_TEAMS_LOOP, EXEC_OMP_MASKED, EXEC_OMP_PARALLEL_MASKED,
+  EXEC_OMP_PARALLEL_MASKED_TASKLOOP, EXEC_OMP_PARALLEL_MASKED_TASKLOOP_SIMD,
+  EXEC_OMP_MASKED_TASKLOOP, EXEC_OMP_MASKED_TASKLOOP_SIMD
 };
 
 typedef struct gfc_code
diff --git a/gcc/fortran/match.h b/gcc/fortran/match.h
index bb1f34fc444..dce650346d3 100644
--- a/gcc/fortran/match.h
+++ b/gcc/fortran/match.h
@@ -169,6 +169,9 @@ match gfc_match_omp_do (void);
 match gfc_match_omp_do_simd (void);
 match gfc_match_omp_loop (void);
 match gfc_match_omp_flush (void);
+match gfc_match_omp_masked (void);
+match gfc_match_omp_masked_taskloop (void);
+match gfc_match_omp_masked_taskloop_simd (void);
 match gfc_match_omp_master (void);
 match gfc_match_omp_master_taskloop (void);
 match gfc_match_omp_master_taskloop_simd (void);
@@ -178,6 +181,9 @@ match gfc_match_omp_parallel (void);
 match gfc_match_omp_parallel_do (void);
 match gfc_match_omp_parallel_do_simd (void);
 match gfc_match_omp_parallel_loop (void);
+match gfc_match_omp_parallel_masked (void);
+match gfc_match_omp_parallel_masked_taskloop (void);
+match gfc_match_omp_parallel_masked_taskloop_simd (void);
 match gfc_match_omp_parallel_master (void);
 match gfc_match_omp_parallel_master_taskloop (void);
 match gfc_match_omp_parallel_master_taskloop_simd (void);
diff --git a/gcc/fortran/openmp.c b/gcc/fortran/openmp.c
index ec558656602..1bce43cb33e 100644
--- a/gcc/fortran/openmp.c
+++ b/gcc/fortran/openmp.c
@@ -847,6 +847,7 @@ enum omp_mask1
   OMP_CLAUSE_DETACH,  /* OpenMP 5.0.  */
   OMP_CLAUSE_AFFINITY,  /* OpenMP 5.0.  */
   OMP_CLAUSE_BIND,  /* OpenMP 5.0.  */
+  OMP_CLAUSE_FILTER,  /* OpenMP 5.1.  */
   OMP_CLAUSE_NOWAIT,
   /* This must come last.  */
   OMP_MASK1_LAST
@@ -1772,6 +1773,10 @@ gfc_match_omp_clauses (gfc_omp_clauses **cp, const omp_mask mask,
 	    }
 	  break;
 	case 'f':
+	  if ((mask & OMP_CLAUSE_FILTER)
+	      && c->filter == NULL
+	      && gfc_match ("filter ( %e )", &c->filter) == MATCH_YES)
+	    continue;
 	  if ((mask & OMP_CLAUSE_FINAL)
 	      && c->final_expr == NULL
 	      && gfc_match ("final ( %e )", &c->final_expr) == MATCH_YES)
@@ -3199,6 +3204,8 @@ cleanup:
 #define OMP_ATOMIC_CLAUSES \
   (omp_mask (OMP_CLAUSE_ATOMIC) | OMP_CLAUSE_CAPTURE | OMP_CLAUSE_HINT	\
    | OMP_CLAUSE_MEMORDER)
+#define OMP_MASKED_CLAUSES \
+  (omp_mask (OMP_CLAUSE_FILTER))
 
 
 static match
@@ -4157,6 +4164,31 @@ gfc_match_omp_parallel_do_simd (void)
 }
 
 
+match
+gfc_match_omp_parallel_masked (void)
+{
+  return match_omp (EXEC_OMP_PARALLEL_MASKED,
+		    OMP_PARALLEL_CLAUSES | OMP_MASKED_CLAUSES);
+}
+
+match
+gfc_match_omp_parallel_masked_taskloop (void)
+{
+  return match_omp (EXEC_OMP_PARALLEL_MASKED_TASKLOOP,
+		    (OMP_PARALLEL_CLAUSES | OMP_MASKED_CLAUSES
+		     | OMP_TASKLOOP_CLAUSES)
+		    & ~(omp_mask (OMP_CLAUSE_IN_REDUCTION)));
+}
+
+match
+gfc_match_omp_parallel_masked_taskloop_simd (void)
+{
+  return match_omp (EXEC_OMP_PARALLEL_MASKED_TASKLOOP_SIMD,
+		    (OMP_PARALLEL_CLAUSES | OMP_MASKED_CLAUSES
+		     | OMP_TASKLOOP_CLAUSES | OMP_SIMD_CLAUSES)
+		    & ~(omp_mask (OMP_CLAUSE_IN_REDUCTION)));
+}
+
 match
 gfc_match_omp_parallel_master (void)
 {
@@ -4703,6 +4735,27 @@ gfc_match_omp_workshare (void)
 }
 
 
+match
+gfc_match_omp_masked (void)
+{
+  return match_omp (EXEC_OMP_MASKED, OMP_MASKED_CLAUSES);
+}
+
+match
+gfc_match_omp_masked_taskloop (void)
+{
+  return match_omp (EXEC_OMP_MASKED_TASKLOOP,
+		    OMP_MASKED_CLAUSES | OMP_TASKLOOP_CLAUSES);
+}
+
+match
+gfc_match_omp_masked_taskloop_simd (void)
+{
+  return match_omp (EXEC_OMP_MASKED_TASKLOOP_SIMD,
+		    (OMP_MASKED_CLAUSES | OMP_TASKLOOP_CLAUSES
+		     | OMP_SIMD_CLAUSES));
+}
+
 match
 gfc_match_omp_master (void)
 {
@@ -5254,6 +5307,7 @@ resolve_omp_clauses (gfc_code *code, gfc_omp_clauses *omp_clauses,
 
 	    case EXEC_OMP_PARALLEL:
 	    case EXEC_OMP_PARALLEL_DO:
+	    case EXEC_OMP_PARALLEL_MASKED:
 	    case EXEC_OMP_PARALLEL_MASTER:
 	    case EXEC_OMP_PARALLEL_SECTIONS:
 	    case EXEC_OMP_PARALLEL_WORKSHARE:
@@ -5268,10 +5322,12 @@ resolve_omp_clauses (gfc_code *code, gfc_omp_clauses *omp_clauses,
 	      ok = ifc == OMP_IF_PARALLEL || ifc == OMP_IF_SIMD;
 	      break;
 
+	    case EXEC_OMP_PARALLEL_MASKED_TASKLOOP:
 	    case EXEC_OMP_PARALLEL_MASTER_TASKLOOP:
 	      ok = ifc == OMP_IF_PARALLEL || ifc == OMP_IF_TASKLOOP;
 	      break;
 
+	    case EXEC_OMP_PARALLEL_MASKED_TASKLOOP_SIMD:
 	    case EXEC_OMP_PARALLEL_MASTER_TASKLOOP_SIMD:
 	      ok = (ifc == OMP_IF_PARALLEL
 		    || ifc == OMP_IF_TASKLOOP
@@ -5290,11 +5346,13 @@ resolve_omp_clauses (gfc_code *code, gfc_omp_clauses *omp_clauses,
 	      break;
 
 	    case EXEC_OMP_TASKLOOP:
+	    case EXEC_OMP_MASKED_TASKLOOP:
 	    case EXEC_OMP_MASTER_TASKLOOP:
 	      ok = ifc == OMP_IF_TASKLOOP;
 	      break;
 
 	    case EXEC_OMP_TASKLOOP_SIMD:
+	    case EXEC_OMP_MASKED_TASKLOOP_SIMD:
 	    case EXEC_OMP_MASTER_TASKLOOP_SIMD:
 	      ok = ifc == OMP_IF_TASKLOOP || ifc == OMP_IF_SIMD;
 	      break;
@@ -6060,9 +6118,13 @@ resolve_omp_clauses (gfc_code *code, gfc_omp_clauses *omp_clauses,
 			&& (code->op == EXEC_OMP_LOOP
 			    || code->op == EXEC_OMP_TASKLOOP
 			    || code->op == EXEC_OMP_TASKLOOP_SIMD
+			    || code->op == EXEC_OMP_MASKED_TASKLOOP
+			    || code->op == EXEC_OMP_MASKED_TASKLOOP_SIMD
 			    || code->op == EXEC_OMP_MASTER_TASKLOOP
 			    || code->op == EXEC_OMP_MASTER_TASKLOOP_SIMD
 			    || code->op == EXEC_OMP_PARALLEL_LOOP
+			    || code->op == EXEC_OMP_PARALLEL_MASKED_TASKLOOP
+			    || code->op == EXEC_OMP_PARALLEL_MASKED_TASKLOOP_SIMD
 			    || code->op == EXEC_OMP_PARALLEL_MASTER_TASKLOOP
 			    || code->op == EXEC_OMP_PARALLEL_MASTER_TASKLOOP_SIMD
 			    || code->op == EXEC_OMP_TARGET_PARALLEL_LOOP
@@ -6322,6 +6384,8 @@ resolve_omp_clauses (gfc_code *code, gfc_omp_clauses *omp_clauses,
     resolve_positive_int_expr (omp_clauses->num_teams, "NUM_TEAMS");
   if (omp_clauses->device)
     resolve_nonnegative_int_expr (omp_clauses->device, "DEVICE");
+  if (omp_clauses->filter)
+    resolve_nonnegative_int_expr (omp_clauses->filter, "FILTER");
   if (omp_clauses->hint)
     {
       resolve_scalar_int_expr (omp_clauses->hint, "HINT");
@@ -6984,8 +7048,12 @@ gfc_resolve_omp_parallel_blocks (gfc_code *code, gfc_namespace *ns)
     case EXEC_OMP_DISTRIBUTE_PARALLEL_DO_SIMD:
     case EXEC_OMP_PARALLEL_DO:
     case EXEC_OMP_PARALLEL_DO_SIMD:
+    case EXEC_OMP_PARALLEL_MASKED_TASKLOOP:
+    case EXEC_OMP_PARALLEL_MASKED_TASKLOOP_SIMD:
     case EXEC_OMP_PARALLEL_MASTER_TASKLOOP:
     case EXEC_OMP_PARALLEL_MASTER_TASKLOOP_SIMD:
+    case EXEC_OMP_MASKED_TASKLOOP:
+    case EXEC_OMP_MASKED_TASKLOOP_SIMD:
     case EXEC_OMP_MASTER_TASKLOOP:
     case EXEC_OMP_MASTER_TASKLOOP_SIMD:
     case EXEC_OMP_TARGET_PARALLEL_DO:
@@ -7133,6 +7201,13 @@ resolve_omp_do (gfc_code *code)
       is_simd = true;
       break;
     case EXEC_OMP_PARALLEL_LOOP: name = "!$OMP PARALLEL LOOP"; break;
+    case EXEC_OMP_PARALLEL_MASKED_TASKLOOP:
+      name = "!$OMP PARALLEL MASKED TASKLOOP";
+      break;
+    case EXEC_OMP_PARALLEL_MASKED_TASKLOOP_SIMD:
+      name = "!$OMP PARALLEL MASKED TASKLOOP SIMD";
+      is_simd = true;
+      break;
     case EXEC_OMP_PARALLEL_MASTER_TASKLOOP:
       name = "!$OMP PARALLEL MASTER TASKLOOP";
       break;
@@ -7140,6 +7215,11 @@ resolve_omp_do (gfc_code *code)
       name = "!$OMP PARALLEL MASTER TASKLOOP SIMD";
       is_simd = true;
       break;
+    case EXEC_OMP_MASKED_TASKLOOP: name = "!$OMP MASKED TASKLOOP"; break;
+    case EXEC_OMP_MASKED_TASKLOOP_SIMD:
+      name = "!$OMP MASKED TASKLOOP SIMD";
+      is_simd = true;
+      break;
     case EXEC_OMP_MASTER_TASKLOOP: name = "!$OMP MASTER TASKLOOP"; break;
     case EXEC_OMP_MASTER_TASKLOOP_SIMD:
       name = "!$OMP MASTER TASKLOOP SIMD";
@@ -7302,6 +7382,12 @@ omp_code_to_statement (gfc_code *code)
     {
     case EXEC_OMP_PARALLEL:
       return ST_OMP_PARALLEL;
+    case EXEC_OMP_PARALLEL_MASKED:
+      return ST_OMP_PARALLEL_MASKED;
+    case EXEC_OMP_PARALLEL_MASKED_TASKLOOP:
+      return ST_OMP_PARALLEL_MASKED_TASKLOOP;
+    case EXEC_OMP_PARALLEL_MASKED_TASKLOOP_SIMD:
+      return ST_OMP_PARALLEL_MASKED_TASKLOOP_SIMD;
     case EXEC_OMP_PARALLEL_MASTER:
       return ST_OMP_PARALLEL_MASTER;
     case EXEC_OMP_PARALLEL_MASTER_TASKLOOP:
@@ -7316,6 +7402,12 @@ omp_code_to_statement (gfc_code *code)
       return ST_OMP_ORDERED;
     case EXEC_OMP_CRITICAL:
       return ST_OMP_CRITICAL;
+    case EXEC_OMP_MASKED:
+      return ST_OMP_MASKED;
+    case EXEC_OMP_MASKED_TASKLOOP:
+      return ST_OMP_MASKED_TASKLOOP;
+    case EXEC_OMP_MASKED_TASKLOOP_SIMD:
+      return ST_OMP_MASKED_TASKLOOP_SIMD;
     case EXEC_OMP_MASTER:
       return ST_OMP_MASTER;
     case EXEC_OMP_MASTER_TASKLOOP:
@@ -7822,8 +7914,12 @@ gfc_resolve_omp_directive (gfc_code *code, gfc_namespace *ns)
     case EXEC_OMP_PARALLEL_DO:
     case EXEC_OMP_PARALLEL_DO_SIMD:
     case EXEC_OMP_PARALLEL_LOOP:
+    case EXEC_OMP_PARALLEL_MASKED_TASKLOOP:
+    case EXEC_OMP_PARALLEL_MASKED_TASKLOOP_SIMD:
     case EXEC_OMP_PARALLEL_MASTER_TASKLOOP:
     case EXEC_OMP_PARALLEL_MASTER_TASKLOOP_SIMD:
+    case EXEC_OMP_MASKED_TASKLOOP:
+    case EXEC_OMP_MASKED_TASKLOOP_SIMD:
     case EXEC_OMP_MASTER_TASKLOOP:
     case EXEC_OMP_MASTER_TASKLOOP_SIMD:
     case EXEC_OMP_SIMD:
@@ -7846,8 +7942,10 @@ gfc_resolve_omp_directive (gfc_code *code, gfc_namespace *ns)
       resolve_omp_do (code);
       break;
     case EXEC_OMP_CANCEL:
+    case EXEC_OMP_MASKED:
     case EXEC_OMP_PARALLEL_WORKSHARE:
     case EXEC_OMP_PARALLEL:
+    case EXEC_OMP_PARALLEL_MASKED:
     case EXEC_OMP_PARALLEL_MASTER:
     case EXEC_OMP_PARALLEL_SECTIONS:
     case EXEC_OMP_SECTIONS:
diff --git a/gcc/fortran/parse.c b/gcc/fortran/parse.c
index 6d7845e8517..e1d78de5d9e 100644
--- a/gcc/fortran/parse.c
+++ b/gcc/fortran/parse.c
@@ -920,6 +920,11 @@ decode_omp_directive (void)
       matchs ("end do simd", gfc_match_omp_end_nowait, ST_OMP_END_DO_SIMD);
       matcho ("end do", gfc_match_omp_end_nowait, ST_OMP_END_DO);
       matchs ("end simd", gfc_match_omp_eos_error, ST_OMP_END_SIMD);
+      matcho ("end masked taskloop simd", gfc_match_omp_eos_error,
+	      ST_OMP_END_MASKED_TASKLOOP_SIMD);
+      matcho ("end masked taskloop", gfc_match_omp_eos_error,
+	      ST_OMP_END_MASKED_TASKLOOP);
+      matcho ("end masked", gfc_match_omp_eos_error, ST_OMP_END_MASKED);
       matcho ("end master taskloop simd", gfc_match_omp_eos_error,
 	      ST_OMP_END_MASTER_TASKLOOP_SIMD);
       matcho ("end master taskloop", gfc_match_omp_eos_error,
@@ -929,6 +934,12 @@ decode_omp_directive (void)
       matchs ("end parallel do simd", gfc_match_omp_eos_error,
 	      ST_OMP_END_PARALLEL_DO_SIMD);
       matcho ("end parallel do", gfc_match_omp_eos_error, ST_OMP_END_PARALLEL_DO);
+      matcho ("end parallel masked taskloop simd", gfc_match_omp_eos_error,
+	      ST_OMP_END_PARALLEL_MASKED_TASKLOOP_SIMD);
+      matcho ("end parallel masked taskloop", gfc_match_omp_eos_error,
+	      ST_OMP_END_PARALLEL_MASKED_TASKLOOP);
+      matcho ("end parallel masked", gfc_match_omp_eos_error,
+	      ST_OMP_END_PARALLEL_MASKED);
       matcho ("end parallel master taskloop simd", gfc_match_omp_eos_error,
 	      ST_OMP_END_PARALLEL_MASTER_TASKLOOP_SIMD);
       matcho ("end parallel master taskloop", gfc_match_omp_eos_error,
@@ -982,6 +993,11 @@ decode_omp_directive (void)
       matcho ("flush", gfc_match_omp_flush, ST_OMP_FLUSH);
       break;
     case 'm':
+      matcho ("masked taskloop simd", gfc_match_omp_masked_taskloop_simd,
+	      ST_OMP_MASKED_TASKLOOP_SIMD);
+      matcho ("masked taskloop", gfc_match_omp_masked_taskloop,
+	      ST_OMP_MASKED_TASKLOOP);
+      matcho ("masked", gfc_match_omp_masked, ST_OMP_MASKED);
       matcho ("master taskloop simd", gfc_match_omp_master_taskloop_simd,
 	      ST_OMP_MASTER_TASKLOOP_SIMD);
       matcho ("master taskloop", gfc_match_omp_master_taskloop,
@@ -1009,6 +1025,14 @@ decode_omp_directive (void)
       matcho ("parallel do", gfc_match_omp_parallel_do, ST_OMP_PARALLEL_DO);
       matcho ("parallel loop", gfc_match_omp_parallel_loop,
 	      ST_OMP_PARALLEL_LOOP);
+      matcho ("parallel masked taskloop simd",
+	      gfc_match_omp_parallel_masked_taskloop_simd,
+	      ST_OMP_PARALLEL_MASKED_TASKLOOP_SIMD);
+      matcho ("parallel masked taskloop",
+	      gfc_match_omp_parallel_masked_taskloop,
+	      ST_OMP_PARALLEL_MASKED_TASKLOOP);
+      matcho ("parallel masked", gfc_match_omp_parallel_masked,
+	      ST_OMP_PARALLEL_MASKED);
       matcho ("parallel master taskloop simd",
 	      gfc_match_omp_parallel_master_taskloop_simd,
 	      ST_OMP_PARALLEL_MASTER_TASKLOOP_SIMD);
@@ -1639,11 +1663,15 @@ next_statement (void)
 #define case_exec_markers case ST_DO: case ST_FORALL_BLOCK: \
   case ST_IF_BLOCK: case ST_BLOCK: case ST_ASSOCIATE: \
   case ST_WHERE_BLOCK: case ST_SELECT_CASE: case ST_SELECT_TYPE: \
-  case ST_SELECT_RANK: case ST_OMP_PARALLEL: case ST_OMP_PARALLEL_MASTER: \
+  case ST_SELECT_RANK: case ST_OMP_PARALLEL: case ST_OMP_PARALLEL_MASKED: \
+  case ST_OMP_PARALLEL_MASKED_TASKLOOP: \
+  case ST_OMP_PARALLEL_MASKED_TASKLOOP_SIMD: case ST_OMP_PARALLEL_MASTER: \
   case ST_OMP_PARALLEL_MASTER_TASKLOOP: \
   case ST_OMP_PARALLEL_MASTER_TASKLOOP_SIMD: \
   case ST_OMP_PARALLEL_SECTIONS: case ST_OMP_SECTIONS: case ST_OMP_ORDERED: \
-  case ST_OMP_CRITICAL: case ST_OMP_MASTER: case ST_OMP_MASTER_TASKLOOP: \
+  case ST_OMP_CRITICAL: case ST_OMP_MASKED: case ST_OMP_MASKED_TASKLOOP: \
+  case ST_OMP_MASKED_TASKLOOP_SIMD: \
+  case ST_OMP_MASTER: case ST_OMP_MASTER_TASKLOOP: \
   case ST_OMP_MASTER_TASKLOOP_SIMD: case ST_OMP_SINGLE: \
   case ST_OMP_DO: case ST_OMP_PARALLEL_DO: case ST_OMP_ATOMIC: \
   case ST_OMP_WORKSHARE: case ST_OMP_PARALLEL_WORKSHARE: \
@@ -2376,6 +2404,15 @@ gfc_ascii_statement (gfc_statement st)
     case ST_OMP_END_LOOP:
       p = "!$OMP END LOOP";
       break;
+    case ST_OMP_END_MASKED:
+      p = "!$OMP END MASKED";
+      break;
+    case ST_OMP_END_MASKED_TASKLOOP:
+      p = "!$OMP END MASKED TASKLOOP";
+      break;
+    case ST_OMP_END_MASKED_TASKLOOP_SIMD:
+      p = "!$OMP END MASKED TASKLOOP SIMD";
+      break;
     case ST_OMP_END_MASTER:
       p = "!$OMP END MASTER";
       break;
@@ -2400,6 +2437,15 @@ gfc_ascii_statement (gfc_statement st)
     case ST_OMP_END_PARALLEL_LOOP:
       p = "!$OMP END PARALLEL LOOP";
       break;
+    case ST_OMP_END_PARALLEL_MASKED:
+      p = "!$OMP END PARALLEL MASKED";
+      break;
+    case ST_OMP_END_PARALLEL_MASKED_TASKLOOP:
+      p = "!$OMP END PARALLEL MASKED TASKLOOP";
+      break;
+    case ST_OMP_END_PARALLEL_MASKED_TASKLOOP_SIMD:
+      p = "!$OMP END PARALLEL MASKED TASKLOOP SIMD";
+      break;
     case ST_OMP_END_PARALLEL_MASTER:
       p = "!$OMP END PARALLEL MASTER";
       break;
@@ -2499,6 +2545,15 @@ gfc_ascii_statement (gfc_statement st)
     case ST_OMP_LOOP:
       p = "!$OMP LOOP";
       break;
+    case ST_OMP_MASKED:
+      p = "!$OMP MASKED";
+      break;
+    case ST_OMP_MASKED_TASKLOOP:
+      p = "!$OMP MASKED TASKLOOP";
+      break;
+    case ST_OMP_MASKED_TASKLOOP_SIMD:
+      p = "!$OMP MASKED TASKLOOP SIMD";
+      break;
     case ST_OMP_MASTER:
       p = "!$OMP MASTER";
       break;
@@ -2524,6 +2579,15 @@ gfc_ascii_statement (gfc_statement st)
     case ST_OMP_PARALLEL_DO_SIMD:
       p = "!$OMP PARALLEL DO SIMD";
       break;
+    case ST_OMP_PARALLEL_MASKED:
+      p = "!$OMP PARALLEL MASKED";
+      break;
+    case ST_OMP_PARALLEL_MASKED_TASKLOOP:
+      p = "!$OMP PARALLEL MASKED TASKLOOP";
+      break;
+    case ST_OMP_PARALLEL_MASKED_TASKLOOP_SIMD:
+      p = "!$OMP PARALLEL MASKED TASKLOOP SIMD";
+      break;
     case ST_OMP_PARALLEL_MASTER:
       p = "!$OMP PARALLEL MASTER";
       break;
@@ -5127,10 +5191,20 @@ parse_omp_do (gfc_statement omp_st)
       break;
     case ST_OMP_TASKLOOP: omp_end_st = ST_OMP_END_TASKLOOP; break;
     case ST_OMP_TASKLOOP_SIMD: omp_end_st = ST_OMP_END_TASKLOOP_SIMD; break;
+    case ST_OMP_MASKED_TASKLOOP: omp_end_st = ST_OMP_END_MASKED_TASKLOOP; break;
+    case ST_OMP_MASKED_TASKLOOP_SIMD:
+      omp_end_st = ST_OMP_END_MASKED_TASKLOOP_SIMD;
+      break;
     case ST_OMP_MASTER_TASKLOOP: omp_end_st = ST_OMP_END_MASTER_TASKLOOP; break;
     case ST_OMP_MASTER_TASKLOOP_SIMD:
       omp_end_st = ST_OMP_END_MASTER_TASKLOOP_SIMD;
       break;
+    case ST_OMP_PARALLEL_MASKED_TASKLOOP:
+      omp_end_st = ST_OMP_END_PARALLEL_MASKED_TASKLOOP;
+      break;
+    case ST_OMP_PARALLEL_MASKED_TASKLOOP_SIMD:
+      omp_end_st = ST_OMP_END_PARALLEL_MASKED_TASKLOOP_SIMD;
+      break;
     case ST_OMP_PARALLEL_MASTER_TASKLOOP:
       omp_end_st = ST_OMP_END_PARALLEL_MASTER_TASKLOOP;
       break;
@@ -5380,6 +5454,9 @@ parse_omp_structured_block (gfc_statement omp_st, bool workshare_stmts_only)
     case ST_OMP_PARALLEL:
       omp_end_st = ST_OMP_END_PARALLEL;
       break;
+    case ST_OMP_PARALLEL_MASKED:
+      omp_end_st = ST_OMP_END_PARALLEL_MASKED;
+      break;
     case ST_OMP_PARALLEL_MASTER:
       omp_end_st = ST_OMP_END_PARALLEL_MASTER;
       break;
@@ -5395,6 +5472,9 @@ parse_omp_structured_block (gfc_statement omp_st, bool workshare_stmts_only)
     case ST_OMP_CRITICAL:
       omp_end_st = ST_OMP_END_CRITICAL;
       break;
+    case ST_OMP_MASKED:
+      omp_end_st = ST_OMP_END_MASKED;
+      break;
     case ST_OMP_MASTER:
       omp_end_st = ST_OMP_END_MASTER;
       break;
@@ -5477,6 +5557,7 @@ parse_omp_structured_block (gfc_statement omp_st, bool workshare_stmts_only)
 		  break;
 
 		case ST_OMP_PARALLEL:
+		case ST_OMP_PARALLEL_MASKED:
 		case ST_OMP_PARALLEL_MASTER:
 		case ST_OMP_PARALLEL_SECTIONS:
 		  parse_omp_structured_block (st, false);
@@ -5679,11 +5760,13 @@ parse_executable (gfc_statement st)
 	  break;
 
 	case ST_OMP_PARALLEL:
+	case ST_OMP_PARALLEL_MASKED:
 	case ST_OMP_PARALLEL_MASTER:
 	case ST_OMP_PARALLEL_SECTIONS:
 	case ST_OMP_SECTIONS:
 	case ST_OMP_ORDERED:
 	case ST_OMP_CRITICAL:
+	case ST_OMP_MASKED:
 	case ST_OMP_MASTER:
 	case ST_OMP_SINGLE:
 	case ST_OMP_TARGET:
@@ -5711,8 +5794,12 @@ parse_executable (gfc_statement st)
 	case ST_OMP_PARALLEL_DO:
 	case ST_OMP_PARALLEL_DO_SIMD:
 	case ST_OMP_PARALLEL_LOOP:
+	case ST_OMP_PARALLEL_MASKED_TASKLOOP:
+	case ST_OMP_PARALLEL_MASKED_TASKLOOP_SIMD:
 	case ST_OMP_PARALLEL_MASTER_TASKLOOP:
 	case ST_OMP_PARALLEL_MASTER_TASKLOOP_SIMD:
+	case ST_OMP_MASKED_TASKLOOP:
+	case ST_OMP_MASKED_TASKLOOP_SIMD:
 	case ST_OMP_MASTER_TASKLOOP:
 	case ST_OMP_MASTER_TASKLOOP_SIMD:
 	case ST_OMP_SIMD:
diff --git a/gcc/fortran/resolve.c b/gcc/fortran/resolve.c
index 592364689f9..b0087be5068 100644
--- a/gcc/fortran/resolve.c
+++ b/gcc/fortran/resolve.c
@@ -10810,6 +10810,9 @@ gfc_resolve_blocks (gfc_code *b, gfc_namespace *ns)
 	case EXEC_OMP_DO:
 	case EXEC_OMP_DO_SIMD:
 	case EXEC_OMP_LOOP:
+	case EXEC_OMP_MASKED:
+	case EXEC_OMP_MASKED_TASKLOOP:
+	case EXEC_OMP_MASKED_TASKLOOP_SIMD:
 	case EXEC_OMP_MASTER:
 	case EXEC_OMP_MASTER_TASKLOOP:
 	case EXEC_OMP_MASTER_TASKLOOP_SIMD:
@@ -10818,6 +10821,9 @@ gfc_resolve_blocks (gfc_code *b, gfc_namespace *ns)
 	case EXEC_OMP_PARALLEL_DO:
 	case EXEC_OMP_PARALLEL_DO_SIMD:
 	case EXEC_OMP_PARALLEL_LOOP:
+	case EXEC_OMP_PARALLEL_MASKED:
+	case EXEC_OMP_PARALLEL_MASKED_TASKLOOP:
+	case EXEC_OMP_PARALLEL_MASKED_TASKLOOP_SIMD:
 	case EXEC_OMP_PARALLEL_MASTER:
 	case EXEC_OMP_PARALLEL_MASTER_TASKLOOP:
 	case EXEC_OMP_PARALLEL_MASTER_TASKLOOP_SIMD:
@@ -11785,6 +11791,9 @@ gfc_resolve_code (gfc_code *code, gfc_namespace *ns)
 	    case EXEC_OMP_PARALLEL:
 	    case EXEC_OMP_PARALLEL_DO:
 	    case EXEC_OMP_PARALLEL_DO_SIMD:
+	    case EXEC_OMP_PARALLEL_MASKED:
+	    case EXEC_OMP_PARALLEL_MASKED_TASKLOOP:
+	    case EXEC_OMP_PARALLEL_MASKED_TASKLOOP_SIMD:
 	    case EXEC_OMP_PARALLEL_MASTER:
 	    case EXEC_OMP_PARALLEL_MASTER_TASKLOOP:
 	    case EXEC_OMP_PARALLEL_MASTER_TASKLOOP_SIMD:
@@ -12240,6 +12249,9 @@ start:
 	case EXEC_OMP_MASTER:
 	case EXEC_OMP_MASTER_TASKLOOP:
 	case EXEC_OMP_MASTER_TASKLOOP_SIMD:
+	case EXEC_OMP_MASKED:
+	case EXEC_OMP_MASKED_TASKLOOP:
+	case EXEC_OMP_MASKED_TASKLOOP_SIMD:
 	case EXEC_OMP_ORDERED:
 	case EXEC_OMP_SCAN:
 	case EXEC_OMP_SECTIONS:
@@ -12281,6 +12293,9 @@ start:
 	case EXEC_OMP_PARALLEL_DO:
 	case EXEC_OMP_PARALLEL_DO_SIMD:
 	case EXEC_OMP_PARALLEL_LOOP:
+	case EXEC_OMP_PARALLEL_MASKED:
+	case EXEC_OMP_PARALLEL_MASKED_TASKLOOP:
+	case EXEC_OMP_PARALLEL_MASKED_TASKLOOP_SIMD:
 	case EXEC_OMP_PARALLEL_MASTER:
 	case EXEC_OMP_PARALLEL_MASTER_TASKLOOP:
 	case EXEC_OMP_PARALLEL_MASTER_TASKLOOP_SIMD:
diff --git a/gcc/fortran/st.c b/gcc/fortran/st.c
index 6ae1df612a7..f61f88adcc5 100644
--- a/gcc/fortran/st.c
+++ b/gcc/fortran/st.c
@@ -227,13 +227,19 @@ gfc_free_statement (gfc_code *p)
     case EXEC_OMP_DO_SIMD:
     case EXEC_OMP_LOOP:
     case EXEC_OMP_END_SINGLE:
+    case EXEC_OMP_MASKED_TASKLOOP:
+    case EXEC_OMP_MASKED_TASKLOOP_SIMD:
     case EXEC_OMP_MASTER_TASKLOOP:
     case EXEC_OMP_MASTER_TASKLOOP_SIMD:
     case EXEC_OMP_ORDERED:
+    case EXEC_OMP_MASKED:
     case EXEC_OMP_PARALLEL:
     case EXEC_OMP_PARALLEL_DO:
     case EXEC_OMP_PARALLEL_DO_SIMD:
     case EXEC_OMP_PARALLEL_LOOP:
+    case EXEC_OMP_PARALLEL_MASKED:
+    case EXEC_OMP_PARALLEL_MASKED_TASKLOOP:
+    case EXEC_OMP_PARALLEL_MASKED_TASKLOOP_SIMD:
     case EXEC_OMP_PARALLEL_MASTER:
     case EXEC_OMP_PARALLEL_MASTER_TASKLOOP:
     case EXEC_OMP_PARALLEL_MASTER_TASKLOOP_SIMD:
diff --git a/gcc/fortran/trans-openmp.c b/gcc/fortran/trans-openmp.c
index 3d3b35e9509..623c21fc790 100644
--- a/gcc/fortran/trans-openmp.c
+++ b/gcc/fortran/trans-openmp.c
@@ -4047,6 +4047,21 @@ gfc_trans_omp_clauses (stmtblock_t *block, gfc_omp_clauses *clauses,
       omp_clauses = gfc_trans_add_clause (c, omp_clauses);
     }
 
+  if (clauses->filter)
+    {
+      tree filter;
+
+      gfc_init_se (&se, NULL);
+      gfc_conv_expr (&se, clauses->filter);
+      gfc_add_block_to_block (block, &se.pre);
+      filter = gfc_evaluate_now (se.expr, block);
+      gfc_add_block_to_block (block, &se.post);
+
+      c = build_omp_clause (gfc_get_location (&where), OMP_CLAUSE_FILTER);
+      OMP_CLAUSE_FILTER_EXPR (c) = filter;
+      omp_clauses = gfc_trans_add_clause (c, omp_clauses);
+    }
+
   if (clauses->hint)
     {
       tree hint;
@@ -5389,6 +5404,26 @@ gfc_trans_omp_master (gfc_code *code)
   return build1_v (OMP_MASTER, stmt);
 }
 
+static tree
+gfc_trans_omp_masked (gfc_code *code, gfc_omp_clauses *clauses)
+{
+  stmtblock_t block;
+  tree body = gfc_trans_code (code->block->next);
+  if (IS_EMPTY_STMT (body))
+    return body;
+  if (!clauses)
+    clauses = code->ext.omp_clauses;
+  gfc_start_block (&block);
+  tree omp_clauses = gfc_trans_omp_clauses (&block, clauses, code->loc);
+  tree stmt = make_node (OMP_MASKED);
+  TREE_TYPE (stmt) = void_type_node;
+  OMP_MASKED_BODY (stmt) = body;
+  OMP_MASKED_CLAUSES (stmt) = omp_clauses;
+  gfc_add_expr_to_block (&block, stmt);
+  return gfc_finish_block (&block);
+}
+
+
 static tree
 gfc_trans_omp_ordered (gfc_code *code)
 {
@@ -5432,6 +5467,7 @@ enum
   GFC_OMP_SPLIT_TEAMS,
   GFC_OMP_SPLIT_TARGET,
   GFC_OMP_SPLIT_TASKLOOP,
+  GFC_OMP_SPLIT_MASKED,
   GFC_OMP_SPLIT_NUM
 };
 
@@ -5443,7 +5479,8 @@ enum
   GFC_OMP_MASK_DISTRIBUTE = (1 << GFC_OMP_SPLIT_DISTRIBUTE),
   GFC_OMP_MASK_TEAMS = (1 << GFC_OMP_SPLIT_TEAMS),
   GFC_OMP_MASK_TARGET = (1 << GFC_OMP_SPLIT_TARGET),
-  GFC_OMP_MASK_TASKLOOP = (1 << GFC_OMP_SPLIT_TASKLOOP)
+  GFC_OMP_MASK_TASKLOOP = (1 << GFC_OMP_SPLIT_TASKLOOP),
+  GFC_OMP_MASK_MASKED = (1 << GFC_OMP_SPLIT_MASKED)
 };
 
 /* If a var is in lastprivate/firstprivate/reduction but not in a
@@ -5632,10 +5669,24 @@ gfc_split_omp_clauses (gfc_code *code,
       mask = GFC_OMP_MASK_PARALLEL | GFC_OMP_MASK_DO | GFC_OMP_MASK_SIMD;
       innermost = GFC_OMP_SPLIT_SIMD;
       break;
+    case EXEC_OMP_PARALLEL_MASKED:
+      mask = GFC_OMP_MASK_PARALLEL | GFC_OMP_MASK_MASKED;
+      innermost = GFC_OMP_SPLIT_MASKED;
+      break;
+    case EXEC_OMP_PARALLEL_MASKED_TASKLOOP:
+      mask = (GFC_OMP_MASK_PARALLEL | GFC_OMP_MASK_MASKED
+	      | GFC_OMP_MASK_TASKLOOP | GFC_OMP_MASK_SIMD);
+      innermost = GFC_OMP_SPLIT_TASKLOOP;
+      break;
     case EXEC_OMP_PARALLEL_MASTER_TASKLOOP:
       mask = GFC_OMP_MASK_PARALLEL | GFC_OMP_MASK_TASKLOOP | GFC_OMP_MASK_SIMD;
       innermost = GFC_OMP_SPLIT_TASKLOOP;
       break;
+    case EXEC_OMP_PARALLEL_MASKED_TASKLOOP_SIMD:
+      mask = (GFC_OMP_MASK_PARALLEL | GFC_OMP_MASK_MASKED
+	      | GFC_OMP_MASK_TASKLOOP | GFC_OMP_MASK_SIMD);
+      innermost = GFC_OMP_SPLIT_SIMD;
+      break;
     case EXEC_OMP_PARALLEL_MASTER_TASKLOOP_SIMD:
       mask = GFC_OMP_MASK_PARALLEL | GFC_OMP_MASK_TASKLOOP | GFC_OMP_MASK_SIMD;
       innermost = GFC_OMP_SPLIT_SIMD;
@@ -5692,10 +5743,18 @@ gfc_split_omp_clauses (gfc_code *code,
       mask = GFC_OMP_MASK_TARGET | GFC_OMP_MASK_TEAMS | GFC_OMP_MASK_DO;
       innermost = GFC_OMP_SPLIT_DO;
       break;
+    case EXEC_OMP_MASKED_TASKLOOP:
+      mask = GFC_OMP_SPLIT_MASKED | GFC_OMP_SPLIT_TASKLOOP;
+      innermost = GFC_OMP_SPLIT_TASKLOOP;
+      break;
     case EXEC_OMP_MASTER_TASKLOOP:
     case EXEC_OMP_TASKLOOP:
       innermost = GFC_OMP_SPLIT_TASKLOOP;
       break;
+    case EXEC_OMP_MASKED_TASKLOOP_SIMD:
+      mask = GFC_OMP_MASK_MASKED | GFC_OMP_MASK_TASKLOOP | GFC_OMP_MASK_SIMD;
+      innermost = GFC_OMP_SPLIT_SIMD;
+      break;
     case EXEC_OMP_MASTER_TASKLOOP_SIMD:
     case EXEC_OMP_TASKLOOP_SIMD:
       mask = GFC_OMP_MASK_TASKLOOP | GFC_OMP_MASK_SIMD;
@@ -5814,6 +5873,8 @@ gfc_split_omp_clauses (gfc_code *code,
 	  clausesa[GFC_OMP_SPLIT_PARALLEL].if_expr
 	    = code->ext.omp_clauses->if_expr;
 	}
+      if (mask & GFC_OMP_MASK_MASKED)
+	clausesa[GFC_OMP_SPLIT_MASKED].filter = code->ext.omp_clauses->filter;
       if ((mask & GFC_OMP_MASK_DO) && !is_loop)
 	{
 	  /* First the clauses that are unique to some constructs.  */
@@ -5896,16 +5957,18 @@ gfc_split_omp_clauses (gfc_code *code,
 	  clausesa[GFC_OMP_SPLIT_TASKLOOP].collapse
 	    = code->ext.omp_clauses->collapse;
 	}
-      /* Private clause is supported on all constructs,
-	 it is enough to put it on the innermost one.  For
+      /* Private clause is supported on all constructs but master/masked,
+	 it is enough to put it on the innermost one except for master/masked.  For
 	 !$ omp parallel do put it on parallel though,
 	 as that's what we did for OpenMP 3.1.  */
-      clausesa[innermost == GFC_OMP_SPLIT_DO && !is_loop
+      clausesa[((innermost == GFC_OMP_SPLIT_DO && !is_loop)
+		|| code->op == EXEC_OMP_PARALLEL_MASTER
+		|| code->op == EXEC_OMP_PARALLEL_MASKED)
 	       ? (int) GFC_OMP_SPLIT_PARALLEL
 	       : innermost].lists[OMP_LIST_PRIVATE]
 	= code->ext.omp_clauses->lists[OMP_LIST_PRIVATE];
       /* Firstprivate clause is supported on all constructs but
-	 simd.  Put it on the outermost of those and duplicate
+	 simd and masked/master.  Put it on the outermost of those and duplicate
 	 on parallel and teams.  */
       if (mask & GFC_OMP_MASK_TARGET)
 	clausesa[GFC_OMP_SPLIT_TARGET].lists[OMP_LIST_FIRSTPRIVATE]
@@ -6588,43 +6651,66 @@ gfc_trans_omp_taskloop (gfc_code *code, gfc_exec_op op)
 }
 
 static tree
-gfc_trans_omp_master_taskloop (gfc_code *code, gfc_exec_op op)
+gfc_trans_omp_master_masked_taskloop (gfc_code *code, gfc_exec_op op)
 {
+  gfc_omp_clauses clausesa[GFC_OMP_SPLIT_NUM];
   stmtblock_t block;
   tree stmt;
 
-  gfc_start_block (&block);
+  if (op != EXEC_OMP_MASTER_TASKLOOP_SIMD
+      && code->op != EXEC_OMP_MASTER_TASKLOOP)
+    gfc_split_omp_clauses (code, clausesa);
+
   pushlevel ();
-  if (op == EXEC_OMP_MASTER_TASKLOOP_SIMD)
+  if (op == EXEC_OMP_MASKED_TASKLOOP_SIMD
+      || op == EXEC_OMP_MASTER_TASKLOOP_SIMD)
     stmt = gfc_trans_omp_taskloop (code, EXEC_OMP_TASKLOOP_SIMD);
   else
     {
-      gfc_omp_clauses clausesa[GFC_OMP_SPLIT_NUM];
-      gcc_assert (op == EXEC_OMP_MASTER_TASKLOOP);
-      if (op != code->op)
-	gfc_split_omp_clauses (code, clausesa);
+      gcc_assert (op == EXEC_OMP_MASKED_TASKLOOP
+		  || op == EXEC_OMP_MASTER_TASKLOOP);
       stmt = gfc_trans_omp_do (code, EXEC_OMP_TASKLOOP, NULL,
-			       op != code->op
+			       code->op != EXEC_OMP_MASTER_TASKLOOP
 			       ? &clausesa[GFC_OMP_SPLIT_TASKLOOP]
 			       : code->ext.omp_clauses, NULL);
-      if (op != code->op)
-	gfc_free_split_omp_clauses (code, clausesa);
     }
   if (TREE_CODE (stmt) != BIND_EXPR)
     stmt = build3_v (BIND_EXPR, NULL, stmt, poplevel (1, 0));
   else
     poplevel (0, 0);
-  stmt = build1_v (OMP_MASTER, stmt);
-  gfc_add_expr_to_block (&block, stmt);
+  gfc_start_block (&block);
+  if (op == EXEC_OMP_MASKED_TASKLOOP || op == EXEC_OMP_MASKED_TASKLOOP_SIMD)
+    {
+      tree clauses = gfc_trans_omp_clauses (&block,
+					    &clausesa[GFC_OMP_SPLIT_MASKED],
+					    code->loc);
+      tree msk = make_node (OMP_MASKED);
+      TREE_TYPE (msk) = void_type_node;
+      OMP_MASKED_BODY (msk) = stmt;
+      OMP_MASKED_CLAUSES (msk) = clauses;
+      OMP_MASKED_COMBINED (msk) = 1;
+      gfc_add_expr_to_block (&block, msk);
+    }
+  else
+    {
+      gcc_assert (op == EXEC_OMP_MASTER_TASKLOOP
+		  || op == EXEC_OMP_MASTER_TASKLOOP_SIMD);
+      stmt = build1_v (OMP_MASTER, stmt);
+      gfc_add_expr_to_block (&block, stmt);
+    }
+  if (op != EXEC_OMP_MASTER_TASKLOOP_SIMD
+      && code->op != EXEC_OMP_MASTER_TASKLOOP)
+    gfc_free_split_omp_clauses (code, clausesa);
   return gfc_finish_block (&block);
 }
 
 static tree
-gfc_trans_omp_parallel_master (gfc_code *code)
+gfc_trans_omp_parallel_master_masked (gfc_code *code)
 {
   stmtblock_t block;
   tree stmt, omp_clauses;
   gfc_omp_clauses clausesa[GFC_OMP_SPLIT_NUM];
+  bool parallel_combined = false;
 
   if (code->op != EXEC_OMP_PARALLEL_MASTER)
     gfc_split_omp_clauses (code, clausesa);
@@ -6635,19 +6721,33 @@ gfc_trans_omp_parallel_master (gfc_code *code)
 				       ? code->ext.omp_clauses
 				       : &clausesa[GFC_OMP_SPLIT_PARALLEL],
 				       code->loc);
-  if (code->op != EXEC_OMP_PARALLEL_MASTER)
-    gfc_free_split_omp_clauses (code, clausesa);
   pushlevel ();
   if (code->op == EXEC_OMP_PARALLEL_MASTER)
     stmt = gfc_trans_omp_master (code);
+  else if (code->op == EXEC_OMP_PARALLEL_MASKED)
+    stmt = gfc_trans_omp_masked (code, &clausesa[GFC_OMP_SPLIT_MASKED]);
   else
     {
-      gcc_assert (code->op == EXEC_OMP_PARALLEL_MASTER_TASKLOOP
-		  || code->op == EXEC_OMP_PARALLEL_MASTER_TASKLOOP_SIMD);
-      gfc_exec_op op = (code->op == EXEC_OMP_PARALLEL_MASTER_TASKLOOP
-			? EXEC_OMP_MASTER_TASKLOOP
-			: EXEC_OMP_MASTER_TASKLOOP_SIMD);
-      stmt = gfc_trans_omp_master_taskloop (code, op);
+      gfc_exec_op op;
+      switch (code->op)
+	{
+	case EXEC_OMP_PARALLEL_MASKED_TASKLOOP:
+	  op = EXEC_OMP_MASKED_TASKLOOP;
+	  break;
+	case EXEC_OMP_PARALLEL_MASKED_TASKLOOP_SIMD:
+	  op = EXEC_OMP_MASKED_TASKLOOP_SIMD;
+	  break;
+	case EXEC_OMP_PARALLEL_MASTER_TASKLOOP:
+	  op = EXEC_OMP_MASTER_TASKLOOP;
+	  break;
+	case EXEC_OMP_PARALLEL_MASTER_TASKLOOP_SIMD:
+	  op = EXEC_OMP_MASTER_TASKLOOP_SIMD;
+	  break;
+	default:
+	  gcc_unreachable ();
+	}
+      stmt = gfc_trans_omp_master_masked_taskloop (code, op);
+      parallel_combined = true;
     }
   if (TREE_CODE (stmt) != BIND_EXPR)
     stmt = build3_v (BIND_EXPR, NULL, stmt, poplevel (1, 0));
@@ -6655,8 +6755,19 @@ gfc_trans_omp_parallel_master (gfc_code *code)
     poplevel (0, 0);
   stmt = build2_loc (gfc_get_location (&code->loc), OMP_PARALLEL,
 		     void_type_node, stmt, omp_clauses);
-  OMP_PARALLEL_COMBINED (stmt) = 1;
+  /* masked does have just filter clause, but during gimplification
+     isn't represented by a gimplification omp context, so for
+       !$omp parallel masked don't set OMP_PARALLEL_COMBINED,
+     so that
+       !$omp parallel masked
+       !$omp taskloop simd lastprivate (x)
+     isn't confused with
+       !$omp parallel masked taskloop simd lastprivate (x)  */
+  if (parallel_combined)
+    OMP_PARALLEL_COMBINED (stmt) = 1;
   gfc_add_expr_to_block (&block, stmt);
+  if (code->op != EXEC_OMP_PARALLEL_MASTER)
+    gfc_free_split_omp_clauses (code, clausesa);
   return gfc_finish_block (&block);
 }
 
@@ -6969,11 +7080,15 @@ gfc_trans_omp_directive (gfc_code *code)
       return gfc_trans_omp_do_simd (code, NULL, NULL, NULL_TREE);
     case EXEC_OMP_FLUSH:
       return gfc_trans_omp_flush (code);
+    case EXEC_OMP_MASKED:
+      return gfc_trans_omp_masked (code, NULL);
     case EXEC_OMP_MASTER:
       return gfc_trans_omp_master (code);
+    case EXEC_OMP_MASKED_TASKLOOP:
+    case EXEC_OMP_MASKED_TASKLOOP_SIMD:
     case EXEC_OMP_MASTER_TASKLOOP:
     case EXEC_OMP_MASTER_TASKLOOP_SIMD:
-      return gfc_trans_omp_master_taskloop (code, code->op);
+      return gfc_trans_omp_master_masked_taskloop (code, code->op);
     case EXEC_OMP_ORDERED:
       return gfc_trans_omp_ordered (code);
     case EXEC_OMP_PARALLEL:
@@ -6984,10 +7099,13 @@ gfc_trans_omp_directive (gfc_code *code)
       return gfc_trans_omp_parallel_do (code, true, NULL, NULL);
     case EXEC_OMP_PARALLEL_DO_SIMD:
       return gfc_trans_omp_parallel_do_simd (code, NULL, NULL);
+    case EXEC_OMP_PARALLEL_MASKED:
+    case EXEC_OMP_PARALLEL_MASKED_TASKLOOP:
+    case EXEC_OMP_PARALLEL_MASKED_TASKLOOP_SIMD:
     case EXEC_OMP_PARALLEL_MASTER:
     case EXEC_OMP_PARALLEL_MASTER_TASKLOOP:
     case EXEC_OMP_PARALLEL_MASTER_TASKLOOP_SIMD:
-      return gfc_trans_omp_parallel_master (code);
+      return gfc_trans_omp_parallel_master_masked (code);
     case EXEC_OMP_PARALLEL_SECTIONS:
       return gfc_trans_omp_parallel_sections (code);
     case EXEC_OMP_PARALLEL_WORKSHARE:
diff --git a/gcc/fortran/trans.c b/gcc/fortran/trans.c
index 275d6a28f1c..ce5b2f8d594 100644
--- a/gcc/fortran/trans.c
+++ b/gcc/fortran/trans.c
@@ -2156,6 +2156,9 @@ trans_code (gfc_code * code, tree cond)
 	case EXEC_OMP_DO_SIMD:
 	case EXEC_OMP_LOOP:
 	case EXEC_OMP_FLUSH:
+	case EXEC_OMP_MASKED:
+	case EXEC_OMP_MASKED_TASKLOOP:
+	case EXEC_OMP_MASKED_TASKLOOP_SIMD:
 	case EXEC_OMP_MASTER:
 	case EXEC_OMP_MASTER_TASKLOOP:
 	case EXEC_OMP_MASTER_TASKLOOP_SIMD:
@@ -2164,6 +2167,9 @@ trans_code (gfc_code * code, tree cond)
 	case EXEC_OMP_PARALLEL_DO:
 	case EXEC_OMP_PARALLEL_DO_SIMD:
 	case EXEC_OMP_PARALLEL_LOOP:
+	case EXEC_OMP_PARALLEL_MASKED:
+	case EXEC_OMP_PARALLEL_MASKED_TASKLOOP:
+	case EXEC_OMP_PARALLEL_MASKED_TASKLOOP_SIMD:
 	case EXEC_OMP_PARALLEL_MASTER:
 	case EXEC_OMP_PARALLEL_MASTER_TASKLOOP:
 	case EXEC_OMP_PARALLEL_MASTER_TASKLOOP_SIMD:
diff --git a/gcc/testsuite/gfortran.dg/gomp/masked-1.f90 b/gcc/testsuite/gfortran.dg/gomp/masked-1.f90
new file mode 100644
index 00000000000..1bd61760ced
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/gomp/masked-1.f90
@@ -0,0 +1,94 @@
+! { dg-additional-options "-ffree-line-length-none" }
+subroutine foo (x, a)
+  implicit none
+  integer, value :: x
+  integer, contiguous :: a(0:)
+  external :: bar
+  integer :: i
+
+  !$omp masked
+   call bar ()
+  !$omp end masked
+
+  !$omp masked filter (0)
+   call bar ()
+  !$omp end masked
+
+  !$omp masked filter (7)
+   call bar ()
+  !$omp end masked
+
+  !$omp masked filter (x)
+   call bar ()
+  !$omp end masked
+
+  !$omp masked taskloop simd filter (x) grainsize (12) simdlen (4)
+    do i = 0, 127
+      a(i) = i
+    end do
+  !$omp end masked taskloop simd
+
+  !$omp parallel masked filter (x) firstprivate (x)
+    call bar ()
+  !$omp end parallel masked
+
+  !$omp masked
+    !$omp masked filter (0)
+      !$omp masked filter (x)
+      !$omp end masked
+    !$omp end masked
+  !$omp end masked
+end
+
+subroutine foobar (d, f, fi, p, s, g, i1, i2, l, ll, nth, ntm, pp, q, r, r2)
+  implicit none (type, external)
+  logical :: i1, i2, fi
+  integer :: i, d, f, p, s, g, l, ll, nth, ntm, pp, q, r, r2
+  allocatable :: q
+  integer, save :: t
+  !$omp threadprivate (t)
+
+  !$omp parallel masked &
+  !$omp&  private (p) firstprivate (f) if (parallel: i2) default(shared) shared(s) reduction(+:r) &
+  !$omp&  num_threads (nth) proc_bind(spread) copyin(t) filter (d)  ! allocate (f)
+    !
+  !$omp end parallel masked
+
+  !$omp taskgroup task_reduction (+:r2)  ! allocate (r2)
+    !$omp masked taskloop &
+    !$omp&  private (p) firstprivate (f) lastprivate (l) shared (s) default(shared) grainsize (g) collapse(1) untied if(taskloop: i1) final(fi) mergeable priority (pp) &
+    !$omp&  reduction(default, +:r) in_reduction(+:r2) filter (d)  ! allocate (f)
+    do i = 0, 63
+      ll = ll + 1
+    end do
+    !$omp end masked taskloop
+  !$omp end taskgroup
+
+  !$omp taskgroup task_reduction (+:r2)  ! allocate (r2)
+    !$omp masked taskloop simd &
+    !$omp&  private (p) firstprivate (f) lastprivate (l) shared (s) default(shared) grainsize (g) collapse(1) untied if(taskloop: i1) if(simd: i2) final(fi) mergeable priority (pp) &
+    !$omp&  safelen(8) simdlen(4) linear(ll: 1) aligned(q: 32) reduction(default, +:r) in_reduction(+:r2) nontemporal(ntm) &
+    !$omp&  order(concurrent) filter (d)  !  allocate (f)
+    do i = 0, 63
+      ll = ll + 1
+    end do
+    !$omp end masked taskloop simd
+  !$omp end taskgroup
+
+  !$omp parallel masked taskloop &
+    !$omp&  private (p) firstprivate (f) lastprivate (l) shared (s) default(shared) grainsize (g) collapse(1) untied if(taskloop: i1) final(fi) mergeable priority (pp) &
+    !$omp&  reduction(default, +:r) if (parallel: i2) num_threads (nth) proc_bind(spread) copyin(t) filter (d)  ! allocate (f)
+    do i = 0, 63
+      ll = ll + 1
+    end do
+  !$omp end parallel masked taskloop
+
+  !$omp parallel masked taskloop simd &
+    !$omp&  private (p) firstprivate (f) lastprivate (l) shared (s) default(shared) grainsize (g) collapse(1) untied if(taskloop: i1) if(simd: i2) final(fi) mergeable priority (pp) &
+    !$omp&  safelen(8) simdlen(4) linear(ll: 1) aligned(q: 32) reduction(default, +:r) nontemporal(ntm) if (parallel: i2) num_threads (nth) proc_bind(spread) copyin(t) &
+    !$omp&  order(concurrent) filter (d)  ! allocate (f)
+    do i = 0, 63
+      ll = ll + 1
+    end do
+  !$omp end parallel masked taskloop simd
+end subroutine
diff --git a/gcc/testsuite/gfortran.dg/gomp/masked-2.f90 b/gcc/testsuite/gfortran.dg/gomp/masked-2.f90
new file mode 100644
index 00000000000..95ef78c0664
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/gomp/masked-2.f90
@@ -0,0 +1,46 @@
+module m
+  implicit none (external, type)
+  type t
+  end type t
+contains
+subroutine foo (x, y, z, a)
+  external :: bar
+  type(t) :: x
+  integer :: y
+  real :: z
+  integer :: a(4)
+
+  !$omp masked filter (x)  ! { dg-error "FILTER clause at .1. requires a scalar INTEGER expression" }
+    call bar ()
+  !$omp end masked
+
+  !$omp masked filter (y)  ! OK
+    call bar ()
+  !$omp end masked
+
+  !$omp masked filter (z)  ! { dg-error "FILTER clause at .1. requires a scalar INTEGER expression" }
+    call bar ()
+  !$omp end masked
+
+  !$omp masked filter (a)  ! { dg-error "FILTER clause at .1. requires a scalar INTEGER expression" }
+    call bar ()
+  !$omp end masked
+
+  !$omp masked filter (0.0)  ! { dg-error "FILTER clause at .1. requires a scalar INTEGER expression" }
+    call bar ()
+  !$omp end masked
+
+  !$omp masked filter ([1])  ! { dg-error "FILTER clause at .1. requires a scalar INTEGER expression" }
+    call bar ()
+  !$omp end masked
+
+  !$omp masked filter (-1)  ! { dg-warning "INTEGER expression of FILTER clause at .1. must be non-negative" }
+    call bar ()
+  !$omp end masked
+end
+end module
+
+subroutine bar
+  !$omp masked filter (0) filter (0)  ! { dg-error "27: Failed to match clause" }
+    call foobar
+end
diff --git a/gcc/testsuite/gfortran.dg/gomp/masked-3.f90 b/gcc/testsuite/gfortran.dg/gomp/masked-3.f90
new file mode 100644
index 00000000000..49c633d21a5
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/gomp/masked-3.f90
@@ -0,0 +1,12 @@
+subroutine foo
+
+  !$omp masked
+     goto 55  ! { dg-error "invalid branch to/from OpenMP structured block" }
+              ! { dg-warning "Legacy Extension: Label at .1. is not in the same block as the GOTO statement" "" { target *-*-* } .-1 }
+  !$omp end masked
+
+  !$omp masked
+55  continue  ! { dg-warning "Legacy Extension: Label at .1. is not in the same block as the GOTO statement" }
+    return    ! { dg-error "invalid branch to/from OpenMP structured block" }
+  !$omp end masked
+end subroutine foo
diff --git a/gcc/testsuite/gfortran.dg/gomp/masked-combined-1.f90 b/gcc/testsuite/gfortran.dg/gomp/masked-combined-1.f90
new file mode 100644
index 00000000000..23ffb084ee1
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/gomp/masked-combined-1.f90
@@ -0,0 +1,65 @@
+subroutine foo (a, f)
+  implicit none (type, external)
+  interface
+    subroutine bar (x)
+      integer :: x
+    end subroutine
+  end interface
+
+  integer, value :: f
+  integer, contiguous :: a(0:)
+  integer :: i, j, k, u, v, w, x, y, z
+
+  !$omp parallel masked default(none) private (k) filter (f) firstprivate (f)
+    call bar (k)
+  !$omp end parallel masked
+
+  !$omp parallel masked default(none) private (k)
+    call bar (k)
+  !$omp end parallel masked
+  
+  !$omp parallel default(none) firstprivate(a, f) shared(x, y, z)
+    !$omp masked taskloop reduction (+:x) default(none) firstprivate(a) filter (f)
+      do i = 0, 63
+        x = x + a(i)
+      end do
+    !$omp end masked taskloop
+    !$omp masked taskloop simd reduction (+:y) default(none) firstprivate(a) private (i) filter (f)
+      do i = 0, 63
+        y = y + a(i)
+      end do
+    !$omp end masked taskloop simd
+    !$omp masked taskloop simd reduction (+:y) default(none) firstprivate(a) private (i)
+      do i = 0, 63
+        y = y + a(i)
+      end do
+    !$omp end masked taskloop simd
+    !$omp masked taskloop simd collapse(2) reduction (+:z) default(none) firstprivate(a) private (i, j) filter (f)
+      do j = 0, 0
+        do i = 0, 63
+          z = z + a(i)
+        end do
+      end do
+    !$omp end masked taskloop simd
+  !$omp end parallel
+
+  !$omp parallel masked taskloop reduction (+:u) default(none) firstprivate(a, f) filter (f)
+    do i = 0, 63
+      u = u + a(i)
+    end do
+  !$omp end parallel masked taskloop
+
+  !$omp parallel masked taskloop simd reduction (+:v) default(none) firstprivate(a, f) filter (f)
+    do i = 0, 63
+      v = v + a(i)
+    end do
+  !$omp end parallel masked taskloop simd
+
+  !$omp parallel masked taskloop simd collapse(2) reduction (+:w) default(none) firstprivate(a, f) filter (f)
+    do j = 0, 0
+      do i = 0, 63
+        w = w + a(i)
+      end do
+    end do
+  !$omp end parallel masked taskloop simd
+end
diff --git a/gcc/testsuite/gfortran.dg/gomp/masked-combined-2.f90 b/gcc/testsuite/gfortran.dg/gomp/masked-combined-2.f90
new file mode 100644
index 00000000000..c94425fd0bd
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/gomp/masked-combined-2.f90
@@ -0,0 +1,24 @@
+subroutine foo (a)
+  implicit none (external, type)
+  integer, contiguous :: a(0:)
+  integer :: i, r, s
+  r = 0; s = 0
+
+  ! In 'parallel masked taskloop', in_reduction is not permitted.
+
+  !$omp taskgroup task_reduction(+:r)
+    !$omp parallel masked taskloop in_reduction(+:r)  ! { dg-error "36: Failed to match clause" }
+      do i = 0, 63
+        r = r + a(i)
+      end do
+    !!$omp end parallel masked taskloop
+  !$omp end taskgroup
+
+  !$omp taskgroup task_reduction(+:s)
+    !$omp parallel masked taskloop simd in_reduction(+:s)  ! { dg-error "41: Failed to match clause" }
+      do i = 0, 63
+        s = s + a(i)
+      end do
+    !!$omp end parallel masked taskloop simd
+  !$omp end taskgroup
+end
diff --git a/libgomp/testsuite/libgomp.fortran/masked-1.f90 b/libgomp/testsuite/libgomp.fortran/masked-1.f90
new file mode 100644
index 00000000000..6b7ebc7b828
--- /dev/null
+++ b/libgomp/testsuite/libgomp.fortran/masked-1.f90
@@ -0,0 +1,119 @@
+module m
+  use omp_lib
+  implicit none (type, external)
+contains
+  subroutine foo (x, a)
+    integer, value :: x
+    integer, contiguous :: a(0:)
+    integer :: i
+
+    !$omp masked
+      if (omp_get_thread_num () /= 0) &
+        stop 1
+      a(128) = a(128) + 1
+    !$omp end masked
+
+    !$omp masked filter (0)
+      if (omp_get_thread_num () /= 0) &
+        stop 2
+      a(129) = a(129) + 1
+    !$omp end masked
+
+    !$omp masked filter (7)
+      if (omp_get_thread_num () /= 7) &
+        stop 3
+      a(130) = a(130) + 1
+    !$omp end masked
+
+    !$omp masked filter (x)
+      if (omp_get_thread_num () /= x) &
+        stop 4
+      a(131) = a(131) + 1
+    !$omp end masked
+
+    !$omp masked taskloop simd filter (x) shared(a) grainsize (12) simdlen (4)
+      do i = 0, 127
+        a(i) = a(i) + i
+      end do
+    !$omp end masked taskloop simd
+  end
+end
+
+program main
+  use m
+  implicit none (type, external)
+  integer :: i
+  integer :: a(0:135)
+
+  a = 0
+
+  !$omp parallel num_threads (4)
+    call foo (4, a)
+  !$omp end parallel
+  do i = 0, 127
+    if (a(i) /= 0) &
+      stop 5
+  end do
+  if (a(128) /= 1 .or. a(129) /= 1 .or. a(130) /= 0 .or. a(131) /= 0) &
+    stop 6
+
+  !$omp parallel num_threads (4)
+    call foo (3, a)
+  !$omp end parallel
+  do i = 0, 127
+    if (a(i) /= i) &
+      stop 7
+  end do
+  if (a(128) /= 2 .or. a(129) /= 2 .or. a(130) /= 0 .or. a(131) /= 1) &
+    stop 8
+
+  !$omp parallel num_threads (8)
+    call foo (8, a)
+  !$omp end parallel
+  do i = 0, 127
+    if (a(i) /= i) &
+      stop 9
+  end do
+  if (a(128) /= 3 .or. a(129) /= 3 .or. a(130) /= 1 .or. a(131) /= 1) &
+    stop 10
+
+  !$omp parallel num_threads (8)
+    call foo (6, a)
+  !$omp end parallel
+  do i = 0, 127
+    if (a(i) /= 2 * i) &
+      stop 11
+  end do
+  if (a(128) /= 4 .or. a(129) /= 4 .or. a(130) /= 2 .or. a(131) /= 2) &
+    stop 12
+
+  do i = 0, 7
+    a(i) = 0
+  end do
+  ! The filter expression can evaluate to different values in different threads.
+  !$omp parallel masked num_threads (8) filter (omp_get_thread_num () + 1)
+    a(omp_get_thread_num ()) = a(omp_get_thread_num ()) + 1
+  !$omp end parallel masked
+  do i = 0, 7
+    if (a(i) /= 0) &
+      stop 13
+  end do
+
+  ! And multiple threads can be filtered.
+  !$omp parallel masked num_threads (8) filter (iand (omp_get_thread_num (), not(1)))
+    a(omp_get_thread_num ()) = a(omp_get_thread_num ()) + 1
+  !$omp end parallel masked
+  do i = 0, 7
+    block
+      integer :: j
+      j = iand (i, 1)
+      if (j /= 0) then
+        j = 0
+      else
+        j = 1
+      end if
+      if (a(i) /= j) &
+        stop 14
+    end block
+  end do
+end program main

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

* Re: [committed] openmp: Add support for OpenMP 5.1 masked construct
  2021-08-12 20:48 [committed] openmp: Add support for OpenMP 5.1 masked construct Jakub Jelinek
  2021-08-13 14:37 ` [Patch] Fortran/OpenMP: Add support for OpenMP 5.1 masked construct (was: Re: [committed] openmp: Add support for OpenMP 5.1 masked construct) Tobias Burnus
@ 2021-08-13 21:05 ` Thomas Schwinge
  1 sibling, 0 replies; 5+ messages in thread
From: Thomas Schwinge @ 2021-08-13 21:05 UTC (permalink / raw)
  To: Jakub Jelinek, gcc-patches

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

Hi!

On 2021-08-12T22:48:33+0200, Jakub Jelinek via Gcc-patches <gcc-patches@gcc.gnu.org> wrote:
> The patch also contains something I should have done much earlier,

... and as its own commit...  ;-|

> for clauses that accept some integral expression where we only care
> about the value, forces during gimplification that value into
> either a min invariant (as before), SSA_NAME or a fresh temporary,
> but never e.g. a user VAR_DECL, so that for those clauses we don't
> need to worry about adjusting it.

> --- gcc/gimplify.c.jj 2021-08-11 23:43:45.897077306 +0200
> +++ gcc/gimplify.c    2021-08-12 14:47:57.451971003 +0200

> @@ -10110,9 +10112,20 @@ gimplify_scan_omp_clauses (tree *list_p,
>       case OMP_CLAUSE_VECTOR_LENGTH:
>       case OMP_CLAUSE_WORKER:
>       case OMP_CLAUSE_VECTOR:
> -       if (gimplify_expr (&OMP_CLAUSE_OPERAND (c, 0), pre_p, NULL,
> -                          is_gimple_val, fb_rvalue) == GS_ERROR)
> -         remove = true;
> +       if (OMP_CLAUSE_OPERAND (c, 0)
> +           && !is_gimple_min_invariant (OMP_CLAUSE_OPERAND (c, 0)))
> +         {
> +           if (error_operand_p (OMP_CLAUSE_OPERAND (c, 0)))
> +             {
> +               remove = true;
> +               break;
> +             }
> +           /* All these clauses care about value, not a particular decl,
> +              so try to force it into a SSA_NAME or fresh temporary.  */
> +           OMP_CLAUSE_OPERAND (c, 0)
> +             = get_initialized_tmp_var (OMP_CLAUSE_OPERAND (c, 0),
> +                                        pre_p, NULL, true);
> +         }
>         break;

In addition to the adjustments included here:

> --- gcc/testsuite/c-c++-common/goacc/uninit-if-clause.c.jj    2020-07-28 15:39:09.990756475 +0200
> +++ gcc/testsuite/c-c++-common/goacc/uninit-if-clause.c       2021-08-12 15:01:31.299065897 +0200

> -/* { dg-excess-errors "PR70392" { xfail c++ } } */

(I set the PR as resolved.)

> -  #pragma acc parallel if(b) /* { dg-warning "is used uninitialized" "" { xfail c++ } } */
> +  #pragma acc parallel if(b) /* { dg-warning "is used uninitialized" } */
> [...]

> --- gcc/testsuite/gfortran.dg/goacc/host_data-tree.f95.jj     2020-01-12 11:54:38.237385890 +0100
> +++ gcc/testsuite/gfortran.dg/goacc/host_data-tree.f95        2021-08-12 15:04:02.269980316 +0200

> -  ! { dg-final { scan-tree-dump-times "(?n)#pragma omp target oacc_host_data use_device_ptr\\(p\\) if\\(D\\.\[0-9\]+\\)$" 1 "gimple" } }
> +  ! { dg-final { scan-tree-dump-times "(?n)#pragma omp target oacc_host_data use_device_ptr\\(p\\) if\\((?:D\\.|_)\[0-9\]+\\)$" 1 "gimple" } }

> -  ! { dg-final { scan-tree-dump-times "(?n)#pragma omp target oacc_host_data use_device_ptr\\(if_present:p\\) if\\(D\\.\[0-9\]+\\) if_present$" 1 "gimple" } }
> +  ! { dg-final { scan-tree-dump-times "(?n)#pragma omp target oacc_host_data use_device_ptr\\(if_present:p\\) if\\((?:D\\.|_)\[0-9\]+\\) if_present$" 1 "gimple" } }

> --- gcc/testsuite/gfortran.dg/goacc/kernels-tree.f95.jj       2021-04-19 17:43:20.260417067 +0200
> +++ gcc/testsuite/gfortran.dg/goacc/kernels-tree.f95  2021-08-12 15:04:56.637229260 +0200

> -! { dg-final { scan-tree-dump-times {(?n)#pragma omp target oacc_data_kernels if\(D\.[0-9]+\)$} 1 "omp_oacc_kernels_decompose" } }
> -! { dg-final { scan-tree-dump-times {(?n)#pragma omp target oacc_parallel_kernels_gang_single num_gangs\(1\) if\(D\.[0-9]+\) async\(-1\)$} 1 "omp_oacc_kernels_decompose" } }
> +! { dg-final { scan-tree-dump-times {(?n)#pragma omp target oacc_data_kernels if\((?:D\.|_)[0-9]+\)$} 1 "omp_oacc_kernels_decompose" } }
> +! { dg-final { scan-tree-dump-times {(?n)#pragma omp target oacc_parallel_kernels_gang_single num_gangs\(1\) if\((?:D\.|_)[0-9]+\) async\(-1\)$} 1 "omp_oacc_kernels_decompose" } }

... we need to "Adjust 'libgomp.oacc-c-c++-common/static-variable-1.c'"
in (only) one case, too; pushed to master branch in
commit 2cc65fcbd470de8240f64317629a60fab879dfc5, see attached.

Non-offloading testing is only run with '-O2' but not '-O0'
('{ ! __OPTIMIZE__ }' selector); that's why you didn't see this, I
suppose.


Grüße
 Thomas


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

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: 0001-Adjust-libgomp.oacc-c-c-common-static-variable-1.c.patch --]
[-- Type: text/x-diff, Size: 2006 bytes --]

From 2cc65fcbd470de8240f64317629a60fab879dfc5 Mon Sep 17 00:00:00 2001
From: Thomas Schwinge <thomas@codesourcery.com>
Date: Fri, 13 Aug 2021 10:23:30 +0200
Subject: [PATCH] Adjust 'libgomp.oacc-c-c++-common/static-variable-1.c'

... for 'gcc/gimplify.c:gimplify_scan_omp_clauses' changes in recent
commit d0befed793b94f3f407be44e6f69f81a02f5f073 "openmp: Add support
for OpenMP 5.1 masked construct".

	libgomp/
	* testsuite/libgomp.oacc-c-c++-common/static-variable-1.c: Adjust.
---
 .../testsuite/libgomp.oacc-c-c++-common/static-variable-1.c  | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/libgomp/testsuite/libgomp.oacc-c-c++-common/static-variable-1.c b/libgomp/testsuite/libgomp.oacc-c-c++-common/static-variable-1.c
index ceb2c88d3e5..69df0a6dd1d 100644
--- a/libgomp/testsuite/libgomp.oacc-c-c++-common/static-variable-1.c
+++ b/libgomp/testsuite/libgomp.oacc-c-c++-common/static-variable-1.c
@@ -298,7 +298,10 @@ static void t2(void)
 
 #pragma acc data \
   copy(results_1, results_2, results_3)
-  /* { dg-note {variable 'i' declared in block isn't candidate for adjusting OpenACC privatization level: not addressable} "" { target *-*-* } .-2 } */
+  /* { dg-note {variable 'num_gangs_request_1\.[0-9]+' declared in block isn't candidate for adjusting OpenACC privatization level: not addressable} "" { target { c && { ! __OPTIMIZE__ } } } .-2 } */
+  /* { dg-note {variable 'num_gangs_request_2\.[0-9]+' declared in block isn't candidate for adjusting OpenACC privatization level: not addressable} "" { target { c && { ! __OPTIMIZE__ } } } .-3 } */
+  /* { dg-note {variable 'num_gangs_request_3\.[0-9]+' declared in block isn't candidate for adjusting OpenACC privatization level: not addressable} "" { target { c && { ! __OPTIMIZE__ } } } .-4 } */
+  /* { dg-note {variable 'i' declared in block isn't candidate for adjusting OpenACC privatization level: not addressable} "" { target *-*-* } .-5 } */
   {
     for (int i = 0; i < i_limit; ++i)
       {
-- 
2.30.2


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

* Re: [Patch] Fortran/OpenMP: Add support for OpenMP 5.1 masked construct (was: Re: [committed] openmp: Add support for OpenMP 5.1 masked construct)
  2021-08-13 18:52   ` Tobias Burnus
@ 2021-08-16  7:17     ` Jakub Jelinek
  0 siblings, 0 replies; 5+ messages in thread
From: Jakub Jelinek @ 2021-08-16  7:17 UTC (permalink / raw)
  To: Tobias Burnus; +Cc: gcc-patches, fortran

On Fri, Aug 13, 2021 at 08:52:34PM +0200, Tobias Burnus wrote:
> gcc/fortran/ChangeLog:
> 
> 	* dump-parse-tree.c (show_omp_clauses): Handle 'filter' clause.
> 	(show_omp_node, show_code_node): Handle (combined) omp masked construct.
> 	* frontend-passes.c (gfc_code_walker): Likewise.
> 	* gfortran.h (enum gfc_statement): Add ST_OMP_*_MASKED*.
> 	(enum gfc_exec_op): Add EXEC_OMP_*_MASKED*.
> 	* match.h (gfc_match_omp_masked, gfc_match_omp_masked_taskloop,
> 	gfc_match_omp_masked_taskloop_simd, gfc_match_omp_parallel_masked,
> 	gfc_match_omp_parallel_masked_taskloop,
> 	gfc_match_omp_parallel_masked_taskloop_simd): New prototypes.
> 	* openmp.c (enum omp_mask1): Add OMP_CLAUSE_FILTER.
> 	(gfc_match_omp_clauses): Match it.
> 	(OMP_MASKED_CLAUSES, gfc_match_omp_parallel_masked,
> 	gfc_match_omp_parallel_masked_taskloop,
> 	gfc_match_omp_parallel_masked_taskloop_simd,
> 	gfc_match_omp_masked, gfc_match_omp_masked_taskloop,
> 	gfc_match_omp_masked_taskloop_simd): New.
> 	(resolve_omp_clauses): Resolve filter clause. 
> 	(gfc_resolve_omp_parallel_blocks, resolve_omp_do,
> 	omp_code_to_statement, gfc_resolve_omp_directive): Handle
> 	omp masked constructs.
> 	* parse.c (decode_omp_directive, case_exec_markers,
> 	gfc_ascii_statement, parse_omp_do, parse_omp_structured_block,
> 	parse_executable): Likewise.
> 	* resolve.c (gfc_resolve_blocks, gfc_resolve_code): Likewise.
> 	* st.c (gfc_free_statement): Likewise.
> 	* trans-openmp.c (gfc_trans_omp_clauses): Handle filter clause.
> 	(GFC_OMP_SPLIT_MASKED, GFC_OMP_MASK_MASKED): New enum values.
> 	(gfc_trans_omp_masked): New.
> 	(gfc_split_omp_clauses): Handle combined masked directives.
> 	(gfc_trans_omp_master_taskloop): Rename to ...
> 	(gfc_trans_omp_master_masked_taskloop): ... this; handle also
> 	combined masked directives.
> 	(gfc_trans_omp_parallel_master): Rename to ...
> 	(gfc_trans_omp_parallel_master_masked): ... this; handle
> 	combined masked directives.
> 	(gfc_trans_omp_directive): Handle EXEC_OMP_*_MASKED*.
> 	* trans.c (trans_code): Likewise.
> 
> libgomp/ChangeLog:
> 
> 	* testsuite/libgomp.fortran/masked-1.f90: New test.
> 
> gcc/testsuite/ChangeLog:
> 
> 	* gfortran.dg/gomp/masked-1.f90: New test.
> 	* gfortran.dg/gomp/masked-2.f90: New test.
> 	* gfortran.dg/gomp/masked-3.f90: New test.
> 	* gfortran.dg/gomp/masked-combined-1.f90: New test.
> 	* gfortran.dg/gomp/masked-combined-2.f90: New test.

Ok, thanks.

	Jakub


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

end of thread, other threads:[~2021-08-16  7:18 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-08-12 20:48 [committed] openmp: Add support for OpenMP 5.1 masked construct Jakub Jelinek
2021-08-13 14:37 ` [Patch] Fortran/OpenMP: Add support for OpenMP 5.1 masked construct (was: Re: [committed] openmp: Add support for OpenMP 5.1 masked construct) Tobias Burnus
2021-08-13 18:52   ` Tobias Burnus
2021-08-16  7:17     ` Jakub Jelinek
2021-08-13 21:05 ` [committed] openmp: Add support for OpenMP 5.1 masked construct Thomas Schwinge

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