]> git.ipfire.org Git - thirdparty/gcc.git/blame - libgomp/oacc-init.c
Filter out LTO in config/bootstrap-lto-lean.mk.
[thirdparty/gcc.git] / libgomp / oacc-init.c
CommitLineData
ca4c3545 1/* OpenACC Runtime initialization routines
2
fbd26352 3 Copyright (C) 2013-2019 Free Software Foundation, Inc.
ca4c3545 4
5 Contributed by Mentor Embedded.
6
7 This file is part of the GNU Offloading and Multi Processing Library
8 (libgomp).
9
10 Libgomp is free software; you can redistribute it and/or modify it
11 under the terms of the GNU General Public License as published by
12 the Free Software Foundation; either version 3, or (at your option)
13 any later version.
14
15 Libgomp is distributed in the hope that it will be useful, but WITHOUT ANY
16 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
17 FOR A PARTICULAR PURPOSE. See the GNU General Public License for
18 more details.
19
20 Under Section 7 of GPL version 3, you are granted additional
21 permissions described in the GCC Runtime Library Exception, version
22 3.1, as published by the Free Software Foundation.
23
24 You should have received a copy of the GNU General Public License and
25 a copy of the GCC Runtime Library Exception along with this program;
26 see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
27 <http://www.gnu.org/licenses/>. */
28
29#include "libgomp.h"
30#include "oacc-int.h"
31#include "openacc.h"
32#include <assert.h>
33#include <stdlib.h>
34#include <strings.h>
35#include <stdbool.h>
36#include <string.h>
37
d39966e5 38/* This lock is used to protect access to cached_base_dev, dispatchers and
39 the (abstract) initialisation state of attached offloading devices. */
40
ca4c3545 41static gomp_mutex_t acc_device_lock;
42
0a1fe572 43/* A cached version of the dispatcher for the global "current" accelerator type,
44 e.g. used as the default when creating new host threads. This is the
45 device-type equivalent of goacc_device_num (which specifies which device to
46 use out of potentially several of the same type). If there are several
47 devices of a given type, this points at the first one. */
48
49static struct gomp_device_descr *cached_base_dev = NULL;
ca4c3545 50
51#if defined HAVE_TLS || defined USE_EMUTLS
52__thread struct goacc_thread *goacc_tls_data;
53#else
54pthread_key_t goacc_tls_key;
55#endif
56static pthread_key_t goacc_cleanup_key;
57
ca4c3545 58static struct goacc_thread *goacc_threads;
59static gomp_mutex_t goacc_thread_lock;
60
61/* An array of dispatchers for device types, indexed by the type. This array
62 only references "base" devices, and other instances of the same type are
63 found by simply indexing from each such device (which are stored linearly,
64 grouped by device in target.c:devices). */
65static struct gomp_device_descr *dispatchers[_ACC_device_hwm] = { 0 };
66
67attribute_hidden void
68goacc_register (struct gomp_device_descr *disp)
69{
70 /* Only register the 0th device here. */
71 if (disp->target_id != 0)
72 return;
73
74 gomp_mutex_lock (&acc_device_lock);
75
76 assert (acc_device_type (disp->type) != acc_device_none
77 && acc_device_type (disp->type) != acc_device_default
78 && acc_device_type (disp->type) != acc_device_not_host);
79 assert (!dispatchers[disp->type]);
80 dispatchers[disp->type] = disp;
81
82 gomp_mutex_unlock (&acc_device_lock);
83}
84
85/* OpenACC names some things a little differently. */
86
87static const char *
88get_openacc_name (const char *name)
89{
90 if (strcmp (name, "nvptx") == 0)
91 return "nvidia";
92 else
93 return name;
94}
95
0a1fe572 96static const char *
97name_of_acc_device_t (enum acc_device_t type)
98{
99 switch (type)
100 {
101 case acc_device_none: return "none";
102 case acc_device_default: return "default";
103 case acc_device_host: return "host";
0a1fe572 104 case acc_device_not_host: return "not_host";
105 case acc_device_nvidia: return "nvidia";
106 default: gomp_fatal ("unknown device type %u", (unsigned) type);
107 }
108}
109
dd7f667e 110/* ACC_DEVICE_LOCK must be held before calling this function. If FAIL_IS_ERROR
111 is true, this function raises an error if there are no devices of type D,
112 otherwise it returns NULL in that case. */
d39966e5 113
ca4c3545 114static struct gomp_device_descr *
dd7f667e 115resolve_device (acc_device_t d, bool fail_is_error)
ca4c3545 116{
117 acc_device_t d_arg = d;
118
119 switch (d)
120 {
121 case acc_device_default:
122 {
123 if (goacc_device_type)
124 {
125 /* Lookup the named device. */
126 while (++d != _ACC_device_hwm)
127 if (dispatchers[d]
128 && !strcasecmp (goacc_device_type,
129 get_openacc_name (dispatchers[d]->name))
130 && dispatchers[d]->get_num_devices_func () > 0)
131 goto found;
132
dd7f667e 133 if (fail_is_error)
134 {
135 gomp_mutex_unlock (&acc_device_lock);
136 gomp_fatal ("device type %s not supported", goacc_device_type);
137 }
138 else
139 return NULL;
ca4c3545 140 }
141
142 /* No default device specified, so start scanning for any non-host
143 device that is available. */
144 d = acc_device_not_host;
145 }
146 /* FALLTHROUGH */
147
148 case acc_device_not_host:
149 /* Find the first available device after acc_device_not_host. */
150 while (++d != _ACC_device_hwm)
151 if (dispatchers[d] && dispatchers[d]->get_num_devices_func () > 0)
152 goto found;
153 if (d_arg == acc_device_default)
154 {
155 d = acc_device_host;
156 goto found;
157 }
dd7f667e 158 if (fail_is_error)
159 {
160 gomp_mutex_unlock (&acc_device_lock);
161 gomp_fatal ("no device found");
162 }
163 else
164 return NULL;
ca4c3545 165 break;
166
167 case acc_device_host:
168 break;
169
170 default:
171 if (d > _ACC_device_hwm)
dd7f667e 172 {
173 if (fail_is_error)
174 goto unsupported_device;
175 else
176 return NULL;
177 }
ca4c3545 178 break;
179 }
180 found:
181
182 assert (d != acc_device_none
183 && d != acc_device_default
184 && d != acc_device_not_host);
185
dd7f667e 186 if (dispatchers[d] == NULL && fail_is_error)
187 {
188 unsupported_device:
189 gomp_mutex_unlock (&acc_device_lock);
190 gomp_fatal ("device type %s not supported", name_of_acc_device_t (d));
191 }
192
ca4c3545 193 return dispatchers[d];
194}
195
dd7f667e 196/* Emit a suitable error if no device of a particular type is available, or
197 the given device number is out-of-range. */
198static void
199acc_dev_num_out_of_range (acc_device_t d, int ord, int ndevs)
200{
201 if (ndevs == 0)
202 gomp_fatal ("no devices of type %s available", name_of_acc_device_t (d));
203 else
204 gomp_fatal ("device %u out of range", ord);
205}
206
ca4c3545 207/* This is called when plugins have been initialized, and serves to call
208 (indirectly) the target's device_init hook. Calling multiple times without
dd7f667e 209 an intervening acc_shutdown_1 call is an error. ACC_DEVICE_LOCK must be
d39966e5 210 held before calling this function. */
ca4c3545 211
212static struct gomp_device_descr *
213acc_init_1 (acc_device_t d)
214{
0a1fe572 215 struct gomp_device_descr *base_dev, *acc_dev;
216 int ndevs;
ca4c3545 217
dd7f667e 218 base_dev = resolve_device (d, true);
0a1fe572 219
220 ndevs = base_dev->get_num_devices_func ();
221
dd7f667e 222 if (ndevs <= 0 || goacc_device_num >= ndevs)
223 acc_dev_num_out_of_range (d, goacc_device_num, ndevs);
ca4c3545 224
0a1fe572 225 acc_dev = &base_dev[goacc_device_num];
ca4c3545 226
d39966e5 227 gomp_mutex_lock (&acc_dev->lock);
f87b2900 228 if (acc_dev->state == GOMP_DEVICE_INITIALIZED)
d39966e5 229 {
230 gomp_mutex_unlock (&acc_dev->lock);
231 gomp_fatal ("device already active");
232 }
ca4c3545 233
ca4c3545 234 gomp_init_device (acc_dev);
d39966e5 235 gomp_mutex_unlock (&acc_dev->lock);
ca4c3545 236
0a1fe572 237 return base_dev;
238}
239
dd7f667e 240/* ACC_DEVICE_LOCK must be held before calling this function. */
d39966e5 241
0a1fe572 242static void
243acc_shutdown_1 (acc_device_t d)
244{
245 struct gomp_device_descr *base_dev;
246 struct goacc_thread *walk;
247 int ndevs, i;
248 bool devices_active = false;
249
250 /* Get the base device for this device type. */
dd7f667e 251 base_dev = resolve_device (d, true);
0a1fe572 252
7de5731e 253 ndevs = base_dev->get_num_devices_func ();
254
255 /* Unload all the devices of this type that have been opened. */
256 for (i = 0; i < ndevs; i++)
257 {
258 struct gomp_device_descr *acc_dev = &base_dev[i];
259
260 gomp_mutex_lock (&acc_dev->lock);
261 gomp_unload_device (acc_dev);
262 gomp_mutex_unlock (&acc_dev->lock);
263 }
264
0a1fe572 265 gomp_mutex_lock (&goacc_thread_lock);
266
267 /* Free target-specific TLS data and close all devices. */
268 for (walk = goacc_threads; walk != NULL; walk = walk->next)
269 {
270 if (walk->target_tls)
271 base_dev->openacc.destroy_thread_data_func (walk->target_tls);
272
273 walk->target_tls = NULL;
274
275 /* This would mean the user is shutting down OpenACC in the middle of an
276 "acc data" pragma. Likely not intentional. */
277 if (walk->mapped_data)
09f66ac1 278 {
279 gomp_mutex_unlock (&goacc_thread_lock);
280 gomp_fatal ("shutdown in 'acc data' region");
281 }
0a1fe572 282
283 /* Similarly, if this happens then user code has done something weird. */
284 if (walk->saved_bound_dev)
09f66ac1 285 {
286 gomp_mutex_unlock (&goacc_thread_lock);
287 gomp_fatal ("shutdown during host fallback");
288 }
0a1fe572 289
290 if (walk->dev)
291 {
292 gomp_mutex_lock (&walk->dev->lock);
293 gomp_free_memmap (&walk->dev->mem_map);
294 gomp_mutex_unlock (&walk->dev->lock);
295
296 walk->dev = NULL;
297 walk->base_dev = NULL;
298 }
299 }
300
301 gomp_mutex_unlock (&goacc_thread_lock);
302
0a1fe572 303 /* Close all the devices of this type that have been opened. */
9b50ad1d 304 bool ret = true;
0a1fe572 305 for (i = 0; i < ndevs; i++)
306 {
307 struct gomp_device_descr *acc_dev = &base_dev[i];
d39966e5 308 gomp_mutex_lock (&acc_dev->lock);
f87b2900 309 if (acc_dev->state == GOMP_DEVICE_INITIALIZED)
0a1fe572 310 {
311 devices_active = true;
9b50ad1d 312 ret &= acc_dev->fini_device_func (acc_dev->target_id);
f87b2900 313 acc_dev->state = GOMP_DEVICE_UNINITIALIZED;
0a1fe572 314 }
d39966e5 315 gomp_mutex_unlock (&acc_dev->lock);
0a1fe572 316 }
317
9b50ad1d 318 if (!ret)
319 gomp_fatal ("device finalization failed");
320
0a1fe572 321 if (!devices_active)
322 gomp_fatal ("no device initialized");
ca4c3545 323}
324
325static struct goacc_thread *
326goacc_new_thread (void)
327{
43f7268a 328 struct goacc_thread *thr = gomp_malloc (sizeof (struct goacc_thread));
ca4c3545 329
330#if defined HAVE_TLS || defined USE_EMUTLS
331 goacc_tls_data = thr;
332#else
333 pthread_setspecific (goacc_tls_key, thr);
334#endif
335
336 pthread_setspecific (goacc_cleanup_key, thr);
337
338 gomp_mutex_lock (&goacc_thread_lock);
339 thr->next = goacc_threads;
340 goacc_threads = thr;
341 gomp_mutex_unlock (&goacc_thread_lock);
342
343 return thr;
344}
345
346static void
347goacc_destroy_thread (void *data)
348{
349 struct goacc_thread *thr = data, *walk, *prev;
350
351 gomp_mutex_lock (&goacc_thread_lock);
352
353 if (thr)
354 {
0a1fe572 355 struct gomp_device_descr *acc_dev = thr->dev;
356
357 if (acc_dev && thr->target_tls)
ca4c3545 358 {
0a1fe572 359 acc_dev->openacc.destroy_thread_data_func (thr->target_tls);
ca4c3545 360 thr->target_tls = NULL;
361 }
362
363 assert (!thr->mapped_data);
364
365 /* Remove from thread list. */
366 for (prev = NULL, walk = goacc_threads; walk;
367 prev = walk, walk = walk->next)
368 if (walk == thr)
369 {
370 if (prev == NULL)
371 goacc_threads = walk->next;
372 else
373 prev->next = walk->next;
374
375 free (thr);
376
377 break;
378 }
379
380 assert (walk);
381 }
382
383 gomp_mutex_unlock (&goacc_thread_lock);
384}
385
0a1fe572 386/* Use the ORD'th device instance for the current host thread (or -1 for the
387 current global default). The device (and the runtime) must be initialised
388 before calling this function. */
ca4c3545 389
0a1fe572 390void
391goacc_attach_host_thread_to_device (int ord)
ca4c3545 392{
393 struct goacc_thread *thr = goacc_thread ();
0a1fe572 394 struct gomp_device_descr *acc_dev = NULL, *base_dev = NULL;
395 int num_devices;
396
397 if (thr && thr->dev && (thr->dev->target_id == ord || ord < 0))
398 return;
399
ca4c3545 400 if (ord < 0)
401 ord = goacc_device_num;
0a1fe572 402
403 /* Decide which type of device to use. If the current thread has a device
404 type already (e.g. set by acc_set_device_type), use that, else use the
405 global default. */
406 if (thr && thr->base_dev)
407 base_dev = thr->base_dev;
408 else
409 {
410 assert (cached_base_dev);
411 base_dev = cached_base_dev;
412 }
413
414 num_devices = base_dev->get_num_devices_func ();
415 if (num_devices <= 0 || ord >= num_devices)
dd7f667e 416 acc_dev_num_out_of_range (acc_device_type (base_dev->type), ord,
417 num_devices);
0a1fe572 418
ca4c3545 419 if (!thr)
420 thr = goacc_new_thread ();
0a1fe572 421
422 thr->base_dev = base_dev;
423 thr->dev = acc_dev = &base_dev[ord];
ca4c3545 424 thr->saved_bound_dev = NULL;
425 thr->mapped_data = NULL;
0a1fe572 426
ca4c3545 427 thr->target_tls
0a1fe572 428 = acc_dev->openacc.create_thread_data_func (ord);
429
ca4c3545 430 acc_dev->openacc.async_set_async_func (acc_async_sync);
ca4c3545 431}
432
433/* OpenACC 2.0a (3.2.12, 3.2.13) doesn't specify whether the serialization of
434 init/shutdown is per-process or per-thread. We choose per-process. */
435
436void
437acc_init (acc_device_t d)
438{
921d472d 439 gomp_init_targets_once ();
ca4c3545 440
441 gomp_mutex_lock (&acc_device_lock);
442
0a1fe572 443 cached_base_dev = acc_init_1 (d);
ca4c3545 444
445 gomp_mutex_unlock (&acc_device_lock);
0a1fe572 446
447 goacc_attach_host_thread_to_device (-1);
ca4c3545 448}
449
450ialias (acc_init)
451
ca4c3545 452void
453acc_shutdown (acc_device_t d)
454{
cfe316ad 455 gomp_init_targets_once ();
456
ca4c3545 457 gomp_mutex_lock (&acc_device_lock);
458
459 acc_shutdown_1 (d);
460
461 gomp_mutex_unlock (&acc_device_lock);
462}
463
464ialias (acc_shutdown)
465
ca4c3545 466int
467acc_get_num_devices (acc_device_t d)
468{
469 int n = 0;
0a1fe572 470 struct gomp_device_descr *acc_dev;
ca4c3545 471
472 if (d == acc_device_none)
473 return 0;
474
0a1fe572 475 gomp_init_targets_once ();
ca4c3545 476
d39966e5 477 gomp_mutex_lock (&acc_device_lock);
dd7f667e 478 acc_dev = resolve_device (d, false);
d39966e5 479 gomp_mutex_unlock (&acc_device_lock);
480
ca4c3545 481 if (!acc_dev)
482 return 0;
483
484 n = acc_dev->get_num_devices_func ();
485 if (n < 0)
486 n = 0;
487
488 return n;
489}
490
491ialias (acc_get_num_devices)
492
0a1fe572 493/* Set the device type for the current thread only (using the current global
494 default device number), initialising that device if necessary. Also set the
495 default device type for new threads to D. */
496
ca4c3545 497void
498acc_set_device_type (acc_device_t d)
499{
0a1fe572 500 struct gomp_device_descr *base_dev, *acc_dev;
501 struct goacc_thread *thr = goacc_thread ();
502
921d472d 503 gomp_init_targets_once ();
0a1fe572 504
921d472d 505 gomp_mutex_lock (&acc_device_lock);
0a1fe572 506
dd7f667e 507 cached_base_dev = base_dev = resolve_device (d, true);
0a1fe572 508 acc_dev = &base_dev[goacc_device_num];
509
d39966e5 510 gomp_mutex_lock (&acc_dev->lock);
f87b2900 511 if (acc_dev->state == GOMP_DEVICE_UNINITIALIZED)
0a1fe572 512 gomp_init_device (acc_dev);
d39966e5 513 gomp_mutex_unlock (&acc_dev->lock);
0a1fe572 514
515 gomp_mutex_unlock (&acc_device_lock);
516
517 /* We're changing device type: invalidate the current thread's dev and
518 base_dev pointers. */
519 if (thr && thr->base_dev != base_dev)
520 {
521 thr->base_dev = thr->dev = NULL;
522 if (thr->mapped_data)
523 gomp_fatal ("acc_set_device_type in 'acc data' region");
524 }
525
526 goacc_attach_host_thread_to_device (-1);
ca4c3545 527}
528
529ialias (acc_set_device_type)
530
531acc_device_t
532acc_get_device_type (void)
533{
534 acc_device_t res = acc_device_none;
0a1fe572 535 struct gomp_device_descr *dev;
536 struct goacc_thread *thr = goacc_thread ();
ca4c3545 537
0a1fe572 538 if (thr && thr->base_dev)
539 res = acc_device_type (thr->base_dev->type);
ca4c3545 540 else
541 {
542 gomp_init_targets_once ();
543
d39966e5 544 gomp_mutex_lock (&acc_device_lock);
dd7f667e 545 dev = resolve_device (acc_device_default, true);
d39966e5 546 gomp_mutex_unlock (&acc_device_lock);
ca4c3545 547 res = acc_device_type (dev->type);
548 }
549
550 assert (res != acc_device_default
551 && res != acc_device_not_host);
552
553 return res;
554}
555
556ialias (acc_get_device_type)
557
558int
559acc_get_device_num (acc_device_t d)
560{
561 const struct gomp_device_descr *dev;
0a1fe572 562 struct goacc_thread *thr = goacc_thread ();
ca4c3545 563
564 if (d >= _ACC_device_hwm)
dd7f667e 565 gomp_fatal ("unknown device type %u", (unsigned) d);
ca4c3545 566
921d472d 567 gomp_init_targets_once ();
ca4c3545 568
d39966e5 569 gomp_mutex_lock (&acc_device_lock);
dd7f667e 570 dev = resolve_device (d, true);
d39966e5 571 gomp_mutex_unlock (&acc_device_lock);
ca4c3545 572
0a1fe572 573 if (thr && thr->base_dev == dev && thr->dev)
574 return thr->dev->target_id;
ca4c3545 575
0a1fe572 576 return goacc_device_num;
ca4c3545 577}
578
579ialias (acc_get_device_num)
580
581void
0a1fe572 582acc_set_device_num (int ord, acc_device_t d)
ca4c3545 583{
0a1fe572 584 struct gomp_device_descr *base_dev, *acc_dev;
ca4c3545 585 int num_devices;
586
921d472d 587 gomp_init_targets_once ();
ca4c3545 588
0a1fe572 589 if (ord < 0)
590 ord = goacc_device_num;
ca4c3545 591
0a1fe572 592 if ((int) d == 0)
593 /* Set whatever device is being used by the current host thread to use
594 device instance ORD. It's unclear if this is supposed to affect other
595 host threads too (OpenACC 2.0 (3.2.4) acc_set_device_num). */
596 goacc_attach_host_thread_to_device (ord);
ca4c3545 597 else
598 {
ca4c3545 599 gomp_mutex_lock (&acc_device_lock);
600
dd7f667e 601 cached_base_dev = base_dev = resolve_device (d, true);
ca4c3545 602
603 num_devices = base_dev->get_num_devices_func ();
604
dd7f667e 605 if (num_devices <= 0 || ord >= num_devices)
606 acc_dev_num_out_of_range (d, ord, num_devices);
ca4c3545 607
0a1fe572 608 acc_dev = &base_dev[ord];
ca4c3545 609
d39966e5 610 gomp_mutex_lock (&acc_dev->lock);
f87b2900 611 if (acc_dev->state == GOMP_DEVICE_UNINITIALIZED)
0a1fe572 612 gomp_init_device (acc_dev);
d39966e5 613 gomp_mutex_unlock (&acc_dev->lock);
ca4c3545 614
615 gomp_mutex_unlock (&acc_device_lock);
0a1fe572 616
617 goacc_attach_host_thread_to_device (ord);
ca4c3545 618 }
0a1fe572 619
620 goacc_device_num = ord;
ca4c3545 621}
622
623ialias (acc_set_device_num)
624
689db5ed 625/* For -O and higher, the compiler always attempts to expand acc_on_device, but
626 if the user disables the builtin, or calls it via a pointer, we'll need this
627 version.
628
629 Compile this with optimization, so that the compiler expands
1ae4e7aa 630 this, rather than generating infinitely recursive code. */
631
632int __attribute__ ((__optimize__ ("O2")))
ca4c3545 633acc_on_device (acc_device_t dev)
634{
f212338e 635 return __builtin_acc_on_device (dev);
ca4c3545 636}
637
638ialias (acc_on_device)
639
640attribute_hidden void
641goacc_runtime_initialize (void)
642{
643 gomp_mutex_init (&acc_device_lock);
644
645#if !(defined HAVE_TLS || defined USE_EMUTLS)
646 pthread_key_create (&goacc_tls_key, NULL);
647#endif
648
649 pthread_key_create (&goacc_cleanup_key, goacc_destroy_thread);
650
0a1fe572 651 cached_base_dev = NULL;
ca4c3545 652
653 goacc_threads = NULL;
654 gomp_mutex_init (&goacc_thread_lock);
2f6c4c35 655
656 /* Initialize and register the 'host' device type. */
657 goacc_host_init ();
ca4c3545 658}
659
660/* Compiler helper functions */
661
662attribute_hidden void
663goacc_save_and_set_bind (acc_device_t d)
664{
665 struct goacc_thread *thr = goacc_thread ();
666
667 assert (!thr->saved_bound_dev);
668
669 thr->saved_bound_dev = thr->dev;
670 thr->dev = dispatchers[d];
671}
672
673attribute_hidden void
674goacc_restore_bind (void)
675{
676 struct goacc_thread *thr = goacc_thread ();
677
678 thr->dev = thr->saved_bound_dev;
679 thr->saved_bound_dev = NULL;
680}
681
682/* This is called from any OpenACC support function that may need to implicitly
0a1fe572 683 initialize the libgomp runtime, either globally or from a new host thread.
684 On exit "goacc_thread" will return a valid & populated thread block. */
ca4c3545 685
686attribute_hidden void
687goacc_lazy_initialize (void)
688{
689 struct goacc_thread *thr = goacc_thread ();
690
691 if (thr && thr->dev)
692 return;
693
0a1fe572 694 if (!cached_base_dev)
695 acc_init (acc_device_default);
ca4c3545 696 else
0a1fe572 697 goacc_attach_host_thread_to_device (-1);
ca4c3545 698}