diff options
author | Kwok Cheung Yeung <kcy@codesourcery.com> | 2021-01-16 12:58:13 -0800 |
---|---|---|
committer | Kwok Cheung Yeung <kcy@codesourcery.com> | 2021-01-16 12:58:13 -0800 |
commit | a6d22fb21c6f1ad7e8b6b722bfc0e7e11f50cb92 (patch) | |
tree | 7d7d0ac7d3170bea065caea25f6942a864b9a73b /libgomp/task.c | |
parent | 5e5d56919dd544a530445cfd8c3f6264f3d706f3 (diff) | |
download | gcc-a6d22fb21c6f1ad7e8b6b722bfc0e7e11f50cb92.zip gcc-a6d22fb21c6f1ad7e8b6b722bfc0e7e11f50cb92.tar.gz gcc-a6d22fb21c6f1ad7e8b6b722bfc0e7e11f50cb92.tar.bz2 |
openmp: Add support for the OpenMP 5.0 task detach clause
2021-01-16 Kwok Cheung Yeung <kcy@codesourcery.com>
gcc/
* builtin-types.def
(BT_FN_VOID_OMPFN_PTR_OMPCPYFN_LONG_LONG_BOOL_UINT_PTR_INT): Rename
to...
(BT_FN_VOID_OMPFN_PTR_OMPCPYFN_LONG_LONG_BOOL_UINT_PTR_INT_PTR):
...this. Add extra argument.
* gimplify.c (omp_default_clause): Ensure that event handle is
firstprivate in a task region.
(gimplify_scan_omp_clauses): Handle OMP_CLAUSE_DETACH.
(gimplify_adjust_omp_clauses): Likewise.
* omp-builtins.def (BUILT_IN_GOMP_TASK): Change function type to
BT_FN_VOID_OMPFN_PTR_OMPCPYFN_LONG_LONG_BOOL_UINT_PTR_INT_PTR.
* omp-expand.c (expand_task_call): Add GOMP_TASK_FLAG_DETACH to flags
if detach clause specified. Add detach argument when generating
call to GOMP_task.
* omp-low.c (scan_sharing_clauses): Setup data environment for detach
clause.
(finish_taskreg_scan): Move field for variable containing the event
handle to the front of the struct.
* tree-core.h (enum omp_clause_code): Add OMP_CLAUSE_DETACH. Fix
ordering.
* tree-nested.c (convert_nonlocal_omp_clauses): Handle
OMP_CLAUSE_DETACH clause.
(convert_local_omp_clauses): Handle OMP_CLAUSE_DETACH clause.
* tree-pretty-print.c (dump_omp_clause): Handle OMP_CLAUSE_DETACH.
* tree.c (omp_clause_num_ops): Add entry for OMP_CLAUSE_DETACH.
Fix ordering.
(omp_clause_code_name): Add entry for OMP_CLAUSE_DETACH. Fix
ordering.
(walk_tree_1): Handle OMP_CLAUSE_DETACH.
gcc/c-family/
* c-pragma.h (pragma_omp_clause): Add PRAGMA_OMP_CLAUSE_DETACH.
Redefine PRAGMA_OACC_CLAUSE_DETACH.
gcc/c/
* c-parser.c (c_parser_omp_clause_detach): New.
(c_parser_omp_all_clauses): Handle PRAGMA_OMP_CLAUSE_DETACH clause.
(OMP_TASK_CLAUSE_MASK): Add mask for PRAGMA_OMP_CLAUSE_DETACH.
* c-typeck.c (c_finish_omp_clauses): Handle PRAGMA_OMP_CLAUSE_DETACH
clause. Prevent use of detach with mergeable and overriding the
data sharing mode of the event handle.
gcc/cp/
* parser.c (cp_parser_omp_clause_detach): New.
(cp_parser_omp_all_clauses): Handle PRAGMA_OMP_CLAUSE_DETACH.
(OMP_TASK_CLAUSE_MASK): Add mask for PRAGMA_OMP_CLAUSE_DETACH.
* pt.c (tsubst_omp_clauses): Handle OMP_CLAUSE_DETACH clause.
* semantics.c (finish_omp_clauses): Handle OMP_CLAUSE_DETACH clause.
Prevent use of detach with mergeable and overriding the data sharing
mode of the event handle.
gcc/fortran/
* dump-parse-tree.c (show_omp_clauses): Handle detach clause.
* frontend-passes.c (gfc_code_walker): Walk detach expression.
* gfortran.h (struct gfc_omp_clauses): Add detach field.
(gfc_c_intptr_kind): New.
* openmp.c (gfc_free_omp_clauses): Free detach clause.
(gfc_match_omp_detach): New.
(enum omp_mask1): Add OMP_CLAUSE_DETACH.
(enum omp_mask2): Remove OMP_CLAUSE_DETACH.
(gfc_match_omp_clauses): Handle OMP_CLAUSE_DETACH for OpenMP.
(OMP_TASK_CLAUSES): Add OMP_CLAUSE_DETACH.
(resolve_omp_clauses): Prevent use of detach with mergeable and
overriding the data sharing mode of the event handle.
* trans-openmp.c (gfc_trans_omp_clauses): Handle detach clause.
* trans-types.c (gfc_c_intptr_kind): New.
(gfc_init_kinds): Initialize gfc_c_intptr_kind.
* types.def
(BT_FN_VOID_OMPFN_PTR_OMPCPYFN_LONG_LONG_BOOL_UINT_PTR_INT): Rename
to...
(BT_FN_VOID_OMPFN_PTR_OMPCPYFN_LONG_LONG_BOOL_UINT_PTR_INT_PTR):
...this. Add extra argument.
gcc/testsuite/
* c-c++-common/gomp/task-detach-1.c: New.
* g++.dg/gomp/task-detach-1.C: New.
* gcc.dg/gomp/task-detach-1.c: New.
* gfortran.dg/gomp/task-detach-1.f90: New.
include/
* gomp-constants.h (GOMP_TASK_FLAG_DETACH): New.
libgomp/
* fortran.c (omp_fulfill_event_): New.
* libgomp.h (struct gomp_task): Add detach and completion_sem fields.
(struct gomp_team): Add task_detach_queue and task_detach_count
fields.
* libgomp.map (OMP_5.0.1): Add omp_fulfill_event and omp_fulfill_event_.
* libgomp_g.h (GOMP_task): Add extra argument.
* omp.h.in (enum omp_event_handle_t): New.
(omp_fulfill_event): New.
* omp_lib.f90.in (omp_event_handle_kind): New.
(omp_fulfill_event): New.
* omp_lib.h.in (omp_event_handle_kind): New.
(omp_fulfill_event): Declare.
* priority_queue.c (priority_tree_find): New.
(priority_list_find): New.
(priority_queue_find): New.
* priority_queue.h (priority_queue_predicate): New.
(priority_queue_find): New.
* task.c (gomp_init_task): Initialize detach field.
(task_fulfilled_p): New.
(GOMP_task): Add detach argument. Ignore detach argument if
GOMP_TASK_FLAG_DETACH not set in flags. Initialize completion_sem
field. Copy address of completion_sem into detach argument and
into the start of the data record. Wait for detach event if task
not deferred.
(gomp_barrier_handle_tasks): Queue tasks with unfulfilled events.
Remove completed tasks and requeue dependent tasks.
(omp_fulfill_event): New.
* team.c (gomp_new_team): Initialize task_detach_queue and
task_detach_count fields.
(free_team): Free task_detach_queue field.
* testsuite/libgomp.c-c++-common/task-detach-1.c: New testcase.
* testsuite/libgomp.c-c++-common/task-detach-2.c: New testcase.
* testsuite/libgomp.c-c++-common/task-detach-3.c: New testcase.
* testsuite/libgomp.c-c++-common/task-detach-4.c: New testcase.
* testsuite/libgomp.c-c++-common/task-detach-5.c: New testcase.
* testsuite/libgomp.c-c++-common/task-detach-6.c: New testcase.
* testsuite/libgomp.fortran/task-detach-1.f90: New testcase.
* testsuite/libgomp.fortran/task-detach-2.f90: New testcase.
* testsuite/libgomp.fortran/task-detach-3.f90: New testcase.
* testsuite/libgomp.fortran/task-detach-4.f90: New testcase.
* testsuite/libgomp.fortran/task-detach-5.f90: New testcase.
* testsuite/libgomp.fortran/task-detach-6.f90: New testcase.
Diffstat (limited to 'libgomp/task.c')
-rw-r--r-- | libgomp/task.c | 132 |
1 files changed, 111 insertions, 21 deletions
diff --git a/libgomp/task.c b/libgomp/task.c index 0e9887d..5ece878 100644 --- a/libgomp/task.c +++ b/libgomp/task.c @@ -86,6 +86,7 @@ gomp_init_task (struct gomp_task *task, struct gomp_task *parent_task, task->dependers = NULL; task->depend_hash = NULL; task->depend_count = 0; + task->detach = false; } /* Clean up a task, after completing it. */ @@ -326,6 +327,12 @@ gomp_task_handle_depend (struct gomp_task *task, struct gomp_task *parent, } } +static bool +task_fulfilled_p (struct gomp_task *task) +{ + return __atomic_load_n (&task->completion_sem, __ATOMIC_RELAXED); +} + /* 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. @@ -347,7 +354,7 @@ gomp_task_handle_depend (struct gomp_task *task, struct gomp_task *parent, void GOMP_task (void (*fn) (void *), void *data, void (*cpyfn) (void *, void *), long arg_size, long arg_align, bool if_clause, unsigned flags, - void **depend, int priority) + void **depend, int priority, void *detach) { struct gomp_thread *thr = gomp_thread (); struct gomp_team *team = thr->ts.team; @@ -383,6 +390,9 @@ GOMP_task (void (*fn) (void *), void *data, void (*cpyfn) (void *, void *), else if (priority > gomp_max_task_priority_var) priority = gomp_max_task_priority_var; + if ((flags & GOMP_TASK_FLAG_DETACH) == 0) + detach = NULL; + if (!if_clause || team == NULL || (thr->task && thr->task->final_task) || team->task_count > 64 * team->nthreads) @@ -404,6 +414,18 @@ GOMP_task (void (*fn) (void *), void *data, void (*cpyfn) (void *, void *), task.final_task = (thr->task && thr->task->final_task) || (flags & GOMP_TASK_FLAG_FINAL); task.priority = priority; + + if (detach) + { + task.detach = true; + gomp_sem_init (&task.completion_sem, 0); + *(void **) detach = &task.completion_sem; + if (data) + *(void **) data = &task.completion_sem; + + gomp_debug (0, "New event: %p\n", &task.completion_sem); + } + if (thr->task) { task.in_tied_task = thr->task->in_tied_task; @@ -420,6 +442,10 @@ GOMP_task (void (*fn) (void *), void *data, void (*cpyfn) (void *, void *), } else fn (data); + + if (detach && !task_fulfilled_p (&task)) + gomp_sem_wait (&task.completion_sem); + /* Access to "children" is normally done inside a task_lock mutex region, but the only way this particular task.children can be set is if this thread's task work function (fn) @@ -458,6 +484,16 @@ GOMP_task (void (*fn) (void *), void *data, void (*cpyfn) (void *, void *), task->kind = GOMP_TASK_UNDEFERRED; task->in_tied_task = parent->in_tied_task; task->taskgroup = taskgroup; + if (detach) + { + task->detach = true; + gomp_sem_init (&task->completion_sem, 0); + *(void **) detach = &task->completion_sem; + if (data) + *(void **) data = &task->completion_sem; + + gomp_debug (0, "New event: %p\n", &task->completion_sem); + } thr->task = task; if (cpyfn) { @@ -1325,6 +1361,28 @@ gomp_barrier_handle_tasks (gomp_barrier_state_t state) while (1) { bool cancelled = false; + + /* Look for a queued detached task with a fulfilled completion event + that is ready to finish. */ + child_task = priority_queue_find (PQ_TEAM, &team->task_detach_queue, + task_fulfilled_p); + if (child_task) + { + priority_queue_remove (PQ_TEAM, &team->task_detach_queue, + child_task, MEMMODEL_RELAXED); + --team->task_detach_count; + gomp_debug (0, "thread %d: found task with fulfilled event %p\n", + thr->ts.team_id, &child_task->completion_sem); + + if (to_free) + { + gomp_finish_task (to_free); + free (to_free); + to_free = NULL; + } + goto finish_cancelled; + } + if (!priority_queue_empty_p (&team->task_queue, MEMMODEL_RELAXED)) { bool ignored; @@ -1392,29 +1450,43 @@ gomp_barrier_handle_tasks (gomp_barrier_state_t state) gomp_mutex_lock (&team->task_lock); if (child_task) { - finish_cancelled:; - size_t new_tasks - = gomp_task_run_post_handle_depend (child_task, team); - gomp_task_run_post_remove_parent (child_task); - gomp_clear_parent (&child_task->children_queue); - gomp_task_run_post_remove_taskgroup (child_task); - to_free = child_task; - child_task = NULL; - if (!cancelled) - team->task_running_count--; - if (new_tasks > 1) + if (child_task->detach && !task_fulfilled_p (child_task)) { - do_wake = team->nthreads - team->task_running_count; - if (do_wake > new_tasks) - do_wake = new_tasks; + priority_queue_insert (PQ_TEAM, &team->task_detach_queue, + child_task, child_task->priority, + PRIORITY_INSERT_END, + false, false); + ++team->task_detach_count; + gomp_debug (0, "thread %d: queueing task with event %p\n", + thr->ts.team_id, &child_task->completion_sem); + child_task = NULL; } - if (--team->task_count == 0 - && gomp_team_barrier_waiting_for_tasks (&team->barrier)) + else { - gomp_team_barrier_done (&team->barrier, state); - gomp_mutex_unlock (&team->task_lock); - gomp_team_barrier_wake (&team->barrier, 0); - gomp_mutex_lock (&team->task_lock); + finish_cancelled:; + size_t new_tasks + = gomp_task_run_post_handle_depend (child_task, team); + gomp_task_run_post_remove_parent (child_task); + gomp_clear_parent (&child_task->children_queue); + gomp_task_run_post_remove_taskgroup (child_task); + to_free = child_task; + child_task = NULL; + if (!cancelled) + team->task_running_count--; + if (new_tasks > 1) + { + do_wake = team->nthreads - team->task_running_count; + if (do_wake > new_tasks) + do_wake = new_tasks; + } + if (--team->task_count == 0 + && gomp_team_barrier_waiting_for_tasks (&team->barrier)) + { + gomp_team_barrier_done (&team->barrier, state); + gomp_mutex_unlock (&team->task_lock); + gomp_team_barrier_wake (&team->barrier, 0); + gomp_mutex_lock (&team->task_lock); + } } } } @@ -2326,3 +2398,21 @@ omp_in_final (void) } ialias (omp_in_final) + +void +omp_fulfill_event (omp_event_handle_t event) +{ + gomp_sem_t *sem = (gomp_sem_t *) event; + struct gomp_thread *thr = gomp_thread (); + struct gomp_team *team = thr ? thr->ts.team : NULL; + + if (__atomic_load_n (sem, __ATOMIC_RELAXED)) + gomp_fatal ("omp_fulfill_event: %p event already fulfilled!\n", sem); + + gomp_debug (0, "omp_fulfill_event: %p\n", sem); + gomp_sem_post (sem); + if (team) + gomp_team_barrier_wake (&team->barrier, 1); +} + +ialias (omp_fulfill_event) |