]> git.ipfire.org Git - thirdparty/gcc.git/blob - libgomp/oacc-init.c
tree-optimization/95495 - use SLP_TREE_REPRESENTATIVE in assertion
[thirdparty/gcc.git] / libgomp / oacc-init.c
1 /* OpenACC Runtime initialization routines
2
3 Copyright (C) 2013-2020 Free Software Foundation, Inc.
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
38 /* This lock is used to protect access to cached_base_dev, dispatchers and
39 the (abstract) initialisation state of attached offloading devices. */
40
41 static gomp_mutex_t acc_device_lock;
42
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
49 static struct gomp_device_descr *cached_base_dev = NULL;
50
51 #if defined HAVE_TLS || defined USE_EMUTLS
52 __thread struct goacc_thread *goacc_tls_data;
53 #else
54 pthread_key_t goacc_tls_key;
55 #endif
56 static pthread_key_t goacc_cleanup_key;
57
58 static struct goacc_thread *goacc_threads;
59 static 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). */
65 static struct gomp_device_descr *dispatchers[_ACC_device_hwm] = { 0 };
66
67 attribute_hidden void
68 goacc_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 static bool
86 known_device_type_p (acc_device_t d)
87 {
88 return d >= 0 && d < _ACC_device_hwm;
89 }
90
91 static void
92 unknown_device_type_error (acc_device_t invalid_type)
93 {
94 gomp_fatal ("unknown device type %u", invalid_type);
95 }
96
97 /* OpenACC names some things a little differently. */
98
99 static const char *
100 get_openacc_name (const char *name)
101 {
102 if (strcmp (name, "gcn") == 0)
103 return "radeon";
104 else if (strcmp (name, "nvptx") == 0)
105 return "nvidia";
106 else
107 return name;
108 }
109
110 static const char *
111 name_of_acc_device_t (enum acc_device_t type)
112 {
113 switch (type)
114 {
115 case acc_device_none: return "none";
116 case acc_device_default: return "default";
117 case acc_device_host: return "host";
118 case acc_device_not_host: return "not_host";
119 case acc_device_nvidia: return "nvidia";
120 case acc_device_radeon: return "radeon";
121 default: unknown_device_type_error (type);
122 }
123 __builtin_unreachable ();
124 }
125
126 /* ACC_DEVICE_LOCK must be held before calling this function. If FAIL_IS_ERROR
127 is true, this function raises an error if there are no devices of type D,
128 otherwise it returns NULL in that case. */
129
130 static struct gomp_device_descr *
131 resolve_device (acc_device_t d, bool fail_is_error)
132 {
133 acc_device_t d_arg = d;
134
135 switch (d)
136 {
137 case acc_device_default:
138 {
139 if (goacc_device_type)
140 {
141 /* Lookup the named device. */
142 while (known_device_type_p (++d))
143 if (dispatchers[d]
144 && !strcasecmp (goacc_device_type,
145 get_openacc_name (dispatchers[d]->name))
146 && dispatchers[d]->get_num_devices_func () > 0)
147 goto found;
148
149 if (fail_is_error)
150 {
151 gomp_mutex_unlock (&acc_device_lock);
152 gomp_fatal ("device type %s not supported", goacc_device_type);
153 }
154 else
155 return NULL;
156 }
157
158 /* No default device specified, so start scanning for any non-host
159 device that is available. */
160 d = acc_device_not_host;
161 }
162 /* FALLTHROUGH */
163
164 case acc_device_not_host:
165 /* Find the first available device after acc_device_not_host. */
166 while (known_device_type_p (++d))
167 if (dispatchers[d] && dispatchers[d]->get_num_devices_func () > 0)
168 goto found;
169 if (d_arg == acc_device_default)
170 {
171 d = acc_device_host;
172 goto found;
173 }
174 if (fail_is_error)
175 {
176 gomp_mutex_unlock (&acc_device_lock);
177 gomp_fatal ("no device found");
178 }
179 else
180 return NULL;
181 break;
182
183 case acc_device_host:
184 break;
185
186 default:
187 if (!known_device_type_p (d))
188 {
189 if (fail_is_error)
190 goto unsupported_device;
191 else
192 return NULL;
193 }
194 break;
195 }
196 found:
197
198 assert (d != acc_device_none
199 && d != acc_device_default
200 && d != acc_device_not_host);
201
202 if (dispatchers[d] == NULL && fail_is_error)
203 {
204 unsupported_device:
205 gomp_mutex_unlock (&acc_device_lock);
206 gomp_fatal ("device type %s not supported", name_of_acc_device_t (d));
207 }
208
209 return dispatchers[d];
210 }
211
212 /* Emit a suitable error if no device of a particular type is available, or
213 the given device number is out-of-range. */
214 static void
215 acc_dev_num_out_of_range (acc_device_t d, int ord, int ndevs)
216 {
217 if (ndevs == 0)
218 gomp_fatal ("no devices of type %s available", name_of_acc_device_t (d));
219 else
220 gomp_fatal ("device %u out of range", ord);
221 }
222
223 /* This is called when plugins have been initialized, and serves to call
224 (indirectly) the target's device_init hook. Calling multiple times without
225 an intervening acc_shutdown_1 call is an error. ACC_DEVICE_LOCK must be
226 held before calling this function. */
227
228 static struct gomp_device_descr *
229 acc_init_1 (acc_device_t d, acc_construct_t parent_construct, int implicit)
230 {
231 bool check_not_nested_p;
232 if (implicit)
233 {
234 /* In the implicit case, there should (TODO: must?) already be something
235 have been set up for an outer construct. */
236 check_not_nested_p = false;
237 }
238 else
239 {
240 check_not_nested_p = true;
241 /* TODO: should we set 'thr->prof_info' etc. in this case ('acc_init')?
242 The problem is, that we don't have 'thr' yet? (So,
243 'check_not_nested_p = true' also is pointless actually.) */
244 }
245 bool profiling_p = GOACC_PROFILING_DISPATCH_P (check_not_nested_p);
246
247 acc_prof_info prof_info;
248 if (profiling_p)
249 {
250 prof_info.event_type = acc_ev_device_init_start;
251 prof_info.valid_bytes = _ACC_PROF_INFO_VALID_BYTES;
252 prof_info.version = _ACC_PROF_INFO_VERSION;
253 prof_info.device_type = d;
254 prof_info.device_number = goacc_device_num;
255 prof_info.thread_id = -1;
256 prof_info.async = acc_async_sync;
257 prof_info.async_queue = prof_info.async;
258 prof_info.src_file = NULL;
259 prof_info.func_name = NULL;
260 prof_info.line_no = -1;
261 prof_info.end_line_no = -1;
262 prof_info.func_line_no = -1;
263 prof_info.func_end_line_no = -1;
264 }
265 acc_event_info device_init_event_info;
266 if (profiling_p)
267 {
268 device_init_event_info.other_event.event_type = prof_info.event_type;
269 device_init_event_info.other_event.valid_bytes
270 = _ACC_OTHER_EVENT_INFO_VALID_BYTES;
271 device_init_event_info.other_event.parent_construct = parent_construct;
272 device_init_event_info.other_event.implicit = implicit;
273 device_init_event_info.other_event.tool_info = NULL;
274 }
275 acc_api_info api_info;
276 if (profiling_p)
277 {
278 api_info.device_api = acc_device_api_none;
279 api_info.valid_bytes = _ACC_API_INFO_VALID_BYTES;
280 api_info.device_type = prof_info.device_type;
281 api_info.vendor = -1;
282 api_info.device_handle = NULL;
283 api_info.context_handle = NULL;
284 api_info.async_handle = NULL;
285 }
286
287 if (profiling_p)
288 goacc_profiling_dispatch (&prof_info, &device_init_event_info, &api_info);
289
290 struct gomp_device_descr *base_dev, *acc_dev;
291 int ndevs;
292
293 base_dev = resolve_device (d, true);
294
295 ndevs = base_dev->get_num_devices_func ();
296
297 if (ndevs <= 0 || goacc_device_num >= ndevs)
298 acc_dev_num_out_of_range (d, goacc_device_num, ndevs);
299
300 acc_dev = &base_dev[goacc_device_num];
301
302 gomp_mutex_lock (&acc_dev->lock);
303 if (acc_dev->state == GOMP_DEVICE_INITIALIZED)
304 {
305 gomp_mutex_unlock (&acc_dev->lock);
306 gomp_fatal ("device already active");
307 }
308
309 gomp_init_device (acc_dev);
310 gomp_mutex_unlock (&acc_dev->lock);
311
312 if (profiling_p)
313 {
314 prof_info.event_type = acc_ev_device_init_end;
315 device_init_event_info.other_event.event_type = prof_info.event_type;
316 goacc_profiling_dispatch (&prof_info, &device_init_event_info,
317 &api_info);
318 }
319
320 return base_dev;
321 }
322
323 /* ACC_DEVICE_LOCK must be held before calling this function. */
324
325 static void
326 acc_shutdown_1 (acc_device_t d)
327 {
328 struct gomp_device_descr *base_dev;
329 struct goacc_thread *walk;
330 int ndevs, i;
331 bool devices_active = false;
332
333 /* Get the base device for this device type. */
334 base_dev = resolve_device (d, true);
335
336 ndevs = base_dev->get_num_devices_func ();
337
338 /* Unload all the devices of this type that have been opened. */
339 for (i = 0; i < ndevs; i++)
340 {
341 struct gomp_device_descr *acc_dev = &base_dev[i];
342
343 gomp_mutex_lock (&acc_dev->lock);
344 gomp_unload_device (acc_dev);
345 gomp_mutex_unlock (&acc_dev->lock);
346 }
347
348 gomp_mutex_lock (&goacc_thread_lock);
349
350 /* Free target-specific TLS data and close all devices. */
351 for (walk = goacc_threads; walk != NULL; walk = walk->next)
352 {
353 if (walk->target_tls)
354 base_dev->openacc.destroy_thread_data_func (walk->target_tls);
355
356 walk->target_tls = NULL;
357
358 /* This would mean the user is shutting down OpenACC in the middle of an
359 "acc data" pragma. Likely not intentional. */
360 if (walk->mapped_data)
361 {
362 gomp_mutex_unlock (&goacc_thread_lock);
363 gomp_fatal ("shutdown in 'acc data' region");
364 }
365
366 /* Similarly, if this happens then user code has done something weird. */
367 if (walk->saved_bound_dev)
368 {
369 gomp_mutex_unlock (&goacc_thread_lock);
370 gomp_fatal ("shutdown during host fallback");
371 }
372
373 if (walk->dev)
374 {
375 gomp_mutex_lock (&walk->dev->lock);
376
377 while (walk->dev->mem_map.root)
378 {
379 splay_tree_key k = &walk->dev->mem_map.root->key;
380 if (k->aux)
381 k->aux->link_key = NULL;
382 gomp_remove_var (walk->dev, k);
383 }
384
385 gomp_mutex_unlock (&walk->dev->lock);
386
387 walk->dev = NULL;
388 walk->base_dev = NULL;
389 }
390 }
391
392 gomp_mutex_unlock (&goacc_thread_lock);
393
394 /* Close all the devices of this type that have been opened. */
395 bool ret = true;
396 for (i = 0; i < ndevs; i++)
397 {
398 struct gomp_device_descr *acc_dev = &base_dev[i];
399 gomp_mutex_lock (&acc_dev->lock);
400 if (acc_dev->state == GOMP_DEVICE_INITIALIZED)
401 {
402 devices_active = true;
403 ret &= gomp_fini_device (acc_dev);
404 acc_dev->state = GOMP_DEVICE_UNINITIALIZED;
405 }
406 gomp_mutex_unlock (&acc_dev->lock);
407 }
408
409 if (!ret)
410 gomp_fatal ("device finalization failed");
411
412 if (!devices_active)
413 gomp_fatal ("no device initialized");
414 }
415
416 static struct goacc_thread *
417 goacc_new_thread (void)
418 {
419 struct goacc_thread *thr = gomp_malloc (sizeof (struct goacc_thread));
420
421 #if defined HAVE_TLS || defined USE_EMUTLS
422 goacc_tls_data = thr;
423 #else
424 pthread_setspecific (goacc_tls_key, thr);
425 #endif
426
427 pthread_setspecific (goacc_cleanup_key, thr);
428
429 gomp_mutex_lock (&goacc_thread_lock);
430 thr->next = goacc_threads;
431 goacc_threads = thr;
432 gomp_mutex_unlock (&goacc_thread_lock);
433
434 return thr;
435 }
436
437 static void
438 goacc_destroy_thread (void *data)
439 {
440 struct goacc_thread *thr = data, *walk, *prev;
441
442 gomp_mutex_lock (&goacc_thread_lock);
443
444 if (thr)
445 {
446 struct gomp_device_descr *acc_dev = thr->dev;
447
448 if (acc_dev && thr->target_tls)
449 {
450 acc_dev->openacc.destroy_thread_data_func (thr->target_tls);
451 thr->target_tls = NULL;
452 }
453
454 assert (!thr->mapped_data);
455
456 /* Remove from thread list. */
457 for (prev = NULL, walk = goacc_threads; walk;
458 prev = walk, walk = walk->next)
459 if (walk == thr)
460 {
461 if (prev == NULL)
462 goacc_threads = walk->next;
463 else
464 prev->next = walk->next;
465
466 free (thr);
467
468 break;
469 }
470
471 assert (walk);
472 }
473
474 gomp_mutex_unlock (&goacc_thread_lock);
475 }
476
477 /* Use the ORD'th device instance for the current host thread (or -1 for the
478 current global default). The device (and the runtime) must be initialised
479 before calling this function. */
480
481 void
482 goacc_attach_host_thread_to_device (int ord)
483 {
484 struct goacc_thread *thr = goacc_thread ();
485 struct gomp_device_descr *acc_dev = NULL, *base_dev = NULL;
486 int num_devices;
487
488 if (thr && thr->dev && (thr->dev->target_id == ord || ord < 0))
489 return;
490
491 if (ord < 0)
492 ord = goacc_device_num;
493
494 /* Decide which type of device to use. If the current thread has a device
495 type already (e.g. set by acc_set_device_type), use that, else use the
496 global default. */
497 if (thr && thr->base_dev)
498 base_dev = thr->base_dev;
499 else
500 {
501 assert (cached_base_dev);
502 base_dev = cached_base_dev;
503 }
504
505 num_devices = base_dev->get_num_devices_func ();
506 if (num_devices <= 0 || ord >= num_devices)
507 acc_dev_num_out_of_range (acc_device_type (base_dev->type), ord,
508 num_devices);
509
510 if (!thr)
511 thr = goacc_new_thread ();
512
513 thr->base_dev = base_dev;
514 thr->dev = acc_dev = &base_dev[ord];
515 thr->saved_bound_dev = NULL;
516 thr->mapped_data = NULL;
517 thr->prof_info = NULL;
518 thr->api_info = NULL;
519 /* Initially, all callbacks for all events are enabled. */
520 thr->prof_callbacks_enabled = true;
521
522 thr->target_tls
523 = acc_dev->openacc.create_thread_data_func (ord);
524 }
525
526 /* OpenACC 2.0a (3.2.12, 3.2.13) doesn't specify whether the serialization of
527 init/shutdown is per-process or per-thread. We choose per-process. */
528
529 void
530 acc_init (acc_device_t d)
531 {
532 if (!known_device_type_p (d))
533 unknown_device_type_error (d);
534
535 gomp_init_targets_once ();
536
537 gomp_mutex_lock (&acc_device_lock);
538 cached_base_dev = acc_init_1 (d, acc_construct_runtime_api, 0);
539 gomp_mutex_unlock (&acc_device_lock);
540
541 goacc_attach_host_thread_to_device (-1);
542 }
543
544 ialias (acc_init)
545
546 void
547 acc_shutdown (acc_device_t d)
548 {
549 if (!known_device_type_p (d))
550 unknown_device_type_error (d);
551
552 gomp_init_targets_once ();
553
554 gomp_mutex_lock (&acc_device_lock);
555
556 acc_shutdown_1 (d);
557
558 gomp_mutex_unlock (&acc_device_lock);
559 }
560
561 ialias (acc_shutdown)
562
563 int
564 acc_get_num_devices (acc_device_t d)
565 {
566 if (!known_device_type_p (d))
567 unknown_device_type_error (d);
568
569 int n = 0;
570 struct gomp_device_descr *acc_dev;
571
572 if (d == acc_device_none)
573 return 0;
574
575 gomp_init_targets_once ();
576
577 gomp_mutex_lock (&acc_device_lock);
578 acc_dev = resolve_device (d, false);
579 gomp_mutex_unlock (&acc_device_lock);
580
581 if (!acc_dev)
582 return 0;
583
584 n = acc_dev->get_num_devices_func ();
585 if (n < 0)
586 n = 0;
587
588 return n;
589 }
590
591 ialias (acc_get_num_devices)
592
593 /* Set the device type for the current thread only (using the current global
594 default device number), initialising that device if necessary. Also set the
595 default device type for new threads to D. */
596
597 void
598 acc_set_device_type (acc_device_t d)
599 {
600 if (!known_device_type_p (d))
601 unknown_device_type_error (d);
602
603 struct gomp_device_descr *base_dev, *acc_dev;
604 struct goacc_thread *thr = goacc_thread ();
605
606 acc_prof_info prof_info;
607 acc_api_info api_info;
608 bool profiling_p = GOACC_PROFILING_SETUP_P (thr, &prof_info, &api_info);
609 if (profiling_p)
610 prof_info.device_type = d;
611
612 gomp_init_targets_once ();
613
614 gomp_mutex_lock (&acc_device_lock);
615
616 cached_base_dev = base_dev = resolve_device (d, true);
617 acc_dev = &base_dev[goacc_device_num];
618
619 gomp_mutex_lock (&acc_dev->lock);
620 if (acc_dev->state == GOMP_DEVICE_UNINITIALIZED)
621 gomp_init_device (acc_dev);
622 gomp_mutex_unlock (&acc_dev->lock);
623
624 gomp_mutex_unlock (&acc_device_lock);
625
626 /* We're changing device type: invalidate the current thread's dev and
627 base_dev pointers. */
628 if (thr && thr->base_dev != base_dev)
629 {
630 thr->base_dev = thr->dev = NULL;
631 if (thr->mapped_data)
632 gomp_fatal ("acc_set_device_type in 'acc data' region");
633 }
634
635 goacc_attach_host_thread_to_device (-1);
636
637 if (profiling_p)
638 {
639 thr->prof_info = NULL;
640 thr->api_info = NULL;
641 }
642 }
643
644 ialias (acc_set_device_type)
645
646 acc_device_t
647 acc_get_device_type (void)
648 {
649 acc_device_t res = acc_device_none;
650 struct gomp_device_descr *dev;
651 struct goacc_thread *thr = goacc_thread ();
652
653 if (thr && thr->base_dev)
654 res = acc_device_type (thr->base_dev->type);
655 else
656 {
657 acc_prof_info prof_info;
658 acc_api_info api_info;
659 bool profiling_p = GOACC_PROFILING_SETUP_P (thr, &prof_info, &api_info);
660
661 gomp_init_targets_once ();
662
663 gomp_mutex_lock (&acc_device_lock);
664 dev = resolve_device (acc_device_default, true);
665 gomp_mutex_unlock (&acc_device_lock);
666 res = acc_device_type (dev->type);
667
668 if (profiling_p)
669 {
670 thr->prof_info = NULL;
671 thr->api_info = NULL;
672 }
673 }
674
675 assert (res != acc_device_default
676 && res != acc_device_not_host
677 && res != acc_device_current);
678
679 return res;
680 }
681
682 ialias (acc_get_device_type)
683
684 int
685 acc_get_device_num (acc_device_t d)
686 {
687 if (!known_device_type_p (d))
688 unknown_device_type_error (d);
689
690 const struct gomp_device_descr *dev;
691 struct goacc_thread *thr = goacc_thread ();
692
693 acc_prof_info prof_info;
694 acc_api_info api_info;
695 bool profiling_p = GOACC_PROFILING_SETUP_P (thr, &prof_info, &api_info);
696 if (profiling_p)
697 prof_info.device_type = d;
698
699 gomp_init_targets_once ();
700
701 gomp_mutex_lock (&acc_device_lock);
702 dev = resolve_device (d, true);
703 gomp_mutex_unlock (&acc_device_lock);
704
705 if (profiling_p)
706 {
707 thr->prof_info = NULL;
708 thr->api_info = NULL;
709 }
710
711 if (thr && thr->base_dev == dev && thr->dev)
712 return thr->dev->target_id;
713
714 return goacc_device_num;
715 }
716
717 ialias (acc_get_device_num)
718
719 void
720 acc_set_device_num (int ord, acc_device_t d)
721 {
722 if (!known_device_type_p (d))
723 unknown_device_type_error (d);
724
725 struct gomp_device_descr *base_dev, *acc_dev;
726 int num_devices;
727
728 gomp_init_targets_once ();
729
730 if (ord < 0)
731 ord = goacc_device_num;
732
733 if ((int) d == 0)
734 /* Set whatever device is being used by the current host thread to use
735 device instance ORD. It's unclear if this is supposed to affect other
736 host threads too (OpenACC 2.0 (3.2.4) acc_set_device_num). */
737 goacc_attach_host_thread_to_device (ord);
738 else
739 {
740 gomp_mutex_lock (&acc_device_lock);
741
742 cached_base_dev = base_dev = resolve_device (d, true);
743
744 num_devices = base_dev->get_num_devices_func ();
745
746 if (num_devices <= 0 || ord >= num_devices)
747 acc_dev_num_out_of_range (d, ord, num_devices);
748
749 acc_dev = &base_dev[ord];
750
751 gomp_mutex_lock (&acc_dev->lock);
752 if (acc_dev->state == GOMP_DEVICE_UNINITIALIZED)
753 gomp_init_device (acc_dev);
754 gomp_mutex_unlock (&acc_dev->lock);
755
756 gomp_mutex_unlock (&acc_device_lock);
757
758 goacc_attach_host_thread_to_device (ord);
759 }
760
761 goacc_device_num = ord;
762 }
763
764 ialias (acc_set_device_num)
765
766 static union goacc_property_value
767 get_property_any (int ord, acc_device_t d, acc_device_property_t prop)
768 {
769 goacc_lazy_initialize ();
770 struct goacc_thread *thr = goacc_thread ();
771
772 if (d == acc_device_current && thr && thr->dev)
773 return thr->dev->openacc.get_property_func (thr->dev->target_id, prop);
774
775 gomp_mutex_lock (&acc_device_lock);
776
777 struct gomp_device_descr *dev = resolve_device (d, true);
778
779 int num_devices = dev->get_num_devices_func ();
780
781 if (num_devices <= 0 || ord >= num_devices)
782 acc_dev_num_out_of_range (d, ord, num_devices);
783
784 dev += ord;
785
786 gomp_mutex_lock (&dev->lock);
787 if (dev->state == GOMP_DEVICE_UNINITIALIZED)
788 gomp_init_device (dev);
789 gomp_mutex_unlock (&dev->lock);
790
791 gomp_mutex_unlock (&acc_device_lock);
792
793 assert (dev);
794
795 return dev->openacc.get_property_func (dev->target_id, prop);
796 }
797
798 size_t
799 acc_get_property (int ord, acc_device_t d, acc_device_property_t prop)
800 {
801 if (!known_device_type_p (d))
802 unknown_device_type_error(d);
803
804 if (prop & GOACC_PROPERTY_STRING_MASK)
805 return 0;
806 else
807 return get_property_any (ord, d, prop).val;
808 }
809
810 ialias (acc_get_property)
811
812 const char *
813 acc_get_property_string (int ord, acc_device_t d, acc_device_property_t prop)
814 {
815 if (!known_device_type_p (d))
816 unknown_device_type_error(d);
817
818 if (prop & GOACC_PROPERTY_STRING_MASK)
819 return get_property_any (ord, d, prop).ptr;
820 else
821 return NULL;
822 }
823
824 ialias (acc_get_property_string)
825
826 /* For -O and higher, the compiler always attempts to expand acc_on_device, but
827 if the user disables the builtin, or calls it via a pointer, we'll need this
828 version.
829
830 Compile this with optimization, so that the compiler expands
831 this, rather than generating infinitely recursive code.
832
833 The function just forwards its argument to __builtin_acc_on_device. It does
834 not verify that the argument is a valid acc_device_t enumeration value. */
835
836 int __attribute__ ((__optimize__ ("O2")))
837 acc_on_device (acc_device_t dev)
838 {
839 return __builtin_acc_on_device (dev);
840 }
841
842 ialias (acc_on_device)
843
844 attribute_hidden void
845 goacc_runtime_initialize (void)
846 {
847 gomp_mutex_init (&acc_device_lock);
848
849 #if !(defined HAVE_TLS || defined USE_EMUTLS)
850 pthread_key_create (&goacc_tls_key, NULL);
851 #endif
852
853 pthread_key_create (&goacc_cleanup_key, goacc_destroy_thread);
854
855 cached_base_dev = NULL;
856
857 goacc_threads = NULL;
858 gomp_mutex_init (&goacc_thread_lock);
859
860 /* Initialize and register the 'host' device type. */
861 goacc_host_init ();
862 }
863
864 static void __attribute__((destructor))
865 goacc_runtime_deinitialize (void)
866 {
867 #if !(defined HAVE_TLS || defined USE_EMUTLS)
868 pthread_key_delete (goacc_tls_key);
869 #endif
870 pthread_key_delete (goacc_cleanup_key);
871 }
872
873 /* Compiler helper functions */
874
875 attribute_hidden void
876 goacc_save_and_set_bind (acc_device_t d)
877 {
878 struct goacc_thread *thr = goacc_thread ();
879
880 assert (!thr->saved_bound_dev);
881
882 thr->saved_bound_dev = thr->dev;
883 thr->dev = dispatchers[d];
884 }
885
886 attribute_hidden void
887 goacc_restore_bind (void)
888 {
889 struct goacc_thread *thr = goacc_thread ();
890
891 thr->dev = thr->saved_bound_dev;
892 thr->saved_bound_dev = NULL;
893 }
894
895 /* This is called from any OpenACC support function that may need to implicitly
896 initialize the libgomp runtime, either globally or from a new host thread.
897 On exit "goacc_thread" will return a valid & populated thread block. */
898
899 attribute_hidden void
900 goacc_lazy_initialize (void)
901 {
902 struct goacc_thread *thr = goacc_thread ();
903
904 if (thr && thr->dev)
905 return;
906
907 gomp_init_targets_once ();
908
909 gomp_mutex_lock (&acc_device_lock);
910 if (!cached_base_dev)
911 cached_base_dev = acc_init_1 (acc_device_default,
912 acc_construct_parallel, 1);
913 gomp_mutex_unlock (&acc_device_lock);
914
915 goacc_attach_host_thread_to_device (-1);
916 }