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