[gomp3.1] Add support for parsing final and mergeable task clauses and taskyield directive

Jakub Jelinek jakub@redhat.com
Thu Apr 28 15:51:00 GMT 2011


Hi!

Both final and mergeable are passed to GOMP_task in flags, but mergeable
is currently ignored, we might want to clone it on the compiler side in
that case.  taskyield calls new GOMP_taskyield function, which is currently
empty though.

2011-04-28  Jakub Jelinek  <jakub@redhat.com>

	* tree-pretty-print.c (dump_omp_clause): Handle OMP_CLAUSE_FINAL
	and OMP_CLAUSE_MERGEABLE.
	* tree.c (omp_clause_num_ops): Add OMP_CLAUSE_FINAL and
	OMP_CLAUSE_MERGEABLE.
	(omp_clause_code_name): Likewise.
	(walk_tree_1): Handle OMP_CLAUSE_FINAL and OMP_CLAUSE_MERGEABLE.
	* tree.h (enum omp_clause_code): Add OMP_CLAUSE_FINAL
	and OMP_CLAUSE_MERGEABLE.
	(OMP_CLAUSE_FINAL_EXPR): Define.
	* omp-low.c (scan_sharing_clauses): Handle OMP_CLAUSE_FINAL and
	OMP_CLAUSE_MERGEABLE.
	(expand_task_call): Likewise.
	* c-typeck.c (c_finish_omp_clauses): Likewise.
	* gimplify.c (gimplify_scan_omp_clauses,
	gimplify_adjust_omp_clauses): Likewise.
	* tree-nested.c (convert_nonlocal_omp_clauses,
	convert_local_omp_clauses): Likewise.
	* omp-builtins.def (BUILT_IN_GOMP_TASKYIELD): New builtin.
	* c-parser.c (c_parser_omp_taskyield): New function.
	(c_parser_pragma): Handle PRAGMA_OMP_TASKYIELD.
	(c_parser_omp_clause_name): Handle final and mergeable clauses.
	(c_parser_omp_clause_final, c_parser_omp_clause_mergeable): New
	functions.
	(c_parser_omp_all_clauses): Handle PRAGMA_OMP_CLAUSE_FINAL
	and PRAGMA_OMP_CLAUSE_MERGEABLE.
	(OMP_TASK_CLAUSE_MASK): Allow final and mergeable clauses.
	* doc/generic.texi: Mention OMP_CLAUSE_COLLAPSE,
	OMP_CLAUSE_UNTIED, OMP_CLAUSE_FINAL and OMP_CLAUSE_MERGEABLE.

	* c-omp.c (c_finish_omp_taskyield): New function.
	* c-common.h (c_finish_omp_taskyield): New prototype.
	* c-pragma.c (omp_pragmas): Add taskyield.
	* c-pragma.h (enum pragma_kind): Add PRAGMA_OMP_TASKYIELD.
	(enum pragma_omp_clause): Add PRAGMA_OMP_CLAUSE_FINAL and
	PRAGMA_OMP_CLAUSE_MERGEABLE.

	* pt.c (tsubst_omp_clauses): Handle OMP_CLAUSE_FINAL and
	OMP_CLAUSE_MERGEABLE.
	* semantics.c (finish_omp_clauses): Likewise.
	(finish_omp_taskyield): New function.
	* parser.c (cp_parser_omp_clause_name): Handle final and
	mergeable clauses.
	(cp_parser_omp_clause_final, cp_parser_omp_clause_mergeable): New
	functions.
	(cp_parser_omp_all_clauses): Handle PRAGMA_OMP_CLAUSE_FINAL
	and PRAGMA_OMP_CLAUSE_MERGEABLE.
	(OMP_TASK_CLAUSE_MASK): Allow final and mergeable clauses.
	(cp_parser_omp_taskyield): New function.
	(cp_parser_pragma): Handle PRAGMA_OMP_TASKYIELD.
	* cp-tree.h (finish_omp_taskyield): New prototype.

	* openmp.c (gfc_free_omp_clauses): Free also final_expr.
	(OMP_CLAUSE_FINAL, OMP_CLAUSE_MERGEABLE): Define.
	(gfc_match_omp_clauses): Handle parsing final and mergeable
	clauses.
	(OMP_TASK_CLAUSES): Allow final and mergeable clauses.
	(gfc_match_omp_taskyield): New function.
	(resolve_omp_clauses): Resolve final clause.
	* dump-parse-tree.c (show_omp_node): Handle EXEC_OMP_TASKYIELD,
	print final and mergeable clauses.
	(show_code_node): Handle EXEC_OMP_TASKYIELD.
	* trans-openmp.c (gfc_trans_omp_clauses): Handle final and
	mergeable clauses.
	(gfc_trans_omp_taskyield): New function.
	(gfc_trans_omp_directive): Handle EXEC_OMP_TASKYIELD.
	* gfortran.h (gfc_statement): Add ST_OMP_TASKYIELD.
	(gfc_omp_clauses): Add final_expr and mergeable fields.
	(gfc_exec_op): Add EXEC_OMP_TASKYIELD.
	* trans.c (trans_code): Handle EXEC_OMP_TASKYIELD.
	* frontend-passes.c (gfc_code_walker): Also walk final_expr.
	* resolve.c (gfc_resolve_blocks, resolve_code): Handle
	EXEC_OMP_TASKYIELD.
	* st.c (gfc_free_statement): Likewise.
	* match.h (gfc_match_omp_taskyield): New prototype.
	* parse.c (decode_omp_directive): Handle taskyield directive.
	(case_executable): Add ST_OMP_TASKYIELD case.
	(gfc_ascii_statement): Handle ST_OMP_TASKYIELD.

	* libgomp_g.h (GOMP_taskyield): New prototype.
	* libgomp.map (GOMP_taskyield): Export with GOMP_3.0 symver.
	* libgomp.h (struct gomp_task): Add final_task field.
	* task.c (gomp_init_task): Initialize final_task.
	(GOMP_task): Remove unused attribute from flags.  Handle final
	tasks.
	(GOMP_taskyield): New function.
	(omp_in_final): Return true if if (false) or final (true) task
	or descendant of final (true).
	* testsuite/libgomp.c/task-5.c: New test.
	* testsuite/libgomp.c++/task-8.C: New test.
	* testsuite/libgomp.fortran/task3.f90: New test.

--- gcc/doc/generic.texi	(revision 172776)
+++ gcc/doc/generic.texi	(working copy)
@@ -2210,7 +2210,9 @@ Clauses are represented by separate sub-
 @code{OMP_CLAUSE_COPYPRIVATE}, @code{OMP_CLAUSE_IF},
 @code{OMP_CLAUSE_NUM_THREADS}, @code{OMP_CLAUSE_SCHEDULE},
 @code{OMP_CLAUSE_NOWAIT}, @code{OMP_CLAUSE_ORDERED},
-@code{OMP_CLAUSE_DEFAULT}, and @code{OMP_CLAUSE_REDUCTION}.  Each code
+@code{OMP_CLAUSE_DEFAULT}, @code{OMP_CLAUSE_REDUCTION},
+@code{OMP_CLAUSE_COLLAPSE}, @code{OMP_CLAUSE_UNTIED},
+@code{OMP_CLAUSE_FINAL}, and @code{OMP_CLAUSE_MERGEABLE}.  Each code
 represents the corresponding OpenMP clause.
 
 Clauses associated with the same directive are chained together
