openacc: Fortran derived-type mapping fix
[platform/upstream/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 }