diff --git a/gcc/c/c-parser.cc b/gcc/c/c-parser.cc index 8df8f60ef21..492d995a281 100644 --- a/gcc/c/c-parser.cc +++ b/gcc/c/c-parser.cc @@ -20453,7 +20453,8 @@ c_parser_omp_task (location_t loc, c_parser *parser, bool *if_p) */ #define OMP_TASKWAIT_CLAUSE_MASK \ - (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEPEND) + ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEPEND) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NOWAIT)) static void c_parser_omp_taskwait (c_parser *parser) diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc index 24585c1c013..868b8610d60 100644 --- a/gcc/cp/parser.cc +++ b/gcc/cp/parser.cc @@ -43793,7 +43793,8 @@ cp_parser_omp_task (cp_parser *parser, cp_token *pragma_tok, bool *if_p) # pragma omp taskwait taskwait-clause[opt] new-line */ #define OMP_TASKWAIT_CLAUSE_MASK \ - (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEPEND) + ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEPEND) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NOWAIT)) static void cp_parser_omp_taskwait (cp_parser *parser, cp_token *pragma_tok) diff --git a/gcc/gimplify.cc b/gcc/gimplify.cc index 98f554491e2..cd1796643d7 100644 --- a/gcc/gimplify.cc +++ b/gcc/gimplify.cc @@ -12319,17 +12319,34 @@ gimplify_omp_task (tree *expr_p, gimple_seq *pre_p) tree expr = *expr_p; gimple *g; gimple_seq body = NULL; + bool nowait = false; + bool has_depend = false; if (OMP_TASK_BODY (expr) == NULL_TREE) - for (tree c = OMP_TASK_CLAUSES (expr); c; c = OMP_CLAUSE_CHAIN (c)) - if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_DEPEND - && OMP_CLAUSE_DEPEND_KIND (c) == OMP_CLAUSE_DEPEND_MUTEXINOUTSET) + { + for (tree c = OMP_TASK_CLAUSES (expr); c; c = OMP_CLAUSE_CHAIN (c)) + if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_DEPEND) + { + has_depend = true; + if (OMP_CLAUSE_DEPEND_KIND (c) == OMP_CLAUSE_DEPEND_MUTEXINOUTSET) + { + error_at (OMP_CLAUSE_LOCATION (c), + "% kind in % clause on a " + "% construct"); + break; + } + } + else if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_NOWAIT) + nowait = true; + if (nowait && !has_depend) { - error_at (OMP_CLAUSE_LOCATION (c), - "% kind in % clause on a " - "% construct"); - break; + error_at (EXPR_LOCATION (expr), + "% construct with % clause but no " + "% clauses"); + *expr_p = NULL_TREE; + return; } + } gimplify_scan_omp_clauses (&OMP_TASK_CLAUSES (expr), pre_p, omp_find_clause (OMP_TASK_CLAUSES (expr), diff --git a/gcc/omp-builtins.def b/gcc/omp-builtins.def index cfa6483c7ae..ee5213eedcf 100644 --- a/gcc/omp-builtins.def +++ b/gcc/omp-builtins.def @@ -89,6 +89,9 @@ DEF_GOMP_BUILTIN (BUILT_IN_GOMP_TASKWAIT, "GOMP_taskwait", BT_FN_VOID, ATTR_NOTHROW_LEAF_LIST) DEF_GOMP_BUILTIN (BUILT_IN_GOMP_TASKWAIT_DEPEND, "GOMP_taskwait_depend", BT_FN_VOID_PTR, ATTR_NOTHROW_LEAF_LIST) +DEF_GOMP_BUILTIN (BUILT_IN_GOMP_TASKWAIT_DEPEND_NOWAIT, + "GOMP_taskwait_depend_nowait", + BT_FN_VOID_PTR, 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_TASKGROUP_START, "GOMP_taskgroup_start", diff --git a/gcc/omp-expand.cc b/gcc/omp-expand.cc index 5729a20397d..0821b8d0688 100644 --- a/gcc/omp-expand.cc +++ b/gcc/omp-expand.cc @@ -916,10 +916,12 @@ expand_taskwait_call (basic_block bb, gomp_task *entry_stmt) depend = OMP_CLAUSE_DECL (depend); + bool nowait = omp_find_clause (clauses, OMP_CLAUSE_NOWAIT) != NULL_TREE; gimple_stmt_iterator gsi = gsi_last_nondebug_bb (bb); - tree t - = build_call_expr (builtin_decl_explicit (BUILT_IN_GOMP_TASKWAIT_DEPEND), - 1, depend); + enum built_in_function f = (nowait + ? BUILT_IN_GOMP_TASKWAIT_DEPEND_NOWAIT + : BUILT_IN_GOMP_TASKWAIT_DEPEND); + tree t = build_call_expr (builtin_decl_explicit (f), 1, depend); force_gimple_operand_gsi (&gsi, t, true, NULL_TREE, false, GSI_CONTINUE_LINKING); diff --git a/gcc/testsuite/c-c++-common/gomp/taskwait-depend-nowait-1.c b/gcc/testsuite/c-c++-common/gomp/taskwait-depend-nowait-1.c new file mode 100644 index 00000000000..54df0235bde --- /dev/null +++ b/gcc/testsuite/c-c++-common/gomp/taskwait-depend-nowait-1.c @@ -0,0 +1,17 @@ +void +foo (int *p) +{ + #pragma omp taskwait depend(iterator(i = 0:16) , in : p[i]) nowait depend(out : p[32]) +} + +void +bar (int *p) +{ + #pragma omp taskwait depend(mutexinoutset : p[0]) nowait /* { dg-error "'mutexinoutset' kind in 'depend' clause on a 'taskwait' construct" } */ +} + +void +baz (void) +{ + #pragma omp taskwait nowait /* { dg-error "'taskwait' construct with 'nowait' clause but no 'depend' clauses" } */ +} diff --git a/libgomp/libgomp.map b/libgomp/libgomp.map index 6334fdcce53..46d5f10f3e1 100644 --- a/libgomp/libgomp.map +++ b/libgomp/libgomp.map @@ -410,6 +410,11 @@ GOMP_5.1 { GOMP_teams4; } GOMP_5.0.1; +GOMP_5.1.1 { + global: + GOMP_taskwait_depend_nowait; +} GOMP_5.1; + OACC_2.0 { global: acc_get_num_devices; diff --git a/libgomp/libgomp_g.h b/libgomp/libgomp_g.h index 09674a1225c..84b9f2cfed6 100644 --- a/libgomp/libgomp_g.h +++ b/libgomp/libgomp_g.h @@ -305,6 +305,7 @@ extern void GOMP_taskloop_ull (void (*) (void *), void *, unsigned long long); extern void GOMP_taskwait (void); extern void GOMP_taskwait_depend (void **); +extern void GOMP_taskwait_depend_nowait (void **); extern void GOMP_taskyield (void); extern void GOMP_taskgroup_start (void); extern void GOMP_taskgroup_end (void); diff --git a/libgomp/task.c b/libgomp/task.c index 6b11a8f02ef..7925e5873c4 100644 --- a/libgomp/task.c +++ b/libgomp/task.c @@ -460,6 +460,17 @@ gomp_task_handle_depend (struct gomp_task *task, struct gomp_task *parent, } } +/* Body of empty task like taskwait nowait depend. */ + +static void +empty_task (void *data __attribute__((unused))) +{ +} + +static void gomp_task_run_post_handle_depend_hash (struct gomp_task *); +static inline size_t gomp_task_run_post_handle_depend (struct gomp_task *, + struct gomp_team *); + /* Called when encountering an explicit task directive. If IF_CLAUSE is false, then we must not delay in executing the task. If UNTIED is true, then the task may be executed by any member of the team. @@ -681,6 +692,18 @@ GOMP_task (void (*fn) (void *), void *data, void (*cpyfn) (void *, void *), gomp_mutex_unlock (&team->task_lock); return; } + /* Check for taskwait nowait depend which doesn't need to wait for + anything. */ + if (__builtin_expect (fn == empty_task, 0)) + { + if (taskgroup) + taskgroup->num_children--; + gomp_task_run_post_handle_depend_hash (task); + gomp_mutex_unlock (&team->task_lock); + gomp_finish_task (task); + free (task); + return; + } } priority_queue_insert (PQ_CHILDREN, &parent->children_queue, @@ -839,8 +862,6 @@ GOMP_PLUGIN_target_task_completion (void *data) gomp_mutex_unlock (&team->task_lock); } -static void gomp_task_run_post_handle_depend_hash (struct gomp_task *); - /* Called for nowait target tasks. */ bool @@ -1357,6 +1378,18 @@ gomp_task_run_post_handle_dependers (struct gomp_task *child_task, continue; struct gomp_taskgroup *taskgroup = task->taskgroup; + if (__builtin_expect (task->fn == empty_task, 0)) + { + if (!parent) + task->parent = NULL; + if (gomp_task_run_post_handle_depend (task, team)) + ++ret; + if (taskgroup) + taskgroup->num_children--; + gomp_finish_task (task); + free (task); + continue; + } if (parent) { priority_queue_insert (PQ_CHILDREN, &parent->children_queue, @@ -1832,6 +1865,16 @@ GOMP_taskwait_depend (void **depend) gomp_task_maybe_wait_for_dependencies (depend); } +/* Called when encountering a taskwait directive with nowait and depend + clause(s). Create a possibly deferred task construct with empty body. */ + +void +GOMP_taskwait_depend_nowait (void **depend) +{ + ialias_call (GOMP_task) (empty_task, "", NULL, 0, 1, true, + GOMP_TASK_FLAG_DEPEND, depend, 0, NULL); +} + /* An undeferred task is about to run. Wait for all tasks that this undeferred task depends on. diff --git a/libgomp/testsuite/libgomp.c-c++-common/taskwait-depend-nowait-1.c b/libgomp/testsuite/libgomp.c-c++-common/taskwait-depend-nowait-1.c new file mode 100644 index 00000000000..3d1519ee70a --- /dev/null +++ b/libgomp/testsuite/libgomp.c-c++-common/taskwait-depend-nowait-1.c @@ -0,0 +1,39 @@ +#ifdef __cplusplus +extern "C" +#endif +void abort (void); + +int +main () +{ + int a[64], b = 1; + #pragma omp parallel num_threads (4) + #pragma omp single + { + int i; + #pragma omp taskwait depend(in: a) nowait + #pragma omp taskwait depend(in: a) nowait + #pragma omp taskwait + #pragma omp taskgroup + { + #pragma omp taskwait depend(in: a) nowait + #pragma omp taskwait depend(in: a) nowait + } + for (i = 0; i < 64; ++i) + #pragma omp task depend(in: a) shared(a) + a[i] = i; + #pragma omp taskwait depend(inout: a) nowait + for (i = 0; i < 64; ++i) + #pragma omp task depend(inoutset: a) shared(a) + if (a[i] != i) + abort (); + else + a[i] = 2 * i + 1; + #pragma omp taskwait nowait depend(out: a) depend(in: b) + #pragma omp taskwait depend(inout: b) + for (i = 0; i < 64; ++i) + if (a[i] != 2 * i + 1) + abort (); + } + return 0; +}