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  <ja...@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

Reply via email to