10069 lines
304 KiB
Diff
10069 lines
304 KiB
Diff
--- libgomp/loop.c.jj 2018-04-25 09:40:31.870655561 +0200
|
|
+++ libgomp/loop.c 2019-05-07 18:46:36.526109736 +0200
|
|
@@ -27,9 +27,13 @@
|
|
|
|
#include <limits.h>
|
|
#include <stdlib.h>
|
|
+#include <string.h>
|
|
#include "libgomp.h"
|
|
|
|
|
|
+ialias (GOMP_loop_runtime_next)
|
|
+ialias_redirect (GOMP_taskgroup_reduction_register)
|
|
+
|
|
/* Initialize the given work share construct from the given arguments. */
|
|
|
|
static inline void
|
|
@@ -79,12 +83,12 @@ gomp_loop_init (struct gomp_work_share *
|
|
}
|
|
|
|
/* The *_start routines are called when first encountering a loop construct
|
|
- that is not bound directly to a parallel construct. The first thread
|
|
+ that is not bound directly to a parallel construct. The first thread
|
|
that arrives will create the work-share construct; subsequent threads
|
|
will see the construct exists and allocate work from it.
|
|
|
|
START, END, INCR are the bounds of the loop; due to the restrictions of
|
|
- OpenMP, these values must be the same in every thread. This is not
|
|
+ OpenMP, these values must be the same in every thread. This is not
|
|
verified (nor is it entirely verifiable, since START is not necessarily
|
|
retained intact in the work-share data structure). CHUNK_SIZE is the
|
|
scheduling parameter; again this must be identical in all threads.
|
|
@@ -101,7 +105,7 @@ gomp_loop_static_start (long start, long
|
|
struct gomp_thread *thr = gomp_thread ();
|
|
|
|
thr->ts.static_trip = 0;
|
|
- if (gomp_work_share_start (false))
|
|
+ if (gomp_work_share_start (0))
|
|
{
|
|
gomp_loop_init (thr->ts.work_share, start, end, incr,
|
|
GFS_STATIC, chunk_size);
|
|
@@ -123,7 +127,7 @@ gomp_loop_dynamic_start (long start, lon
|
|
struct gomp_thread *thr = gomp_thread ();
|
|
bool ret;
|
|
|
|
- if (gomp_work_share_start (false))
|
|
+ if (gomp_work_share_start (0))
|
|
{
|
|
gomp_loop_init (thr->ts.work_share, start, end, incr,
|
|
GFS_DYNAMIC, chunk_size);
|
|
@@ -151,7 +155,7 @@ gomp_loop_guided_start (long start, long
|
|
struct gomp_thread *thr = gomp_thread ();
|
|
bool ret;
|
|
|
|
- if (gomp_work_share_start (false))
|
|
+ if (gomp_work_share_start (0))
|
|
{
|
|
gomp_loop_init (thr->ts.work_share, start, end, incr,
|
|
GFS_GUIDED, chunk_size);
|
|
@@ -174,7 +178,7 @@ GOMP_loop_runtime_start (long start, lon
|
|
long *istart, long *iend)
|
|
{
|
|
struct gomp_task_icv *icv = gomp_icv (false);
|
|
- switch (icv->run_sched_var)
|
|
+ switch (icv->run_sched_var & ~GFS_MONOTONIC)
|
|
{
|
|
case GFS_STATIC:
|
|
return gomp_loop_static_start (start, end, incr,
|
|
@@ -197,6 +201,100 @@ GOMP_loop_runtime_start (long start, lon
|
|
}
|
|
}
|
|
|
|
+static long
|
|
+gomp_adjust_sched (long sched, long *chunk_size)
|
|
+{
|
|
+ sched &= ~GFS_MONOTONIC;
|
|
+ switch (sched)
|
|
+ {
|
|
+ case GFS_STATIC:
|
|
+ case GFS_DYNAMIC:
|
|
+ case GFS_GUIDED:
|
|
+ return sched;
|
|
+ /* GFS_RUNTIME is used for runtime schedule without monotonic
|
|
+ or nonmonotonic modifiers on the clause.
|
|
+ GFS_RUNTIME|GFS_MONOTONIC for runtime schedule with monotonic
|
|
+ modifier. */
|
|
+ case GFS_RUNTIME:
|
|
+ /* GFS_AUTO is used for runtime schedule with nonmonotonic
|
|
+ modifier. */
|
|
+ case GFS_AUTO:
|
|
+ {
|
|
+ struct gomp_task_icv *icv = gomp_icv (false);
|
|
+ sched = icv->run_sched_var & ~GFS_MONOTONIC;
|
|
+ switch (sched)
|
|
+ {
|
|
+ case GFS_STATIC:
|
|
+ case GFS_DYNAMIC:
|
|
+ case GFS_GUIDED:
|
|
+ *chunk_size = icv->run_sched_chunk_size;
|
|
+ break;
|
|
+ case GFS_AUTO:
|
|
+ sched = GFS_STATIC;
|
|
+ *chunk_size = 0;
|
|
+ break;
|
|
+ default:
|
|
+ abort ();
|
|
+ }
|
|
+ return sched;
|
|
+ }
|
|
+ default:
|
|
+ abort ();
|
|
+ }
|
|
+}
|
|
+
|
|
+bool
|
|
+GOMP_loop_start (long start, long end, long incr, long sched,
|
|
+ long chunk_size, long *istart, long *iend,
|
|
+ uintptr_t *reductions, void **mem)
|
|
+{
|
|
+ struct gomp_thread *thr = gomp_thread ();
|
|
+
|
|
+ thr->ts.static_trip = 0;
|
|
+ if (reductions)
|
|
+ gomp_workshare_taskgroup_start ();
|
|
+ if (gomp_work_share_start (0))
|
|
+ {
|
|
+ sched = gomp_adjust_sched (sched, &chunk_size);
|
|
+ gomp_loop_init (thr->ts.work_share, start, end, incr,
|
|
+ sched, chunk_size);
|
|
+ if (reductions)
|
|
+ {
|
|
+ GOMP_taskgroup_reduction_register (reductions);
|
|
+ thr->task->taskgroup->workshare = true;
|
|
+ thr->ts.work_share->task_reductions = reductions;
|
|
+ }
|
|
+ if (mem)
|
|
+ {
|
|
+ uintptr_t size = (uintptr_t) *mem;
|
|
+ if (size > (sizeof (struct gomp_work_share)
|
|
+ - offsetof (struct gomp_work_share,
|
|
+ inline_ordered_team_ids)))
|
|
+ thr->ts.work_share->ordered_team_ids
|
|
+ = gomp_malloc_cleared (size);
|
|
+ else
|
|
+ memset (thr->ts.work_share->ordered_team_ids, '\0', size);
|
|
+ *mem = (void *) thr->ts.work_share->ordered_team_ids;
|
|
+ }
|
|
+ gomp_work_share_init_done ();
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+ if (reductions)
|
|
+ {
|
|
+ uintptr_t *first_reductions = thr->ts.work_share->task_reductions;
|
|
+ gomp_workshare_task_reduction_register (reductions,
|
|
+ first_reductions);
|
|
+ }
|
|
+ if (mem)
|
|
+ *mem = (void *) thr->ts.work_share->ordered_team_ids;
|
|
+ }
|
|
+
|
|
+ if (!istart)
|
|
+ return true;
|
|
+ return ialias_call (GOMP_loop_runtime_next) (istart, iend);
|
|
+}
|
|
+
|
|
/* The *_ordered_*_start routines are similar. The only difference is that
|
|
this work-share construct is initialized to expect an ORDERED section. */
|
|
|
|
@@ -207,7 +305,7 @@ gomp_loop_ordered_static_start (long sta
|
|
struct gomp_thread *thr = gomp_thread ();
|
|
|
|
thr->ts.static_trip = 0;
|
|
- if (gomp_work_share_start (true))
|
|
+ if (gomp_work_share_start (1))
|
|
{
|
|
gomp_loop_init (thr->ts.work_share, start, end, incr,
|
|
GFS_STATIC, chunk_size);
|
|
@@ -225,7 +323,7 @@ gomp_loop_ordered_dynamic_start (long st
|
|
struct gomp_thread *thr = gomp_thread ();
|
|
bool ret;
|
|
|
|
- if (gomp_work_share_start (true))
|
|
+ if (gomp_work_share_start (1))
|
|
{
|
|
gomp_loop_init (thr->ts.work_share, start, end, incr,
|
|
GFS_DYNAMIC, chunk_size);
|
|
@@ -250,7 +348,7 @@ gomp_loop_ordered_guided_start (long sta
|
|
struct gomp_thread *thr = gomp_thread ();
|
|
bool ret;
|
|
|
|
- if (gomp_work_share_start (true))
|
|
+ if (gomp_work_share_start (1))
|
|
{
|
|
gomp_loop_init (thr->ts.work_share, start, end, incr,
|
|
GFS_GUIDED, chunk_size);
|
|
@@ -273,7 +371,7 @@ GOMP_loop_ordered_runtime_start (long st
|
|
long *istart, long *iend)
|
|
{
|
|
struct gomp_task_icv *icv = gomp_icv (false);
|
|
- switch (icv->run_sched_var)
|
|
+ switch (icv->run_sched_var & ~GFS_MONOTONIC)
|
|
{
|
|
case GFS_STATIC:
|
|
return gomp_loop_ordered_static_start (start, end, incr,
|
|
@@ -297,6 +395,81 @@ GOMP_loop_ordered_runtime_start (long st
|
|
}
|
|
}
|
|
|
|
+bool
|
|
+GOMP_loop_ordered_start (long start, long end, long incr, long sched,
|
|
+ long chunk_size, long *istart, long *iend,
|
|
+ uintptr_t *reductions, void **mem)
|
|
+{
|
|
+ struct gomp_thread *thr = gomp_thread ();
|
|
+ size_t ordered = 1;
|
|
+ bool ret;
|
|
+
|
|
+ thr->ts.static_trip = 0;
|
|
+ if (reductions)
|
|
+ gomp_workshare_taskgroup_start ();
|
|
+ if (mem)
|
|
+ ordered += (uintptr_t) *mem;
|
|
+ if (gomp_work_share_start (ordered))
|
|
+ {
|
|
+ sched = gomp_adjust_sched (sched, &chunk_size);
|
|
+ gomp_loop_init (thr->ts.work_share, start, end, incr,
|
|
+ sched, chunk_size);
|
|
+ if (reductions)
|
|
+ {
|
|
+ GOMP_taskgroup_reduction_register (reductions);
|
|
+ thr->task->taskgroup->workshare = true;
|
|
+ thr->ts.work_share->task_reductions = reductions;
|
|
+ }
|
|
+ if (sched == GFS_STATIC)
|
|
+ gomp_ordered_static_init ();
|
|
+ else
|
|
+ gomp_mutex_lock (&thr->ts.work_share->lock);
|
|
+ gomp_work_share_init_done ();
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+ if (reductions)
|
|
+ {
|
|
+ uintptr_t *first_reductions = thr->ts.work_share->task_reductions;
|
|
+ gomp_workshare_task_reduction_register (reductions,
|
|
+ first_reductions);
|
|
+ }
|
|
+ sched = thr->ts.work_share->sched;
|
|
+ if (sched != GFS_STATIC)
|
|
+ gomp_mutex_lock (&thr->ts.work_share->lock);
|
|
+ }
|
|
+
|
|
+ if (mem)
|
|
+ {
|
|
+ uintptr_t p
|
|
+ = (uintptr_t) (thr->ts.work_share->ordered_team_ids
|
|
+ + (thr->ts.team ? thr->ts.team->nthreads : 1));
|
|
+ p += __alignof__ (long long) - 1;
|
|
+ p &= ~(__alignof__ (long long) - 1);
|
|
+ *mem = (void *) p;
|
|
+ }
|
|
+
|
|
+ switch (sched)
|
|
+ {
|
|
+ case GFS_STATIC:
|
|
+ case GFS_AUTO:
|
|
+ return !gomp_iter_static_next (istart, iend);
|
|
+ case GFS_DYNAMIC:
|
|
+ ret = gomp_iter_dynamic_next_locked (istart, iend);
|
|
+ break;
|
|
+ case GFS_GUIDED:
|
|
+ ret = gomp_iter_guided_next_locked (istart, iend);
|
|
+ break;
|
|
+ default:
|
|
+ abort ();
|
|
+ }
|
|
+
|
|
+ if (ret)
|
|
+ gomp_ordered_first ();
|
|
+ gomp_mutex_unlock (&thr->ts.work_share->lock);
|
|
+ return ret;
|
|
+}
|
|
+
|
|
/* The *_doacross_*_start routines are similar. The only difference is that
|
|
this work-share construct is initialized to expect an ORDERED(N) - DOACROSS
|
|
section, and the worksharing loop iterates always from 0 to COUNTS[0] - 1
|
|
@@ -310,11 +483,11 @@ gomp_loop_doacross_static_start (unsigne
|
|
struct gomp_thread *thr = gomp_thread ();
|
|
|
|
thr->ts.static_trip = 0;
|
|
- if (gomp_work_share_start (false))
|
|
+ if (gomp_work_share_start (0))
|
|
{
|
|
gomp_loop_init (thr->ts.work_share, 0, counts[0], 1,
|
|
GFS_STATIC, chunk_size);
|
|
- gomp_doacross_init (ncounts, counts, chunk_size);
|
|
+ gomp_doacross_init (ncounts, counts, chunk_size, 0);
|
|
gomp_work_share_init_done ();
|
|
}
|
|
|
|
@@ -328,11 +501,11 @@ gomp_loop_doacross_dynamic_start (unsign
|
|
struct gomp_thread *thr = gomp_thread ();
|
|
bool ret;
|
|
|
|
- if (gomp_work_share_start (false))
|
|
+ if (gomp_work_share_start (0))
|
|
{
|
|
gomp_loop_init (thr->ts.work_share, 0, counts[0], 1,
|
|
GFS_DYNAMIC, chunk_size);
|
|
- gomp_doacross_init (ncounts, counts, chunk_size);
|
|
+ gomp_doacross_init (ncounts, counts, chunk_size, 0);
|
|
gomp_work_share_init_done ();
|
|
}
|
|
|
|
@@ -354,11 +527,11 @@ gomp_loop_doacross_guided_start (unsigne
|
|
struct gomp_thread *thr = gomp_thread ();
|
|
bool ret;
|
|
|
|
- if (gomp_work_share_start (false))
|
|
+ if (gomp_work_share_start (0))
|
|
{
|
|
gomp_loop_init (thr->ts.work_share, 0, counts[0], 1,
|
|
GFS_GUIDED, chunk_size);
|
|
- gomp_doacross_init (ncounts, counts, chunk_size);
|
|
+ gomp_doacross_init (ncounts, counts, chunk_size, 0);
|
|
gomp_work_share_init_done ();
|
|
}
|
|
|
|
@@ -378,7 +551,7 @@ GOMP_loop_doacross_runtime_start (unsign
|
|
long *istart, long *iend)
|
|
{
|
|
struct gomp_task_icv *icv = gomp_icv (false);
|
|
- switch (icv->run_sched_var)
|
|
+ switch (icv->run_sched_var & ~GFS_MONOTONIC)
|
|
{
|
|
case GFS_STATIC:
|
|
return gomp_loop_doacross_static_start (ncounts, counts,
|
|
@@ -402,8 +575,52 @@ GOMP_loop_doacross_runtime_start (unsign
|
|
}
|
|
}
|
|
|
|
-/* The *_next routines are called when the thread completes processing of
|
|
- the iteration block currently assigned to it. If the work-share
|
|
+bool
|
|
+GOMP_loop_doacross_start (unsigned ncounts, long *counts, long sched,
|
|
+ long chunk_size, long *istart, long *iend,
|
|
+ uintptr_t *reductions, void **mem)
|
|
+{
|
|
+ struct gomp_thread *thr = gomp_thread ();
|
|
+
|
|
+ thr->ts.static_trip = 0;
|
|
+ if (reductions)
|
|
+ gomp_workshare_taskgroup_start ();
|
|
+ if (gomp_work_share_start (0))
|
|
+ {
|
|
+ size_t extra = 0;
|
|
+ if (mem)
|
|
+ extra = (uintptr_t) *mem;
|
|
+ sched = gomp_adjust_sched (sched, &chunk_size);
|
|
+ gomp_loop_init (thr->ts.work_share, 0, counts[0], 1,
|
|
+ sched, chunk_size);
|
|
+ gomp_doacross_init (ncounts, counts, chunk_size, extra);
|
|
+ if (reductions)
|
|
+ {
|
|
+ GOMP_taskgroup_reduction_register (reductions);
|
|
+ thr->task->taskgroup->workshare = true;
|
|
+ thr->ts.work_share->task_reductions = reductions;
|
|
+ }
|
|
+ gomp_work_share_init_done ();
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+ if (reductions)
|
|
+ {
|
|
+ uintptr_t *first_reductions = thr->ts.work_share->task_reductions;
|
|
+ gomp_workshare_task_reduction_register (reductions,
|
|
+ first_reductions);
|
|
+ }
|
|
+ sched = thr->ts.work_share->sched;
|
|
+ }
|
|
+
|
|
+ if (mem)
|
|
+ *mem = thr->ts.work_share->doacross->extra;
|
|
+
|
|
+ return ialias_call (GOMP_loop_runtime_next) (istart, iend);
|
|
+}
|
|
+
|
|
+/* The *_next routines are called when the thread completes processing of
|
|
+ the iteration block currently assigned to it. If the work-share
|
|
construct is bound directly to a parallel construct, then the iteration
|
|
bounds may have been set up before the parallel. In which case, this
|
|
may be the first iteration for the thread.
|
|
@@ -456,7 +673,7 @@ bool
|
|
GOMP_loop_runtime_next (long *istart, long *iend)
|
|
{
|
|
struct gomp_thread *thr = gomp_thread ();
|
|
-
|
|
+
|
|
switch (thr->ts.work_share->sched)
|
|
{
|
|
case GFS_STATIC:
|
|
@@ -534,7 +751,7 @@ bool
|
|
GOMP_loop_ordered_runtime_next (long *istart, long *iend)
|
|
{
|
|
struct gomp_thread *thr = gomp_thread ();
|
|
-
|
|
+
|
|
switch (thr->ts.work_share->sched)
|
|
{
|
|
case GFS_STATIC:
|
|
@@ -563,7 +780,7 @@ gomp_parallel_loop_start (void (*fn) (vo
|
|
num_threads = gomp_resolve_num_threads (num_threads, 0);
|
|
team = gomp_new_team (num_threads);
|
|
gomp_loop_init (&team->work_shares[0], start, end, incr, sched, chunk_size);
|
|
- gomp_team_start (fn, data, num_threads, flags, team);
|
|
+ gomp_team_start (fn, data, num_threads, flags, team, NULL);
|
|
}
|
|
|
|
void
|
|
@@ -600,7 +817,8 @@ GOMP_parallel_loop_runtime_start (void (
|
|
{
|
|
struct gomp_task_icv *icv = gomp_icv (false);
|
|
gomp_parallel_loop_start (fn, data, num_threads, start, end, incr,
|
|
- icv->run_sched_var, icv->run_sched_chunk_size, 0);
|
|
+ icv->run_sched_var & ~GFS_MONOTONIC,
|
|
+ icv->run_sched_chunk_size, 0);
|
|
}
|
|
|
|
ialias_redirect (GOMP_parallel_end)
|
|
@@ -638,11 +856,28 @@ GOMP_parallel_loop_guided (void (*fn) (v
|
|
GOMP_parallel_end ();
|
|
}
|
|
|
|
+void
|
|
+GOMP_parallel_loop_runtime (void (*fn) (void *), void *data,
|
|
+ unsigned num_threads, long start, long end,
|
|
+ long incr, unsigned flags)
|
|
+{
|
|
+ struct gomp_task_icv *icv = gomp_icv (false);
|
|
+ gomp_parallel_loop_start (fn, data, num_threads, start, end, incr,
|
|
+ icv->run_sched_var & ~GFS_MONOTONIC,
|
|
+ icv->run_sched_chunk_size, flags);
|
|
+ fn (data);
|
|
+ GOMP_parallel_end ();
|
|
+}
|
|
+
|
|
#ifdef HAVE_ATTRIBUTE_ALIAS
|
|
extern __typeof(GOMP_parallel_loop_dynamic) GOMP_parallel_loop_nonmonotonic_dynamic
|
|
__attribute__((alias ("GOMP_parallel_loop_dynamic")));
|
|
extern __typeof(GOMP_parallel_loop_guided) GOMP_parallel_loop_nonmonotonic_guided
|
|
__attribute__((alias ("GOMP_parallel_loop_guided")));
|
|
+extern __typeof(GOMP_parallel_loop_runtime) GOMP_parallel_loop_nonmonotonic_runtime
|
|
+ __attribute__((alias ("GOMP_parallel_loop_runtime")));
|
|
+extern __typeof(GOMP_parallel_loop_runtime) GOMP_parallel_loop_maybe_nonmonotonic_runtime
|
|
+ __attribute__((alias ("GOMP_parallel_loop_runtime")));
|
|
#else
|
|
void
|
|
GOMP_parallel_loop_nonmonotonic_dynamic (void (*fn) (void *), void *data,
|
|
@@ -667,21 +902,35 @@ GOMP_parallel_loop_nonmonotonic_guided (
|
|
fn (data);
|
|
GOMP_parallel_end ();
|
|
}
|
|
-#endif
|
|
|
|
void
|
|
-GOMP_parallel_loop_runtime (void (*fn) (void *), void *data,
|
|
- unsigned num_threads, long start, long end,
|
|
- long incr, unsigned flags)
|
|
+GOMP_parallel_loop_nonmonotonic_runtime (void (*fn) (void *), void *data,
|
|
+ unsigned num_threads, long start,
|
|
+ long end, long incr, unsigned flags)
|
|
{
|
|
struct gomp_task_icv *icv = gomp_icv (false);
|
|
gomp_parallel_loop_start (fn, data, num_threads, start, end, incr,
|
|
- icv->run_sched_var, icv->run_sched_chunk_size,
|
|
- flags);
|
|
+ icv->run_sched_var & ~GFS_MONOTONIC,
|
|
+ icv->run_sched_chunk_size, flags);
|
|
fn (data);
|
|
GOMP_parallel_end ();
|
|
}
|
|
|
|
+void
|
|
+GOMP_parallel_loop_maybe_nonmonotonic_runtime (void (*fn) (void *), void *data,
|
|
+ unsigned num_threads, long start,
|
|
+ long end, long incr,
|
|
+ unsigned flags)
|
|
+{
|
|
+ struct gomp_task_icv *icv = gomp_icv (false);
|
|
+ gomp_parallel_loop_start (fn, data, num_threads, start, end, incr,
|
|
+ icv->run_sched_var & ~GFS_MONOTONIC,
|
|
+ icv->run_sched_chunk_size, flags);
|
|
+ fn (data);
|
|
+ GOMP_parallel_end ();
|
|
+}
|
|
+#endif
|
|
+
|
|
/* The GOMP_loop_end* routines are called after the thread is told that
|
|
all loop iterations are complete. The first two versions synchronize
|
|
all threads; the nowait version does not. */
|
|
@@ -721,6 +970,10 @@ extern __typeof(gomp_loop_dynamic_start)
|
|
__attribute__((alias ("gomp_loop_dynamic_start")));
|
|
extern __typeof(gomp_loop_guided_start) GOMP_loop_nonmonotonic_guided_start
|
|
__attribute__((alias ("gomp_loop_guided_start")));
|
|
+extern __typeof(GOMP_loop_runtime_start) GOMP_loop_nonmonotonic_runtime_start
|
|
+ __attribute__((alias ("GOMP_loop_runtime_start")));
|
|
+extern __typeof(GOMP_loop_runtime_start) GOMP_loop_maybe_nonmonotonic_runtime_start
|
|
+ __attribute__((alias ("GOMP_loop_runtime_start")));
|
|
|
|
extern __typeof(gomp_loop_ordered_static_start) GOMP_loop_ordered_static_start
|
|
__attribute__((alias ("gomp_loop_ordered_static_start")));
|
|
@@ -746,6 +999,10 @@ extern __typeof(gomp_loop_dynamic_next)
|
|
__attribute__((alias ("gomp_loop_dynamic_next")));
|
|
extern __typeof(gomp_loop_guided_next) GOMP_loop_nonmonotonic_guided_next
|
|
__attribute__((alias ("gomp_loop_guided_next")));
|
|
+extern __typeof(GOMP_loop_runtime_next) GOMP_loop_nonmonotonic_runtime_next
|
|
+ __attribute__((alias ("GOMP_loop_runtime_next")));
|
|
+extern __typeof(GOMP_loop_runtime_next) GOMP_loop_maybe_nonmonotonic_runtime_next
|
|
+ __attribute__((alias ("GOMP_loop_runtime_next")));
|
|
|
|
extern __typeof(gomp_loop_ordered_static_next) GOMP_loop_ordered_static_next
|
|
__attribute__((alias ("gomp_loop_ordered_static_next")));
|
|
@@ -791,6 +1048,20 @@ GOMP_loop_nonmonotonic_guided_start (lon
|
|
}
|
|
|
|
bool
|
|
+GOMP_loop_nonmonotonic_runtime_start (long start, long end, long incr,
|
|
+ long *istart, long *iend)
|
|
+{
|
|
+ return GOMP_loop_runtime_start (start, end, incr, istart, iend);
|
|
+}
|
|
+
|
|
+bool
|
|
+GOMP_loop_maybe_nonmonotonic_runtime_start (long start, long end, long incr,
|
|
+ long *istart, long *iend)
|
|
+{
|
|
+ return GOMP_loop_runtime_start (start, end, incr, istart, iend);
|
|
+}
|
|
+
|
|
+bool
|
|
GOMP_loop_ordered_static_start (long start, long end, long incr,
|
|
long chunk_size, long *istart, long *iend)
|
|
{
|
|
@@ -869,6 +1140,18 @@ GOMP_loop_nonmonotonic_guided_next (long
|
|
}
|
|
|
|
bool
|
|
+GOMP_loop_nonmonotonic_runtime_next (long *istart, long *iend)
|
|
+{
|
|
+ return GOMP_loop_runtime_next (istart, iend);
|
|
+}
|
|
+
|
|
+bool
|
|
+GOMP_loop_maybe_nonmonotonic_runtime_next (long *istart, long *iend)
|
|
+{
|
|
+ return GOMP_loop_runtime_next (istart, iend);
|
|
+}
|
|
+
|
|
+bool
|
|
GOMP_loop_ordered_static_next (long *istart, long *iend)
|
|
{
|
|
return gomp_loop_ordered_static_next (istart, iend);
|
|
--- libgomp/oacc-plugin.c.jj 2018-04-25 09:40:31.322655307 +0200
|
|
+++ libgomp/oacc-plugin.c 2019-05-07 18:46:36.531109656 +0200
|
|
@@ -49,3 +49,14 @@ GOMP_PLUGIN_acc_thread (void)
|
|
struct goacc_thread *thr = goacc_thread ();
|
|
return thr ? thr->target_tls : NULL;
|
|
}
|
|
+
|
|
+int
|
|
+GOMP_PLUGIN_acc_default_dim (unsigned int i)
|
|
+{
|
|
+ if (i >= GOMP_DIM_MAX)
|
|
+ {
|
|
+ gomp_fatal ("invalid dimension argument: %d", i);
|
|
+ return -1;
|
|
+ }
|
|
+ return goacc_default_dims[i];
|
|
+}
|
|
--- libgomp/libgomp_g.h.jj 2018-04-25 09:40:31.320655306 +0200
|
|
+++ libgomp/libgomp_g.h 2019-05-07 18:46:36.513109943 +0200
|
|
@@ -1,4 +1,4 @@
|
|
-/* Copyright (C) 2005-2018 Free Software Foundation, Inc.
|
|
+/* Copyright (C) 2005-2019 Free Software Foundation, Inc.
|
|
Contributed by Richard Henderson <rth@redhat.com>.
|
|
|
|
This file is part of the GNU Offloading and Multi Processing Library
|
|
@@ -31,6 +31,7 @@
|
|
|
|
#include <stdbool.h>
|
|
#include <stddef.h>
|
|
+#include "gstdint.h"
|
|
|
|
/* barrier.c */
|
|
|
|
@@ -56,6 +57,12 @@ extern bool GOMP_loop_nonmonotonic_dynam
|
|
long *, long *);
|
|
extern bool GOMP_loop_nonmonotonic_guided_start (long, long, long, long,
|
|
long *, long *);
|
|
+extern bool GOMP_loop_nonmonotonic_runtime_start (long, long, long,
|
|
+ long *, long *);
|
|
+extern bool GOMP_loop_maybe_nonmonotonic_runtime_start (long, long, long,
|
|
+ long *, long *);
|
|
+extern bool GOMP_loop_start (long, long, long, long, long, long *, long *,
|
|
+ uintptr_t *, void **);
|
|
|
|
extern bool GOMP_loop_ordered_static_start (long, long, long, long,
|
|
long *, long *);
|
|
@@ -64,6 +71,8 @@ extern bool GOMP_loop_ordered_dynamic_st
|
|
extern bool GOMP_loop_ordered_guided_start (long, long, long, long,
|
|
long *, long *);
|
|
extern bool GOMP_loop_ordered_runtime_start (long, long, long, long *, long *);
|
|
+extern bool GOMP_loop_ordered_start (long, long, long, long, long, long *,
|
|
+ long *, uintptr_t *, void **);
|
|
|
|
extern bool GOMP_loop_static_next (long *, long *);
|
|
extern bool GOMP_loop_dynamic_next (long *, long *);
|
|
@@ -71,6 +80,8 @@ extern bool GOMP_loop_guided_next (long
|
|
extern bool GOMP_loop_runtime_next (long *, long *);
|
|
extern bool GOMP_loop_nonmonotonic_dynamic_next (long *, long *);
|
|
extern bool GOMP_loop_nonmonotonic_guided_next (long *, long *);
|
|
+extern bool GOMP_loop_nonmonotonic_runtime_next (long *, long *);
|
|
+extern bool GOMP_loop_maybe_nonmonotonic_runtime_next (long *, long *);
|
|
|
|
extern bool GOMP_loop_ordered_static_next (long *, long *);
|
|
extern bool GOMP_loop_ordered_dynamic_next (long *, long *);
|
|
@@ -85,6 +96,8 @@ extern bool GOMP_loop_doacross_guided_st
|
|
long *);
|
|
extern bool GOMP_loop_doacross_runtime_start (unsigned, long *, long *,
|
|
long *);
|
|
+extern bool GOMP_loop_doacross_start (unsigned, long *, long, long, long *,
|
|
+ long *, uintptr_t *, void **);
|
|
|
|
extern void GOMP_parallel_loop_static_start (void (*)(void *), void *,
|
|
unsigned, long, long, long, long);
|
|
@@ -112,6 +125,13 @@ extern void GOMP_parallel_loop_nonmonoto
|
|
extern void GOMP_parallel_loop_nonmonotonic_guided (void (*)(void *), void *,
|
|
unsigned, long, long,
|
|
long, long, unsigned);
|
|
+extern void GOMP_parallel_loop_nonmonotonic_runtime (void (*)(void *), void *,
|
|
+ unsigned, long, long,
|
|
+ long, unsigned);
|
|
+extern void GOMP_parallel_loop_maybe_nonmonotonic_runtime (void (*)(void *),
|
|
+ void *, unsigned,
|
|
+ long, long,
|
|
+ long, unsigned);
|
|
|
|
extern void GOMP_loop_end (void);
|
|
extern void GOMP_loop_end_nowait (void);
|
|
@@ -154,6 +174,21 @@ extern bool GOMP_loop_ull_nonmonotonic_g
|
|
unsigned long long,
|
|
unsigned long long *,
|
|
unsigned long long *);
|
|
+extern bool GOMP_loop_ull_nonmonotonic_runtime_start (bool, unsigned long long,
|
|
+ unsigned long long,
|
|
+ unsigned long long,
|
|
+ unsigned long long *,
|
|
+ unsigned long long *);
|
|
+extern bool GOMP_loop_ull_maybe_nonmonotonic_runtime_start (bool,
|
|
+ unsigned long long,
|
|
+ unsigned long long,
|
|
+ unsigned long long,
|
|
+ unsigned long long *,
|
|
+ unsigned long long *);
|
|
+extern bool GOMP_loop_ull_start (bool, unsigned long long, unsigned long long,
|
|
+ unsigned long long, long, unsigned long long,
|
|
+ unsigned long long *, unsigned long long *,
|
|
+ uintptr_t *, void **);
|
|
|
|
extern bool GOMP_loop_ull_ordered_static_start (bool, unsigned long long,
|
|
unsigned long long,
|
|
@@ -178,6 +213,13 @@ extern bool GOMP_loop_ull_ordered_runtim
|
|
unsigned long long,
|
|
unsigned long long *,
|
|
unsigned long long *);
|
|
+extern bool GOMP_loop_ull_ordered_start (bool, unsigned long long,
|
|
+ unsigned long long,
|
|
+ unsigned long long, long,
|
|
+ unsigned long long,
|
|
+ unsigned long long *,
|
|
+ unsigned long long *,
|
|
+ uintptr_t *, void **);
|
|
|
|
extern bool GOMP_loop_ull_static_next (unsigned long long *,
|
|
unsigned long long *);
|
|
@@ -191,6 +233,10 @@ extern bool GOMP_loop_ull_nonmonotonic_d
|
|
unsigned long long *);
|
|
extern bool GOMP_loop_ull_nonmonotonic_guided_next (unsigned long long *,
|
|
unsigned long long *);
|
|
+extern bool GOMP_loop_ull_nonmonotonic_runtime_next (unsigned long long *,
|
|
+ unsigned long long *);
|
|
+extern bool GOMP_loop_ull_maybe_nonmonotonic_runtime_next (unsigned long long *,
|
|
+ unsigned long long *);
|
|
|
|
extern bool GOMP_loop_ull_ordered_static_next (unsigned long long *,
|
|
unsigned long long *);
|
|
@@ -220,6 +266,11 @@ extern bool GOMP_loop_ull_doacross_runti
|
|
unsigned long long *,
|
|
unsigned long long *,
|
|
unsigned long long *);
|
|
+extern bool GOMP_loop_ull_doacross_start (unsigned, unsigned long long *,
|
|
+ long, unsigned long long,
|
|
+ unsigned long long *,
|
|
+ unsigned long long *,
|
|
+ uintptr_t *, void **);
|
|
|
|
/* ordered.c */
|
|
|
|
@@ -235,6 +286,8 @@ extern void GOMP_doacross_ull_wait (unsi
|
|
extern void GOMP_parallel_start (void (*) (void *), void *, unsigned);
|
|
extern void GOMP_parallel_end (void);
|
|
extern void GOMP_parallel (void (*) (void *), void *, unsigned, unsigned);
|
|
+extern unsigned GOMP_parallel_reductions (void (*) (void *), void *, unsigned,
|
|
+ unsigned);
|
|
extern bool GOMP_cancel (int, bool);
|
|
extern bool GOMP_cancellation_point (int);
|
|
|
|
@@ -251,13 +304,19 @@ extern void GOMP_taskloop_ull (void (*)
|
|
unsigned long long, unsigned long long,
|
|
unsigned long long);
|
|
extern void GOMP_taskwait (void);
|
|
+extern void GOMP_taskwait_depend (void **);
|
|
extern void GOMP_taskyield (void);
|
|
extern void GOMP_taskgroup_start (void);
|
|
extern void GOMP_taskgroup_end (void);
|
|
+extern void GOMP_taskgroup_reduction_register (uintptr_t *);
|
|
+extern void GOMP_taskgroup_reduction_unregister (uintptr_t *);
|
|
+extern void GOMP_task_reduction_remap (size_t, size_t, void **);
|
|
+extern void GOMP_workshare_task_reduction_unregister (bool);
|
|
|
|
/* sections.c */
|
|
|
|
extern unsigned GOMP_sections_start (unsigned);
|
|
+extern unsigned GOMP_sections2_start (unsigned, uintptr_t *, void **);
|
|
extern unsigned GOMP_sections_next (void);
|
|
extern void GOMP_parallel_sections_start (void (*) (void *), void *,
|
|
unsigned, unsigned);
|
|
@@ -293,6 +352,11 @@ extern void GOMP_target_enter_exit_data
|
|
void **);
|
|
extern void GOMP_teams (unsigned int, unsigned int);
|
|
|
|
+/* teams.c */
|
|
+
|
|
+extern void GOMP_teams_reg (void (*) (void *), void *, unsigned, unsigned,
|
|
+ unsigned);
|
|
+
|
|
/* oacc-parallel.c */
|
|
|
|
extern void GOACC_parallel_keyed (int, void (*) (void *), size_t,
|
|
--- libgomp/affinity.c.jj 2018-04-25 09:40:31.913655581 +0200
|
|
+++ libgomp/affinity.c 2019-05-07 18:46:36.254114081 +0200
|
|
@@ -26,6 +26,8 @@
|
|
/* This is a generic stub implementation of a CPU affinity setting. */
|
|
|
|
#include "libgomp.h"
|
|
+#include <string.h>
|
|
+#include <stdio.h>
|
|
|
|
void
|
|
gomp_init_affinity (void)
|
|
@@ -138,5 +140,17 @@ gomp_get_place_proc_ids_8 (int place_num
|
|
(void) ids;
|
|
}
|
|
|
|
+void
|
|
+gomp_display_affinity_place (char *buffer, size_t size, size_t *ret,
|
|
+ int place)
|
|
+{
|
|
+ char buf[sizeof (long) * 3 + 4];
|
|
+ if (gomp_available_cpus > 1)
|
|
+ sprintf (buf, "0-%lu", gomp_available_cpus - 1);
|
|
+ else
|
|
+ strcpy (buf, "0");
|
|
+ gomp_display_string (buffer, size, ret, buf, strlen (buf));
|
|
+}
|
|
+
|
|
ialias(omp_get_place_num_procs)
|
|
ialias(omp_get_place_proc_ids)
|
|
--- libgomp/sections.c.jj 2018-04-25 09:40:31.924655586 +0200
|
|
+++ libgomp/sections.c 2019-05-07 18:46:36.535109592 +0200
|
|
@@ -26,8 +26,11 @@
|
|
/* This file handles the SECTIONS construct. */
|
|
|
|
#include "libgomp.h"
|
|
+#include <string.h>
|
|
|
|
|
|
+ialias_redirect (GOMP_taskgroup_reduction_register)
|
|
+
|
|
/* Initialize the given work share construct from the given arguments. */
|
|
|
|
static inline void
|
|
@@ -72,7 +75,7 @@ GOMP_sections_start (unsigned count)
|
|
struct gomp_thread *thr = gomp_thread ();
|
|
long s, e, ret;
|
|
|
|
- if (gomp_work_share_start (false))
|
|
+ if (gomp_work_share_start (0))
|
|
{
|
|
gomp_sections_init (thr->ts.work_share, count);
|
|
gomp_work_share_init_done ();
|
|
@@ -95,6 +98,66 @@ GOMP_sections_start (unsigned count)
|
|
return ret;
|
|
}
|
|
|
|
+unsigned
|
|
+GOMP_sections2_start (unsigned count, uintptr_t *reductions, void **mem)
|
|
+{
|
|
+ struct gomp_thread *thr = gomp_thread ();
|
|
+ long s, e, ret;
|
|
+
|
|
+ if (reductions)
|
|
+ gomp_workshare_taskgroup_start ();
|
|
+ if (gomp_work_share_start (0))
|
|
+ {
|
|
+ gomp_sections_init (thr->ts.work_share, count);
|
|
+ if (reductions)
|
|
+ {
|
|
+ GOMP_taskgroup_reduction_register (reductions);
|
|
+ thr->task->taskgroup->workshare = true;
|
|
+ thr->ts.work_share->task_reductions = reductions;
|
|
+ }
|
|
+ if (mem)
|
|
+ {
|
|
+ uintptr_t size = (uintptr_t) *mem;
|
|
+ if (size > (sizeof (struct gomp_work_share)
|
|
+ - offsetof (struct gomp_work_share,
|
|
+ inline_ordered_team_ids)))
|
|
+ thr->ts.work_share->ordered_team_ids
|
|
+ = gomp_malloc_cleared (size);
|
|
+ else
|
|
+ memset (thr->ts.work_share->ordered_team_ids, '\0', size);
|
|
+ *mem = (void *) thr->ts.work_share->ordered_team_ids;
|
|
+ }
|
|
+ gomp_work_share_init_done ();
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+ if (reductions)
|
|
+ {
|
|
+ uintptr_t *first_reductions = thr->ts.work_share->task_reductions;
|
|
+ gomp_workshare_task_reduction_register (reductions,
|
|
+ first_reductions);
|
|
+ }
|
|
+ if (mem)
|
|
+ *mem = (void *) thr->ts.work_share->ordered_team_ids;
|
|
+ }
|
|
+
|
|
+#ifdef HAVE_SYNC_BUILTINS
|
|
+ if (gomp_iter_dynamic_next (&s, &e))
|
|
+ ret = s;
|
|
+ else
|
|
+ ret = 0;
|
|
+#else
|
|
+ gomp_mutex_lock (&thr->ts.work_share->lock);
|
|
+ if (gomp_iter_dynamic_next_locked (&s, &e))
|
|
+ ret = s;
|
|
+ else
|
|
+ ret = 0;
|
|
+ gomp_mutex_unlock (&thr->ts.work_share->lock);
|
|
+#endif
|
|
+
|
|
+ return ret;
|
|
+}
|
|
+
|
|
/* This routine is called when the thread completes processing of the
|
|
section currently assigned to it. If the work-share construct is
|
|
bound directly to a parallel construct, then the construct may have
|
|
@@ -140,7 +203,7 @@ GOMP_parallel_sections_start (void (*fn)
|
|
num_threads = gomp_resolve_num_threads (num_threads, count);
|
|
team = gomp_new_team (num_threads);
|
|
gomp_sections_init (&team->work_shares[0], count);
|
|
- gomp_team_start (fn, data, num_threads, 0, team);
|
|
+ gomp_team_start (fn, data, num_threads, 0, team, NULL);
|
|
}
|
|
|
|
ialias_redirect (GOMP_parallel_end)
|
|
@@ -154,7 +217,7 @@ GOMP_parallel_sections (void (*fn) (void
|
|
num_threads = gomp_resolve_num_threads (num_threads, count);
|
|
team = gomp_new_team (num_threads);
|
|
gomp_sections_init (&team->work_shares[0], count);
|
|
- gomp_team_start (fn, data, num_threads, flags, team);
|
|
+ gomp_team_start (fn, data, num_threads, flags, team, NULL);
|
|
fn (data);
|
|
GOMP_parallel_end ();
|
|
}
|
|
--- libgomp/config/linux/affinity.c.jj 2018-04-25 09:40:31.875655563 +0200
|
|
+++ libgomp/config/linux/affinity.c 2019-05-07 18:46:36.344112642 +0200
|
|
@@ -396,6 +396,56 @@ gomp_get_place_proc_ids_8 (int place_num
|
|
*ids++ = i;
|
|
}
|
|
|
|
+void
|
|
+gomp_display_affinity_place (char *buffer, size_t size, size_t *ret,
|
|
+ int place)
|
|
+{
|
|
+ cpu_set_t *cpusetp;
|
|
+ char buf[sizeof (long) * 3 + 4];
|
|
+ if (place >= 0 && place < gomp_places_list_len)
|
|
+ cpusetp = (cpu_set_t *) gomp_places_list[place];
|
|
+ else if (gomp_cpusetp)
|
|
+ cpusetp = gomp_cpusetp;
|
|
+ else
|
|
+ {
|
|
+ if (gomp_available_cpus > 1)
|
|
+ sprintf (buf, "0-%lu", gomp_available_cpus - 1);
|
|
+ else
|
|
+ strcpy (buf, "0");
|
|
+ gomp_display_string (buffer, size, ret, buf, strlen (buf));
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ unsigned long i, max = 8 * gomp_cpuset_size, start;
|
|
+ bool prev_set = false;
|
|
+ start = max;
|
|
+ for (i = 0; i <= max; i++)
|
|
+ {
|
|
+ bool this_set;
|
|
+ if (i == max)
|
|
+ this_set = false;
|
|
+ else
|
|
+ this_set = CPU_ISSET_S (i, gomp_cpuset_size, cpusetp);
|
|
+ if (this_set != prev_set)
|
|
+ {
|
|
+ prev_set = this_set;
|
|
+ if (this_set)
|
|
+ {
|
|
+ char *p = buf;
|
|
+ if (start != max)
|
|
+ *p++ = ',';
|
|
+ sprintf (p, "%lu", i);
|
|
+ start = i;
|
|
+ }
|
|
+ else if (i == start + 1)
|
|
+ continue;
|
|
+ else
|
|
+ sprintf (buf, "-%lu", i - 1);
|
|
+ gomp_display_string (buffer, size, ret, buf, strlen (buf));
|
|
+ }
|
|
+ }
|
|
+}
|
|
+
|
|
ialias(omp_get_place_num_procs)
|
|
ialias(omp_get_place_proc_ids)
|
|
|
|
--- libgomp/config/linux/ia64/futex.h.jj 2018-04-25 09:40:31.877655564 +0200
|
|
+++ libgomp/config/linux/ia64/futex.h 2019-05-07 18:46:36.344112642 +0200
|
|
@@ -45,8 +45,8 @@ sys_futex0(int *addr, int op, int val)
|
|
"=r"(r8), "=r"(r10)
|
|
: "r"(r15), "r"(out0), "r"(out1), "r"(out2), "r"(out3)
|
|
: "memory", "out4", "out5", "out6", "out7",
|
|
- /* Non-stacked integer registers, minus r8, r10, r15. */
|
|
- "r2", "r3", "r9", "r11", "r12", "r13", "r14", "r16", "r17", "r18",
|
|
+ /* Non-stacked integer registers, minus r8, r10, r12, r15. */
|
|
+ "r2", "r3", "r9", "r11", "r13", "r14", "r16", "r17", "r18",
|
|
"r19", "r20", "r21", "r22", "r23", "r24", "r25", "r26", "r27",
|
|
"r28", "r29", "r30", "r31",
|
|
/* Predicate registers. */
|
|
--- libgomp/config/nvptx/teams.c.jj 2019-05-07 18:46:36.459110805 +0200
|
|
+++ libgomp/config/nvptx/teams.c 2019-05-07 18:46:36.459110805 +0200
|
|
@@ -0,0 +1,57 @@
|
|
+/* Copyright (C) 2015-2019 Free Software Foundation, Inc.
|
|
+ Contributed by Alexander Monakov <amonakov@ispras.ru>
|
|
+
|
|
+ This file is part of the GNU Offloading and Multi Processing Library
|
|
+ (libgomp).
|
|
+
|
|
+ Libgomp is free software; you can redistribute it and/or modify it
|
|
+ under the terms of the GNU General Public License as published by
|
|
+ the Free Software Foundation; either version 3, or (at your option)
|
|
+ any later version.
|
|
+
|
|
+ Libgomp is distributed in the hope that it will be useful, but WITHOUT ANY
|
|
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
|
+ FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
|
+ more details.
|
|
+
|
|
+ Under Section 7 of GPL version 3, you are granted additional
|
|
+ permissions described in the GCC Runtime Library Exception, version
|
|
+ 3.1, as published by the Free Software Foundation.
|
|
+
|
|
+ You should have received a copy of the GNU General Public License and
|
|
+ a copy of the GCC Runtime Library Exception along with this program;
|
|
+ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
|
|
+ <http://www.gnu.org/licenses/>. */
|
|
+
|
|
+/* This file defines OpenMP API entry points that accelerator targets are
|
|
+ expected to replace. */
|
|
+
|
|
+#include "libgomp.h"
|
|
+
|
|
+void
|
|
+GOMP_teams_reg (void (*fn) (void *), void *data, unsigned int num_teams,
|
|
+ unsigned int thread_limit, unsigned int flags)
|
|
+{
|
|
+ (void) fn;
|
|
+ (void) data;
|
|
+ (void) flags;
|
|
+ (void) num_teams;
|
|
+ (void) thread_limit;
|
|
+}
|
|
+
|
|
+int
|
|
+omp_get_num_teams (void)
|
|
+{
|
|
+ return gomp_num_teams_var + 1;
|
|
+}
|
|
+
|
|
+int
|
|
+omp_get_team_num (void)
|
|
+{
|
|
+ int ctaid;
|
|
+ asm ("mov.u32 %0, %%ctaid.x;" : "=r" (ctaid));
|
|
+ return ctaid;
|
|
+}
|
|
+
|
|
+ialias (omp_get_num_teams)
|
|
+ialias (omp_get_team_num)
|
|
--- libgomp/config/nvptx/team.c.jj 2018-04-25 09:40:31.890655570 +0200
|
|
+++ libgomp/config/nvptx/team.c 2019-05-07 18:46:36.459110805 +0200
|
|
@@ -116,7 +116,8 @@ gomp_thread_start (struct gomp_thread_po
|
|
|
|
void
|
|
gomp_team_start (void (*fn) (void *), void *data, unsigned nthreads,
|
|
- unsigned flags, struct gomp_team *team)
|
|
+ unsigned flags, struct gomp_team *team,
|
|
+ struct gomp_taskgroup *taskgroup)
|
|
{
|
|
struct gomp_thread *thr, *nthr;
|
|
struct gomp_task *task;
|
|
@@ -147,6 +148,7 @@ gomp_team_start (void (*fn) (void *), vo
|
|
nthreads_var = icv->nthreads_var;
|
|
gomp_init_task (thr->task, task, icv);
|
|
team->implicit_task[0].icv.nthreads_var = nthreads_var;
|
|
+ team->implicit_task[0].taskgroup = taskgroup;
|
|
|
|
if (nthreads == 1)
|
|
return;
|
|
@@ -166,6 +168,7 @@ gomp_team_start (void (*fn) (void *), vo
|
|
nthr->task = &team->implicit_task[i];
|
|
gomp_init_task (nthr->task, task, icv);
|
|
team->implicit_task[i].icv.nthreads_var = nthreads_var;
|
|
+ team->implicit_task[i].taskgroup = taskgroup;
|
|
nthr->fn = fn;
|
|
nthr->data = data;
|
|
team->ordered_release[i] = &nthr->release;
|
|
@@ -174,5 +177,11 @@ gomp_team_start (void (*fn) (void *), vo
|
|
gomp_simple_barrier_wait (&pool->threads_dock);
|
|
}
|
|
|
|
+int
|
|
+gomp_pause_host (void)
|
|
+{
|
|
+ return -1;
|
|
+}
|
|
+
|
|
#include "../../team.c"
|
|
#endif
|
|
--- libgomp/config/nvptx/oacc-parallel.c.jj 2018-04-25 09:40:31.887655569 +0200
|
|
+++ libgomp/config/nvptx/oacc-parallel.c 2019-05-07 18:46:36.453110901 +0200
|
|
@@ -1,358 +0,0 @@
|
|
-/* OpenACC constructs
|
|
-
|
|
- Copyright (C) 2014-2018 Free Software Foundation, Inc.
|
|
-
|
|
- Contributed by Mentor Embedded.
|
|
-
|
|
- This file is part of the GNU Offloading and Multi Processing Library
|
|
- (libgomp).
|
|
-
|
|
- Libgomp is free software; you can redistribute it and/or modify it
|
|
- under the terms of the GNU General Public License as published by
|
|
- the Free Software Foundation; either version 3, or (at your option)
|
|
- any later version.
|
|
-
|
|
- Libgomp is distributed in the hope that it will be useful, but WITHOUT ANY
|
|
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
|
- FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
|
- more details.
|
|
-
|
|
- Under Section 7 of GPL version 3, you are granted additional
|
|
- permissions described in the GCC Runtime Library Exception, version
|
|
- 3.1, as published by the Free Software Foundation.
|
|
-
|
|
- You should have received a copy of the GNU General Public License and
|
|
- a copy of the GCC Runtime Library Exception along with this program;
|
|
- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
|
|
- <http://www.gnu.org/licenses/>. */
|
|
-
|
|
-#include "libgomp_g.h"
|
|
-
|
|
-__asm__ (".visible .func (.param .u32 %out_retval) GOACC_tid (.param .u32 %in_ar1);\n"
|
|
- ".visible .func (.param .u32 %out_retval) GOACC_ntid (.param .u32 %in_ar1);\n"
|
|
- ".visible .func (.param .u32 %out_retval) GOACC_ctaid (.param .u32 %in_ar1);\n"
|
|
- ".visible .func (.param .u32 %out_retval) GOACC_nctaid (.param .u32 %in_ar1);\n"
|
|
- "// BEGIN GLOBAL FUNCTION DECL: GOACC_get_num_threads\n"
|
|
- ".visible .func (.param .u32 %out_retval) GOACC_get_num_threads;\n"
|
|
- "// BEGIN GLOBAL FUNCTION DECL: GOACC_get_thread_num\n"
|
|
- ".visible .func (.param .u32 %out_retval) GOACC_get_thread_num;\n"
|
|
- "// BEGIN GLOBAL FUNCTION DECL: abort\n"
|
|
- ".extern .func abort;\n"
|
|
- ".visible .func (.param .u32 %out_retval) GOACC_tid (.param .u32 %in_ar1)\n"
|
|
- "{\n"
|
|
- ".reg .u32 %ar1;\n"
|
|
- ".reg .u32 %retval;\n"
|
|
- ".reg .u64 %hr10;\n"
|
|
- ".reg .u32 %r22;\n"
|
|
- ".reg .u32 %r23;\n"
|
|
- ".reg .u32 %r24;\n"
|
|
- ".reg .u32 %r25;\n"
|
|
- ".reg .u32 %r26;\n"
|
|
- ".reg .u32 %r27;\n"
|
|
- ".reg .u32 %r28;\n"
|
|
- ".reg .u32 %r29;\n"
|
|
- ".reg .pred %r30;\n"
|
|
- ".reg .u32 %r31;\n"
|
|
- ".reg .pred %r32;\n"
|
|
- ".reg .u32 %r33;\n"
|
|
- ".reg .pred %r34;\n"
|
|
- ".local .align 8 .b8 %frame[4];\n"
|
|
- "ld.param.u32 %ar1,[%in_ar1];\n"
|
|
- "mov.u32 %r27,%ar1;\n"
|
|
- "st.local.u32 [%frame],%r27;\n"
|
|
- "ld.local.u32 %r28,[%frame];\n"
|
|
- "mov.u32 %r29,1;\n"
|
|
- "setp.eq.u32 %r30,%r28,%r29;\n"
|
|
- "@%r30 bra $L4;\n"
|
|
- "mov.u32 %r31,2;\n"
|
|
- "setp.eq.u32 %r32,%r28,%r31;\n"
|
|
- "@%r32 bra $L5;\n"
|
|
- "mov.u32 %r33,0;\n"
|
|
- "setp.eq.u32 %r34,%r28,%r33;\n"
|
|
- "@!%r34 bra $L8;\n"
|
|
- "mov.u32 %r23,%tid.x;\n"
|
|
- "mov.u32 %r22,%r23;\n"
|
|
- "bra $L7;\n"
|
|
- "$L4:\n"
|
|
- "mov.u32 %r24,%tid.y;\n"
|
|
- "mov.u32 %r22,%r24;\n"
|
|
- "bra $L7;\n"
|
|
- "$L5:\n"
|
|
- "mov.u32 %r25,%tid.z;\n"
|
|
- "mov.u32 %r22,%r25;\n"
|
|
- "bra $L7;\n"
|
|
- "$L8:\n"
|
|
- "{\n"
|
|
- "{\n"
|
|
- "call abort;\n"
|
|
- "}\n"
|
|
- "}\n"
|
|
- "$L7:\n"
|
|
- "mov.u32 %r26,%r22;\n"
|
|
- "mov.u32 %retval,%r26;\n"
|
|
- "st.param.u32 [%out_retval],%retval;\n"
|
|
- "ret;\n"
|
|
- "}\n"
|
|
- ".visible .func (.param .u32 %out_retval) GOACC_ntid (.param .u32 %in_ar1)\n"
|
|
- "{\n"
|
|
- ".reg .u32 %ar1;\n"
|
|
- ".reg .u32 %retval;\n"
|
|
- ".reg .u64 %hr10;\n"
|
|
- ".reg .u32 %r22;\n"
|
|
- ".reg .u32 %r23;\n"
|
|
- ".reg .u32 %r24;\n"
|
|
- ".reg .u32 %r25;\n"
|
|
- ".reg .u32 %r26;\n"
|
|
- ".reg .u32 %r27;\n"
|
|
- ".reg .u32 %r28;\n"
|
|
- ".reg .u32 %r29;\n"
|
|
- ".reg .pred %r30;\n"
|
|
- ".reg .u32 %r31;\n"
|
|
- ".reg .pred %r32;\n"
|
|
- ".reg .u32 %r33;\n"
|
|
- ".reg .pred %r34;\n"
|
|
- ".local .align 8 .b8 %frame[4];\n"
|
|
- "ld.param.u32 %ar1,[%in_ar1];\n"
|
|
- "mov.u32 %r27,%ar1;\n"
|
|
- "st.local.u32 [%frame],%r27;\n"
|
|
- "ld.local.u32 %r28,[%frame];\n"
|
|
- "mov.u32 %r29,1;\n"
|
|
- "setp.eq.u32 %r30,%r28,%r29;\n"
|
|
- "@%r30 bra $L11;\n"
|
|
- "mov.u32 %r31,2;\n"
|
|
- "setp.eq.u32 %r32,%r28,%r31;\n"
|
|
- "@%r32 bra $L12;\n"
|
|
- "mov.u32 %r33,0;\n"
|
|
- "setp.eq.u32 %r34,%r28,%r33;\n"
|
|
- "@!%r34 bra $L15;\n"
|
|
- "mov.u32 %r23,%ntid.x;\n"
|
|
- "mov.u32 %r22,%r23;\n"
|
|
- "bra $L14;\n"
|
|
- "$L11:\n"
|
|
- "mov.u32 %r24,%ntid.y;\n"
|
|
- "mov.u32 %r22,%r24;\n"
|
|
- "bra $L14;\n"
|
|
- "$L12:\n"
|
|
- "mov.u32 %r25,%ntid.z;\n"
|
|
- "mov.u32 %r22,%r25;\n"
|
|
- "bra $L14;\n"
|
|
- "$L15:\n"
|
|
- "{\n"
|
|
- "{\n"
|
|
- "call abort;\n"
|
|
- "}\n"
|
|
- "}\n"
|
|
- "$L14:\n"
|
|
- "mov.u32 %r26,%r22;\n"
|
|
- "mov.u32 %retval,%r26;\n"
|
|
- "st.param.u32 [%out_retval],%retval;\n"
|
|
- "ret;\n"
|
|
- "}\n"
|
|
- ".visible .func (.param .u32 %out_retval) GOACC_ctaid (.param .u32 %in_ar1)\n"
|
|
- "{\n"
|
|
- ".reg .u32 %ar1;\n"
|
|
- ".reg .u32 %retval;\n"
|
|
- ".reg .u64 %hr10;\n"
|
|
- ".reg .u32 %r22;\n"
|
|
- ".reg .u32 %r23;\n"
|
|
- ".reg .u32 %r24;\n"
|
|
- ".reg .u32 %r25;\n"
|
|
- ".reg .u32 %r26;\n"
|
|
- ".reg .u32 %r27;\n"
|
|
- ".reg .u32 %r28;\n"
|
|
- ".reg .u32 %r29;\n"
|
|
- ".reg .pred %r30;\n"
|
|
- ".reg .u32 %r31;\n"
|
|
- ".reg .pred %r32;\n"
|
|
- ".reg .u32 %r33;\n"
|
|
- ".reg .pred %r34;\n"
|
|
- ".local .align 8 .b8 %frame[4];\n"
|
|
- "ld.param.u32 %ar1,[%in_ar1];\n"
|
|
- "mov.u32 %r27,%ar1;\n"
|
|
- "st.local.u32 [%frame],%r27;\n"
|
|
- "ld.local.u32 %r28,[%frame];\n"
|
|
- "mov.u32 %r29,1;\n"
|
|
- "setp.eq.u32 %r30,%r28,%r29;\n"
|
|
- "@%r30 bra $L18;\n"
|
|
- "mov.u32 %r31,2;\n"
|
|
- "setp.eq.u32 %r32,%r28,%r31;\n"
|
|
- "@%r32 bra $L19;\n"
|
|
- "mov.u32 %r33,0;\n"
|
|
- "setp.eq.u32 %r34,%r28,%r33;\n"
|
|
- "@!%r34 bra $L22;\n"
|
|
- "mov.u32 %r23,%ctaid.x;\n"
|
|
- "mov.u32 %r22,%r23;\n"
|
|
- "bra $L21;\n"
|
|
- "$L18:\n"
|
|
- "mov.u32 %r24,%ctaid.y;\n"
|
|
- "mov.u32 %r22,%r24;\n"
|
|
- "bra $L21;\n"
|
|
- "$L19:\n"
|
|
- "mov.u32 %r25,%ctaid.z;\n"
|
|
- "mov.u32 %r22,%r25;\n"
|
|
- "bra $L21;\n"
|
|
- "$L22:\n"
|
|
- "{\n"
|
|
- "{\n"
|
|
- "call abort;\n"
|
|
- "}\n"
|
|
- "}\n"
|
|
- "$L21:\n"
|
|
- "mov.u32 %r26,%r22;\n"
|
|
- "mov.u32 %retval,%r26;\n"
|
|
- "st.param.u32 [%out_retval],%retval;\n"
|
|
- "ret;\n"
|
|
- "}\n"
|
|
- ".visible .func (.param .u32 %out_retval) GOACC_nctaid (.param .u32 %in_ar1)\n"
|
|
- "{\n"
|
|
- ".reg .u32 %ar1;\n"
|
|
- ".reg .u32 %retval;\n"
|
|
- ".reg .u64 %hr10;\n"
|
|
- ".reg .u32 %r22;\n"
|
|
- ".reg .u32 %r23;\n"
|
|
- ".reg .u32 %r24;\n"
|
|
- ".reg .u32 %r25;\n"
|
|
- ".reg .u32 %r26;\n"
|
|
- ".reg .u32 %r27;\n"
|
|
- ".reg .u32 %r28;\n"
|
|
- ".reg .u32 %r29;\n"
|
|
- ".reg .pred %r30;\n"
|
|
- ".reg .u32 %r31;\n"
|
|
- ".reg .pred %r32;\n"
|
|
- ".reg .u32 %r33;\n"
|
|
- ".reg .pred %r34;\n"
|
|
- ".local .align 8 .b8 %frame[4];\n"
|
|
- "ld.param.u32 %ar1,[%in_ar1];\n"
|
|
- "mov.u32 %r27,%ar1;\n"
|
|
- "st.local.u32 [%frame],%r27;\n"
|
|
- "ld.local.u32 %r28,[%frame];\n"
|
|
- "mov.u32 %r29,1;\n"
|
|
- "setp.eq.u32 %r30,%r28,%r29;\n"
|
|
- "@%r30 bra $L25;\n"
|
|
- "mov.u32 %r31,2;\n"
|
|
- "setp.eq.u32 %r32,%r28,%r31;\n"
|
|
- "@%r32 bra $L26;\n"
|
|
- "mov.u32 %r33,0;\n"
|
|
- "setp.eq.u32 %r34,%r28,%r33;\n"
|
|
- "@!%r34 bra $L29;\n"
|
|
- "mov.u32 %r23,%nctaid.x;\n"
|
|
- "mov.u32 %r22,%r23;\n"
|
|
- "bra $L28;\n"
|
|
- "$L25:\n"
|
|
- "mov.u32 %r24,%nctaid.y;\n"
|
|
- "mov.u32 %r22,%r24;\n"
|
|
- "bra $L28;\n"
|
|
- "$L26:\n"
|
|
- "mov.u32 %r25,%nctaid.z;\n"
|
|
- "mov.u32 %r22,%r25;\n"
|
|
- "bra $L28;\n"
|
|
- "$L29:\n"
|
|
- "{\n"
|
|
- "{\n"
|
|
- "call abort;\n"
|
|
- "}\n"
|
|
- "}\n"
|
|
- "$L28:\n"
|
|
- "mov.u32 %r26,%r22;\n"
|
|
- "mov.u32 %retval,%r26;\n"
|
|
- "st.param.u32 [%out_retval],%retval;\n"
|
|
- "ret;\n"
|
|
- "}\n"
|
|
- "// BEGIN GLOBAL FUNCTION DEF: GOACC_get_num_threads\n"
|
|
- ".visible .func (.param .u32 %out_retval) GOACC_get_num_threads\n"
|
|
- "{\n"
|
|
- ".reg .u32 %retval;\n"
|
|
- ".reg .u64 %hr10;\n"
|
|
- ".reg .u32 %r22;\n"
|
|
- ".reg .u32 %r23;\n"
|
|
- ".reg .u32 %r24;\n"
|
|
- ".reg .u32 %r25;\n"
|
|
- ".reg .u32 %r26;\n"
|
|
- ".reg .u32 %r27;\n"
|
|
- ".reg .u32 %r28;\n"
|
|
- ".reg .u32 %r29;\n"
|
|
- "mov.u32 %r26,0;\n"
|
|
- "{\n"
|
|
- ".param .u32 %retval_in;\n"
|
|
- "{\n"
|
|
- ".param .u32 %out_arg0;\n"
|
|
- "st.param.u32 [%out_arg0],%r26;\n"
|
|
- "call (%retval_in),GOACC_ntid,(%out_arg0);\n"
|
|
- "}\n"
|
|
- "ld.param.u32 %r27,[%retval_in];\n"
|
|
- "}\n"
|
|
- "mov.u32 %r22,%r27;\n"
|
|
- "mov.u32 %r28,0;\n"
|
|
- "{\n"
|
|
- ".param .u32 %retval_in;\n"
|
|
- "{\n"
|
|
- ".param .u32 %out_arg0;\n"
|
|
- "st.param.u32 [%out_arg0],%r28;\n"
|
|
- "call (%retval_in),GOACC_nctaid,(%out_arg0);\n"
|
|
- "}\n"
|
|
- "ld.param.u32 %r29,[%retval_in];\n"
|
|
- "}\n"
|
|
- "mov.u32 %r23,%r29;\n"
|
|
- "mul.lo.u32 %r24,%r22,%r23;\n"
|
|
- "mov.u32 %r25,%r24;\n"
|
|
- "mov.u32 %retval,%r25;\n"
|
|
- "st.param.u32 [%out_retval],%retval;\n"
|
|
- "ret;\n"
|
|
- "}\n"
|
|
- "// BEGIN GLOBAL FUNCTION DEF: GOACC_get_thread_num\n"
|
|
- ".visible .func (.param .u32 %out_retval) GOACC_get_thread_num\n"
|
|
- "{\n"
|
|
- ".reg .u32 %retval;\n"
|
|
- ".reg .u64 %hr10;\n"
|
|
- ".reg .u32 %r22;\n"
|
|
- ".reg .u32 %r23;\n"
|
|
- ".reg .u32 %r24;\n"
|
|
- ".reg .u32 %r25;\n"
|
|
- ".reg .u32 %r26;\n"
|
|
- ".reg .u32 %r27;\n"
|
|
- ".reg .u32 %r28;\n"
|
|
- ".reg .u32 %r29;\n"
|
|
- ".reg .u32 %r30;\n"
|
|
- ".reg .u32 %r31;\n"
|
|
- ".reg .u32 %r32;\n"
|
|
- ".reg .u32 %r33;\n"
|
|
- "mov.u32 %r28,0;\n"
|
|
- "{\n"
|
|
- ".param .u32 %retval_in;\n"
|
|
- "{\n"
|
|
- ".param .u32 %out_arg0;\n"
|
|
- "st.param.u32 [%out_arg0],%r28;\n"
|
|
- "call (%retval_in),GOACC_ntid,(%out_arg0);\n"
|
|
- "}\n"
|
|
- "ld.param.u32 %r29,[%retval_in];\n"
|
|
- "}\n"
|
|
- "mov.u32 %r22,%r29;\n"
|
|
- "mov.u32 %r30,0;\n"
|
|
- "{\n"
|
|
- ".param .u32 %retval_in;\n"
|
|
- "{\n"
|
|
- ".param .u32 %out_arg0;\n"
|
|
- "st.param.u32 [%out_arg0],%r30;\n"
|
|
- "call (%retval_in),GOACC_ctaid,(%out_arg0);\n"
|
|
- "}\n"
|
|
- "ld.param.u32 %r31,[%retval_in];\n"
|
|
- "}\n"
|
|
- "mov.u32 %r23,%r31;\n"
|
|
- "mul.lo.u32 %r24,%r22,%r23;\n"
|
|
- "mov.u32 %r32,0;\n"
|
|
- "{\n"
|
|
- ".param .u32 %retval_in;\n"
|
|
- "{\n"
|
|
- ".param .u32 %out_arg0;\n"
|
|
- "st.param.u32 [%out_arg0],%r32;\n"
|
|
- "call (%retval_in),GOACC_tid,(%out_arg0);\n"
|
|
- "}\n"
|
|
- "ld.param.u32 %r33,[%retval_in];\n"
|
|
- "}\n"
|
|
- "mov.u32 %r25,%r33;\n"
|
|
- "add.u32 %r26,%r24,%r25;\n"
|
|
- "mov.u32 %r27,%r26;\n"
|
|
- "mov.u32 %retval,%r27;\n"
|
|
- "st.param.u32 [%out_retval],%retval;\n"
|
|
- "ret;\n"
|
|
- "}\n");
|
|
--- libgomp/config/nvptx/target.c.jj 2018-04-25 09:40:31.890655570 +0200
|
|
+++ libgomp/config/nvptx/target.c 2019-05-07 18:46:36.453110901 +0200
|
|
@@ -47,3 +47,21 @@ GOMP_teams (unsigned int num_teams, unsi
|
|
}
|
|
gomp_num_teams_var = num_teams - 1;
|
|
}
|
|
+
|
|
+int
|
|
+omp_pause_resource (omp_pause_resource_t kind, int device_num)
|
|
+{
|
|
+ (void) kind;
|
|
+ (void) device_num;
|
|
+ return -1;
|
|
+}
|
|
+
|
|
+int
|
|
+omp_pause_resource_all (omp_pause_resource_t kind)
|
|
+{
|
|
+ (void) kind;
|
|
+ return -1;
|
|
+}
|
|
+
|
|
+ialias (omp_pause_resource)
|
|
+ialias (omp_pause_resource_all)
|
|
--- libgomp/config/nvptx/icv-device.c.jj 2018-04-25 09:40:31.889655570 +0200
|
|
+++ libgomp/config/nvptx/icv-device.c 2019-05-07 18:46:36.453110901 +0200
|
|
@@ -46,20 +46,6 @@ omp_get_num_devices (void)
|
|
}
|
|
|
|
int
|
|
-omp_get_num_teams (void)
|
|
-{
|
|
- return gomp_num_teams_var + 1;
|
|
-}
|
|
-
|
|
-int
|
|
-omp_get_team_num (void)
|
|
-{
|
|
- int ctaid;
|
|
- asm ("mov.u32 %0, %%ctaid.x;" : "=r" (ctaid));
|
|
- return ctaid;
|
|
-}
|
|
-
|
|
-int
|
|
omp_is_initial_device (void)
|
|
{
|
|
/* NVPTX is an accelerator-only target. */
|
|
@@ -69,6 +55,4 @@ omp_is_initial_device (void)
|
|
ialias (omp_set_default_device)
|
|
ialias (omp_get_default_device)
|
|
ialias (omp_get_num_devices)
|
|
-ialias (omp_get_num_teams)
|
|
-ialias (omp_get_team_num)
|
|
ialias (omp_is_initial_device)
|
|
--- libgomp/config/nvptx/affinity-fmt.c.jj 2019-05-07 18:46:36.358112419 +0200
|
|
+++ libgomp/config/nvptx/affinity-fmt.c 2019-05-07 18:46:36.358112419 +0200
|
|
@@ -0,0 +1,51 @@
|
|
+/* Copyright (C) 2018-2019 Free Software Foundation, Inc.
|
|
+
|
|
+ This file is part of the GNU Offloading and Multi Processing Library
|
|
+ (libgomp).
|
|
+
|
|
+ Libgomp is free software; you can redistribute it and/or modify it
|
|
+ under the terms of the GNU General Public License as published by
|
|
+ the Free Software Foundation; either version 3, or (at your option)
|
|
+ any later version.
|
|
+
|
|
+ Libgomp is distributed in the hope that it will be useful, but WITHOUT ANY
|
|
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
|
+ FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
|
+ more details.
|
|
+
|
|
+ Under Section 7 of GPL version 3, you are granted additional
|
|
+ permissions described in the GCC Runtime Library Exception, version
|
|
+ 3.1, as published by the Free Software Foundation.
|
|
+
|
|
+ You should have received a copy of the GNU General Public License and
|
|
+ a copy of the GCC Runtime Library Exception along with this program;
|
|
+ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
|
|
+ <http://www.gnu.org/licenses/>. */
|
|
+
|
|
+#include "libgomp.h"
|
|
+#include <string.h>
|
|
+#include <stdio.h>
|
|
+#include <stdlib.h>
|
|
+#ifdef HAVE_UNISTD_H
|
|
+#include <unistd.h>
|
|
+#endif
|
|
+#ifdef HAVE_INTTYPES_H
|
|
+# include <inttypes.h> /* For PRIx64. */
|
|
+#endif
|
|
+#ifdef HAVE_UNAME
|
|
+#include <sys/utsname.h>
|
|
+#endif
|
|
+
|
|
+/* The HAVE_GETPID and HAVE_GETHOSTNAME configure tests are passing for nvptx,
|
|
+ while the nvptx newlib implementation does not support those functions.
|
|
+ Override the configure test results here. */
|
|
+#undef HAVE_GETPID
|
|
+#undef HAVE_GETHOSTNAME
|
|
+
|
|
+/* The nvptx newlib implementation does not support fwrite, but it does support
|
|
+ write. Map fwrite to write. */
|
|
+#undef fwrite
|
|
+#define fwrite(ptr, size, nmemb, stream) write (1, (ptr), (nmemb) * (size))
|
|
+
|
|
+#include "../../affinity-fmt.c"
|
|
+
|
|
--- libgomp/config/mingw32/affinity-fmt.c.jj 2019-05-07 18:46:36.344112642 +0200
|
|
+++ libgomp/config/mingw32/affinity-fmt.c 2019-05-07 18:46:36.344112642 +0200
|
|
@@ -0,0 +1,68 @@
|
|
+/* Copyright (C) 2018-2019 Free Software Foundation, Inc.
|
|
+ Contributed by Jakub Jelinek <jakub@redhat.com>.
|
|
+
|
|
+ This file is part of the GNU Offloading and Multi Processing Library
|
|
+ (libgomp).
|
|
+
|
|
+ Libgomp is free software; you can redistribute it and/or modify it
|
|
+ under the terms of the GNU General Public License as published by
|
|
+ the Free Software Foundation; either version 3, or (at your option)
|
|
+ any later version.
|
|
+
|
|
+ Libgomp is distributed in the hope that it will be useful, but WITHOUT ANY
|
|
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
|
+ FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
|
+ more details.
|
|
+
|
|
+ Under Section 7 of GPL version 3, you are granted additional
|
|
+ permissions described in the GCC Runtime Library Exception, version
|
|
+ 3.1, as published by the Free Software Foundation.
|
|
+
|
|
+ You should have received a copy of the GNU General Public License and
|
|
+ a copy of the GCC Runtime Library Exception along with this program;
|
|
+ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
|
|
+ <http://www.gnu.org/licenses/>. */
|
|
+
|
|
+#include "libgomp.h"
|
|
+#include <string.h>
|
|
+#include <stdio.h>
|
|
+#include <stdlib.h>
|
|
+#ifdef HAVE_UNISTD_H
|
|
+#include <unistd.h>
|
|
+#endif
|
|
+#ifdef HAVE_INTTYPES_H
|
|
+# include <inttypes.h> /* For PRIx64. */
|
|
+#endif
|
|
+#define WIN32_LEAN_AND_MEAN
|
|
+#include <windows.h>
|
|
+#include <errno.h>
|
|
+
|
|
+static int
|
|
+gomp_gethostname (char *name, size_t len)
|
|
+{
|
|
+ /* On Win9x GetComputerName fails if the input size is less
|
|
+ than MAX_COMPUTERNAME_LENGTH + 1. */
|
|
+ char buffer[MAX_COMPUTERNAME_LENGTH + 1];
|
|
+ DWORD size = sizeof (buffer);
|
|
+ int ret = 0;
|
|
+
|
|
+ if (!GetComputerName (buffer, &size))
|
|
+ return -1;
|
|
+
|
|
+ if ((size = strlen (buffer) + 1) > len)
|
|
+ {
|
|
+ errno = EINVAL;
|
|
+ /* Truncate as per POSIX spec. We do not NUL-terminate. */
|
|
+ size = len;
|
|
+ ret = -1;
|
|
+ }
|
|
+ memcpy (name, buffer, (size_t) size);
|
|
+
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+#undef gethostname
|
|
+#define gethostname gomp_gethostname
|
|
+#define HAVE_GETHOSTNAME 1
|
|
+
|
|
+#include "../../affinity-fmt.c"
|
|
--- libgomp/config/rtems/bar.c.jj 2018-04-25 09:40:31.902655576 +0200
|
|
+++ libgomp/config/rtems/bar.c 2019-05-07 18:46:36.460110789 +0200
|
|
@@ -72,184 +72,5 @@ do_wait (int *addr, int val)
|
|
futex_wait (addr, val);
|
|
}
|
|
|
|
-/* Everything below this point should be identical to the Linux
|
|
- implementation. */
|
|
-
|
|
-void
|
|
-gomp_barrier_wait_end (gomp_barrier_t *bar, gomp_barrier_state_t state)
|
|
-{
|
|
- if (__builtin_expect (state & BAR_WAS_LAST, 0))
|
|
- {
|
|
- /* Next time we'll be awaiting TOTAL threads again. */
|
|
- bar->awaited = bar->total;
|
|
- __atomic_store_n (&bar->generation, bar->generation + BAR_INCR,
|
|
- MEMMODEL_RELEASE);
|
|
- futex_wake ((int *) &bar->generation, INT_MAX);
|
|
- }
|
|
- else
|
|
- {
|
|
- do
|
|
- do_wait ((int *) &bar->generation, state);
|
|
- while (__atomic_load_n (&bar->generation, MEMMODEL_ACQUIRE) == state);
|
|
- }
|
|
-}
|
|
-
|
|
-void
|
|
-gomp_barrier_wait (gomp_barrier_t *bar)
|
|
-{
|
|
- gomp_barrier_wait_end (bar, gomp_barrier_wait_start (bar));
|
|
-}
|
|
-
|
|
-/* Like gomp_barrier_wait, except that if the encountering thread
|
|
- is not the last one to hit the barrier, it returns immediately.
|
|
- The intended usage is that a thread which intends to gomp_barrier_destroy
|
|
- this barrier calls gomp_barrier_wait, while all other threads
|
|
- call gomp_barrier_wait_last. When gomp_barrier_wait returns,
|
|
- the barrier can be safely destroyed. */
|
|
-
|
|
-void
|
|
-gomp_barrier_wait_last (gomp_barrier_t *bar)
|
|
-{
|
|
- gomp_barrier_state_t state = gomp_barrier_wait_start (bar);
|
|
- if (state & BAR_WAS_LAST)
|
|
- gomp_barrier_wait_end (bar, state);
|
|
-}
|
|
-
|
|
-void
|
|
-gomp_team_barrier_wake (gomp_barrier_t *bar, int count)
|
|
-{
|
|
- futex_wake ((int *) &bar->generation, count == 0 ? INT_MAX : count);
|
|
-}
|
|
-
|
|
-void
|
|
-gomp_team_barrier_wait_end (gomp_barrier_t *bar, gomp_barrier_state_t state)
|
|
-{
|
|
- unsigned int generation, gen;
|
|
-
|
|
- if (__builtin_expect (state & BAR_WAS_LAST, 0))
|
|
- {
|
|
- /* Next time we'll be awaiting TOTAL threads again. */
|
|
- struct gomp_thread *thr = gomp_thread ();
|
|
- struct gomp_team *team = thr->ts.team;
|
|
-
|
|
- bar->awaited = bar->total;
|
|
- team->work_share_cancelled = 0;
|
|
- if (__builtin_expect (team->task_count, 0))
|
|
- {
|
|
- gomp_barrier_handle_tasks (state);
|
|
- state &= ~BAR_WAS_LAST;
|
|
- }
|
|
- else
|
|
- {
|
|
- state &= ~BAR_CANCELLED;
|
|
- state += BAR_INCR - BAR_WAS_LAST;
|
|
- __atomic_store_n (&bar->generation, state, MEMMODEL_RELEASE);
|
|
- futex_wake ((int *) &bar->generation, INT_MAX);
|
|
- return;
|
|
- }
|
|
- }
|
|
-
|
|
- generation = state;
|
|
- state &= ~BAR_CANCELLED;
|
|
- do
|
|
- {
|
|
- do_wait ((int *) &bar->generation, generation);
|
|
- gen = __atomic_load_n (&bar->generation, MEMMODEL_ACQUIRE);
|
|
- if (__builtin_expect (gen & BAR_TASK_PENDING, 0))
|
|
- {
|
|
- gomp_barrier_handle_tasks (state);
|
|
- gen = __atomic_load_n (&bar->generation, MEMMODEL_ACQUIRE);
|
|
- }
|
|
- generation |= gen & BAR_WAITING_FOR_TASK;
|
|
- }
|
|
- while (gen != state + BAR_INCR);
|
|
-}
|
|
-
|
|
-void
|
|
-gomp_team_barrier_wait (gomp_barrier_t *bar)
|
|
-{
|
|
- gomp_team_barrier_wait_end (bar, gomp_barrier_wait_start (bar));
|
|
-}
|
|
-
|
|
-void
|
|
-gomp_team_barrier_wait_final (gomp_barrier_t *bar)
|
|
-{
|
|
- gomp_barrier_state_t state = gomp_barrier_wait_final_start (bar);
|
|
- if (__builtin_expect (state & BAR_WAS_LAST, 0))
|
|
- bar->awaited_final = bar->total;
|
|
- gomp_team_barrier_wait_end (bar, state);
|
|
-}
|
|
-
|
|
-bool
|
|
-gomp_team_barrier_wait_cancel_end (gomp_barrier_t *bar,
|
|
- gomp_barrier_state_t state)
|
|
-{
|
|
- unsigned int generation, gen;
|
|
-
|
|
- if (__builtin_expect (state & BAR_WAS_LAST, 0))
|
|
- {
|
|
- /* Next time we'll be awaiting TOTAL threads again. */
|
|
- /* BAR_CANCELLED should never be set in state here, because
|
|
- cancellation means that at least one of the threads has been
|
|
- cancelled, thus on a cancellable barrier we should never see
|
|
- all threads to arrive. */
|
|
- struct gomp_thread *thr = gomp_thread ();
|
|
- struct gomp_team *team = thr->ts.team;
|
|
-
|
|
- bar->awaited = bar->total;
|
|
- team->work_share_cancelled = 0;
|
|
- if (__builtin_expect (team->task_count, 0))
|
|
- {
|
|
- gomp_barrier_handle_tasks (state);
|
|
- state &= ~BAR_WAS_LAST;
|
|
- }
|
|
- else
|
|
- {
|
|
- state += BAR_INCR - BAR_WAS_LAST;
|
|
- __atomic_store_n (&bar->generation, state, MEMMODEL_RELEASE);
|
|
- futex_wake ((int *) &bar->generation, INT_MAX);
|
|
- return false;
|
|
- }
|
|
- }
|
|
-
|
|
- if (__builtin_expect (state & BAR_CANCELLED, 0))
|
|
- return true;
|
|
-
|
|
- generation = state;
|
|
- do
|
|
- {
|
|
- do_wait ((int *) &bar->generation, generation);
|
|
- gen = __atomic_load_n (&bar->generation, MEMMODEL_ACQUIRE);
|
|
- if (__builtin_expect (gen & BAR_CANCELLED, 0))
|
|
- return true;
|
|
- if (__builtin_expect (gen & BAR_TASK_PENDING, 0))
|
|
- {
|
|
- gomp_barrier_handle_tasks (state);
|
|
- gen = __atomic_load_n (&bar->generation, MEMMODEL_ACQUIRE);
|
|
- }
|
|
- generation |= gen & BAR_WAITING_FOR_TASK;
|
|
- }
|
|
- while (gen != state + BAR_INCR);
|
|
-
|
|
- return false;
|
|
-}
|
|
-
|
|
-bool
|
|
-gomp_team_barrier_wait_cancel (gomp_barrier_t *bar)
|
|
-{
|
|
- return gomp_team_barrier_wait_cancel_end (bar, gomp_barrier_wait_start (bar));
|
|
-}
|
|
-
|
|
-void
|
|
-gomp_team_barrier_cancel (struct gomp_team *team)
|
|
-{
|
|
- gomp_mutex_lock (&team->task_lock);
|
|
- if (team->barrier.generation & BAR_CANCELLED)
|
|
- {
|
|
- gomp_mutex_unlock (&team->task_lock);
|
|
- return;
|
|
- }
|
|
- team->barrier.generation |= BAR_CANCELLED;
|
|
- gomp_mutex_unlock (&team->task_lock);
|
|
- futex_wake ((int *) &team->barrier.generation, INT_MAX);
|
|
-}
|
|
+#define GOMP_WAIT_H 1
|
|
+#include "../linux/bar.c"
|
|
--- libgomp/config/rtems/affinity-fmt.c.jj 2019-05-07 18:46:36.459110805 +0200
|
|
+++ libgomp/config/rtems/affinity-fmt.c 2019-05-07 18:46:36.459110805 +0200
|
|
@@ -0,0 +1,49 @@
|
|
+/* Copyright (C) 2018-2019 Free Software Foundation, Inc.
|
|
+
|
|
+ This file is part of the GNU Offloading and Multi Processing Library
|
|
+ (libgomp).
|
|
+
|
|
+ Libgomp is free software; you can redistribute it and/or modify it
|
|
+ under the terms of the GNU General Public License as published by
|
|
+ the Free Software Foundation; either version 3, or (at your option)
|
|
+ any later version.
|
|
+
|
|
+ Libgomp is distributed in the hope that it will be useful, but WITHOUT ANY
|
|
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
|
+ FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
|
+ more details.
|
|
+
|
|
+ Under Section 7 of GPL version 3, you are granted additional
|
|
+ permissions described in the GCC Runtime Library Exception, version
|
|
+ 3.1, as published by the Free Software Foundation.
|
|
+
|
|
+ You should have received a copy of the GNU General Public License and
|
|
+ a copy of the GCC Runtime Library Exception along with this program;
|
|
+ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
|
|
+ <http://www.gnu.org/licenses/>. */
|
|
+
|
|
+#include "libgomp.h"
|
|
+#include <string.h>
|
|
+#include <stdio.h>
|
|
+#include <stdlib.h>
|
|
+#ifdef HAVE_UNISTD_H
|
|
+#include <unistd.h>
|
|
+#endif
|
|
+#ifdef HAVE_INTTYPES_H
|
|
+# include <inttypes.h> /* For PRIx64. */
|
|
+#endif
|
|
+#ifdef HAVE_UNAME
|
|
+#include <sys/utsname.h>
|
|
+#endif
|
|
+
|
|
+/* The HAVE_GETPID and HAVE_GETHOSTNAME configure tests are passing for RTEMS,
|
|
+ but the extra information they give are of little value for the user.
|
|
+ Override the configure test results here. */
|
|
+#undef HAVE_GETPID
|
|
+#undef HAVE_GETHOSTNAME
|
|
+
|
|
+/* Avoid the complex fwrite() in favour of the simple write(). */
|
|
+#undef fwrite
|
|
+#define fwrite(ptr, size, nmemb, stream) write (1, (ptr), (nmemb) * (size))
|
|
+
|
|
+#include "../../affinity-fmt.c"
|
|
--- libgomp/config.h.in.jj 2018-04-25 09:40:31.870655561 +0200
|
|
+++ libgomp/config.h.in 2019-05-07 18:46:36.465110710 +0200
|
|
@@ -1,5 +1,8 @@
|
|
/* config.h.in. Generated from configure.ac by autoheader. */
|
|
|
|
+/* Define to 1 if you have the `aligned_alloc' function. */
|
|
+#undef HAVE_ALIGNED_ALLOC
|
|
+
|
|
/* Define to 1 if the target assembler supports .symver directive. */
|
|
#undef HAVE_AS_SYMVER_DIRECTIVE
|
|
|
|
@@ -33,9 +36,15 @@
|
|
/* Define to 1 if you have the `getgid' function. */
|
|
#undef HAVE_GETGID
|
|
|
|
+/* Define if gethostname is supported. */
|
|
+#undef HAVE_GETHOSTNAME
|
|
+
|
|
/* Define to 1 if you have the `getloadavg' function. */
|
|
#undef HAVE_GETLOADAVG
|
|
|
|
+/* Define if getpid is supported. */
|
|
+#undef HAVE_GETPID
|
|
+
|
|
/* Define to 1 if you have the `getuid' function. */
|
|
#undef HAVE_GETUID
|
|
|
|
@@ -45,9 +54,15 @@
|
|
/* Define to 1 if you have the `dl' library (-ldl). */
|
|
#undef HAVE_LIBDL
|
|
|
|
+/* Define to 1 if you have the `memalign' function. */
|
|
+#undef HAVE_MEMALIGN
|
|
+
|
|
/* Define to 1 if you have the <memory.h> header file. */
|
|
#undef HAVE_MEMORY_H
|
|
|
|
+/* Define to 1 if you have the `posix_memalign' function. */
|
|
+#undef HAVE_POSIX_MEMALIGN
|
|
+
|
|
/* Define if pthread_{,attr_}{g,s}etaffinity_np is supported. */
|
|
#undef HAVE_PTHREAD_AFFINITY_NP
|
|
|
|
@@ -103,9 +118,15 @@
|
|
/* Define to 1 if the target supports thread-local storage. */
|
|
#undef HAVE_TLS
|
|
|
|
+/* Define if uname is supported and struct utsname has nodename field. */
|
|
+#undef HAVE_UNAME
|
|
+
|
|
/* Define to 1 if you have the <unistd.h> header file. */
|
|
#undef HAVE_UNISTD_H
|
|
|
|
+/* Define to 1 if you have the `_aligned_malloc' function. */
|
|
+#undef HAVE__ALIGNED_MALLOC
|
|
+
|
|
/* Define to 1 if you have the `__secure_getenv' function. */
|
|
#undef HAVE___SECURE_GETENV
|
|
|
|
@@ -125,8 +146,8 @@
|
|
*/
|
|
#undef LT_OBJDIR
|
|
|
|
-/* Define to offload targets, separated by commas. */
|
|
-#undef OFFLOAD_TARGETS
|
|
+/* Define to offload plugins, separated by commas. */
|
|
+#undef OFFLOAD_PLUGINS
|
|
|
|
/* Name of package */
|
|
#undef PACKAGE
|
|
--- libgomp/teams.c.jj 2019-05-07 18:46:36.548109384 +0200
|
|
+++ libgomp/teams.c 2019-05-07 18:46:36.548109384 +0200
|
|
@@ -0,0 +1,74 @@
|
|
+/* Copyright (C) 2018-2019 Free Software Foundation, Inc.
|
|
+ Contributed by Jakub Jelinek <jakub@redhat.com>.
|
|
+
|
|
+ This file is part of the GNU Offloading and Multi Processing Library
|
|
+ (libgomp).
|
|
+
|
|
+ Libgomp is free software; you can redistribute it and/or modify it
|
|
+ under the terms of the GNU General Public License as published by
|
|
+ the Free Software Foundation; either version 3, or (at your option)
|
|
+ any later version.
|
|
+
|
|
+ Libgomp is distributed in the hope that it will be useful, but WITHOUT ANY
|
|
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
|
+ FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
|
+ more details.
|
|
+
|
|
+ Under Section 7 of GPL version 3, you are granted additional
|
|
+ permissions described in the GCC Runtime Library Exception, version
|
|
+ 3.1, as published by the Free Software Foundation.
|
|
+
|
|
+ You should have received a copy of the GNU General Public License and
|
|
+ a copy of the GCC Runtime Library Exception along with this program;
|
|
+ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
|
|
+ <http://www.gnu.org/licenses/>. */
|
|
+
|
|
+/* This file handles the host TEAMS construct. */
|
|
+
|
|
+#include "libgomp.h"
|
|
+#include <limits.h>
|
|
+
|
|
+static unsigned gomp_num_teams = 1, gomp_team_num = 0;
|
|
+
|
|
+void
|
|
+GOMP_teams_reg (void (*fn) (void *), void *data, unsigned int num_teams,
|
|
+ unsigned int thread_limit, unsigned int flags)
|
|
+{
|
|
+ (void) flags;
|
|
+ (void) num_teams;
|
|
+ unsigned old_thread_limit_var = 0;
|
|
+ if (thread_limit)
|
|
+ {
|
|
+ struct gomp_task_icv *icv = gomp_icv (true);
|
|
+ old_thread_limit_var = icv->thread_limit_var;
|
|
+ icv->thread_limit_var
|
|
+ = thread_limit > INT_MAX ? UINT_MAX : thread_limit;
|
|
+ }
|
|
+ if (num_teams == 0)
|
|
+ num_teams = 3;
|
|
+ gomp_num_teams = num_teams;
|
|
+ for (gomp_team_num = 0; gomp_team_num < num_teams; gomp_team_num++)
|
|
+ fn (data);
|
|
+ gomp_num_teams = 1;
|
|
+ gomp_team_num = 0;
|
|
+ if (thread_limit)
|
|
+ {
|
|
+ struct gomp_task_icv *icv = gomp_icv (true);
|
|
+ icv->thread_limit_var = old_thread_limit_var;
|
|
+ }
|
|
+}
|
|
+
|
|
+int
|
|
+omp_get_num_teams (void)
|
|
+{
|
|
+ return gomp_num_teams;
|
|
+}
|
|
+
|
|
+int
|
|
+omp_get_team_num (void)
|
|
+{
|
|
+ return gomp_team_num;
|
|
+}
|
|
+
|
|
+ialias (omp_get_num_teams)
|
|
+ialias (omp_get_team_num)
|
|
--- libgomp/libgomp.map.jj 2018-04-25 09:40:31.321655307 +0200
|
|
+++ libgomp/libgomp.map 2019-05-07 18:46:36.525109751 +0200
|
|
@@ -164,6 +164,22 @@ OMP_4.5 {
|
|
omp_target_disassociate_ptr;
|
|
} OMP_4.0;
|
|
|
|
+OMP_5.0 {
|
|
+ global:
|
|
+ omp_capture_affinity;
|
|
+ omp_capture_affinity_;
|
|
+ omp_display_affinity;
|
|
+ omp_display_affinity_;
|
|
+ omp_get_affinity_format;
|
|
+ omp_get_affinity_format_;
|
|
+ omp_set_affinity_format;
|
|
+ omp_set_affinity_format_;
|
|
+ omp_pause_resource;
|
|
+ omp_pause_resource_;
|
|
+ omp_pause_resource_all;
|
|
+ omp_pause_resource_all_;
|
|
+} OMP_4.5;
|
|
+
|
|
GOMP_1.0 {
|
|
global:
|
|
GOMP_atomic_end;
|
|
@@ -298,6 +314,34 @@ GOMP_4.5 {
|
|
GOMP_parallel_loop_nonmonotonic_guided;
|
|
} GOMP_4.0.1;
|
|
|
|
+GOMP_5.0 {
|
|
+ global:
|
|
+ GOMP_loop_doacross_start;
|
|
+ GOMP_loop_maybe_nonmonotonic_runtime_next;
|
|
+ GOMP_loop_maybe_nonmonotonic_runtime_start;
|
|
+ GOMP_loop_nonmonotonic_runtime_next;
|
|
+ GOMP_loop_nonmonotonic_runtime_start;
|
|
+ GOMP_loop_ordered_start;
|
|
+ GOMP_loop_start;
|
|
+ GOMP_loop_ull_doacross_start;
|
|
+ GOMP_loop_ull_maybe_nonmonotonic_runtime_next;
|
|
+ GOMP_loop_ull_maybe_nonmonotonic_runtime_start;
|
|
+ GOMP_loop_ull_nonmonotonic_runtime_next;
|
|
+ GOMP_loop_ull_nonmonotonic_runtime_start;
|
|
+ GOMP_loop_ull_ordered_start;
|
|
+ GOMP_loop_ull_start;
|
|
+ GOMP_parallel_loop_maybe_nonmonotonic_runtime;
|
|
+ GOMP_parallel_loop_nonmonotonic_runtime;
|
|
+ GOMP_parallel_reductions;
|
|
+ GOMP_sections2_start;
|
|
+ GOMP_taskgroup_reduction_register;
|
|
+ GOMP_taskgroup_reduction_unregister;
|
|
+ GOMP_task_reduction_remap;
|
|
+ GOMP_taskwait_depend;
|
|
+ GOMP_teams_reg;
|
|
+ GOMP_workshare_task_reduction_unregister;
|
|
+} GOMP_4.5;
|
|
+
|
|
OACC_2.0 {
|
|
global:
|
|
acc_get_num_devices;
|
|
@@ -386,6 +430,52 @@ OACC_2.0.1 {
|
|
acc_pcreate;
|
|
} OACC_2.0;
|
|
|
|
+OACC_2.5 {
|
|
+ global:
|
|
+ acc_copyin_async;
|
|
+ acc_copyin_async_32_h_;
|
|
+ acc_copyin_async_64_h_;
|
|
+ acc_copyin_async_array_h_;
|
|
+ acc_copyout_async;
|
|
+ acc_copyout_async_32_h_;
|
|
+ acc_copyout_async_64_h_;
|
|
+ acc_copyout_async_array_h_;
|
|
+ acc_copyout_finalize;
|
|
+ acc_copyout_finalize_32_h_;
|
|
+ acc_copyout_finalize_64_h_;
|
|
+ acc_copyout_finalize_array_h_;
|
|
+ acc_copyout_finalize_async;
|
|
+ acc_copyout_finalize_async_32_h_;
|
|
+ acc_copyout_finalize_async_64_h_;
|
|
+ acc_copyout_finalize_async_array_h_;
|
|
+ acc_create_async;
|
|
+ acc_create_async_32_h_;
|
|
+ acc_create_async_64_h_;
|
|
+ acc_create_async_array_h_;
|
|
+ acc_delete_async;
|
|
+ acc_delete_async_32_h_;
|
|
+ acc_delete_async_64_h_;
|
|
+ acc_delete_async_array_h_;
|
|
+ acc_delete_finalize;
|
|
+ acc_delete_finalize_32_h_;
|
|
+ acc_delete_finalize_64_h_;
|
|
+ acc_delete_finalize_array_h_;
|
|
+ acc_delete_finalize_async;
|
|
+ acc_delete_finalize_async_32_h_;
|
|
+ acc_delete_finalize_async_64_h_;
|
|
+ acc_delete_finalize_async_array_h_;
|
|
+ acc_memcpy_from_device_async;
|
|
+ acc_memcpy_to_device_async;
|
|
+ acc_update_device_async;
|
|
+ acc_update_device_async_32_h_;
|
|
+ acc_update_device_async_64_h_;
|
|
+ acc_update_device_async_array_h_;
|
|
+ acc_update_self_async;
|
|
+ acc_update_self_async_32_h_;
|
|
+ acc_update_self_async_64_h_;
|
|
+ acc_update_self_async_array_h_;
|
|
+} OACC_2.0.1;
|
|
+
|
|
GOACC_2.0 {
|
|
global:
|
|
GOACC_data_end;
|
|
@@ -420,3 +510,8 @@ GOMP_PLUGIN_1.1 {
|
|
global:
|
|
GOMP_PLUGIN_target_task_completion;
|
|
} GOMP_PLUGIN_1.0;
|
|
+
|
|
+GOMP_PLUGIN_1.2 {
|
|
+ global:
|
|
+ GOMP_PLUGIN_acc_default_dim;
|
|
+} GOMP_PLUGIN_1.1;
|
|
--- libgomp/oacc-async.c.jj 2018-04-25 09:40:31.925655587 +0200
|
|
+++ libgomp/oacc-async.c 2019-05-07 18:46:36.528109704 +0200
|
|
@@ -34,7 +34,7 @@
|
|
int
|
|
acc_async_test (int async)
|
|
{
|
|
- if (async < acc_async_sync)
|
|
+ if (!async_valid_p (async))
|
|
gomp_fatal ("invalid async argument: %d", async);
|
|
|
|
struct goacc_thread *thr = goacc_thread ();
|
|
@@ -59,7 +59,7 @@ acc_async_test_all (void)
|
|
void
|
|
acc_wait (int async)
|
|
{
|
|
- if (async < acc_async_sync)
|
|
+ if (!async_valid_p (async))
|
|
gomp_fatal ("invalid async argument: %d", async);
|
|
|
|
struct goacc_thread *thr = goacc_thread ();
|
|
@@ -117,7 +117,7 @@ acc_async_wait_all (void)
|
|
void
|
|
acc_wait_all_async (int async)
|
|
{
|
|
- if (async < acc_async_sync)
|
|
+ if (!async_valid_p (async))
|
|
gomp_fatal ("invalid async argument: %d", async);
|
|
|
|
struct goacc_thread *thr = goacc_thread ();
|
|
--- libgomp/loop_ull.c.jj 2018-04-25 09:40:31.912655580 +0200
|
|
+++ libgomp/loop_ull.c 2019-05-07 18:46:36.527109719 +0200
|
|
@@ -27,8 +27,12 @@
|
|
|
|
#include <limits.h>
|
|
#include <stdlib.h>
|
|
+#include <string.h>
|
|
#include "libgomp.h"
|
|
|
|
+ialias (GOMP_loop_ull_runtime_next)
|
|
+ialias_redirect (GOMP_taskgroup_reduction_register)
|
|
+
|
|
typedef unsigned long long gomp_ull;
|
|
|
|
/* Initialize the given work share construct from the given arguments. */
|
|
@@ -104,7 +108,7 @@ gomp_loop_ull_static_start (bool up, gom
|
|
struct gomp_thread *thr = gomp_thread ();
|
|
|
|
thr->ts.static_trip = 0;
|
|
- if (gomp_work_share_start (false))
|
|
+ if (gomp_work_share_start (0))
|
|
{
|
|
gomp_loop_ull_init (thr->ts.work_share, up, start, end, incr,
|
|
GFS_STATIC, chunk_size);
|
|
@@ -122,7 +126,7 @@ gomp_loop_ull_dynamic_start (bool up, go
|
|
struct gomp_thread *thr = gomp_thread ();
|
|
bool ret;
|
|
|
|
- if (gomp_work_share_start (false))
|
|
+ if (gomp_work_share_start (0))
|
|
{
|
|
gomp_loop_ull_init (thr->ts.work_share, up, start, end, incr,
|
|
GFS_DYNAMIC, chunk_size);
|
|
@@ -148,7 +152,7 @@ gomp_loop_ull_guided_start (bool up, gom
|
|
struct gomp_thread *thr = gomp_thread ();
|
|
bool ret;
|
|
|
|
- if (gomp_work_share_start (false))
|
|
+ if (gomp_work_share_start (0))
|
|
{
|
|
gomp_loop_ull_init (thr->ts.work_share, up, start, end, incr,
|
|
GFS_GUIDED, chunk_size);
|
|
@@ -171,7 +175,7 @@ GOMP_loop_ull_runtime_start (bool up, go
|
|
gomp_ull incr, gomp_ull *istart, gomp_ull *iend)
|
|
{
|
|
struct gomp_task_icv *icv = gomp_icv (false);
|
|
- switch (icv->run_sched_var)
|
|
+ switch (icv->run_sched_var & ~GFS_MONOTONIC)
|
|
{
|
|
case GFS_STATIC:
|
|
return gomp_loop_ull_static_start (up, start, end, incr,
|
|
@@ -195,6 +199,99 @@ GOMP_loop_ull_runtime_start (bool up, go
|
|
}
|
|
}
|
|
|
|
+static long
|
|
+gomp_adjust_sched (long sched, gomp_ull *chunk_size)
|
|
+{
|
|
+ sched &= ~GFS_MONOTONIC;
|
|
+ switch (sched)
|
|
+ {
|
|
+ case GFS_STATIC:
|
|
+ case GFS_DYNAMIC:
|
|
+ case GFS_GUIDED:
|
|
+ return sched;
|
|
+ /* GFS_RUNTIME is used for runtime schedule without monotonic
|
|
+ or nonmonotonic modifiers on the clause.
|
|
+ GFS_RUNTIME|GFS_MONOTONIC for runtime schedule with monotonic
|
|
+ modifier. */
|
|
+ case GFS_RUNTIME:
|
|
+ /* GFS_AUTO is used for runtime schedule with nonmonotonic
|
|
+ modifier. */
|
|
+ case GFS_AUTO:
|
|
+ {
|
|
+ struct gomp_task_icv *icv = gomp_icv (false);
|
|
+ sched = icv->run_sched_var & ~GFS_MONOTONIC;
|
|
+ switch (sched)
|
|
+ {
|
|
+ case GFS_STATIC:
|
|
+ case GFS_DYNAMIC:
|
|
+ case GFS_GUIDED:
|
|
+ *chunk_size = icv->run_sched_chunk_size;
|
|
+ break;
|
|
+ case GFS_AUTO:
|
|
+ sched = GFS_STATIC;
|
|
+ *chunk_size = 0;
|
|
+ break;
|
|
+ default:
|
|
+ abort ();
|
|
+ }
|
|
+ return sched;
|
|
+ }
|
|
+ default:
|
|
+ abort ();
|
|
+ }
|
|
+}
|
|
+
|
|
+bool
|
|
+GOMP_loop_ull_start (bool up, gomp_ull start, gomp_ull end,
|
|
+ gomp_ull incr, long sched, gomp_ull chunk_size,
|
|
+ gomp_ull *istart, gomp_ull *iend,
|
|
+ uintptr_t *reductions, void **mem)
|
|
+{
|
|
+ struct gomp_thread *thr = gomp_thread ();
|
|
+
|
|
+ thr->ts.static_trip = 0;
|
|
+ if (reductions)
|
|
+ gomp_workshare_taskgroup_start ();
|
|
+ if (gomp_work_share_start (0))
|
|
+ {
|
|
+ sched = gomp_adjust_sched (sched, &chunk_size);
|
|
+ gomp_loop_ull_init (thr->ts.work_share, up, start, end, incr,
|
|
+ sched, chunk_size);
|
|
+ if (reductions)
|
|
+ {
|
|
+ GOMP_taskgroup_reduction_register (reductions);
|
|
+ thr->task->taskgroup->workshare = true;
|
|
+ thr->ts.work_share->task_reductions = reductions;
|
|
+ }
|
|
+ if (mem)
|
|
+ {
|
|
+ uintptr_t size = (uintptr_t) *mem;
|
|
+ if (size > (sizeof (struct gomp_work_share)
|
|
+ - offsetof (struct gomp_work_share,
|
|
+ inline_ordered_team_ids)))
|
|
+ thr->ts.work_share->ordered_team_ids
|
|
+ = gomp_malloc_cleared (size);
|
|
+ else
|
|
+ memset (thr->ts.work_share->ordered_team_ids, '\0', size);
|
|
+ *mem = (void *) thr->ts.work_share->ordered_team_ids;
|
|
+ }
|
|
+ gomp_work_share_init_done ();
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+ if (reductions)
|
|
+ {
|
|
+ uintptr_t *first_reductions = thr->ts.work_share->task_reductions;
|
|
+ gomp_workshare_task_reduction_register (reductions,
|
|
+ first_reductions);
|
|
+ }
|
|
+ if (mem)
|
|
+ *mem = (void *) thr->ts.work_share->ordered_team_ids;
|
|
+ }
|
|
+
|
|
+ return ialias_call (GOMP_loop_ull_runtime_next) (istart, iend);
|
|
+}
|
|
+
|
|
/* The *_ordered_*_start routines are similar. The only difference is that
|
|
this work-share construct is initialized to expect an ORDERED section. */
|
|
|
|
@@ -206,7 +303,7 @@ gomp_loop_ull_ordered_static_start (bool
|
|
struct gomp_thread *thr = gomp_thread ();
|
|
|
|
thr->ts.static_trip = 0;
|
|
- if (gomp_work_share_start (true))
|
|
+ if (gomp_work_share_start (1))
|
|
{
|
|
gomp_loop_ull_init (thr->ts.work_share, up, start, end, incr,
|
|
GFS_STATIC, chunk_size);
|
|
@@ -225,7 +322,7 @@ gomp_loop_ull_ordered_dynamic_start (boo
|
|
struct gomp_thread *thr = gomp_thread ();
|
|
bool ret;
|
|
|
|
- if (gomp_work_share_start (true))
|
|
+ if (gomp_work_share_start (1))
|
|
{
|
|
gomp_loop_ull_init (thr->ts.work_share, up, start, end, incr,
|
|
GFS_DYNAMIC, chunk_size);
|
|
@@ -251,7 +348,7 @@ gomp_loop_ull_ordered_guided_start (bool
|
|
struct gomp_thread *thr = gomp_thread ();
|
|
bool ret;
|
|
|
|
- if (gomp_work_share_start (true))
|
|
+ if (gomp_work_share_start (1))
|
|
{
|
|
gomp_loop_ull_init (thr->ts.work_share, up, start, end, incr,
|
|
GFS_GUIDED, chunk_size);
|
|
@@ -275,7 +372,7 @@ GOMP_loop_ull_ordered_runtime_start (boo
|
|
gomp_ull *iend)
|
|
{
|
|
struct gomp_task_icv *icv = gomp_icv (false);
|
|
- switch (icv->run_sched_var)
|
|
+ switch (icv->run_sched_var & ~GFS_MONOTONIC)
|
|
{
|
|
case GFS_STATIC:
|
|
return gomp_loop_ull_ordered_static_start (up, start, end, incr,
|
|
@@ -299,6 +396,82 @@ GOMP_loop_ull_ordered_runtime_start (boo
|
|
}
|
|
}
|
|
|
|
+bool
|
|
+GOMP_loop_ull_ordered_start (bool up, gomp_ull start, gomp_ull end,
|
|
+ gomp_ull incr, long sched, gomp_ull chunk_size,
|
|
+ gomp_ull *istart, gomp_ull *iend,
|
|
+ uintptr_t *reductions, void **mem)
|
|
+{
|
|
+ struct gomp_thread *thr = gomp_thread ();
|
|
+ size_t ordered = 1;
|
|
+ bool ret;
|
|
+
|
|
+ thr->ts.static_trip = 0;
|
|
+ if (reductions)
|
|
+ gomp_workshare_taskgroup_start ();
|
|
+ if (mem)
|
|
+ ordered += (uintptr_t) *mem;
|
|
+ if (gomp_work_share_start (ordered))
|
|
+ {
|
|
+ sched = gomp_adjust_sched (sched, &chunk_size);
|
|
+ gomp_loop_ull_init (thr->ts.work_share, up, start, end, incr,
|
|
+ sched, chunk_size);
|
|
+ if (reductions)
|
|
+ {
|
|
+ GOMP_taskgroup_reduction_register (reductions);
|
|
+ thr->task->taskgroup->workshare = true;
|
|
+ thr->ts.work_share->task_reductions = reductions;
|
|
+ }
|
|
+ if (sched == GFS_STATIC)
|
|
+ gomp_ordered_static_init ();
|
|
+ else
|
|
+ gomp_mutex_lock (&thr->ts.work_share->lock);
|
|
+ gomp_work_share_init_done ();
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+ if (reductions)
|
|
+ {
|
|
+ uintptr_t *first_reductions = thr->ts.work_share->task_reductions;
|
|
+ gomp_workshare_task_reduction_register (reductions,
|
|
+ first_reductions);
|
|
+ }
|
|
+ sched = thr->ts.work_share->sched;
|
|
+ if (sched != GFS_STATIC)
|
|
+ gomp_mutex_lock (&thr->ts.work_share->lock);
|
|
+ }
|
|
+
|
|
+ if (mem)
|
|
+ {
|
|
+ uintptr_t p
|
|
+ = (uintptr_t) (thr->ts.work_share->ordered_team_ids
|
|
+ + (thr->ts.team ? thr->ts.team->nthreads : 1));
|
|
+ p += __alignof__ (long long) - 1;
|
|
+ p &= ~(__alignof__ (long long) - 1);
|
|
+ *mem = (void *) p;
|
|
+ }
|
|
+
|
|
+ switch (sched)
|
|
+ {
|
|
+ case GFS_STATIC:
|
|
+ case GFS_AUTO:
|
|
+ return !gomp_iter_ull_static_next (istart, iend);
|
|
+ case GFS_DYNAMIC:
|
|
+ ret = gomp_iter_ull_dynamic_next_locked (istart, iend);
|
|
+ break;
|
|
+ case GFS_GUIDED:
|
|
+ ret = gomp_iter_ull_guided_next_locked (istart, iend);
|
|
+ break;
|
|
+ default:
|
|
+ abort ();
|
|
+ }
|
|
+
|
|
+ if (ret)
|
|
+ gomp_ordered_first ();
|
|
+ gomp_mutex_unlock (&thr->ts.work_share->lock);
|
|
+ return ret;
|
|
+}
|
|
+
|
|
/* The *_doacross_*_start routines are similar. The only difference is that
|
|
this work-share construct is initialized to expect an ORDERED(N) - DOACROSS
|
|
section, and the worksharing loop iterates always from 0 to COUNTS[0] - 1
|
|
@@ -313,11 +486,11 @@ gomp_loop_ull_doacross_static_start (uns
|
|
struct gomp_thread *thr = gomp_thread ();
|
|
|
|
thr->ts.static_trip = 0;
|
|
- if (gomp_work_share_start (false))
|
|
+ if (gomp_work_share_start (0))
|
|
{
|
|
gomp_loop_ull_init (thr->ts.work_share, true, 0, counts[0], 1,
|
|
GFS_STATIC, chunk_size);
|
|
- gomp_doacross_ull_init (ncounts, counts, chunk_size);
|
|
+ gomp_doacross_ull_init (ncounts, counts, chunk_size, 0);
|
|
gomp_work_share_init_done ();
|
|
}
|
|
|
|
@@ -332,11 +505,11 @@ gomp_loop_ull_doacross_dynamic_start (un
|
|
struct gomp_thread *thr = gomp_thread ();
|
|
bool ret;
|
|
|
|
- if (gomp_work_share_start (false))
|
|
+ if (gomp_work_share_start (0))
|
|
{
|
|
gomp_loop_ull_init (thr->ts.work_share, true, 0, counts[0], 1,
|
|
GFS_DYNAMIC, chunk_size);
|
|
- gomp_doacross_ull_init (ncounts, counts, chunk_size);
|
|
+ gomp_doacross_ull_init (ncounts, counts, chunk_size, 0);
|
|
gomp_work_share_init_done ();
|
|
}
|
|
|
|
@@ -359,11 +532,11 @@ gomp_loop_ull_doacross_guided_start (uns
|
|
struct gomp_thread *thr = gomp_thread ();
|
|
bool ret;
|
|
|
|
- if (gomp_work_share_start (false))
|
|
+ if (gomp_work_share_start (0))
|
|
{
|
|
gomp_loop_ull_init (thr->ts.work_share, true, 0, counts[0], 1,
|
|
GFS_GUIDED, chunk_size);
|
|
- gomp_doacross_ull_init (ncounts, counts, chunk_size);
|
|
+ gomp_doacross_ull_init (ncounts, counts, chunk_size, 0);
|
|
gomp_work_share_init_done ();
|
|
}
|
|
|
|
@@ -383,7 +556,7 @@ GOMP_loop_ull_doacross_runtime_start (un
|
|
gomp_ull *istart, gomp_ull *iend)
|
|
{
|
|
struct gomp_task_icv *icv = gomp_icv (false);
|
|
- switch (icv->run_sched_var)
|
|
+ switch (icv->run_sched_var & ~GFS_MONOTONIC)
|
|
{
|
|
case GFS_STATIC:
|
|
return gomp_loop_ull_doacross_static_start (ncounts, counts,
|
|
@@ -407,6 +580,51 @@ GOMP_loop_ull_doacross_runtime_start (un
|
|
}
|
|
}
|
|
|
|
+bool
|
|
+GOMP_loop_ull_doacross_start (unsigned ncounts, gomp_ull *counts,
|
|
+ long sched, gomp_ull chunk_size,
|
|
+ gomp_ull *istart, gomp_ull *iend,
|
|
+ uintptr_t *reductions, void **mem)
|
|
+{
|
|
+ struct gomp_thread *thr = gomp_thread ();
|
|
+
|
|
+ thr->ts.static_trip = 0;
|
|
+ if (reductions)
|
|
+ gomp_workshare_taskgroup_start ();
|
|
+ if (gomp_work_share_start (0))
|
|
+ {
|
|
+ size_t extra = 0;
|
|
+ if (mem)
|
|
+ extra = (uintptr_t) *mem;
|
|
+ sched = gomp_adjust_sched (sched, &chunk_size);
|
|
+ gomp_loop_ull_init (thr->ts.work_share, true, 0, counts[0], 1,
|
|
+ sched, chunk_size);
|
|
+ gomp_doacross_ull_init (ncounts, counts, chunk_size, extra);
|
|
+ if (reductions)
|
|
+ {
|
|
+ GOMP_taskgroup_reduction_register (reductions);
|
|
+ thr->task->taskgroup->workshare = true;
|
|
+ thr->ts.work_share->task_reductions = reductions;
|
|
+ }
|
|
+ gomp_work_share_init_done ();
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+ if (reductions)
|
|
+ {
|
|
+ uintptr_t *first_reductions = thr->ts.work_share->task_reductions;
|
|
+ gomp_workshare_task_reduction_register (reductions,
|
|
+ first_reductions);
|
|
+ }
|
|
+ sched = thr->ts.work_share->sched;
|
|
+ }
|
|
+
|
|
+ if (mem)
|
|
+ *mem = thr->ts.work_share->doacross->extra;
|
|
+
|
|
+ return ialias_call (GOMP_loop_ull_runtime_next) (istart, iend);
|
|
+}
|
|
+
|
|
/* The *_next routines are called when the thread completes processing of
|
|
the iteration block currently assigned to it. If the work-share
|
|
construct is bound directly to a parallel construct, then the iteration
|
|
@@ -570,6 +788,10 @@ extern __typeof(gomp_loop_ull_dynamic_st
|
|
__attribute__((alias ("gomp_loop_ull_dynamic_start")));
|
|
extern __typeof(gomp_loop_ull_guided_start) GOMP_loop_ull_nonmonotonic_guided_start
|
|
__attribute__((alias ("gomp_loop_ull_guided_start")));
|
|
+extern __typeof(GOMP_loop_ull_runtime_start) GOMP_loop_ull_nonmonotonic_runtime_start
|
|
+ __attribute__((alias ("GOMP_loop_ull_runtime_start")));
|
|
+extern __typeof(GOMP_loop_ull_runtime_start) GOMP_loop_ull_maybe_nonmonotonic_runtime_start
|
|
+ __attribute__((alias ("GOMP_loop_ull_runtime_start")));
|
|
|
|
extern __typeof(gomp_loop_ull_ordered_static_start) GOMP_loop_ull_ordered_static_start
|
|
__attribute__((alias ("gomp_loop_ull_ordered_static_start")));
|
|
@@ -595,6 +817,10 @@ extern __typeof(gomp_loop_ull_dynamic_ne
|
|
__attribute__((alias ("gomp_loop_ull_dynamic_next")));
|
|
extern __typeof(gomp_loop_ull_guided_next) GOMP_loop_ull_nonmonotonic_guided_next
|
|
__attribute__((alias ("gomp_loop_ull_guided_next")));
|
|
+extern __typeof(GOMP_loop_ull_runtime_next) GOMP_loop_ull_nonmonotonic_runtime_next
|
|
+ __attribute__((alias ("GOMP_loop_ull_runtime_next")));
|
|
+extern __typeof(GOMP_loop_ull_runtime_next) GOMP_loop_ull_maybe_nonmonotonic_runtime_next
|
|
+ __attribute__((alias ("GOMP_loop_ull_runtime_next")));
|
|
|
|
extern __typeof(gomp_loop_ull_ordered_static_next) GOMP_loop_ull_ordered_static_next
|
|
__attribute__((alias ("gomp_loop_ull_ordered_static_next")));
|
|
@@ -650,6 +876,23 @@ GOMP_loop_ull_nonmonotonic_guided_start
|
|
}
|
|
|
|
bool
|
|
+GOMP_loop_ull_nonmonotonic_runtime_start (bool up, gomp_ull start,
|
|
+ gomp_ull end, gomp_ull incr,
|
|
+ gomp_ull *istart, gomp_ull *iend)
|
|
+{
|
|
+ return GOMP_loop_ull_runtime_start (up, start, end, incr, istart, iend);
|
|
+}
|
|
+
|
|
+bool
|
|
+GOMP_loop_ull_maybe_nonmonotonic_runtime_start (bool up, gomp_ull start,
|
|
+ gomp_ull end, gomp_ull incr,
|
|
+ gomp_ull *istart,
|
|
+ gomp_ull *iend)
|
|
+{
|
|
+ return GOMP_loop_ull_runtime_start (up, start, end, incr, istart, iend);
|
|
+}
|
|
+
|
|
+bool
|
|
GOMP_loop_ull_ordered_static_start (bool up, gomp_ull start, gomp_ull end,
|
|
gomp_ull incr, gomp_ull chunk_size,
|
|
gomp_ull *istart, gomp_ull *iend)
|
|
@@ -734,6 +977,19 @@ GOMP_loop_ull_nonmonotonic_guided_next (
|
|
}
|
|
|
|
bool
|
|
+GOMP_loop_ull_nonmonotonic_runtime_next (gomp_ull *istart, gomp_ull *iend)
|
|
+{
|
|
+ return GOMP_loop_ull_runtime_next (istart, iend);
|
|
+}
|
|
+
|
|
+bool
|
|
+GOMP_loop_ull_maybe_nonmonotonic_runtime_next (gomp_ull *istart,
|
|
+ gomp_ull *iend)
|
|
+{
|
|
+ return GOMP_loop_ull_runtime_next (istart, iend);
|
|
+}
|
|
+
|
|
+bool
|
|
GOMP_loop_ull_ordered_static_next (gomp_ull *istart, gomp_ull *iend)
|
|
{
|
|
return gomp_loop_ull_ordered_static_next (istart, iend);
|
|
--- libgomp/oacc-int.h.jj 2018-04-25 09:40:31.320655306 +0200
|
|
+++ libgomp/oacc-int.h 2019-05-07 18:46:36.529109688 +0200
|
|
@@ -99,6 +99,28 @@ void goacc_restore_bind (void);
|
|
void goacc_lazy_initialize (void);
|
|
void goacc_host_init (void);
|
|
|
|
+static inline bool
|
|
+async_valid_stream_id_p (int async)
|
|
+{
|
|
+ return async >= 0;
|
|
+}
|
|
+
|
|
+static inline bool
|
|
+async_valid_p (int async)
|
|
+{
|
|
+ return (async == acc_async_noval || async == acc_async_sync
|
|
+ || async_valid_stream_id_p (async));
|
|
+}
|
|
+
|
|
+static inline bool
|
|
+async_synchronous_p (int async)
|
|
+{
|
|
+ if (!async_valid_p (async))
|
|
+ return true;
|
|
+
|
|
+ return async == acc_async_sync;
|
|
+}
|
|
+
|
|
#ifdef HAVE_ATTRIBUTE_VISIBILITY
|
|
# pragma GCC visibility pop
|
|
#endif
|
|
--- libgomp/testsuite/Makefile.in.jj 2018-04-25 09:40:31.452655368 +0200
|
|
+++ libgomp/testsuite/Makefile.in 2019-05-07 18:51:35.754330084 +0200
|
|
@@ -223,6 +223,7 @@ mkdir_p = @mkdir_p@
|
|
multi_basedir = @multi_basedir@
|
|
offload_additional_lib_paths = @offload_additional_lib_paths@
|
|
offload_additional_options = @offload_additional_options@
|
|
+offload_plugins = @offload_plugins@
|
|
offload_targets = @offload_targets@
|
|
oldincludedir = @oldincludedir@
|
|
pdfdir = @pdfdir@
|
|
--- libgomp/task.c.jj 2018-04-25 09:40:31.925655587 +0200
|
|
+++ libgomp/task.c 2019-05-07 18:46:36.547109400 +0200
|
|
@@ -166,21 +166,72 @@ gomp_task_handle_depend (struct gomp_tas
|
|
void **depend)
|
|
{
|
|
size_t ndepend = (uintptr_t) depend[0];
|
|
- size_t nout = (uintptr_t) depend[1];
|
|
size_t i;
|
|
hash_entry_type ent;
|
|
|
|
+ if (ndepend)
|
|
+ {
|
|
+ /* depend[0] is total # */
|
|
+ size_t nout = (uintptr_t) depend[1]; /* # of out: and inout: */
|
|
+ /* ndepend - nout is # of in: */
|
|
+ for (i = 0; i < ndepend; i++)
|
|
+ {
|
|
+ task->depend[i].addr = depend[2 + i];
|
|
+ task->depend[i].is_in = i >= nout;
|
|
+ }
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+ ndepend = (uintptr_t) depend[1]; /* total # */
|
|
+ size_t nout = (uintptr_t) depend[2]; /* # of out: and inout: */
|
|
+ size_t nmutexinoutset = (uintptr_t) depend[3]; /* # of mutexinoutset: */
|
|
+ /* For now we treat mutexinoutset like out, which is compliant, but
|
|
+ inefficient. */
|
|
+ size_t nin = (uintptr_t) depend[4]; /* # of in: */
|
|
+ /* ndepend - nout - nmutexinoutset - nin is # of depobjs */
|
|
+ size_t normal = nout + nmutexinoutset + nin;
|
|
+ size_t n = 0;
|
|
+ for (i = normal; i < ndepend; i++)
|
|
+ {
|
|
+ void **d = (void **) (uintptr_t) depend[5 + i];
|
|
+ switch ((uintptr_t) d[1])
|
|
+ {
|
|
+ case GOMP_DEPEND_OUT:
|
|
+ case GOMP_DEPEND_INOUT:
|
|
+ case GOMP_DEPEND_MUTEXINOUTSET:
|
|
+ break;
|
|
+ case GOMP_DEPEND_IN:
|
|
+ continue;
|
|
+ default:
|
|
+ gomp_fatal ("unknown omp_depend_t dependence type %d",
|
|
+ (int) (uintptr_t) d[1]);
|
|
+ }
|
|
+ task->depend[n].addr = d[0];
|
|
+ task->depend[n++].is_in = 0;
|
|
+ }
|
|
+ for (i = 0; i < normal; i++)
|
|
+ {
|
|
+ task->depend[n].addr = depend[5 + i];
|
|
+ task->depend[n++].is_in = i >= nout + nmutexinoutset;
|
|
+ }
|
|
+ for (i = normal; i < ndepend; i++)
|
|
+ {
|
|
+ void **d = (void **) (uintptr_t) depend[5 + i];
|
|
+ if ((uintptr_t) d[1] != GOMP_DEPEND_IN)
|
|
+ continue;
|
|
+ task->depend[n].addr = d[0];
|
|
+ task->depend[n++].is_in = 1;
|
|
+ }
|
|
+ }
|
|
task->depend_count = ndepend;
|
|
task->num_dependees = 0;
|
|
if (parent->depend_hash == NULL)
|
|
parent->depend_hash = htab_create (2 * ndepend > 12 ? 2 * ndepend : 12);
|
|
for (i = 0; i < ndepend; i++)
|
|
{
|
|
- task->depend[i].addr = depend[2 + i];
|
|
task->depend[i].next = NULL;
|
|
task->depend[i].prev = NULL;
|
|
task->depend[i].task = task;
|
|
- task->depend[i].is_in = i >= nout;
|
|
task->depend[i].redundant = false;
|
|
task->depend[i].redundant_out = false;
|
|
|
|
@@ -205,7 +256,7 @@ gomp_task_handle_depend (struct gomp_tas
|
|
last = ent;
|
|
|
|
/* depend(in:...) doesn't depend on earlier depend(in:...). */
|
|
- if (i >= nout && ent->is_in)
|
|
+ if (task->depend[i].is_in && ent->is_in)
|
|
continue;
|
|
|
|
if (!ent->is_in)
|
|
@@ -280,9 +331,18 @@ gomp_task_handle_depend (struct gomp_tas
|
|
then the task may be executed by any member of the team.
|
|
|
|
DEPEND is an array containing:
|
|
+ if depend[0] is non-zero, then:
|
|
depend[0]: number of depend elements.
|
|
- depend[1]: number of depend elements of type "out".
|
|
- depend[2..N+1]: address of [1..N]th depend element. */
|
|
+ depend[1]: number of depend elements of type "out/inout".
|
|
+ depend[2..N+1]: address of [1..N]th depend element.
|
|
+ otherwise, when depend[0] is zero, then:
|
|
+ depend[1]: number of depend elements.
|
|
+ depend[2]: number of depend elements of type "out/inout".
|
|
+ depend[3]: number of depend elements of type "mutexinoutset".
|
|
+ depend[4]: number of depend elements of type "in".
|
|
+ depend[5..4+depend[2]+depend[3]+depend[4]]: address of depend elements
|
|
+ depend[5+depend[2]+depend[3]+depend[4]..4+depend[1]]: address of
|
|
+ omp_depend_t objects. */
|
|
|
|
void
|
|
GOMP_task (void (*fn) (void *), void *data, void (*cpyfn) (void *, void *),
|
|
@@ -303,10 +363,20 @@ GOMP_task (void (*fn) (void *), void *da
|
|
#endif
|
|
|
|
/* If parallel or taskgroup has been cancelled, don't start new tasks. */
|
|
- if (team
|
|
- && (gomp_team_barrier_cancelled (&team->barrier)
|
|
- || (thr->task->taskgroup && thr->task->taskgroup->cancelled)))
|
|
- return;
|
|
+ if (__builtin_expect (gomp_cancel_var, 0) && team)
|
|
+ {
|
|
+ if (gomp_team_barrier_cancelled (&team->barrier))
|
|
+ return;
|
|
+ if (thr->task->taskgroup)
|
|
+ {
|
|
+ if (thr->task->taskgroup->cancelled)
|
|
+ return;
|
|
+ if (thr->task->taskgroup->workshare
|
|
+ && thr->task->taskgroup->prev
|
|
+ && thr->task->taskgroup->prev->cancelled)
|
|
+ return;
|
|
+ }
|
|
+ }
|
|
|
|
if ((flags & GOMP_TASK_FLAG_PRIORITY) == 0)
|
|
priority = 0;
|
|
@@ -377,7 +447,7 @@ GOMP_task (void (*fn) (void *), void *da
|
|
size_t depend_size = 0;
|
|
|
|
if (flags & GOMP_TASK_FLAG_DEPEND)
|
|
- depend_size = ((uintptr_t) depend[0]
|
|
+ depend_size = ((uintptr_t) (depend[0] ? depend[0] : depend[1])
|
|
* sizeof (struct gomp_task_depend_entry));
|
|
task = gomp_malloc (sizeof (*task) + depend_size
|
|
+ arg_size + arg_align - 1);
|
|
@@ -404,14 +474,26 @@ GOMP_task (void (*fn) (void *), void *da
|
|
gomp_mutex_lock (&team->task_lock);
|
|
/* If parallel or taskgroup has been cancelled, don't start new
|
|
tasks. */
|
|
- if (__builtin_expect ((gomp_team_barrier_cancelled (&team->barrier)
|
|
- || (taskgroup && taskgroup->cancelled))
|
|
- && !task->copy_ctors_done, 0))
|
|
+ if (__builtin_expect (gomp_cancel_var, 0)
|
|
+ && !task->copy_ctors_done)
|
|
{
|
|
- gomp_mutex_unlock (&team->task_lock);
|
|
- gomp_finish_task (task);
|
|
- free (task);
|
|
- return;
|
|
+ if (gomp_team_barrier_cancelled (&team->barrier))
|
|
+ {
|
|
+ do_cancel:
|
|
+ gomp_mutex_unlock (&team->task_lock);
|
|
+ gomp_finish_task (task);
|
|
+ free (task);
|
|
+ return;
|
|
+ }
|
|
+ if (taskgroup)
|
|
+ {
|
|
+ if (taskgroup->cancelled)
|
|
+ goto do_cancel;
|
|
+ if (taskgroup->workshare
|
|
+ && taskgroup->prev
|
|
+ && taskgroup->prev->cancelled)
|
|
+ goto do_cancel;
|
|
+ }
|
|
}
|
|
if (taskgroup)
|
|
taskgroup->num_children++;
|
|
@@ -463,6 +545,7 @@ GOMP_task (void (*fn) (void *), void *da
|
|
|
|
ialias (GOMP_taskgroup_start)
|
|
ialias (GOMP_taskgroup_end)
|
|
+ialias (GOMP_taskgroup_reduction_register)
|
|
|
|
#define TYPE long
|
|
#define UTYPE unsigned long
|
|
@@ -601,10 +684,20 @@ gomp_create_target_task (struct gomp_dev
|
|
struct gomp_team *team = thr->ts.team;
|
|
|
|
/* If parallel or taskgroup has been cancelled, don't start new tasks. */
|
|
- if (team
|
|
- && (gomp_team_barrier_cancelled (&team->barrier)
|
|
- || (thr->task->taskgroup && thr->task->taskgroup->cancelled)))
|
|
- return true;
|
|
+ if (__builtin_expect (gomp_cancel_var, 0) && team)
|
|
+ {
|
|
+ if (gomp_team_barrier_cancelled (&team->barrier))
|
|
+ return true;
|
|
+ if (thr->task->taskgroup)
|
|
+ {
|
|
+ if (thr->task->taskgroup->cancelled)
|
|
+ return true;
|
|
+ if (thr->task->taskgroup->workshare
|
|
+ && thr->task->taskgroup->prev
|
|
+ && thr->task->taskgroup->prev->cancelled)
|
|
+ return true;
|
|
+ }
|
|
+ }
|
|
|
|
struct gomp_target_task *ttask;
|
|
struct gomp_task *task;
|
|
@@ -617,7 +710,7 @@ gomp_create_target_task (struct gomp_dev
|
|
|
|
if (depend != NULL)
|
|
{
|
|
- depend_cnt = (uintptr_t) depend[0];
|
|
+ depend_cnt = (uintptr_t) (depend[0] ? depend[0] : depend[1]);
|
|
depend_size = depend_cnt * sizeof (struct gomp_task_depend_entry);
|
|
}
|
|
if (fn)
|
|
@@ -687,13 +780,25 @@ gomp_create_target_task (struct gomp_dev
|
|
task->final_task = 0;
|
|
gomp_mutex_lock (&team->task_lock);
|
|
/* If parallel or taskgroup has been cancelled, don't start new tasks. */
|
|
- if (__builtin_expect (gomp_team_barrier_cancelled (&team->barrier)
|
|
- || (taskgroup && taskgroup->cancelled), 0))
|
|
+ if (__builtin_expect (gomp_cancel_var, 0))
|
|
{
|
|
- gomp_mutex_unlock (&team->task_lock);
|
|
- gomp_finish_task (task);
|
|
- free (task);
|
|
- return true;
|
|
+ if (gomp_team_barrier_cancelled (&team->barrier))
|
|
+ {
|
|
+ do_cancel:
|
|
+ gomp_mutex_unlock (&team->task_lock);
|
|
+ gomp_finish_task (task);
|
|
+ free (task);
|
|
+ return true;
|
|
+ }
|
|
+ if (taskgroup)
|
|
+ {
|
|
+ if (taskgroup->cancelled)
|
|
+ goto do_cancel;
|
|
+ if (taskgroup->workshare
|
|
+ && taskgroup->prev
|
|
+ && taskgroup->prev->cancelled)
|
|
+ goto do_cancel;
|
|
+ }
|
|
}
|
|
if (depend_size)
|
|
{
|
|
@@ -986,10 +1091,21 @@ gomp_task_run_pre (struct gomp_task *chi
|
|
|
|
if (--team->task_queued_count == 0)
|
|
gomp_team_barrier_clear_task_pending (&team->barrier);
|
|
- if ((gomp_team_barrier_cancelled (&team->barrier)
|
|
- || (taskgroup && taskgroup->cancelled))
|
|
+ if (__builtin_expect (gomp_cancel_var, 0)
|
|
&& !child_task->copy_ctors_done)
|
|
- return true;
|
|
+ {
|
|
+ if (gomp_team_barrier_cancelled (&team->barrier))
|
|
+ return true;
|
|
+ if (taskgroup)
|
|
+ {
|
|
+ if (taskgroup->cancelled)
|
|
+ return true;
|
|
+ if (taskgroup->workshare
|
|
+ && taskgroup->prev
|
|
+ && taskgroup->prev->cancelled)
|
|
+ return true;
|
|
+ }
|
|
+ }
|
|
return false;
|
|
}
|
|
|
|
@@ -1456,6 +1572,35 @@ GOMP_taskwait (void)
|
|
}
|
|
}
|
|
|
|
+/* Called when encountering a taskwait directive with depend clause(s).
|
|
+ Wait as if it was an mergeable included task construct with empty body. */
|
|
+
|
|
+void
|
|
+GOMP_taskwait_depend (void **depend)
|
|
+{
|
|
+ struct gomp_thread *thr = gomp_thread ();
|
|
+ struct gomp_team *team = thr->ts.team;
|
|
+
|
|
+ /* If parallel or taskgroup has been cancelled, return early. */
|
|
+ if (__builtin_expect (gomp_cancel_var, 0) && team)
|
|
+ {
|
|
+ if (gomp_team_barrier_cancelled (&team->barrier))
|
|
+ return;
|
|
+ if (thr->task->taskgroup)
|
|
+ {
|
|
+ if (thr->task->taskgroup->cancelled)
|
|
+ return;
|
|
+ if (thr->task->taskgroup->workshare
|
|
+ && thr->task->taskgroup->prev
|
|
+ && thr->task->taskgroup->prev->cancelled)
|
|
+ return;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if (thr->task && thr->task->depend_hash)
|
|
+ gomp_task_maybe_wait_for_dependencies (depend);
|
|
+}
|
|
+
|
|
/* An undeferred task is about to run. Wait for all tasks that this
|
|
undeferred task depends on.
|
|
|
|
@@ -1464,7 +1609,7 @@ GOMP_taskwait (void)
|
|
the scheduling queues. Then we iterate through these imminently
|
|
ready tasks (and possibly other high priority tasks), and run them.
|
|
If we run out of ready dependencies to execute, we either wait for
|
|
- the reamining dependencies to finish, or wait for them to get
|
|
+ the remaining dependencies to finish, or wait for them to get
|
|
scheduled so we can run them.
|
|
|
|
DEPEND is as in GOMP_task. */
|
|
@@ -1477,21 +1622,50 @@ gomp_task_maybe_wait_for_dependencies (v
|
|
struct gomp_team *team = thr->ts.team;
|
|
struct gomp_task_depend_entry elem, *ent = NULL;
|
|
struct gomp_taskwait taskwait;
|
|
- size_t ndepend = (uintptr_t) depend[0];
|
|
+ size_t orig_ndepend = (uintptr_t) depend[0];
|
|
size_t nout = (uintptr_t) depend[1];
|
|
+ size_t ndepend = orig_ndepend;
|
|
+ size_t normal = ndepend;
|
|
+ size_t n = 2;
|
|
size_t i;
|
|
size_t num_awaited = 0;
|
|
struct gomp_task *child_task = NULL;
|
|
struct gomp_task *to_free = NULL;
|
|
int do_wake = 0;
|
|
|
|
+ if (ndepend == 0)
|
|
+ {
|
|
+ ndepend = nout;
|
|
+ nout = (uintptr_t) depend[2] + (uintptr_t) depend[3];
|
|
+ normal = nout + (uintptr_t) depend[4];
|
|
+ n = 5;
|
|
+ }
|
|
gomp_mutex_lock (&team->task_lock);
|
|
for (i = 0; i < ndepend; i++)
|
|
{
|
|
- elem.addr = depend[i + 2];
|
|
+ elem.addr = depend[i + n];
|
|
+ elem.is_in = i >= nout;
|
|
+ if (__builtin_expect (i >= normal, 0))
|
|
+ {
|
|
+ void **d = (void **) elem.addr;
|
|
+ switch ((uintptr_t) d[1])
|
|
+ {
|
|
+ case GOMP_DEPEND_IN:
|
|
+ break;
|
|
+ case GOMP_DEPEND_OUT:
|
|
+ case GOMP_DEPEND_INOUT:
|
|
+ case GOMP_DEPEND_MUTEXINOUTSET:
|
|
+ elem.is_in = 0;
|
|
+ break;
|
|
+ default:
|
|
+ gomp_fatal ("unknown omp_depend_t dependence type %d",
|
|
+ (int) (uintptr_t) d[1]);
|
|
+ }
|
|
+ elem.addr = d[0];
|
|
+ }
|
|
ent = htab_find (task->depend_hash, &elem);
|
|
for (; ent; ent = ent->next)
|
|
- if (i >= nout && ent->is_in)
|
|
+ if (elem.is_in && ent->is_in)
|
|
continue;
|
|
else
|
|
{
|
|
@@ -1654,13 +1828,28 @@ GOMP_taskyield (void)
|
|
/* Nothing at the moment. */
|
|
}
|
|
|
|
+static inline struct gomp_taskgroup *
|
|
+gomp_taskgroup_init (struct gomp_taskgroup *prev)
|
|
+{
|
|
+ struct gomp_taskgroup *taskgroup
|
|
+ = gomp_malloc (sizeof (struct gomp_taskgroup));
|
|
+ taskgroup->prev = prev;
|
|
+ priority_queue_init (&taskgroup->taskgroup_queue);
|
|
+ taskgroup->reductions = prev ? prev->reductions : NULL;
|
|
+ taskgroup->in_taskgroup_wait = false;
|
|
+ taskgroup->cancelled = false;
|
|
+ taskgroup->workshare = false;
|
|
+ taskgroup->num_children = 0;
|
|
+ gomp_sem_init (&taskgroup->taskgroup_sem, 0);
|
|
+ return taskgroup;
|
|
+}
|
|
+
|
|
void
|
|
GOMP_taskgroup_start (void)
|
|
{
|
|
struct gomp_thread *thr = gomp_thread ();
|
|
struct gomp_team *team = thr->ts.team;
|
|
struct gomp_task *task = thr->task;
|
|
- struct gomp_taskgroup *taskgroup;
|
|
|
|
/* If team is NULL, all tasks are executed as
|
|
GOMP_TASK_UNDEFERRED tasks and thus all children tasks of
|
|
@@ -1668,14 +1857,7 @@ GOMP_taskgroup_start (void)
|
|
by the time GOMP_taskgroup_end is called. */
|
|
if (team == NULL)
|
|
return;
|
|
- taskgroup = gomp_malloc (sizeof (struct gomp_taskgroup));
|
|
- taskgroup->prev = task->taskgroup;
|
|
- priority_queue_init (&taskgroup->taskgroup_queue);
|
|
- taskgroup->in_taskgroup_wait = false;
|
|
- taskgroup->cancelled = false;
|
|
- taskgroup->num_children = 0;
|
|
- gomp_sem_init (&taskgroup->taskgroup_sem, 0);
|
|
- task->taskgroup = taskgroup;
|
|
+ task->taskgroup = gomp_taskgroup_init (task->taskgroup);
|
|
}
|
|
|
|
void
|
|
@@ -1840,6 +2022,302 @@ GOMP_taskgroup_end (void)
|
|
free (taskgroup);
|
|
}
|
|
|
|
+static inline __attribute__((always_inline)) void
|
|
+gomp_reduction_register (uintptr_t *data, uintptr_t *old, uintptr_t *orig,
|
|
+ unsigned nthreads)
|
|
+{
|
|
+ size_t total_cnt = 0;
|
|
+ uintptr_t *d = data;
|
|
+ struct htab *old_htab = NULL, *new_htab;
|
|
+ do
|
|
+ {
|
|
+ if (__builtin_expect (orig != NULL, 0))
|
|
+ {
|
|
+ /* For worksharing task reductions, memory has been allocated
|
|
+ already by some other thread that encountered the construct
|
|
+ earlier. */
|
|
+ d[2] = orig[2];
|
|
+ d[6] = orig[6];
|
|
+ orig = (uintptr_t *) orig[4];
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+ size_t sz = d[1] * nthreads;
|
|
+ /* Should use omp_alloc if d[3] is not -1. */
|
|
+ void *ptr = gomp_aligned_alloc (d[2], sz);
|
|
+ memset (ptr, '\0', sz);
|
|
+ d[2] = (uintptr_t) ptr;
|
|
+ d[6] = d[2] + sz;
|
|
+ }
|
|
+ d[5] = 0;
|
|
+ total_cnt += d[0];
|
|
+ if (d[4] == 0)
|
|
+ {
|
|
+ d[4] = (uintptr_t) old;
|
|
+ break;
|
|
+ }
|
|
+ else
|
|
+ d = (uintptr_t *) d[4];
|
|
+ }
|
|
+ while (1);
|
|
+ if (old && old[5])
|
|
+ {
|
|
+ old_htab = (struct htab *) old[5];
|
|
+ total_cnt += htab_elements (old_htab);
|
|
+ }
|
|
+ new_htab = htab_create (total_cnt);
|
|
+ if (old_htab)
|
|
+ {
|
|
+ /* Copy old hash table, like in htab_expand. */
|
|
+ hash_entry_type *p, *olimit;
|
|
+ new_htab->n_elements = htab_elements (old_htab);
|
|
+ olimit = old_htab->entries + old_htab->size;
|
|
+ p = old_htab->entries;
|
|
+ do
|
|
+ {
|
|
+ hash_entry_type x = *p;
|
|
+ if (x != HTAB_EMPTY_ENTRY && x != HTAB_DELETED_ENTRY)
|
|
+ *find_empty_slot_for_expand (new_htab, htab_hash (x)) = x;
|
|
+ p++;
|
|
+ }
|
|
+ while (p < olimit);
|
|
+ }
|
|
+ d = data;
|
|
+ do
|
|
+ {
|
|
+ size_t j;
|
|
+ for (j = 0; j < d[0]; ++j)
|
|
+ {
|
|
+ uintptr_t *p = d + 7 + j * 3;
|
|
+ p[2] = (uintptr_t) d;
|
|
+ /* Ugly hack, hash_entry_type is defined for the task dependencies,
|
|
+ which hash on the first element which is a pointer. We need
|
|
+ to hash also on the first sizeof (uintptr_t) bytes which contain
|
|
+ a pointer. Hide the cast from the compiler. */
|
|
+ hash_entry_type n;
|
|
+ __asm ("" : "=g" (n) : "0" (p));
|
|
+ *htab_find_slot (&new_htab, n, INSERT) = n;
|
|
+ }
|
|
+ if (d[4] == (uintptr_t) old)
|
|
+ break;
|
|
+ else
|
|
+ d = (uintptr_t *) d[4];
|
|
+ }
|
|
+ while (1);
|
|
+ d[5] = (uintptr_t) new_htab;
|
|
+}
|
|
+
|
|
+static void
|
|
+gomp_create_artificial_team (void)
|
|
+{
|
|
+ struct gomp_thread *thr = gomp_thread ();
|
|
+ struct gomp_task_icv *icv;
|
|
+ struct gomp_team *team = gomp_new_team (1);
|
|
+ struct gomp_task *task = thr->task;
|
|
+ icv = task ? &task->icv : &gomp_global_icv;
|
|
+ team->prev_ts = thr->ts;
|
|
+ thr->ts.team = team;
|
|
+ thr->ts.team_id = 0;
|
|
+ thr->ts.work_share = &team->work_shares[0];
|
|
+ thr->ts.last_work_share = NULL;
|
|
+#ifdef HAVE_SYNC_BUILTINS
|
|
+ thr->ts.single_count = 0;
|
|
+#endif
|
|
+ thr->ts.static_trip = 0;
|
|
+ thr->task = &team->implicit_task[0];
|
|
+ gomp_init_task (thr->task, NULL, icv);
|
|
+ if (task)
|
|
+ {
|
|
+ thr->task = task;
|
|
+ gomp_end_task ();
|
|
+ free (task);
|
|
+ thr->task = &team->implicit_task[0];
|
|
+ }
|
|
+#ifdef LIBGOMP_USE_PTHREADS
|
|
+ else
|
|
+ pthread_setspecific (gomp_thread_destructor, thr);
|
|
+#endif
|
|
+}
|
|
+
|
|
+/* The format of data is:
|
|
+ data[0] cnt
|
|
+ data[1] size
|
|
+ data[2] alignment (on output array pointer)
|
|
+ data[3] allocator (-1 if malloc allocator)
|
|
+ data[4] next pointer
|
|
+ data[5] used internally (htab pointer)
|
|
+ data[6] used internally (end of array)
|
|
+ cnt times
|
|
+ ent[0] address
|
|
+ ent[1] offset
|
|
+ ent[2] used internally (pointer to data[0])
|
|
+ The entries are sorted by increasing offset, so that a binary
|
|
+ search can be performed. Normally, data[8] is 0, exception is
|
|
+ for worksharing construct task reductions in cancellable parallel,
|
|
+ where at offset 0 there should be space for a pointer and an integer
|
|
+ which are used internally. */
|
|
+
|
|
+void
|
|
+GOMP_taskgroup_reduction_register (uintptr_t *data)
|
|
+{
|
|
+ struct gomp_thread *thr = gomp_thread ();
|
|
+ struct gomp_team *team = thr->ts.team;
|
|
+ struct gomp_task *task;
|
|
+ unsigned nthreads;
|
|
+ if (__builtin_expect (team == NULL, 0))
|
|
+ {
|
|
+ /* The task reduction code needs a team and task, so for
|
|
+ orphaned taskgroups just create the implicit team. */
|
|
+ gomp_create_artificial_team ();
|
|
+ ialias_call (GOMP_taskgroup_start) ();
|
|
+ team = thr->ts.team;
|
|
+ }
|
|
+ nthreads = team->nthreads;
|
|
+ task = thr->task;
|
|
+ gomp_reduction_register (data, task->taskgroup->reductions, NULL, nthreads);
|
|
+ task->taskgroup->reductions = data;
|
|
+}
|
|
+
|
|
+void
|
|
+GOMP_taskgroup_reduction_unregister (uintptr_t *data)
|
|
+{
|
|
+ uintptr_t *d = data;
|
|
+ htab_free ((struct htab *) data[5]);
|
|
+ do
|
|
+ {
|
|
+ gomp_aligned_free ((void *) d[2]);
|
|
+ d = (uintptr_t *) d[4];
|
|
+ }
|
|
+ while (d && !d[5]);
|
|
+}
|
|
+ialias (GOMP_taskgroup_reduction_unregister)
|
|
+
|
|
+/* For i = 0 to cnt-1, remap ptrs[i] which is either address of the
|
|
+ original list item or address of previously remapped original list
|
|
+ item to address of the private copy, store that to ptrs[i].
|
|
+ For i < cntorig, additionally set ptrs[cnt+i] to the address of
|
|
+ the original list item. */
|
|
+
|
|
+void
|
|
+GOMP_task_reduction_remap (size_t cnt, size_t cntorig, void **ptrs)
|
|
+{
|
|
+ struct gomp_thread *thr = gomp_thread ();
|
|
+ struct gomp_task *task = thr->task;
|
|
+ unsigned id = thr->ts.team_id;
|
|
+ uintptr_t *data = task->taskgroup->reductions;
|
|
+ uintptr_t *d;
|
|
+ struct htab *reduction_htab = (struct htab *) data[5];
|
|
+ size_t i;
|
|
+ for (i = 0; i < cnt; ++i)
|
|
+ {
|
|
+ hash_entry_type ent, n;
|
|
+ __asm ("" : "=g" (ent) : "0" (ptrs + i));
|
|
+ n = htab_find (reduction_htab, ent);
|
|
+ if (n)
|
|
+ {
|
|
+ uintptr_t *p;
|
|
+ __asm ("" : "=g" (p) : "0" (n));
|
|
+ /* At this point, p[0] should be equal to (uintptr_t) ptrs[i],
|
|
+ p[1] is the offset within the allocated chunk for each
|
|
+ thread, p[2] is the array registered with
|
|
+ GOMP_taskgroup_reduction_register, d[2] is the base of the
|
|
+ allocated memory and d[1] is the size of the allocated chunk
|
|
+ for one thread. */
|
|
+ d = (uintptr_t *) p[2];
|
|
+ ptrs[i] = (void *) (d[2] + id * d[1] + p[1]);
|
|
+ if (__builtin_expect (i < cntorig, 0))
|
|
+ ptrs[cnt + i] = (void *) p[0];
|
|
+ continue;
|
|
+ }
|
|
+ d = data;
|
|
+ while (d != NULL)
|
|
+ {
|
|
+ if ((uintptr_t) ptrs[i] >= d[2] && (uintptr_t) ptrs[i] < d[6])
|
|
+ break;
|
|
+ d = (uintptr_t *) d[4];
|
|
+ }
|
|
+ if (d == NULL)
|
|
+ gomp_fatal ("couldn't find matching task_reduction or reduction with "
|
|
+ "task modifier for %p", ptrs[i]);
|
|
+ uintptr_t off = ((uintptr_t) ptrs[i] - d[2]) % d[1];
|
|
+ ptrs[i] = (void *) (d[2] + id * d[1] + off);
|
|
+ if (__builtin_expect (i < cntorig, 0))
|
|
+ {
|
|
+ size_t lo = 0, hi = d[0] - 1;
|
|
+ while (lo <= hi)
|
|
+ {
|
|
+ size_t m = (lo + hi) / 2;
|
|
+ if (d[7 + 3 * m + 1] < off)
|
|
+ lo = m + 1;
|
|
+ else if (d[7 + 3 * m + 1] == off)
|
|
+ {
|
|
+ ptrs[cnt + i] = (void *) d[7 + 3 * m];
|
|
+ break;
|
|
+ }
|
|
+ else
|
|
+ hi = m - 1;
|
|
+ }
|
|
+ if (lo > hi)
|
|
+ gomp_fatal ("couldn't find matching task_reduction or reduction "
|
|
+ "with task modifier for %p", ptrs[i]);
|
|
+ }
|
|
+ }
|
|
+}
|
|
+
|
|
+struct gomp_taskgroup *
|
|
+gomp_parallel_reduction_register (uintptr_t *data, unsigned nthreads)
|
|
+{
|
|
+ struct gomp_taskgroup *taskgroup = gomp_taskgroup_init (NULL);
|
|
+ gomp_reduction_register (data, NULL, NULL, nthreads);
|
|
+ taskgroup->reductions = data;
|
|
+ return taskgroup;
|
|
+}
|
|
+
|
|
+void
|
|
+gomp_workshare_task_reduction_register (uintptr_t *data, uintptr_t *orig)
|
|
+{
|
|
+ struct gomp_thread *thr = gomp_thread ();
|
|
+ struct gomp_team *team = thr->ts.team;
|
|
+ struct gomp_task *task = thr->task;
|
|
+ unsigned nthreads = team->nthreads;
|
|
+ gomp_reduction_register (data, task->taskgroup->reductions, orig, nthreads);
|
|
+ task->taskgroup->reductions = data;
|
|
+}
|
|
+
|
|
+void
|
|
+gomp_workshare_taskgroup_start (void)
|
|
+{
|
|
+ struct gomp_thread *thr = gomp_thread ();
|
|
+ struct gomp_team *team = thr->ts.team;
|
|
+ struct gomp_task *task;
|
|
+
|
|
+ if (team == NULL)
|
|
+ {
|
|
+ gomp_create_artificial_team ();
|
|
+ team = thr->ts.team;
|
|
+ }
|
|
+ task = thr->task;
|
|
+ task->taskgroup = gomp_taskgroup_init (task->taskgroup);
|
|
+ task->taskgroup->workshare = true;
|
|
+}
|
|
+
|
|
+void
|
|
+GOMP_workshare_task_reduction_unregister (bool cancelled)
|
|
+{
|
|
+ struct gomp_thread *thr = gomp_thread ();
|
|
+ struct gomp_task *task = thr->task;
|
|
+ struct gomp_team *team = thr->ts.team;
|
|
+ uintptr_t *data = task->taskgroup->reductions;
|
|
+ ialias_call (GOMP_taskgroup_end) ();
|
|
+ if (thr->ts.team_id == 0)
|
|
+ ialias_call (GOMP_taskgroup_reduction_unregister) (data);
|
|
+ else
|
|
+ htab_free ((struct htab *) data[5]);
|
|
+
|
|
+ if (!cancelled)
|
|
+ gomp_team_barrier_wait (&team->barrier);
|
|
+}
|
|
+
|
|
int
|
|
omp_in_final (void)
|
|
{
|
|
--- libgomp/team.c.jj 2018-04-25 09:40:31.322655307 +0200
|
|
+++ libgomp/team.c 2019-05-07 18:46:36.548109384 +0200
|
|
@@ -32,7 +32,6 @@
|
|
#include <string.h>
|
|
|
|
#ifdef LIBGOMP_USE_PTHREADS
|
|
-/* This attribute contains PTHREAD_CREATE_DETACHED. */
|
|
pthread_attr_t gomp_thread_attr;
|
|
|
|
/* This key is for the thread destructor. */
|
|
@@ -58,6 +57,7 @@ struct gomp_thread_start_data
|
|
struct gomp_thread_pool *thread_pool;
|
|
unsigned int place;
|
|
bool nested;
|
|
+ pthread_t handle;
|
|
};
|
|
|
|
|
|
@@ -89,6 +89,9 @@ gomp_thread_start (void *xdata)
|
|
thr->ts = data->ts;
|
|
thr->task = data->task;
|
|
thr->place = data->place;
|
|
+#ifdef GOMP_NEEDS_THREAD_HANDLE
|
|
+ thr->handle = data->handle;
|
|
+#endif
|
|
|
|
thr->ts.team->ordered_release[thr->ts.team_id] = &thr->release;
|
|
|
|
@@ -131,6 +134,7 @@ gomp_thread_start (void *xdata)
|
|
}
|
|
|
|
gomp_sem_destroy (&thr->release);
|
|
+ pthread_detach (pthread_self ());
|
|
thr->thread_pool = NULL;
|
|
thr->task = NULL;
|
|
return NULL;
|
|
@@ -183,7 +187,7 @@ gomp_new_team (unsigned nthreads)
|
|
team->single_count = 0;
|
|
#endif
|
|
team->work_shares_to_free = &team->work_shares[0];
|
|
- gomp_init_work_share (&team->work_shares[0], false, nthreads);
|
|
+ gomp_init_work_share (&team->work_shares[0], 0, nthreads);
|
|
team->work_shares[0].next_alloc = NULL;
|
|
team->work_share_list_free = NULL;
|
|
team->work_share_list_alloc = &team->work_shares[1];
|
|
@@ -231,6 +235,7 @@ gomp_free_pool_helper (void *thread_pool
|
|
thr->thread_pool = NULL;
|
|
thr->task = NULL;
|
|
#ifdef LIBGOMP_USE_PTHREADS
|
|
+ pthread_detach (pthread_self ());
|
|
pthread_exit (NULL);
|
|
#elif defined(__nvptx__)
|
|
asm ("exit;");
|
|
@@ -297,7 +302,8 @@ gomp_free_thread (void *arg __attribute_
|
|
#ifdef LIBGOMP_USE_PTHREADS
|
|
void
|
|
gomp_team_start (void (*fn) (void *), void *data, unsigned nthreads,
|
|
- unsigned flags, struct gomp_team *team)
|
|
+ unsigned flags, struct gomp_team *team,
|
|
+ struct gomp_taskgroup *taskgroup)
|
|
{
|
|
struct gomp_thread_start_data *start_data;
|
|
struct gomp_thread *thr, *nthr;
|
|
@@ -312,6 +318,7 @@ gomp_team_start (void (*fn) (void *), vo
|
|
unsigned int s = 0, rest = 0, p = 0, k = 0;
|
|
unsigned int affinity_count = 0;
|
|
struct gomp_thread **affinity_thr = NULL;
|
|
+ bool force_display = false;
|
|
|
|
thr = gomp_thread ();
|
|
nested = thr->ts.level;
|
|
@@ -319,7 +326,12 @@ gomp_team_start (void (*fn) (void *), vo
|
|
task = thr->task;
|
|
icv = task ? &task->icv : &gomp_global_icv;
|
|
if (__builtin_expect (gomp_places_list != NULL, 0) && thr->place == 0)
|
|
- gomp_init_affinity ();
|
|
+ {
|
|
+ gomp_init_affinity ();
|
|
+ if (__builtin_expect (gomp_display_affinity_var, 0) && nthreads == 1)
|
|
+ gomp_display_affinity_thread (gomp_thread_self (), &thr->ts,
|
|
+ thr->place);
|
|
+ }
|
|
|
|
/* Always save the previous state, even if this isn't a nested team.
|
|
In particular, we should save any work share state from an outer
|
|
@@ -338,6 +350,9 @@ gomp_team_start (void (*fn) (void *), vo
|
|
#endif
|
|
thr->ts.static_trip = 0;
|
|
thr->task = &team->implicit_task[0];
|
|
+#ifdef GOMP_NEEDS_THREAD_HANDLE
|
|
+ thr->handle = pthread_self ();
|
|
+#endif
|
|
nthreads_var = icv->nthreads_var;
|
|
if (__builtin_expect (gomp_nthreads_var_list != NULL, 0)
|
|
&& thr->ts.level < gomp_nthreads_var_list_len)
|
|
@@ -350,6 +365,7 @@ gomp_team_start (void (*fn) (void *), vo
|
|
&& thr->ts.level < gomp_bind_var_list_len)
|
|
bind_var = gomp_bind_var_list[thr->ts.level];
|
|
gomp_init_task (thr->task, task, icv);
|
|
+ thr->task->taskgroup = taskgroup;
|
|
team->implicit_task[0].icv.nthreads_var = nthreads_var;
|
|
team->implicit_task[0].icv.bind_var = bind_var;
|
|
|
|
@@ -465,7 +481,9 @@ gomp_team_start (void (*fn) (void *), vo
|
|
pool->threads
|
|
= gomp_realloc (pool->threads,
|
|
pool->threads_size
|
|
- * sizeof (struct gomp_thread_data *));
|
|
+ * sizeof (struct gomp_thread *));
|
|
+ /* Add current (master) thread to threads[]. */
|
|
+ pool->threads[0] = thr;
|
|
}
|
|
|
|
/* Release existing idle threads. */
|
|
@@ -540,6 +558,7 @@ gomp_team_start (void (*fn) (void *), vo
|
|
+ place_partition_len))
|
|
{
|
|
unsigned int l;
|
|
+ force_display = true;
|
|
if (affinity_thr == NULL)
|
|
{
|
|
unsigned int j;
|
|
@@ -623,6 +642,7 @@ gomp_team_start (void (*fn) (void *), vo
|
|
gomp_init_task (nthr->task, task, icv);
|
|
team->implicit_task[i].icv.nthreads_var = nthreads_var;
|
|
team->implicit_task[i].icv.bind_var = bind_var;
|
|
+ nthr->task->taskgroup = taskgroup;
|
|
nthr->fn = fn;
|
|
nthr->data = data;
|
|
team->ordered_release[i] = &nthr->release;
|
|
@@ -712,19 +732,17 @@ gomp_team_start (void (*fn) (void *), vo
|
|
{
|
|
size_t stacksize;
|
|
pthread_attr_init (&thread_attr);
|
|
- pthread_attr_setdetachstate (&thread_attr, PTHREAD_CREATE_DETACHED);
|
|
if (! pthread_attr_getstacksize (&gomp_thread_attr, &stacksize))
|
|
pthread_attr_setstacksize (&thread_attr, stacksize);
|
|
attr = &thread_attr;
|
|
}
|
|
|
|
start_data = gomp_alloca (sizeof (struct gomp_thread_start_data)
|
|
- * (nthreads-i));
|
|
+ * (nthreads - i));
|
|
|
|
/* Launch new threads. */
|
|
for (; i < nthreads; ++i)
|
|
{
|
|
- pthread_t pt;
|
|
int err;
|
|
|
|
start_data->ts.place_partition_off = thr->ts.place_partition_off;
|
|
@@ -810,11 +828,14 @@ gomp_team_start (void (*fn) (void *), vo
|
|
gomp_init_task (start_data->task, task, icv);
|
|
team->implicit_task[i].icv.nthreads_var = nthreads_var;
|
|
team->implicit_task[i].icv.bind_var = bind_var;
|
|
+ start_data->task->taskgroup = taskgroup;
|
|
start_data->thread_pool = pool;
|
|
start_data->nested = nested;
|
|
|
|
attr = gomp_adjust_thread_attr (attr, &thread_attr);
|
|
- err = pthread_create (&pt, attr, gomp_thread_start, start_data++);
|
|
+ err = pthread_create (&start_data->handle, attr, gomp_thread_start,
|
|
+ start_data);
|
|
+ start_data++;
|
|
if (err != 0)
|
|
gomp_fatal ("Thread creation failed: %s", strerror (err));
|
|
}
|
|
@@ -854,6 +875,42 @@ gomp_team_start (void (*fn) (void *), vo
|
|
gomp_mutex_unlock (&gomp_managed_threads_lock);
|
|
#endif
|
|
}
|
|
+ if (__builtin_expect (gomp_display_affinity_var, 0))
|
|
+ {
|
|
+ if (nested
|
|
+ || nthreads != old_threads_used
|
|
+ || force_display)
|
|
+ {
|
|
+ gomp_display_affinity_thread (gomp_thread_self (), &thr->ts,
|
|
+ thr->place);
|
|
+ if (nested)
|
|
+ {
|
|
+ start_data -= nthreads - 1;
|
|
+ for (i = 1; i < nthreads; ++i)
|
|
+ {
|
|
+ gomp_display_affinity_thread (
|
|
+#ifdef LIBGOMP_USE_PTHREADS
|
|
+ start_data->handle,
|
|
+#else
|
|
+ gomp_thread_self (),
|
|
+#endif
|
|
+ &start_data->ts,
|
|
+ start_data->place);
|
|
+ start_data++;
|
|
+ }
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+ for (i = 1; i < nthreads; ++i)
|
|
+ {
|
|
+ gomp_thread_handle handle
|
|
+ = gomp_thread_to_pthread_t (pool->threads[i]);
|
|
+ gomp_display_affinity_thread (handle, &pool->threads[i]->ts,
|
|
+ pool->threads[i]->place);
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ }
|
|
if (__builtin_expect (affinity_thr != NULL, 0)
|
|
&& team->prev_ts.place_partition_len > 64)
|
|
free (affinity_thr);
|
|
@@ -894,7 +951,7 @@ gomp_team_end (void)
|
|
gomp_end_task ();
|
|
thr->ts = team->prev_ts;
|
|
|
|
- if (__builtin_expect (thr->ts.team != NULL, 0))
|
|
+ if (__builtin_expect (thr->ts.level != 0, 0))
|
|
{
|
|
#ifdef HAVE_SYNC_BUILTINS
|
|
__sync_fetch_and_add (&gomp_managed_threads, 1L - team->nthreads);
|
|
@@ -959,6 +1016,76 @@ team_destructor (void)
|
|
crashes. */
|
|
pthread_key_delete (gomp_thread_destructor);
|
|
}
|
|
+
|
|
+/* Similar to gomp_free_pool_helper, but don't detach itself,
|
|
+ gomp_pause_host will pthread_join those threads. */
|
|
+
|
|
+static void
|
|
+gomp_pause_pool_helper (void *thread_pool)
|
|
+{
|
|
+ struct gomp_thread *thr = gomp_thread ();
|
|
+ struct gomp_thread_pool *pool
|
|
+ = (struct gomp_thread_pool *) thread_pool;
|
|
+ gomp_simple_barrier_wait_last (&pool->threads_dock);
|
|
+ gomp_sem_destroy (&thr->release);
|
|
+ thr->thread_pool = NULL;
|
|
+ thr->task = NULL;
|
|
+ pthread_exit (NULL);
|
|
+}
|
|
+
|
|
+/* Free a thread pool and release its threads. Return non-zero on
|
|
+ failure. */
|
|
+
|
|
+int
|
|
+gomp_pause_host (void)
|
|
+{
|
|
+ struct gomp_thread *thr = gomp_thread ();
|
|
+ struct gomp_thread_pool *pool = thr->thread_pool;
|
|
+ if (thr->ts.level)
|
|
+ return -1;
|
|
+ if (pool)
|
|
+ {
|
|
+ if (pool->threads_used > 0)
|
|
+ {
|
|
+ int i;
|
|
+ pthread_t *thrs
|
|
+ = gomp_alloca (sizeof (pthread_t) * pool->threads_used);
|
|
+ for (i = 1; i < pool->threads_used; i++)
|
|
+ {
|
|
+ struct gomp_thread *nthr = pool->threads[i];
|
|
+ nthr->fn = gomp_pause_pool_helper;
|
|
+ nthr->data = pool;
|
|
+ thrs[i] = gomp_thread_to_pthread_t (nthr);
|
|
+ }
|
|
+ /* This barrier undocks threads docked on pool->threads_dock. */
|
|
+ gomp_simple_barrier_wait (&pool->threads_dock);
|
|
+ /* And this waits till all threads have called gomp_barrier_wait_last
|
|
+ in gomp_pause_pool_helper. */
|
|
+ gomp_simple_barrier_wait (&pool->threads_dock);
|
|
+ /* Now it is safe to destroy the barrier and free the pool. */
|
|
+ gomp_simple_barrier_destroy (&pool->threads_dock);
|
|
+
|
|
+#ifdef HAVE_SYNC_BUILTINS
|
|
+ __sync_fetch_and_add (&gomp_managed_threads,
|
|
+ 1L - pool->threads_used);
|
|
+#else
|
|
+ gomp_mutex_lock (&gomp_managed_threads_lock);
|
|
+ gomp_managed_threads -= pool->threads_used - 1L;
|
|
+ gomp_mutex_unlock (&gomp_managed_threads_lock);
|
|
+#endif
|
|
+ for (i = 1; i < pool->threads_used; i++)
|
|
+ pthread_join (thrs[i], NULL);
|
|
+ }
|
|
+ if (pool->last_team)
|
|
+ free_team (pool->last_team);
|
|
+#ifndef __nvptx__
|
|
+ free (pool->threads);
|
|
+ free (pool);
|
|
+#endif
|
|
+ thr->thread_pool = NULL;
|
|
+ }
|
|
+ return 0;
|
|
+}
|
|
#endif
|
|
|
|
struct gomp_task_icv *
|
|
--- libgomp/libgomp.h.jj 2018-04-25 09:40:31.925655587 +0200
|
|
+++ libgomp/libgomp.h 2019-05-07 19:01:51.285535999 +0200
|
|
@@ -44,6 +44,7 @@
|
|
#include "config.h"
|
|
#include "gstdint.h"
|
|
#include "libgomp-plugin.h"
|
|
+#include "gomp-constants.h"
|
|
|
|
#ifdef HAVE_PTHREAD_H
|
|
#include <pthread.h>
|
|
@@ -85,9 +86,21 @@ enum memmodel
|
|
|
|
/* alloc.c */
|
|
|
|
+#if defined(HAVE_ALIGNED_ALLOC) \
|
|
+ || defined(HAVE__ALIGNED_MALLOC) \
|
|
+ || defined(HAVE_POSIX_MEMALIGN) \
|
|
+ || defined(HAVE_MEMALIGN)
|
|
+/* Defined if gomp_aligned_alloc doesn't use fallback version
|
|
+ and free can be used instead of gomp_aligned_free. */
|
|
+#define GOMP_HAVE_EFFICIENT_ALIGNED_ALLOC 1
|
|
+#endif
|
|
+
|
|
extern void *gomp_malloc (size_t) __attribute__((malloc));
|
|
extern void *gomp_malloc_cleared (size_t) __attribute__((malloc));
|
|
extern void *gomp_realloc (void *, size_t);
|
|
+extern void *gomp_aligned_alloc (size_t, size_t)
|
|
+ __attribute__((malloc, alloc_size (2)));
|
|
+extern void gomp_aligned_free (void *);
|
|
|
|
/* Avoid conflicting prototypes of alloca() in system headers by using
|
|
GCC's builtin alloca(). */
|
|
@@ -137,7 +150,8 @@ enum gomp_schedule_type
|
|
GFS_STATIC,
|
|
GFS_DYNAMIC,
|
|
GFS_GUIDED,
|
|
- GFS_AUTO
|
|
+ GFS_AUTO,
|
|
+ GFS_MONOTONIC = 0x80000000U
|
|
};
|
|
|
|
struct gomp_doacross_work_share
|
|
@@ -174,6 +188,8 @@ struct gomp_doacross_work_share
|
|
/* Likewise, but for the ull implementation. */
|
|
unsigned long long boundary_ull;
|
|
};
|
|
+ /* Pointer to extra memory if needed for lastprivate(conditional). */
|
|
+ void *extra;
|
|
/* Array of shift counts for each dimension if they can be flattened. */
|
|
unsigned int shift_counts[];
|
|
};
|
|
@@ -275,6 +291,9 @@ struct gomp_work_share
|
|
struct gomp_work_share *next_free;
|
|
};
|
|
|
|
+ /* Task reductions for this work-sharing construct. */
|
|
+ uintptr_t *task_reductions;
|
|
+
|
|
/* If only few threads are in the team, ordered_team_ids can point
|
|
to this array which fills the padding at the end of this struct. */
|
|
unsigned inline_ordered_team_ids[0];
|
|
@@ -365,8 +384,12 @@ extern void **gomp_places_list;
|
|
extern unsigned long gomp_places_list_len;
|
|
extern unsigned int gomp_num_teams_var;
|
|
extern int gomp_debug_var;
|
|
+extern bool gomp_display_affinity_var;
|
|
+extern char *gomp_affinity_format_var;
|
|
+extern size_t gomp_affinity_format_len;
|
|
extern int goacc_device_num;
|
|
extern char *goacc_device_type;
|
|
+extern int goacc_default_dims[GOMP_DIM_MAX];
|
|
|
|
enum gomp_task_kind
|
|
{
|
|
@@ -469,8 +492,10 @@ struct gomp_taskgroup
|
|
struct gomp_taskgroup *prev;
|
|
/* Queue of tasks that belong in this taskgroup. */
|
|
struct priority_queue taskgroup_queue;
|
|
+ uintptr_t *reductions;
|
|
bool in_taskgroup_wait;
|
|
bool cancelled;
|
|
+ bool workshare;
|
|
gomp_sem_t taskgroup_sem;
|
|
size_t num_children;
|
|
};
|
|
@@ -613,6 +638,19 @@ struct gomp_thread
|
|
|
|
/* User pthread thread pool */
|
|
struct gomp_thread_pool *thread_pool;
|
|
+
|
|
+#if defined(LIBGOMP_USE_PTHREADS) \
|
|
+ && (!defined(HAVE_TLS) \
|
|
+ || !defined(__GLIBC__) \
|
|
+ || !defined(USING_INITIAL_EXEC_TLS))
|
|
+ /* pthread_t of the thread containing this gomp_thread.
|
|
+ On Linux when using initial-exec TLS,
|
|
+ (typeof (pthread_t)) gomp_thread () - pthread_self ()
|
|
+ is constant in all threads, so we can optimize and not
|
|
+ store it. */
|
|
+#define GOMP_NEEDS_THREAD_HANDLE 1
|
|
+ pthread_t handle;
|
|
+#endif
|
|
};
|
|
|
|
|
|
@@ -709,6 +747,25 @@ extern bool gomp_affinity_finalize_place
|
|
extern bool gomp_affinity_init_level (int, unsigned long, bool);
|
|
extern void gomp_affinity_print_place (void *);
|
|
extern void gomp_get_place_proc_ids_8 (int, int64_t *);
|
|
+extern void gomp_display_affinity_place (char *, size_t, size_t *, int);
|
|
+
|
|
+/* affinity-fmt.c */
|
|
+
|
|
+extern void gomp_print_string (const char *str, size_t len);
|
|
+extern void gomp_set_affinity_format (const char *, size_t);
|
|
+extern void gomp_display_string (char *, size_t, size_t *, const char *,
|
|
+ size_t);
|
|
+#ifdef LIBGOMP_USE_PTHREADS
|
|
+typedef pthread_t gomp_thread_handle;
|
|
+#else
|
|
+typedef struct {} gomp_thread_handle;
|
|
+#endif
|
|
+extern size_t gomp_display_affinity (char *, size_t, const char *,
|
|
+ gomp_thread_handle,
|
|
+ struct gomp_team_state *, unsigned int);
|
|
+extern void gomp_display_affinity_thread (gomp_thread_handle,
|
|
+ struct gomp_team_state *,
|
|
+ unsigned int) __attribute__((cold));
|
|
|
|
/* iter.c */
|
|
|
|
@@ -745,9 +802,9 @@ extern void gomp_ordered_next (void);
|
|
extern void gomp_ordered_static_init (void);
|
|
extern void gomp_ordered_static_next (void);
|
|
extern void gomp_ordered_sync (void);
|
|
-extern void gomp_doacross_init (unsigned, long *, long);
|
|
+extern void gomp_doacross_init (unsigned, long *, long, size_t);
|
|
extern void gomp_doacross_ull_init (unsigned, unsigned long long *,
|
|
- unsigned long long);
|
|
+ unsigned long long, size_t);
|
|
|
|
/* parallel.c */
|
|
|
|
@@ -770,6 +827,10 @@ extern bool gomp_create_target_task (str
|
|
size_t *, unsigned short *, unsigned int,
|
|
void **, void **,
|
|
enum gomp_target_task_state);
|
|
+extern struct gomp_taskgroup *gomp_parallel_reduction_register (uintptr_t *,
|
|
+ unsigned);
|
|
+extern void gomp_workshare_taskgroup_start (void);
|
|
+extern void gomp_workshare_task_reduction_register (uintptr_t *, uintptr_t *);
|
|
|
|
static void inline
|
|
gomp_finish_task (struct gomp_task *task)
|
|
@@ -782,9 +843,11 @@ gomp_finish_task (struct gomp_task *task
|
|
|
|
extern struct gomp_team *gomp_new_team (unsigned);
|
|
extern void gomp_team_start (void (*) (void *), void *, unsigned,
|
|
- unsigned, struct gomp_team *);
|
|
+ unsigned, struct gomp_team *,
|
|
+ struct gomp_taskgroup *);
|
|
extern void gomp_team_end (void);
|
|
extern void gomp_free_thread (void *);
|
|
+extern int gomp_pause_host (void);
|
|
|
|
/* target.c */
|
|
|
|
@@ -851,6 +914,8 @@ struct splay_tree_key_s {
|
|
uintptr_t tgt_offset;
|
|
/* Reference count. */
|
|
uintptr_t refcount;
|
|
+ /* Dynamic reference count. */
|
|
+ uintptr_t dynamic_refcount;
|
|
/* Pointer to the original mapping of "omp declare target link" object. */
|
|
splay_tree_key link_key;
|
|
};
|
|
@@ -989,7 +1054,9 @@ enum gomp_map_vars_kind
|
|
};
|
|
|
|
extern void gomp_acc_insert_pointer (size_t, void **, size_t *, void *);
|
|
-extern void gomp_acc_remove_pointer (void *, bool, int, int);
|
|
+extern void gomp_acc_remove_pointer (void *, size_t, bool, int, int, int);
|
|
+extern void gomp_acc_declare_allocate (bool, size_t, void **, size_t *,
|
|
+ unsigned short *);
|
|
|
|
extern struct target_mem_desc *gomp_map_vars (struct gomp_device_descr *,
|
|
size_t, void **, void **,
|
|
@@ -999,12 +1066,13 @@ extern void gomp_unmap_vars (struct targ
|
|
extern void gomp_init_device (struct gomp_device_descr *);
|
|
extern void gomp_free_memmap (struct splay_tree_s *);
|
|
extern void gomp_unload_device (struct gomp_device_descr *);
|
|
+extern bool gomp_remove_var (struct gomp_device_descr *, splay_tree_key);
|
|
|
|
/* work.c */
|
|
|
|
-extern void gomp_init_work_share (struct gomp_work_share *, bool, unsigned);
|
|
+extern void gomp_init_work_share (struct gomp_work_share *, size_t, unsigned);
|
|
extern void gomp_fini_work_share (struct gomp_work_share *);
|
|
-extern bool gomp_work_share_start (bool);
|
|
+extern bool gomp_work_share_start (size_t);
|
|
extern void gomp_work_share_end (void);
|
|
extern bool gomp_work_share_end_cancel (void);
|
|
extern void gomp_work_share_end_nowait (void);
|
|
@@ -1028,6 +1096,14 @@ gomp_work_share_init_done (void)
|
|
#include "omp-lock.h"
|
|
#define _LIBGOMP_OMP_LOCK_DEFINED 1
|
|
#include "omp.h.in"
|
|
+#define omp_sched_monotonic 0x80000000U
|
|
+typedef enum omp_pause_resource_t
|
|
+{
|
|
+ omp_pause_soft = 1,
|
|
+ omp_pause_hard = 2
|
|
+} omp_pause_resource_t;
|
|
+extern int omp_pause_resource (omp_pause_resource_t, int) __GOMP_NOTHROW;
|
|
+extern int omp_pause_resource_all (omp_pause_resource_t) __GOMP_NOTHROW;
|
|
|
|
#if !defined (HAVE_ATTRIBUTE_VISIBILITY) \
|
|
|| !defined (HAVE_ATTRIBUTE_ALIAS) \
|
|
@@ -1082,16 +1158,26 @@ extern int gomp_test_nest_lock_25 (omp_n
|
|
# define attribute_hidden
|
|
#endif
|
|
|
|
+#if __GNUC__ >= 9
|
|
+# define HAVE_ATTRIBUTE_COPY
|
|
+#endif
|
|
+
|
|
+#ifdef HAVE_ATTRIBUTE_COPY
|
|
+# define attribute_copy(arg) __attribute__ ((copy (arg)))
|
|
+#else
|
|
+# define attribute_copy(arg)
|
|
+#endif
|
|
+
|
|
#ifdef HAVE_ATTRIBUTE_ALIAS
|
|
# define strong_alias(fn, al) \
|
|
- extern __typeof (fn) al __attribute__ ((alias (#fn)));
|
|
+ extern __typeof (fn) al __attribute__ ((alias (#fn))) attribute_copy (fn);
|
|
|
|
# define ialias_ulp ialias_str1(__USER_LABEL_PREFIX__)
|
|
# define ialias_str1(x) ialias_str2(x)
|
|
# define ialias_str2(x) #x
|
|
# define ialias(fn) \
|
|
extern __typeof (fn) gomp_ialias_##fn \
|
|
- __attribute__ ((alias (#fn))) attribute_hidden;
|
|
+ __attribute__ ((alias (#fn))) attribute_hidden attribute_copy (fn);
|
|
# define ialias_redirect(fn) \
|
|
extern __typeof (fn) fn __asm__ (ialias_ulp "gomp_ialias_" #fn) attribute_hidden;
|
|
# define ialias_call(fn) gomp_ialias_ ## fn
|
|
@@ -1131,4 +1217,42 @@ task_to_priority_node (enum priority_que
|
|
return (struct priority_node *) ((char *) task
|
|
+ priority_queue_offset (type));
|
|
}
|
|
+
|
|
+#ifdef LIBGOMP_USE_PTHREADS
|
|
+static inline gomp_thread_handle
|
|
+gomp_thread_self (void)
|
|
+{
|
|
+ return pthread_self ();
|
|
+}
|
|
+
|
|
+static inline gomp_thread_handle
|
|
+gomp_thread_to_pthread_t (struct gomp_thread *thr)
|
|
+{
|
|
+ struct gomp_thread *this_thr = gomp_thread ();
|
|
+ if (thr == this_thr)
|
|
+ return pthread_self ();
|
|
+#ifdef GOMP_NEEDS_THREAD_HANDLE
|
|
+ return thr->handle;
|
|
+#else
|
|
+ /* On Linux with initial-exec TLS, the pthread_t of the thread containing
|
|
+ thr can be computed from thr, this_thr and pthread_self (),
|
|
+ as the distance between this_thr and pthread_self () is constant. */
|
|
+ return pthread_self () + ((uintptr_t) thr - (uintptr_t) this_thr);
|
|
+#endif
|
|
+}
|
|
+#else
|
|
+static inline gomp_thread_handle
|
|
+gomp_thread_self (void)
|
|
+{
|
|
+ return (gomp_thread_handle) {};
|
|
+}
|
|
+
|
|
+static inline gomp_thread_handle
|
|
+gomp_thread_to_pthread_t (struct gomp_thread *thr)
|
|
+{
|
|
+ (void) thr;
|
|
+ return gomp_thread_self ();
|
|
+}
|
|
+#endif
|
|
+
|
|
#endif /* LIBGOMP_H */
|
|
--- libgomp/oacc-parallel.c.jj 2018-04-25 09:40:31.319655306 +0200
|
|
+++ libgomp/oacc-parallel.c 2019-05-07 19:09:47.010991153 +0200
|
|
@@ -27,6 +27,8 @@
|
|
/* This file handles OpenACC constructs. */
|
|
|
|
#include "openacc.h"
|
|
+void acc_copyout_finalize (void *, size_t) __GOACC_NOTHROW;
|
|
+void acc_delete_finalize (void *, size_t) __GOACC_NOTHROW;
|
|
#include "libgomp.h"
|
|
#include "libgomp_g.h"
|
|
#include "gomp-constants.h"
|
|
@@ -38,31 +40,95 @@
|
|
#include <stdarg.h>
|
|
#include <assert.h>
|
|
|
|
+
|
|
+/* In the ABI, the GOACC_FLAGs are encoded as an inverted bitmask, so that we
|
|
+ continue to support the following two legacy values. */
|
|
+_Static_assert (GOACC_FLAGS_UNMARSHAL (GOMP_DEVICE_ICV) == 0,
|
|
+ "legacy GOMP_DEVICE_ICV broken");
|
|
+_Static_assert (GOACC_FLAGS_UNMARSHAL (GOMP_DEVICE_HOST_FALLBACK)
|
|
+ == GOACC_FLAG_HOST_FALLBACK,
|
|
+ "legacy GOMP_DEVICE_HOST_FALLBACK broken");
|
|
+
|
|
+
|
|
+/* Returns the number of mappings associated with the pointer or pset. PSET
|
|
+ have three mappings, whereas pointer have two. */
|
|
+
|
|
static int
|
|
-find_pset (int pos, size_t mapnum, unsigned short *kinds)
|
|
+find_pointer (int pos, size_t mapnum, unsigned short *kinds)
|
|
{
|
|
if (pos + 1 >= mapnum)
|
|
return 0;
|
|
|
|
unsigned char kind = kinds[pos+1] & 0xff;
|
|
|
|
- return kind == GOMP_MAP_TO_PSET;
|
|
+ if (kind == GOMP_MAP_TO_PSET)
|
|
+ return 3;
|
|
+ else if (kind == GOMP_MAP_POINTER)
|
|
+ return 2;
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+/* Handle the mapping pair that are presented when a
|
|
+ deviceptr clause is used with Fortran. */
|
|
+
|
|
+static void
|
|
+handle_ftn_pointers (size_t mapnum, void **hostaddrs, size_t *sizes,
|
|
+ unsigned short *kinds)
|
|
+{
|
|
+ int i;
|
|
+
|
|
+ for (i = 0; i < mapnum; i++)
|
|
+ {
|
|
+ unsigned short kind1 = kinds[i] & 0xff;
|
|
+
|
|
+ /* Handle Fortran deviceptr clause. */
|
|
+ if (kind1 == GOMP_MAP_FORCE_DEVICEPTR)
|
|
+ {
|
|
+ unsigned short kind2;
|
|
+
|
|
+ if (i < (signed)mapnum - 1)
|
|
+ kind2 = kinds[i + 1] & 0xff;
|
|
+ else
|
|
+ kind2 = 0xffff;
|
|
+
|
|
+ if (sizes[i] == sizeof (void *))
|
|
+ continue;
|
|
+
|
|
+ /* At this point, we're dealing with a Fortran deviceptr.
|
|
+ If the next element is not what we're expecting, then
|
|
+ this is an instance of where the deviceptr variable was
|
|
+ not used within the region and the pointer was removed
|
|
+ by the gimplifier. */
|
|
+ if (kind2 == GOMP_MAP_POINTER
|
|
+ && sizes[i + 1] == 0
|
|
+ && hostaddrs[i] == *(void **)hostaddrs[i + 1])
|
|
+ {
|
|
+ kinds[i+1] = kinds[i];
|
|
+ sizes[i+1] = sizeof (void *);
|
|
+ }
|
|
+
|
|
+ /* Invalidate the entry. */
|
|
+ hostaddrs[i] = NULL;
|
|
+ }
|
|
+ }
|
|
}
|
|
|
|
static void goacc_wait (int async, int num_waits, va_list *ap);
|
|
|
|
|
|
-/* Launch a possibly offloaded function on DEVICE. FN is the host fn
|
|
+/* Launch a possibly offloaded function with FLAGS. FN is the host fn
|
|
address. MAPNUM, HOSTADDRS, SIZES & KINDS describe the memory
|
|
blocks to be copied to/from the device. Varadic arguments are
|
|
keyed optional parameters terminated with a zero. */
|
|
|
|
void
|
|
-GOACC_parallel_keyed (int device, void (*fn) (void *),
|
|
+GOACC_parallel_keyed (int flags_m, void (*fn) (void *),
|
|
size_t mapnum, void **hostaddrs, size_t *sizes,
|
|
unsigned short *kinds, ...)
|
|
{
|
|
- bool host_fallback = device == GOMP_DEVICE_HOST_FALLBACK;
|
|
+ int flags = GOACC_FLAGS_UNMARSHAL (flags_m);
|
|
+
|
|
va_list ap;
|
|
struct goacc_thread *thr;
|
|
struct gomp_device_descr *acc_dev;
|
|
@@ -88,9 +154,11 @@ GOACC_parallel_keyed (int device, void (
|
|
thr = goacc_thread ();
|
|
acc_dev = thr->dev;
|
|
|
|
+ handle_ftn_pointers (mapnum, hostaddrs, sizes, kinds);
|
|
+
|
|
/* Host fallback if "if" clause is false or if the current device is set to
|
|
the host. */
|
|
- if (host_fallback)
|
|
+ if (flags & GOACC_FLAG_HOST_FALLBACK)
|
|
{
|
|
goacc_save_and_set_bind (acc_device_host);
|
|
fn (hostaddrs);
|
|
@@ -140,9 +208,7 @@ GOACC_parallel_keyed (int device, void (
|
|
case GOMP_LAUNCH_WAIT:
|
|
{
|
|
unsigned num_waits = GOMP_LAUNCH_OP (tag);
|
|
-
|
|
- if (num_waits)
|
|
- goacc_wait (async, num_waits, &ap);
|
|
+ goacc_wait (async, num_waits, &ap);
|
|
break;
|
|
}
|
|
|
|
@@ -177,16 +243,36 @@ GOACC_parallel_keyed (int device, void (
|
|
devaddrs = gomp_alloca (sizeof (void *) * mapnum);
|
|
for (i = 0; i < mapnum; i++)
|
|
devaddrs[i] = (void *) (tgt->list[i].key->tgt->tgt_start
|
|
- + tgt->list[i].key->tgt_offset);
|
|
+ + tgt->list[i].key->tgt_offset
|
|
+ + tgt->list[i].offset);
|
|
|
|
acc_dev->openacc.exec_func (tgt_fn, mapnum, hostaddrs, devaddrs,
|
|
async, dims, tgt);
|
|
|
|
/* If running synchronously, unmap immediately. */
|
|
- if (async < acc_async_noval)
|
|
+ bool copyfrom = true;
|
|
+ if (async_synchronous_p (async))
|
|
gomp_unmap_vars (tgt, true);
|
|
else
|
|
- tgt->device_descr->openacc.register_async_cleanup_func (tgt, async);
|
|
+ {
|
|
+ bool async_unmap = false;
|
|
+ for (size_t i = 0; i < tgt->list_count; i++)
|
|
+ {
|
|
+ splay_tree_key k = tgt->list[i].key;
|
|
+ if (k && k->refcount == 1)
|
|
+ {
|
|
+ async_unmap = true;
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+ if (async_unmap)
|
|
+ tgt->device_descr->openacc.register_async_cleanup_func (tgt, async);
|
|
+ else
|
|
+ {
|
|
+ copyfrom = false;
|
|
+ gomp_unmap_vars (tgt, copyfrom);
|
|
+ }
|
|
+ }
|
|
|
|
acc_dev->openacc.async_set_async_func (acc_async_sync);
|
|
}
|
|
@@ -194,7 +280,7 @@ GOACC_parallel_keyed (int device, void (
|
|
/* Legacy entry point, only provide host execution. */
|
|
|
|
void
|
|
-GOACC_parallel (int device, void (*fn) (void *),
|
|
+GOACC_parallel (int flags_m, void (*fn) (void *),
|
|
size_t mapnum, void **hostaddrs, size_t *sizes,
|
|
unsigned short *kinds,
|
|
int num_gangs, int num_workers, int vector_length,
|
|
@@ -206,10 +292,11 @@ GOACC_parallel (int device, void (*fn) (
|
|
}
|
|
|
|
void
|
|
-GOACC_data_start (int device, size_t mapnum,
|
|
+GOACC_data_start (int flags_m, size_t mapnum,
|
|
void **hostaddrs, size_t *sizes, unsigned short *kinds)
|
|
{
|
|
- bool host_fallback = device == GOMP_DEVICE_HOST_FALLBACK;
|
|
+ int flags = GOACC_FLAGS_UNMARSHAL (flags_m);
|
|
+
|
|
struct target_mem_desc *tgt;
|
|
|
|
#ifdef HAVE_INTTYPES_H
|
|
@@ -227,7 +314,7 @@ GOACC_data_start (int device, size_t map
|
|
|
|
/* Host fallback or 'do nothing'. */
|
|
if ((acc_dev->capabilities & GOMP_OFFLOAD_CAP_SHARED_MEM)
|
|
- || host_fallback)
|
|
+ || (flags & GOACC_FLAG_HOST_FALLBACK))
|
|
{
|
|
tgt = gomp_map_vars (NULL, 0, NULL, NULL, NULL, NULL, true,
|
|
GOMP_MAP_VARS_OPENACC);
|
|
@@ -258,13 +345,14 @@ GOACC_data_end (void)
|
|
}
|
|
|
|
void
|
|
-GOACC_enter_exit_data (int device, size_t mapnum,
|
|
+GOACC_enter_exit_data (int flags_m, size_t mapnum,
|
|
void **hostaddrs, size_t *sizes, unsigned short *kinds,
|
|
int async, int num_waits, ...)
|
|
{
|
|
+ int flags = GOACC_FLAGS_UNMARSHAL (flags_m);
|
|
+
|
|
struct goacc_thread *thr;
|
|
struct gomp_device_descr *acc_dev;
|
|
- bool host_fallback = device == GOMP_DEVICE_HOST_FALLBACK;
|
|
bool data_enter = false;
|
|
size_t i;
|
|
|
|
@@ -274,7 +362,7 @@ GOACC_enter_exit_data (int device, size_
|
|
acc_dev = thr->dev;
|
|
|
|
if ((acc_dev->capabilities & GOMP_OFFLOAD_CAP_SHARED_MEM)
|
|
- || host_fallback)
|
|
+ || (flags & GOACC_FLAG_HOST_FALLBACK))
|
|
return;
|
|
|
|
if (num_waits)
|
|
@@ -286,6 +374,17 @@ GOACC_enter_exit_data (int device, size_
|
|
va_end (ap);
|
|
}
|
|
|
|
+ /* Determine whether "finalize" semantics apply to all mappings of this
|
|
+ OpenACC directive. */
|
|
+ bool finalize = false;
|
|
+ if (mapnum > 0)
|
|
+ {
|
|
+ unsigned char kind = kinds[0] & 0xff;
|
|
+ if (kind == GOMP_MAP_DELETE
|
|
+ || kind == GOMP_MAP_FORCE_FROM)
|
|
+ finalize = true;
|
|
+ }
|
|
+
|
|
acc_dev->openacc.async_set_async_func (async);
|
|
|
|
/* Determine if this is an "acc enter data". */
|
|
@@ -298,13 +397,17 @@ GOACC_enter_exit_data (int device, size_
|
|
|
|
if (kind == GOMP_MAP_FORCE_ALLOC
|
|
|| kind == GOMP_MAP_FORCE_PRESENT
|
|
- || kind == GOMP_MAP_FORCE_TO)
|
|
+ || kind == GOMP_MAP_FORCE_TO
|
|
+ || kind == GOMP_MAP_TO
|
|
+ || kind == GOMP_MAP_ALLOC)
|
|
{
|
|
data_enter = true;
|
|
break;
|
|
}
|
|
|
|
- if (kind == GOMP_MAP_DELETE
|
|
+ if (kind == GOMP_MAP_RELEASE
|
|
+ || kind == GOMP_MAP_DELETE
|
|
+ || kind == GOMP_MAP_FROM
|
|
|| kind == GOMP_MAP_FORCE_FROM)
|
|
break;
|
|
|
|
@@ -312,31 +415,35 @@ GOACC_enter_exit_data (int device, size_
|
|
kind);
|
|
}
|
|
|
|
+ /* In c, non-pointers and arrays are represented by a single data clause.
|
|
+ Dynamically allocated arrays and subarrays are represented by a data
|
|
+ clause followed by an internal GOMP_MAP_POINTER.
|
|
+
|
|
+ In fortran, scalars and not allocated arrays are represented by a
|
|
+ single data clause. Allocated arrays and subarrays have three mappings:
|
|
+ 1) the original data clause, 2) a PSET 3) a pointer to the array data.
|
|
+ */
|
|
+
|
|
if (data_enter)
|
|
{
|
|
for (i = 0; i < mapnum; i++)
|
|
{
|
|
unsigned char kind = kinds[i] & 0xff;
|
|
|
|
- /* Scan for PSETs. */
|
|
- int psets = find_pset (i, mapnum, kinds);
|
|
+ /* Scan for pointers and PSETs. */
|
|
+ int pointer = find_pointer (i, mapnum, kinds);
|
|
|
|
- if (!psets)
|
|
+ if (!pointer)
|
|
{
|
|
switch (kind)
|
|
{
|
|
- case GOMP_MAP_POINTER:
|
|
- gomp_acc_insert_pointer (1, &hostaddrs[i], &sizes[i],
|
|
- &kinds[i]);
|
|
- break;
|
|
+ case GOMP_MAP_ALLOC:
|
|
case GOMP_MAP_FORCE_ALLOC:
|
|
acc_create (hostaddrs[i], sizes[i]);
|
|
break;
|
|
- case GOMP_MAP_FORCE_PRESENT:
|
|
- acc_present_or_copyin (hostaddrs[i], sizes[i]);
|
|
- break;
|
|
+ case GOMP_MAP_TO:
|
|
case GOMP_MAP_FORCE_TO:
|
|
- acc_present_or_copyin (hostaddrs[i], sizes[i]);
|
|
+ acc_copyin (hostaddrs[i], sizes[i]);
|
|
break;
|
|
default:
|
|
gomp_fatal (">>>> GOACC_enter_exit_data UNHANDLED kind 0x%.2x",
|
|
@@ -346,12 +453,13 @@ GOACC_enter_exit_data (int device, size_
|
|
}
|
|
else
|
|
{
|
|
- gomp_acc_insert_pointer (3, &hostaddrs[i], &sizes[i], &kinds[i]);
|
|
+ gomp_acc_insert_pointer (pointer, &hostaddrs[i],
|
|
+ &sizes[i], &kinds[i]);
|
|
/* Increment 'i' by two because OpenACC requires fortran
|
|
arrays to be contiguous, so each PSET is associated with
|
|
one of MAP_FORCE_ALLOC/MAP_FORCE_PRESET/MAP_FORCE_TO, and
|
|
one MAP_POINTER. */
|
|
- i += 2;
|
|
+ i += pointer - 1;
|
|
}
|
|
}
|
|
}
|
|
@@ -360,22 +468,28 @@ GOACC_enter_exit_data (int device, size_
|
|
{
|
|
unsigned char kind = kinds[i] & 0xff;
|
|
|
|
- int psets = find_pset (i, mapnum, kinds);
|
|
+ int pointer = find_pointer (i, mapnum, kinds);
|
|
|
|
- if (!psets)
|
|
+ if (!pointer)
|
|
{
|
|
switch (kind)
|
|
{
|
|
- case GOMP_MAP_POINTER:
|
|
- gomp_acc_remove_pointer (hostaddrs[i], (kinds[i] & 0xff)
|
|
- == GOMP_MAP_FORCE_FROM,
|
|
- async, 1);
|
|
- break;
|
|
+ case GOMP_MAP_RELEASE:
|
|
case GOMP_MAP_DELETE:
|
|
- acc_delete (hostaddrs[i], sizes[i]);
|
|
+ if (acc_is_present (hostaddrs[i], sizes[i]))
|
|
+ {
|
|
+ if (finalize)
|
|
+ acc_delete_finalize (hostaddrs[i], sizes[i]);
|
|
+ else
|
|
+ acc_delete (hostaddrs[i], sizes[i]);
|
|
+ }
|
|
break;
|
|
+ case GOMP_MAP_FROM:
|
|
case GOMP_MAP_FORCE_FROM:
|
|
- acc_copyout (hostaddrs[i], sizes[i]);
|
|
+ if (finalize)
|
|
+ acc_copyout_finalize (hostaddrs[i], sizes[i]);
|
|
+ else
|
|
+ acc_copyout (hostaddrs[i], sizes[i]);
|
|
break;
|
|
default:
|
|
gomp_fatal (">>>> GOACC_enter_exit_data UNHANDLED kind 0x%.2x",
|
|
@@ -385,10 +499,12 @@ GOACC_enter_exit_data (int device, size_
|
|
}
|
|
else
|
|
{
|
|
- gomp_acc_remove_pointer (hostaddrs[i], (kinds[i] & 0xff)
|
|
- == GOMP_MAP_FORCE_FROM, async, 3);
|
|
+ bool copyfrom = (kind == GOMP_MAP_FORCE_FROM
|
|
+ || kind == GOMP_MAP_FROM);
|
|
+ gomp_acc_remove_pointer (hostaddrs[i], sizes[i], copyfrom, async,
|
|
+ finalize, pointer);
|
|
/* See the above comment. */
|
|
- i += 2;
|
|
+ i += pointer - 1;
|
|
}
|
|
}
|
|
|
|
@@ -398,13 +514,20 @@ GOACC_enter_exit_data (int device, size_
|
|
static void
|
|
goacc_wait (int async, int num_waits, va_list *ap)
|
|
{
|
|
- struct goacc_thread *thr = goacc_thread ();
|
|
- struct gomp_device_descr *acc_dev = thr->dev;
|
|
-
|
|
while (num_waits--)
|
|
{
|
|
int qid = va_arg (*ap, int);
|
|
-
|
|
+
|
|
+ /* Waiting on ACC_ASYNC_NOVAL maps to 'wait all'. */
|
|
+ if (qid == acc_async_noval)
|
|
+ {
|
|
+ if (async == acc_async_sync)
|
|
+ acc_wait_all ();
|
|
+ else
|
|
+ acc_wait_all_async (async);
|
|
+ break;
|
|
+ }
|
|
+
|
|
if (acc_async_test (qid))
|
|
continue;
|
|
|
|
@@ -415,16 +538,17 @@ goacc_wait (int async, int num_waits, va
|
|
launching on, the queue itself will order work as
|
|
required, so there's no need to wait explicitly. */
|
|
else
|
|
- acc_dev->openacc.async_wait_async_func (qid, async);
|
|
+ acc_wait_async (qid, async);
|
|
}
|
|
}
|
|
|
|
void
|
|
-GOACC_update (int device, size_t mapnum,
|
|
+GOACC_update (int flags_m, size_t mapnum,
|
|
void **hostaddrs, size_t *sizes, unsigned short *kinds,
|
|
int async, int num_waits, ...)
|
|
{
|
|
- bool host_fallback = device == GOMP_DEVICE_HOST_FALLBACK;
|
|
+ int flags = GOACC_FLAGS_UNMARSHAL (flags_m);
|
|
+
|
|
size_t i;
|
|
|
|
goacc_lazy_initialize ();
|
|
@@ -433,7 +557,7 @@ GOACC_update (int device, size_t mapnum,
|
|
struct gomp_device_descr *acc_dev = thr->dev;
|
|
|
|
if ((acc_dev->capabilities & GOMP_OFFLOAD_CAP_SHARED_MEM)
|
|
- || host_fallback)
|
|
+ || (flags & GOACC_FLAG_HOST_FALLBACK))
|
|
return;
|
|
|
|
if (num_waits)
|
|
@@ -447,6 +571,7 @@ GOACC_update (int device, size_t mapnum,
|
|
|
|
acc_dev->openacc.async_set_async_func (async);
|
|
|
|
+ bool update_device = false;
|
|
for (i = 0; i < mapnum; ++i)
|
|
{
|
|
unsigned char kind = kinds[i] & 0xff;
|
|
@@ -457,11 +582,46 @@ GOACC_update (int device, size_t mapnum,
|
|
case GOMP_MAP_TO_PSET:
|
|
break;
|
|
|
|
+ case GOMP_MAP_ALWAYS_POINTER:
|
|
+ if (update_device)
|
|
+ {
|
|
+ /* Save the contents of the host pointer. */
|
|
+ void *dptr = acc_deviceptr (hostaddrs[i-1]);
|
|
+ uintptr_t t = *(uintptr_t *) hostaddrs[i];
|
|
+
|
|
+ /* Update the contents of the host pointer to reflect
|
|
+ the value of the allocated device memory in the
|
|
+ previous pointer. */
|
|
+ *(uintptr_t *) hostaddrs[i] = (uintptr_t)dptr;
|
|
+ acc_update_device (hostaddrs[i], sizeof (uintptr_t));
|
|
+
|
|
+ /* Restore the host pointer. */
|
|
+ *(uintptr_t *) hostaddrs[i] = t;
|
|
+ update_device = false;
|
|
+ }
|
|
+ break;
|
|
+
|
|
+ case GOMP_MAP_TO:
|
|
+ if (!acc_is_present (hostaddrs[i], sizes[i]))
|
|
+ {
|
|
+ update_device = false;
|
|
+ break;
|
|
+ }
|
|
+ /* Fallthru */
|
|
case GOMP_MAP_FORCE_TO:
|
|
+ update_device = true;
|
|
acc_update_device (hostaddrs[i], sizes[i]);
|
|
break;
|
|
|
|
+ case GOMP_MAP_FROM:
|
|
+ if (!acc_is_present (hostaddrs[i], sizes[i]))
|
|
+ {
|
|
+ update_device = false;
|
|
+ break;
|
|
+ }
|
|
+ /* Fallthru */
|
|
case GOMP_MAP_FORCE_FROM:
|
|
+ update_device = false;
|
|
acc_update_self (hostaddrs[i], sizes[i]);
|
|
break;
|
|
|
|
@@ -487,8 +647,8 @@ GOACC_wait (int async, int num_waits, ..
|
|
}
|
|
else if (async == acc_async_sync)
|
|
acc_wait_all ();
|
|
- else if (async == acc_async_noval)
|
|
- goacc_thread ()->dev->openacc.async_wait_all_async_func (acc_async_noval);
|
|
+ else
|
|
+ acc_wait_all_async (async);
|
|
}
|
|
|
|
int
|
|
@@ -504,7 +664,7 @@ GOACC_get_thread_num (void)
|
|
}
|
|
|
|
void
|
|
-GOACC_declare (int device, size_t mapnum,
|
|
+GOACC_declare (int flags_m, size_t mapnum,
|
|
void **hostaddrs, size_t *sizes, unsigned short *kinds)
|
|
{
|
|
int i;
|
|
@@ -522,9 +682,10 @@ GOACC_declare (int device, size_t mapnum
|
|
case GOMP_MAP_FORCE_FROM:
|
|
case GOMP_MAP_FORCE_TO:
|
|
case GOMP_MAP_POINTER:
|
|
+ case GOMP_MAP_RELEASE:
|
|
case GOMP_MAP_DELETE:
|
|
- GOACC_enter_exit_data (device, 1, &hostaddrs[i], &sizes[i],
|
|
- &kinds[i], 0, 0);
|
|
+ GOACC_enter_exit_data (flags_m, 1, &hostaddrs[i], &sizes[i],
|
|
+ &kinds[i], GOMP_ASYNC_SYNC, 0);
|
|
break;
|
|
|
|
case GOMP_MAP_FORCE_DEVICEPTR:
|
|
@@ -532,20 +693,19 @@ GOACC_declare (int device, size_t mapnum
|
|
|
|
case GOMP_MAP_ALLOC:
|
|
if (!acc_is_present (hostaddrs[i], sizes[i]))
|
|
- GOACC_enter_exit_data (device, 1, &hostaddrs[i], &sizes[i],
|
|
- &kinds[i], 0, 0);
|
|
+ GOACC_enter_exit_data (flags_m, 1, &hostaddrs[i], &sizes[i],
|
|
+ &kinds[i], GOMP_ASYNC_SYNC, 0);
|
|
break;
|
|
|
|
case GOMP_MAP_TO:
|
|
- GOACC_enter_exit_data (device, 1, &hostaddrs[i], &sizes[i],
|
|
- &kinds[i], 0, 0);
|
|
+ GOACC_enter_exit_data (flags_m, 1, &hostaddrs[i], &sizes[i],
|
|
+ &kinds[i], GOMP_ASYNC_SYNC, 0);
|
|
|
|
break;
|
|
|
|
case GOMP_MAP_FROM:
|
|
- kinds[i] = GOMP_MAP_FORCE_FROM;
|
|
- GOACC_enter_exit_data (device, 1, &hostaddrs[i], &sizes[i],
|
|
- &kinds[i], 0, 0);
|
|
+ GOACC_enter_exit_data (flags_m, 1, &hostaddrs[i], &sizes[i],
|
|
+ &kinds[i], GOMP_ASYNC_SYNC, 0);
|
|
break;
|
|
|
|
case GOMP_MAP_FORCE_PRESENT:
|
|
--- libgomp/openacc2.f90.jj 2019-05-07 19:54:18.828514375 +0200
|
|
+++ libgomp/openacc2.f90 2019-05-07 19:56:38.454296347 +0200
|
|
@@ -0,0 +1,1502 @@
|
|
+! OpenACC Runtime Library Definitions.
|
|
+
|
|
+! Copyright (C) 2014-2019 Free Software Foundation, Inc.
|
|
+
|
|
+! Contributed by Tobias Burnus <burnus@net-b.de>
|
|
+! and Mentor Embedded.
|
|
+
|
|
+! This file is part of the GNU Offloading and Multi Processing Library
|
|
+! (libgomp).
|
|
+
|
|
+! Libgomp is free software; you can redistribute it and/or modify it
|
|
+! under the terms of the GNU General Public License as published by
|
|
+! the Free Software Foundation; either version 3, or (at your option)
|
|
+! any later version.
|
|
+
|
|
+! Libgomp is distributed in the hope that it will be useful, but WITHOUT ANY
|
|
+! WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
|
+! FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
|
+! more details.
|
|
+
|
|
+! Under Section 7 of GPL version 3, you are granted additional
|
|
+! permissions described in the GCC Runtime Library Exception, version
|
|
+! 3.1, as published by the Free Software Foundation.
|
|
+
|
|
+! You should have received a copy of the GNU General Public License and
|
|
+! a copy of the GCC Runtime Library Exception along with this program;
|
|
+! see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
|
|
+! <http://www.gnu.org/licenses/>.
|
|
+
|
|
+module openacc_kinds2
|
|
+ use iso_fortran_env, only: int32
|
|
+ implicit none
|
|
+
|
|
+ private :: int32
|
|
+ public :: acc_device_kind
|
|
+
|
|
+ integer, parameter :: acc_device_kind = int32
|
|
+
|
|
+ public :: acc_device_none, acc_device_default, acc_device_host
|
|
+ public :: acc_device_not_host, acc_device_nvidia
|
|
+
|
|
+ ! Keep in sync with include/gomp-constants.h.
|
|
+ integer (acc_device_kind), parameter :: acc_device_none = 0
|
|
+ integer (acc_device_kind), parameter :: acc_device_default = 1
|
|
+ integer (acc_device_kind), parameter :: acc_device_host = 2
|
|
+ ! integer (acc_device_kind), parameter :: acc_device_host_nonshm = 3 removed.
|
|
+ integer (acc_device_kind), parameter :: acc_device_not_host = 4
|
|
+ integer (acc_device_kind), parameter :: acc_device_nvidia = 5
|
|
+
|
|
+ public :: acc_handle_kind
|
|
+
|
|
+ integer, parameter :: acc_handle_kind = int32
|
|
+
|
|
+ public :: acc_async_noval, acc_async_sync
|
|
+
|
|
+ ! Keep in sync with include/gomp-constants.h.
|
|
+ integer (acc_handle_kind), parameter :: acc_async_noval = -1
|
|
+ integer (acc_handle_kind), parameter :: acc_async_sync = -2
|
|
+
|
|
+end module
|
|
+
|
|
+module openacc_internal2
|
|
+ use openacc_kinds2
|
|
+ implicit none
|
|
+
|
|
+ interface
|
|
+ function acc_get_num_devices_h (d)
|
|
+ import
|
|
+ integer acc_get_num_devices_h
|
|
+ integer (acc_device_kind) d
|
|
+ end function
|
|
+
|
|
+ subroutine acc_set_device_type_h (d)
|
|
+ import
|
|
+ integer (acc_device_kind) d
|
|
+ end subroutine
|
|
+
|
|
+ function acc_get_device_type_h ()
|
|
+ import
|
|
+ integer (acc_device_kind) acc_get_device_type_h
|
|
+ end function
|
|
+
|
|
+ subroutine acc_set_device_num_h (n, d)
|
|
+ import
|
|
+ integer n
|
|
+ integer (acc_device_kind) d
|
|
+ end subroutine
|
|
+
|
|
+ function acc_get_device_num_h (d)
|
|
+ import
|
|
+ integer acc_get_device_num_h
|
|
+ integer (acc_device_kind) d
|
|
+ end function
|
|
+
|
|
+ function acc_async_test_h (a)
|
|
+ logical acc_async_test_h
|
|
+ integer a
|
|
+ end function
|
|
+
|
|
+ function acc_async_test_all_h ()
|
|
+ logical acc_async_test_all_h
|
|
+ end function
|
|
+
|
|
+ subroutine acc_wait_h (a)
|
|
+ integer a
|
|
+ end subroutine
|
|
+
|
|
+ subroutine acc_wait_async_h (a1, a2)
|
|
+ integer a1, a2
|
|
+ end subroutine
|
|
+
|
|
+ subroutine acc_wait_all_h ()
|
|
+ end subroutine
|
|
+
|
|
+ subroutine acc_wait_all_async_h (a)
|
|
+ integer a
|
|
+ end subroutine
|
|
+
|
|
+ subroutine acc_init_h (d)
|
|
+ import
|
|
+ integer (acc_device_kind) d
|
|
+ end subroutine
|
|
+
|
|
+ subroutine acc_shutdown_h (d)
|
|
+ import
|
|
+ integer (acc_device_kind) d
|
|
+ end subroutine
|
|
+
|
|
+ function acc_on_device_h (d)
|
|
+ import
|
|
+ integer (acc_device_kind) d
|
|
+ logical acc_on_device_h
|
|
+ end function
|
|
+
|
|
+ subroutine acc_copyin_32_h (a, len)
|
|
+ use iso_c_binding, only: c_int32_t
|
|
+ !GCC$ ATTRIBUTES NO_ARG_CHECK :: a
|
|
+ type (*), dimension (*) :: a
|
|
+ integer (c_int32_t) len
|
|
+ end subroutine
|
|
+
|
|
+ subroutine acc_copyin_64_h (a, len)
|
|
+ use iso_c_binding, only: c_int64_t
|
|
+ !GCC$ ATTRIBUTES NO_ARG_CHECK :: a
|
|
+ type (*), dimension (*) :: a
|
|
+ integer (c_int64_t) len
|
|
+ end subroutine
|
|
+
|
|
+ subroutine acc_copyin_array_h (a)
|
|
+ type (*), dimension (..), contiguous :: a
|
|
+ end subroutine
|
|
+
|
|
+ subroutine acc_present_or_copyin_32_h (a, len)
|
|
+ use iso_c_binding, only: c_int32_t
|
|
+ !GCC$ ATTRIBUTES NO_ARG_CHECK :: a
|
|
+ type (*), dimension (*) :: a
|
|
+ integer (c_int32_t) len
|
|
+ end subroutine
|
|
+
|
|
+ subroutine acc_present_or_copyin_64_h (a, len)
|
|
+ use iso_c_binding, only: c_int64_t
|
|
+ !GCC$ ATTRIBUTES NO_ARG_CHECK :: a
|
|
+ type (*), dimension (*) :: a
|
|
+ integer (c_int64_t) len
|
|
+ end subroutine
|
|
+
|
|
+ subroutine acc_present_or_copyin_array_h (a)
|
|
+ type (*), dimension (..), contiguous :: a
|
|
+ end subroutine
|
|
+
|
|
+ subroutine acc_create_32_h (a, len)
|
|
+ use iso_c_binding, only: c_int32_t
|
|
+ !GCC$ ATTRIBUTES NO_ARG_CHECK :: a
|
|
+ type (*), dimension (*) :: a
|
|
+ integer (c_int32_t) len
|
|
+ end subroutine
|
|
+
|
|
+ subroutine acc_create_64_h (a, len)
|
|
+ use iso_c_binding, only: c_int64_t
|
|
+ !GCC$ ATTRIBUTES NO_ARG_CHECK :: a
|
|
+ type (*), dimension (*) :: a
|
|
+ integer (c_int64_t) len
|
|
+ end subroutine
|
|
+
|
|
+ subroutine acc_create_array_h (a)
|
|
+ type (*), dimension (..), contiguous :: a
|
|
+ end subroutine
|
|
+
|
|
+ subroutine acc_present_or_create_32_h (a, len)
|
|
+ use iso_c_binding, only: c_int32_t
|
|
+ !GCC$ ATTRIBUTES NO_ARG_CHECK :: a
|
|
+ type (*), dimension (*) :: a
|
|
+ integer (c_int32_t) len
|
|
+ end subroutine
|
|
+
|
|
+ subroutine acc_present_or_create_64_h (a, len)
|
|
+ use iso_c_binding, only: c_int64_t
|
|
+ !GCC$ ATTRIBUTES NO_ARG_CHECK :: a
|
|
+ type (*), dimension (*) :: a
|
|
+ integer (c_int64_t) len
|
|
+ end subroutine
|
|
+
|
|
+ subroutine acc_present_or_create_array_h (a)
|
|
+ type (*), dimension (..), contiguous :: a
|
|
+ end subroutine
|
|
+
|
|
+ subroutine acc_copyout_32_h (a, len)
|
|
+ use iso_c_binding, only: c_int32_t
|
|
+ !GCC$ ATTRIBUTES NO_ARG_CHECK :: a
|
|
+ type (*), dimension (*) :: a
|
|
+ integer (c_int32_t) len
|
|
+ end subroutine
|
|
+
|
|
+ subroutine acc_copyout_64_h (a, len)
|
|
+ use iso_c_binding, only: c_int64_t
|
|
+ !GCC$ ATTRIBUTES NO_ARG_CHECK :: a
|
|
+ type (*), dimension (*) :: a
|
|
+ integer (c_int64_t) len
|
|
+ end subroutine
|
|
+
|
|
+ subroutine acc_copyout_array_h (a)
|
|
+ type (*), dimension (..), contiguous :: a
|
|
+ end subroutine
|
|
+
|
|
+ subroutine acc_copyout_finalize_32_h (a, len)
|
|
+ use iso_c_binding, only: c_int32_t
|
|
+ !GCC$ ATTRIBUTES NO_ARG_CHECK :: a
|
|
+ type (*), dimension (*) :: a
|
|
+ integer (c_int32_t) len
|
|
+ end subroutine
|
|
+
|
|
+ subroutine acc_copyout_finalize_64_h (a, len)
|
|
+ use iso_c_binding, only: c_int64_t
|
|
+ !GCC$ ATTRIBUTES NO_ARG_CHECK :: a
|
|
+ type (*), dimension (*) :: a
|
|
+ integer (c_int64_t) len
|
|
+ end subroutine
|
|
+
|
|
+ subroutine acc_copyout_finalize_array_h (a)
|
|
+ type (*), dimension (..), contiguous :: a
|
|
+ end subroutine
|
|
+
|
|
+ subroutine acc_delete_32_h (a, len)
|
|
+ use iso_c_binding, only: c_int32_t
|
|
+ !GCC$ ATTRIBUTES NO_ARG_CHECK :: a
|
|
+ type (*), dimension (*) :: a
|
|
+ integer (c_int32_t) len
|
|
+ end subroutine
|
|
+
|
|
+ subroutine acc_delete_64_h (a, len)
|
|
+ use iso_c_binding, only: c_int64_t
|
|
+ !GCC$ ATTRIBUTES NO_ARG_CHECK :: a
|
|
+ type (*), dimension (*) :: a
|
|
+ integer (c_int64_t) len
|
|
+ end subroutine
|
|
+
|
|
+ subroutine acc_delete_array_h (a)
|
|
+ type (*), dimension (..), contiguous :: a
|
|
+ end subroutine
|
|
+
|
|
+ subroutine acc_delete_finalize_32_h (a, len)
|
|
+ use iso_c_binding, only: c_int32_t
|
|
+ !GCC$ ATTRIBUTES NO_ARG_CHECK :: a
|
|
+ type (*), dimension (*) :: a
|
|
+ integer (c_int32_t) len
|
|
+ end subroutine
|
|
+
|
|
+ subroutine acc_delete_finalize_64_h (a, len)
|
|
+ use iso_c_binding, only: c_int64_t
|
|
+ !GCC$ ATTRIBUTES NO_ARG_CHECK :: a
|
|
+ type (*), dimension (*) :: a
|
|
+ integer (c_int64_t) len
|
|
+ end subroutine
|
|
+
|
|
+ subroutine acc_delete_finalize_array_h (a)
|
|
+ type (*), dimension (..), contiguous :: a
|
|
+ end subroutine
|
|
+
|
|
+ subroutine acc_update_device_32_h (a, len)
|
|
+ use iso_c_binding, only: c_int32_t
|
|
+ !GCC$ ATTRIBUTES NO_ARG_CHECK :: a
|
|
+ type (*), dimension (*) :: a
|
|
+ integer (c_int32_t) len
|
|
+ end subroutine
|
|
+
|
|
+ subroutine acc_update_device_64_h (a, len)
|
|
+ use iso_c_binding, only: c_int64_t
|
|
+ !GCC$ ATTRIBUTES NO_ARG_CHECK :: a
|
|
+ type (*), dimension (*) :: a
|
|
+ integer (c_int64_t) len
|
|
+ end subroutine
|
|
+
|
|
+ subroutine acc_update_device_array_h (a)
|
|
+ type (*), dimension (..), contiguous :: a
|
|
+ end subroutine
|
|
+
|
|
+ subroutine acc_update_self_32_h (a, len)
|
|
+ use iso_c_binding, only: c_int32_t
|
|
+ !GCC$ ATTRIBUTES NO_ARG_CHECK :: a
|
|
+ type (*), dimension (*) :: a
|
|
+ integer (c_int32_t) len
|
|
+ end subroutine
|
|
+
|
|
+ subroutine acc_update_self_64_h (a, len)
|
|
+ use iso_c_binding, only: c_int64_t
|
|
+ !GCC$ ATTRIBUTES NO_ARG_CHECK :: a
|
|
+ type (*), dimension (*) :: a
|
|
+ integer (c_int64_t) len
|
|
+ end subroutine
|
|
+
|
|
+ subroutine acc_update_self_array_h (a)
|
|
+ type (*), dimension (..), contiguous :: a
|
|
+ end subroutine
|
|
+
|
|
+ function acc_is_present_32_h (a, len)
|
|
+ use iso_c_binding, only: c_int32_t
|
|
+ logical acc_is_present_32_h
|
|
+ !GCC$ ATTRIBUTES NO_ARG_CHECK :: a
|
|
+ type (*), dimension (*) :: a
|
|
+ integer (c_int32_t) len
|
|
+ end function
|
|
+
|
|
+ function acc_is_present_64_h (a, len)
|
|
+ use iso_c_binding, only: c_int64_t
|
|
+ logical acc_is_present_64_h
|
|
+ !GCC$ ATTRIBUTES NO_ARG_CHECK :: a
|
|
+ type (*), dimension (*) :: a
|
|
+ integer (c_int64_t) len
|
|
+ end function
|
|
+
|
|
+ function acc_is_present_array_h (a)
|
|
+ logical acc_is_present_array_h
|
|
+ type (*), dimension (..), contiguous :: a
|
|
+ end function
|
|
+
|
|
+ subroutine acc_copyin_async_32_h (a, len, async)
|
|
+ use iso_c_binding, only: c_int32_t
|
|
+ use openacc_kinds2, only: acc_handle_kind
|
|
+ !GCC$ ATTRIBUTES NO_ARG_CHECK :: a
|
|
+ type (*), dimension (*) :: a
|
|
+ integer (c_int32_t) len
|
|
+ integer (acc_handle_kind) async
|
|
+ end subroutine
|
|
+
|
|
+ subroutine acc_copyin_async_64_h (a, len, async)
|
|
+ use iso_c_binding, only: c_int64_t
|
|
+ use openacc_kinds2, only: acc_handle_kind
|
|
+ !GCC$ ATTRIBUTES NO_ARG_CHECK :: a
|
|
+ type (*), dimension (*) :: a
|
|
+ integer (c_int64_t) len
|
|
+ integer (acc_handle_kind) async
|
|
+ end subroutine
|
|
+
|
|
+ subroutine acc_copyin_async_array_h (a, async)
|
|
+ use openacc_kinds2, only: acc_handle_kind
|
|
+ type (*), dimension (..), contiguous :: a
|
|
+ integer (acc_handle_kind) async
|
|
+ end subroutine
|
|
+
|
|
+ subroutine acc_create_async_32_h (a, len, async)
|
|
+ use iso_c_binding, only: c_int32_t
|
|
+ use openacc_kinds2, only: acc_handle_kind
|
|
+ !GCC$ ATTRIBUTES NO_ARG_CHECK :: a
|
|
+ type (*), dimension (*) :: a
|
|
+ integer (c_int32_t) len
|
|
+ integer (acc_handle_kind) async
|
|
+ end subroutine
|
|
+
|
|
+ subroutine acc_create_async_64_h (a, len, async)
|
|
+ use iso_c_binding, only: c_int64_t
|
|
+ use openacc_kinds2, only: acc_handle_kind
|
|
+ !GCC$ ATTRIBUTES NO_ARG_CHECK :: a
|
|
+ type (*), dimension (*) :: a
|
|
+ integer (c_int64_t) len
|
|
+ integer (acc_handle_kind) async
|
|
+ end subroutine
|
|
+
|
|
+ subroutine acc_create_async_array_h (a, async)
|
|
+ use openacc_kinds2, only: acc_handle_kind
|
|
+ type (*), dimension (..), contiguous :: a
|
|
+ integer (acc_handle_kind) async
|
|
+ end subroutine
|
|
+
|
|
+ subroutine acc_copyout_async_32_h (a, len, async)
|
|
+ use iso_c_binding, only: c_int32_t
|
|
+ use openacc_kinds2, only: acc_handle_kind
|
|
+ !GCC$ ATTRIBUTES NO_ARG_CHECK :: a
|
|
+ type (*), dimension (*) :: a
|
|
+ integer (c_int32_t) len
|
|
+ integer (acc_handle_kind) async
|
|
+ end subroutine
|
|
+
|
|
+ subroutine acc_copyout_async_64_h (a, len, async)
|
|
+ use iso_c_binding, only: c_int64_t
|
|
+ use openacc_kinds2, only: acc_handle_kind
|
|
+ !GCC$ ATTRIBUTES NO_ARG_CHECK :: a
|
|
+ type (*), dimension (*) :: a
|
|
+ integer (c_int64_t) len
|
|
+ integer (acc_handle_kind) async
|
|
+ end subroutine
|
|
+
|
|
+ subroutine acc_copyout_async_array_h (a, async)
|
|
+ use openacc_kinds2, only: acc_handle_kind
|
|
+ type (*), dimension (..), contiguous :: a
|
|
+ integer (acc_handle_kind) async
|
|
+ end subroutine
|
|
+
|
|
+ subroutine acc_delete_async_32_h (a, len, async)
|
|
+ use iso_c_binding, only: c_int32_t
|
|
+ use openacc_kinds2, only: acc_handle_kind
|
|
+ !GCC$ ATTRIBUTES NO_ARG_CHECK :: a
|
|
+ type (*), dimension (*) :: a
|
|
+ integer (c_int32_t) len
|
|
+ integer (acc_handle_kind) async
|
|
+ end subroutine
|
|
+
|
|
+ subroutine acc_delete_async_64_h (a, len, async)
|
|
+ use iso_c_binding, only: c_int64_t
|
|
+ use openacc_kinds2, only: acc_handle_kind
|
|
+ !GCC$ ATTRIBUTES NO_ARG_CHECK :: a
|
|
+ type (*), dimension (*) :: a
|
|
+ integer (c_int64_t) len
|
|
+ integer (acc_handle_kind) async
|
|
+ end subroutine
|
|
+
|
|
+ subroutine acc_delete_async_array_h (a, async)
|
|
+ use openacc_kinds2, only: acc_handle_kind
|
|
+ type (*), dimension (..), contiguous :: a
|
|
+ integer (acc_handle_kind) async
|
|
+ end subroutine
|
|
+
|
|
+ subroutine acc_update_device_async_32_h (a, len, async)
|
|
+ use iso_c_binding, only: c_int32_t
|
|
+ use openacc_kinds2, only: acc_handle_kind
|
|
+ !GCC$ ATTRIBUTES NO_ARG_CHECK :: a
|
|
+ type (*), dimension (*) :: a
|
|
+ integer (c_int32_t) len
|
|
+ integer (acc_handle_kind) async
|
|
+ end subroutine
|
|
+
|
|
+ subroutine acc_update_device_async_64_h (a, len, async)
|
|
+ use iso_c_binding, only: c_int64_t
|
|
+ use openacc_kinds2, only: acc_handle_kind
|
|
+ !GCC$ ATTRIBUTES NO_ARG_CHECK :: a
|
|
+ type (*), dimension (*) :: a
|
|
+ integer (c_int64_t) len
|
|
+ integer (acc_handle_kind) async
|
|
+ end subroutine
|
|
+
|
|
+ subroutine acc_update_device_async_array_h (a, async)
|
|
+ use openacc_kinds2, only: acc_handle_kind
|
|
+ type (*), dimension (..), contiguous :: a
|
|
+ integer (acc_handle_kind) async
|
|
+ end subroutine
|
|
+
|
|
+ subroutine acc_update_self_async_32_h (a, len, async)
|
|
+ use iso_c_binding, only: c_int32_t
|
|
+ use openacc_kinds2, only: acc_handle_kind
|
|
+ !GCC$ ATTRIBUTES NO_ARG_CHECK :: a
|
|
+ type (*), dimension (*) :: a
|
|
+ integer (c_int32_t) len
|
|
+ integer (acc_handle_kind) async
|
|
+ end subroutine
|
|
+
|
|
+ subroutine acc_update_self_async_64_h (a, len, async)
|
|
+ use iso_c_binding, only: c_int64_t
|
|
+ use openacc_kinds2, only: acc_handle_kind
|
|
+ !GCC$ ATTRIBUTES NO_ARG_CHECK :: a
|
|
+ type (*), dimension (*) :: a
|
|
+ integer (c_int64_t) len
|
|
+ integer (acc_handle_kind) async
|
|
+ end subroutine
|
|
+
|
|
+ subroutine acc_update_self_async_array_h (a, async)
|
|
+ use openacc_kinds2, only: acc_handle_kind
|
|
+ type (*), dimension (..), contiguous :: a
|
|
+ integer (acc_handle_kind) async
|
|
+ end subroutine
|
|
+ end interface
|
|
+
|
|
+ interface
|
|
+ function acc_get_num_devices_l (d) &
|
|
+ bind (C, name = "acc_get_num_devices")
|
|
+ use iso_c_binding, only: c_int
|
|
+ integer (c_int) :: acc_get_num_devices_l
|
|
+ integer (c_int), value :: d
|
|
+ end function
|
|
+
|
|
+ subroutine acc_set_device_type_l (d) &
|
|
+ bind (C, name = "acc_set_device_type")
|
|
+ use iso_c_binding, only: c_int
|
|
+ integer (c_int), value :: d
|
|
+ end subroutine
|
|
+
|
|
+ function acc_get_device_type_l () &
|
|
+ bind (C, name = "acc_get_device_type")
|
|
+ use iso_c_binding, only: c_int
|
|
+ integer (c_int) :: acc_get_device_type_l
|
|
+ end function
|
|
+
|
|
+ subroutine acc_set_device_num_l (n, d) &
|
|
+ bind (C, name = "acc_set_device_num")
|
|
+ use iso_c_binding, only: c_int
|
|
+ integer (c_int), value :: n, d
|
|
+ end subroutine
|
|
+
|
|
+ function acc_get_device_num_l (d) &
|
|
+ bind (C, name = "acc_get_device_num")
|
|
+ use iso_c_binding, only: c_int
|
|
+ integer (c_int) :: acc_get_device_num_l
|
|
+ integer (c_int), value :: d
|
|
+ end function
|
|
+
|
|
+ function acc_async_test_l (a) &
|
|
+ bind (C, name = "acc_async_test")
|
|
+ use iso_c_binding, only: c_int
|
|
+ integer (c_int) :: acc_async_test_l
|
|
+ integer (c_int), value :: a
|
|
+ end function
|
|
+
|
|
+ function acc_async_test_all_l () &
|
|
+ bind (C, name = "acc_async_test_all")
|
|
+ use iso_c_binding, only: c_int
|
|
+ integer (c_int) :: acc_async_test_all_l
|
|
+ end function
|
|
+
|
|
+ subroutine acc_wait_l (a) &
|
|
+ bind (C, name = "acc_wait")
|
|
+ use iso_c_binding, only: c_int
|
|
+ integer (c_int), value :: a
|
|
+ end subroutine
|
|
+
|
|
+ subroutine acc_wait_async_l (a1, a2) &
|
|
+ bind (C, name = "acc_wait_async")
|
|
+ use iso_c_binding, only: c_int
|
|
+ integer (c_int), value :: a1, a2
|
|
+ end subroutine
|
|
+
|
|
+ subroutine acc_wait_all_l () &
|
|
+ bind (C, name = "acc_wait_all")
|
|
+ use iso_c_binding, only: c_int
|
|
+ end subroutine
|
|
+
|
|
+ subroutine acc_wait_all_async_l (a) &
|
|
+ bind (C, name = "acc_wait_all_async")
|
|
+ use iso_c_binding, only: c_int
|
|
+ integer (c_int), value :: a
|
|
+ end subroutine
|
|
+
|
|
+ subroutine acc_init_l (d) &
|
|
+ bind (C, name = "acc_init")
|
|
+ use iso_c_binding, only: c_int
|
|
+ integer (c_int), value :: d
|
|
+ end subroutine
|
|
+
|
|
+ subroutine acc_shutdown_l (d) &
|
|
+ bind (C, name = "acc_shutdown")
|
|
+ use iso_c_binding, only: c_int
|
|
+ integer (c_int), value :: d
|
|
+ end subroutine
|
|
+
|
|
+ function acc_on_device_l (d) &
|
|
+ bind (C, name = "acc_on_device")
|
|
+ use iso_c_binding, only: c_int
|
|
+ integer (c_int) :: acc_on_device_l
|
|
+ integer (c_int), value :: d
|
|
+ end function
|
|
+
|
|
+ subroutine acc_copyin_l (a, len) &
|
|
+ bind (C, name = "acc_copyin")
|
|
+ use iso_c_binding, only: c_size_t
|
|
+ !GCC$ ATTRIBUTES NO_ARG_CHECK :: a
|
|
+ type (*), dimension (*) :: a
|
|
+ integer (c_size_t), value :: len
|
|
+ end subroutine
|
|
+
|
|
+ subroutine acc_present_or_copyin_l (a, len) &
|
|
+ bind (C, name = "acc_present_or_copyin")
|
|
+ use iso_c_binding, only: c_size_t
|
|
+ !GCC$ ATTRIBUTES NO_ARG_CHECK :: a
|
|
+ type (*), dimension (*) :: a
|
|
+ integer (c_size_t), value :: len
|
|
+ end subroutine
|
|
+
|
|
+ subroutine acc_create_l (a, len) &
|
|
+ bind (C, name = "acc_create")
|
|
+ use iso_c_binding, only: c_size_t
|
|
+ !GCC$ ATTRIBUTES NO_ARG_CHECK :: a
|
|
+ type (*), dimension (*) :: a
|
|
+ integer (c_size_t), value :: len
|
|
+ end subroutine
|
|
+
|
|
+ subroutine acc_present_or_create_l (a, len) &
|
|
+ bind (C, name = "acc_present_or_create")
|
|
+ use iso_c_binding, only: c_size_t
|
|
+ !GCC$ ATTRIBUTES NO_ARG_CHECK :: a
|
|
+ type (*), dimension (*) :: a
|
|
+ integer (c_size_t), value :: len
|
|
+ end subroutine
|
|
+
|
|
+ subroutine acc_copyout_l (a, len) &
|
|
+ bind (C, name = "acc_copyout")
|
|
+ use iso_c_binding, only: c_size_t
|
|
+ !GCC$ ATTRIBUTES NO_ARG_CHECK :: a
|
|
+ type (*), dimension (*) :: a
|
|
+ integer (c_size_t), value :: len
|
|
+ end subroutine
|
|
+
|
|
+ subroutine acc_copyout_finalize_l (a, len) &
|
|
+ bind (C, name = "acc_copyout_finalize")
|
|
+ use iso_c_binding, only: c_size_t
|
|
+ !GCC$ ATTRIBUTES NO_ARG_CHECK :: a
|
|
+ type (*), dimension (*) :: a
|
|
+ integer (c_size_t), value :: len
|
|
+ end subroutine
|
|
+
|
|
+ subroutine acc_delete_l (a, len) &
|
|
+ bind (C, name = "acc_delete")
|
|
+ use iso_c_binding, only: c_size_t
|
|
+ !GCC$ ATTRIBUTES NO_ARG_CHECK :: a
|
|
+ type (*), dimension (*) :: a
|
|
+ integer (c_size_t), value :: len
|
|
+ end subroutine
|
|
+
|
|
+ subroutine acc_delete_finalize_l (a, len) &
|
|
+ bind (C, name = "acc_delete_finalize")
|
|
+ use iso_c_binding, only: c_size_t
|
|
+ !GCC$ ATTRIBUTES NO_ARG_CHECK :: a
|
|
+ type (*), dimension (*) :: a
|
|
+ integer (c_size_t), value :: len
|
|
+ end subroutine
|
|
+
|
|
+ subroutine acc_update_device_l (a, len) &
|
|
+ bind (C, name = "acc_update_device")
|
|
+ use iso_c_binding, only: c_size_t
|
|
+ !GCC$ ATTRIBUTES NO_ARG_CHECK :: a
|
|
+ type (*), dimension (*) :: a
|
|
+ integer (c_size_t), value :: len
|
|
+ end subroutine
|
|
+
|
|
+ subroutine acc_update_self_l (a, len) &
|
|
+ bind (C, name = "acc_update_self")
|
|
+ use iso_c_binding, only: c_size_t
|
|
+ !GCC$ ATTRIBUTES NO_ARG_CHECK :: a
|
|
+ type (*), dimension (*) :: a
|
|
+ integer (c_size_t), value :: len
|
|
+ end subroutine
|
|
+
|
|
+ function acc_is_present_l (a, len) &
|
|
+ bind (C, name = "acc_is_present")
|
|
+ use iso_c_binding, only: c_int32_t, c_size_t
|
|
+ !GCC$ ATTRIBUTES NO_ARG_CHECK :: a
|
|
+ integer (c_int32_t) :: acc_is_present_l
|
|
+ type (*), dimension (*) :: a
|
|
+ integer (c_size_t), value :: len
|
|
+ end function
|
|
+
|
|
+ subroutine acc_copyin_async_l (a, len, async) &
|
|
+ bind (C, name = "acc_copyin_async")
|
|
+ use iso_c_binding, only: c_size_t, c_int
|
|
+ !GCC$ ATTRIBUTES NO_ARG_CHECK :: a
|
|
+ type (*), dimension (*) :: a
|
|
+ integer (c_size_t), value :: len
|
|
+ integer (c_int), value :: async
|
|
+ end subroutine
|
|
+
|
|
+ subroutine acc_create_async_l (a, len, async) &
|
|
+ bind (C, name = "acc_create_async")
|
|
+ use iso_c_binding, only: c_size_t, c_int
|
|
+ !GCC$ ATTRIBUTES NO_ARG_CHECK :: a
|
|
+ type (*), dimension (*) :: a
|
|
+ integer (c_size_t), value :: len
|
|
+ integer (c_int), value :: async
|
|
+ end subroutine
|
|
+
|
|
+ subroutine acc_copyout_async_l (a, len, async) &
|
|
+ bind (C, name = "acc_copyout_async")
|
|
+ use iso_c_binding, only: c_size_t, c_int
|
|
+ !GCC$ ATTRIBUTES NO_ARG_CHECK :: a
|
|
+ type (*), dimension (*) :: a
|
|
+ integer (c_size_t), value :: len
|
|
+ integer (c_int), value :: async
|
|
+ end subroutine
|
|
+
|
|
+ subroutine acc_delete_async_l (a, len, async) &
|
|
+ bind (C, name = "acc_delete_async")
|
|
+ use iso_c_binding, only: c_size_t, c_int
|
|
+ !GCC$ ATTRIBUTES NO_ARG_CHECK :: a
|
|
+ type (*), dimension (*) :: a
|
|
+ integer (c_size_t), value :: len
|
|
+ integer (c_int), value :: async
|
|
+ end subroutine
|
|
+
|
|
+ subroutine acc_update_device_async_l (a, len, async) &
|
|
+ bind (C, name = "acc_update_device_async")
|
|
+ use iso_c_binding, only: c_size_t, c_int
|
|
+ !GCC$ ATTRIBUTES NO_ARG_CHECK :: a
|
|
+ type (*), dimension (*) :: a
|
|
+ integer (c_size_t), value :: len
|
|
+ integer (c_int), value :: async
|
|
+ end subroutine
|
|
+
|
|
+ subroutine acc_update_self_async_l (a, len, async) &
|
|
+ bind (C, name = "acc_update_self_async")
|
|
+ use iso_c_binding, only: c_size_t, c_int
|
|
+ !GCC$ ATTRIBUTES NO_ARG_CHECK :: a
|
|
+ type (*), dimension (*) :: a
|
|
+ integer (c_size_t), value :: len
|
|
+ integer (c_int), value :: async
|
|
+ end subroutine
|
|
+ end interface
|
|
+end module
|
|
+
|
|
+module openacc2
|
|
+ use openacc_kinds2
|
|
+ use openacc_internal2
|
|
+ implicit none
|
|
+
|
|
+ public :: openacc_version
|
|
+
|
|
+ public :: acc_get_num_devices, acc_set_device_type, acc_get_device_type
|
|
+ public :: acc_set_device_num, acc_get_device_num, acc_async_test
|
|
+ public :: acc_async_test_all
|
|
+ public :: acc_wait, acc_async_wait, acc_wait_async
|
|
+ public :: acc_wait_all, acc_async_wait_all, acc_wait_all_async
|
|
+ public :: acc_init, acc_shutdown, acc_on_device
|
|
+ public :: acc_copyin, acc_present_or_copyin, acc_pcopyin, acc_create
|
|
+ public :: acc_present_or_create, acc_pcreate, acc_copyout, acc_delete
|
|
+ public :: acc_update_device, acc_update_self, acc_is_present
|
|
+ public :: acc_copyin_async, acc_create_async, acc_copyout_async
|
|
+ public :: acc_delete_async, acc_update_device_async, acc_update_self_async
|
|
+
|
|
+ integer, parameter :: openacc_version = 201306
|
|
+
|
|
+ interface acc_get_num_devices
|
|
+ procedure :: acc_get_num_devices_h
|
|
+ end interface
|
|
+
|
|
+ interface acc_set_device_type
|
|
+ procedure :: acc_set_device_type_h
|
|
+ end interface
|
|
+
|
|
+ interface acc_get_device_type
|
|
+ procedure :: acc_get_device_type_h
|
|
+ end interface
|
|
+
|
|
+ interface acc_set_device_num
|
|
+ procedure :: acc_set_device_num_h
|
|
+ end interface
|
|
+
|
|
+ interface acc_get_device_num
|
|
+ procedure :: acc_get_device_num_h
|
|
+ end interface
|
|
+
|
|
+ interface acc_async_test
|
|
+ procedure :: acc_async_test_h
|
|
+ end interface
|
|
+
|
|
+ interface acc_async_test_all
|
|
+ procedure :: acc_async_test_all_h
|
|
+ end interface
|
|
+
|
|
+ interface acc_wait
|
|
+ procedure :: acc_wait_h
|
|
+ end interface
|
|
+
|
|
+ ! acc_async_wait is an OpenACC 1.0 compatibility name for acc_wait.
|
|
+ interface acc_async_wait
|
|
+ procedure :: acc_wait_h
|
|
+ end interface
|
|
+
|
|
+ interface acc_wait_async
|
|
+ procedure :: acc_wait_async_h
|
|
+ end interface
|
|
+
|
|
+ interface acc_wait_all
|
|
+ procedure :: acc_wait_all_h
|
|
+ end interface
|
|
+
|
|
+ ! acc_async_wait_all is an OpenACC 1.0 compatibility name for acc_wait_all.
|
|
+ interface acc_async_wait_all
|
|
+ procedure :: acc_wait_all_h
|
|
+ end interface
|
|
+
|
|
+ interface acc_wait_all_async
|
|
+ procedure :: acc_wait_all_async_h
|
|
+ end interface
|
|
+
|
|
+ interface acc_init
|
|
+ procedure :: acc_init_h
|
|
+ end interface
|
|
+
|
|
+ interface acc_shutdown
|
|
+ procedure :: acc_shutdown_h
|
|
+ end interface
|
|
+
|
|
+ interface acc_on_device
|
|
+ procedure :: acc_on_device_h
|
|
+ end interface
|
|
+
|
|
+ ! acc_malloc: Only available in C/C++
|
|
+ ! acc_free: Only available in C/C++
|
|
+
|
|
+ ! As vendor extension, the following code supports both 32bit and 64bit
|
|
+ ! arguments for "size"; the OpenACC standard only permits default-kind
|
|
+ ! integers, which are of kind 4 (i.e. 32 bits).
|
|
+ ! Additionally, the two-argument version also takes arrays as argument.
|
|
+ ! and the one argument version also scalars. Note that the code assumes
|
|
+ ! that the arrays are contiguous.
|
|
+
|
|
+ interface acc_copyin
|
|
+ procedure :: acc_copyin_32_h
|
|
+ procedure :: acc_copyin_64_h
|
|
+ procedure :: acc_copyin_array_h
|
|
+ end interface
|
|
+
|
|
+ interface acc_present_or_copyin
|
|
+ procedure :: acc_present_or_copyin_32_h
|
|
+ procedure :: acc_present_or_copyin_64_h
|
|
+ procedure :: acc_present_or_copyin_array_h
|
|
+ end interface
|
|
+
|
|
+ interface acc_pcopyin
|
|
+ procedure :: acc_present_or_copyin_32_h
|
|
+ procedure :: acc_present_or_copyin_64_h
|
|
+ procedure :: acc_present_or_copyin_array_h
|
|
+ end interface
|
|
+
|
|
+ interface acc_create
|
|
+ procedure :: acc_create_32_h
|
|
+ procedure :: acc_create_64_h
|
|
+ procedure :: acc_create_array_h
|
|
+ end interface
|
|
+
|
|
+ interface acc_present_or_create
|
|
+ procedure :: acc_present_or_create_32_h
|
|
+ procedure :: acc_present_or_create_64_h
|
|
+ procedure :: acc_present_or_create_array_h
|
|
+ end interface
|
|
+
|
|
+ interface acc_pcreate
|
|
+ procedure :: acc_present_or_create_32_h
|
|
+ procedure :: acc_present_or_create_64_h
|
|
+ procedure :: acc_present_or_create_array_h
|
|
+ end interface
|
|
+
|
|
+ interface acc_copyout
|
|
+ procedure :: acc_copyout_32_h
|
|
+ procedure :: acc_copyout_64_h
|
|
+ procedure :: acc_copyout_array_h
|
|
+ end interface
|
|
+
|
|
+ interface acc_copyout_finalize
|
|
+ procedure :: acc_copyout_finalize_32_h
|
|
+ procedure :: acc_copyout_finalize_64_h
|
|
+ procedure :: acc_copyout_finalize_array_h
|
|
+ end interface
|
|
+
|
|
+ interface acc_delete
|
|
+ procedure :: acc_delete_32_h
|
|
+ procedure :: acc_delete_64_h
|
|
+ procedure :: acc_delete_array_h
|
|
+ end interface
|
|
+
|
|
+ interface acc_delete_finalize
|
|
+ procedure :: acc_delete_finalize_32_h
|
|
+ procedure :: acc_delete_finalize_64_h
|
|
+ procedure :: acc_delete_finalize_array_h
|
|
+ end interface
|
|
+
|
|
+ interface acc_update_device
|
|
+ procedure :: acc_update_device_32_h
|
|
+ procedure :: acc_update_device_64_h
|
|
+ procedure :: acc_update_device_array_h
|
|
+ end interface
|
|
+
|
|
+ interface acc_update_self
|
|
+ procedure :: acc_update_self_32_h
|
|
+ procedure :: acc_update_self_64_h
|
|
+ procedure :: acc_update_self_array_h
|
|
+ end interface
|
|
+
|
|
+ ! acc_map_data: Only available in C/C++
|
|
+ ! acc_unmap_data: Only available in C/C++
|
|
+ ! acc_deviceptr: Only available in C/C++
|
|
+ ! acc_hostptr: Only available in C/C++
|
|
+
|
|
+ interface acc_is_present
|
|
+ procedure :: acc_is_present_32_h
|
|
+ procedure :: acc_is_present_64_h
|
|
+ procedure :: acc_is_present_array_h
|
|
+ end interface
|
|
+
|
|
+ ! acc_memcpy_to_device: Only available in C/C++
|
|
+ ! acc_memcpy_from_device: Only available in C/C++
|
|
+
|
|
+ interface acc_copyin_async
|
|
+ procedure :: acc_copyin_async_32_h
|
|
+ procedure :: acc_copyin_async_64_h
|
|
+ procedure :: acc_copyin_async_array_h
|
|
+ end interface
|
|
+
|
|
+ interface acc_create_async
|
|
+ procedure :: acc_create_async_32_h
|
|
+ procedure :: acc_create_async_64_h
|
|
+ procedure :: acc_create_async_array_h
|
|
+ end interface
|
|
+
|
|
+ interface acc_copyout_async
|
|
+ procedure :: acc_copyout_async_32_h
|
|
+ procedure :: acc_copyout_async_64_h
|
|
+ procedure :: acc_copyout_async_array_h
|
|
+ end interface
|
|
+
|
|
+ interface acc_delete_async
|
|
+ procedure :: acc_delete_async_32_h
|
|
+ procedure :: acc_delete_async_64_h
|
|
+ procedure :: acc_delete_async_array_h
|
|
+ end interface
|
|
+
|
|
+ interface acc_update_device_async
|
|
+ procedure :: acc_update_device_async_32_h
|
|
+ procedure :: acc_update_device_async_64_h
|
|
+ procedure :: acc_update_device_async_array_h
|
|
+ end interface
|
|
+
|
|
+ interface acc_update_self_async
|
|
+ procedure :: acc_update_self_async_32_h
|
|
+ procedure :: acc_update_self_async_64_h
|
|
+ procedure :: acc_update_self_async_array_h
|
|
+ end interface
|
|
+
|
|
+end module
|
|
+
|
|
+function acc_get_num_devices_h (d)
|
|
+ use openacc_internal2, only: acc_get_num_devices_l
|
|
+ use openacc_kinds2
|
|
+ integer acc_get_num_devices_h
|
|
+ integer (acc_device_kind) d
|
|
+ acc_get_num_devices_h = acc_get_num_devices_l (d)
|
|
+end function
|
|
+
|
|
+subroutine acc_set_device_type_h (d)
|
|
+ use openacc_internal2, only: acc_set_device_type_l
|
|
+ use openacc_kinds2
|
|
+ integer (acc_device_kind) d
|
|
+ call acc_set_device_type_l (d)
|
|
+end subroutine
|
|
+
|
|
+function acc_get_device_type_h ()
|
|
+ use openacc_internal2, only: acc_get_device_type_l
|
|
+ use openacc_kinds2
|
|
+ integer (acc_device_kind) acc_get_device_type_h
|
|
+ acc_get_device_type_h = acc_get_device_type_l ()
|
|
+end function
|
|
+
|
|
+subroutine acc_set_device_num_h (n, d)
|
|
+ use openacc_internal2, only: acc_set_device_num_l
|
|
+ use openacc_kinds2
|
|
+ integer n
|
|
+ integer (acc_device_kind) d
|
|
+ call acc_set_device_num_l (n, d)
|
|
+end subroutine
|
|
+
|
|
+function acc_get_device_num_h (d)
|
|
+ use openacc_internal2, only: acc_get_device_num_l
|
|
+ use openacc_kinds2
|
|
+ integer acc_get_device_num_h
|
|
+ integer (acc_device_kind) d
|
|
+ acc_get_device_num_h = acc_get_device_num_l (d)
|
|
+end function
|
|
+
|
|
+function acc_async_test_h (a)
|
|
+ use openacc_internal2, only: acc_async_test_l
|
|
+ logical acc_async_test_h
|
|
+ integer a
|
|
+ if (acc_async_test_l (a) .eq. 1) then
|
|
+ acc_async_test_h = .TRUE.
|
|
+ else
|
|
+ acc_async_test_h = .FALSE.
|
|
+ end if
|
|
+end function
|
|
+
|
|
+function acc_async_test_all_h ()
|
|
+ use openacc_internal2, only: acc_async_test_all_l
|
|
+ logical acc_async_test_all_h
|
|
+ if (acc_async_test_all_l () .eq. 1) then
|
|
+ acc_async_test_all_h = .TRUE.
|
|
+ else
|
|
+ acc_async_test_all_h = .FALSE.
|
|
+ end if
|
|
+end function
|
|
+
|
|
+subroutine acc_wait_h (a)
|
|
+ use openacc_internal2, only: acc_wait_l
|
|
+ integer a
|
|
+ call acc_wait_l (a)
|
|
+end subroutine
|
|
+
|
|
+subroutine acc_wait_async_h (a1, a2)
|
|
+ use openacc_internal2, only: acc_wait_async_l
|
|
+ integer a1, a2
|
|
+ call acc_wait_async_l (a1, a2)
|
|
+end subroutine
|
|
+
|
|
+subroutine acc_wait_all_h ()
|
|
+ use openacc_internal2, only: acc_wait_all_l
|
|
+ call acc_wait_all_l ()
|
|
+end subroutine
|
|
+
|
|
+subroutine acc_wait_all_async_h (a)
|
|
+ use openacc_internal2, only: acc_wait_all_async_l
|
|
+ integer a
|
|
+ call acc_wait_all_async_l (a)
|
|
+end subroutine
|
|
+
|
|
+subroutine acc_init_h (d)
|
|
+ use openacc_internal2, only: acc_init_l
|
|
+ use openacc_kinds2
|
|
+ integer (acc_device_kind) d
|
|
+ call acc_init_l (d)
|
|
+end subroutine
|
|
+
|
|
+subroutine acc_shutdown_h (d)
|
|
+ use openacc_internal2, only: acc_shutdown_l
|
|
+ use openacc_kinds2
|
|
+ integer (acc_device_kind) d
|
|
+ call acc_shutdown_l (d)
|
|
+end subroutine
|
|
+
|
|
+function acc_on_device_h (d)
|
|
+ use openacc_internal2, only: acc_on_device_l
|
|
+ use openacc_kinds2
|
|
+ integer (acc_device_kind) d
|
|
+ logical acc_on_device_h
|
|
+ if (acc_on_device_l (d) .eq. 1) then
|
|
+ acc_on_device_h = .TRUE.
|
|
+ else
|
|
+ acc_on_device_h = .FALSE.
|
|
+ end if
|
|
+end function
|
|
+
|
|
+subroutine acc_copyin_32_h (a, len)
|
|
+ use iso_c_binding, only: c_int32_t, c_size_t
|
|
+ use openacc_internal2, only: acc_copyin_l
|
|
+ !GCC$ ATTRIBUTES NO_ARG_CHECK :: a
|
|
+ type (*), dimension (*) :: a
|
|
+ integer (c_int32_t) len
|
|
+ call acc_copyin_l (a, int (len, kind = c_size_t))
|
|
+end subroutine
|
|
+
|
|
+subroutine acc_copyin_64_h (a, len)
|
|
+ use iso_c_binding, only: c_int64_t, c_size_t
|
|
+ use openacc_internal2, only: acc_copyin_l
|
|
+ !GCC$ ATTRIBUTES NO_ARG_CHECK :: a
|
|
+ type (*), dimension (*) :: a
|
|
+ integer (c_int64_t) len
|
|
+ call acc_copyin_l (a, int (len, kind = c_size_t))
|
|
+end subroutine
|
|
+
|
|
+subroutine acc_copyin_array_h (a)
|
|
+ use openacc_internal2, only: acc_copyin_l
|
|
+ type (*), dimension (..), contiguous :: a
|
|
+ call acc_copyin_l (a, sizeof (a))
|
|
+end subroutine
|
|
+
|
|
+subroutine acc_present_or_copyin_32_h (a, len)
|
|
+ use iso_c_binding, only: c_int32_t, c_size_t
|
|
+ use openacc_internal2, only: acc_present_or_copyin_l
|
|
+ !GCC$ ATTRIBUTES NO_ARG_CHECK :: a
|
|
+ type (*), dimension (*) :: a
|
|
+ integer (c_int32_t) len
|
|
+ call acc_present_or_copyin_l (a, int (len, kind = c_size_t))
|
|
+end subroutine
|
|
+
|
|
+subroutine acc_present_or_copyin_64_h (a, len)
|
|
+ use iso_c_binding, only: c_int64_t, c_size_t
|
|
+ use openacc_internal2, only: acc_present_or_copyin_l
|
|
+ !GCC$ ATTRIBUTES NO_ARG_CHECK :: a
|
|
+ type (*), dimension (*) :: a
|
|
+ integer (c_int64_t) len
|
|
+ call acc_present_or_copyin_l (a, int (len, kind = c_size_t))
|
|
+end subroutine
|
|
+
|
|
+subroutine acc_present_or_copyin_array_h (a)
|
|
+ use openacc_internal2, only: acc_present_or_copyin_l
|
|
+ type (*), dimension (..), contiguous :: a
|
|
+ call acc_present_or_copyin_l (a, sizeof (a))
|
|
+end subroutine
|
|
+
|
|
+subroutine acc_create_32_h (a, len)
|
|
+ use iso_c_binding, only: c_int32_t, c_size_t
|
|
+ use openacc_internal2, only: acc_create_l
|
|
+ !GCC$ ATTRIBUTES NO_ARG_CHECK :: a
|
|
+ type (*), dimension (*) :: a
|
|
+ integer (c_int32_t) len
|
|
+ call acc_create_l (a, int (len, kind = c_size_t))
|
|
+end subroutine
|
|
+
|
|
+subroutine acc_create_64_h (a, len)
|
|
+ use iso_c_binding, only: c_int64_t, c_size_t
|
|
+ use openacc_internal2, only: acc_create_l
|
|
+ !GCC$ ATTRIBUTES NO_ARG_CHECK :: a
|
|
+ type (*), dimension (*) :: a
|
|
+ integer (c_int64_t) len
|
|
+ call acc_create_l (a, int (len, kind = c_size_t))
|
|
+end subroutine
|
|
+
|
|
+subroutine acc_create_array_h (a)
|
|
+ use openacc_internal2, only: acc_create_l
|
|
+ type (*), dimension (..), contiguous :: a
|
|
+ call acc_create_l (a, sizeof (a))
|
|
+end subroutine
|
|
+
|
|
+subroutine acc_present_or_create_32_h (a, len)
|
|
+ use iso_c_binding, only: c_int32_t, c_size_t
|
|
+ use openacc_internal2, only: acc_present_or_create_l
|
|
+ !GCC$ ATTRIBUTES NO_ARG_CHECK :: a
|
|
+ type (*), dimension (*) :: a
|
|
+ integer (c_int32_t) len
|
|
+ call acc_present_or_create_l (a, int (len, kind = c_size_t))
|
|
+end subroutine
|
|
+
|
|
+subroutine acc_present_or_create_64_h (a, len)
|
|
+ use iso_c_binding, only: c_int64_t, c_size_t
|
|
+ use openacc_internal2, only: acc_present_or_create_l
|
|
+ !GCC$ ATTRIBUTES NO_ARG_CHECK :: a
|
|
+ type (*), dimension (*) :: a
|
|
+ integer (c_int64_t) len
|
|
+ call acc_present_or_create_l (a, int (len, kind = c_size_t))
|
|
+end subroutine
|
|
+
|
|
+subroutine acc_present_or_create_array_h (a)
|
|
+ use openacc_internal2, only: acc_present_or_create_l
|
|
+ type (*), dimension (..), contiguous :: a
|
|
+ call acc_present_or_create_l (a, sizeof (a))
|
|
+end subroutine
|
|
+
|
|
+subroutine acc_copyout_32_h (a, len)
|
|
+ use iso_c_binding, only: c_int32_t, c_size_t
|
|
+ use openacc_internal2, only: acc_copyout_l
|
|
+ !GCC$ ATTRIBUTES NO_ARG_CHECK :: a
|
|
+ type (*), dimension (*) :: a
|
|
+ integer (c_int32_t) len
|
|
+ call acc_copyout_l (a, int (len, kind = c_size_t))
|
|
+end subroutine
|
|
+
|
|
+subroutine acc_copyout_64_h (a, len)
|
|
+ use iso_c_binding, only: c_int64_t, c_size_t
|
|
+ use openacc_internal2, only: acc_copyout_l
|
|
+ !GCC$ ATTRIBUTES NO_ARG_CHECK :: a
|
|
+ type (*), dimension (*) :: a
|
|
+ integer (c_int64_t) len
|
|
+ call acc_copyout_l (a, int (len, kind = c_size_t))
|
|
+end subroutine
|
|
+
|
|
+subroutine acc_copyout_array_h (a)
|
|
+ use openacc_internal2, only: acc_copyout_l
|
|
+ type (*), dimension (..), contiguous :: a
|
|
+ call acc_copyout_l (a, sizeof (a))
|
|
+end subroutine
|
|
+
|
|
+subroutine acc_copyout_finalize_32_h (a, len)
|
|
+ use iso_c_binding, only: c_int32_t, c_size_t
|
|
+ use openacc_internal2, only: acc_copyout_finalize_l
|
|
+ !GCC$ ATTRIBUTES NO_ARG_CHECK :: a
|
|
+ type (*), dimension (*) :: a
|
|
+ integer (c_int32_t) len
|
|
+ call acc_copyout_finalize_l (a, int (len, kind = c_size_t))
|
|
+end subroutine
|
|
+
|
|
+subroutine acc_copyout_finalize_64_h (a, len)
|
|
+ use iso_c_binding, only: c_int64_t, c_size_t
|
|
+ use openacc_internal2, only: acc_copyout_finalize_l
|
|
+ !GCC$ ATTRIBUTES NO_ARG_CHECK :: a
|
|
+ type (*), dimension (*) :: a
|
|
+ integer (c_int64_t) len
|
|
+ call acc_copyout_finalize_l (a, int (len, kind = c_size_t))
|
|
+end subroutine
|
|
+
|
|
+subroutine acc_copyout_finalize_array_h (a)
|
|
+ use openacc_internal2, only: acc_copyout_finalize_l
|
|
+ type (*), dimension (..), contiguous :: a
|
|
+ call acc_copyout_finalize_l (a, sizeof (a))
|
|
+end subroutine
|
|
+
|
|
+subroutine acc_delete_32_h (a, len)
|
|
+ use iso_c_binding, only: c_int32_t, c_size_t
|
|
+ use openacc_internal2, only: acc_delete_l
|
|
+ !GCC$ ATTRIBUTES NO_ARG_CHECK :: a
|
|
+ type (*), dimension (*) :: a
|
|
+ integer (c_int32_t) len
|
|
+ call acc_delete_l (a, int (len, kind = c_size_t))
|
|
+end subroutine
|
|
+
|
|
+subroutine acc_delete_64_h (a, len)
|
|
+ use iso_c_binding, only: c_int64_t, c_size_t
|
|
+ use openacc_internal2, only: acc_delete_l
|
|
+ !GCC$ ATTRIBUTES NO_ARG_CHECK :: a
|
|
+ type (*), dimension (*) :: a
|
|
+ integer (c_int64_t) len
|
|
+ call acc_delete_l (a, int (len, kind = c_size_t))
|
|
+end subroutine
|
|
+
|
|
+subroutine acc_delete_array_h (a)
|
|
+ use openacc_internal2, only: acc_delete_l
|
|
+ type (*), dimension (..), contiguous :: a
|
|
+ call acc_delete_l (a, sizeof (a))
|
|
+end subroutine
|
|
+
|
|
+subroutine acc_delete_finalize_32_h (a, len)
|
|
+ use iso_c_binding, only: c_int32_t, c_size_t
|
|
+ use openacc_internal2, only: acc_delete_finalize_l
|
|
+ !GCC$ ATTRIBUTES NO_ARG_CHECK :: a
|
|
+ type (*), dimension (*) :: a
|
|
+ integer (c_int32_t) len
|
|
+ call acc_delete_finalize_l (a, int (len, kind = c_size_t))
|
|
+end subroutine
|
|
+
|
|
+subroutine acc_delete_finalize_64_h (a, len)
|
|
+ use iso_c_binding, only: c_int64_t, c_size_t
|
|
+ use openacc_internal2, only: acc_delete_finalize_l
|
|
+ !GCC$ ATTRIBUTES NO_ARG_CHECK :: a
|
|
+ type (*), dimension (*) :: a
|
|
+ integer (c_int64_t) len
|
|
+ call acc_delete_finalize_l (a, int (len, kind = c_size_t))
|
|
+end subroutine
|
|
+
|
|
+subroutine acc_delete_finalize_array_h (a)
|
|
+ use openacc_internal2, only: acc_delete_finalize_l
|
|
+ type (*), dimension (..), contiguous :: a
|
|
+ call acc_delete_finalize_l (a, sizeof (a))
|
|
+end subroutine
|
|
+
|
|
+subroutine acc_update_device_32_h (a, len)
|
|
+ use iso_c_binding, only: c_int32_t, c_size_t
|
|
+ use openacc_internal2, only: acc_update_device_l
|
|
+ !GCC$ ATTRIBUTES NO_ARG_CHECK :: a
|
|
+ type (*), dimension (*) :: a
|
|
+ integer (c_int32_t) len
|
|
+ call acc_update_device_l (a, int (len, kind = c_size_t))
|
|
+end subroutine
|
|
+
|
|
+subroutine acc_update_device_64_h (a, len)
|
|
+ use iso_c_binding, only: c_int64_t, c_size_t
|
|
+ use openacc_internal2, only: acc_update_device_l
|
|
+ !GCC$ ATTRIBUTES NO_ARG_CHECK :: a
|
|
+ type (*), dimension (*) :: a
|
|
+ integer (c_int64_t) len
|
|
+ call acc_update_device_l (a, int (len, kind = c_size_t))
|
|
+end subroutine
|
|
+
|
|
+subroutine acc_update_device_array_h (a)
|
|
+ use openacc_internal2, only: acc_update_device_l
|
|
+ type (*), dimension (..), contiguous :: a
|
|
+ call acc_update_device_l (a, sizeof (a))
|
|
+end subroutine
|
|
+
|
|
+subroutine acc_update_self_32_h (a, len)
|
|
+ use iso_c_binding, only: c_int32_t, c_size_t
|
|
+ use openacc_internal2, only: acc_update_self_l
|
|
+ !GCC$ ATTRIBUTES NO_ARG_CHECK :: a
|
|
+ type (*), dimension (*) :: a
|
|
+ integer (c_int32_t) len
|
|
+ call acc_update_self_l (a, int (len, kind = c_size_t))
|
|
+end subroutine
|
|
+
|
|
+subroutine acc_update_self_64_h (a, len)
|
|
+ use iso_c_binding, only: c_int64_t, c_size_t
|
|
+ use openacc_internal2, only: acc_update_self_l
|
|
+ !GCC$ ATTRIBUTES NO_ARG_CHECK :: a
|
|
+ type (*), dimension (*) :: a
|
|
+ integer (c_int64_t) len
|
|
+ call acc_update_self_l (a, int (len, kind = c_size_t))
|
|
+end subroutine
|
|
+
|
|
+subroutine acc_update_self_array_h (a)
|
|
+ use openacc_internal2, only: acc_update_self_l
|
|
+ type (*), dimension (..), contiguous :: a
|
|
+ call acc_update_self_l (a, sizeof (a))
|
|
+end subroutine
|
|
+
|
|
+function acc_is_present_32_h (a, len)
|
|
+ use iso_c_binding, only: c_int32_t, c_size_t
|
|
+ use openacc_internal2, only: acc_is_present_l
|
|
+ logical acc_is_present_32_h
|
|
+ !GCC$ ATTRIBUTES NO_ARG_CHECK :: a
|
|
+ type (*), dimension (*) :: a
|
|
+ integer (c_int32_t) len
|
|
+ if (acc_is_present_l (a, int (len, kind = c_size_t)) .eq. 1) then
|
|
+ acc_is_present_32_h = .TRUE.
|
|
+ else
|
|
+ acc_is_present_32_h = .FALSE.
|
|
+ end if
|
|
+end function
|
|
+
|
|
+function acc_is_present_64_h (a, len)
|
|
+ use iso_c_binding, only: c_int64_t, c_size_t
|
|
+ use openacc_internal2, only: acc_is_present_l
|
|
+ logical acc_is_present_64_h
|
|
+ !GCC$ ATTRIBUTES NO_ARG_CHECK :: a
|
|
+ type (*), dimension (*) :: a
|
|
+ integer (c_int64_t) len
|
|
+ if (acc_is_present_l (a, int (len, kind = c_size_t)) .eq. 1) then
|
|
+ acc_is_present_64_h = .TRUE.
|
|
+ else
|
|
+ acc_is_present_64_h = .FALSE.
|
|
+ end if
|
|
+end function
|
|
+
|
|
+function acc_is_present_array_h (a)
|
|
+ use openacc_internal2, only: acc_is_present_l
|
|
+ logical acc_is_present_array_h
|
|
+ type (*), dimension (..), contiguous :: a
|
|
+ acc_is_present_array_h = acc_is_present_l (a, sizeof (a)) == 1
|
|
+end function
|
|
+
|
|
+subroutine acc_copyin_async_32_h (a, len, async)
|
|
+ use iso_c_binding, only: c_int32_t, c_size_t, c_int
|
|
+ use openacc_internal2, only: acc_copyin_async_l
|
|
+ use openacc_kinds2, only: acc_handle_kind
|
|
+ !GCC$ ATTRIBUTES NO_ARG_CHECK :: a
|
|
+ type (*), dimension (*) :: a
|
|
+ integer (c_int32_t) len
|
|
+ integer (acc_handle_kind) async
|
|
+ call acc_copyin_async_l (a, int (len, kind = c_size_t), int (async, kind = c_int))
|
|
+end subroutine
|
|
+
|
|
+subroutine acc_copyin_async_64_h (a, len, async)
|
|
+ use iso_c_binding, only: c_int64_t, c_size_t, c_int
|
|
+ use openacc_internal2, only: acc_copyin_async_l
|
|
+ use openacc_kinds2, only: acc_handle_kind
|
|
+ !GCC$ ATTRIBUTES NO_ARG_CHECK :: a
|
|
+ type (*), dimension (*) :: a
|
|
+ integer (c_int64_t) len
|
|
+ integer (acc_handle_kind) async
|
|
+ call acc_copyin_async_l (a, int (len, kind = c_size_t), int (async, kind = c_int))
|
|
+end subroutine
|
|
+
|
|
+subroutine acc_copyin_async_array_h (a, async)
|
|
+ use iso_c_binding, only: c_int
|
|
+ use openacc_internal2, only: acc_copyin_async_l
|
|
+ use openacc_kinds2, only: acc_handle_kind
|
|
+ type (*), dimension (..), contiguous :: a
|
|
+ integer (acc_handle_kind) async
|
|
+ call acc_copyin_async_l (a, sizeof (a), int (async, kind = c_int))
|
|
+end subroutine
|
|
+
|
|
+subroutine acc_create_async_32_h (a, len, async)
|
|
+ use iso_c_binding, only: c_int32_t, c_size_t, c_int
|
|
+ use openacc_internal2, only: acc_create_async_l
|
|
+ use openacc_kinds2, only: acc_handle_kind
|
|
+ !GCC$ ATTRIBUTES NO_ARG_CHECK :: a
|
|
+ type (*), dimension (*) :: a
|
|
+ integer (c_int32_t) len
|
|
+ integer (acc_handle_kind) async
|
|
+ call acc_create_async_l (a, int (len, kind = c_size_t), int (async, kind = c_int))
|
|
+end subroutine
|
|
+
|
|
+subroutine acc_create_async_64_h (a, len, async)
|
|
+ use iso_c_binding, only: c_int64_t, c_size_t, c_int
|
|
+ use openacc_internal2, only: acc_create_async_l
|
|
+ use openacc_kinds2, only: acc_handle_kind
|
|
+ !GCC$ ATTRIBUTES NO_ARG_CHECK :: a
|
|
+ type (*), dimension (*) :: a
|
|
+ integer (c_int64_t) len
|
|
+ integer (acc_handle_kind) async
|
|
+ call acc_create_async_l (a, int (len, kind = c_size_t), int (async, kind = c_int))
|
|
+end subroutine
|
|
+
|
|
+subroutine acc_create_async_array_h (a, async)
|
|
+ use iso_c_binding, only: c_int
|
|
+ use openacc_internal2, only: acc_create_async_l
|
|
+ use openacc_kinds2, only: acc_handle_kind
|
|
+ type (*), dimension (..), contiguous :: a
|
|
+ integer (acc_handle_kind) async
|
|
+ call acc_create_async_l (a, sizeof (a), int (async, kind = c_int))
|
|
+end subroutine
|
|
+
|
|
+subroutine acc_copyout_async_32_h (a, len, async)
|
|
+ use iso_c_binding, only: c_int32_t, c_size_t, c_int
|
|
+ use openacc_internal2, only: acc_copyout_async_l
|
|
+ use openacc_kinds2, only: acc_handle_kind
|
|
+ !GCC$ ATTRIBUTES NO_ARG_CHECK :: a
|
|
+ type (*), dimension (*) :: a
|
|
+ integer (c_int32_t) len
|
|
+ integer (acc_handle_kind) async
|
|
+ call acc_copyout_async_l (a, int (len, kind = c_size_t), int (async, kind = c_int))
|
|
+end subroutine
|
|
+
|
|
+subroutine acc_copyout_async_64_h (a, len, async)
|
|
+ use iso_c_binding, only: c_int64_t, c_size_t, c_int
|
|
+ use openacc_internal2, only: acc_copyout_async_l
|
|
+ use openacc_kinds2, only: acc_handle_kind
|
|
+ !GCC$ ATTRIBUTES NO_ARG_CHECK :: a
|
|
+ type (*), dimension (*) :: a
|
|
+ integer (c_int64_t) len
|
|
+ integer (acc_handle_kind) async
|
|
+ call acc_copyout_async_l (a, int (len, kind = c_size_t), int (async, kind = c_int))
|
|
+end subroutine
|
|
+
|
|
+subroutine acc_copyout_async_array_h (a, async)
|
|
+ use iso_c_binding, only: c_int
|
|
+ use openacc_internal2, only: acc_copyout_async_l
|
|
+ use openacc_kinds2, only: acc_handle_kind
|
|
+ type (*), dimension (..), contiguous :: a
|
|
+ integer (acc_handle_kind) async
|
|
+ call acc_copyout_async_l (a, sizeof (a), int (async, kind = c_int))
|
|
+end subroutine
|
|
+
|
|
+subroutine acc_delete_async_32_h (a, len, async)
|
|
+ use iso_c_binding, only: c_int32_t, c_size_t, c_int
|
|
+ use openacc_internal2, only: acc_delete_async_l
|
|
+ use openacc_kinds2, only: acc_handle_kind
|
|
+ !GCC$ ATTRIBUTES NO_ARG_CHECK :: a
|
|
+ type (*), dimension (*) :: a
|
|
+ integer (c_int32_t) len
|
|
+ integer (acc_handle_kind) async
|
|
+ call acc_delete_async_l (a, int (len, kind = c_size_t), int (async, kind = c_int))
|
|
+end subroutine
|
|
+
|
|
+subroutine acc_delete_async_64_h (a, len, async)
|
|
+ use iso_c_binding, only: c_int64_t, c_size_t, c_int
|
|
+ use openacc_internal2, only: acc_delete_async_l
|
|
+ use openacc_kinds2, only: acc_handle_kind
|
|
+ !GCC$ ATTRIBUTES NO_ARG_CHECK :: a
|
|
+ type (*), dimension (*) :: a
|
|
+ integer (c_int64_t) len
|
|
+ integer (acc_handle_kind) async
|
|
+ call acc_delete_async_l (a, int (len, kind = c_size_t), int (async, kind = c_int))
|
|
+end subroutine
|
|
+
|
|
+subroutine acc_delete_async_array_h (a, async)
|
|
+ use iso_c_binding, only: c_int
|
|
+ use openacc_internal2, only: acc_delete_async_l
|
|
+ use openacc_kinds2, only: acc_handle_kind
|
|
+ type (*), dimension (..), contiguous :: a
|
|
+ integer (acc_handle_kind) async
|
|
+ call acc_delete_async_l (a, sizeof (a), int (async, kind = c_int))
|
|
+end subroutine
|
|
+
|
|
+subroutine acc_update_device_async_32_h (a, len, async)
|
|
+ use iso_c_binding, only: c_int32_t, c_size_t, c_int
|
|
+ use openacc_internal2, only: acc_update_device_async_l
|
|
+ use openacc_kinds2, only: acc_handle_kind
|
|
+ !GCC$ ATTRIBUTES NO_ARG_CHECK :: a
|
|
+ type (*), dimension (*) :: a
|
|
+ integer (c_int32_t) len
|
|
+ integer (acc_handle_kind) async
|
|
+ call acc_update_device_async_l (a, int (len, kind = c_size_t), int (async, kind = c_int))
|
|
+end subroutine
|
|
+
|
|
+subroutine acc_update_device_async_64_h (a, len, async)
|
|
+ use iso_c_binding, only: c_int64_t, c_size_t, c_int
|
|
+ use openacc_internal2, only: acc_update_device_async_l
|
|
+ use openacc_kinds2, only: acc_handle_kind
|
|
+ !GCC$ ATTRIBUTES NO_ARG_CHECK :: a
|
|
+ type (*), dimension (*) :: a
|
|
+ integer (c_int64_t) len
|
|
+ integer (acc_handle_kind) async
|
|
+ call acc_update_device_async_l (a, int (len, kind = c_size_t), int (async, kind = c_int))
|
|
+end subroutine
|
|
+
|
|
+subroutine acc_update_device_async_array_h (a, async)
|
|
+ use iso_c_binding, only: c_int
|
|
+ use openacc_internal2, only: acc_update_device_async_l
|
|
+ use openacc_kinds2, only: acc_handle_kind
|
|
+ type (*), dimension (..), contiguous :: a
|
|
+ integer (acc_handle_kind) async
|
|
+ call acc_update_device_async_l (a, sizeof (a), int (async, kind = c_int))
|
|
+end subroutine
|
|
+
|
|
+subroutine acc_update_self_async_32_h (a, len, async)
|
|
+ use iso_c_binding, only: c_int32_t, c_size_t, c_int
|
|
+ use openacc_internal2, only: acc_update_self_async_l
|
|
+ use openacc_kinds2, only: acc_handle_kind
|
|
+ !GCC$ ATTRIBUTES NO_ARG_CHECK :: a
|
|
+ type (*), dimension (*) :: a
|
|
+ integer (c_int32_t) len
|
|
+ integer (acc_handle_kind) async
|
|
+ call acc_update_self_async_l (a, int (len, kind = c_size_t), int (async, kind = c_int))
|
|
+end subroutine
|
|
+
|
|
+subroutine acc_update_self_async_64_h (a, len, async)
|
|
+ use iso_c_binding, only: c_int64_t, c_size_t, c_int
|
|
+ use openacc_internal2, only: acc_update_self_async_l
|
|
+ use openacc_kinds2, only: acc_handle_kind
|
|
+ !GCC$ ATTRIBUTES NO_ARG_CHECK :: a
|
|
+ type (*), dimension (*) :: a
|
|
+ integer (c_int64_t) len
|
|
+ integer (acc_handle_kind) async
|
|
+ call acc_update_self_async_l (a, int (len, kind = c_size_t), int (async, kind = c_int))
|
|
+end subroutine
|
|
+
|
|
+subroutine acc_update_self_async_array_h (a, async)
|
|
+ use iso_c_binding, only: c_int
|
|
+ use openacc_internal2, only: acc_update_self_async_l
|
|
+ use openacc_kinds2, only: acc_handle_kind
|
|
+ type (*), dimension (..), contiguous :: a
|
|
+ integer (acc_handle_kind) async
|
|
+ call acc_update_self_async_l (a, sizeof (a), int (async, kind = c_int))
|
|
+end subroutine
|
|
--- libgomp/taskloop.c.jj 2018-04-25 09:40:31.913655581 +0200
|
|
+++ libgomp/taskloop.c 2019-05-07 18:46:36.547109400 +0200
|
|
@@ -149,11 +149,28 @@ GOMP_taskloop (void (*fn) (void *), void
|
|
|
|
if (flags & GOMP_TASK_FLAG_NOGROUP)
|
|
{
|
|
- if (thr->task && thr->task->taskgroup && thr->task->taskgroup->cancelled)
|
|
- return;
|
|
+ if (__builtin_expect (gomp_cancel_var, 0)
|
|
+ && thr->task
|
|
+ && thr->task->taskgroup)
|
|
+ {
|
|
+ if (thr->task->taskgroup->cancelled)
|
|
+ return;
|
|
+ if (thr->task->taskgroup->workshare
|
|
+ && thr->task->taskgroup->prev
|
|
+ && thr->task->taskgroup->prev->cancelled)
|
|
+ return;
|
|
+ }
|
|
}
|
|
else
|
|
- ialias_call (GOMP_taskgroup_start) ();
|
|
+ {
|
|
+ ialias_call (GOMP_taskgroup_start) ();
|
|
+ if (flags & GOMP_TASK_FLAG_REDUCTION)
|
|
+ {
|
|
+ struct gomp_data_head { TYPE t1, t2; uintptr_t *ptr; };
|
|
+ uintptr_t *ptr = ((struct gomp_data_head *) data)->ptr;
|
|
+ ialias_call (GOMP_taskgroup_reduction_register) (ptr);
|
|
+ }
|
|
+ }
|
|
|
|
if (priority > gomp_max_task_priority_var)
|
|
priority = gomp_max_task_priority_var;
|
|
@@ -284,19 +301,31 @@ GOMP_taskloop (void (*fn) (void *), void
|
|
gomp_mutex_lock (&team->task_lock);
|
|
/* If parallel or taskgroup has been cancelled, don't start new
|
|
tasks. */
|
|
- if (__builtin_expect ((gomp_team_barrier_cancelled (&team->barrier)
|
|
- || (taskgroup && taskgroup->cancelled))
|
|
- && cpyfn == NULL, 0))
|
|
+ if (__builtin_expect (gomp_cancel_var, 0)
|
|
+ && cpyfn == NULL)
|
|
{
|
|
- gomp_mutex_unlock (&team->task_lock);
|
|
- for (i = 0; i < num_tasks; i++)
|
|
+ if (gomp_team_barrier_cancelled (&team->barrier))
|
|
+ {
|
|
+ do_cancel:
|
|
+ gomp_mutex_unlock (&team->task_lock);
|
|
+ for (i = 0; i < num_tasks; i++)
|
|
+ {
|
|
+ gomp_finish_task (tasks[i]);
|
|
+ free (tasks[i]);
|
|
+ }
|
|
+ if ((flags & GOMP_TASK_FLAG_NOGROUP) == 0)
|
|
+ ialias_call (GOMP_taskgroup_end) ();
|
|
+ return;
|
|
+ }
|
|
+ if (taskgroup)
|
|
{
|
|
- gomp_finish_task (tasks[i]);
|
|
- free (tasks[i]);
|
|
+ if (taskgroup->cancelled)
|
|
+ goto do_cancel;
|
|
+ if (taskgroup->workshare
|
|
+ && taskgroup->prev
|
|
+ && taskgroup->prev->cancelled)
|
|
+ goto do_cancel;
|
|
}
|
|
- if ((flags & GOMP_TASK_FLAG_NOGROUP) == 0)
|
|
- ialias_call (GOMP_taskgroup_end) ();
|
|
- return;
|
|
}
|
|
if (taskgroup)
|
|
taskgroup->num_children += num_tasks;
|
|
--- libgomp/parallel.c.jj 2018-04-25 09:40:31.926655587 +0200
|
|
+++ libgomp/parallel.c 2019-05-07 18:46:36.532109640 +0200
|
|
@@ -123,7 +123,8 @@ void
|
|
GOMP_parallel_start (void (*fn) (void *), void *data, unsigned num_threads)
|
|
{
|
|
num_threads = gomp_resolve_num_threads (num_threads, 0);
|
|
- gomp_team_start (fn, data, num_threads, 0, gomp_new_team (num_threads));
|
|
+ gomp_team_start (fn, data, num_threads, 0, gomp_new_team (num_threads),
|
|
+ NULL);
|
|
}
|
|
|
|
void
|
|
@@ -161,14 +162,33 @@ GOMP_parallel_end (void)
|
|
ialias (GOMP_parallel_end)
|
|
|
|
void
|
|
-GOMP_parallel (void (*fn) (void *), void *data, unsigned num_threads, unsigned int flags)
|
|
+GOMP_parallel (void (*fn) (void *), void *data, unsigned num_threads,
|
|
+ unsigned int flags)
|
|
{
|
|
num_threads = gomp_resolve_num_threads (num_threads, 0);
|
|
- gomp_team_start (fn, data, num_threads, flags, gomp_new_team (num_threads));
|
|
+ gomp_team_start (fn, data, num_threads, flags, gomp_new_team (num_threads),
|
|
+ NULL);
|
|
fn (data);
|
|
ialias_call (GOMP_parallel_end) ();
|
|
}
|
|
|
|
+unsigned
|
|
+GOMP_parallel_reductions (void (*fn) (void *), void *data,
|
|
+ unsigned num_threads, unsigned int flags)
|
|
+{
|
|
+ struct gomp_taskgroup *taskgroup;
|
|
+ num_threads = gomp_resolve_num_threads (num_threads, 0);
|
|
+ uintptr_t *rdata = *(uintptr_t **)data;
|
|
+ taskgroup = gomp_parallel_reduction_register (rdata, num_threads);
|
|
+ gomp_team_start (fn, data, num_threads, flags, gomp_new_team (num_threads),
|
|
+ taskgroup);
|
|
+ fn (data);
|
|
+ ialias_call (GOMP_parallel_end) ();
|
|
+ gomp_sem_destroy (&taskgroup->taskgroup_sem);
|
|
+ free (taskgroup);
|
|
+ return num_threads;
|
|
+}
|
|
+
|
|
bool
|
|
GOMP_cancellation_point (int which)
|
|
{
|
|
@@ -185,8 +205,15 @@ GOMP_cancellation_point (int which)
|
|
}
|
|
else if (which & GOMP_CANCEL_TASKGROUP)
|
|
{
|
|
- if (thr->task->taskgroup && thr->task->taskgroup->cancelled)
|
|
- return true;
|
|
+ if (thr->task->taskgroup)
|
|
+ {
|
|
+ if (thr->task->taskgroup->cancelled)
|
|
+ return true;
|
|
+ if (thr->task->taskgroup->workshare
|
|
+ && thr->task->taskgroup->prev
|
|
+ && thr->task->taskgroup->prev->cancelled)
|
|
+ return true;
|
|
+ }
|
|
/* FALLTHRU into the GOMP_CANCEL_PARALLEL case,
|
|
as #pragma omp cancel parallel also cancels all explicit
|
|
tasks. */
|
|
@@ -218,11 +245,17 @@ GOMP_cancel (int which, bool do_cancel)
|
|
}
|
|
else if (which & GOMP_CANCEL_TASKGROUP)
|
|
{
|
|
- if (thr->task->taskgroup && !thr->task->taskgroup->cancelled)
|
|
+ if (thr->task->taskgroup)
|
|
{
|
|
- gomp_mutex_lock (&team->task_lock);
|
|
- thr->task->taskgroup->cancelled = true;
|
|
- gomp_mutex_unlock (&team->task_lock);
|
|
+ struct gomp_taskgroup *taskgroup = thr->task->taskgroup;
|
|
+ if (taskgroup->workshare && taskgroup->prev)
|
|
+ taskgroup = taskgroup->prev;
|
|
+ if (!taskgroup->cancelled)
|
|
+ {
|
|
+ gomp_mutex_lock (&team->task_lock);
|
|
+ taskgroup->cancelled = true;
|
|
+ gomp_mutex_unlock (&team->task_lock);
|
|
+ }
|
|
}
|
|
return true;
|
|
}
|
|
--- libgomp/oacc-plugin.h.jj 2018-04-25 09:40:31.322655307 +0200
|
|
+++ libgomp/oacc-plugin.h 2019-05-07 18:46:36.531109656 +0200
|
|
@@ -29,5 +29,6 @@
|
|
|
|
extern void GOMP_PLUGIN_async_unmap_vars (void *, int);
|
|
extern void *GOMP_PLUGIN_acc_thread (void);
|
|
+extern int GOMP_PLUGIN_acc_default_dim (unsigned int);
|
|
|
|
#endif
|
|
--- libgomp/target.c.jj 2018-04-25 09:40:31.912655580 +0200
|
|
+++ libgomp/target.c 2019-05-07 19:07:21.032306327 +0200
|
|
@@ -180,16 +180,22 @@ gomp_device_copy (struct gomp_device_des
|
|
/* Infrastructure for coalescing adjacent or nearly adjacent (in device addresses)
|
|
host to device memory transfers. */
|
|
|
|
+struct gomp_coalesce_chunk
|
|
+{
|
|
+ /* The starting and ending point of a coalesced chunk of memory. */
|
|
+ size_t start, end;
|
|
+};
|
|
+
|
|
struct gomp_coalesce_buf
|
|
{
|
|
/* Buffer into which gomp_copy_host2dev will memcpy data and from which
|
|
it will be copied to the device. */
|
|
void *buf;
|
|
struct target_mem_desc *tgt;
|
|
- /* Array with offsets, chunks[2 * i] is the starting offset and
|
|
- chunks[2 * i + 1] ending offset relative to tgt->tgt_start device address
|
|
+ /* Array with offsets, chunks[i].start is the starting offset and
|
|
+ chunks[i].end ending offset relative to tgt->tgt_start device address
|
|
of chunks which are to be copied to buf and later copied to device. */
|
|
- size_t *chunks;
|
|
+ struct gomp_coalesce_chunk *chunks;
|
|
/* Number of chunks in chunks array, or -1 if coalesce buffering should not
|
|
be performed. */
|
|
long chunk_cnt;
|
|
@@ -222,14 +228,14 @@ gomp_coalesce_buf_add (struct gomp_coale
|
|
{
|
|
if (cbuf->chunk_cnt < 0)
|
|
return;
|
|
- if (start < cbuf->chunks[2 * cbuf->chunk_cnt - 1])
|
|
+ if (start < cbuf->chunks[cbuf->chunk_cnt - 1].end)
|
|
{
|
|
cbuf->chunk_cnt = -1;
|
|
return;
|
|
}
|
|
- if (start < cbuf->chunks[2 * cbuf->chunk_cnt - 1] + MAX_COALESCE_BUF_GAP)
|
|
+ if (start < cbuf->chunks[cbuf->chunk_cnt - 1].end + MAX_COALESCE_BUF_GAP)
|
|
{
|
|
- cbuf->chunks[2 * cbuf->chunk_cnt - 1] = start + len;
|
|
+ cbuf->chunks[cbuf->chunk_cnt - 1].end = start + len;
|
|
cbuf->use_cnt++;
|
|
return;
|
|
}
|
|
@@ -239,8 +245,8 @@ gomp_coalesce_buf_add (struct gomp_coale
|
|
if (cbuf->use_cnt == 1)
|
|
cbuf->chunk_cnt--;
|
|
}
|
|
- cbuf->chunks[2 * cbuf->chunk_cnt] = start;
|
|
- cbuf->chunks[2 * cbuf->chunk_cnt + 1] = start + len;
|
|
+ cbuf->chunks[cbuf->chunk_cnt].start = start;
|
|
+ cbuf->chunks[cbuf->chunk_cnt].end = start + len;
|
|
cbuf->chunk_cnt++;
|
|
cbuf->use_cnt = 1;
|
|
}
|
|
@@ -271,20 +277,20 @@ gomp_copy_host2dev (struct gomp_device_d
|
|
if (cbuf)
|
|
{
|
|
uintptr_t doff = (uintptr_t) d - cbuf->tgt->tgt_start;
|
|
- if (doff < cbuf->chunks[2 * cbuf->chunk_cnt - 1])
|
|
+ if (doff < cbuf->chunks[cbuf->chunk_cnt - 1].end)
|
|
{
|
|
long first = 0;
|
|
long last = cbuf->chunk_cnt - 1;
|
|
while (first <= last)
|
|
{
|
|
long middle = (first + last) >> 1;
|
|
- if (cbuf->chunks[2 * middle + 1] <= doff)
|
|
+ if (cbuf->chunks[middle].end <= doff)
|
|
first = middle + 1;
|
|
- else if (cbuf->chunks[2 * middle] <= doff)
|
|
+ else if (cbuf->chunks[middle].start <= doff)
|
|
{
|
|
- if (doff + sz > cbuf->chunks[2 * middle + 1])
|
|
+ if (doff + sz > cbuf->chunks[middle].end)
|
|
gomp_fatal ("internal libgomp cbuf error");
|
|
- memcpy ((char *) cbuf->buf + (doff - cbuf->chunks[0]),
|
|
+ memcpy ((char *) cbuf->buf + (doff - cbuf->chunks[0].start),
|
|
h, sz);
|
|
return;
|
|
}
|
|
@@ -510,8 +516,8 @@ gomp_map_vars (struct gomp_device_descr
|
|
cbuf.buf = NULL;
|
|
if (mapnum > 1 || pragma_kind == GOMP_MAP_VARS_TARGET)
|
|
{
|
|
- cbuf.chunks
|
|
- = (size_t *) gomp_alloca ((2 * mapnum + 2) * sizeof (size_t));
|
|
+ size_t chunks_size = (mapnum + 1) * sizeof (struct gomp_coalesce_chunk);
|
|
+ cbuf.chunks = (struct gomp_coalesce_chunk *) gomp_alloca (chunks_size);
|
|
cbuf.chunk_cnt = 0;
|
|
}
|
|
if (pragma_kind == GOMP_MAP_VARS_TARGET)
|
|
@@ -521,8 +527,8 @@ gomp_map_vars (struct gomp_device_descr
|
|
tgt_size = mapnum * sizeof (void *);
|
|
cbuf.chunk_cnt = 1;
|
|
cbuf.use_cnt = 1 + (mapnum > 1);
|
|
- cbuf.chunks[0] = 0;
|
|
- cbuf.chunks[1] = tgt_size;
|
|
+ cbuf.chunks[0].start = 0;
|
|
+ cbuf.chunks[0].end = tgt_size;
|
|
}
|
|
|
|
gomp_mutex_lock (&devicep->lock);
|
|
@@ -707,7 +713,7 @@ gomp_map_vars (struct gomp_device_descr
|
|
if (cbuf.chunk_cnt > 0)
|
|
{
|
|
cbuf.buf
|
|
- = malloc (cbuf.chunks[2 * cbuf.chunk_cnt - 1] - cbuf.chunks[0]);
|
|
+ = malloc (cbuf.chunks[cbuf.chunk_cnt - 1].end - cbuf.chunks[0].start);
|
|
if (cbuf.buf)
|
|
{
|
|
cbuf.tgt = tgt;
|
|
@@ -859,6 +865,7 @@ gomp_map_vars (struct gomp_device_descr
|
|
tgt->list[i].offset = 0;
|
|
tgt->list[i].length = k->host_end - k->host_start;
|
|
k->refcount = 1;
|
|
+ k->dynamic_refcount = 0;
|
|
tgt->refcount++;
|
|
array->left = NULL;
|
|
array->right = NULL;
|
|
@@ -956,9 +963,10 @@ gomp_map_vars (struct gomp_device_descr
|
|
/* Set link pointer on target to the device address of the
|
|
mapped object. */
|
|
void *tgt_addr = (void *) (tgt->tgt_start + k->tgt_offset);
|
|
- devicep->host2dev_func (devicep->target_id,
|
|
- (void *) n->tgt_offset,
|
|
- &tgt_addr, sizeof (void *));
|
|
+ /* We intentionally do not use coalescing here, as it's not
|
|
+ data allocated by the current call to this function. */
|
|
+ gomp_copy_host2dev (devicep, (void *) n->tgt_offset,
|
|
+ &tgt_addr, sizeof (void *), NULL);
|
|
}
|
|
array++;
|
|
}
|
|
@@ -981,10 +989,14 @@ gomp_map_vars (struct gomp_device_descr
|
|
{
|
|
long c = 0;
|
|
for (c = 0; c < cbuf.chunk_cnt; ++c)
|
|
- gomp_copy_host2dev (devicep, (void *) (tgt->tgt_start + cbuf.chunks[2 * c]),
|
|
- (char *) cbuf.buf + (cbuf.chunks[2 * c] - cbuf.chunks[0]),
|
|
- cbuf.chunks[2 * c + 1] - cbuf.chunks[2 * c], NULL);
|
|
+ gomp_copy_host2dev (devicep,
|
|
+ (void *) (tgt->tgt_start + cbuf.chunks[c].start),
|
|
+ (char *) cbuf.buf + (cbuf.chunks[c].start
|
|
+ - cbuf.chunks[0].start),
|
|
+ cbuf.chunks[c].end - cbuf.chunks[c].start, NULL);
|
|
free (cbuf.buf);
|
|
+ cbuf.buf = NULL;
|
|
+ cbufp = NULL;
|
|
}
|
|
|
|
/* If the variable from "omp target enter data" map-list was already mapped,
|
|
@@ -1011,6 +1023,23 @@ gomp_unmap_tgt (struct target_mem_desc *
|
|
free (tgt);
|
|
}
|
|
|
|
+attribute_hidden bool
|
|
+gomp_remove_var (struct gomp_device_descr *devicep, splay_tree_key k)
|
|
+{
|
|
+ bool is_tgt_unmapped = false;
|
|
+ splay_tree_remove (&devicep->mem_map, k);
|
|
+ if (k->link_key)
|
|
+ splay_tree_insert (&devicep->mem_map, (splay_tree_node) k->link_key);
|
|
+ if (k->tgt->refcount > 1)
|
|
+ k->tgt->refcount--;
|
|
+ else
|
|
+ {
|
|
+ is_tgt_unmapped = true;
|
|
+ gomp_unmap_tgt (k->tgt);
|
|
+ }
|
|
+ return is_tgt_unmapped;
|
|
+}
|
|
+
|
|
/* Unmap variables described by TGT. If DO_COPYFROM is true, copy relevant
|
|
variables back from device to host: if it is false, it is assumed that this
|
|
has been done already. */
|
|
@@ -1059,16 +1088,7 @@ gomp_unmap_vars (struct target_mem_desc
|
|
+ tgt->list[i].offset),
|
|
tgt->list[i].length);
|
|
if (do_unmap)
|
|
- {
|
|
- splay_tree_remove (&devicep->mem_map, k);
|
|
- if (k->link_key)
|
|
- splay_tree_insert (&devicep->mem_map,
|
|
- (splay_tree_node) k->link_key);
|
|
- if (k->tgt->refcount > 1)
|
|
- k->tgt->refcount--;
|
|
- else
|
|
- gomp_unmap_tgt (k->tgt);
|
|
- }
|
|
+ gomp_remove_var (devicep, k);
|
|
}
|
|
|
|
if (tgt->refcount > 1)
|
|
@@ -1298,17 +1318,7 @@ gomp_unload_image_from_device (struct go
|
|
else
|
|
{
|
|
splay_tree_key n = splay_tree_lookup (&devicep->mem_map, &k);
|
|
- splay_tree_remove (&devicep->mem_map, n);
|
|
- if (n->link_key)
|
|
- {
|
|
- if (n->tgt->refcount > 1)
|
|
- n->tgt->refcount--;
|
|
- else
|
|
- {
|
|
- is_tgt_unmapped = true;
|
|
- gomp_unmap_tgt (n->tgt);
|
|
- }
|
|
- }
|
|
+ is_tgt_unmapped = gomp_remove_var (devicep, n);
|
|
}
|
|
}
|
|
|
|
@@ -1855,11 +1865,20 @@ GOMP_target_update_ext (int device, size
|
|
struct gomp_team *team = thr->ts.team;
|
|
/* If parallel or taskgroup has been cancelled, don't start new
|
|
tasks. */
|
|
- if (team
|
|
- && (gomp_team_barrier_cancelled (&team->barrier)
|
|
- || (thr->task->taskgroup
|
|
- && thr->task->taskgroup->cancelled)))
|
|
- return;
|
|
+ if (__builtin_expect (gomp_cancel_var, 0) && team)
|
|
+ {
|
|
+ if (gomp_team_barrier_cancelled (&team->barrier))
|
|
+ return;
|
|
+ if (thr->task->taskgroup)
|
|
+ {
|
|
+ if (thr->task->taskgroup->cancelled)
|
|
+ return;
|
|
+ if (thr->task->taskgroup->workshare
|
|
+ && thr->task->taskgroup->prev
|
|
+ && thr->task->taskgroup->prev->cancelled)
|
|
+ return;
|
|
+ }
|
|
+ }
|
|
|
|
gomp_task_maybe_wait_for_dependencies (depend);
|
|
}
|
|
@@ -1874,10 +1893,20 @@ GOMP_target_update_ext (int device, size
|
|
struct gomp_thread *thr = gomp_thread ();
|
|
struct gomp_team *team = thr->ts.team;
|
|
/* If parallel or taskgroup has been cancelled, don't start new tasks. */
|
|
- if (team
|
|
- && (gomp_team_barrier_cancelled (&team->barrier)
|
|
- || (thr->task->taskgroup && thr->task->taskgroup->cancelled)))
|
|
- return;
|
|
+ if (__builtin_expect (gomp_cancel_var, 0) && team)
|
|
+ {
|
|
+ if (gomp_team_barrier_cancelled (&team->barrier))
|
|
+ return;
|
|
+ if (thr->task->taskgroup)
|
|
+ {
|
|
+ if (thr->task->taskgroup->cancelled)
|
|
+ return;
|
|
+ if (thr->task->taskgroup->workshare
|
|
+ && thr->task->taskgroup->prev
|
|
+ && thr->task->taskgroup->prev->cancelled)
|
|
+ return;
|
|
+ }
|
|
+ }
|
|
|
|
gomp_update (devicep, mapnum, hostaddrs, sizes, kinds, true);
|
|
}
|
|
@@ -1986,11 +2015,20 @@ GOMP_target_enter_exit_data (int device,
|
|
struct gomp_team *team = thr->ts.team;
|
|
/* If parallel or taskgroup has been cancelled, don't start new
|
|
tasks. */
|
|
- if (team
|
|
- && (gomp_team_barrier_cancelled (&team->barrier)
|
|
- || (thr->task->taskgroup
|
|
- && thr->task->taskgroup->cancelled)))
|
|
- return;
|
|
+ if (__builtin_expect (gomp_cancel_var, 0) && team)
|
|
+ {
|
|
+ if (gomp_team_barrier_cancelled (&team->barrier))
|
|
+ return;
|
|
+ if (thr->task->taskgroup)
|
|
+ {
|
|
+ if (thr->task->taskgroup->cancelled)
|
|
+ return;
|
|
+ if (thr->task->taskgroup->workshare
|
|
+ && thr->task->taskgroup->prev
|
|
+ && thr->task->taskgroup->prev->cancelled)
|
|
+ return;
|
|
+ }
|
|
+ }
|
|
|
|
gomp_task_maybe_wait_for_dependencies (depend);
|
|
}
|
|
@@ -2005,10 +2043,20 @@ GOMP_target_enter_exit_data (int device,
|
|
struct gomp_thread *thr = gomp_thread ();
|
|
struct gomp_team *team = thr->ts.team;
|
|
/* If parallel or taskgroup has been cancelled, don't start new tasks. */
|
|
- if (team
|
|
- && (gomp_team_barrier_cancelled (&team->barrier)
|
|
- || (thr->task->taskgroup && thr->task->taskgroup->cancelled)))
|
|
- return;
|
|
+ if (__builtin_expect (gomp_cancel_var, 0) && team)
|
|
+ {
|
|
+ if (gomp_team_barrier_cancelled (&team->barrier))
|
|
+ return;
|
|
+ if (thr->task->taskgroup)
|
|
+ {
|
|
+ if (thr->task->taskgroup->cancelled)
|
|
+ return;
|
|
+ if (thr->task->taskgroup->workshare
|
|
+ && thr->task->taskgroup->prev
|
|
+ && thr->task->taskgroup->prev->cancelled)
|
|
+ return;
|
|
+ }
|
|
+ }
|
|
|
|
size_t i;
|
|
if ((flags & GOMP_TARGET_FLAG_EXIT_DATA) == 0)
|
|
@@ -2197,8 +2245,9 @@ omp_target_is_present (void *ptr, int de
|
|
}
|
|
|
|
int
|
|
-omp_target_memcpy (void *dst, void *src, size_t length, size_t dst_offset,
|
|
- size_t src_offset, int dst_device_num, int src_device_num)
|
|
+omp_target_memcpy (void *dst, void *src, size_t length,
|
|
+ size_t dst_offset, size_t src_offset, int dst_device_num,
|
|
+ int src_device_num)
|
|
{
|
|
struct gomp_device_descr *dst_devicep = NULL, *src_devicep = NULL;
|
|
bool ret;
|
|
@@ -2287,21 +2336,25 @@ omp_target_memcpy_rect_worker (void *dst
|
|
return EINVAL;
|
|
if (dst_devicep == NULL && src_devicep == NULL)
|
|
{
|
|
- memcpy ((char *) dst + dst_off, (char *) src + src_off, length);
|
|
+ memcpy ((char *) dst + dst_off, (char *) src + src_off,
|
|
+ length);
|
|
ret = 1;
|
|
}
|
|
else if (src_devicep == NULL)
|
|
ret = dst_devicep->host2dev_func (dst_devicep->target_id,
|
|
(char *) dst + dst_off,
|
|
- (char *) src + src_off, length);
|
|
+ (char *) src + src_off,
|
|
+ length);
|
|
else if (dst_devicep == NULL)
|
|
ret = src_devicep->dev2host_func (src_devicep->target_id,
|
|
(char *) dst + dst_off,
|
|
- (char *) src + src_off, length);
|
|
+ (char *) src + src_off,
|
|
+ length);
|
|
else if (src_devicep == dst_devicep)
|
|
ret = src_devicep->dev2dev_func (src_devicep->target_id,
|
|
(char *) dst + dst_off,
|
|
- (char *) src + src_off, length);
|
|
+ (char *) src + src_off,
|
|
+ length);
|
|
else
|
|
ret = 0;
|
|
return ret ? 0 : EINVAL;
|
|
@@ -2396,8 +2449,8 @@ omp_target_memcpy_rect (void *dst, void
|
|
}
|
|
|
|
int
|
|
-omp_target_associate_ptr (void *host_ptr, void *device_ptr, size_t size,
|
|
- size_t device_offset, int device_num)
|
|
+omp_target_associate_ptr (void *host_ptr, void *device_ptr,
|
|
+ size_t size, size_t device_offset, int device_num)
|
|
{
|
|
if (device_num == GOMP_DEVICE_HOST_FALLBACK)
|
|
return EINVAL;
|
|
@@ -2499,6 +2552,31 @@ omp_target_disassociate_ptr (void *ptr,
|
|
return ret;
|
|
}
|
|
|
|
+int
|
|
+omp_pause_resource (omp_pause_resource_t kind, int device_num)
|
|
+{
|
|
+ (void) kind;
|
|
+ if (device_num == GOMP_DEVICE_HOST_FALLBACK)
|
|
+ return gomp_pause_host ();
|
|
+ if (device_num < 0 || device_num >= gomp_get_num_devices ())
|
|
+ return -1;
|
|
+ /* Do nothing for target devices for now. */
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+int
|
|
+omp_pause_resource_all (omp_pause_resource_t kind)
|
|
+{
|
|
+ (void) kind;
|
|
+ if (gomp_pause_host ())
|
|
+ return -1;
|
|
+ /* Do nothing for target devices for now. */
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+ialias (omp_pause_resource)
|
|
+ialias (omp_pause_resource_all)
|
|
+
|
|
#ifdef PLUGIN_SUPPORT
|
|
|
|
/* This function tries to load a plugin for DEVICE. Name of plugin is passed
|
|
@@ -2632,9 +2710,9 @@ gomp_target_fini (void)
|
|
}
|
|
}
|
|
|
|
-/* This function initializes the runtime needed for offloading.
|
|
- It parses the list of offload targets and tries to load the plugins for
|
|
- these targets. On return, the variables NUM_DEVICES and NUM_DEVICES_OPENMP
|
|
+/* This function initializes the runtime for offloading.
|
|
+ It parses the list of offload plugins, and tries to load these.
|
|
+ On return, the variables NUM_DEVICES and NUM_DEVICES_OPENMP
|
|
will be set, and the array DEVICES initialized, containing descriptors for
|
|
corresponding devices, first the GOMP_OFFLOAD_CAP_OPENMP_400 ones, follows
|
|
by the others. */
|
|
@@ -2651,7 +2729,7 @@ gomp_target_init (void)
|
|
num_devices = 0;
|
|
devices = NULL;
|
|
|
|
- cur = OFFLOAD_TARGETS;
|
|
+ cur = OFFLOAD_PLUGINS;
|
|
if (*cur)
|
|
do
|
|
{
|
|
--- libgomp/ordered.c.jj 2018-04-25 09:40:31.926655587 +0200
|
|
+++ libgomp/ordered.c 2019-05-07 18:46:36.532109640 +0200
|
|
@@ -259,7 +259,8 @@ GOMP_ordered_end (void)
|
|
#define MAX_COLLAPSED_BITS (__SIZEOF_LONG__ * __CHAR_BIT__)
|
|
|
|
void
|
|
-gomp_doacross_init (unsigned ncounts, long *counts, long chunk_size)
|
|
+gomp_doacross_init (unsigned ncounts, long *counts, long chunk_size,
|
|
+ size_t extra)
|
|
{
|
|
struct gomp_thread *thr = gomp_thread ();
|
|
struct gomp_team *team = thr->ts.team;
|
|
@@ -269,13 +270,24 @@ gomp_doacross_init (unsigned ncounts, lo
|
|
struct gomp_doacross_work_share *doacross;
|
|
|
|
if (team == NULL || team->nthreads == 1)
|
|
- return;
|
|
+ {
|
|
+ empty:
|
|
+ if (!extra)
|
|
+ ws->doacross = NULL;
|
|
+ else
|
|
+ {
|
|
+ doacross = gomp_malloc_cleared (sizeof (*doacross) + extra);
|
|
+ doacross->extra = (void *) (doacross + 1);
|
|
+ ws->doacross = doacross;
|
|
+ }
|
|
+ return;
|
|
+ }
|
|
|
|
for (i = 0; i < ncounts; i++)
|
|
{
|
|
/* If any count is 0, GOMP_doacross_{post,wait} can't be called. */
|
|
if (counts[i] == 0)
|
|
- return;
|
|
+ goto empty;
|
|
|
|
if (num_bits <= MAX_COLLAPSED_BITS)
|
|
{
|
|
@@ -314,7 +326,7 @@ gomp_doacross_init (unsigned ncounts, lo
|
|
elt_sz = (elt_sz + 63) & ~63UL;
|
|
|
|
doacross = gomp_malloc (sizeof (*doacross) + 63 + num_ents * elt_sz
|
|
- + shift_sz);
|
|
+ + shift_sz + extra);
|
|
doacross->chunk_size = chunk_size;
|
|
doacross->elt_sz = elt_sz;
|
|
doacross->ncounts = ncounts;
|
|
@@ -322,6 +334,13 @@ gomp_doacross_init (unsigned ncounts, lo
|
|
doacross->array = (unsigned char *)
|
|
((((uintptr_t) (doacross + 1)) + 63 + shift_sz)
|
|
& ~(uintptr_t) 63);
|
|
+ if (extra)
|
|
+ {
|
|
+ doacross->extra = doacross->array + num_ents * elt_sz;
|
|
+ memset (doacross->extra, '\0', extra);
|
|
+ }
|
|
+ else
|
|
+ doacross->extra = NULL;
|
|
if (num_bits <= MAX_COLLAPSED_BITS)
|
|
{
|
|
unsigned int shift_count = 0;
|
|
@@ -360,7 +379,8 @@ GOMP_doacross_post (long *counts)
|
|
unsigned long ent;
|
|
unsigned int i;
|
|
|
|
- if (__builtin_expect (doacross == NULL, 0))
|
|
+ if (__builtin_expect (doacross == NULL, 0)
|
|
+ || __builtin_expect (doacross->array == NULL, 0))
|
|
{
|
|
__sync_synchronize ();
|
|
return;
|
|
@@ -411,7 +431,8 @@ GOMP_doacross_wait (long first, ...)
|
|
unsigned long ent;
|
|
unsigned int i;
|
|
|
|
- if (__builtin_expect (doacross == NULL, 0))
|
|
+ if (__builtin_expect (doacross == NULL, 0)
|
|
+ || __builtin_expect (doacross->array == NULL, 0))
|
|
{
|
|
__sync_synchronize ();
|
|
return;
|
|
@@ -488,7 +509,8 @@ GOMP_doacross_wait (long first, ...)
|
|
typedef unsigned long long gomp_ull;
|
|
|
|
void
|
|
-gomp_doacross_ull_init (unsigned ncounts, gomp_ull *counts, gomp_ull chunk_size)
|
|
+gomp_doacross_ull_init (unsigned ncounts, gomp_ull *counts,
|
|
+ gomp_ull chunk_size, size_t extra)
|
|
{
|
|
struct gomp_thread *thr = gomp_thread ();
|
|
struct gomp_team *team = thr->ts.team;
|
|
@@ -498,13 +520,24 @@ gomp_doacross_ull_init (unsigned ncounts
|
|
struct gomp_doacross_work_share *doacross;
|
|
|
|
if (team == NULL || team->nthreads == 1)
|
|
- return;
|
|
+ {
|
|
+ empty:
|
|
+ if (!extra)
|
|
+ ws->doacross = NULL;
|
|
+ else
|
|
+ {
|
|
+ doacross = gomp_malloc_cleared (sizeof (*doacross) + extra);
|
|
+ doacross->extra = (void *) (doacross + 1);
|
|
+ ws->doacross = doacross;
|
|
+ }
|
|
+ return;
|
|
+ }
|
|
|
|
for (i = 0; i < ncounts; i++)
|
|
{
|
|
/* If any count is 0, GOMP_doacross_{post,wait} can't be called. */
|
|
if (counts[i] == 0)
|
|
- return;
|
|
+ goto empty;
|
|
|
|
if (num_bits <= MAX_COLLAPSED_BITS)
|
|
{
|
|
@@ -557,6 +590,13 @@ gomp_doacross_ull_init (unsigned ncounts
|
|
doacross->array = (unsigned char *)
|
|
((((uintptr_t) (doacross + 1)) + 63 + shift_sz)
|
|
& ~(uintptr_t) 63);
|
|
+ if (extra)
|
|
+ {
|
|
+ doacross->extra = doacross->array + num_ents * elt_sz;
|
|
+ memset (doacross->extra, '\0', extra);
|
|
+ }
|
|
+ else
|
|
+ doacross->extra = NULL;
|
|
if (num_bits <= MAX_COLLAPSED_BITS)
|
|
{
|
|
unsigned int shift_count = 0;
|
|
@@ -595,7 +635,8 @@ GOMP_doacross_ull_post (gomp_ull *counts
|
|
unsigned long ent;
|
|
unsigned int i;
|
|
|
|
- if (__builtin_expect (doacross == NULL, 0))
|
|
+ if (__builtin_expect (doacross == NULL, 0)
|
|
+ || __builtin_expect (doacross->array == NULL, 0))
|
|
{
|
|
__sync_synchronize ();
|
|
return;
|
|
@@ -667,7 +708,8 @@ GOMP_doacross_ull_wait (gomp_ull first,
|
|
unsigned long ent;
|
|
unsigned int i;
|
|
|
|
- if (__builtin_expect (doacross == NULL, 0))
|
|
+ if (__builtin_expect (doacross == NULL, 0)
|
|
+ || __builtin_expect (doacross->array == NULL, 0))
|
|
{
|
|
__sync_synchronize ();
|
|
return;
|
|
--- libgomp/alloc.c.jj 2018-04-25 09:40:31.926655587 +0200
|
|
+++ libgomp/alloc.c 2019-05-07 18:46:36.336112770 +0200
|
|
@@ -57,3 +57,50 @@ gomp_realloc (void *old, size_t size)
|
|
gomp_fatal ("Out of memory allocating %lu bytes", (unsigned long) size);
|
|
return ret;
|
|
}
|
|
+
|
|
+void *
|
|
+gomp_aligned_alloc (size_t al, size_t size)
|
|
+{
|
|
+ void *ret;
|
|
+ if (al < sizeof (void *))
|
|
+ al = sizeof (void *);
|
|
+#ifdef HAVE_ALIGNED_ALLOC
|
|
+ ret = aligned_alloc (al, size);
|
|
+#elif defined(HAVE__ALIGNED_MALLOC)
|
|
+ ret = _aligned_malloc (size, al);
|
|
+#elif defined(HAVE_POSIX_MEMALIGN)
|
|
+ if (posix_memalign (&ret, al, size) != 0)
|
|
+ ret = NULL;
|
|
+#elif defined(HAVE_MEMALIGN)
|
|
+ {
|
|
+ extern void *memalign (size_t, size_t);
|
|
+ ret = memalign (al, size);
|
|
+ }
|
|
+#else
|
|
+ ret = NULL;
|
|
+ if ((al & (al - 1)) == 0 && size)
|
|
+ {
|
|
+ void *p = malloc (size + al);
|
|
+ if (p)
|
|
+ {
|
|
+ void *ap = (void *) (((uintptr_t) p + al) & -al);
|
|
+ ((void **) ap)[-1] = p;
|
|
+ ret = ap;
|
|
+ }
|
|
+ }
|
|
+#endif
|
|
+ if (ret == NULL)
|
|
+ gomp_fatal ("Out of memory allocating %lu bytes", (unsigned long) size);
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+void
|
|
+gomp_aligned_free (void *ptr)
|
|
+{
|
|
+#ifdef GOMP_HAVE_EFFICIENT_ALIGNED_ALLOC
|
|
+ free (ptr);
|
|
+#else
|
|
+ if (ptr)
|
|
+ free (((void **) ptr)[-1]);
|
|
+#endif
|
|
+}
|
|
--- libgomp/configure.ac.jj 2018-04-25 09:40:31.321655307 +0200
|
|
+++ libgomp/configure.ac 2019-05-07 18:46:36.471110614 +0200
|
|
@@ -219,6 +219,7 @@ m4_include([plugin/configfrag.ac])
|
|
|
|
# Check for functions needed.
|
|
AC_CHECK_FUNCS(getloadavg clock_gettime strtoull)
|
|
+AC_CHECK_FUNCS(aligned_alloc posix_memalign memalign _aligned_malloc)
|
|
|
|
# Check for broken semaphore implementation on darwin.
|
|
# sem_init returns: sem_init error: Function not implemented.
|
|
@@ -266,6 +267,41 @@ if test $ac_cv_func_clock_gettime = no;
|
|
[Define to 1 if you have the `clock_gettime' function.])])
|
|
fi
|
|
|
|
+# Check for uname.
|
|
+AC_COMPILE_IFELSE(
|
|
+ [AC_LANG_PROGRAM(
|
|
+ [#include <string.h>
|
|
+ #include <stdlib.h>
|
|
+ #include <sys/utsname.h>],
|
|
+ [struct utsname buf;
|
|
+ volatile size_t len = 0;
|
|
+ if (!uname (buf))
|
|
+ len = strlen (buf.nodename);])],
|
|
+ AC_DEFINE(HAVE_UNAME, 1,
|
|
+[ Define if uname is supported and struct utsname has nodename field.]))
|
|
+
|
|
+# Check for gethostname.
|
|
+AC_COMPILE_IFELSE(
|
|
+ [AC_LANG_PROGRAM(
|
|
+ [#include <unistd.h>],
|
|
+ [
|
|
+changequote(,)dnl
|
|
+ char buf[256];
|
|
+ if (gethostname (buf, sizeof (buf) - 1) == 0)
|
|
+ buf[255] = '\0';
|
|
+changequote([,])dnl
|
|
+ ])],
|
|
+ AC_DEFINE(HAVE_GETHOSTNAME, 1,
|
|
+[ Define if gethostname is supported.]))
|
|
+
|
|
+# Check for getpid.
|
|
+AC_COMPILE_IFELSE(
|
|
+ [AC_LANG_PROGRAM(
|
|
+ [#include <unistd.h>],
|
|
+ [int pid = getpid ();])],
|
|
+ AC_DEFINE(HAVE_GETPID, 1,
|
|
+[ Define if getpid is supported.]))
|
|
+
|
|
# See if we support thread-local storage.
|
|
GCC_CHECK_TLS
|
|
|
|
--- libgomp/icv.c.jj 2018-04-25 09:40:31.870655561 +0200
|
|
+++ libgomp/icv.c 2019-05-07 18:46:36.501110134 +0200
|
|
@@ -69,7 +69,7 @@ void
|
|
omp_set_schedule (omp_sched_t kind, int chunk_size)
|
|
{
|
|
struct gomp_task_icv *icv = gomp_icv (true);
|
|
- switch (kind)
|
|
+ switch (kind & ~omp_sched_monotonic)
|
|
{
|
|
case omp_sched_static:
|
|
if (chunk_size < 1)
|
|
--- libgomp/configure.jj 2018-04-25 09:40:31.913655581 +0200
|
|
+++ libgomp/configure 2019-05-07 18:47:37.961128420 +0200
|
|
@@ -636,6 +636,8 @@ PLUGIN_NVPTX_FALSE
|
|
PLUGIN_NVPTX_TRUE
|
|
offload_additional_lib_paths
|
|
offload_additional_options
|
|
+offload_targets
|
|
+offload_plugins
|
|
PLUGIN_HSA_LIBS
|
|
PLUGIN_HSA_LDFLAGS
|
|
PLUGIN_HSA_CPPFLAGS
|
|
@@ -648,7 +650,6 @@ PLUGIN_NVPTX_CPPFLAGS
|
|
PLUGIN_NVPTX
|
|
CUDA_DRIVER_LIB
|
|
CUDA_DRIVER_INCLUDE
|
|
-offload_targets
|
|
libtool_VERSION
|
|
ac_ct_FC
|
|
FCFLAGS
|
|
@@ -11157,7 +11158,7 @@ else
|
|
lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
|
|
lt_status=$lt_dlunknown
|
|
cat > conftest.$ac_ext <<_LT_EOF
|
|
-#line 11160 "configure"
|
|
+#line 11161 "configure"
|
|
#include "confdefs.h"
|
|
|
|
#if HAVE_DLFCN_H
|
|
@@ -11263,7 +11264,7 @@ else
|
|
lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
|
|
lt_status=$lt_dlunknown
|
|
cat > conftest.$ac_ext <<_LT_EOF
|
|
-#line 11266 "configure"
|
|
+#line 11267 "configure"
|
|
#include "confdefs.h"
|
|
|
|
#if HAVE_DLFCN_H
|
|
@@ -15167,8 +15168,6 @@ fi
|
|
# see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
|
|
# <http://www.gnu.org/licenses/>.
|
|
|
|
-offload_targets=
|
|
-
|
|
plugin_support=yes
|
|
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlsym in -ldl" >&5
|
|
$as_echo_n "checking for dlsym in -ldl... " >&6; }
|
|
@@ -15302,7 +15301,11 @@ if test "${with_cuda_driver_lib+set}" =
|
|
fi
|
|
|
|
case "x$with_cuda_driver" in
|
|
- x | xno) ;;
|
|
+ x) ;;
|
|
+ xno)
|
|
+ CUDA_DRIVER_INCLUDE=no
|
|
+ CUDA_DRIVER_LIB=no
|
|
+ ;;
|
|
*) CUDA_DRIVER_INCLUDE=$with_cuda_driver/include
|
|
CUDA_DRIVER_LIB=$with_cuda_driver/lib
|
|
;;
|
|
@@ -15313,10 +15316,12 @@ fi
|
|
if test "x$with_cuda_driver_lib" != x; then
|
|
CUDA_DRIVER_LIB=$with_cuda_driver_lib
|
|
fi
|
|
-if test "x$CUDA_DRIVER_INCLUDE" != x; then
|
|
+if test "x$CUDA_DRIVER_INCLUDE" != x \
|
|
+ && test "x$CUDA_DRIVER_INCLUDE" != xno; then
|
|
CUDA_DRIVER_CPPFLAGS=-I$CUDA_DRIVER_INCLUDE
|
|
fi
|
|
-if test "x$CUDA_DRIVER_LIB" != x; then
|
|
+if test "x$CUDA_DRIVER_LIB" != x \
|
|
+ && test "x$CUDA_DRIVER_LIB" != xno; then
|
|
CUDA_DRIVER_LDFLAGS=-L$CUDA_DRIVER_LIB
|
|
fi
|
|
|
|
@@ -15383,7 +15388,13 @@ PLUGIN_HSA_LIBS=
|
|
|
|
|
|
|
|
-# Get offload targets and path to install tree of offloading compiler.
|
|
+# Parse '--enable-offload-targets', figure out the corresponding libgomp
|
|
+# plugins, and configure to find the corresponding offload compilers.
|
|
+# 'offload_plugins' and 'offload_targets' will be populated in the same order.
|
|
+offload_plugins=
|
|
+offload_targets=
|
|
+
|
|
+
|
|
offload_additional_options=
|
|
offload_additional_lib_paths=
|
|
|
|
@@ -15403,10 +15403,10 @@ if test x"$enable_offload_targets" != x;
|
|
for tgt in `echo $enable_offload_targets | sed -e 's#,# #g'`; do
|
|
tgt_dir=`echo $tgt | grep '=' | sed 's/.*=//'`
|
|
tgt=`echo $tgt | sed 's/=.*//'`
|
|
- tgt_name=
|
|
+ tgt_plugin=
|
|
case $tgt in
|
|
*-intelmic-* | *-intelmicemul-*)
|
|
- tgt_name=intelmic
|
|
+ tgt_plugin=intelmic
|
|
;;
|
|
nvptx*)
|
|
case "${target}" in
|
|
@@ -15418,19 +15418,21 @@ if test x"$enable_offload_targets" != x;
|
|
PLUGIN_NVPTX=0
|
|
;;
|
|
*)
|
|
- tgt_name=nvptx
|
|
+ tgt_plugin=nvptx
|
|
PLUGIN_NVPTX=$tgt
|
|
- PLUGIN_NVPTX_CPPFLAGS=$CUDA_DRIVER_CPPFLAGS
|
|
- PLUGIN_NVPTX_LDFLAGS=$CUDA_DRIVER_LDFLAGS
|
|
- PLUGIN_NVPTX_LIBS='-lcuda'
|
|
+ if test "x$CUDA_DRIVER_LIB" != xno \
|
|
+ && test "x$CUDA_DRIVER_LIB" != xno; then
|
|
+ PLUGIN_NVPTX_CPPFLAGS=$CUDA_DRIVER_CPPFLAGS
|
|
+ PLUGIN_NVPTX_LDFLAGS=$CUDA_DRIVER_LDFLAGS
|
|
+ PLUGIN_NVPTX_LIBS='-lcuda'
|
|
|
|
- PLUGIN_NVPTX_save_CPPFLAGS=$CPPFLAGS
|
|
- CPPFLAGS="$PLUGIN_NVPTX_CPPFLAGS $CPPFLAGS"
|
|
- PLUGIN_NVPTX_save_LDFLAGS=$LDFLAGS
|
|
- LDFLAGS="$PLUGIN_NVPTX_LDFLAGS $LDFLAGS"
|
|
- PLUGIN_NVPTX_save_LIBS=$LIBS
|
|
- LIBS="$PLUGIN_NVPTX_LIBS $LIBS"
|
|
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
|
|
+ PLUGIN_NVPTX_save_CPPFLAGS=$CPPFLAGS
|
|
+ CPPFLAGS="$PLUGIN_NVPTX_CPPFLAGS $CPPFLAGS"
|
|
+ PLUGIN_NVPTX_save_LDFLAGS=$LDFLAGS
|
|
+ LDFLAGS="$PLUGIN_NVPTX_LDFLAGS $LDFLAGS"
|
|
+ PLUGIN_NVPTX_save_LIBS=$LIBS
|
|
+ LIBS="$PLUGIN_NVPTX_LIBS $LIBS"
|
|
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
|
|
/* end confdefs.h. */
|
|
#include "cuda.h"
|
|
int
|
|
@@ -15446,13 +15448,16 @@ if ac_fn_c_try_link "$LINENO"; then :
|
|
fi
|
|
rm -f core conftest.err conftest.$ac_objext \
|
|
conftest$ac_exeext conftest.$ac_ext
|
|
- CPPFLAGS=$PLUGIN_NVPTX_save_CPPFLAGS
|
|
- LDFLAGS=$PLUGIN_NVPTX_save_LDFLAGS
|
|
- LIBS=$PLUGIN_NVPTX_save_LIBS
|
|
+ CPPFLAGS=$PLUGIN_NVPTX_save_CPPFLAGS
|
|
+ LDFLAGS=$PLUGIN_NVPTX_save_LDFLAGS
|
|
+ LIBS=$PLUGIN_NVPTX_save_LIBS
|
|
+ fi
|
|
case $PLUGIN_NVPTX in
|
|
nvptx*)
|
|
- if test "x$CUDA_DRIVER_INCLUDE" = x \
|
|
- && test "x$CUDA_DRIVER_LIB" = x; then
|
|
+ if (test "x$CUDA_DRIVER_INCLUDE" = x \
|
|
+ || test "x$CUDA_DRIVER_INCLUDE" = xno) \
|
|
+ && (test "x$CUDA_DRIVER_LIB" = x \
|
|
+ || test "x$CUDA_DRIVER_LIB" = xno); then
|
|
PLUGIN_NVPTX=1
|
|
PLUGIN_NVPTX_CPPFLAGS='-I$(srcdir)/plugin/cuda'
|
|
PLUGIN_NVPTX_LIBS='-ldl'
|
|
@@ -15452,7 +15468,7 @@ rm -f core conftest.err conftest.$ac_obj
|
|
PLUGIN_HSA=0
|
|
;;
|
|
*)
|
|
- tgt_name=hsa
|
|
+ tgt_plugin=hsa
|
|
PLUGIN_HSA=$tgt
|
|
PLUGIN_HSA_CPPFLAGS=$HSA_RUNTIME_CPPFLAGS
|
|
PLUGIN_HSA_LDFLAGS="$HSA_RUNTIME_LDFLAGS"
|
|
@@ -15470,7 +15486,7 @@ rm -f core conftest.err conftest.$ac_obj
|
|
LDFLAGS=$PLUGIN_HSA_save_LDFLAGS
|
|
LIBS=$PLUGIN_HSA_save_LIBS
|
|
case $PLUGIN_HSA in
|
|
- hsa*)
|
|
+ hsa*)
|
|
HSA_PLUGIN=0
|
|
as_fn_error "HSA run-time package required for HSA support" "$LINENO" 5
|
|
;;
|
|
@@ -15487,16 +15503,19 @@ rm -f core conftest.err conftest.$ac_obj
|
|
as_fn_error "unknown offload target specified" "$LINENO" 5
|
|
;;
|
|
esac
|
|
- if test x"$tgt_name" = x; then
|
|
- # Don't configure libgomp for this offloading target if we don't build
|
|
- # the corresponding plugin.
|
|
+ if test x"$tgt_plugin" = x; then
|
|
+ # Not configuring libgomp for this offload target if we're not building
|
|
+ # the corresponding offload plugin.
|
|
continue
|
|
- elif test x"$offload_targets" = x; then
|
|
- offload_targets=$tgt_name
|
|
+ elif test x"$offload_plugins" = x; then
|
|
+ offload_plugins=$tgt_plugin
|
|
+ offload_targets=$tgt
|
|
else
|
|
- offload_targets=$offload_targets,$tgt_name
|
|
+ offload_plugins=$offload_plugins,$tgt_plugin
|
|
+ offload_targets=$offload_targets,$tgt
|
|
fi
|
|
- if test "$tgt_name" = hsa; then
|
|
+ # Configure additional search paths.
|
|
+ if test "$tgt_plugin" = hsa; then
|
|
# Offloading compilation is all handled by the target compiler.
|
|
:
|
|
elif test x"$tgt_dir" != x; then
|
|
@@ -15510,7 +15529,7 @@ rm -f core conftest.err conftest.$ac_obj
|
|
fi
|
|
|
|
cat >>confdefs.h <<_ACEOF
|
|
-#define OFFLOAD_TARGETS "$offload_targets"
|
|
+#define OFFLOAD_PLUGINS "$offload_plugins"
|
|
_ACEOF
|
|
|
|
if test $PLUGIN_NVPTX = 1; then
|
|
@@ -15570,6 +15589,19 @@ _ACEOF
|
|
fi
|
|
done
|
|
|
|
+for ac_func in aligned_alloc posix_memalign memalign _aligned_malloc
|
|
+do :
|
|
+ as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
|
|
+ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var"
|
|
+eval as_val=\$$as_ac_var
|
|
+ if test "x$as_val" = x""yes; then :
|
|
+ cat >>confdefs.h <<_ACEOF
|
|
+#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1
|
|
+_ACEOF
|
|
+
|
|
+fi
|
|
+done
|
|
+
|
|
|
|
# Check for broken semaphore implementation on darwin.
|
|
# sem_init returns: sem_init error: Function not implemented.
|
|
@@ -15784,6 +15816,72 @@ fi
|
|
|
|
fi
|
|
|
|
+# Check for uname.
|
|
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
|
|
+/* end confdefs.h. */
|
|
+#include <string.h>
|
|
+ #include <stdlib.h>
|
|
+ #include <sys/utsname.h>
|
|
+int
|
|
+main ()
|
|
+{
|
|
+struct utsname buf;
|
|
+ volatile size_t len = 0;
|
|
+ if (!uname (buf))
|
|
+ len = strlen (buf.nodename);
|
|
+ ;
|
|
+ return 0;
|
|
+}
|
|
+_ACEOF
|
|
+if ac_fn_c_try_compile "$LINENO"; then :
|
|
+
|
|
+$as_echo "#define HAVE_UNAME 1" >>confdefs.h
|
|
+
|
|
+fi
|
|
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
|
|
+
|
|
+# Check for gethostname.
|
|
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
|
|
+/* end confdefs.h. */
|
|
+#include <unistd.h>
|
|
+int
|
|
+main ()
|
|
+{
|
|
+
|
|
+ char buf[256];
|
|
+ if (gethostname (buf, sizeof (buf) - 1) == 0)
|
|
+ buf[255] = '\0';
|
|
+
|
|
+ ;
|
|
+ return 0;
|
|
+}
|
|
+_ACEOF
|
|
+if ac_fn_c_try_compile "$LINENO"; then :
|
|
+
|
|
+$as_echo "#define HAVE_GETHOSTNAME 1" >>confdefs.h
|
|
+
|
|
+fi
|
|
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
|
|
+
|
|
+# Check for getpid.
|
|
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
|
|
+/* end confdefs.h. */
|
|
+#include <unistd.h>
|
|
+int
|
|
+main ()
|
|
+{
|
|
+int pid = getpid ();
|
|
+ ;
|
|
+ return 0;
|
|
+}
|
|
+_ACEOF
|
|
+if ac_fn_c_try_compile "$LINENO"; then :
|
|
+
|
|
+$as_echo "#define HAVE_GETPID 1" >>confdefs.h
|
|
+
|
|
+fi
|
|
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
|
|
+
|
|
# See if we support thread-local storage.
|
|
|
|
|
|
--- libgomp/Makefile.am.jj 2018-04-25 09:40:31.926655587 +0200
|
|
+++ libgomp/Makefile.am 2019-05-07 19:59:03.683989317 +0200
|
|
@@ -63,12 +63,13 @@ libgomp_la_SOURCES = alloc.c atomic.c ba
|
|
parallel.c sections.c single.c task.c team.c work.c lock.c mutex.c \
|
|
proc.c sem.c bar.c ptrlock.c time.c fortran.c affinity.c target.c \
|
|
splay-tree.c libgomp-plugin.c oacc-parallel.c oacc-host.c oacc-init.c \
|
|
- oacc-mem.c oacc-async.c oacc-plugin.c oacc-cuda.c priority_queue.c
|
|
+ oacc-mem.c oacc-async.c oacc-plugin.c oacc-cuda.c priority_queue.c \
|
|
+ affinity-fmt.c teams.c
|
|
|
|
include $(top_srcdir)/plugin/Makefrag.am
|
|
|
|
if USE_FORTRAN
|
|
-libgomp_la_SOURCES += openacc.f90
|
|
+libgomp_la_SOURCES += openacc2.f90
|
|
endif
|
|
|
|
nodist_noinst_HEADERS = libgomp_f.h
|
|
@@ -87,8 +88,6 @@ omp_lib_kinds.mod: omp_lib.mod
|
|
:
|
|
openacc_kinds.mod: openacc.mod
|
|
:
|
|
-openacc.mod: openacc.lo
|
|
- :
|
|
%.mod: %.f90
|
|
$(FC) $(FCFLAGS) -fsyntax-only $<
|
|
fortran.lo: libgomp_f.h
|
|
--- libgomp/oacc-mem.c.jj 2018-04-25 09:40:31.924655586 +0200
|
|
+++ libgomp/oacc-mem.c 2019-05-07 18:46:36.530109672 +0200
|
|
@@ -153,8 +153,9 @@ acc_free (void *d)
|
|
gomp_fatal ("error in freeing device memory in %s", __FUNCTION__);
|
|
}
|
|
|
|
-void
|
|
-acc_memcpy_to_device (void *d, void *h, size_t s)
|
|
+static void
|
|
+memcpy_tofrom_device (bool from, void *d, void *h, size_t s, int async,
|
|
+ const char *libfnname)
|
|
{
|
|
/* No need to call lazy open here, as the device pointer must have
|
|
been obtained from a routine that did that. */
|
|
@@ -164,31 +165,49 @@ acc_memcpy_to_device (void *d, void *h,
|
|
|
|
if (thr->dev->capabilities & GOMP_OFFLOAD_CAP_SHARED_MEM)
|
|
{
|
|
- memmove (d, h, s);
|
|
+ if (from)
|
|
+ memmove (h, d, s);
|
|
+ else
|
|
+ memmove (d, h, s);
|
|
return;
|
|
}
|
|
|
|
- if (!thr->dev->host2dev_func (thr->dev->target_id, d, h, s))
|
|
- gomp_fatal ("error in %s", __FUNCTION__);
|
|
+ if (async > acc_async_sync)
|
|
+ thr->dev->openacc.async_set_async_func (async);
|
|
+
|
|
+ bool ret = (from
|
|
+ ? thr->dev->dev2host_func (thr->dev->target_id, h, d, s)
|
|
+ : thr->dev->host2dev_func (thr->dev->target_id, d, h, s));
|
|
+
|
|
+ if (async > acc_async_sync)
|
|
+ thr->dev->openacc.async_set_async_func (acc_async_sync);
|
|
+
|
|
+ if (!ret)
|
|
+ gomp_fatal ("error in %s", libfnname);
|
|
}
|
|
|
|
void
|
|
-acc_memcpy_from_device (void *h, void *d, size_t s)
|
|
+acc_memcpy_to_device (void *d, void *h, size_t s)
|
|
{
|
|
- /* No need to call lazy open here, as the device pointer must have
|
|
- been obtained from a routine that did that. */
|
|
- struct goacc_thread *thr = goacc_thread ();
|
|
+ memcpy_tofrom_device (false, d, h, s, acc_async_sync, __FUNCTION__);
|
|
+}
|
|
|
|
- assert (thr && thr->dev);
|
|
+void
|
|
+acc_memcpy_to_device_async (void *d, void *h, size_t s, int async)
|
|
+{
|
|
+ memcpy_tofrom_device (false, d, h, s, async, __FUNCTION__);
|
|
+}
|
|
|
|
- if (thr->dev->capabilities & GOMP_OFFLOAD_CAP_SHARED_MEM)
|
|
- {
|
|
- memmove (h, d, s);
|
|
- return;
|
|
- }
|
|
+void
|
|
+acc_memcpy_from_device (void *h, void *d, size_t s)
|
|
+{
|
|
+ memcpy_tofrom_device (true, d, h, s, acc_async_sync, __FUNCTION__);
|
|
+}
|
|
|
|
- if (!thr->dev->dev2host_func (thr->dev->target_id, h, d, s))
|
|
- gomp_fatal ("error in %s", __FUNCTION__);
|
|
+void
|
|
+acc_memcpy_from_device_async (void *h, void *d, size_t s, int async)
|
|
+{
|
|
+ memcpy_tofrom_device (true, d, h, s, async, __FUNCTION__);
|
|
}
|
|
|
|
/* Return the device pointer that corresponds to host data H. Or NULL
|
|
@@ -347,6 +366,7 @@ acc_map_data (void *h, void *d, size_t s
|
|
|
|
tgt = gomp_map_vars (acc_dev, mapnum, &hostaddrs, &devaddrs, &sizes,
|
|
&kinds, true, GOMP_MAP_VARS_OPENACC);
|
|
+ tgt->list[0].key->refcount = REFCOUNT_INFINITY;
|
|
}
|
|
|
|
gomp_mutex_lock (&acc_dev->lock);
|
|
@@ -389,6 +409,9 @@ acc_unmap_data (void *h)
|
|
(void *) n->host_start, (int) host_size, (void *) h);
|
|
}
|
|
|
|
+ /* Mark for removal. */
|
|
+ n->refcount = 1;
|
|
+
|
|
t = n->tgt;
|
|
|
|
if (t->refcount == 2)
|
|
@@ -424,7 +447,7 @@ acc_unmap_data (void *h)
|
|
#define FLAG_COPY (1 << 2)
|
|
|
|
static void *
|
|
-present_create_copy (unsigned f, void *h, size_t s)
|
|
+present_create_copy (unsigned f, void *h, size_t s, int async)
|
|
{
|
|
void *d;
|
|
splay_tree_key n;
|
|
@@ -460,6 +483,11 @@ present_create_copy (unsigned f, void *h
|
|
gomp_fatal ("[%p,+%d] not mapped", (void *)h, (int)s);
|
|
}
|
|
|
|
+ if (n->refcount != REFCOUNT_INFINITY)
|
|
+ {
|
|
+ n->refcount++;
|
|
+ n->dynamic_refcount++;
|
|
+ }
|
|
gomp_mutex_unlock (&acc_dev->lock);
|
|
}
|
|
else if (!(f & FLAG_CREATE))
|
|
@@ -481,8 +509,16 @@ present_create_copy (unsigned f, void *h
|
|
|
|
gomp_mutex_unlock (&acc_dev->lock);
|
|
|
|
+ if (async > acc_async_sync)
|
|
+ acc_dev->openacc.async_set_async_func (async);
|
|
+
|
|
tgt = gomp_map_vars (acc_dev, mapnum, &hostaddrs, NULL, &s, &kinds, true,
|
|
GOMP_MAP_VARS_OPENACC);
|
|
+ /* Initialize dynamic refcount. */
|
|
+ tgt->list[0].key->dynamic_refcount = 1;
|
|
+
|
|
+ if (async > acc_async_sync)
|
|
+ acc_dev->openacc.async_set_async_func (acc_async_sync);
|
|
|
|
gomp_mutex_lock (&acc_dev->lock);
|
|
|
|
@@ -499,53 +535,71 @@ present_create_copy (unsigned f, void *h
|
|
void *
|
|
acc_create (void *h, size_t s)
|
|
{
|
|
- return present_create_copy (FLAG_CREATE, h, s);
|
|
+ return present_create_copy (FLAG_PRESENT | FLAG_CREATE, h, s, acc_async_sync);
|
|
}
|
|
|
|
-void *
|
|
-acc_copyin (void *h, size_t s)
|
|
+void
|
|
+acc_create_async (void *h, size_t s, int async)
|
|
{
|
|
- return present_create_copy (FLAG_CREATE | FLAG_COPY, h, s);
|
|
+ present_create_copy (FLAG_PRESENT | FLAG_CREATE, h, s, async);
|
|
}
|
|
|
|
+/* acc_present_or_create used to be what acc_create is now. */
|
|
+/* acc_pcreate is acc_present_or_create by a different name. */
|
|
+#ifdef HAVE_ATTRIBUTE_ALIAS
|
|
+strong_alias (acc_create, acc_present_or_create)
|
|
+strong_alias (acc_create, acc_pcreate)
|
|
+#else
|
|
void *
|
|
acc_present_or_create (void *h, size_t s)
|
|
{
|
|
- return present_create_copy (FLAG_PRESENT | FLAG_CREATE, h, s);
|
|
+ return acc_create (h, s);
|
|
}
|
|
|
|
-/* acc_pcreate is acc_present_or_create by a different name. */
|
|
-#ifdef HAVE_ATTRIBUTE_ALIAS
|
|
-strong_alias (acc_present_or_create, acc_pcreate)
|
|
-#else
|
|
void *
|
|
acc_pcreate (void *h, size_t s)
|
|
{
|
|
- return acc_present_or_create (h, s);
|
|
+ return acc_create (h, s);
|
|
}
|
|
#endif
|
|
|
|
void *
|
|
-acc_present_or_copyin (void *h, size_t s)
|
|
+acc_copyin (void *h, size_t s)
|
|
+{
|
|
+ return present_create_copy (FLAG_PRESENT | FLAG_CREATE | FLAG_COPY, h, s,
|
|
+ acc_async_sync);
|
|
+}
|
|
+
|
|
+void
|
|
+acc_copyin_async (void *h, size_t s, int async)
|
|
{
|
|
- return present_create_copy (FLAG_PRESENT | FLAG_CREATE | FLAG_COPY, h, s);
|
|
+ present_create_copy (FLAG_PRESENT | FLAG_CREATE | FLAG_COPY, h, s, async);
|
|
}
|
|
|
|
+/* acc_present_or_copyin used to be what acc_copyin is now. */
|
|
/* acc_pcopyin is acc_present_or_copyin by a different name. */
|
|
#ifdef HAVE_ATTRIBUTE_ALIAS
|
|
-strong_alias (acc_present_or_copyin, acc_pcopyin)
|
|
+strong_alias (acc_copyin, acc_present_or_copyin)
|
|
+strong_alias (acc_copyin, acc_pcopyin)
|
|
#else
|
|
void *
|
|
+acc_present_or_copyin (void *h, size_t s)
|
|
+{
|
|
+ return acc_copyin (h, s);
|
|
+}
|
|
+
|
|
+void *
|
|
acc_pcopyin (void *h, size_t s)
|
|
{
|
|
- return acc_present_or_copyin (h, s);
|
|
+ return acc_copyin (h, s);
|
|
}
|
|
#endif
|
|
|
|
-#define FLAG_COPYOUT (1 << 0)
|
|
+#define FLAG_COPYOUT (1 << 0)
|
|
+#define FLAG_FINALIZE (1 << 1)
|
|
|
|
static void
|
|
-delete_copyout (unsigned f, void *h, size_t s, const char *libfnname)
|
|
+delete_copyout (unsigned f, void *h, size_t s, int async, const char *libfnname)
|
|
{
|
|
size_t host_size;
|
|
splay_tree_key n;
|
|
@@ -581,31 +635,111 @@ delete_copyout (unsigned f, void *h, siz
|
|
(void *) n->host_start, (int) host_size, (void *) h, (int) s);
|
|
}
|
|
|
|
- gomp_mutex_unlock (&acc_dev->lock);
|
|
+ if (n->refcount == REFCOUNT_INFINITY)
|
|
+ {
|
|
+ n->refcount = 0;
|
|
+ n->dynamic_refcount = 0;
|
|
+ }
|
|
+ if (n->refcount < n->dynamic_refcount)
|
|
+ {
|
|
+ gomp_mutex_unlock (&acc_dev->lock);
|
|
+ gomp_fatal ("Dynamic reference counting assert fail\n");
|
|
+ }
|
|
|
|
- if (f & FLAG_COPYOUT)
|
|
- acc_dev->dev2host_func (acc_dev->target_id, h, d, s);
|
|
+ if (f & FLAG_FINALIZE)
|
|
+ {
|
|
+ n->refcount -= n->dynamic_refcount;
|
|
+ n->dynamic_refcount = 0;
|
|
+ }
|
|
+ else if (n->dynamic_refcount)
|
|
+ {
|
|
+ n->dynamic_refcount--;
|
|
+ n->refcount--;
|
|
+ }
|
|
+
|
|
+ if (n->refcount == 0)
|
|
+ {
|
|
+ if (n->tgt->refcount == 2)
|
|
+ {
|
|
+ struct target_mem_desc *tp, *t;
|
|
+ for (tp = NULL, t = acc_dev->openacc.data_environ; t != NULL;
|
|
+ tp = t, t = t->prev)
|
|
+ if (n->tgt == t)
|
|
+ {
|
|
+ if (tp)
|
|
+ tp->prev = t->prev;
|
|
+ else
|
|
+ acc_dev->openacc.data_environ = t->prev;
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if (f & FLAG_COPYOUT)
|
|
+ {
|
|
+ if (async > acc_async_sync)
|
|
+ acc_dev->openacc.async_set_async_func (async);
|
|
+ acc_dev->dev2host_func (acc_dev->target_id, h, d, s);
|
|
+ if (async > acc_async_sync)
|
|
+ acc_dev->openacc.async_set_async_func (acc_async_sync);
|
|
+ }
|
|
|
|
- acc_unmap_data (h);
|
|
+ gomp_remove_var (acc_dev, n);
|
|
+ }
|
|
|
|
- if (!acc_dev->free_func (acc_dev->target_id, d))
|
|
- gomp_fatal ("error in freeing device memory in %s", libfnname);
|
|
+ gomp_mutex_unlock (&acc_dev->lock);
|
|
}
|
|
|
|
void
|
|
acc_delete (void *h , size_t s)
|
|
{
|
|
- delete_copyout (0, h, s, __FUNCTION__);
|
|
+ delete_copyout (0, h, s, acc_async_sync, __FUNCTION__);
|
|
+}
|
|
+
|
|
+void
|
|
+acc_delete_async (void *h , size_t s, int async)
|
|
+{
|
|
+ delete_copyout (0, h, s, async, __FUNCTION__);
|
|
+}
|
|
+
|
|
+void
|
|
+acc_delete_finalize (void *h , size_t s)
|
|
+{
|
|
+ delete_copyout (FLAG_FINALIZE, h, s, acc_async_sync, __FUNCTION__);
|
|
+}
|
|
+
|
|
+void
|
|
+acc_delete_finalize_async (void *h , size_t s, int async)
|
|
+{
|
|
+ delete_copyout (FLAG_FINALIZE, h, s, async, __FUNCTION__);
|
|
}
|
|
|
|
void
|
|
acc_copyout (void *h, size_t s)
|
|
{
|
|
- delete_copyout (FLAG_COPYOUT, h, s, __FUNCTION__);
|
|
+ delete_copyout (FLAG_COPYOUT, h, s, acc_async_sync, __FUNCTION__);
|
|
+}
|
|
+
|
|
+void
|
|
+acc_copyout_async (void *h, size_t s, int async)
|
|
+{
|
|
+ delete_copyout (FLAG_COPYOUT, h, s, async, __FUNCTION__);
|
|
+}
|
|
+
|
|
+void
|
|
+acc_copyout_finalize (void *h, size_t s)
|
|
+{
|
|
+ delete_copyout (FLAG_COPYOUT | FLAG_FINALIZE, h, s, acc_async_sync,
|
|
+ __FUNCTION__);
|
|
+}
|
|
+
|
|
+void
|
|
+acc_copyout_finalize_async (void *h, size_t s, int async)
|
|
+{
|
|
+ delete_copyout (FLAG_COPYOUT | FLAG_FINALIZE, h, s, async, __FUNCTION__);
|
|
}
|
|
|
|
static void
|
|
-update_dev_host (int is_dev, void *h, size_t s)
|
|
+update_dev_host (int is_dev, void *h, size_t s, int async)
|
|
{
|
|
splay_tree_key n;
|
|
void *d;
|
|
@@ -631,24 +765,42 @@ update_dev_host (int is_dev, void *h, si
|
|
d = (void *) (n->tgt->tgt_start + n->tgt_offset
|
|
+ (uintptr_t) h - n->host_start);
|
|
|
|
+ if (async > acc_async_sync)
|
|
+ acc_dev->openacc.async_set_async_func (async);
|
|
+
|
|
if (is_dev)
|
|
acc_dev->host2dev_func (acc_dev->target_id, d, h, s);
|
|
else
|
|
acc_dev->dev2host_func (acc_dev->target_id, h, d, s);
|
|
|
|
+ if (async > acc_async_sync)
|
|
+ acc_dev->openacc.async_set_async_func (acc_async_sync);
|
|
+
|
|
gomp_mutex_unlock (&acc_dev->lock);
|
|
}
|
|
|
|
void
|
|
acc_update_device (void *h, size_t s)
|
|
{
|
|
- update_dev_host (1, h, s);
|
|
+ update_dev_host (1, h, s, acc_async_sync);
|
|
+}
|
|
+
|
|
+void
|
|
+acc_update_device_async (void *h, size_t s, int async)
|
|
+{
|
|
+ update_dev_host (1, h, s, async);
|
|
}
|
|
|
|
void
|
|
acc_update_self (void *h, size_t s)
|
|
{
|
|
- update_dev_host (0, h, s);
|
|
+ update_dev_host (0, h, s, acc_async_sync);
|
|
+}
|
|
+
|
|
+void
|
|
+acc_update_self_async (void *h, size_t s, int async)
|
|
+{
|
|
+ update_dev_host (0, h, s, async);
|
|
}
|
|
|
|
void
|
|
@@ -659,11 +811,37 @@ gomp_acc_insert_pointer (size_t mapnum,
|
|
struct goacc_thread *thr = goacc_thread ();
|
|
struct gomp_device_descr *acc_dev = thr->dev;
|
|
|
|
+ if (acc_is_present (*hostaddrs, *sizes))
|
|
+ {
|
|
+ splay_tree_key n;
|
|
+ gomp_mutex_lock (&acc_dev->lock);
|
|
+ n = lookup_host (acc_dev, *hostaddrs, *sizes);
|
|
+ gomp_mutex_unlock (&acc_dev->lock);
|
|
+
|
|
+ tgt = n->tgt;
|
|
+ for (size_t i = 0; i < tgt->list_count; i++)
|
|
+ if (tgt->list[i].key == n)
|
|
+ {
|
|
+ for (size_t j = 0; j < mapnum; j++)
|
|
+ if (i + j < tgt->list_count && tgt->list[i + j].key)
|
|
+ {
|
|
+ tgt->list[i + j].key->refcount++;
|
|
+ tgt->list[i + j].key->dynamic_refcount++;
|
|
+ }
|
|
+ return;
|
|
+ }
|
|
+ /* Should not reach here. */
|
|
+ gomp_fatal ("Dynamic refcount incrementing failed for pointer/pset");
|
|
+ }
|
|
+
|
|
gomp_debug (0, " %s: prepare mappings\n", __FUNCTION__);
|
|
tgt = gomp_map_vars (acc_dev, mapnum, hostaddrs,
|
|
NULL, sizes, kinds, true, GOMP_MAP_VARS_OPENACC);
|
|
gomp_debug (0, " %s: mappings prepared\n", __FUNCTION__);
|
|
|
|
+ /* Initialize dynamic refcount. */
|
|
+ tgt->list[0].key->dynamic_refcount = 1;
|
|
+
|
|
gomp_mutex_lock (&acc_dev->lock);
|
|
tgt->prev = acc_dev->openacc.data_environ;
|
|
acc_dev->openacc.data_environ = tgt;
|
|
@@ -671,7 +849,8 @@ gomp_acc_insert_pointer (size_t mapnum,
|
|
}
|
|
|
|
void
|
|
-gomp_acc_remove_pointer (void *h, bool force_copyfrom, int async, int mapnum)
|
|
+gomp_acc_remove_pointer (void *h, size_t s, bool force_copyfrom, int async,
|
|
+ int finalize, int mapnum)
|
|
{
|
|
struct goacc_thread *thr = goacc_thread ();
|
|
struct gomp_device_descr *acc_dev = thr->dev;
|
|
@@ -679,6 +858,9 @@ gomp_acc_remove_pointer (void *h, bool f
|
|
struct target_mem_desc *t;
|
|
int minrefs = (mapnum == 1) ? 2 : 3;
|
|
|
|
+ if (!acc_is_present (h, s))
|
|
+ return;
|
|
+
|
|
gomp_mutex_lock (&acc_dev->lock);
|
|
|
|
n = lookup_host (acc_dev, h, 1);
|
|
@@ -693,40 +875,65 @@ gomp_acc_remove_pointer (void *h, bool f
|
|
|
|
t = n->tgt;
|
|
|
|
- struct target_mem_desc *tp;
|
|
+ if (n->refcount < n->dynamic_refcount)
|
|
+ {
|
|
+ gomp_mutex_unlock (&acc_dev->lock);
|
|
+ gomp_fatal ("Dynamic reference counting assert fail\n");
|
|
+ }
|
|
|
|
- if (t->refcount == minrefs)
|
|
+ if (finalize)
|
|
{
|
|
- /* This is the last reference, so pull the descriptor off the
|
|
- chain. This avoids gomp_unmap_vars via gomp_unmap_tgt from
|
|
- freeing the device memory. */
|
|
- t->tgt_end = 0;
|
|
- t->to_free = 0;
|
|
+ n->refcount -= n->dynamic_refcount;
|
|
+ n->dynamic_refcount = 0;
|
|
+ }
|
|
+ else if (n->dynamic_refcount)
|
|
+ {
|
|
+ n->dynamic_refcount--;
|
|
+ n->refcount--;
|
|
+ }
|
|
|
|
- for (tp = NULL, t = acc_dev->openacc.data_environ; t != NULL;
|
|
- tp = t, t = t->prev)
|
|
+ gomp_mutex_unlock (&acc_dev->lock);
|
|
+
|
|
+ if (n->refcount == 0)
|
|
+ {
|
|
+ if (t->refcount == minrefs)
|
|
{
|
|
- if (n->tgt == t)
|
|
+ /* This is the last reference, so pull the descriptor off the
|
|
+ chain. This prevents gomp_unmap_vars via gomp_unmap_tgt from
|
|
+ freeing the device memory. */
|
|
+ struct target_mem_desc *tp;
|
|
+ for (tp = NULL, t = acc_dev->openacc.data_environ; t != NULL;
|
|
+ tp = t, t = t->prev)
|
|
{
|
|
- if (tp)
|
|
- tp->prev = t->prev;
|
|
- else
|
|
- acc_dev->openacc.data_environ = t->prev;
|
|
- break;
|
|
+ if (n->tgt == t)
|
|
+ {
|
|
+ if (tp)
|
|
+ tp->prev = t->prev;
|
|
+ else
|
|
+ acc_dev->openacc.data_environ = t->prev;
|
|
+ break;
|
|
+ }
|
|
}
|
|
}
|
|
- }
|
|
|
|
- if (force_copyfrom)
|
|
- t->list[0].copy_from = 1;
|
|
+ /* Set refcount to 1 to allow gomp_unmap_vars to unmap it. */
|
|
+ n->refcount = 1;
|
|
+ t->refcount = minrefs;
|
|
+ for (size_t i = 0; i < t->list_count; i++)
|
|
+ if (t->list[i].key == n)
|
|
+ {
|
|
+ t->list[i].copy_from = force_copyfrom ? 1 : 0;
|
|
+ break;
|
|
+ }
|
|
|
|
- gomp_mutex_unlock (&acc_dev->lock);
|
|
+ /* If running synchronously, unmap immediately. */
|
|
+ if (async < acc_async_noval)
|
|
+ gomp_unmap_vars (t, true);
|
|
+ else
|
|
+ t->device_descr->openacc.register_async_cleanup_func (t, async);
|
|
+ }
|
|
|
|
- /* If running synchronously, unmap immediately. */
|
|
- if (async < acc_async_noval)
|
|
- gomp_unmap_vars (t, true);
|
|
- else
|
|
- t->device_descr->openacc.register_async_cleanup_func (t, async);
|
|
+ gomp_mutex_unlock (&acc_dev->lock);
|
|
|
|
gomp_debug (0, " %s: mappings restored\n", __FUNCTION__);
|
|
}
|
|
--- libgomp/env.c.jj 2018-04-25 09:40:31.924655586 +0200
|
|
+++ libgomp/env.c 2019-05-07 18:46:36.482110438 +0200
|
|
@@ -88,8 +88,12 @@ void **gomp_places_list;
|
|
unsigned long gomp_places_list_len;
|
|
int gomp_debug_var;
|
|
unsigned int gomp_num_teams_var;
|
|
+bool gomp_display_affinity_var;
|
|
+char *gomp_affinity_format_var = "level %L thread %i affinity %A";
|
|
+size_t gomp_affinity_format_len;
|
|
char *goacc_device_type;
|
|
int goacc_device_num;
|
|
+int goacc_default_dims[GOMP_DIM_MAX];
|
|
|
|
#ifndef LIBGOMP_OFFLOADED_ONLY
|
|
|
|
@@ -100,6 +104,7 @@ parse_schedule (void)
|
|
{
|
|
char *env, *end;
|
|
unsigned long value;
|
|
+ int monotonic = 0;
|
|
|
|
env = getenv ("OMP_SCHEDULE");
|
|
if (env == NULL)
|
|
@@ -107,6 +112,26 @@ parse_schedule (void)
|
|
|
|
while (isspace ((unsigned char) *env))
|
|
++env;
|
|
+ if (strncasecmp (env, "monotonic", 9) == 0)
|
|
+ {
|
|
+ monotonic = 1;
|
|
+ env += 9;
|
|
+ }
|
|
+ else if (strncasecmp (env, "nonmonotonic", 12) == 0)
|
|
+ {
|
|
+ monotonic = -1;
|
|
+ env += 12;
|
|
+ }
|
|
+ if (monotonic)
|
|
+ {
|
|
+ while (isspace ((unsigned char) *env))
|
|
+ ++env;
|
|
+ if (*env != ':')
|
|
+ goto unknown;
|
|
+ ++env;
|
|
+ while (isspace ((unsigned char) *env))
|
|
+ ++env;
|
|
+ }
|
|
if (strncasecmp (env, "static", 6) == 0)
|
|
{
|
|
gomp_global_icv.run_sched_var = GFS_STATIC;
|
|
@@ -130,12 +155,16 @@ parse_schedule (void)
|
|
else
|
|
goto unknown;
|
|
|
|
+ if (monotonic == 1
|
|
+ || (monotonic == 0 && gomp_global_icv.run_sched_var == GFS_STATIC))
|
|
+ gomp_global_icv.run_sched_var |= GFS_MONOTONIC;
|
|
+
|
|
while (isspace ((unsigned char) *env))
|
|
++env;
|
|
if (*env == '\0')
|
|
{
|
|
gomp_global_icv.run_sched_chunk_size
|
|
- = gomp_global_icv.run_sched_var != GFS_STATIC;
|
|
+ = (gomp_global_icv.run_sched_var & ~GFS_MONOTONIC) != GFS_STATIC;
|
|
return;
|
|
}
|
|
if (*env++ != ',')
|
|
@@ -158,7 +187,8 @@ parse_schedule (void)
|
|
if ((int)value != value)
|
|
goto invalid;
|
|
|
|
- if (value == 0 && gomp_global_icv.run_sched_var != GFS_STATIC)
|
|
+ if (value == 0
|
|
+ && (gomp_global_icv.run_sched_var & ~GFS_MONOTONIC) != GFS_STATIC)
|
|
value = 1;
|
|
gomp_global_icv.run_sched_chunk_size = value;
|
|
return;
|
|
@@ -1066,6 +1096,36 @@ parse_acc_device_type (void)
|
|
}
|
|
|
|
static void
|
|
+parse_gomp_openacc_dim (void)
|
|
+{
|
|
+ /* The syntax is the same as for the -fopenacc-dim compilation option. */
|
|
+ const char *var_name = "GOMP_OPENACC_DIM";
|
|
+ const char *env_var = getenv (var_name);
|
|
+ if (!env_var)
|
|
+ return;
|
|
+
|
|
+ const char *pos = env_var;
|
|
+ int i;
|
|
+ for (i = 0; *pos && i != GOMP_DIM_MAX; i++)
|
|
+ {
|
|
+ if (i && *pos++ != ':')
|
|
+ break;
|
|
+
|
|
+ if (*pos == ':')
|
|
+ continue;
|
|
+
|
|
+ const char *eptr;
|
|
+ errno = 0;
|
|
+ long val = strtol (pos, (char **)&eptr, 10);
|
|
+ if (errno || val < 0 || (unsigned)val != val)
|
|
+ break;
|
|
+
|
|
+ goacc_default_dims[i] = (int)val;
|
|
+ pos = eptr;
|
|
+ }
|
|
+}
|
|
+
|
|
+static void
|
|
handle_omp_display_env (unsigned long stacksize, int wait_policy)
|
|
{
|
|
const char *env;
|
|
@@ -1119,19 +1179,34 @@ handle_omp_display_env (unsigned long st
|
|
fputs ("'\n", stderr);
|
|
|
|
fprintf (stderr, " OMP_SCHEDULE = '");
|
|
- switch (gomp_global_icv.run_sched_var)
|
|
+ if ((gomp_global_icv.run_sched_var & GFS_MONOTONIC))
|
|
+ {
|
|
+ if (gomp_global_icv.run_sched_var != (GFS_MONOTONIC | GFS_STATIC))
|
|
+ fputs ("MONOTONIC:", stderr);
|
|
+ }
|
|
+ else if (gomp_global_icv.run_sched_var == GFS_STATIC)
|
|
+ fputs ("NONMONOTONIC:", stderr);
|
|
+ switch (gomp_global_icv.run_sched_var & ~GFS_MONOTONIC)
|
|
{
|
|
case GFS_RUNTIME:
|
|
fputs ("RUNTIME", stderr);
|
|
+ if (gomp_global_icv.run_sched_chunk_size != 1)
|
|
+ fprintf (stderr, ",%d", gomp_global_icv.run_sched_chunk_size);
|
|
break;
|
|
case GFS_STATIC:
|
|
fputs ("STATIC", stderr);
|
|
+ if (gomp_global_icv.run_sched_chunk_size != 0)
|
|
+ fprintf (stderr, ",%d", gomp_global_icv.run_sched_chunk_size);
|
|
break;
|
|
case GFS_DYNAMIC:
|
|
fputs ("DYNAMIC", stderr);
|
|
+ if (gomp_global_icv.run_sched_chunk_size != 1)
|
|
+ fprintf (stderr, ",%d", gomp_global_icv.run_sched_chunk_size);
|
|
break;
|
|
case GFS_GUIDED:
|
|
fputs ("GUIDED", stderr);
|
|
+ if (gomp_global_icv.run_sched_chunk_size != 1)
|
|
+ fprintf (stderr, ",%d", gomp_global_icv.run_sched_chunk_size);
|
|
break;
|
|
case GFS_AUTO:
|
|
fputs ("AUTO", stderr);
|
|
@@ -1197,6 +1272,10 @@ handle_omp_display_env (unsigned long st
|
|
gomp_global_icv.default_device_var);
|
|
fprintf (stderr, " OMP_MAX_TASK_PRIORITY = '%d'\n",
|
|
gomp_max_task_priority_var);
|
|
+ fprintf (stderr, " OMP_DISPLAY_AFFINITY = '%s'\n",
|
|
+ gomp_display_affinity_var ? "TRUE" : "FALSE");
|
|
+ fprintf (stderr, " OMP_AFFINITY_FORMAT = '%s'\n",
|
|
+ gomp_affinity_format_var);
|
|
|
|
if (verbose)
|
|
{
|
|
@@ -1228,6 +1307,7 @@ initialize_env (void)
|
|
parse_boolean ("OMP_DYNAMIC", &gomp_global_icv.dyn_var);
|
|
parse_boolean ("OMP_NESTED", &gomp_global_icv.nest_var);
|
|
parse_boolean ("OMP_CANCELLATION", &gomp_cancel_var);
|
|
+ parse_boolean ("OMP_DISPLAY_AFFINITY", &gomp_display_affinity_var);
|
|
parse_int ("OMP_DEFAULT_DEVICE", &gomp_global_icv.default_device_var, true);
|
|
parse_int ("OMP_MAX_TASK_PRIORITY", &gomp_max_task_priority_var, true);
|
|
parse_unsigned_long ("OMP_MAX_ACTIVE_LEVELS", &gomp_max_active_levels_var,
|
|
@@ -1277,6 +1357,13 @@ initialize_env (void)
|
|
}
|
|
if (gomp_global_icv.bind_var != omp_proc_bind_false)
|
|
gomp_init_affinity ();
|
|
+
|
|
+ {
|
|
+ const char *env = getenv ("OMP_AFFINITY_FORMAT");
|
|
+ if (env != NULL)
|
|
+ gomp_set_affinity_format (env, strlen (env));
|
|
+ }
|
|
+
|
|
wait_policy = parse_wait_policy ();
|
|
if (!parse_spincount ("GOMP_SPINCOUNT", &gomp_spin_count_var))
|
|
{
|
|
@@ -1302,7 +1389,6 @@ initialize_env (void)
|
|
|
|
/* Not strictly environment related, but ordering constructors is tricky. */
|
|
pthread_attr_init (&gomp_thread_attr);
|
|
- pthread_attr_setdetachstate (&gomp_thread_attr, PTHREAD_CREATE_DETACHED);
|
|
|
|
if (parse_stacksize ("OMP_STACKSIZE", &stacksize)
|
|
|| parse_stacksize ("GOMP_STACKSIZE", &stacksize)
|
|
@@ -1336,6 +1422,7 @@ initialize_env (void)
|
|
goacc_device_num = 0;
|
|
|
|
parse_acc_device_type ();
|
|
+ parse_gomp_openacc_dim ();
|
|
|
|
goacc_runtime_initialize ();
|
|
}
|
|
--- libgomp/fortran.c.jj 2018-04-25 09:40:31.913655581 +0200
|
|
+++ libgomp/fortran.c 2019-05-07 18:46:36.491110295 +0200
|
|
@@ -28,6 +28,8 @@
|
|
#include "libgomp.h"
|
|
#include "libgomp_f.h"
|
|
#include <stdlib.h>
|
|
+#include <stdio.h>
|
|
+#include <string.h>
|
|
#include <limits.h>
|
|
|
|
#ifdef HAVE_ATTRIBUTE_ALIAS
|
|
@@ -82,6 +84,8 @@ ialias_redirect (omp_get_team_num)
|
|
ialias_redirect (omp_is_initial_device)
|
|
ialias_redirect (omp_get_initial_device)
|
|
ialias_redirect (omp_get_max_task_priority)
|
|
+ialias_redirect (omp_pause_resource)
|
|
+ialias_redirect (omp_pause_resource_all)
|
|
#endif
|
|
|
|
#ifndef LIBGOMP_GNU_SYMBOL_VERSIONING
|
|
@@ -368,7 +372,9 @@ omp_get_schedule_ (int32_t *kind, int32_
|
|
omp_sched_t k;
|
|
int cs;
|
|
omp_get_schedule (&k, &cs);
|
|
- *kind = k;
|
|
+ /* For now mask off GFS_MONOTONIC, because OpenMP 4.5 code will not
|
|
+ expect to see it. */
|
|
+ *kind = k & ~GFS_MONOTONIC;
|
|
*chunk_size = cs;
|
|
}
|
|
|
|
@@ -378,7 +384,8 @@ omp_get_schedule_8_ (int32_t *kind, int6
|
|
omp_sched_t k;
|
|
int cs;
|
|
omp_get_schedule (&k, &cs);
|
|
- *kind = k;
|
|
+ /* See above. */
|
|
+ *kind = k & ~GFS_MONOTONIC;
|
|
*chunk_size = cs;
|
|
}
|
|
|
|
@@ -576,3 +583,96 @@ omp_get_max_task_priority_ (void)
|
|
{
|
|
return omp_get_max_task_priority ();
|
|
}
|
|
+
|
|
+void
|
|
+omp_set_affinity_format_ (const char *format, size_t format_len)
|
|
+{
|
|
+ gomp_set_affinity_format (format, format_len);
|
|
+}
|
|
+
|
|
+int32_t
|
|
+omp_get_affinity_format_ (char *buffer, size_t buffer_len)
|
|
+{
|
|
+ size_t len = strlen (gomp_affinity_format_var);
|
|
+ if (buffer_len)
|
|
+ {
|
|
+ if (len < buffer_len)
|
|
+ {
|
|
+ memcpy (buffer, gomp_affinity_format_var, len);
|
|
+ memset (buffer + len, ' ', buffer_len - len);
|
|
+ }
|
|
+ else
|
|
+ memcpy (buffer, gomp_affinity_format_var, buffer_len);
|
|
+ }
|
|
+ return len;
|
|
+}
|
|
+
|
|
+void
|
|
+omp_display_affinity_ (const char *format, size_t format_len)
|
|
+{
|
|
+ char *fmt = NULL, fmt_buf[256];
|
|
+ char buf[512];
|
|
+ if (format_len)
|
|
+ {
|
|
+ fmt = format_len < 256 ? fmt_buf : gomp_malloc (format_len + 1);
|
|
+ memcpy (fmt, format, format_len);
|
|
+ fmt[format_len] = '\0';
|
|
+ }
|
|
+ struct gomp_thread *thr = gomp_thread ();
|
|
+ size_t ret
|
|
+ = gomp_display_affinity (buf, sizeof buf,
|
|
+ format_len ? fmt : gomp_affinity_format_var,
|
|
+ gomp_thread_self (), &thr->ts, thr->place);
|
|
+ if (ret < sizeof buf)
|
|
+ {
|
|
+ buf[ret] = '\n';
|
|
+ gomp_print_string (buf, ret + 1);
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+ char *b = gomp_malloc (ret + 1);
|
|
+ gomp_display_affinity (buf, sizeof buf,
|
|
+ format_len ? fmt : gomp_affinity_format_var,
|
|
+ gomp_thread_self (), &thr->ts, thr->place);
|
|
+ b[ret] = '\n';
|
|
+ gomp_print_string (b, ret + 1);
|
|
+ free (b);
|
|
+ }
|
|
+ if (fmt && fmt != fmt_buf)
|
|
+ free (fmt);
|
|
+}
|
|
+
|
|
+int32_t
|
|
+omp_capture_affinity_ (char *buffer, const char *format,
|
|
+ size_t buffer_len, size_t format_len)
|
|
+{
|
|
+ char *fmt = NULL, fmt_buf[256];
|
|
+ if (format_len)
|
|
+ {
|
|
+ fmt = format_len < 256 ? fmt_buf : gomp_malloc (format_len + 1);
|
|
+ memcpy (fmt, format, format_len);
|
|
+ fmt[format_len] = '\0';
|
|
+ }
|
|
+ struct gomp_thread *thr = gomp_thread ();
|
|
+ size_t ret
|
|
+ = gomp_display_affinity (buffer, buffer_len,
|
|
+ format_len ? fmt : gomp_affinity_format_var,
|
|
+ gomp_thread_self (), &thr->ts, thr->place);
|
|
+ if (fmt && fmt != fmt_buf)
|
|
+ free (fmt);
|
|
+ if (ret < buffer_len)
|
|
+ memset (buffer + ret, ' ', buffer_len - ret);
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+int32_t
|
|
+omp_pause_resource_ (const int32_t *kind, const int32_t *device_num)
|
|
+{
|
|
+ return omp_pause_resource (*kind, *device_num);
|
|
+}
|
|
+
|
|
+int32_t
|
|
+omp_pause_resource_all_ (const int32_t *kind)
|
|
+{
|
|
+ return omp_pause_resource_all (*kind);
|
|
+}
|
|
--- libgomp/configure.tgt.jj 2018-04-25 09:40:31.925655587 +0200
|
|
+++ libgomp/configure.tgt 2019-05-07 18:46:36.479110486 +0200
|
|
@@ -18,7 +18,7 @@ if test $gcc_cv_have_tls = yes ; then
|
|
;;
|
|
|
|
*-*-linux* | *-*-gnu*)
|
|
- XCFLAGS="${XCFLAGS} -ftls-model=initial-exec"
|
|
+ XCFLAGS="${XCFLAGS} -ftls-model=initial-exec -DUSING_INITIAL_EXEC_TLS"
|
|
;;
|
|
|
|
*-*-rtems*)
|
|
--- libgomp/icv-device.c.jj 2018-04-25 09:40:31.925655587 +0200
|
|
+++ libgomp/icv-device.c 2019-05-07 18:46:36.513109943 +0200
|
|
@@ -49,20 +49,6 @@ omp_get_num_devices (void)
|
|
}
|
|
|
|
int
|
|
-omp_get_num_teams (void)
|
|
-{
|
|
- /* Hardcoded to 1 on host, MIC, HSAIL? Maybe variable on PTX. */
|
|
- return 1;
|
|
-}
|
|
-
|
|
-int
|
|
-omp_get_team_num (void)
|
|
-{
|
|
- /* Hardcoded to 0 on host, MIC, HSAIL? Maybe variable on PTX. */
|
|
- return 0;
|
|
-}
|
|
-
|
|
-int
|
|
omp_is_initial_device (void)
|
|
{
|
|
/* Hardcoded to 1 on host, should be 0 on MIC, HSAIL, PTX. */
|
|
@@ -72,6 +58,4 @@ omp_is_initial_device (void)
|
|
ialias (omp_set_default_device)
|
|
ialias (omp_get_default_device)
|
|
ialias (omp_get_num_devices)
|
|
-ialias (omp_get_num_teams)
|
|
-ialias (omp_get_team_num)
|
|
ialias (omp_is_initial_device)
|
|
--- libgomp/Makefile.in.jj 2018-04-25 09:40:31.320655306 +0200
|
|
+++ libgomp/Makefile.in 2019-05-07 20:00:01.082077522 +0200
|
|
@@ -90,7 +90,7 @@ DIST_COMMON = $(top_srcdir)/plugin/Makef
|
|
$(srcdir)/libgomp.spec.in $(srcdir)/../depcomp
|
|
@PLUGIN_NVPTX_TRUE@am__append_1 = libgomp-plugin-nvptx.la
|
|
@PLUGIN_HSA_TRUE@am__append_2 = libgomp-plugin-hsa.la
|
|
-@USE_FORTRAN_TRUE@am__append_3 = openacc.f90
|
|
+@USE_FORTRAN_TRUE@am__append_3 = openacc2.f90
|
|
subdir = .
|
|
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
|
|
am__aclocal_m4_deps = $(top_srcdir)/../config/acx.m4 \
|
|
@@ -172,7 +172,7 @@ libgomp_plugin_nvptx_la_LINK = $(LIBTOOL
|
|
@PLUGIN_NVPTX_TRUE@am_libgomp_plugin_nvptx_la_rpath = -rpath \
|
|
@PLUGIN_NVPTX_TRUE@ $(toolexeclibdir)
|
|
libgomp_la_LIBADD =
|
|
-@USE_FORTRAN_TRUE@am__objects_1 = openacc.lo
|
|
+@USE_FORTRAN_TRUE@am__objects_1 = openacc2.lo
|
|
am_libgomp_la_OBJECTS = alloc.lo atomic.lo barrier.lo critical.lo \
|
|
env.lo error.lo icv.lo icv-device.lo iter.lo iter_ull.lo \
|
|
loop.lo loop_ull.lo ordered.lo parallel.lo sections.lo \
|
|
@@ -180,7 +180,8 @@ am_libgomp_la_OBJECTS = alloc.lo atomic.
|
|
sem.lo bar.lo ptrlock.lo time.lo fortran.lo affinity.lo \
|
|
target.lo splay-tree.lo libgomp-plugin.lo oacc-parallel.lo \
|
|
oacc-host.lo oacc-init.lo oacc-mem.lo oacc-async.lo \
|
|
- oacc-plugin.lo oacc-cuda.lo priority_queue.lo $(am__objects_1)
|
|
+ oacc-plugin.lo oacc-cuda.lo priority_queue.lo affinity-fmt.lo \
|
|
+ teams.lo $(am__objects_1)
|
|
libgomp_la_OBJECTS = $(am_libgomp_la_OBJECTS)
|
|
DEFAULT_INCLUDES = -I.@am__isrc@
|
|
depcomp = $(SHELL) $(top_srcdir)/../depcomp
|
|
@@ -380,6 +381,7 @@ mkdir_p = @mkdir_p@
|
|
multi_basedir = @multi_basedir@
|
|
offload_additional_lib_paths = @offload_additional_lib_paths@
|
|
offload_additional_options = @offload_additional_options@
|
|
+offload_plugins = @offload_plugins@
|
|
offload_targets = @offload_targets@
|
|
oldincludedir = @oldincludedir@
|
|
pdfdir = @pdfdir@
|
|
@@ -436,7 +438,7 @@ libgomp_la_SOURCES = alloc.c atomic.c ba
|
|
affinity.c target.c splay-tree.c libgomp-plugin.c \
|
|
oacc-parallel.c oacc-host.c oacc-init.c oacc-mem.c \
|
|
oacc-async.c oacc-plugin.c oacc-cuda.c priority_queue.c \
|
|
- $(am__append_3)
|
|
+ affinity-fmt.c teams.c $(am__append_3)
|
|
|
|
# Nvidia PTX OpenACC plugin.
|
|
@PLUGIN_NVPTX_TRUE@libgomp_plugin_nvptx_version_info = -version-info $(libtool_VERSION)
|
|
@@ -599,6 +601,7 @@ mostlyclean-compile:
|
|
distclean-compile:
|
|
-rm -f *.tab.c
|
|
|
|
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/affinity-fmt.Plo@am__quote@
|
|
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/affinity.Plo@am__quote@
|
|
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/alloc.Plo@am__quote@
|
|
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/atomic.Plo@am__quote@
|
|
@@ -638,6 +641,7 @@ distclean-compile:
|
|
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/target.Plo@am__quote@
|
|
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/task.Plo@am__quote@
|
|
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/team.Plo@am__quote@
|
|
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/teams.Plo@am__quote@
|
|
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/time.Plo@am__quote@
|
|
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/work.Plo@am__quote@
|
|
|
|
@@ -1292,8 +1296,6 @@ omp_lib_kinds.mod: omp_lib.mod
|
|
:
|
|
openacc_kinds.mod: openacc.mod
|
|
:
|
|
-openacc.mod: openacc.lo
|
|
- :
|
|
%.mod: %.f90
|
|
$(FC) $(FCFLAGS) -fsyntax-only $<
|
|
fortran.lo: libgomp_f.h
|
|
--- libgomp/plugin/cuda/cuda.h.jj 2018-04-25 09:40:31.914655581 +0200
|
|
+++ libgomp/plugin/cuda/cuda.h 2019-05-07 18:46:36.533109624 +0200
|
|
@@ -44,6 +44,7 @@ typedef void *CUevent;
|
|
typedef void *CUfunction;
|
|
typedef void *CUlinkState;
|
|
typedef void *CUmodule;
|
|
+typedef size_t (*CUoccupancyB2DSize)(int);
|
|
typedef void *CUstream;
|
|
|
|
typedef enum {
|
|
@@ -88,6 +89,7 @@ typedef enum {
|
|
CU_JIT_INFO_LOG_BUFFER_SIZE_BYTES = 4,
|
|
CU_JIT_ERROR_LOG_BUFFER = 5,
|
|
CU_JIT_ERROR_LOG_BUFFER_SIZE_BYTES = 6,
|
|
+ CU_JIT_OPTIMIZATION_LEVEL = 7,
|
|
CU_JIT_LOG_VERBOSE = 12
|
|
} CUjit_option;
|
|
|
|
@@ -169,6 +171,8 @@ CUresult cuModuleGetGlobal (CUdeviceptr
|
|
CUresult cuModuleLoad (CUmodule *, const char *);
|
|
CUresult cuModuleLoadData (CUmodule *, const void *);
|
|
CUresult cuModuleUnload (CUmodule);
|
|
+CUresult cuOccupancyMaxPotentialBlockSize(int *, int *, CUfunction,
|
|
+ CUoccupancyB2DSize, size_t, int);
|
|
CUresult cuStreamCreate (CUstream *, unsigned);
|
|
#define cuStreamDestroy cuStreamDestroy_v2
|
|
CUresult cuStreamDestroy (CUstream);
|
|
--- libgomp/plugin/cuda-lib.def.jj 2019-05-07 18:46:36.533109624 +0200
|
|
+++ libgomp/plugin/cuda-lib.def 2019-05-07 18:46:36.533109624 +0200
|
|
@@ -0,0 +1,49 @@
|
|
+CUDA_ONE_CALL (cuCtxCreate)
|
|
+CUDA_ONE_CALL (cuCtxDestroy)
|
|
+CUDA_ONE_CALL (cuCtxGetCurrent)
|
|
+CUDA_ONE_CALL (cuCtxGetDevice)
|
|
+CUDA_ONE_CALL (cuCtxPopCurrent)
|
|
+CUDA_ONE_CALL (cuCtxPushCurrent)
|
|
+CUDA_ONE_CALL (cuCtxSynchronize)
|
|
+CUDA_ONE_CALL (cuDeviceGet)
|
|
+CUDA_ONE_CALL (cuDeviceGetAttribute)
|
|
+CUDA_ONE_CALL (cuDeviceGetCount)
|
|
+CUDA_ONE_CALL (cuEventCreate)
|
|
+CUDA_ONE_CALL (cuEventDestroy)
|
|
+CUDA_ONE_CALL (cuEventElapsedTime)
|
|
+CUDA_ONE_CALL (cuEventQuery)
|
|
+CUDA_ONE_CALL (cuEventRecord)
|
|
+CUDA_ONE_CALL (cuEventSynchronize)
|
|
+CUDA_ONE_CALL (cuFuncGetAttribute)
|
|
+CUDA_ONE_CALL_MAYBE_NULL (cuGetErrorString)
|
|
+CUDA_ONE_CALL (cuInit)
|
|
+CUDA_ONE_CALL (cuLaunchKernel)
|
|
+CUDA_ONE_CALL (cuLinkAddData)
|
|
+CUDA_ONE_CALL_MAYBE_NULL (cuLinkAddData_v2)
|
|
+CUDA_ONE_CALL (cuLinkComplete)
|
|
+CUDA_ONE_CALL (cuLinkCreate)
|
|
+CUDA_ONE_CALL_MAYBE_NULL (cuLinkCreate_v2)
|
|
+CUDA_ONE_CALL (cuLinkDestroy)
|
|
+CUDA_ONE_CALL (cuMemAlloc)
|
|
+CUDA_ONE_CALL (cuMemAllocHost)
|
|
+CUDA_ONE_CALL (cuMemcpy)
|
|
+CUDA_ONE_CALL (cuMemcpyDtoDAsync)
|
|
+CUDA_ONE_CALL (cuMemcpyDtoH)
|
|
+CUDA_ONE_CALL (cuMemcpyDtoHAsync)
|
|
+CUDA_ONE_CALL (cuMemcpyHtoD)
|
|
+CUDA_ONE_CALL (cuMemcpyHtoDAsync)
|
|
+CUDA_ONE_CALL (cuMemFree)
|
|
+CUDA_ONE_CALL (cuMemFreeHost)
|
|
+CUDA_ONE_CALL (cuMemGetAddressRange)
|
|
+CUDA_ONE_CALL (cuMemHostGetDevicePointer)
|
|
+CUDA_ONE_CALL (cuModuleGetFunction)
|
|
+CUDA_ONE_CALL (cuModuleGetGlobal)
|
|
+CUDA_ONE_CALL (cuModuleLoad)
|
|
+CUDA_ONE_CALL (cuModuleLoadData)
|
|
+CUDA_ONE_CALL (cuModuleUnload)
|
|
+CUDA_ONE_CALL_MAYBE_NULL (cuOccupancyMaxPotentialBlockSize)
|
|
+CUDA_ONE_CALL (cuStreamCreate)
|
|
+CUDA_ONE_CALL (cuStreamDestroy)
|
|
+CUDA_ONE_CALL (cuStreamQuery)
|
|
+CUDA_ONE_CALL (cuStreamSynchronize)
|
|
+CUDA_ONE_CALL (cuStreamWaitEvent)
|
|
--- libgomp/plugin/plugin-nvptx.c.jj 2018-04-25 09:40:31.915655582 +0200
|
|
+++ libgomp/plugin/plugin-nvptx.c 2019-05-07 18:46:36.535109592 +0200
|
|
@@ -31,6 +31,7 @@
|
|
is not clear as to what that state might be. Or how one might
|
|
propagate it from one thread to another. */
|
|
|
|
+#define _GNU_SOURCE
|
|
#include "openacc.h"
|
|
#include "config.h"
|
|
#include "libgomp-plugin.h"
|
|
@@ -48,60 +49,41 @@
|
|
#include <assert.h>
|
|
#include <errno.h>
|
|
|
|
+#if CUDA_VERSION < 6000
|
|
+extern CUresult cuGetErrorString (CUresult, const char **);
|
|
+#define CU_DEVICE_ATTRIBUTE_MAX_REGISTERS_PER_MULTIPROCESSOR 82
|
|
+#endif
|
|
+
|
|
+#if CUDA_VERSION >= 6050
|
|
+#undef cuLinkCreate
|
|
+#undef cuLinkAddData
|
|
+CUresult cuLinkAddData (CUlinkState, CUjitInputType, void *, size_t,
|
|
+ const char *, unsigned, CUjit_option *, void **);
|
|
+CUresult cuLinkCreate (unsigned, CUjit_option *, void **, CUlinkState *);
|
|
+#else
|
|
+typedef size_t (*CUoccupancyB2DSize)(int);
|
|
+CUresult cuLinkAddData_v2 (CUlinkState, CUjitInputType, void *, size_t,
|
|
+ const char *, unsigned, CUjit_option *, void **);
|
|
+CUresult cuLinkCreate_v2 (unsigned, CUjit_option *, void **, CUlinkState *);
|
|
+CUresult cuOccupancyMaxPotentialBlockSize(int *, int *, CUfunction,
|
|
+ CUoccupancyB2DSize, size_t, int);
|
|
+#endif
|
|
+
|
|
+#define DO_PRAGMA(x) _Pragma (#x)
|
|
+
|
|
#if PLUGIN_NVPTX_DYNAMIC
|
|
# include <dlfcn.h>
|
|
|
|
-# define CUDA_CALLS \
|
|
-CUDA_ONE_CALL (cuCtxCreate) \
|
|
-CUDA_ONE_CALL (cuCtxDestroy) \
|
|
-CUDA_ONE_CALL (cuCtxGetCurrent) \
|
|
-CUDA_ONE_CALL (cuCtxGetDevice) \
|
|
-CUDA_ONE_CALL (cuCtxPopCurrent) \
|
|
-CUDA_ONE_CALL (cuCtxPushCurrent) \
|
|
-CUDA_ONE_CALL (cuCtxSynchronize) \
|
|
-CUDA_ONE_CALL (cuDeviceGet) \
|
|
-CUDA_ONE_CALL (cuDeviceGetAttribute) \
|
|
-CUDA_ONE_CALL (cuDeviceGetCount) \
|
|
-CUDA_ONE_CALL (cuEventCreate) \
|
|
-CUDA_ONE_CALL (cuEventDestroy) \
|
|
-CUDA_ONE_CALL (cuEventElapsedTime) \
|
|
-CUDA_ONE_CALL (cuEventQuery) \
|
|
-CUDA_ONE_CALL (cuEventRecord) \
|
|
-CUDA_ONE_CALL (cuEventSynchronize) \
|
|
-CUDA_ONE_CALL (cuFuncGetAttribute) \
|
|
-CUDA_ONE_CALL (cuGetErrorString) \
|
|
-CUDA_ONE_CALL (cuInit) \
|
|
-CUDA_ONE_CALL (cuLaunchKernel) \
|
|
-CUDA_ONE_CALL (cuLinkAddData) \
|
|
-CUDA_ONE_CALL (cuLinkComplete) \
|
|
-CUDA_ONE_CALL (cuLinkCreate) \
|
|
-CUDA_ONE_CALL (cuLinkDestroy) \
|
|
-CUDA_ONE_CALL (cuMemAlloc) \
|
|
-CUDA_ONE_CALL (cuMemAllocHost) \
|
|
-CUDA_ONE_CALL (cuMemcpy) \
|
|
-CUDA_ONE_CALL (cuMemcpyDtoDAsync) \
|
|
-CUDA_ONE_CALL (cuMemcpyDtoH) \
|
|
-CUDA_ONE_CALL (cuMemcpyDtoHAsync) \
|
|
-CUDA_ONE_CALL (cuMemcpyHtoD) \
|
|
-CUDA_ONE_CALL (cuMemcpyHtoDAsync) \
|
|
-CUDA_ONE_CALL (cuMemFree) \
|
|
-CUDA_ONE_CALL (cuMemFreeHost) \
|
|
-CUDA_ONE_CALL (cuMemGetAddressRange) \
|
|
-CUDA_ONE_CALL (cuMemHostGetDevicePointer)\
|
|
-CUDA_ONE_CALL (cuModuleGetFunction) \
|
|
-CUDA_ONE_CALL (cuModuleGetGlobal) \
|
|
-CUDA_ONE_CALL (cuModuleLoad) \
|
|
-CUDA_ONE_CALL (cuModuleLoadData) \
|
|
-CUDA_ONE_CALL (cuModuleUnload) \
|
|
-CUDA_ONE_CALL (cuStreamCreate) \
|
|
-CUDA_ONE_CALL (cuStreamDestroy) \
|
|
-CUDA_ONE_CALL (cuStreamQuery) \
|
|
-CUDA_ONE_CALL (cuStreamSynchronize) \
|
|
-CUDA_ONE_CALL (cuStreamWaitEvent)
|
|
-# define CUDA_ONE_CALL(call) \
|
|
- __typeof (call) *call;
|
|
struct cuda_lib_s {
|
|
- CUDA_CALLS
|
|
+
|
|
+# define CUDA_ONE_CALL(call) \
|
|
+ __typeof (call) *call;
|
|
+# define CUDA_ONE_CALL_MAYBE_NULL(call) \
|
|
+ CUDA_ONE_CALL (call)
|
|
+#include "cuda-lib.def"
|
|
+# undef CUDA_ONE_CALL
|
|
+# undef CUDA_ONE_CALL_MAYBE_NULL
|
|
+
|
|
} cuda_lib;
|
|
|
|
/* -1 if init_cuda_lib has not been called yet, false
|
|
@@ -120,24 +102,41 @@ init_cuda_lib (void)
|
|
cuda_lib_inited = false;
|
|
if (h == NULL)
|
|
return false;
|
|
-# undef CUDA_ONE_CALL
|
|
-# define CUDA_ONE_CALL(call) CUDA_ONE_CALL_1 (call)
|
|
-# define CUDA_ONE_CALL_1(call) \
|
|
+
|
|
+# define CUDA_ONE_CALL(call) CUDA_ONE_CALL_1 (call, false)
|
|
+# define CUDA_ONE_CALL_MAYBE_NULL(call) CUDA_ONE_CALL_1 (call, true)
|
|
+# define CUDA_ONE_CALL_1(call, allow_null) \
|
|
cuda_lib.call = dlsym (h, #call); \
|
|
- if (cuda_lib.call == NULL) \
|
|
+ if (!allow_null && cuda_lib.call == NULL) \
|
|
return false;
|
|
- CUDA_CALLS
|
|
+#include "cuda-lib.def"
|
|
+# undef CUDA_ONE_CALL
|
|
+# undef CUDA_ONE_CALL_1
|
|
+# undef CUDA_ONE_CALL_MAYBE_NULL
|
|
+
|
|
cuda_lib_inited = true;
|
|
return true;
|
|
}
|
|
-# undef CUDA_ONE_CALL
|
|
-# undef CUDA_ONE_CALL_1
|
|
# define CUDA_CALL_PREFIX cuda_lib.
|
|
#else
|
|
+
|
|
+# define CUDA_ONE_CALL(call)
|
|
+# define CUDA_ONE_CALL_MAYBE_NULL(call) DO_PRAGMA (weak call)
|
|
+#include "cuda-lib.def"
|
|
+#undef CUDA_ONE_CALL_MAYBE_NULL
|
|
+#undef CUDA_ONE_CALL
|
|
+
|
|
# define CUDA_CALL_PREFIX
|
|
# define init_cuda_lib() true
|
|
#endif
|
|
|
|
+#include "secure_getenv.h"
|
|
+
|
|
+#undef MIN
|
|
+#undef MAX
|
|
+#define MIN(X,Y) ((X) < (Y) ? (X) : (Y))
|
|
+#define MAX(X,Y) ((X) > (Y) ? (X) : (Y))
|
|
+
|
|
/* Convenience macros for the frequently used CUDA library call and
|
|
error handling sequence as well as CUDA library calls that
|
|
do the error checking themselves or don't do it at all. */
|
|
@@ -171,40 +170,42 @@ init_cuda_lib (void)
|
|
#define CUDA_CALL_NOCHECK(FN, ...) \
|
|
CUDA_CALL_PREFIX FN (__VA_ARGS__)
|
|
|
|
+#define CUDA_CALL_EXISTS(FN) \
|
|
+ CUDA_CALL_PREFIX FN
|
|
+
|
|
static const char *
|
|
cuda_error (CUresult r)
|
|
{
|
|
-#if CUDA_VERSION < 7000
|
|
- /* Specified in documentation and present in library from at least
|
|
- 5.5. Not declared in header file prior to 7.0. */
|
|
- extern CUresult cuGetErrorString (CUresult, const char **);
|
|
-#endif
|
|
+ const char *fallback = "unknown cuda error";
|
|
const char *desc;
|
|
|
|
+ if (!CUDA_CALL_EXISTS (cuGetErrorString))
|
|
+ return fallback;
|
|
+
|
|
r = CUDA_CALL_NOCHECK (cuGetErrorString, r, &desc);
|
|
- if (r != CUDA_SUCCESS)
|
|
- desc = "unknown cuda error";
|
|
+ if (r == CUDA_SUCCESS)
|
|
+ return desc;
|
|
|
|
- return desc;
|
|
+ return fallback;
|
|
}
|
|
|
|
static unsigned int instantiated_devices = 0;
|
|
static pthread_mutex_t ptx_dev_lock = PTHREAD_MUTEX_INITIALIZER;
|
|
|
|
+struct cuda_map
|
|
+{
|
|
+ CUdeviceptr d;
|
|
+ size_t size;
|
|
+ bool active;
|
|
+ struct cuda_map *next;
|
|
+};
|
|
+
|
|
struct ptx_stream
|
|
{
|
|
CUstream stream;
|
|
pthread_t host_thread;
|
|
bool multithreaded;
|
|
-
|
|
- CUdeviceptr d;
|
|
- void *h;
|
|
- void *h_begin;
|
|
- void *h_end;
|
|
- void *h_next;
|
|
- void *h_prev;
|
|
- void *h_tail;
|
|
-
|
|
+ struct cuda_map *map;
|
|
struct ptx_stream *next;
|
|
};
|
|
|
|
@@ -216,12 +217,64 @@ struct nvptx_thread
|
|
struct ptx_device *ptx_dev;
|
|
};
|
|
|
|
-struct map
|
|
+static struct cuda_map *
|
|
+cuda_map_create (size_t size)
|
|
{
|
|
- int async;
|
|
- size_t size;
|
|
- char mappings[0];
|
|
-};
|
|
+ struct cuda_map *map = GOMP_PLUGIN_malloc (sizeof (struct cuda_map));
|
|
+
|
|
+ assert (map);
|
|
+
|
|
+ map->next = NULL;
|
|
+ map->size = size;
|
|
+ map->active = false;
|
|
+
|
|
+ CUDA_CALL_ERET (NULL, cuMemAlloc, &map->d, size);
|
|
+ assert (map->d);
|
|
+
|
|
+ return map;
|
|
+}
|
|
+
|
|
+static void
|
|
+cuda_map_destroy (struct cuda_map *map)
|
|
+{
|
|
+ if (map->active)
|
|
+ /* Possible reasons for the map to be still active:
|
|
+ - the associated async kernel might still be running.
|
|
+ - the associated async kernel might have finished, but the
|
|
+ corresponding event that should trigger the pop_map has not been
|
|
+ processed by event_gc.
|
|
+ - the associated sync kernel might have aborted
|
|
+
|
|
+ The async cases could happen if the user specified an async region
|
|
+ without adding a corresponding wait that is guaranteed to be executed
|
|
+ (before returning from main, or in an atexit handler).
|
|
+ We do not want to deallocate a device pointer that is still being
|
|
+ used, so skip it.
|
|
+
|
|
+ In the sync case, the device pointer is no longer used, but deallocating
|
|
+ it using cuMemFree will not succeed, so skip it.
|
|
+
|
|
+ TODO: Handle this in a more constructive way, by f.i. waiting for streams
|
|
+ to finish before de-allocating them (PR88981), or by ensuring the CUDA
|
|
+ lib atexit handler is called before rather than after the libgomp plugin
|
|
+ atexit handler (PR83795). */
|
|
+ ;
|
|
+ else
|
|
+ CUDA_CALL_NOCHECK (cuMemFree, map->d);
|
|
+
|
|
+ free (map);
|
|
+}
|
|
+
|
|
+/* The following map_* routines manage the CUDA device memory that
|
|
+ contains the data mapping arguments for cuLaunchKernel. Each
|
|
+ asynchronous PTX stream may have multiple pending kernel
|
|
+ invocations, which are launched in a FIFO order. As such, the map
|
|
+ routines maintains a queue of cuLaunchKernel arguments.
|
|
+
|
|
+ Calls to map_push and map_pop must be guarded by ptx_event_lock.
|
|
+ Likewise, calls to map_init and map_fini are guarded by
|
|
+ ptx_dev_lock inside GOMP_OFFLOAD_init_device and
|
|
+ GOMP_OFFLOAD_fini_device, respectively. */
|
|
|
|
static bool
|
|
map_init (struct ptx_stream *s)
|
|
@@ -229,109 +282,83 @@ map_init (struct ptx_stream *s)
|
|
int size = getpagesize ();
|
|
|
|
assert (s);
|
|
- assert (!s->d);
|
|
- assert (!s->h);
|
|
-
|
|
- CUDA_CALL (cuMemAllocHost, &s->h, size);
|
|
- CUDA_CALL (cuMemHostGetDevicePointer, &s->d, s->h, 0);
|
|
|
|
- assert (s->h);
|
|
+ s->map = cuda_map_create (size);
|
|
|
|
- s->h_begin = s->h;
|
|
- s->h_end = s->h_begin + size;
|
|
- s->h_next = s->h_prev = s->h_tail = s->h_begin;
|
|
-
|
|
- assert (s->h_next);
|
|
- assert (s->h_end);
|
|
return true;
|
|
}
|
|
|
|
static bool
|
|
map_fini (struct ptx_stream *s)
|
|
{
|
|
- CUDA_CALL (cuMemFreeHost, s->h);
|
|
+ assert (s->map->next == NULL);
|
|
+
|
|
+ cuda_map_destroy (s->map);
|
|
+
|
|
return true;
|
|
}
|
|
|
|
static void
|
|
map_pop (struct ptx_stream *s)
|
|
{
|
|
- struct map *m;
|
|
+ struct cuda_map *next;
|
|
|
|
assert (s != NULL);
|
|
- assert (s->h_next);
|
|
- assert (s->h_prev);
|
|
- assert (s->h_tail);
|
|
-
|
|
- m = s->h_tail;
|
|
-
|
|
- s->h_tail += m->size;
|
|
-
|
|
- if (s->h_tail >= s->h_end)
|
|
- s->h_tail = s->h_begin + (int) (s->h_tail - s->h_end);
|
|
-
|
|
- if (s->h_next == s->h_tail)
|
|
- s->h_prev = s->h_next;
|
|
|
|
- assert (s->h_next >= s->h_begin);
|
|
- assert (s->h_tail >= s->h_begin);
|
|
- assert (s->h_prev >= s->h_begin);
|
|
+ if (s->map->next == NULL)
|
|
+ {
|
|
+ s->map->active = false;
|
|
+ return;
|
|
+ }
|
|
|
|
- assert (s->h_next <= s->h_end);
|
|
- assert (s->h_tail <= s->h_end);
|
|
- assert (s->h_prev <= s->h_end);
|
|
+ next = s->map->next;
|
|
+ cuda_map_destroy (s->map);
|
|
+ s->map = next;
|
|
}
|
|
|
|
-static void
|
|
-map_push (struct ptx_stream *s, int async, size_t size, void **h, void **d)
|
|
+static CUdeviceptr
|
|
+map_push (struct ptx_stream *s, size_t size)
|
|
{
|
|
- int left;
|
|
- int offset;
|
|
- struct map *m;
|
|
+ struct cuda_map *map = NULL;
|
|
+ struct cuda_map **t;
|
|
|
|
- assert (s != NULL);
|
|
-
|
|
- left = s->h_end - s->h_next;
|
|
- size += sizeof (struct map);
|
|
-
|
|
- assert (s->h_prev);
|
|
- assert (s->h_next);
|
|
+ assert (s);
|
|
+ assert (s->map);
|
|
|
|
- if (size >= left)
|
|
+ /* Select an element to push. */
|
|
+ if (s->map->active)
|
|
+ map = cuda_map_create (size);
|
|
+ else
|
|
{
|
|
- m = s->h_prev;
|
|
- m->size += left;
|
|
- s->h_next = s->h_begin;
|
|
-
|
|
- if (s->h_next + size > s->h_end)
|
|
- GOMP_PLUGIN_fatal ("unable to push map");
|
|
- }
|
|
-
|
|
- assert (s->h_next);
|
|
-
|
|
- m = s->h_next;
|
|
- m->async = async;
|
|
- m->size = size;
|
|
+ /* Pop the inactive front element. */
|
|
+ struct cuda_map *pop = s->map;
|
|
+ s->map = pop->next;
|
|
+ pop->next = NULL;
|
|
|
|
- offset = (void *)&m->mappings[0] - s->h;
|
|
+ if (pop->size < size)
|
|
+ {
|
|
+ cuda_map_destroy (pop);
|
|
|
|
- *d = (void *)(s->d + offset);
|
|
- *h = (void *)(s->h + offset);
|
|
+ map = cuda_map_create (size);
|
|
+ }
|
|
+ else
|
|
+ map = pop;
|
|
+ }
|
|
|
|
- s->h_prev = s->h_next;
|
|
- s->h_next += size;
|
|
+ /* Check that the element is as expected. */
|
|
+ assert (map->next == NULL);
|
|
+ assert (!map->active);
|
|
|
|
- assert (s->h_prev);
|
|
- assert (s->h_next);
|
|
+ /* Mark the element active. */
|
|
+ map->active = true;
|
|
|
|
- assert (s->h_next >= s->h_begin);
|
|
- assert (s->h_tail >= s->h_begin);
|
|
- assert (s->h_prev >= s->h_begin);
|
|
- assert (s->h_next <= s->h_end);
|
|
- assert (s->h_tail <= s->h_end);
|
|
- assert (s->h_prev <= s->h_end);
|
|
+ /* Push the element to the back of the list. */
|
|
+ for (t = &s->map; (*t) != NULL; t = &(*t)->next)
|
|
+ ;
|
|
+ assert (t != NULL && *t == NULL);
|
|
+ *t = map;
|
|
|
|
- return;
|
|
+ return map->d;
|
|
}
|
|
|
|
/* Target data function launch information. */
|
|
@@ -411,6 +438,10 @@ struct ptx_device
|
|
int num_sms;
|
|
int regs_per_block;
|
|
int regs_per_sm;
|
|
+ int warp_size;
|
|
+ int max_threads_per_block;
|
|
+ int max_threads_per_multiprocessor;
|
|
+ int default_dims[GOMP_DIM_MAX];
|
|
|
|
struct ptx_image_data *images; /* Images loaded on device. */
|
|
pthread_mutex_t image_lock; /* Lock for above list. */
|
|
@@ -458,8 +489,6 @@ init_streams_for_device (struct ptx_devi
|
|
null_stream->stream = NULL;
|
|
null_stream->host_thread = pthread_self ();
|
|
null_stream->multithreaded = true;
|
|
- null_stream->d = (CUdeviceptr) NULL;
|
|
- null_stream->h = NULL;
|
|
if (!map_init (null_stream))
|
|
return false;
|
|
|
|
@@ -594,8 +623,6 @@ select_stream_for_async (int async, pthr
|
|
s->host_thread = thread;
|
|
s->multithreaded = false;
|
|
|
|
- s->d = (CUdeviceptr) NULL;
|
|
- s->h = NULL;
|
|
if (!map_init (s))
|
|
{
|
|
pthread_mutex_unlock (&ptx_dev->stream_lock);
|
|
@@ -777,9 +804,11 @@ nvptx_open_device (int n)
|
|
&pi, CU_DEVICE_ATTRIBUTE_MAX_REGISTERS_PER_BLOCK, dev);
|
|
ptx_dev->regs_per_block = pi;
|
|
|
|
- /* CU_DEVICE_ATTRIBUTE_MAX_REGISTERS_PER_MULTIPROCESSOR = 82 is defined only
|
|
+ /* CU_DEVICE_ATTRIBUTE_MAX_REGISTERS_PER_MULTIPROCESSOR is defined only
|
|
in CUDA 6.0 and newer. */
|
|
- r = CUDA_CALL_NOCHECK (cuDeviceGetAttribute, &pi, 82, dev);
|
|
+ r = CUDA_CALL_NOCHECK (cuDeviceGetAttribute, &pi,
|
|
+ CU_DEVICE_ATTRIBUTE_MAX_REGISTERS_PER_MULTIPROCESSOR,
|
|
+ dev);
|
|
/* Fallback: use limit of registers per block, which is usually equal. */
|
|
if (r == CUDA_ERROR_INVALID_VALUE)
|
|
pi = ptx_dev->regs_per_block;
|
|
@@ -797,12 +826,24 @@ nvptx_open_device (int n)
|
|
GOMP_PLUGIN_error ("Only warp size 32 is supported");
|
|
return NULL;
|
|
}
|
|
+ ptx_dev->warp_size = pi;
|
|
+
|
|
+ CUDA_CALL_ERET (NULL, cuDeviceGetAttribute, &pi,
|
|
+ CU_DEVICE_ATTRIBUTE_MAX_THREADS_PER_BLOCK, dev);
|
|
+ ptx_dev->max_threads_per_block = pi;
|
|
+
|
|
+ CUDA_CALL_ERET (NULL, cuDeviceGetAttribute, &pi,
|
|
+ CU_DEVICE_ATTRIBUTE_MAX_THREADS_PER_MULTIPROCESSOR, dev);
|
|
+ ptx_dev->max_threads_per_multiprocessor = pi;
|
|
|
|
r = CUDA_CALL_NOCHECK (cuDeviceGetAttribute, &async_engines,
|
|
CU_DEVICE_ATTRIBUTE_ASYNC_ENGINE_COUNT, dev);
|
|
if (r != CUDA_SUCCESS)
|
|
async_engines = 1;
|
|
|
|
+ for (int i = 0; i != GOMP_DIM_MAX; i++)
|
|
+ ptx_dev->default_dims[i] = 0;
|
|
+
|
|
ptx_dev->images = NULL;
|
|
pthread_mutex_init (&ptx_dev->image_lock, NULL);
|
|
|
|
@@ -876,12 +917,42 @@ notify_var (const char *var_name, const
|
|
GOMP_PLUGIN_debug (0, "%s: '%s'\n", var_name, env_var);
|
|
}
|
|
|
|
+static void
|
|
+process_GOMP_NVPTX_JIT (intptr_t *gomp_nvptx_o)
|
|
+{
|
|
+ const char *var_name = "GOMP_NVPTX_JIT";
|
|
+ const char *env_var = secure_getenv (var_name);
|
|
+ notify_var (var_name, env_var);
|
|
+
|
|
+ if (env_var == NULL)
|
|
+ return;
|
|
+
|
|
+ const char *c = env_var;
|
|
+ while (*c != '\0')
|
|
+ {
|
|
+ while (*c == ' ')
|
|
+ c++;
|
|
+
|
|
+ if (c[0] == '-' && c[1] == 'O'
|
|
+ && '0' <= c[2] && c[2] <= '4'
|
|
+ && (c[3] == '\0' || c[3] == ' '))
|
|
+ {
|
|
+ *gomp_nvptx_o = c[2] - '0';
|
|
+ c += 3;
|
|
+ continue;
|
|
+ }
|
|
+
|
|
+ GOMP_PLUGIN_error ("Error parsing %s", var_name);
|
|
+ break;
|
|
+ }
|
|
+}
|
|
+
|
|
static bool
|
|
link_ptx (CUmodule *module, const struct targ_ptx_obj *ptx_objs,
|
|
unsigned num_objs)
|
|
{
|
|
- CUjit_option opts[6];
|
|
- void *optvals[6];
|
|
+ CUjit_option opts[7];
|
|
+ void *optvals[7];
|
|
float elapsed = 0.0;
|
|
char elog[1024];
|
|
char ilog[16384];
|
|
@@ -908,16 +979,41 @@ link_ptx (CUmodule *module, const struct
|
|
opts[5] = CU_JIT_LOG_VERBOSE;
|
|
optvals[5] = (void *) 1;
|
|
|
|
- CUDA_CALL (cuLinkCreate, 6, opts, optvals, &linkstate);
|
|
+ static intptr_t gomp_nvptx_o = -1;
|
|
+
|
|
+ static bool init_done = false;
|
|
+ if (!init_done)
|
|
+ {
|
|
+ process_GOMP_NVPTX_JIT (&gomp_nvptx_o);
|
|
+ init_done = true;
|
|
+ }
|
|
+
|
|
+ int nopts = 6;
|
|
+ if (gomp_nvptx_o != -1)
|
|
+ {
|
|
+ opts[nopts] = CU_JIT_OPTIMIZATION_LEVEL;
|
|
+ optvals[nopts] = (void *) gomp_nvptx_o;
|
|
+ nopts++;
|
|
+ }
|
|
+
|
|
+ if (CUDA_CALL_EXISTS (cuLinkCreate_v2))
|
|
+ CUDA_CALL (cuLinkCreate_v2, nopts, opts, optvals, &linkstate);
|
|
+ else
|
|
+ CUDA_CALL (cuLinkCreate, nopts, opts, optvals, &linkstate);
|
|
|
|
for (; num_objs--; ptx_objs++)
|
|
{
|
|
/* cuLinkAddData's 'data' argument erroneously omits the const
|
|
qualifier. */
|
|
GOMP_PLUGIN_debug (0, "Loading:\n---\n%s\n---\n", ptx_objs->code);
|
|
- r = CUDA_CALL_NOCHECK (cuLinkAddData, linkstate, CU_JIT_INPUT_PTX,
|
|
- (char *) ptx_objs->code, ptx_objs->size,
|
|
- 0, 0, 0, 0);
|
|
+ if (CUDA_CALL_EXISTS (cuLinkAddData_v2))
|
|
+ r = CUDA_CALL_NOCHECK (cuLinkAddData_v2, linkstate, CU_JIT_INPUT_PTX,
|
|
+ (char *) ptx_objs->code, ptx_objs->size,
|
|
+ 0, 0, 0, 0);
|
|
+ else
|
|
+ r = CUDA_CALL_NOCHECK (cuLinkAddData, linkstate, CU_JIT_INPUT_PTX,
|
|
+ (char *) ptx_objs->code, ptx_objs->size,
|
|
+ 0, 0, 0, 0);
|
|
if (r != CUDA_SUCCESS)
|
|
{
|
|
GOMP_PLUGIN_error ("Link error log %s\n", &elog[0]);
|
|
@@ -1067,8 +1163,10 @@ nvptx_exec (void (*fn), size_t mapnum, v
|
|
int i;
|
|
struct ptx_stream *dev_str;
|
|
void *kargs[1];
|
|
- void *hp, *dp;
|
|
+ void *hp;
|
|
+ CUdeviceptr dp = 0;
|
|
struct nvptx_thread *nvthd = nvptx_thread ();
|
|
+ int warp_size = nvthd->ptx_dev->warp_size;
|
|
const char *maybe_abort_msg = "(perhaps abort was called)";
|
|
|
|
function = targ_fn->fn;
|
|
@@ -1090,68 +1188,36 @@ nvptx_exec (void (*fn), size_t mapnum, v
|
|
|
|
if (seen_zero)
|
|
{
|
|
- /* See if the user provided GOMP_OPENACC_DIM environment
|
|
- variable to specify runtime defaults. */
|
|
- static int default_dims[GOMP_DIM_MAX];
|
|
-
|
|
pthread_mutex_lock (&ptx_dev_lock);
|
|
- if (!default_dims[0])
|
|
- {
|
|
- const char *var_name = "GOMP_OPENACC_DIM";
|
|
- /* We only read the environment variable once. You can't
|
|
- change it in the middle of execution. The syntax is
|
|
- the same as for the -fopenacc-dim compilation option. */
|
|
- const char *env_var = getenv (var_name);
|
|
- notify_var (var_name, env_var);
|
|
- if (env_var)
|
|
- {
|
|
- const char *pos = env_var;
|
|
|
|
- for (i = 0; *pos && i != GOMP_DIM_MAX; i++)
|
|
- {
|
|
- if (i && *pos++ != ':')
|
|
- break;
|
|
- if (*pos != ':')
|
|
- {
|
|
- const char *eptr;
|
|
-
|
|
- errno = 0;
|
|
- long val = strtol (pos, (char **)&eptr, 10);
|
|
- if (errno || val < 0 || (unsigned)val != val)
|
|
- break;
|
|
- default_dims[i] = (int)val;
|
|
- pos = eptr;
|
|
- }
|
|
- }
|
|
- }
|
|
+ static int gomp_openacc_dims[GOMP_DIM_MAX];
|
|
+ if (!gomp_openacc_dims[0])
|
|
+ {
|
|
+ /* See if the user provided GOMP_OPENACC_DIM environment
|
|
+ variable to specify runtime defaults. */
|
|
+ for (int i = 0; i < GOMP_DIM_MAX; ++i)
|
|
+ gomp_openacc_dims[i] = GOMP_PLUGIN_acc_default_dim (i);
|
|
+ }
|
|
|
|
- int warp_size, block_size, dev_size, cpu_size;
|
|
- CUdevice dev = nvptx_thread()->ptx_dev->dev;
|
|
- /* 32 is the default for known hardware. */
|
|
- int gang = 0, worker = 32, vector = 32;
|
|
- CUdevice_attribute cu_tpb, cu_ws, cu_mpc, cu_tpm;
|
|
-
|
|
- cu_tpb = CU_DEVICE_ATTRIBUTE_MAX_THREADS_PER_BLOCK;
|
|
- cu_ws = CU_DEVICE_ATTRIBUTE_WARP_SIZE;
|
|
- cu_mpc = CU_DEVICE_ATTRIBUTE_MULTIPROCESSOR_COUNT;
|
|
- cu_tpm = CU_DEVICE_ATTRIBUTE_MAX_THREADS_PER_MULTIPROCESSOR;
|
|
-
|
|
- if (CUDA_CALL_NOCHECK (cuDeviceGetAttribute, &block_size, cu_tpb,
|
|
- dev) == CUDA_SUCCESS
|
|
- && CUDA_CALL_NOCHECK (cuDeviceGetAttribute, &warp_size, cu_ws,
|
|
- dev) == CUDA_SUCCESS
|
|
- && CUDA_CALL_NOCHECK (cuDeviceGetAttribute, &dev_size, cu_mpc,
|
|
- dev) == CUDA_SUCCESS
|
|
- && CUDA_CALL_NOCHECK (cuDeviceGetAttribute, &cpu_size, cu_tpm,
|
|
- dev) == CUDA_SUCCESS)
|
|
- {
|
|
- GOMP_PLUGIN_debug (0, " warp_size=%d, block_size=%d,"
|
|
- " dev_size=%d, cpu_size=%d\n",
|
|
- warp_size, block_size, dev_size, cpu_size);
|
|
- gang = (cpu_size / block_size) * dev_size;
|
|
- worker = block_size / warp_size;
|
|
- vector = warp_size;
|
|
- }
|
|
+ if (!nvthd->ptx_dev->default_dims[0])
|
|
+ {
|
|
+ int default_dims[GOMP_DIM_MAX];
|
|
+ for (int i = 0; i < GOMP_DIM_MAX; ++i)
|
|
+ default_dims[i] = gomp_openacc_dims[i];
|
|
+
|
|
+ int gang, worker, vector;
|
|
+ {
|
|
+ int block_size = nvthd->ptx_dev->max_threads_per_block;
|
|
+ int cpu_size = nvthd->ptx_dev->max_threads_per_multiprocessor;
|
|
+ int dev_size = nvthd->ptx_dev->num_sms;
|
|
+ GOMP_PLUGIN_debug (0, " warp_size=%d, block_size=%d,"
|
|
+ " dev_size=%d, cpu_size=%d\n",
|
|
+ warp_size, block_size, dev_size, cpu_size);
|
|
+
|
|
+ gang = (cpu_size / block_size) * dev_size;
|
|
+ worker = block_size / warp_size;
|
|
+ vector = warp_size;
|
|
+ }
|
|
|
|
/* There is no upper bound on the gang size. The best size
|
|
matches the hardware configuration. Logical gangs are
|
|
@@ -1172,29 +1238,150 @@ nvptx_exec (void (*fn), size_t mapnum, v
|
|
default_dims[GOMP_DIM_GANG],
|
|
default_dims[GOMP_DIM_WORKER],
|
|
default_dims[GOMP_DIM_VECTOR]);
|
|
+
|
|
+ for (i = 0; i != GOMP_DIM_MAX; i++)
|
|
+ nvthd->ptx_dev->default_dims[i] = default_dims[i];
|
|
}
|
|
pthread_mutex_unlock (&ptx_dev_lock);
|
|
|
|
- for (i = 0; i != GOMP_DIM_MAX; i++)
|
|
- if (!dims[i])
|
|
- dims[i] = default_dims[i];
|
|
- }
|
|
-
|
|
- /* This reserves a chunk of a pre-allocated page of memory mapped on both
|
|
- the host and the device. HP is a host pointer to the new chunk, and DP is
|
|
- the corresponding device pointer. */
|
|
- map_push (dev_str, async, mapnum * sizeof (void *), &hp, &dp);
|
|
-
|
|
- GOMP_PLUGIN_debug (0, " %s: prepare mappings\n", __FUNCTION__);
|
|
-
|
|
- /* Copy the array of arguments to the mapped page. */
|
|
- for (i = 0; i < mapnum; i++)
|
|
- ((void **) hp)[i] = devaddrs[i];
|
|
-
|
|
- /* Copy the (device) pointers to arguments to the device (dp and hp might in
|
|
- fact have the same value on a unified-memory system). */
|
|
- CUDA_CALL_ASSERT (cuMemcpy, (CUdeviceptr) dp, (CUdeviceptr) hp,
|
|
- mapnum * sizeof (void *));
|
|
+ {
|
|
+ bool default_dim_p[GOMP_DIM_MAX];
|
|
+ for (i = 0; i != GOMP_DIM_MAX; i++)
|
|
+ default_dim_p[i] = !dims[i];
|
|
+
|
|
+ if (!CUDA_CALL_EXISTS (cuOccupancyMaxPotentialBlockSize))
|
|
+ {
|
|
+ for (i = 0; i != GOMP_DIM_MAX; i++)
|
|
+ if (default_dim_p[i])
|
|
+ dims[i] = nvthd->ptx_dev->default_dims[i];
|
|
+
|
|
+ if (default_dim_p[GOMP_DIM_VECTOR])
|
|
+ dims[GOMP_DIM_VECTOR]
|
|
+ = MIN (dims[GOMP_DIM_VECTOR],
|
|
+ (targ_fn->max_threads_per_block / warp_size
|
|
+ * warp_size));
|
|
+
|
|
+ if (default_dim_p[GOMP_DIM_WORKER])
|
|
+ dims[GOMP_DIM_WORKER]
|
|
+ = MIN (dims[GOMP_DIM_WORKER],
|
|
+ targ_fn->max_threads_per_block / dims[GOMP_DIM_VECTOR]);
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+ /* Handle the case that the compiler allows the runtime to choose
|
|
+ the vector-length conservatively, by ignoring
|
|
+ gomp_openacc_dims[GOMP_DIM_VECTOR]. TODO: actually handle
|
|
+ it. */
|
|
+ int vectors = 0;
|
|
+ /* TODO: limit gomp_openacc_dims[GOMP_DIM_WORKER] such that that
|
|
+ gomp_openacc_dims[GOMP_DIM_WORKER] * actual_vectors does not
|
|
+ exceed targ_fn->max_threads_per_block. */
|
|
+ int workers = gomp_openacc_dims[GOMP_DIM_WORKER];
|
|
+ int gangs = gomp_openacc_dims[GOMP_DIM_GANG];
|
|
+ int grids, blocks;
|
|
+
|
|
+ CUDA_CALL_ASSERT (cuOccupancyMaxPotentialBlockSize, &grids,
|
|
+ &blocks, function, NULL, 0,
|
|
+ dims[GOMP_DIM_WORKER] * dims[GOMP_DIM_VECTOR]);
|
|
+ GOMP_PLUGIN_debug (0, "cuOccupancyMaxPotentialBlockSize: "
|
|
+ "grid = %d, block = %d\n", grids, blocks);
|
|
+
|
|
+ /* Keep the num_gangs proportional to the block size. In
|
|
+ the case were a block size is limited by shared-memory
|
|
+ or the register file capacity, the runtime will not
|
|
+ excessively over assign gangs to the multiprocessor
|
|
+ units if their state is going to be swapped out even
|
|
+ more than necessary. The constant factor 2 is there to
|
|
+ prevent threads from idling when there is insufficient
|
|
+ work for them. */
|
|
+ if (gangs == 0)
|
|
+ gangs = 2 * grids * (blocks / warp_size);
|
|
+
|
|
+ if (vectors == 0)
|
|
+ vectors = warp_size;
|
|
+
|
|
+ if (workers == 0)
|
|
+ {
|
|
+ int actual_vectors = (default_dim_p[GOMP_DIM_VECTOR]
|
|
+ ? vectors
|
|
+ : dims[GOMP_DIM_VECTOR]);
|
|
+ workers = blocks / actual_vectors;
|
|
+ workers = MAX (workers, 1);
|
|
+ /* If we need a per-worker barrier ... . */
|
|
+ if (actual_vectors > 32)
|
|
+ /* Don't use more barriers than available. */
|
|
+ workers = MIN (workers, 15);
|
|
+ }
|
|
+
|
|
+ for (i = 0; i != GOMP_DIM_MAX; i++)
|
|
+ if (default_dim_p[i])
|
|
+ switch (i)
|
|
+ {
|
|
+ case GOMP_DIM_GANG: dims[i] = gangs; break;
|
|
+ case GOMP_DIM_WORKER: dims[i] = workers; break;
|
|
+ case GOMP_DIM_VECTOR: dims[i] = vectors; break;
|
|
+ default: GOMP_PLUGIN_fatal ("invalid dim");
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
+ /* Check if the accelerator has sufficient hardware resources to
|
|
+ launch the offloaded kernel. */
|
|
+ if (dims[GOMP_DIM_WORKER] * dims[GOMP_DIM_VECTOR]
|
|
+ > targ_fn->max_threads_per_block)
|
|
+ {
|
|
+ const char *msg
|
|
+ = ("The Nvidia accelerator has insufficient resources to launch '%s'"
|
|
+ " with num_workers = %d and vector_length = %d"
|
|
+ "; "
|
|
+ "recompile the program with 'num_workers = x and vector_length = y'"
|
|
+ " on that offloaded region or '-fopenacc-dim=:x:y' where"
|
|
+ " x * y <= %d"
|
|
+ ".\n");
|
|
+ GOMP_PLUGIN_fatal (msg, targ_fn->launch->fn, dims[GOMP_DIM_WORKER],
|
|
+ dims[GOMP_DIM_VECTOR], targ_fn->max_threads_per_block);
|
|
+ }
|
|
+
|
|
+ /* Check if the accelerator has sufficient barrier resources to
|
|
+ launch the offloaded kernel. */
|
|
+ if (dims[GOMP_DIM_WORKER] > 15 && dims[GOMP_DIM_VECTOR] > 32)
|
|
+ {
|
|
+ const char *msg
|
|
+ = ("The Nvidia accelerator has insufficient barrier resources to launch"
|
|
+ " '%s' with num_workers = %d and vector_length = %d"
|
|
+ "; "
|
|
+ "recompile the program with 'num_workers = x' on that offloaded"
|
|
+ " region or '-fopenacc-dim=:x:' where x <= 15"
|
|
+ "; "
|
|
+ "or, recompile the program with 'vector_length = 32' on that"
|
|
+ " offloaded region or '-fopenacc-dim=::32'"
|
|
+ ".\n");
|
|
+ GOMP_PLUGIN_fatal (msg, targ_fn->launch->fn, dims[GOMP_DIM_WORKER],
|
|
+ dims[GOMP_DIM_VECTOR]);
|
|
+ }
|
|
+
|
|
+ if (mapnum > 0)
|
|
+ {
|
|
+ /* This reserves a chunk of a pre-allocated page of memory mapped on both
|
|
+ the host and the device. HP is a host pointer to the new chunk, and DP is
|
|
+ the corresponding device pointer. */
|
|
+ pthread_mutex_lock (&ptx_event_lock);
|
|
+ dp = map_push (dev_str, mapnum * sizeof (void *));
|
|
+ pthread_mutex_unlock (&ptx_event_lock);
|
|
+
|
|
+ GOMP_PLUGIN_debug (0, " %s: prepare mappings\n", __FUNCTION__);
|
|
+
|
|
+ /* Copy the array of arguments to the mapped page. */
|
|
+ hp = alloca(sizeof(void *) * mapnum);
|
|
+ for (i = 0; i < mapnum; i++)
|
|
+ ((void **) hp)[i] = devaddrs[i];
|
|
+
|
|
+ /* Copy the (device) pointers to arguments to the device */
|
|
+ CUDA_CALL_ASSERT (cuMemcpyHtoD, dp, hp,
|
|
+ mapnum * sizeof (void *));
|
|
+ }
|
|
+
|
|
GOMP_PLUGIN_debug (0, " %s: kernel %s: launch"
|
|
" gangs=%u, workers=%u, vectors=%u\n",
|
|
__FUNCTION__, targ_fn->launch->fn, dims[GOMP_DIM_GANG],
|
|
@@ -1239,7 +1426,8 @@ nvptx_exec (void (*fn), size_t mapnum, v
|
|
|
|
CUDA_CALL_ASSERT (cuEventRecord, *e, dev_str->stream);
|
|
|
|
- event_add (PTX_EVT_KNL, e, (void *)dev_str, 0);
|
|
+ if (mapnum > 0)
|
|
+ event_add (PTX_EVT_KNL, e, (void *)dev_str, 0);
|
|
}
|
|
#else
|
|
r = CUDA_CALL_NOCHECK (cuCtxSynchronize, );
|
|
@@ -1256,7 +1444,10 @@ nvptx_exec (void (*fn), size_t mapnum, v
|
|
#ifndef DISABLE_ASYNC
|
|
if (async < acc_async_noval)
|
|
#endif
|
|
- map_pop (dev_str);
|
|
+ {
|
|
+ if (mapnum > 0)
|
|
+ map_pop (dev_str);
|
|
+ }
|
|
}
|
|
|
|
void * openacc_get_current_cuda_context (void);
|
|
@@ -1415,9 +1606,8 @@ nvptx_async_test (int async)
|
|
struct ptx_stream *s;
|
|
|
|
s = select_stream_for_async (async, pthread_self (), false, NULL);
|
|
-
|
|
if (!s)
|
|
- GOMP_PLUGIN_fatal ("unknown async %d", async);
|
|
+ return 1;
|
|
|
|
r = CUDA_CALL_NOCHECK (cuStreamQuery, s->stream);
|
|
if (r == CUDA_SUCCESS)
|
|
@@ -1472,7 +1662,7 @@ nvptx_wait (int async)
|
|
|
|
s = select_stream_for_async (async, pthread_self (), false, NULL);
|
|
if (!s)
|
|
- GOMP_PLUGIN_fatal ("unknown async %d", async);
|
|
+ return;
|
|
|
|
CUDA_CALL_ASSERT (cuStreamSynchronize, s->stream);
|
|
|
|
@@ -1486,16 +1676,17 @@ nvptx_wait_async (int async1, int async2
|
|
struct ptx_stream *s1, *s2;
|
|
pthread_t self = pthread_self ();
|
|
|
|
+ s1 = select_stream_for_async (async1, self, false, NULL);
|
|
+ if (!s1)
|
|
+ return;
|
|
+
|
|
/* The stream that is waiting (rather than being waited for) doesn't
|
|
necessarily have to exist already. */
|
|
s2 = select_stream_for_async (async2, self, true, NULL);
|
|
|
|
- s1 = select_stream_for_async (async1, self, false, NULL);
|
|
- if (!s1)
|
|
- GOMP_PLUGIN_fatal ("invalid async 1\n");
|
|
-
|
|
+ /* A stream is always synchronized with itself. */
|
|
if (s1 == s2)
|
|
- GOMP_PLUGIN_fatal ("identical parameters");
|
|
+ return;
|
|
|
|
e = (CUevent *) GOMP_PLUGIN_malloc (sizeof (CUevent));
|
|
|
|
@@ -1629,8 +1820,14 @@ nvptx_set_cuda_stream (int async, void *
|
|
pthread_t self = pthread_self ();
|
|
struct nvptx_thread *nvthd = nvptx_thread ();
|
|
|
|
- if (async < 0)
|
|
- GOMP_PLUGIN_fatal ("bad async %d", async);
|
|
+ /* Due to the "null_stream" usage for "acc_async_sync", this cannot be used
|
|
+ to change the stream handle associated with "acc_async_sync". */
|
|
+ if (async == acc_async_sync)
|
|
+ {
|
|
+ GOMP_PLUGIN_debug (0, "Refusing request to set CUDA stream associated"
|
|
+ " with \"acc_async_sync\"\n");
|
|
+ return 0;
|
|
+ }
|
|
|
|
pthread_mutex_lock (&nvthd->ptx_dev->stream_lock);
|
|
|
|
@@ -1739,6 +1936,12 @@ GOMP_OFFLOAD_fini_device (int n)
|
|
instantiated_devices--;
|
|
}
|
|
|
|
+ if (instantiated_devices == 0)
|
|
+ {
|
|
+ free (ptx_devices);
|
|
+ ptx_devices = NULL;
|
|
+ }
|
|
+
|
|
pthread_mutex_unlock (&ptx_dev_lock);
|
|
return true;
|
|
}
|
|
--- libgomp/plugin/configfrag.ac.jj 2018-04-25 09:40:31.914655581 +0200
|
|
+++ libgomp/plugin/configfrag.ac 2019-05-07 18:46:36.533109624 +0200
|
|
@@ -26,8 +26,6 @@
|
|
# see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
|
|
# <http://www.gnu.org/licenses/>.
|
|
|
|
-offload_targets=
|
|
-AC_SUBST(offload_targets)
|
|
plugin_support=yes
|
|
AC_CHECK_LIB(dl, dlsym, , [plugin_support=no])
|
|
if test x"$plugin_support" = xyes; then
|
|
@@ -59,7 +57,11 @@ AC_ARG_WITH(cuda-driver-lib,
|
|
[AS_HELP_STRING([--with-cuda-driver-lib=PATH],
|
|
[specify directory for the installed CUDA driver library])])
|
|
case "x$with_cuda_driver" in
|
|
- x | xno) ;;
|
|
+ x) ;;
|
|
+ xno)
|
|
+ CUDA_DRIVER_INCLUDE=no
|
|
+ CUDA_DRIVER_LIB=no
|
|
+ ;;
|
|
*) CUDA_DRIVER_INCLUDE=$with_cuda_driver/include
|
|
CUDA_DRIVER_LIB=$with_cuda_driver/lib
|
|
;;
|
|
@@ -70,10 +72,12 @@ fi
|
|
if test "x$with_cuda_driver_lib" != x; then
|
|
CUDA_DRIVER_LIB=$with_cuda_driver_lib
|
|
fi
|
|
-if test "x$CUDA_DRIVER_INCLUDE" != x; then
|
|
+if test "x$CUDA_DRIVER_INCLUDE" != x \
|
|
+ && test "x$CUDA_DRIVER_INCLUDE" != xno; then
|
|
CUDA_DRIVER_CPPFLAGS=-I$CUDA_DRIVER_INCLUDE
|
|
fi
|
|
-if test "x$CUDA_DRIVER_LIB" != x; then
|
|
+if test "x$CUDA_DRIVER_LIB" != x \
|
|
+ && test "x$CUDA_DRIVER_LIB" != xno; then
|
|
CUDA_DRIVER_LDFLAGS=-L$CUDA_DRIVER_LIB
|
|
fi
|
|
|
|
@@ -133,7 +137,13 @@ AC_SUBST(PLUGIN_HSA_CPPFLAGS)
|
|
AC_SUBST(PLUGIN_HSA_LDFLAGS)
|
|
AC_SUBST(PLUGIN_HSA_LIBS)
|
|
|
|
-# Get offload targets and path to install tree of offloading compiler.
|
|
+# Parse '--enable-offload-targets', figure out the corresponding libgomp
|
|
+# plugins, and configure to find the corresponding offload compilers.
|
|
+# 'offload_plugins' and 'offload_targets' will be populated in the same order.
|
|
+offload_plugins=
|
|
+offload_targets=
|
|
+AC_SUBST(offload_plugins)
|
|
+AC_SUBST(offload_targets)
|
|
offload_additional_options=
|
|
offload_additional_lib_paths=
|
|
AC_SUBST(offload_additional_options)
|
|
@@ -152,10 +152,10 @@ if test x"$enable_offload_targets" != x;
|
|
for tgt in `echo $enable_offload_targets | sed -e 's#,# #g'`; do
|
|
tgt_dir=`echo $tgt | grep '=' | sed 's/.*=//'`
|
|
tgt=`echo $tgt | sed 's/=.*//'`
|
|
- tgt_name=
|
|
+ tgt_plugin=
|
|
case $tgt in
|
|
*-intelmic-* | *-intelmicemul-*)
|
|
- tgt_name=intelmic
|
|
+ tgt_plugin=intelmic
|
|
;;
|
|
nvptx*)
|
|
case "${target}" in
|
|
@@ -167,30 +167,35 @@ if test x"$enable_offload_targets" != x;
|
|
PLUGIN_NVPTX=0
|
|
;;
|
|
*)
|
|
- tgt_name=nvptx
|
|
+ tgt_plugin=nvptx
|
|
PLUGIN_NVPTX=$tgt
|
|
- PLUGIN_NVPTX_CPPFLAGS=$CUDA_DRIVER_CPPFLAGS
|
|
- PLUGIN_NVPTX_LDFLAGS=$CUDA_DRIVER_LDFLAGS
|
|
- PLUGIN_NVPTX_LIBS='-lcuda'
|
|
+ if test "x$CUDA_DRIVER_LIB" != xno \
|
|
+ && test "x$CUDA_DRIVER_LIB" != xno; then
|
|
+ PLUGIN_NVPTX_CPPFLAGS=$CUDA_DRIVER_CPPFLAGS
|
|
+ PLUGIN_NVPTX_LDFLAGS=$CUDA_DRIVER_LDFLAGS
|
|
+ PLUGIN_NVPTX_LIBS='-lcuda'
|
|
|
|
- PLUGIN_NVPTX_save_CPPFLAGS=$CPPFLAGS
|
|
- CPPFLAGS="$PLUGIN_NVPTX_CPPFLAGS $CPPFLAGS"
|
|
- PLUGIN_NVPTX_save_LDFLAGS=$LDFLAGS
|
|
- LDFLAGS="$PLUGIN_NVPTX_LDFLAGS $LDFLAGS"
|
|
- PLUGIN_NVPTX_save_LIBS=$LIBS
|
|
- LIBS="$PLUGIN_NVPTX_LIBS $LIBS"
|
|
- AC_LINK_IFELSE(
|
|
- [AC_LANG_PROGRAM(
|
|
- [#include "cuda.h"],
|
|
- [CUresult r = cuCtxPushCurrent (NULL);])],
|
|
- [PLUGIN_NVPTX=1])
|
|
- CPPFLAGS=$PLUGIN_NVPTX_save_CPPFLAGS
|
|
- LDFLAGS=$PLUGIN_NVPTX_save_LDFLAGS
|
|
- LIBS=$PLUGIN_NVPTX_save_LIBS
|
|
+ PLUGIN_NVPTX_save_CPPFLAGS=$CPPFLAGS
|
|
+ CPPFLAGS="$PLUGIN_NVPTX_CPPFLAGS $CPPFLAGS"
|
|
+ PLUGIN_NVPTX_save_LDFLAGS=$LDFLAGS
|
|
+ LDFLAGS="$PLUGIN_NVPTX_LDFLAGS $LDFLAGS"
|
|
+ PLUGIN_NVPTX_save_LIBS=$LIBS
|
|
+ LIBS="$PLUGIN_NVPTX_LIBS $LIBS"
|
|
+ AC_LINK_IFELSE(
|
|
+ [AC_LANG_PROGRAM(
|
|
+ [#include "cuda.h"],
|
|
+ [CUresult r = cuCtxPushCurrent (NULL);])],
|
|
+ [PLUGIN_NVPTX=1])
|
|
+ CPPFLAGS=$PLUGIN_NVPTX_save_CPPFLAGS
|
|
+ LDFLAGS=$PLUGIN_NVPTX_save_LDFLAGS
|
|
+ LIBS=$PLUGIN_NVPTX_save_LIBS
|
|
+ fi
|
|
case $PLUGIN_NVPTX in
|
|
nvptx*)
|
|
- if test "x$CUDA_DRIVER_INCLUDE" = x \
|
|
- && test "x$CUDA_DRIVER_LIB" = x; then
|
|
+ if (test "x$CUDA_DRIVER_INCLUDE" = x \
|
|
+ || test "x$CUDA_DRIVER_INCLUDE" = xno) \
|
|
+ && (test "x$CUDA_DRIVER_LIB" = x \
|
|
+ || test "x$CUDA_DRIVER_LIB" = xno); then
|
|
PLUGIN_NVPTX=1
|
|
PLUGIN_NVPTX_CPPFLAGS='-I$(srcdir)/plugin/cuda'
|
|
PLUGIN_NVPTX_LIBS='-ldl'
|
|
@@ -191,7 +206,7 @@ if test x"$enable_offload_targets" != x;
|
|
PLUGIN_HSA=0
|
|
;;
|
|
*)
|
|
- tgt_name=hsa
|
|
+ tgt_plugin=hsa
|
|
PLUGIN_HSA=$tgt
|
|
PLUGIN_HSA_CPPFLAGS=$HSA_RUNTIME_CPPFLAGS
|
|
PLUGIN_HSA_LDFLAGS="$HSA_RUNTIME_LDFLAGS"
|
|
@@ -209,7 +224,7 @@ if test x"$enable_offload_targets" != x;
|
|
LDFLAGS=$PLUGIN_HSA_save_LDFLAGS
|
|
LIBS=$PLUGIN_HSA_save_LIBS
|
|
case $PLUGIN_HSA in
|
|
- hsa*)
|
|
+ hsa*)
|
|
HSA_PLUGIN=0
|
|
AC_MSG_ERROR([HSA run-time package required for HSA support])
|
|
;;
|
|
@@ -226,16 +241,19 @@ if test x"$enable_offload_targets" != x;
|
|
AC_MSG_ERROR([unknown offload target specified])
|
|
;;
|
|
esac
|
|
- if test x"$tgt_name" = x; then
|
|
- # Don't configure libgomp for this offloading target if we don't build
|
|
- # the corresponding plugin.
|
|
+ if test x"$tgt_plugin" = x; then
|
|
+ # Not configuring libgomp for this offload target if we're not building
|
|
+ # the corresponding offload plugin.
|
|
continue
|
|
- elif test x"$offload_targets" = x; then
|
|
- offload_targets=$tgt_name
|
|
+ elif test x"$offload_plugins" = x; then
|
|
+ offload_plugins=$tgt_plugin
|
|
+ offload_targets=$tgt
|
|
else
|
|
- offload_targets=$offload_targets,$tgt_name
|
|
+ offload_plugins=$offload_plugins,$tgt_plugin
|
|
+ offload_targets=$offload_targets,$tgt
|
|
fi
|
|
- if test "$tgt_name" = hsa; then
|
|
+ # Configure additional search paths.
|
|
+ if test "$tgt_plugin" = hsa; then
|
|
# Offloading compilation is all handled by the target compiler.
|
|
:
|
|
elif test x"$tgt_dir" != x; then
|
|
@@ -247,8 +265,8 @@ if test x"$enable_offload_targets" != x;
|
|
fi
|
|
done
|
|
fi
|
|
-AC_DEFINE_UNQUOTED(OFFLOAD_TARGETS, "$offload_targets",
|
|
- [Define to offload targets, separated by commas.])
|
|
+AC_DEFINE_UNQUOTED(OFFLOAD_PLUGINS, "$offload_plugins",
|
|
+ [Define to offload plugins, separated by commas.])
|
|
AM_CONDITIONAL([PLUGIN_NVPTX], [test $PLUGIN_NVPTX = 1])
|
|
AC_DEFINE_UNQUOTED([PLUGIN_NVPTX], [$PLUGIN_NVPTX],
|
|
[Define to 1 if the NVIDIA plugin is built, 0 if not.])
|
|
--- libgomp/affinity-fmt.c.jj 2019-05-07 18:46:36.285113585 +0200
|
|
+++ libgomp/affinity-fmt.c 2019-05-07 18:46:36.285113585 +0200
|
|
@@ -0,0 +1,495 @@
|
|
+/* Copyright (C) 2018-2019 Free Software Foundation, Inc.
|
|
+ Contributed by Jakub Jelinek <jakub@redhat.com>.
|
|
+
|
|
+ This file is part of the GNU Offloading and Multi Processing Library
|
|
+ (libgomp).
|
|
+
|
|
+ Libgomp is free software; you can redistribute it and/or modify it
|
|
+ under the terms of the GNU General Public License as published by
|
|
+ the Free Software Foundation; either version 3, or (at your option)
|
|
+ any later version.
|
|
+
|
|
+ Libgomp is distributed in the hope that it will be useful, but WITHOUT ANY
|
|
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
|
+ FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
|
+ more details.
|
|
+
|
|
+ Under Section 7 of GPL version 3, you are granted additional
|
|
+ permissions described in the GCC Runtime Library Exception, version
|
|
+ 3.1, as published by the Free Software Foundation.
|
|
+
|
|
+ You should have received a copy of the GNU General Public License and
|
|
+ a copy of the GCC Runtime Library Exception along with this program;
|
|
+ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
|
|
+ <http://www.gnu.org/licenses/>. */
|
|
+
|
|
+#include "libgomp.h"
|
|
+#include <string.h>
|
|
+#include <stdio.h>
|
|
+#include <stdlib.h>
|
|
+#ifdef HAVE_UNISTD_H
|
|
+#include <unistd.h>
|
|
+#endif
|
|
+#ifdef HAVE_INTTYPES_H
|
|
+# include <inttypes.h> /* For PRIx64. */
|
|
+#endif
|
|
+#ifdef HAVE_UNAME
|
|
+#include <sys/utsname.h>
|
|
+#endif
|
|
+
|
|
+void
|
|
+gomp_print_string (const char *str, size_t len)
|
|
+{
|
|
+ fwrite (str, 1, len, stderr);
|
|
+}
|
|
+
|
|
+void
|
|
+gomp_set_affinity_format (const char *format, size_t len)
|
|
+{
|
|
+ if (len < gomp_affinity_format_len)
|
|
+ memcpy (gomp_affinity_format_var, format, len);
|
|
+ else
|
|
+ {
|
|
+ char *p;
|
|
+ if (gomp_affinity_format_len)
|
|
+ p = gomp_realloc (gomp_affinity_format_var, len + 1);
|
|
+ else
|
|
+ p = gomp_malloc (len + 1);
|
|
+ memcpy (p, format, len);
|
|
+ gomp_affinity_format_var = p;
|
|
+ gomp_affinity_format_len = len + 1;
|
|
+ }
|
|
+ gomp_affinity_format_var[len] = '\0';
|
|
+}
|
|
+
|
|
+void
|
|
+omp_set_affinity_format (const char *format)
|
|
+{
|
|
+ gomp_set_affinity_format (format, strlen (format));
|
|
+}
|
|
+
|
|
+size_t
|
|
+omp_get_affinity_format (char *buffer, size_t size)
|
|
+{
|
|
+ size_t len = strlen (gomp_affinity_format_var);
|
|
+ if (size)
|
|
+ {
|
|
+ if (len < size)
|
|
+ memcpy (buffer, gomp_affinity_format_var, len + 1);
|
|
+ else
|
|
+ {
|
|
+ memcpy (buffer, gomp_affinity_format_var, size - 1);
|
|
+ buffer[size - 1] = '\0';
|
|
+ }
|
|
+ }
|
|
+ return len;
|
|
+}
|
|
+
|
|
+void
|
|
+gomp_display_string (char *buffer, size_t size, size_t *ret,
|
|
+ const char *str, size_t len)
|
|
+{
|
|
+ size_t r = *ret;
|
|
+ if (size && r < size)
|
|
+ {
|
|
+ size_t l = len;
|
|
+ if (size - r < len)
|
|
+ l = size - r;
|
|
+ memcpy (buffer + r, str, l);
|
|
+ }
|
|
+ *ret += len;
|
|
+ if (__builtin_expect (r > *ret, 0))
|
|
+ gomp_fatal ("overflow in omp_capture_affinity");
|
|
+}
|
|
+
|
|
+static void
|
|
+gomp_display_repeat (char *buffer, size_t size, size_t *ret,
|
|
+ char c, size_t len)
|
|
+{
|
|
+ size_t r = *ret;
|
|
+ if (size && r < size)
|
|
+ {
|
|
+ size_t l = len;
|
|
+ if (size - r < len)
|
|
+ l = size - r;
|
|
+ memset (buffer + r, c, l);
|
|
+ }
|
|
+ *ret += len;
|
|
+ if (__builtin_expect (r > *ret, 0))
|
|
+ gomp_fatal ("overflow in omp_capture_affinity");
|
|
+}
|
|
+
|
|
+static void
|
|
+gomp_display_num (char *buffer, size_t size, size_t *ret,
|
|
+ bool zero, bool right, size_t sz, char *buf)
|
|
+{
|
|
+ size_t l = strlen (buf);
|
|
+ if (sz == (size_t) -1 || l >= sz)
|
|
+ {
|
|
+ gomp_display_string (buffer, size, ret, buf, l);
|
|
+ return;
|
|
+ }
|
|
+ if (zero)
|
|
+ {
|
|
+ if (buf[0] == '-')
|
|
+ gomp_display_string (buffer, size, ret, buf, 1);
|
|
+ else if (buf[0] == '0' && buf[1] == 'x')
|
|
+ gomp_display_string (buffer, size, ret, buf, 2);
|
|
+ gomp_display_repeat (buffer, size, ret, '0', sz - l);
|
|
+ if (buf[0] == '-')
|
|
+ gomp_display_string (buffer, size, ret, buf + 1, l - 1);
|
|
+ else if (buf[0] == '0' && buf[1] == 'x')
|
|
+ gomp_display_string (buffer, size, ret, buf + 2, l - 2);
|
|
+ else
|
|
+ gomp_display_string (buffer, size, ret, buf, l);
|
|
+ }
|
|
+ else if (right)
|
|
+ {
|
|
+ gomp_display_repeat (buffer, size, ret, ' ', sz - l);
|
|
+ gomp_display_string (buffer, size, ret, buf, l);
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+ gomp_display_string (buffer, size, ret, buf, l);
|
|
+ gomp_display_repeat (buffer, size, ret, ' ', sz - l);
|
|
+ }
|
|
+}
|
|
+
|
|
+static void
|
|
+gomp_display_int (char *buffer, size_t size, size_t *ret,
|
|
+ bool zero, bool right, size_t sz, int num)
|
|
+{
|
|
+ char buf[3 * sizeof (int) + 2];
|
|
+ sprintf (buf, "%d", num);
|
|
+ gomp_display_num (buffer, size, ret, zero, right, sz, buf);
|
|
+}
|
|
+
|
|
+static void
|
|
+gomp_display_string_len (char *buffer, size_t size, size_t *ret,
|
|
+ bool right, size_t sz, char *str, size_t len)
|
|
+{
|
|
+ if (sz == (size_t) -1 || len >= sz)
|
|
+ {
|
|
+ gomp_display_string (buffer, size, ret, str, len);
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ if (right)
|
|
+ {
|
|
+ gomp_display_repeat (buffer, size, ret, ' ', sz - len);
|
|
+ gomp_display_string (buffer, size, ret, str, len);
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+ gomp_display_string (buffer, size, ret, str, len);
|
|
+ gomp_display_repeat (buffer, size, ret, ' ', sz - len);
|
|
+ }
|
|
+}
|
|
+
|
|
+static void
|
|
+gomp_display_hostname (char *buffer, size_t size, size_t *ret,
|
|
+ bool right, size_t sz)
|
|
+{
|
|
+#ifdef HAVE_GETHOSTNAME
|
|
+ {
|
|
+ char buf[256];
|
|
+ char *b = buf;
|
|
+ size_t len = 256;
|
|
+ do
|
|
+ {
|
|
+ b[len - 1] = '\0';
|
|
+ if (gethostname (b, len - 1) == 0)
|
|
+ {
|
|
+ size_t l = strlen (b);
|
|
+ if (l < len - 1)
|
|
+ {
|
|
+ gomp_display_string_len (buffer, size, ret,
|
|
+ right, sz, b, l);
|
|
+ if (b != buf)
|
|
+ free (b);
|
|
+ return;
|
|
+ }
|
|
+ }
|
|
+ if (len == 1048576)
|
|
+ break;
|
|
+ len = len * 2;
|
|
+ if (len == 512)
|
|
+ b = gomp_malloc (len);
|
|
+ else
|
|
+ b = gomp_realloc (b, len);
|
|
+ }
|
|
+ while (1);
|
|
+ if (b != buf)
|
|
+ free (b);
|
|
+ }
|
|
+#endif
|
|
+#ifdef HAVE_UNAME
|
|
+ {
|
|
+ struct utsname buf;
|
|
+ if (uname (&buf) == 0)
|
|
+ {
|
|
+ gomp_display_string_len (buffer, size, ret, right, sz,
|
|
+ buf.nodename, strlen (buf.nodename));
|
|
+ return;
|
|
+ }
|
|
+ }
|
|
+#endif
|
|
+ gomp_display_string_len (buffer, size, ret, right, sz, "node", 4);
|
|
+}
|
|
+
|
|
+struct affinity_types_struct {
|
|
+ char long_str[18];
|
|
+ char long_len;
|
|
+ char short_c; };
|
|
+
|
|
+static struct affinity_types_struct affinity_types[] =
|
|
+{
|
|
+#define AFFINITY_TYPE(l, s) \
|
|
+ { #l, sizeof (#l) - 1, s }
|
|
+ AFFINITY_TYPE (team_num, 't'),
|
|
+ AFFINITY_TYPE (num_teams, 'T'),
|
|
+ AFFINITY_TYPE (nesting_level, 'L'),
|
|
+ AFFINITY_TYPE (thread_num, 'n'),
|
|
+ AFFINITY_TYPE (num_threads, 'N'),
|
|
+ AFFINITY_TYPE (ancestor_tnum, 'a'),
|
|
+ AFFINITY_TYPE (host, 'H'),
|
|
+ AFFINITY_TYPE (process_id, 'P'),
|
|
+ AFFINITY_TYPE (native_thread_id, 'i'),
|
|
+ AFFINITY_TYPE (thread_affinity, 'A')
|
|
+#undef AFFINITY_TYPE
|
|
+};
|
|
+
|
|
+size_t
|
|
+gomp_display_affinity (char *buffer, size_t size,
|
|
+ const char *format, gomp_thread_handle handle,
|
|
+ struct gomp_team_state *ts, unsigned int place)
|
|
+{
|
|
+ size_t ret = 0;
|
|
+ do
|
|
+ {
|
|
+ const char *p = strchr (format, '%');
|
|
+ bool zero = false;
|
|
+ bool right = false;
|
|
+ size_t sz = -1;
|
|
+ char c;
|
|
+ int val;
|
|
+ if (p == NULL)
|
|
+ p = strchr (format, '\0');
|
|
+ if (p != format)
|
|
+ gomp_display_string (buffer, size, &ret,
|
|
+ format, p - format);
|
|
+ if (*p == '\0')
|
|
+ break;
|
|
+ p++;
|
|
+ if (*p == '%')
|
|
+ {
|
|
+ gomp_display_string (buffer, size, &ret, "%", 1);
|
|
+ format = p + 1;
|
|
+ continue;
|
|
+ }
|
|
+ if (*p == '0')
|
|
+ {
|
|
+ zero = true;
|
|
+ p++;
|
|
+ if (*p != '.')
|
|
+ gomp_fatal ("leading zero not followed by dot in affinity format");
|
|
+ }
|
|
+ if (*p == '.')
|
|
+ {
|
|
+ right = true;
|
|
+ p++;
|
|
+ }
|
|
+ if (*p >= '1' && *p <= '9')
|
|
+ {
|
|
+ char *end;
|
|
+ sz = strtoul (p, &end, 10);
|
|
+ p = end;
|
|
+ }
|
|
+ else if (zero || right)
|
|
+ gomp_fatal ("leading zero or right justification in affinity format "
|
|
+ "requires size");
|
|
+ c = *p;
|
|
+ if (c == '{')
|
|
+ {
|
|
+ int i;
|
|
+ for (i = 0;
|
|
+ i < sizeof (affinity_types) / sizeof (affinity_types[0]); ++i)
|
|
+ if (strncmp (p + 1, affinity_types[i].long_str,
|
|
+ affinity_types[i].long_len) == 0
|
|
+ && p[affinity_types[i].long_len + 1] == '}')
|
|
+ {
|
|
+ c = affinity_types[i].short_c;
|
|
+ p += affinity_types[i].long_len + 1;
|
|
+ break;
|
|
+ }
|
|
+ if (c == '{')
|
|
+ {
|
|
+ char *q = strchr (p + 1, '}');
|
|
+ if (q)
|
|
+ gomp_fatal ("unsupported long type name '%.*s' in affinity "
|
|
+ "format", (int) (q - (p + 1)), p + 1);
|
|
+ else
|
|
+ gomp_fatal ("unterminated long type name '%s' in affinity "
|
|
+ "format", p + 1);
|
|
+ }
|
|
+ }
|
|
+ switch (c)
|
|
+ {
|
|
+ case 't':
|
|
+ val = omp_get_team_num ();
|
|
+ goto do_int;
|
|
+ case 'T':
|
|
+ val = omp_get_num_teams ();
|
|
+ goto do_int;
|
|
+ case 'L':
|
|
+ val = ts->level;
|
|
+ goto do_int;
|
|
+ case 'n':
|
|
+ val = ts->team_id;
|
|
+ goto do_int;
|
|
+ case 'N':
|
|
+ val = ts->team ? ts->team->nthreads : 1;
|
|
+ goto do_int;
|
|
+ case 'a':
|
|
+ val = ts->team ? ts->team->prev_ts.team_id : -1;
|
|
+ goto do_int;
|
|
+ case 'H':
|
|
+ gomp_display_hostname (buffer, size, &ret, right, sz);
|
|
+ break;
|
|
+ case 'P':
|
|
+#ifdef HAVE_GETPID
|
|
+ val = getpid ();
|
|
+#else
|
|
+ val = 0;
|
|
+#endif
|
|
+ goto do_int;
|
|
+ case 'i':
|
|
+#if defined(LIBGOMP_USE_PTHREADS) && defined(__GNUC__)
|
|
+ {
|
|
+ char buf[3 * (sizeof (handle) + sizeof (uintptr_t) + sizeof (int))
|
|
+ + 4];
|
|
+ /* This macro returns expr unmodified for integral or pointer
|
|
+ types and 0 for anything else (e.g. aggregates). */
|
|
+#define gomp_nonaggregate(expr) \
|
|
+ __builtin_choose_expr (__builtin_classify_type (expr) == 1 \
|
|
+ || __builtin_classify_type (expr) == 5, expr, 0)
|
|
+ /* This macro returns expr unmodified for integral types,
|
|
+ (uintptr_t) (expr) for pointer types and 0 for anything else
|
|
+ (e.g. aggregates). */
|
|
+#define gomp_integral(expr) \
|
|
+ __builtin_choose_expr (__builtin_classify_type (expr) == 5, \
|
|
+ (uintptr_t) gomp_nonaggregate (expr), \
|
|
+ gomp_nonaggregate (expr))
|
|
+
|
|
+ if (sizeof (gomp_integral (handle)) == sizeof (unsigned long))
|
|
+ sprintf (buf, "0x%lx", (unsigned long) gomp_integral (handle));
|
|
+#if defined (HAVE_INTTYPES_H) && defined (PRIx64)
|
|
+ else if (sizeof (gomp_integral (handle)) == sizeof (uint64_t))
|
|
+ sprintf (buf, "0x%" PRIx64, (uint64_t) gomp_integral (handle));
|
|
+#else
|
|
+ else if (sizeof (gomp_integral (handle))
|
|
+ == sizeof (unsigned long long))
|
|
+ sprintf (buf, "0x%llx",
|
|
+ (unsigned long long) gomp_integral (handle));
|
|
+#endif
|
|
+ else
|
|
+ sprintf (buf, "0x%x", (unsigned int) gomp_integral (handle));
|
|
+ gomp_display_num (buffer, size, &ret, zero, right, sz, buf);
|
|
+ break;
|
|
+ }
|
|
+#else
|
|
+ val = 0;
|
|
+ goto do_int;
|
|
+#endif
|
|
+ case 'A':
|
|
+ if (sz == (size_t) -1)
|
|
+ gomp_display_affinity_place (buffer, size, &ret,
|
|
+ place - 1);
|
|
+ else if (right)
|
|
+ {
|
|
+ size_t len = 0;
|
|
+ gomp_display_affinity_place (NULL, 0, &len, place - 1);
|
|
+ if (len < sz)
|
|
+ gomp_display_repeat (buffer, size, &ret, ' ', sz - len);
|
|
+ gomp_display_affinity_place (buffer, size, &ret, place - 1);
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+ size_t start = ret;
|
|
+ gomp_display_affinity_place (buffer, size, &ret, place - 1);
|
|
+ if (ret - start < sz)
|
|
+ gomp_display_repeat (buffer, size, &ret, ' ', sz - (ret - start));
|
|
+ }
|
|
+ break;
|
|
+ do_int:
|
|
+ gomp_display_int (buffer, size, &ret, zero, right, sz, val);
|
|
+ break;
|
|
+ default:
|
|
+ gomp_fatal ("unsupported type %c in affinity format", c);
|
|
+ }
|
|
+ format = p + 1;
|
|
+ }
|
|
+ while (1);
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+size_t
|
|
+omp_capture_affinity (char *buffer, size_t size, const char *format)
|
|
+{
|
|
+ struct gomp_thread *thr = gomp_thread ();
|
|
+ size_t ret
|
|
+ = gomp_display_affinity (buffer, size,
|
|
+ format && *format
|
|
+ ? format : gomp_affinity_format_var,
|
|
+ gomp_thread_self (), &thr->ts, thr->place);
|
|
+ if (size)
|
|
+ {
|
|
+ if (ret >= size)
|
|
+ buffer[size - 1] = '\0';
|
|
+ else
|
|
+ buffer[ret] = '\0';
|
|
+ }
|
|
+ return ret;
|
|
+}
|
|
+ialias (omp_capture_affinity)
|
|
+
|
|
+void
|
|
+omp_display_affinity (const char *format)
|
|
+{
|
|
+ char buf[512];
|
|
+ char *b;
|
|
+ size_t ret = ialias_call (omp_capture_affinity) (buf, sizeof buf, format);
|
|
+ if (ret < sizeof buf)
|
|
+ {
|
|
+ buf[ret] = '\n';
|
|
+ gomp_print_string (buf, ret + 1);
|
|
+ return;
|
|
+ }
|
|
+ b = gomp_malloc (ret + 1);
|
|
+ ialias_call (omp_capture_affinity) (b, ret + 1, format);
|
|
+ b[ret] = '\n';
|
|
+ gomp_print_string (b, ret + 1);
|
|
+ free (b);
|
|
+}
|
|
+
|
|
+void
|
|
+gomp_display_affinity_thread (gomp_thread_handle handle,
|
|
+ struct gomp_team_state *ts, unsigned int place)
|
|
+{
|
|
+ char buf[512];
|
|
+ char *b;
|
|
+ size_t ret = gomp_display_affinity (buf, sizeof buf, gomp_affinity_format_var,
|
|
+ handle, ts, place);
|
|
+ if (ret < sizeof buf)
|
|
+ {
|
|
+ buf[ret] = '\n';
|
|
+ gomp_print_string (buf, ret + 1);
|
|
+ return;
|
|
+ }
|
|
+ b = gomp_malloc (ret + 1);
|
|
+ gomp_display_affinity (b, ret + 1, gomp_affinity_format_var,
|
|
+ handle, ts, place);
|
|
+ b[ret] = '\n';
|
|
+ gomp_print_string (b, ret + 1);
|
|
+ free (b);
|
|
+}
|
|
--- libgomp/single.c.jj 2018-04-25 09:40:31.870655561 +0200
|
|
+++ libgomp/single.c 2019-05-07 18:46:36.536109576 +0200
|
|
@@ -47,7 +47,7 @@ GOMP_single_start (void)
|
|
return __sync_bool_compare_and_swap (&team->single_count, single_count,
|
|
single_count + 1L);
|
|
#else
|
|
- bool ret = gomp_work_share_start (false);
|
|
+ bool ret = gomp_work_share_start (0);
|
|
if (ret)
|
|
gomp_work_share_init_done ();
|
|
gomp_work_share_end_nowait ();
|
|
@@ -68,7 +68,7 @@ GOMP_single_copy_start (void)
|
|
bool first;
|
|
void *ret;
|
|
|
|
- first = gomp_work_share_start (false);
|
|
+ first = gomp_work_share_start (0);
|
|
|
|
if (first)
|
|
{
|
|
--- libgomp/oacc-cuda.c.jj 2018-04-25 09:40:31.321655307 +0200
|
|
+++ libgomp/oacc-cuda.c 2019-05-07 18:46:36.528109704 +0200
|
|
@@ -58,7 +58,7 @@ acc_get_cuda_stream (int async)
|
|
{
|
|
struct goacc_thread *thr = goacc_thread ();
|
|
|
|
- if (async < 0)
|
|
+ if (!async_valid_p (async))
|
|
return NULL;
|
|
|
|
if (thr && thr->dev && thr->dev->openacc.cuda.get_stream_func)
|
|
@@ -72,7 +72,7 @@ acc_set_cuda_stream (int async, void *st
|
|
{
|
|
struct goacc_thread *thr;
|
|
|
|
- if (async < 0 || stream == NULL)
|
|
+ if (!async_valid_p (async) || stream == NULL)
|
|
return 0;
|
|
|
|
goacc_lazy_initialize ();
|
|
--- libgomp/work.c.jj 2018-04-25 09:40:31.925655587 +0200
|
|
+++ libgomp/work.c 2019-05-07 18:46:36.548109384 +0200
|
|
@@ -76,7 +76,15 @@ alloc_work_share (struct gomp_team *team
|
|
#endif
|
|
|
|
team->work_share_chunk *= 2;
|
|
+ /* Allocating gomp_work_share structures aligned is just an
|
|
+ optimization, don't do it when using the fallback method. */
|
|
+#ifdef GOMP_HAVE_EFFICIENT_ALIGNED_ALLOC
|
|
+ ws = gomp_aligned_alloc (__alignof (struct gomp_work_share),
|
|
+ team->work_share_chunk
|
|
+ * sizeof (struct gomp_work_share));
|
|
+#else
|
|
ws = gomp_malloc (team->work_share_chunk * sizeof (struct gomp_work_share));
|
|
+#endif
|
|
ws->next_alloc = team->work_shares[0].next_alloc;
|
|
team->work_shares[0].next_alloc = ws;
|
|
team->work_share_list_alloc = &ws[1];
|
|
@@ -90,30 +98,35 @@ alloc_work_share (struct gomp_team *team
|
|
This shouldn't touch the next_alloc field. */
|
|
|
|
void
|
|
-gomp_init_work_share (struct gomp_work_share *ws, bool ordered,
|
|
+gomp_init_work_share (struct gomp_work_share *ws, size_t ordered,
|
|
unsigned nthreads)
|
|
{
|
|
gomp_mutex_init (&ws->lock);
|
|
if (__builtin_expect (ordered, 0))
|
|
{
|
|
-#define INLINE_ORDERED_TEAM_IDS_CNT \
|
|
- ((sizeof (struct gomp_work_share) \
|
|
- - offsetof (struct gomp_work_share, inline_ordered_team_ids)) \
|
|
- / sizeof (((struct gomp_work_share *) 0)->inline_ordered_team_ids[0]))
|
|
-
|
|
- if (nthreads > INLINE_ORDERED_TEAM_IDS_CNT)
|
|
- ws->ordered_team_ids
|
|
- = gomp_malloc (nthreads * sizeof (*ws->ordered_team_ids));
|
|
+#define INLINE_ORDERED_TEAM_IDS_SIZE \
|
|
+ (sizeof (struct gomp_work_share) \
|
|
+ - offsetof (struct gomp_work_share, inline_ordered_team_ids))
|
|
+
|
|
+ if (__builtin_expect (ordered != 1, 0))
|
|
+ {
|
|
+ ordered += nthreads * sizeof (*ws->ordered_team_ids) - 1;
|
|
+ ordered = ordered + __alignof__ (long long) - 1;
|
|
+ ordered &= ~(__alignof__ (long long) - 1);
|
|
+ }
|
|
+ else
|
|
+ ordered = nthreads * sizeof (*ws->ordered_team_ids);
|
|
+ if (ordered > INLINE_ORDERED_TEAM_IDS_SIZE)
|
|
+ ws->ordered_team_ids = gomp_malloc (ordered);
|
|
else
|
|
ws->ordered_team_ids = ws->inline_ordered_team_ids;
|
|
- memset (ws->ordered_team_ids, '\0',
|
|
- nthreads * sizeof (*ws->ordered_team_ids));
|
|
+ memset (ws->ordered_team_ids, '\0', ordered);
|
|
ws->ordered_num_used = 0;
|
|
ws->ordered_owner = -1;
|
|
ws->ordered_cur = 0;
|
|
}
|
|
else
|
|
- ws->ordered_team_ids = NULL;
|
|
+ ws->ordered_team_ids = ws->inline_ordered_team_ids;
|
|
gomp_ptrlock_init (&ws->next_ws, NULL);
|
|
ws->threads_completed = 0;
|
|
}
|
|
@@ -166,7 +179,7 @@ free_work_share (struct gomp_team *team,
|
|
if this was the first thread to reach this point. */
|
|
|
|
bool
|
|
-gomp_work_share_start (bool ordered)
|
|
+gomp_work_share_start (size_t ordered)
|
|
{
|
|
struct gomp_thread *thr = gomp_thread ();
|
|
struct gomp_team *team = thr->ts.team;
|
|
@@ -178,7 +191,7 @@ gomp_work_share_start (bool ordered)
|
|
ws = gomp_malloc (sizeof (*ws));
|
|
gomp_init_work_share (ws, ordered, 1);
|
|
thr->ts.work_share = ws;
|
|
- return ws;
|
|
+ return true;
|
|
}
|
|
|
|
ws = thr->ts.work_share;
|
|
--- include/gomp-constants.h.jj 2018-04-25 09:40:39.757659209 +0200
|
|
+++ include/gomp-constants.h 2019-05-07 18:57:33.333627031 +0200
|
|
@@ -189,6 +189,7 @@ enum gomp_map_kind
|
|
#define GOMP_TASK_FLAG_GRAINSIZE (1 << 9)
|
|
#define GOMP_TASK_FLAG_IF (1 << 10)
|
|
#define GOMP_TASK_FLAG_NOGROUP (1 << 11)
|
|
+#define GOMP_TASK_FLAG_REDUCTION (1 << 12)
|
|
|
|
/* GOMP_target{_ext,update_ext,enter_exit_data} flags argument. */
|
|
#define GOMP_TARGET_FLAG_NOWAIT (1 << 0)
|
|
@@ -196,6 +197,18 @@ enum gomp_map_kind
|
|
/* Internal to libgomp. */
|
|
#define GOMP_TARGET_FLAG_UPDATE (1U << 31)
|
|
|
|
+
|
|
+/* OpenACC construct flags. */
|
|
+
|
|
+/* Force host fallback execution. */
|
|
+#define GOACC_FLAG_HOST_FALLBACK (1 << 0)
|
|
+
|
|
+/* For legacy reasons, in the ABI, the GOACC_FLAGs are encoded as an inverted
|
|
+ bitmask. */
|
|
+#define GOACC_FLAGS_MARSHAL_OP BIT_NOT_EXPR
|
|
+#define GOACC_FLAGS_UNMARSHAL(X) (~(X))
|
|
+
|
|
+
|
|
/* Versions of libgomp and device-specific plugins. GOMP_VERSION
|
|
should be incremented whenever an ABI-incompatible change is introduced
|
|
to the plugin interface defined in libgomp/libgomp.h. */
|
|
@@ -251,6 +264,12 @@ enum gomp_map_kind
|
|
at most and shifted by this many bits. */
|
|
#define GOMP_TARGET_ARG_VALUE_SHIFT 16
|
|
|
|
+/* Dependence types in omp_depend_t objects. */
|
|
+#define GOMP_DEPEND_IN 1
|
|
+#define GOMP_DEPEND_OUT 2
|
|
+#define GOMP_DEPEND_INOUT 3
|
|
+#define GOMP_DEPEND_MUTEXINOUTSET 4
|
|
+
|
|
/* HSA specific data structures. */
|
|
|
|
/* Identifiers of device-specific target arguments. */
|