--- gcc/tree-pretty-print.c	(revision 172823)
+++ gcc/tree-pretty-print.c	(working copy)
@@ -417,6 +417,17 @@ dump_omp_clause (pretty_printer *buffer,
       pp_character (buffer, ')');
       break;
 
+    case OMP_CLAUSE_FINAL:
+      pp_string (buffer, "final(");
+      dump_generic_node (buffer, OMP_CLAUSE_FINAL_EXPR (clause),
+	  spc, flags, false);
+      pp_character (buffer, ')');
+      break;
+
+    case OMP_CLAUSE_MERGEABLE:
+      pp_string (buffer, "mergeable");
+      break;
+
     default:
       /* Should never happen.  */
       dump_generic_node (buffer, clause, spc, flags, false);
--- gcc/c-family/c-omp.c	(revision 172823)
+++ gcc/c-family/c-omp.c	(working copy)
@@ -96,6 +96,20 @@ c_finish_omp_taskwait (location_t loc)
 }
 
 
+/* Complete a #pragma omp taskyield construct.  LOC is the location of the
+   pragma.  */
+
+void
+c_finish_omp_taskyield (location_t loc)
+{
+  tree x;
+
+  x = built_in_decls[BUILT_IN_GOMP_TASKYIELD];
+  x = build_call_expr_loc (loc, x, 0);
+  add_stmt (x);
+}
+
+
 /* Complete a #pragma omp atomic construct.  For CODE OMP_ATOMIC
    the expression to be implemented atomically is LHS opcode= RHS. 
    For OMP_ATOMIC_READ V = LHS, for OMP_ATOMIC_CAPTURE_{NEW,OLD} LHS
--- gcc/c-family/c-common.h	(revision 172823)
+++ gcc/c-family/c-common.h	(working copy)
@@ -999,6 +999,7 @@ extern tree c_finish_omp_atomic (locatio
 				 tree, tree, tree, tree);
 extern void c_finish_omp_flush (location_t);
 extern void c_finish_omp_taskwait (location_t);
+extern void c_finish_omp_taskyield (location_t);
 extern tree c_finish_omp_for (location_t, tree, tree, tree, tree, tree, tree);
 extern void c_split_parallel_clauses (location_t, tree, tree *, tree *);
 extern enum omp_clause_default_kind c_omp_predetermined_sharing (tree);
--- gcc/c-family/c-pragma.c	(revision 172776)
+++ gcc/c-family/c-pragma.c	(working copy)
@@ -1180,6 +1180,7 @@ static const struct omp_pragma_def omp_p
   { "single", PRAGMA_OMP_SINGLE },
   { "task", PRAGMA_OMP_TASK },
   { "taskwait", PRAGMA_OMP_TASKWAIT },
+  { "taskyield", PRAGMA_OMP_TASKYIELD },
   { "threadprivate", PRAGMA_OMP_THREADPRIVATE }
 };
 
--- gcc/c-family/c-pragma.h	(revision 172776)
+++ gcc/c-family/c-pragma.h	(working copy)
@@ -43,6 +43,7 @@ typedef enum pragma_kind {
   PRAGMA_OMP_SINGLE,
   PRAGMA_OMP_TASK,
   PRAGMA_OMP_TASKWAIT,
+  PRAGMA_OMP_TASKYIELD,
   PRAGMA_OMP_THREADPRIVATE,
 
   PRAGMA_GCC_PCH_PREPROCESS,
@@ -70,7 +71,9 @@ typedef enum pragma_omp_clause {
   PRAGMA_OMP_CLAUSE_REDUCTION,
   PRAGMA_OMP_CLAUSE_SCHEDULE,
   PRAGMA_OMP_CLAUSE_SHARED,
-  PRAGMA_OMP_CLAUSE_UNTIED
+  PRAGMA_OMP_CLAUSE_UNTIED,
+  PRAGMA_OMP_CLAUSE_FINAL,
+  PRAGMA_OMP_CLAUSE_MERGEABLE
 } pragma_omp_clause;
 
 extern struct cpp_reader* parse_in;
--- gcc/tree.c	(revision 172776)
+++ gcc/tree.c	(working copy)
@@ -241,7 +241,9 @@ unsigned const char omp_clause_num_ops[]
   0, /* OMP_CLAUSE_ORDERED  */
   0, /* OMP_CLAUSE_DEFAULT  */
   3, /* OMP_CLAUSE_COLLAPSE  */
-  0  /* OMP_CLAUSE_UNTIED   */
+  0, /* OMP_CLAUSE_UNTIED   */
+  1, /* OMP_CLAUSE_FINAL  */
+  0  /* OMP_CLAUSE_MERGEABLE  */
 };
 
 const char * const omp_clause_code_name[] =
@@ -261,7 +263,9 @@ const char * const omp_clause_code_name[
   "ordered",
   "default",
   "collapse",
-  "untied"
+  "untied",
+  "final",
+  "mergeable"
 };
 
 
