blob: e31bc0a7bc6304d5a7a4cd41c93c6a6715d0370d [file] [log] [blame]
Thomas Schwinge41dbbb32015-01-15 21:11:12 +01001/* Copyright (C) 2013-2015 Free Software Foundation, Inc.
2
3 Contributed by Mentor Embedded.
4
5 This file is part of the GNU Offloading and Multi Processing Library
6 (libgomp).
7
8 Libgomp is free software; you can redistribute it and/or modify it
9 under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 3, or (at your option)
11 any later version.
12
13 Libgomp is distributed in the hope that it will be useful, but WITHOUT ANY
14 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
15 FOR A PARTICULAR PURPOSE. See the GNU General Public License for
16 more details.
17
18 Under Section 7 of GPL version 3, you are granted additional
19 permissions described in the GCC Runtime Library Exception, version
20 3.1, as published by the Free Software Foundation.
21
22 You should have received a copy of the GNU General Public License and
23 a copy of the GCC Runtime Library Exception along with this program;
24 see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
25 <http://www.gnu.org/licenses/>. */
26
27/* This file handles OpenACC constructs. */
28
29#include "openacc.h"
30#include "libgomp.h"
31#include "libgomp_g.h"
32#include "gomp-constants.h"
33#include "oacc-int.h"
Kai Tietz01c0b3b2015-03-25 16:05:02 +010034#ifdef HAVE_INTTYPES_H
35# include <inttypes.h> /* For PRIu64. */
36#endif
Thomas Schwinge41dbbb32015-01-15 21:11:12 +010037#include <string.h>
38#include <stdarg.h>
39#include <assert.h>
Thomas Schwinge41dbbb32015-01-15 21:11:12 +010040
41static int
42find_pset (int pos, size_t mapnum, unsigned short *kinds)
43{
44 if (pos + 1 >= mapnum)
45 return 0;
46
47 unsigned char kind = kinds[pos+1] & 0xff;
48
49 return kind == GOMP_MAP_TO_PSET;
50}
51
Nathan Sidwell3e32ee12015-09-28 19:37:33 +000052static void goacc_wait (int async, int num_waits, va_list *ap);
53
54
55/* Launch a possibly offloaded function on DEVICE. FN is the host fn
56 address. MAPNUM, HOSTADDRS, SIZES & KINDS describe the memory
57 blocks to be copied to/from the device. Varadic arguments are
58 keyed optional parameters terminated with a zero. */
Thomas Schwinge41dbbb32015-01-15 21:11:12 +010059
60void
Nathan Sidwell3e32ee12015-09-28 19:37:33 +000061GOACC_parallel_keyed (int device, void (*fn) (void *),
62 size_t mapnum, void **hostaddrs, size_t *sizes,
63 unsigned short *kinds, ...)
Thomas Schwinge41dbbb32015-01-15 21:11:12 +010064{
65 bool host_fallback = device == GOMP_DEVICE_HOST_FALLBACK;
66 va_list ap;
67 struct goacc_thread *thr;
68 struct gomp_device_descr *acc_dev;
69 struct target_mem_desc *tgt;
70 void **devaddrs;
71 unsigned int i;
72 struct splay_tree_key_s k;
73 splay_tree_key tgt_fn_key;
74 void (*tgt_fn);
Nathan Sidwell3e32ee12015-09-28 19:37:33 +000075 int async = GOMP_ASYNC_SYNC;
76 unsigned dims[GOMP_DIM_MAX];
77 unsigned tag;
Thomas Schwinge41dbbb32015-01-15 21:11:12 +010078
Kai Tietz01c0b3b2015-03-25 16:05:02 +010079#ifdef HAVE_INTTYPES_H
Nathan Sidwell3e32ee12015-09-28 19:37:33 +000080 gomp_debug (0, "%s: mapnum=%"PRIu64", hostaddrs=%p, size=%p, kinds=%p\n",
81 __FUNCTION__, (uint64_t) mapnum, hostaddrs, sizes, kinds);
Kai Tietz01c0b3b2015-03-25 16:05:02 +010082#else
Nathan Sidwell3e32ee12015-09-28 19:37:33 +000083 gomp_debug (0, "%s: mapnum=%lu, hostaddrs=%p, sizes=%p, kinds=%p\n",
84 __FUNCTION__, (unsigned long) mapnum, hostaddrs, sizes, kinds);
Kai Tietz01c0b3b2015-03-25 16:05:02 +010085#endif
Julian Brownd93bdab2015-04-08 15:58:33 +000086 goacc_lazy_initialize ();
Thomas Schwinge41dbbb32015-01-15 21:11:12 +010087
88 thr = goacc_thread ();
89 acc_dev = thr->dev;
90
91 /* Host fallback if "if" clause is false or if the current device is set to
92 the host. */
93 if (host_fallback)
94 {
95 goacc_save_and_set_bind (acc_device_host);
96 fn (hostaddrs);
97 goacc_restore_bind ();
98 return;
99 }
100 else if (acc_device_type (acc_dev->type) == acc_device_host)
101 {
102 fn (hostaddrs);
103 return;
104 }
105
Nathan Sidwell3e32ee12015-09-28 19:37:33 +0000106 va_start (ap, kinds);
107 /* TODO: This will need amending when device_type is implemented. */
108 while ((tag = va_arg (ap, unsigned)) != 0)
Nathan Sidwella0911182015-07-20 17:31:46 +0000109 {
Nathan Sidwell3e32ee12015-09-28 19:37:33 +0000110 if (GOMP_LAUNCH_DEVICE (tag))
111 gomp_fatal ("device_type '%d' offload parameters, libgomp is too old",
112 GOMP_LAUNCH_DEVICE (tag));
113
114 switch (GOMP_LAUNCH_CODE (tag))
115 {
116 case GOMP_LAUNCH_DIM:
117 {
118 unsigned mask = GOMP_LAUNCH_OP (tag);
119
120 for (i = 0; i != GOMP_DIM_MAX; i++)
121 if (mask & GOMP_DIM_MASK (i))
122 dims[i] = va_arg (ap, unsigned);
123 }
124 break;
125
126 case GOMP_LAUNCH_ASYNC:
127 {
128 /* Small constant values are encoded in the operand. */
129 async = GOMP_LAUNCH_OP (tag);
130
131 if (async == GOMP_LAUNCH_OP_MAX)
132 async = va_arg (ap, unsigned);
133 break;
134 }
135
136 case GOMP_LAUNCH_WAIT:
137 {
138 unsigned num_waits = GOMP_LAUNCH_OP (tag);
139
140 if (num_waits)
141 goacc_wait (async, num_waits, &ap);
142 break;
143 }
144
145 default:
146 gomp_fatal ("unrecognized offload code '%d',"
147 " libgomp is too old", GOMP_LAUNCH_CODE (tag));
148 }
Nathan Sidwella0911182015-07-20 17:31:46 +0000149 }
Nathan Sidwell3e32ee12015-09-28 19:37:33 +0000150 va_end (ap);
Thomas Schwinge41dbbb32015-01-15 21:11:12 +0100151
Thomas Schwinge41dbbb32015-01-15 21:11:12 +0100152 acc_dev->openacc.async_set_async_func (async);
153
154 if (!(acc_dev->capabilities & GOMP_OFFLOAD_CAP_NATIVE_EXEC))
155 {
156 k.host_start = (uintptr_t) fn;
157 k.host_end = k.host_start + 1;
Ilya Verbina51df542015-04-06 12:40:28 +0000158 gomp_mutex_lock (&acc_dev->lock);
159 tgt_fn_key = splay_tree_lookup (&acc_dev->mem_map, &k);
160 gomp_mutex_unlock (&acc_dev->lock);
Thomas Schwinge41dbbb32015-01-15 21:11:12 +0100161
162 if (tgt_fn_key == NULL)
163 gomp_fatal ("target function wasn't mapped");
164
Julian Brownd93bdab2015-04-08 15:58:33 +0000165 tgt_fn = (void (*)) tgt_fn_key->tgt_offset;
Thomas Schwinge41dbbb32015-01-15 21:11:12 +0100166 }
167 else
168 tgt_fn = (void (*)) fn;
169
170 tgt = gomp_map_vars (acc_dev, mapnum, hostaddrs, NULL, sizes, kinds, true,
171 false);
172
Thomas Schwinge6e361142015-01-16 21:05:21 +0100173 devaddrs = gomp_alloca (sizeof (void *) * mapnum);
Thomas Schwinge41dbbb32015-01-15 21:11:12 +0100174 for (i = 0; i < mapnum; i++)
175 devaddrs[i] = (void *) (tgt->list[i]->tgt->tgt_start
176 + tgt->list[i]->tgt_offset);
177
Nathan Sidwell3e32ee12015-09-28 19:37:33 +0000178 acc_dev->openacc.exec_func (tgt_fn, mapnum, hostaddrs, devaddrs, sizes,
179 kinds, async, dims, tgt);
Thomas Schwinge41dbbb32015-01-15 21:11:12 +0100180
181 /* If running synchronously, unmap immediately. */
182 if (async < acc_async_noval)
183 gomp_unmap_vars (tgt, true);
184 else
185 {
186 gomp_copy_from_async (tgt);
187 acc_dev->openacc.register_async_cleanup_func (tgt);
188 }
189
190 acc_dev->openacc.async_set_async_func (acc_async_sync);
191}
192
Nathan Sidwell3e32ee12015-09-28 19:37:33 +0000193/* Legacy entry point, only provide host execution. */
194
195void
196GOACC_parallel (int device, void (*fn) (void *),
197 size_t mapnum, void **hostaddrs, size_t *sizes,
198 unsigned short *kinds,
199 int num_gangs, int num_workers, int vector_length,
200 int async, int num_waits, ...)
201{
202 goacc_save_and_set_bind (acc_device_host);
203 fn (hostaddrs);
204 goacc_restore_bind ();
205}
206
Thomas Schwinge41dbbb32015-01-15 21:11:12 +0100207void
Thomas Schwinge128b26d2015-01-19 13:03:35 +0100208GOACC_data_start (int device, size_t mapnum,
Thomas Schwinge41dbbb32015-01-15 21:11:12 +0100209 void **hostaddrs, size_t *sizes, unsigned short *kinds)
210{
211 bool host_fallback = device == GOMP_DEVICE_HOST_FALLBACK;
212 struct target_mem_desc *tgt;
213
Kai Tietz01c0b3b2015-03-25 16:05:02 +0100214#ifdef HAVE_INTTYPES_H
215 gomp_debug (0, "%s: mapnum=%"PRIu64", hostaddrs=%p, size=%p, kinds=%p\n",
216 __FUNCTION__, (uint64_t) mapnum, hostaddrs, sizes, kinds);
217#else
218 gomp_debug (0, "%s: mapnum=%lu, hostaddrs=%p, sizes=%p, kinds=%p\n",
219 __FUNCTION__, (unsigned long) mapnum, hostaddrs, sizes, kinds);
220#endif
Thomas Schwinge41dbbb32015-01-15 21:11:12 +0100221
Julian Brownd93bdab2015-04-08 15:58:33 +0000222 goacc_lazy_initialize ();
Thomas Schwinge41dbbb32015-01-15 21:11:12 +0100223
224 struct goacc_thread *thr = goacc_thread ();
225 struct gomp_device_descr *acc_dev = thr->dev;
226
227 /* Host fallback or 'do nothing'. */
228 if ((acc_dev->capabilities & GOMP_OFFLOAD_CAP_SHARED_MEM)
229 || host_fallback)
230 {
231 tgt = gomp_map_vars (NULL, 0, NULL, NULL, NULL, NULL, true, false);
232 tgt->prev = thr->mapped_data;
233 thr->mapped_data = tgt;
234
235 return;
236 }
237
238 gomp_debug (0, " %s: prepare mappings\n", __FUNCTION__);
239 tgt = gomp_map_vars (acc_dev, mapnum, hostaddrs, NULL, sizes, kinds, true,
240 false);
241 gomp_debug (0, " %s: mappings prepared\n", __FUNCTION__);
242 tgt->prev = thr->mapped_data;
243 thr->mapped_data = tgt;
244}
245
246void
247GOACC_data_end (void)
248{
249 struct goacc_thread *thr = goacc_thread ();
250 struct target_mem_desc *tgt = thr->mapped_data;
251
252 gomp_debug (0, " %s: restore mappings\n", __FUNCTION__);
253 thr->mapped_data = tgt->prev;
254 gomp_unmap_vars (tgt, true);
255 gomp_debug (0, " %s: mappings restored\n", __FUNCTION__);
256}
257
258void
Thomas Schwinge128b26d2015-01-19 13:03:35 +0100259GOACC_enter_exit_data (int device, size_t mapnum,
Thomas Schwinge41dbbb32015-01-15 21:11:12 +0100260 void **hostaddrs, size_t *sizes, unsigned short *kinds,
261 int async, int num_waits, ...)
262{
263 struct goacc_thread *thr;
264 struct gomp_device_descr *acc_dev;
265 bool host_fallback = device == GOMP_DEVICE_HOST_FALLBACK;
266 bool data_enter = false;
267 size_t i;
268
Julian Brownd93bdab2015-04-08 15:58:33 +0000269 goacc_lazy_initialize ();
Thomas Schwinge41dbbb32015-01-15 21:11:12 +0100270
271 thr = goacc_thread ();
272 acc_dev = thr->dev;
273
274 if ((acc_dev->capabilities & GOMP_OFFLOAD_CAP_SHARED_MEM)
275 || host_fallback)
276 return;
277
Nathan Sidwella0911182015-07-20 17:31:46 +0000278 if (num_waits)
Thomas Schwinge41dbbb32015-01-15 21:11:12 +0100279 {
280 va_list ap;
281
282 va_start (ap, num_waits);
Nathan Sidwell3e32ee12015-09-28 19:37:33 +0000283 goacc_wait (async, num_waits, &ap);
Thomas Schwinge41dbbb32015-01-15 21:11:12 +0100284 va_end (ap);
285 }
286
287 acc_dev->openacc.async_set_async_func (async);
288
289 /* Determine if this is an "acc enter data". */
290 for (i = 0; i < mapnum; ++i)
291 {
292 unsigned char kind = kinds[i] & 0xff;
293
294 if (kind == GOMP_MAP_POINTER || kind == GOMP_MAP_TO_PSET)
295 continue;
296
297 if (kind == GOMP_MAP_FORCE_ALLOC
298 || kind == GOMP_MAP_FORCE_PRESENT
299 || kind == GOMP_MAP_FORCE_TO)
300 {
301 data_enter = true;
302 break;
303 }
304
305 if (kind == GOMP_MAP_FORCE_DEALLOC
306 || kind == GOMP_MAP_FORCE_FROM)
307 break;
308
309 gomp_fatal (">>>> GOACC_enter_exit_data UNHANDLED kind 0x%.2x",
310 kind);
311 }
312
313 if (data_enter)
314 {
315 for (i = 0; i < mapnum; i++)
316 {
317 unsigned char kind = kinds[i] & 0xff;
318
319 /* Scan for PSETs. */
320 int psets = find_pset (i, mapnum, kinds);
321
322 if (!psets)
323 {
324 switch (kind)
325 {
326 case GOMP_MAP_POINTER:
327 gomp_acc_insert_pointer (1, &hostaddrs[i], &sizes[i],
328 &kinds[i]);
329 break;
330 case GOMP_MAP_FORCE_ALLOC:
331 acc_create (hostaddrs[i], sizes[i]);
332 break;
333 case GOMP_MAP_FORCE_PRESENT:
334 acc_present_or_copyin (hostaddrs[i], sizes[i]);
335 break;
336 case GOMP_MAP_FORCE_TO:
337 acc_present_or_copyin (hostaddrs[i], sizes[i]);
338 break;
339 default:
340 gomp_fatal (">>>> GOACC_enter_exit_data UNHANDLED kind 0x%.2x",
341 kind);
342 break;
343 }
344 }
345 else
346 {
347 gomp_acc_insert_pointer (3, &hostaddrs[i], &sizes[i], &kinds[i]);
348 /* Increment 'i' by two because OpenACC requires fortran
349 arrays to be contiguous, so each PSET is associated with
350 one of MAP_FORCE_ALLOC/MAP_FORCE_PRESET/MAP_FORCE_TO, and
351 one MAP_POINTER. */
352 i += 2;
353 }
354 }
355 }
356 else
357 for (i = 0; i < mapnum; ++i)
358 {
359 unsigned char kind = kinds[i] & 0xff;
360
361 int psets = find_pset (i, mapnum, kinds);
362
363 if (!psets)
364 {
365 switch (kind)
366 {
367 case GOMP_MAP_POINTER:
368 gomp_acc_remove_pointer (hostaddrs[i], (kinds[i] & 0xff)
369 == GOMP_MAP_FORCE_FROM,
370 async, 1);
371 break;
372 case GOMP_MAP_FORCE_DEALLOC:
373 acc_delete (hostaddrs[i], sizes[i]);
374 break;
375 case GOMP_MAP_FORCE_FROM:
376 acc_copyout (hostaddrs[i], sizes[i]);
377 break;
378 default:
379 gomp_fatal (">>>> GOACC_enter_exit_data UNHANDLED kind 0x%.2x",
380 kind);
381 break;
382 }
383 }
384 else
385 {
386 gomp_acc_remove_pointer (hostaddrs[i], (kinds[i] & 0xff)
387 == GOMP_MAP_FORCE_FROM, async, 3);
388 /* See the above comment. */
389 i += 2;
390 }
391 }
392
393 acc_dev->openacc.async_set_async_func (acc_async_sync);
394}
395
396static void
Nathan Sidwell3e32ee12015-09-28 19:37:33 +0000397goacc_wait (int async, int num_waits, va_list *ap)
Thomas Schwinge41dbbb32015-01-15 21:11:12 +0100398{
399 struct goacc_thread *thr = goacc_thread ();
400 struct gomp_device_descr *acc_dev = thr->dev;
Thomas Schwinge41dbbb32015-01-15 21:11:12 +0100401
Nathan Sidwella0911182015-07-20 17:31:46 +0000402 while (num_waits--)
Thomas Schwinge41dbbb32015-01-15 21:11:12 +0100403 {
Nathan Sidwell3e32ee12015-09-28 19:37:33 +0000404 int qid = va_arg (*ap, int);
405
Thomas Schwinge41dbbb32015-01-15 21:11:12 +0100406 if (acc_async_test (qid))
407 continue;
408
Nathan Sidwella0911182015-07-20 17:31:46 +0000409 if (async == acc_async_sync)
410 acc_wait (qid);
411 else if (qid == async)
412 ;/* If we're waiting on the same asynchronous queue as we're
413 launching on, the queue itself will order work as
414 required, so there's no need to wait explicitly. */
415 else
Thomas Schwinge41dbbb32015-01-15 21:11:12 +0100416 acc_dev->openacc.async_wait_async_func (qid, async);
417 }
418}
419
420void
Thomas Schwinge128b26d2015-01-19 13:03:35 +0100421GOACC_update (int device, size_t mapnum,
Thomas Schwinge41dbbb32015-01-15 21:11:12 +0100422 void **hostaddrs, size_t *sizes, unsigned short *kinds,
423 int async, int num_waits, ...)
424{
425 bool host_fallback = device == GOMP_DEVICE_HOST_FALLBACK;
426 size_t i;
427
Julian Brownd93bdab2015-04-08 15:58:33 +0000428 goacc_lazy_initialize ();
Thomas Schwinge41dbbb32015-01-15 21:11:12 +0100429
430 struct goacc_thread *thr = goacc_thread ();
431 struct gomp_device_descr *acc_dev = thr->dev;
432
433 if ((acc_dev->capabilities & GOMP_OFFLOAD_CAP_SHARED_MEM)
434 || host_fallback)
435 return;
436
Nathan Sidwella0911182015-07-20 17:31:46 +0000437 if (num_waits)
Thomas Schwinge41dbbb32015-01-15 21:11:12 +0100438 {
439 va_list ap;
440
441 va_start (ap, num_waits);
Nathan Sidwell3e32ee12015-09-28 19:37:33 +0000442 goacc_wait (async, num_waits, &ap);
Thomas Schwinge41dbbb32015-01-15 21:11:12 +0100443 va_end (ap);
444 }
445
446 acc_dev->openacc.async_set_async_func (async);
447
448 for (i = 0; i < mapnum; ++i)
449 {
450 unsigned char kind = kinds[i] & 0xff;
451
452 switch (kind)
453 {
454 case GOMP_MAP_POINTER:
455 case GOMP_MAP_TO_PSET:
456 break;
457
458 case GOMP_MAP_FORCE_TO:
459 acc_update_device (hostaddrs[i], sizes[i]);
460 break;
461
462 case GOMP_MAP_FORCE_FROM:
463 acc_update_self (hostaddrs[i], sizes[i]);
464 break;
465
466 default:
467 gomp_fatal (">>>> GOACC_update UNHANDLED kind 0x%.2x", kind);
468 break;
469 }
470 }
471
472 acc_dev->openacc.async_set_async_func (acc_async_sync);
473}
474
475void
476GOACC_wait (int async, int num_waits, ...)
477{
Nathan Sidwella0911182015-07-20 17:31:46 +0000478 if (num_waits)
479 {
480 va_list ap;
Thomas Schwinge41dbbb32015-01-15 21:11:12 +0100481
Nathan Sidwella0911182015-07-20 17:31:46 +0000482 va_start (ap, num_waits);
Nathan Sidwell3e32ee12015-09-28 19:37:33 +0000483 goacc_wait (async, num_waits, &ap);
Nathan Sidwella0911182015-07-20 17:31:46 +0000484 va_end (ap);
485 }
486 else if (async == acc_async_sync)
487 acc_wait_all ();
488 else if (async == acc_async_noval)
Nathan Sidwella0513172015-07-20 17:38:49 +0000489 goacc_thread ()->dev->openacc.async_wait_all_async_func (acc_async_noval);
Thomas Schwinge41dbbb32015-01-15 21:11:12 +0100490}
491
492int
493GOACC_get_num_threads (void)
494{
495 return 1;
496}
497
498int
499GOACC_get_thread_num (void)
500{
501 return 0;
502}