@@ -10377,6 +10381,7 @@ walk_tree_1 (tree *tp, walk_tree_fn func
 	case OMP_CLAUSE_FIRSTPRIVATE:
 	case OMP_CLAUSE_COPYIN:
 	case OMP_CLAUSE_COPYPRIVATE:
+	case OMP_CLAUSE_FINAL:
 	case OMP_CLAUSE_IF:
 	case OMP_CLAUSE_NUM_THREADS:
 	case OMP_CLAUSE_SCHEDULE:
@@ -10387,6 +10392,7 @@ walk_tree_1 (tree *tp, walk_tree_fn func
 	case OMP_CLAUSE_ORDERED:
 	case OMP_CLAUSE_DEFAULT:
 	case OMP_CLAUSE_UNTIED:
+	case OMP_CLAUSE_MERGEABLE:
 	  WALK_SUBTREE_TAIL (OMP_CLAUSE_CHAIN (*tp));
 
 	case OMP_CLAUSE_LASTPRIVATE:
--- gcc/tree.h	(revision 172776)
+++ gcc/tree.h	(working copy)
@@ -339,7 +339,13 @@ enum omp_clause_code
   OMP_CLAUSE_COLLAPSE,
 
   /* OpenMP clause: untied.  */
-  OMP_CLAUSE_UNTIED
+  OMP_CLAUSE_UNTIED,
+
+  /* OpenMP clause: final (scalar-expression).  */
+  OMP_CLAUSE_FINAL,
+
+  /* OpenMP clause: mergeable.  */
+  OMP_CLAUSE_MERGEABLE
 };
 
 /* The definition of tree nodes fills the next several pages.  */
@@ -1800,6 +1806,8 @@ extern void protected_set_expr_location 
 #define OMP_CLAUSE_LASTPRIVATE_GIMPLE_SEQ(NODE) \
   (OMP_CLAUSE_CHECK (NODE))->omp_clause.gimple_reduction_init
 
+#define OMP_CLAUSE_FINAL_EXPR(NODE) \
+  OMP_CLAUSE_OPERAND (OMP_CLAUSE_SUBCODE_CHECK (NODE, OMP_CLAUSE_FINAL), 0)
 #define OMP_CLAUSE_IF_EXPR(NODE) \
   OMP_CLAUSE_OPERAND (OMP_CLAUSE_SUBCODE_CHECK (NODE, OMP_CLAUSE_IF), 0)
 #define OMP_CLAUSE_NUM_THREADS_EXPR(NODE) \
--- gcc/omp-low.c	(revision 172823)
+++ gcc/omp-low.c	(working copy)
@@ -1444,6 +1444,7 @@ scan_sharing_clauses (tree clauses, omp_
 	  ctx->default_kind = OMP_CLAUSE_DEFAULT_KIND (c);
 	  break;
 
+	case OMP_CLAUSE_FINAL:
 	case OMP_CLAUSE_IF:
 	case OMP_CLAUSE_NUM_THREADS:
 	case OMP_CLAUSE_SCHEDULE:
@@ -1455,6 +1456,7 @@ scan_sharing_clauses (tree clauses, omp_
 	case OMP_CLAUSE_ORDERED:
 	case OMP_CLAUSE_COLLAPSE:
 	case OMP_CLAUSE_UNTIED:
+	case OMP_CLAUSE_MERGEABLE:
 	  break;
 
 	default:
@@ -1505,6 +1507,8 @@ scan_sharing_clauses (tree clauses, omp_
 	case OMP_CLAUSE_ORDERED:
 	case OMP_CLAUSE_COLLAPSE:
 	case OMP_CLAUSE_UNTIED:
+	case OMP_CLAUSE_FINAL:
+	case OMP_CLAUSE_MERGEABLE:
 	  break;
 
 	default:
@@ -3082,7 +3086,7 @@ expand_parallel_call (struct omp_region 
 static void
 expand_task_call (basic_block bb, gimple entry_stmt)
 {
-  tree t, t1, t2, t3, flags, cond, c, clauses;
+  tree t, t1, t2, t3, flags, cond, c, c2, clauses;
   gimple_stmt_iterator gsi;
   location_t loc = gimple_location (entry_stmt);
 
@@ -3095,7 +3099,19 @@ expand_task_call (basic_block bb, gimple
     cond = boolean_true_node;
 
   c = find_omp_clause (clauses, OMP_CLAUSE_UNTIED);
-  flags = build_int_cst (unsigned_type_node, (c ? 1 : 0));
+  c2 = find_omp_clause (clauses, OMP_CLAUSE_MERGEABLE);
+  flags = build_int_cst (unsigned_type_node,
+			 (c ? 1 : 0) + (c2 ? 4 : 0));
+
+  c = find_omp_clause (clauses, OMP_CLAUSE_FINAL);
+  if (c)
+    {
+      c = gimple_boolify (OMP_CLAUSE_FINAL_EXPR (c));
+      c = fold_build3_loc (loc, COND_EXPR, unsigned_type_node, c,
+			   build_int_cst (unsigned_type_node, 2),
+			   build_int_cst (unsigned_type_node, 0));
+      flags = fold_build2_loc (loc, PLUS_EXPR, unsigned_type_node, flags, c);
+    }
 
   gsi = gsi_last_bb (bb);
   t = gimple_omp_task_data_arg (entry_stmt);
--- gcc/cp/pt.c	(revision 173013)
+++ gcc/cp/pt.c	(working copy)
@@ -11759,6 +11759,7 @@ tsubst_omp_clauses (tree clauses, tree a
 	case OMP_CLAUSE_NUM_THREADS:
 	case OMP_CLAUSE_SCHEDULE:
 	case OMP_CLAUSE_COLLAPSE:
+	case OMP_CLAUSE_FINAL:
 	  OMP_CLAUSE_OPERAND (nc, 0)
 	    = tsubst_expr (OMP_CLAUSE_OPERAND (oc, 0), args, complain, 
 			   in_decl, /*integral_constant_expression_p=*/false);
@@ -11767,6 +11768,7 @@ tsubst_omp_clauses (tree clauses, tree a
 	case OMP_CLAUSE_ORDERED:
 	case OMP_CLAUSE_DEFAULT:
 	case OMP_CLAUSE_UNTIED:
+	case OMP_CLAUSE_MERGEABLE:
 	  break;
 	default:
 	  gcc_unreachable ();
--- gcc/cp/semantics.c	(revision 173013)
+++ gcc/cp/semantics.c	(working copy)
@@ -3768,6 +3768,14 @@ finish_omp_clauses (tree clauses)
 	  OMP_CLAUSE_IF_EXPR (c) = t;
 	  break;
 
+	case OMP_CLAUSE_FINAL:
+	  t = OMP_CLAUSE_FINAL_EXPR (c);
+	  t = maybe_convert_cond (t);
+	  if (t == error_mark_node)
+	    remove = true;
+	  OMP_CLAUSE_FINAL_EXPR (c) = t;
+	  break;
+
 	case OMP_CLAUSE_NUM_THREADS:
 	  t = OMP_CLAUSE_NUM_THREADS_EXPR (c);
 	  if (t == error_mark_node)
@@ -3799,6 +3807,7 @@ finish_omp_clauses (tree clauses)
 	case OMP_CLAUSE_DEFAULT:
 	case OMP_CLAUSE_UNTIED:
 	case OMP_CLAUSE_COLLAPSE:
+	case OMP_CLAUSE_MERGEABLE:
 	  break;
 
 	default:
@@ -4677,6 +4686,16 @@ finish_omp_taskwait (void)
   release_tree_vector (vec);
   finish_expr_stmt (stmt);
 }
+
+void
+finish_omp_taskyield (void)
+{
+  tree fn = built_in_decls[BUILT_IN_GOMP_TASKYIELD];
+  VEC(tree,gc) *vec = make_tree_vector ();
+  tree stmt = finish_call_expr (fn, &vec, false, false, tf_warning_or_error);
+  release_tree_vector (vec);
+  finish_expr_stmt (stmt);
+}
 
 void
 init_cp_semantics (void)
--- gcc/cp/parser.c	(revision 173035)
+++ gcc/cp/parser.c	(working copy)
@@ -23352,13 +23352,19 @@ cp_parser_omp_clause_name (cp_parser *pa
 	    result = PRAGMA_OMP_CLAUSE_COPYPRIVATE;
 	  break;
 	case 'f':
-	  if (!strcmp ("firstprivate", p))
+	  if (!strcmp ("final", p))
+	    result = PRAGMA_OMP_CLAUSE_FINAL;
+	  else if (!strcmp ("firstprivate", p))
 	    result = PRAGMA_OMP_CLAUSE_FIRSTPRIVATE;
 	  break;
 	case 'l':
 	  if (!strcmp ("lastprivate", p))
 	    result = PRAGMA_OMP_CLAUSE_LASTPRIVATE;
 	  break;
+	case 'm':
+	  if (!strcmp ("mergeable", p))
+	    result = PRAGMA_OMP_CLAUSE_MERGEABLE;
+	  break;
 	case 'n':
 	  if (!strcmp ("nowait", p))
 	    result = PRAGMA_OMP_CLAUSE_NOWAIT;
@@ -23588,6 +23594,34 @@ cp_parser_omp_clause_default (cp_parser 
   return c;
 }
 
+/* OpenMP 3.1:
+   final ( expression ) */
+
+static tree
+cp_parser_omp_clause_final (cp_parser *parser, tree list, location_t location)
+{
+  tree t, c;
+
+  if (!cp_parser_require (parser, CPP_OPEN_PAREN, RT_OPEN_PAREN))
+    return list;
+
+  t = cp_parser_condition (parser);
+
+  if (t == error_mark_node
+      || !cp_parser_require (parser, CPP_CLOSE_PAREN, RT_CLOSE_PAREN))
+    cp_parser_skip_to_closing_parenthesis (parser, /*recovering=*/true,
+					   /*or_comma=*/false,
+					   /*consume_paren=*/true);
+
+  check_no_duplicate_clause (list, OMP_CLAUSE_FINAL, "final", location);
+
+  c = build_omp_clause (location, OMP_CLAUSE_FINAL);
+  OMP_CLAUSE_FINAL_EXPR (c) = t;
+  OMP_CLAUSE_CHAIN (c) = list;
+
+  return c;
+}
+
 /* OpenMP 2.5:
    if ( expression ) */
 
@@ -23616,6 +23650,23 @@ cp_parser_omp_clause_if (cp_parser *pars
   return c;
 }
 
+/* OpenMP 3.1:
+   mergeable */
+
+static tree
+cp_parser_omp_clause_mergeable (cp_parser *parser ATTRIBUTE_UNUSED,
+				tree list, location_t location)
+{
+  tree c;
+
+  check_no_duplicate_clause (list, OMP_CLAUSE_MERGEABLE, "mergeable",
+			     location);
+
+  c = build_omp_clause (location, OMP_CLAUSE_MERGEABLE);
+  OMP_CLAUSE_CHAIN (c) = list;
+  return c;
+}
+
 /* OpenMP 2.5:
    nowait */
 
@@ -23917,6 +23968,10 @@ cp_parser_omp_all_clauses (cp_parser *pa
 						  token->location);
 	  c_name = "default";
 	  break;
+	case PRAGMA_OMP_CLAUSE_FINAL:
+	  clauses = cp_parser_omp_clause_final (parser, clauses, token->location);
+	  c_name = "final";
+	  break;
 	case PRAGMA_OMP_CLAUSE_FIRSTPRIVATE:
 	  clauses = cp_parser_omp_var_list (parser, OMP_CLAUSE_FIRSTPRIVATE,
 					    clauses);
@@ -23931,6 +23986,11 @@ cp_parser_omp_all_clauses (cp_parser *pa
 					    clauses);
 	  c_name = "lastprivate";
 	  break;
+	case PRAGMA_OMP_CLAUSE_MERGEABLE:
+	  clauses = cp_parser_omp_clause_mergeable (parser, clauses,
+						    token->location);
+	  c_name = "mergeable";
+	  break;
 	case PRAGMA_OMP_CLAUSE_NOWAIT:
 	  clauses = cp_parser_omp_clause_nowait (parser, clauses, token->location);
 	  c_name = "nowait";
@@ -25150,7 +25210,9 @@ cp_parser_omp_single (cp_parser *parser,
 	| (1u << PRAGMA_OMP_CLAUSE_DEFAULT)		\
 	| (1u << PRAGMA_OMP_CLAUSE_PRIVATE)		\
 	| (1u << PRAGMA_OMP_CLAUSE_FIRSTPRIVATE)	\
-	| (1u << PRAGMA_OMP_CLAUSE_SHARED))
+	| (1u << PRAGMA_OMP_CLAUSE_SHARED)		\
+	| (1u << PRAGMA_OMP_CLAUSE_FINAL)		\
+	| (1u << PRAGMA_OMP_CLAUSE_MERGEABLE))
 
 static tree
 cp_parser_omp_task (cp_parser *parser, cp_token *pragma_tok)
@@ -25177,6 +25239,16 @@ cp_parser_omp_taskwait (cp_parser *parse
   finish_omp_taskwait ();
 }
 
+/* OpenMP 3.1:
+   # pragma omp taskyield new-line  */
+
+static void
+cp_parser_omp_taskyield (cp_parser *parser, cp_token *pragma_tok)
+{
+  cp_parser_require_pragma_eol (parser, pragma_tok);
+  finish_omp_taskyield ();
+}
+
 /* OpenMP 2.5:
    # pragma omp threadprivate (variable-list) */
 
@@ -25352,6 +25424,22 @@ cp_parser_pragma (cp_parser *parser, enu
 	}
       break;
 
+    case PRAGMA_OMP_TASKYIELD:
+      switch (context)
+	{
+	case pragma_compound:
+	  cp_parser_omp_taskyield (parser, pragma_tok);
+	  return false;
+	case pragma_stmt:
+	  error_at (pragma_tok->location,
+		    "%<#pragma omp taskyield%> may only be "
+		    "used in compound statements");
+	  break;
+	default:
+	  goto bad_stmt;
+	}
+      break;
+
     case PRAGMA_OMP_THREADPRIVATE:
       cp_parser_omp_threadprivate (parser, pragma_tok);
       return false;
--- gcc/cp/cp-tree.h	(revision 173013)
+++ gcc/cp/cp-tree.h	(working copy)
@@ -5338,6 +5338,7 @@ extern void finish_omp_atomic			(enum tr
 extern void finish_omp_barrier			(void);
 extern void finish_omp_flush			(void);
 extern void finish_omp_taskwait			(void);
+extern void finish_omp_taskyield		(void);
 extern bool cxx_omp_create_clause_info		(tree, tree, bool, bool, bool);
 extern tree baselink_for_fns                    (tree);
 extern void finish_static_assert                (tree, tree, location_t,
--- gcc/fortran/openmp.c	(revision 173032)
+++ gcc/fortran/openmp.c	(working copy)
@@ -66,6 +66,7 @@ gfc_free_omp_clauses (gfc_omp_clauses *c
     return;
 
   gfc_free_expr (c->if_expr);
+  gfc_free_expr (c->final_expr);
   gfc_free_expr (c->num_threads);
   gfc_free_expr (c->chunk_size);
   for (i = 0; i < OMP_LIST_NUM; i++)
@@ -182,6 +183,8 @@ cleanup:
 #define OMP_CLAUSE_ORDERED	(1 << 11)
 #define OMP_CLAUSE_COLLAPSE	(1 << 12)
 #define OMP_CLAUSE_UNTIED	(1 << 13)
+#define OMP_CLAUSE_FINAL	(1 << 14)
+#define OMP_CLAUSE_MERGEABLE	(1 << 15)
 
 /* Match OpenMP directive clauses. MASK is a bitmask of
    clauses that are allowed for a particular directive.  */
@@ -205,6 +208,9 @@ gfc_match_omp_clauses (gfc_omp_clauses *
       if ((mask & OMP_CLAUSE_IF) && c->if_expr == NULL
 	  && gfc_match ("if ( %e )", &c->if_expr) == MATCH_YES)
 	continue;
+      if ((mask & OMP_CLAUSE_FINAL) && c->final_expr == NULL
+	  && gfc_match ("final ( %e )", &c->final_expr) == MATCH_YES)
+	continue;
       if ((mask & OMP_CLAUSE_NUM_THREADS) && c->num_threads == NULL
 	  && gfc_match ("num_threads ( %e )", &c->num_threads) == MATCH_YES)
 	continue;
@@ -383,6 +389,12 @@ gfc_match_omp_clauses (gfc_omp_clauses *
 	  c->untied = needs_space = true;
 	  continue;
 	}
+      if ((mask & OMP_CLAUSE_MERGEABLE) && !c->mergeable
+	  && gfc_match ("mergeable") == MATCH_YES)
+	{
+	  c->mergeable = needs_space = true;
+	  continue;
+	}
       if ((mask & OMP_CLAUSE_COLLAPSE) && !c->collapse)
 	{
 	  gfc_expr *cexpr = NULL;
@@ -435,7 +447,8 @@ gfc_match_omp_clauses (gfc_omp_clauses *
    | OMP_CLAUSE_LASTPRIVATE | OMP_CLAUSE_REDUCTION)
 #define OMP_TASK_CLAUSES \
   (OMP_CLAUSE_PRIVATE | OMP_CLAUSE_FIRSTPRIVATE | OMP_CLAUSE_SHARED	\
-   | OMP_CLAUSE_IF | OMP_CLAUSE_DEFAULT | OMP_CLAUSE_UNTIED)
+   | OMP_CLAUSE_IF | OMP_CLAUSE_DEFAULT | OMP_CLAUSE_UNTIED		\
+   | OMP_CLAUSE_FINAL | OMP_CLAUSE_MERGEABLE)
 
 match
 gfc_match_omp_parallel (void)
@@ -476,6 +489,20 @@ gfc_match_omp_taskwait (void)
 
 
 match
+gfc_match_omp_taskyield (void)
+{
+  if (gfc_match_omp_eos () != MATCH_YES)
+    {
+      gfc_error ("Unexpected junk after TASKYIELD clause at %C");
+      return MATCH_ERROR;
+    }
+  new_st.op = EXEC_OMP_TASKYIELD;
+  new_st.ext.omp_clauses = NULL;
+  return MATCH_YES;
+}
+
+
+match
 gfc_match_omp_critical (void)
 {
   char n[GFC_MAX_SYMBOL_LEN+1];
@@ -792,6 +819,14 @@ resolve_omp_clauses (gfc_code *code)
 	gfc_error ("IF clause at %L requires a scalar LOGICAL expression",
 		   &expr->where);
     }
+  if (omp_clauses->final_expr)
+    {
+      gfc_expr *expr = omp_clauses->final_expr;
+      if (gfc_resolve_expr (expr) == FAILURE
+	  || expr->ts.type != BT_LOGICAL || expr->rank != 0)
+	gfc_error ("FINAL clause at %L requires a scalar LOGICAL expression",
+		   &expr->where);
+    }
   if (omp_clauses->num_threads)
     {
       gfc_expr *expr = omp_clauses->num_threads;
--- gcc/fortran/dump-parse-tree.c	(revision 172776)
+++ gcc/fortran/dump-parse-tree.c	(working copy)
@@ -1038,6 +1038,7 @@ show_omp_node (int level, gfc_code *c)
     case EXEC_OMP_SINGLE: name = "SINGLE"; break;
     case EXEC_OMP_TASK: name = "TASK"; break;
     case EXEC_OMP_TASKWAIT: name = "TASKWAIT"; break;
+    case EXEC_OMP_TASKYIELD: name = "TASKYIELD"; break;
     case EXEC_OMP_WORKSHARE: name = "WORKSHARE"; break;
     default:
       gcc_unreachable ();
@@ -1070,6 +1071,7 @@ show_omp_node (int level, gfc_code *c)
       return;
     case EXEC_OMP_BARRIER:
     case EXEC_OMP_TASKWAIT:
+    case EXEC_OMP_TASKYIELD:
       return;
     default:
       break;
@@ -1084,6 +1086,12 @@ show_omp_node (int level, gfc_code *c)
 	  show_expr (omp_clauses->if_expr);
 	  fputc (')', dumpfile);
 	}
+      if (omp_clauses->final_expr)
+	{
+	  fputs (" FINAL(", dumpfile);
+	  show_expr (omp_clauses->final_expr);
+	  fputc (')', dumpfile);
+	}
       if (omp_clauses->num_threads)
 	{
 	  fputs (" NUM_THREADS(", dumpfile);
@@ -1129,6 +1137,8 @@ show_omp_node (int level, gfc_code *c)
 	fputs (" ORDERED", dumpfile);
       if (omp_clauses->untied)
 	fputs (" UNTIED", dumpfile);
+      if (omp_clauses->mergeable)
+	fputs (" MERGEABLE", dumpfile);
       if (omp_clauses->collapse)
 	fprintf (dumpfile, " COLLAPSE(%d)", omp_clauses->collapse);
       for (list_type = 0; list_type < OMP_LIST_NUM; list_type++)
@@ -2134,6 +2144,7 @@ show_code_node (int level, gfc_code *c)
     case EXEC_OMP_SINGLE:
     case EXEC_OMP_TASK:
     case EXEC_OMP_TASKWAIT:
+    case EXEC_OMP_TASKYIELD:
     case EXEC_OMP_WORKSHARE:
       show_omp_node (level, c);
       break;
--- gcc/fortran/trans-openmp.c	(revision 173032)
+++ gcc/fortran/trans-openmp.c	(working copy)
@@ -866,6 +866,21 @@ gfc_trans_omp_clauses (stmtblock_t *bloc
       omp_clauses = gfc_trans_add_clause (c, omp_clauses);
     }
 
+  if (clauses->final_expr)
+    {
+      tree final_var;
+
+      gfc_init_se (&se, NULL);
+      gfc_conv_expr (&se, clauses->final_expr);
+      gfc_add_block_to_block (block, &se.pre);
+      final_var = gfc_evaluate_now (se.expr, block);
+      gfc_add_block_to_block (block, &se.post);
+
+      c = build_omp_clause (where.lb->location, OMP_CLAUSE_FINAL);
+      OMP_CLAUSE_FINAL_EXPR (c) = final_var;
+      omp_clauses = gfc_trans_add_clause (c, omp_clauses);
+    }
+
   if (clauses->num_threads)
     {
       tree num_threads;
@@ -959,6 +974,12 @@ gfc_trans_omp_clauses (stmtblock_t *bloc
       omp_clauses = gfc_trans_add_clause (c, omp_clauses);
     }
 
+  if (clauses->mergeable)
+    {
+      c = build_omp_clause (where.lb->location, OMP_CLAUSE_MERGEABLE);
+      omp_clauses = gfc_trans_add_clause (c, omp_clauses);
+    }
+
   if (clauses->collapse)
     {
       c = build_omp_clause (where.lb->location, OMP_CLAUSE_COLLAPSE);
@@ -1719,6 +1740,13 @@ gfc_trans_omp_taskwait (void)
 }
 
 static tree
+gfc_trans_omp_taskyield (void)
+{
+  tree decl = built_in_decls [BUILT_IN_GOMP_TASKYIELD];
+  return build_call_expr_loc (input_location, decl, 0);
+}
+
+static tree
 gfc_trans_omp_workshare (gfc_code *code, gfc_omp_clauses *clauses)
 {
   tree res, tmp, stmt;
@@ -1911,6 +1939,8 @@ gfc_trans_omp_directive (gfc_code *code)
       return gfc_trans_omp_task (code);
     case EXEC_OMP_TASKWAIT:
       return gfc_trans_omp_taskwait ();
+    case EXEC_OMP_TASKYIELD:
+      return gfc_trans_omp_taskyield ();
     case EXEC_OMP_WORKSHARE:
       return gfc_trans_omp_workshare (code, code->ext.omp_clauses);
     default:
--- gcc/fortran/gfortran.h	(revision 173032)
+++ gcc/fortran/gfortran.h	(working copy)
@@ -208,8 +208,8 @@ typedef enum
   ST_OMP_PARALLEL, ST_OMP_PARALLEL_DO, ST_OMP_PARALLEL_SECTIONS,
   ST_OMP_PARALLEL_WORKSHARE, ST_OMP_SECTIONS, ST_OMP_SECTION, ST_OMP_SINGLE,
   ST_OMP_THREADPRIVATE, ST_OMP_WORKSHARE, ST_OMP_TASK, ST_OMP_END_TASK,
-  ST_OMP_TASKWAIT, ST_PROCEDURE, ST_GENERIC, ST_CRITICAL, ST_END_CRITICAL,
-  ST_GET_FCN_CHARACTERISTICS, ST_NONE
+  ST_OMP_TASKWAIT, ST_OMP_TASKYIELD, ST_PROCEDURE, ST_GENERIC, ST_CRITICAL,
+  ST_END_CRITICAL, ST_GET_FCN_CHARACTERISTICS, ST_NONE
 }
 gfc_statement;
 
@@ -1045,13 +1045,14 @@ enum gfc_omp_default_sharing
 typedef struct gfc_omp_clauses
 {
   struct gfc_expr *if_expr;
+  struct gfc_expr *final_expr;
   struct gfc_expr *num_threads;
   gfc_namelist *lists[OMP_LIST_NUM];
   enum gfc_omp_sched_kind sched_kind;
   struct gfc_expr *chunk_size;
   enum gfc_omp_default_sharing default_sharing;
   int collapse;
-  bool nowait, ordered, untied;
+  bool nowait, ordered, untied, mergeable;
 }
 gfc_omp_clauses;
 
@@ -2060,7 +2061,8 @@ typedef enum
   EXEC_OMP_PARALLEL_SECTIONS, EXEC_OMP_PARALLEL_WORKSHARE,
   EXEC_OMP_SECTIONS, EXEC_OMP_SINGLE, EXEC_OMP_WORKSHARE,
   EXEC_OMP_ATOMIC, EXEC_OMP_BARRIER, EXEC_OMP_END_NOWAIT,
-  EXEC_OMP_END_SINGLE, EXEC_OMP_TASK, EXEC_OMP_TASKWAIT
+  EXEC_OMP_END_SINGLE, EXEC_OMP_TASK, EXEC_OMP_TASKWAIT,
+  EXEC_OMP_TASKYIELD
 }
 gfc_exec_op;
 
--- gcc/fortran/trans.c	(revision 172776)
+++ gcc/fortran/trans.c	(working copy)
@@ -1401,6 +1401,7 @@ trans_code (gfc_code * code, tree cond)
 	case EXEC_OMP_SINGLE:
 	case EXEC_OMP_TASK:
 	case EXEC_OMP_TASKWAIT:
+	case EXEC_OMP_TASKYIELD:
 	case EXEC_OMP_WORKSHARE:
 	  res = gfc_trans_omp_directive (code);
 	  break;
--- gcc/fortran/frontend-passes.c	(revision 172776)
+++ gcc/fortran/frontend-passes.c	(working copy)
@@ -810,6 +810,7 @@ gfc_code_walker (gfc_code **c, walk_code
 	      if ((*c)->ext.omp_clauses)
 		{
 		  WALK_SUBEXPR ((*c)->ext.omp_clauses->if_expr);
+		  WALK_SUBEXPR ((*c)->ext.omp_clauses->final_expr);
 		  WALK_SUBEXPR ((*c)->ext.omp_clauses->num_threads);
 		  WALK_SUBEXPR ((*c)->ext.omp_clauses->chunk_size);
 		}
--- gcc/fortran/resolve.c	(revision 172776)
+++ gcc/fortran/resolve.c	(working copy)
@@ -8715,6 +8715,7 @@ gfc_resolve_blocks (gfc_code *b, gfc_nam
 	case EXEC_OMP_SINGLE:
 	case EXEC_OMP_TASK:
 	case EXEC_OMP_TASKWAIT:
+	case EXEC_OMP_TASKYIELD:
 	case EXEC_OMP_WORKSHARE:
 	  break;
 
@@ -9274,6 +9275,7 @@ resolve_code (gfc_code *code, gfc_namesp
 	case EXEC_OMP_SECTIONS:
 	case EXEC_OMP_SINGLE:
 	case EXEC_OMP_TASKWAIT:
+	case EXEC_OMP_TASKYIELD:
 	case EXEC_OMP_WORKSHARE:
 	  gfc_resolve_omp_directive (code, ns);
 	  break;
--- gcc/fortran/st.c	(revision 172776)
+++ gcc/fortran/st.c	(working copy)
@@ -206,6 +206,7 @@ gfc_free_statement (gfc_code *p)
     case EXEC_OMP_ORDERED:
     case EXEC_OMP_END_NOWAIT:
     case EXEC_OMP_TASKWAIT:
+    case EXEC_OMP_TASKYIELD:
       break;
 
     default:
--- gcc/fortran/match.h	(revision 172776)
+++ gcc/fortran/match.h	(working copy)
@@ -136,6 +136,7 @@ match gfc_match_omp_sections (void);
 match gfc_match_omp_single (void);
 match gfc_match_omp_task (void);
 match gfc_match_omp_taskwait (void);
+match gfc_match_omp_taskyield (void);
 match gfc_match_omp_threadprivate (void);
 match gfc_match_omp_workshare (void);
 match gfc_match_omp_end_nowait (void);
--- gcc/fortran/parse.c	(revision 173032)
+++ gcc/fortran/parse.c	(working copy)
@@ -563,6 +563,7 @@ decode_omp_directive (void)
     case 't':
       match ("task", gfc_match_omp_task, ST_OMP_TASK);
       match ("taskwait", gfc_match_omp_taskwait, ST_OMP_TASKWAIT);
+      match ("taskyield", gfc_match_omp_taskyield, ST_OMP_TASKYIELD);
       match ("threadprivate", gfc_match_omp_threadprivate,
 	     ST_OMP_THREADPRIVATE);
     case 'w':
@@ -953,8 +954,9 @@ next_statement (void)
   case ST_POINTER_ASSIGNMENT: case ST_EXIT: case ST_CYCLE: \
   case ST_ASSIGNMENT: case ST_ARITHMETIC_IF: case ST_WHERE: case ST_FORALL: \
   case ST_LABEL_ASSIGNMENT: case ST_FLUSH: case ST_OMP_FLUSH: \
-  case ST_OMP_BARRIER: case ST_OMP_TASKWAIT: case ST_ERROR_STOP: \
-  case ST_SYNC_ALL: case ST_SYNC_IMAGES: case ST_SYNC_MEMORY
+  case ST_OMP_BARRIER: case ST_OMP_TASKWAIT: case ST_OMP_TASKYIELD: \
+  case ST_ERROR_STOP: case ST_SYNC_ALL: case ST_SYNC_IMAGES: \
+  case ST_SYNC_MEMORY
 
 /* Statements that mark other executable statements.  */
 
@@ -1534,6 +1536,9 @@ gfc_ascii_statement (gfc_statement st)
     case ST_OMP_TASKWAIT:
       p = "!$OMP TASKWAIT";
       break;
+    case ST_OMP_TASKYIELD:
+      p = "!$OMP TASKYIELD";
+      break;
     case ST_OMP_THREADPRIVATE:
       p = "!$OMP THREADPRIVATE";
       break;
--- gcc/c-typeck.c	(revision 172776)
+++ gcc/c-typeck.c	(working copy)
@@ -10563,6 +10563,8 @@ c_finish_omp_clauses (tree clauses)
 	case OMP_CLAUSE_DEFAULT:
 	case OMP_CLAUSE_UNTIED:
 	case OMP_CLAUSE_COLLAPSE:
+	case OMP_CLAUSE_FINAL:
+	case OMP_CLAUSE_MERGEABLE:
 	  pc = &OMP_CLAUSE_CHAIN (c);
 	  continue;
 
--- gcc/gimplify.c	(revision 172823)
+++ gcc/gimplify.c	(working copy)
@@ -5904,6 +5904,7 @@ gimplify_scan_omp_clauses (tree *list_p,
 	    }
 	  break;
 
+	case OMP_CLAUSE_FINAL:
 	case OMP_CLAUSE_IF:
 	  OMP_CLAUSE_OPERAND (c, 0)
 	    = gimple_boolify (OMP_CLAUSE_OPERAND (c, 0));
@@ -5920,6 +5921,7 @@ gimplify_scan_omp_clauses (tree *list_p,
 	case OMP_CLAUSE_ORDERED:
 	case OMP_CLAUSE_UNTIED:
 	case OMP_CLAUSE_COLLAPSE:
+	case OMP_CLAUSE_MERGEABLE:
 	  break;
 
 	case OMP_CLAUSE_DEFAULT:
@@ -6060,6 +6062,8 @@ gimplify_adjust_omp_clauses (tree *list_
 	case OMP_CLAUSE_DEFAULT:
 	case OMP_CLAUSE_UNTIED:
 	case OMP_CLAUSE_COLLAPSE:
+	case OMP_CLAUSE_FINAL:
+	case OMP_CLAUSE_MERGEABLE:
 	  break;
 
 	default:
--- gcc/tree-nested.c	(revision 172776)
+++ gcc/tree-nested.c	(working copy)
@@ -1097,6 +1097,7 @@ convert_nonlocal_omp_clauses (tree *pcla
 	  if (OMP_CLAUSE_SCHEDULE_CHUNK_EXPR (clause) == NULL)
 	    break;
 	  /* FALLTHRU */
+	case OMP_CLAUSE_FINAL:
 	case OMP_CLAUSE_IF:
 	case OMP_CLAUSE_NUM_THREADS:
 	  wi->val_only = true;
@@ -1111,6 +1112,7 @@ convert_nonlocal_omp_clauses (tree *pcla
 	case OMP_CLAUSE_COPYIN:
 	case OMP_CLAUSE_COLLAPSE:
 	case OMP_CLAUSE_UNTIED:
+	case OMP_CLAUSE_MERGEABLE:
 	  break;
 
 	default:
@@ -1594,6 +1596,7 @@ convert_local_omp_clauses (tree *pclause
 	  if (OMP_CLAUSE_SCHEDULE_CHUNK_EXPR (clause) == NULL)
 	    break;
 	  /* FALLTHRU */
+	case OMP_CLAUSE_FINAL:
 	case OMP_CLAUSE_IF:
 	case OMP_CLAUSE_NUM_THREADS:
 	  wi->val_only = true;
@@ -1608,6 +1611,7 @@ convert_local_omp_clauses (tree *pclause
 	case OMP_CLAUSE_COPYIN:
 	case OMP_CLAUSE_COLLAPSE:
 	case OMP_CLAUSE_UNTIED:
+	case OMP_CLAUSE_MERGEABLE:
 	  break;
 
 	default:
--- gcc/omp-builtins.def	(revision 172776)
+++ gcc/omp-builtins.def	(working copy)
@@ -37,6 +37,8 @@ DEF_GOMP_BUILTIN (BUILT_IN_GOMP_BARRIER,
 		  BT_FN_VOID, ATTR_NOTHROW_LEAF_LIST)
 DEF_GOMP_BUILTIN (BUILT_IN_GOMP_TASKWAIT, "GOMP_taskwait",
 		  BT_FN_VOID, ATTR_NOTHROW_LEAF_LIST)
+DEF_GOMP_BUILTIN (BUILT_IN_GOMP_TASKYIELD, "GOMP_taskyield",
+		  BT_FN_VOID, ATTR_NOTHROW_LEAF_LIST)
 DEF_GOMP_BUILTIN (BUILT_IN_GOMP_CRITICAL_START, "GOMP_critical_start",
 		  BT_FN_VOID, ATTR_NOTHROW_LEAF_LIST)
 DEF_GOMP_BUILTIN (BUILT_IN_GOMP_CRITICAL_END, "GOMP_critical_end",
--- gcc/c-parser.c	(revision 173035)
+++ gcc/c-parser.c	(working copy)
@@ -1156,6 +1156,7 @@ static void c_parser_omp_threadprivate (
 static void c_parser_omp_barrier (c_parser *);
 static void c_parser_omp_flush (c_parser *);
 static void c_parser_omp_taskwait (c_parser *);
+static void c_parser_omp_taskyield (c_parser *);
 
 enum pragma_context { pragma_external, pragma_stmt, pragma_compound };
 static bool c_parser_pragma (c_parser *, enum pragma_context);
@@ -8205,6 +8206,17 @@ c_parser_pragma (c_parser *parser, enum 
       c_parser_omp_taskwait (parser);
       return false;
 
+    case PRAGMA_OMP_TASKYIELD:
+      if (context != pragma_compound)
+	{
+	  if (context == pragma_stmt)
+	    c_parser_error (parser, "%<#pragma omp taskyield%> may only be "
+			    "used in compound statements");
+	  goto bad_stmt;
+	}
+      c_parser_omp_taskyield (parser);
+      return false;
+
     case PRAGMA_OMP_THREADPRIVATE:
       c_parser_omp_threadprivate (parser);
       return false;
@@ -8320,13 +8332,19 @@ c_parser_omp_clause_name (c_parser *pars
 	    result = PRAGMA_OMP_CLAUSE_COPYPRIVATE;
 	  break;
 	case 'f':
-	  if (!strcmp ("firstprivate", p))
+	  if (!strcmp ("final", p))
+	    result = PRAGMA_OMP_CLAUSE_FINAL;
+	  else if (!strcmp ("firstprivate", p))
 	    result = PRAGMA_OMP_CLAUSE_FIRSTPRIVATE;
 	  break;
 	case 'l':
 	  if (!strcmp ("lastprivate", p))
 	    result = PRAGMA_OMP_CLAUSE_LASTPRIVATE;
 	  break;
+	case 'm':
+	  if (!strcmp ("mergeable", p))
+	    result = PRAGMA_OMP_CLAUSE_MERGEABLE;
+	  break;
 	case 'n':
 	  if (!strcmp ("nowait", p))
 	    result = PRAGMA_OMP_CLAUSE_NOWAIT;
@@ -8568,6 +8586,31 @@ c_parser_omp_clause_firstprivate (c_pars
   return c_parser_omp_var_list_parens (parser, OMP_CLAUSE_FIRSTPRIVATE, list);
 }
 
+/* OpenMP 3.1:
+   final ( expression ) */
+
+static tree
+c_parser_omp_clause_final (c_parser *parser, tree list)
+{
+  location_t loc = c_parser_peek_token (parser)->location;
+  if (c_parser_next_token_is (parser, CPP_OPEN_PAREN))
+    {
+      tree t = c_parser_paren_condition (parser);
+      tree c;
+
+      check_no_duplicate_clause (list, OMP_CLAUSE_FINAL, "final");
+
+      c = build_omp_clause (loc, OMP_CLAUSE_FINAL);
+      OMP_CLAUSE_FINAL_EXPR (c) = t;
+      OMP_CLAUSE_CHAIN (c) = list;
+      list = c;
+    }
+  else
+    c_parser_error (parser, "expected %<(%>");
+
+  return list;
+}
+
 /* OpenMP 2.5:
    if ( expression ) */
 
@@ -8602,6 +8645,24 @@ c_parser_omp_clause_lastprivate (c_parse
   return c_parser_omp_var_list_parens (parser, OMP_CLAUSE_LASTPRIVATE, list);
 }
 
+/* OpenMP 3.1:
+   mergeable */
+
+static tree
+c_parser_omp_clause_mergeable (c_parser *parser ATTRIBUTE_UNUSED, tree list)
+{
+  tree c;
+
+  /* FIXME: Should we allow duplicates?  */
+  check_no_duplicate_clause (list, OMP_CLAUSE_MERGEABLE, "mergeable");
+
+  c = build_omp_clause (c_parser_peek_token (parser)->location,
+			OMP_CLAUSE_MERGEABLE);
+  OMP_CLAUSE_CHAIN (c) = list;
+
+  return c;
+}
+
 /* OpenMP 2.5:
    nowait */
 
@@ -8940,6 +9001,10 @@ c_parser_omp_all_clauses (c_parser *pars
 	  clauses = c_parser_omp_clause_firstprivate (parser, clauses);
 	  c_name = "firstprivate";
 	  break;
+	case PRAGMA_OMP_CLAUSE_FINAL:
+	  clauses = c_parser_omp_clause_final (parser, clauses);
+	  c_name = "final";
+	  break;
 	case PRAGMA_OMP_CLAUSE_IF:
 	  clauses = c_parser_omp_clause_if (parser, clauses);
 	  c_name = "if";
@@ -8948,6 +9013,10 @@ c_parser_omp_all_clauses (c_parser *pars
 	  clauses = c_parser_omp_clause_lastprivate (parser, clauses);
 	  c_name = "lastprivate";
 	  break;
+	case PRAGMA_OMP_CLAUSE_MERGEABLE:
+	  clauses = c_parser_omp_clause_mergeable (parser, clauses);
+	  c_name = "mergeable";
+	  break;
 	case PRAGMA_OMP_CLAUSE_NOWAIT:
 	  clauses = c_parser_omp_clause_nowait (parser, clauses);
 	  c_name = "nowait";
@@ -9958,7 +10027,9 @@ c_parser_omp_single (location_t loc, c_p
 	| (1u << PRAGMA_OMP_CLAUSE_DEFAULT)		\
 	| (1u << PRAGMA_OMP_CLAUSE_PRIVATE)		\
 	| (1u << PRAGMA_OMP_CLAUSE_FIRSTPRIVATE)	\
-	| (1u << PRAGMA_OMP_CLAUSE_SHARED))
+	| (1u << PRAGMA_OMP_CLAUSE_SHARED)		\
+	| (1u << PRAGMA_OMP_CLAUSE_FINAL)		\
+	| (1u << PRAGMA_OMP_CLAUSE_MERGEABLE))
 
 static tree
 c_parser_omp_task (location_t loc, c_parser *parser)
@@ -9987,6 +10058,20 @@ c_parser_omp_taskwait (c_parser *parser)
   c_finish_omp_taskwait (loc);
 }
 
+/* OpenMP 3.1:
+   # pragma omp taskyield new-line
+*/
+
+static void
+c_parser_omp_taskyield (c_parser *parser)
+{
+  location_t loc = c_parser_peek_token (parser)->location;
+  c_parser_consume_pragma (parser);
+  c_parser_skip_to_pragma_eol (parser);
+
+  c_finish_omp_taskyield (loc);
+}
+
 /* Main entry point to parsing most OpenMP pragmas.  */
 
 static void
--- libgomp/libgomp_g.h	(revision 172776)
+++ libgomp/libgomp_g.h	(working copy)
@@ -158,11 +158,12 @@ extern void GOMP_ordered_end (void);
 extern void GOMP_parallel_start (void (*) (void *), void *, unsigned);
 extern void GOMP_parallel_end (void);
 
-/* team.c */
+/* task.c */
 
 extern void GOMP_task (void (*) (void *), void *, void (*) (void *, void *),
 		       long, long, bool, unsigned);
 extern void GOMP_taskwait (void);
+extern void GOMP_taskyield (void);
 
 /* sections.c */
 
--- libgomp/libgomp.map	(revision 172776)
+++ libgomp/libgomp.map	(working copy)
@@ -179,3 +179,8 @@ GOMP_2.0 {
 	GOMP_loop_ull_static_next;
 	GOMP_loop_ull_static_start;
 } GOMP_1.0;
+
+GOMP_3.0 {
+  global:
+	GOMP_taskyield;
+} GOMP_2.0;
--- libgomp/libgomp.h	(revision 172776)
+++ libgomp/libgomp.h	(working copy)
@@ -253,6 +253,7 @@ struct gomp_task
   enum gomp_task_kind kind;
   bool in_taskwait;
   bool in_tied_task;
+  bool final_task;
   gomp_sem_t taskwait_sem;
 };
 
--- libgomp/task.c	(revision 172776)
+++ libgomp/task.c	(working copy)
@@ -41,6 +41,7 @@ gomp_init_task (struct gomp_task *task, 
   task->kind = GOMP_TASK_IMPLICIT;
   task->in_taskwait = false;
   task->in_tied_task = false;
+  task->final_task = false;
   task->children = NULL;
   gomp_sem_init (&task->taskwait_sem, 0);
 }
@@ -77,8 +78,7 @@ gomp_clear_parent (struct gomp_task *chi
 
 void
 GOMP_task (void (*fn) (void *), void *data, void (*cpyfn) (void *, void *),
-	   long arg_size, long arg_align, bool if_clause,
-	   unsigned flags __attribute__((unused)))
+	   long arg_size, long arg_align, bool if_clause, unsigned flags)
 {
   struct gomp_thread *thr = gomp_thread ();
   struct gomp_team *team = thr->ts.team;
@@ -95,12 +95,14 @@ GOMP_task (void (*fn) (void *), void *da
 #endif
 
   if (!if_clause || team == NULL
+      || (thr->task && thr->task->final_task)
       || team->task_count > 64 * team->nthreads)
     {
       struct gomp_task task;
 
       gomp_init_task (&task, thr->task, gomp_icv (false));
       task.kind = GOMP_TASK_IFFALSE;
+      task.final_task = (thr->task && thr->task->final_task) || (flags & 2);
       if (thr->task)
 	task.in_tied_task = thr->task->in_tied_task;
       thr->task = &task;
@@ -145,6 +147,7 @@ GOMP_task (void (*fn) (void *), void *da
       task->fn = fn;
       task->fn_data = arg;
       task->in_tied_task = true;
+      task->final_task = (flags & 2) >> 1;
       gomp_mutex_lock (&team->task_lock);
       if (parent->children)
 	{
@@ -363,10 +366,20 @@ GOMP_taskwait (void)
     }
 }
 
+/* Called when encountering a taskyield directive.  */
+
+void
+GOMP_taskyield (void)
+{
+  /* Nothing at the moment.  */
+}
+
 int
 omp_in_final (void)
 {
-  return false; /* FIXME */
+  struct gomp_thread *thr = gomp_thread ();
+  return thr->task && (thr->task->kind == GOMP_TASK_IFFALSE
+		       || thr->task->final_task);
 }
 
 ialias (omp_in_final)
--- libgomp/testsuite/libgomp.c++/task-8.C	(revision 0)
+++ libgomp/testsuite/libgomp.c++/task-8.C	(revision 0)
@@ -0,0 +1,44 @@
+// { dg-do run }
+
+#include <omp.h>
+#include <cstdlib>
+
+int err;
+
+int
+main ()
+{
+  int e;
+#pragma omp parallel shared(err)
+  {
+    if (omp_in_final ())
+      #pragma omp atomic write
+	err = 1;
+    #pragma omp task if (0) shared(err)
+      {
+	if (!omp_in_final ())
+	  #pragma omp atomic write
+	    err = 1;
+	#pragma omp task if (0) shared(err)
+	  if (!omp_in_final ())
+	    #pragma omp atomic write
+	      err = 1;
+      }
+    #pragma omp task final (1) shared(err)
+      {
+	if (!omp_in_final ())
+	  #pragma omp atomic write
+	    err = 1;
+	#pragma omp taskyield
+	#pragma omp taskwait
+	#pragma omp task shared(err)
+	  if (!omp_in_final ())
+	    #pragma omp atomic write
+	      err = 1;
+      }
+  }
+  #pragma omp atomic read
+    e = err;
+  if (e)
+    abort ();
+}
--- libgomp/testsuite/libgomp.fortran/task3.f90	(revision 0)
+++ libgomp/testsuite/libgomp.fortran/task3.f90	(revision 0)
@@ -0,0 +1,43 @@
+! { dg-do run }
+
+  use omp_lib
+  integer :: err, e
+
+!$omp parallel shared(err) private(e)
+  if (omp_in_final ()) then
+!$omp atomic write
+    err = 1
+  endif
+!$omp task if (.false.) shared(err)
+  if (.not.omp_in_final ()) then
+!$omp atomic write
+    err = 1
+  endif
+!$omp task if (.false.) shared(err)
+  if (.not.omp_in_final ()) then
+!$omp atomic write
+    err = 1
+  endif
+!$omp end task
+!$omp end task
+!$omp atomic read
+  e = err
+!$omp task final (e .eq. 0) shared(err)
+  if (.not.omp_in_final ()) then
+!$omp atomic write
+    err = 1
+  endif
+!$omp taskyield
+!$omp taskwait
+!$omp task shared(err)
+  if (.not.omp_in_final ()) then
+!$omp atomic write
+    err = 1
+  endif
+!$omp end task
+!$omp end task
+!$omp end parallel
+!$omp atomic read
+  e = err
+  if (e .ne. 0) call abort
+end
--- libgomp/testsuite/libgomp.c/task-5.c	(revision 0)
+++ libgomp/testsuite/libgomp.c/task-5.c	(revision 0)
@@ -0,0 +1,45 @@
+/* { dg-do run } */
+
+#include <omp.h>
+#include <stdlib.h>
+
+int err;
+
+int
+main ()
+{
+  int e;
+#pragma omp parallel shared(err)
+  {
+    if (omp_in_final ())
+      #pragma omp atomic write
+	err = 1;
+    #pragma omp task if (0) shared(err)
+      {
+	if (!omp_in_final ())
+	  #pragma omp atomic write
+	    err = 1;
+	#pragma omp task if (0) shared(err)
+	  if (!omp_in_final ())
+	    #pragma omp atomic write
+	      err = 1;
+      }
+    #pragma omp task final (1) shared(err)
+      {
+	if (!omp_in_final ())
+	  #pragma omp atomic write
+	    err = 1;
+	#pragma omp taskyield
+	#pragma omp taskwait
+	#pragma omp task shared(err)
+	  if (!omp_in_final ())
+	    #pragma omp atomic write
+	      err = 1;
+      }
+  }
+  #pragma omp atomic read
+    e = err;
+  if (e)
+    abort ();
+  return 0;
+}

	Jakub



More information about the Gcc-patches mailing list