1/* Copyright (C) 2013-2020 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 "gomp-constants.h"
32#include "oacc-int.h"
33#ifdef HAVE_INTTYPES_H
34# include <inttypes.h>  /* For PRIu64.  */
35#endif
36#include <string.h>
37#include <stdarg.h>
38#include <assert.h>
39
40
41/* In the ABI, the GOACC_FLAGs are encoded as an inverted bitmask, so that we
42   continue to support the following two legacy values.  */
43_Static_assert (GOACC_FLAGS_UNMARSHAL (GOMP_DEVICE_ICV) == 0,
44		"legacy GOMP_DEVICE_ICV broken");
45_Static_assert (GOACC_FLAGS_UNMARSHAL (GOMP_DEVICE_HOST_FALLBACK)
46		== GOACC_FLAG_HOST_FALLBACK,
47		"legacy GOMP_DEVICE_HOST_FALLBACK broken");
48
49
50/* Handle the mapping pair that are presented when a
51   deviceptr clause is used with Fortran.  */
52
53static void
54handle_ftn_pointers (size_t mapnum, void **hostaddrs, size_t *sizes,
55		     unsigned short *kinds)
56{
57  int i;
58
59  for (i = 0; i < mapnum; i++)
60    {
61      unsigned short kind1 = kinds[i] & 0xff;
62
63      /* Handle Fortran deviceptr clause.  */
64      if (kind1 == GOMP_MAP_FORCE_DEVICEPTR)
65	{
66	  unsigned short kind2;
67
68	  if (i < (signed)mapnum - 1)
69	    kind2 = kinds[i + 1] & 0xff;
70	  else
71	    kind2 = 0xffff;
72
73	  if (sizes[i] == sizeof (void *))
74	    continue;
75
76	  /* At this point, we're dealing with a Fortran deviceptr.
77	     If the next element is not what we're expecting, then
78	     this is an instance of where the deviceptr variable was
79	     not used within the region and the pointer was removed
80	     by the gimplifier.  */
81	  if (kind2 == GOMP_MAP_POINTER
82	      && sizes[i + 1] == 0
83	      && hostaddrs[i] == *(void **)hostaddrs[i + 1])
84	    {
85	      kinds[i+1] = kinds[i];
86	      sizes[i+1] = sizeof (void *);
87	    }
88
89	  /* Invalidate the entry.  */
90	  hostaddrs[i] = NULL;
91	}
92    }
93}
94
95
96/* Launch a possibly offloaded function with FLAGS.  FN is the host fn
97   address.  MAPNUM, HOSTADDRS, SIZES & KINDS  describe the memory
98   blocks to be copied to/from the device.  Varadic arguments are
99   keyed optional parameters terminated with a zero.  */
100
101void
102GOACC_parallel_keyed (int flags_m, void (*fn) (void *),
103		      size_t mapnum, void **hostaddrs, size_t *sizes,
104		      unsigned short *kinds, ...)
105{
106  int flags = GOACC_FLAGS_UNMARSHAL (flags_m);
107
108  va_list ap;
109  struct goacc_thread *thr;
110  struct gomp_device_descr *acc_dev;
111  struct target_mem_desc *tgt;
112  void **devaddrs;
113  unsigned int i;
114  struct splay_tree_key_s k;
115  splay_tree_key tgt_fn_key;
116  void (*tgt_fn);
117  int async = GOMP_ASYNC_SYNC;
118  unsigned dims[GOMP_DIM_MAX];
119  unsigned tag;
120
121#ifdef HAVE_INTTYPES_H
122  gomp_debug (0, "%s: mapnum=%"PRIu64", hostaddrs=%p, size=%p, kinds=%p\n",
123	      __FUNCTION__, (uint64_t) mapnum, hostaddrs, sizes, kinds);
124#else
125  gomp_debug (0, "%s: mapnum=%lu, hostaddrs=%p, sizes=%p, kinds=%p\n",
126	      __FUNCTION__, (unsigned long) mapnum, hostaddrs, sizes, kinds);
127#endif
128  goacc_lazy_initialize ();
129
130  thr = goacc_thread ();
131  acc_dev = thr->dev;
132
133  bool profiling_p = GOACC_PROFILING_DISPATCH_P (true);
134
135  acc_prof_info prof_info;
136  if (profiling_p)
137    {
138      thr->prof_info = &prof_info;
139
140      prof_info.event_type = acc_ev_compute_construct_start;
141      prof_info.valid_bytes = _ACC_PROF_INFO_VALID_BYTES;
142      prof_info.version = _ACC_PROF_INFO_VERSION;
143      prof_info.device_type = acc_device_type (acc_dev->type);
144      prof_info.device_number = acc_dev->target_id;
145      prof_info.thread_id = -1;
146      prof_info.async = async;
147      prof_info.async_queue = prof_info.async;
148      prof_info.src_file = NULL;
149      prof_info.func_name = NULL;
150      prof_info.line_no = -1;
151      prof_info.end_line_no = -1;
152      prof_info.func_line_no = -1;
153      prof_info.func_end_line_no = -1;
154    }
155  acc_event_info compute_construct_event_info;
156  if (profiling_p)
157    {
158      compute_construct_event_info.other_event.event_type
159	= prof_info.event_type;
160      compute_construct_event_info.other_event.valid_bytes
161	= _ACC_OTHER_EVENT_INFO_VALID_BYTES;
162      compute_construct_event_info.other_event.parent_construct
163	= acc_construct_parallel;
164      compute_construct_event_info.other_event.implicit = 0;
165      compute_construct_event_info.other_event.tool_info = NULL;
166    }
167  acc_api_info api_info;
168  if (profiling_p)
169    {
170      thr->api_info = &api_info;
171
172      api_info.device_api = acc_device_api_none;
173      api_info.valid_bytes = _ACC_API_INFO_VALID_BYTES;
174      api_info.device_type = prof_info.device_type;
175      api_info.vendor = -1;
176      api_info.device_handle = NULL;
177      api_info.context_handle = NULL;
178      api_info.async_handle = NULL;
179    }
180
181  if (profiling_p)
182    goacc_profiling_dispatch (&prof_info, &compute_construct_event_info,
183			      &api_info);
184
185  handle_ftn_pointers (mapnum, hostaddrs, sizes, kinds);
186
187  /* Host fallback if "if" clause is false or if the current device is set to
188     the host.  */
189  if (flags & GOACC_FLAG_HOST_FALLBACK)
190    {
191      prof_info.device_type = acc_device_host;
192      api_info.device_type = prof_info.device_type;
193      goacc_save_and_set_bind (acc_device_host);
194      fn (hostaddrs);
195      goacc_restore_bind ();
196      goto out_prof;
197    }
198  else if (acc_device_type (acc_dev->type) == acc_device_host)
199    {
200      fn (hostaddrs);
201      goto out_prof;
202    }
203
204  /* Default: let the runtime choose.  */
205  for (i = 0; i != GOMP_DIM_MAX; i++)
206    dims[i] = 0;
207
208  va_start (ap, kinds);
209  /* TODO: This will need amending when device_type is implemented.  */
210  while ((tag = va_arg (ap, unsigned)) != 0)
211    {
212      if (GOMP_LAUNCH_DEVICE (tag))
213	gomp_fatal ("device_type '%d' offload parameters, libgomp is too old",
214		    GOMP_LAUNCH_DEVICE (tag));
215
216      switch (GOMP_LAUNCH_CODE (tag))
217	{
218	case GOMP_LAUNCH_DIM:
219	  {
220	    unsigned mask = GOMP_LAUNCH_OP (tag);
221
222	    for (i = 0; i != GOMP_DIM_MAX; i++)
223	      if (mask & GOMP_DIM_MASK (i))
224		dims[i] = va_arg (ap, unsigned);
225	  }
226	  break;
227
228	case GOMP_LAUNCH_ASYNC:
229	  {
230	    /* Small constant values are encoded in the operand.  */
231	    async = GOMP_LAUNCH_OP (tag);
232
233	    if (async == GOMP_LAUNCH_OP_MAX)
234	      async = va_arg (ap, unsigned);
235
236	    if (profiling_p)
237	      {
238		prof_info.async = async;
239		prof_info.async_queue = prof_info.async;
240	      }
241
242	    break;
243	  }
244
245	case GOMP_LAUNCH_WAIT:
246	  {
247	    unsigned num_waits = GOMP_LAUNCH_OP (tag);
248	    goacc_wait (async, num_waits, &ap);
249	    break;
250	  }
251
252	default:
253	  gomp_fatal ("unrecognized offload code '%d',"
254		      " libgomp is too old", GOMP_LAUNCH_CODE (tag));
255	}
256    }
257  va_end (ap);
258
259  if (!(acc_dev->capabilities & GOMP_OFFLOAD_CAP_NATIVE_EXEC))
260    {
261      k.host_start = (uintptr_t) fn;
262      k.host_end = k.host_start + 1;
263      gomp_mutex_lock (&acc_dev->lock);
264      tgt_fn_key = splay_tree_lookup (&acc_dev->mem_map, &k);
265      gomp_mutex_unlock (&acc_dev->lock);
266
267      if (tgt_fn_key == NULL)
268	gomp_fatal ("target function wasn't mapped");
269
270      tgt_fn = (void (*)) tgt_fn_key->tgt_offset;
271    }
272  else
273    tgt_fn = (void (*)) fn;
274
275  acc_event_info enter_exit_data_event_info;
276  if (profiling_p)
277    {
278      prof_info.event_type = acc_ev_enter_data_start;
279      enter_exit_data_event_info.other_event.event_type
280	= prof_info.event_type;
281      enter_exit_data_event_info.other_event.valid_bytes
282	= _ACC_OTHER_EVENT_INFO_VALID_BYTES;
283      enter_exit_data_event_info.other_event.parent_construct
284	= compute_construct_event_info.other_event.parent_construct;
285      enter_exit_data_event_info.other_event.implicit = 1;
286      enter_exit_data_event_info.other_event.tool_info = NULL;
287      goacc_profiling_dispatch (&prof_info, &enter_exit_data_event_info,
288				&api_info);
289    }
290
291  goacc_aq aq = get_goacc_asyncqueue (async);
292
293  tgt = gomp_map_vars_async (acc_dev, aq, mapnum, hostaddrs, NULL, sizes, kinds,
294			     true, GOMP_MAP_VARS_OPENACC);
295  if (profiling_p)
296    {
297      prof_info.event_type = acc_ev_enter_data_end;
298      enter_exit_data_event_info.other_event.event_type
299	= prof_info.event_type;
300      goacc_profiling_dispatch (&prof_info, &enter_exit_data_event_info,
301				&api_info);
302    }
303
304  devaddrs = gomp_alloca (sizeof (void *) * mapnum);
305  for (i = 0; i < mapnum; i++)
306    devaddrs[i] = (void *) gomp_map_val (tgt, hostaddrs, i);
307
308  if (aq == NULL)
309    acc_dev->openacc.exec_func (tgt_fn, mapnum, hostaddrs, devaddrs, dims,
310				tgt);
311  else
312    acc_dev->openacc.async.exec_func (tgt_fn, mapnum, hostaddrs, devaddrs,
313				      dims, tgt, aq);
314
315  if (profiling_p)
316    {
317      prof_info.event_type = acc_ev_exit_data_start;
318      enter_exit_data_event_info.other_event.event_type = prof_info.event_type;
319      enter_exit_data_event_info.other_event.tool_info = NULL;
320      goacc_profiling_dispatch (&prof_info, &enter_exit_data_event_info,
321				&api_info);
322    }
323
324  /* If running synchronously, unmap immediately.  */
325  if (aq == NULL)
326    gomp_unmap_vars (tgt, true);
327  else
328    gomp_unmap_vars_async (tgt, true, aq);
329
330  if (profiling_p)
331    {
332      prof_info.event_type = acc_ev_exit_data_end;
333      enter_exit_data_event_info.other_event.event_type = prof_info.event_type;
334      goacc_profiling_dispatch (&prof_info, &enter_exit_data_event_info,
335				&api_info);
336    }
337
338 out_prof:
339  if (profiling_p)
340    {
341      prof_info.event_type = acc_ev_compute_construct_end;
342      compute_construct_event_info.other_event.event_type
343	= prof_info.event_type;
344      goacc_profiling_dispatch (&prof_info, &compute_construct_event_info,
345				&api_info);
346
347      thr->prof_info = NULL;
348      thr->api_info = NULL;
349    }
350}
351
352/* Legacy entry point (GCC 5).  Only provide host fallback execution.  */
353
354void
355GOACC_parallel (int flags_m, void (*fn) (void *),
356		size_t mapnum, void **hostaddrs, size_t *sizes,
357		unsigned short *kinds,
358		int num_gangs, int num_workers, int vector_length,
359		int async, int num_waits, ...)
360{
361  goacc_save_and_set_bind (acc_device_host);
362  fn (hostaddrs);
363  goacc_restore_bind ();
364}
365
366void
367GOACC_data_start (int flags_m, size_t mapnum,
368		  void **hostaddrs, size_t *sizes, unsigned short *kinds)
369{
370  int flags = GOACC_FLAGS_UNMARSHAL (flags_m);
371
372  struct target_mem_desc *tgt;
373
374#ifdef HAVE_INTTYPES_H
375  gomp_debug (0, "%s: mapnum=%"PRIu64", hostaddrs=%p, size=%p, kinds=%p\n",
376	      __FUNCTION__, (uint64_t) mapnum, hostaddrs, sizes, kinds);
377#else
378  gomp_debug (0, "%s: mapnum=%lu, hostaddrs=%p, sizes=%p, kinds=%p\n",
379	      __FUNCTION__, (unsigned long) mapnum, hostaddrs, sizes, kinds);
380#endif
381
382  goacc_lazy_initialize ();
383
384  struct goacc_thread *thr = goacc_thread ();
385  struct gomp_device_descr *acc_dev = thr->dev;
386
387  bool profiling_p = GOACC_PROFILING_DISPATCH_P (true);
388
389  acc_prof_info prof_info;
390  if (profiling_p)
391    {
392      thr->prof_info = &prof_info;
393
394      prof_info.event_type = acc_ev_enter_data_start;
395      prof_info.valid_bytes = _ACC_PROF_INFO_VALID_BYTES;
396      prof_info.version = _ACC_PROF_INFO_VERSION;
397      prof_info.device_type = acc_device_type (acc_dev->type);
398      prof_info.device_number = acc_dev->target_id;
399      prof_info.thread_id = -1;
400      prof_info.async = acc_async_sync; /* Always synchronous.  */
401      prof_info.async_queue = prof_info.async;
402      prof_info.src_file = NULL;
403      prof_info.func_name = NULL;
404      prof_info.line_no = -1;
405      prof_info.end_line_no = -1;
406      prof_info.func_line_no = -1;
407      prof_info.func_end_line_no = -1;
408    }
409  acc_event_info enter_data_event_info;
410  if (profiling_p)
411    {
412      enter_data_event_info.other_event.event_type
413	= prof_info.event_type;
414      enter_data_event_info.other_event.valid_bytes
415	= _ACC_OTHER_EVENT_INFO_VALID_BYTES;
416      enter_data_event_info.other_event.parent_construct = acc_construct_data;
417      for (int i = 0; i < mapnum; ++i)
418	if ((kinds[i] & 0xff) == GOMP_MAP_USE_DEVICE_PTR
419	    || (kinds[i] & 0xff) == GOMP_MAP_USE_DEVICE_PTR_IF_PRESENT)
420	  {
421	    /* If there is one such data mapping kind, then this is actually an
422	       OpenACC 'host_data' construct.  (GCC maps the OpenACC
423	       'host_data' construct to the OpenACC 'data' construct.)  Apart
424	       from artificial test cases (such as an OpenACC 'host_data'
425	       construct's (implicit) device initialization when there hasn't
426	       been any device data be set up before...), there can't really
427	       any meaningful events be generated from OpenACC 'host_data'
428	       constructs, though.  */
429	    enter_data_event_info.other_event.parent_construct
430	      = acc_construct_host_data;
431	    break;
432	  }
433      enter_data_event_info.other_event.implicit = 0;
434      enter_data_event_info.other_event.tool_info = NULL;
435    }
436  acc_api_info api_info;
437  if (profiling_p)
438    {
439      thr->api_info = &api_info;
440
441      api_info.device_api = acc_device_api_none;
442      api_info.valid_bytes = _ACC_API_INFO_VALID_BYTES;
443      api_info.device_type = prof_info.device_type;
444      api_info.vendor = -1;
445      api_info.device_handle = NULL;
446      api_info.context_handle = NULL;
447      api_info.async_handle = NULL;
448    }
449
450  if (profiling_p)
451    goacc_profiling_dispatch (&prof_info, &enter_data_event_info, &api_info);
452
453  /* Host fallback or 'do nothing'.  */
454  if ((acc_dev->capabilities & GOMP_OFFLOAD_CAP_SHARED_MEM)
455      || (flags & GOACC_FLAG_HOST_FALLBACK))
456    {
457      prof_info.device_type = acc_device_host;
458      api_info.device_type = prof_info.device_type;
459      tgt = gomp_map_vars (NULL, 0, NULL, NULL, NULL, NULL, true,
460			   GOMP_MAP_VARS_OPENACC);
461      tgt->prev = thr->mapped_data;
462      thr->mapped_data = tgt;
463
464      goto out_prof;
465    }
466
467  gomp_debug (0, "  %s: prepare mappings\n", __FUNCTION__);
468  tgt = gomp_map_vars (acc_dev, mapnum, hostaddrs, NULL, sizes, kinds, true,
469		       GOMP_MAP_VARS_OPENACC);
470  gomp_debug (0, "  %s: mappings prepared\n", __FUNCTION__);
471  tgt->prev = thr->mapped_data;
472  thr->mapped_data = tgt;
473
474 out_prof:
475  if (profiling_p)
476    {
477      prof_info.event_type = acc_ev_enter_data_end;
478      enter_data_event_info.other_event.event_type = prof_info.event_type;
479      goacc_profiling_dispatch (&prof_info, &enter_data_event_info, &api_info);
480
481      thr->prof_info = NULL;
482      thr->api_info = NULL;
483    }
484}
485
486void
487GOACC_data_end (void)
488{
489  struct goacc_thread *thr = goacc_thread ();
490  struct gomp_device_descr *acc_dev = thr->dev;
491  struct target_mem_desc *tgt = thr->mapped_data;
492
493  bool profiling_p = GOACC_PROFILING_DISPATCH_P (true);
494
495  acc_prof_info prof_info;
496  if (profiling_p)
497    {
498      thr->prof_info = &prof_info;
499
500      prof_info.event_type = acc_ev_exit_data_start;
501      prof_info.valid_bytes = _ACC_PROF_INFO_VALID_BYTES;
502      prof_info.version = _ACC_PROF_INFO_VERSION;
503      prof_info.device_type = acc_device_type (acc_dev->type);
504      prof_info.device_number = acc_dev->target_id;
505      prof_info.thread_id = -1;
506      prof_info.async = acc_async_sync; /* Always synchronous.  */
507      prof_info.async_queue = prof_info.async;
508      prof_info.src_file = NULL;
509      prof_info.func_name = NULL;
510      prof_info.line_no = -1;
511      prof_info.end_line_no = -1;
512      prof_info.func_line_no = -1;
513      prof_info.func_end_line_no = -1;
514    }
515  acc_event_info exit_data_event_info;
516  if (profiling_p)
517    {
518      exit_data_event_info.other_event.event_type
519	= prof_info.event_type;
520      exit_data_event_info.other_event.valid_bytes
521	= _ACC_OTHER_EVENT_INFO_VALID_BYTES;
522      exit_data_event_info.other_event.parent_construct = acc_construct_data;
523      exit_data_event_info.other_event.implicit = 0;
524      exit_data_event_info.other_event.tool_info = NULL;
525    }
526  acc_api_info api_info;
527  if (profiling_p)
528    {
529      thr->api_info = &api_info;
530
531      api_info.device_api = acc_device_api_none;
532      api_info.valid_bytes = _ACC_API_INFO_VALID_BYTES;
533      api_info.device_type = prof_info.device_type;
534      api_info.vendor = -1;
535      api_info.device_handle = NULL;
536      api_info.context_handle = NULL;
537      api_info.async_handle = NULL;
538    }
539
540  if (profiling_p)
541    goacc_profiling_dispatch (&prof_info, &exit_data_event_info, &api_info);
542
543  gomp_debug (0, "  %s: restore mappings\n", __FUNCTION__);
544  thr->mapped_data = tgt->prev;
545  gomp_unmap_vars (tgt, true);
546  gomp_debug (0, "  %s: mappings restored\n", __FUNCTION__);
547
548  if (profiling_p)
549    {
550      prof_info.event_type = acc_ev_exit_data_end;
551      exit_data_event_info.other_event.event_type = prof_info.event_type;
552      goacc_profiling_dispatch (&prof_info, &exit_data_event_info, &api_info);
553
554      thr->prof_info = NULL;
555      thr->api_info = NULL;
556    }
557}
558
559void
560GOACC_update (int flags_m, size_t mapnum,
561	      void **hostaddrs, size_t *sizes, unsigned short *kinds,
562	      int async, int num_waits, ...)
563{
564  int flags = GOACC_FLAGS_UNMARSHAL (flags_m);
565
566  size_t i;
567
568  goacc_lazy_initialize ();
569
570  struct goacc_thread *thr = goacc_thread ();
571  struct gomp_device_descr *acc_dev = thr->dev;
572
573  bool profiling_p = GOACC_PROFILING_DISPATCH_P (true);
574
575  acc_prof_info prof_info;
576  if (profiling_p)
577    {
578      thr->prof_info = &prof_info;
579
580      prof_info.event_type = acc_ev_update_start;
581      prof_info.valid_bytes = _ACC_PROF_INFO_VALID_BYTES;
582      prof_info.version = _ACC_PROF_INFO_VERSION;
583      prof_info.device_type = acc_device_type (acc_dev->type);
584      prof_info.device_number = acc_dev->target_id;
585      prof_info.thread_id = -1;
586      prof_info.async = async;
587      prof_info.async_queue = prof_info.async;
588      prof_info.src_file = NULL;
589      prof_info.func_name = NULL;
590      prof_info.line_no = -1;
591      prof_info.end_line_no = -1;
592      prof_info.func_line_no = -1;
593      prof_info.func_end_line_no = -1;
594    }
595  acc_event_info update_event_info;
596  if (profiling_p)
597    {
598      update_event_info.other_event.event_type
599	= prof_info.event_type;
600      update_event_info.other_event.valid_bytes
601	= _ACC_OTHER_EVENT_INFO_VALID_BYTES;
602      update_event_info.other_event.parent_construct = acc_construct_update;
603      update_event_info.other_event.implicit = 0;
604      update_event_info.other_event.tool_info = NULL;
605    }
606  acc_api_info api_info;
607  if (profiling_p)
608    {
609      thr->api_info = &api_info;
610
611      api_info.device_api = acc_device_api_none;
612      api_info.valid_bytes = _ACC_API_INFO_VALID_BYTES;
613      api_info.device_type = prof_info.device_type;
614      api_info.vendor = -1;
615      api_info.device_handle = NULL;
616      api_info.context_handle = NULL;
617      api_info.async_handle = NULL;
618    }
619
620  if (profiling_p)
621    goacc_profiling_dispatch (&prof_info, &update_event_info, &api_info);
622
623  if ((acc_dev->capabilities & GOMP_OFFLOAD_CAP_SHARED_MEM)
624      || (flags & GOACC_FLAG_HOST_FALLBACK))
625    {
626      prof_info.device_type = acc_device_host;
627      api_info.device_type = prof_info.device_type;
628
629      goto out_prof;
630    }
631
632  if (num_waits)
633    {
634      va_list ap;
635
636      va_start (ap, num_waits);
637      goacc_wait (async, num_waits, &ap);
638      va_end (ap);
639    }
640
641  bool update_device = false;
642  for (i = 0; i < mapnum; ++i)
643    {
644      unsigned char kind = kinds[i] & 0xff;
645
646      switch (kind)
647	{
648	case GOMP_MAP_POINTER:
649	case GOMP_MAP_TO_PSET:
650	  break;
651
652	case GOMP_MAP_ALWAYS_POINTER:
653	  if (update_device)
654	    {
655	      /* Save the contents of the host pointer.  */
656	      void *dptr = acc_deviceptr (hostaddrs[i-1]);
657	      uintptr_t t = *(uintptr_t *) hostaddrs[i];
658
659	      /* Update the contents of the host pointer to reflect
660		 the value of the allocated device memory in the
661		 previous pointer.  */
662	      *(uintptr_t *) hostaddrs[i] = (uintptr_t)dptr;
663	      /* TODO: verify that we really cannot use acc_update_device_async
664		 here.  */
665	      acc_update_device (hostaddrs[i], sizeof (uintptr_t));
666
667	      /* Restore the host pointer.  */
668	      *(uintptr_t *) hostaddrs[i] = t;
669	      update_device = false;
670	    }
671	  break;
672
673	case GOMP_MAP_TO:
674	  if (!acc_is_present (hostaddrs[i], sizes[i]))
675	    {
676	      update_device = false;
677	      break;
678	    }
679	  /* Fallthru  */
680	case GOMP_MAP_FORCE_TO:
681	  update_device = true;
682	  acc_update_device_async (hostaddrs[i], sizes[i], async);
683	  break;
684
685	case GOMP_MAP_FROM:
686	  if (!acc_is_present (hostaddrs[i], sizes[i]))
687	    {
688	      update_device = false;
689	      break;
690	    }
691	  /* Fallthru  */
692	case GOMP_MAP_FORCE_FROM:
693	  update_device = false;
694	  acc_update_self_async (hostaddrs[i], sizes[i], async);
695	  break;
696
697	default:
698	  gomp_fatal (">>>> GOACC_update UNHANDLED kind 0x%.2x", kind);
699	  break;
700	}
701    }
702
703 out_prof:
704  if (profiling_p)
705    {
706      prof_info.event_type = acc_ev_update_end;
707      update_event_info.other_event.event_type = prof_info.event_type;
708      goacc_profiling_dispatch (&prof_info, &update_event_info, &api_info);
709
710      thr->prof_info = NULL;
711      thr->api_info = NULL;
712    }
713}
714
715
716/* Legacy entry point (GCC 5).  */
717
718int
719GOACC_get_num_threads (void)
720{
721  return 1;
722}
723
724/* Legacy entry point (GCC 5).  */
725
726int
727GOACC_get_thread_num (void)
728{
729  return 0;
730}
731
732void
733GOACC_declare (int flags_m, size_t mapnum,
734	       void **hostaddrs, size_t *sizes, unsigned short *kinds)
735{
736  int i;
737
738  for (i = 0; i < mapnum; i++)
739    {
740      unsigned char kind = kinds[i] & 0xff;
741
742      if (kind == GOMP_MAP_POINTER || kind == GOMP_MAP_TO_PSET)
743	continue;
744
745      switch (kind)
746	{
747	  case GOMP_MAP_FORCE_ALLOC:
748	  case GOMP_MAP_FORCE_FROM:
749	  case GOMP_MAP_FORCE_TO:
750	  case GOMP_MAP_POINTER:
751	  case GOMP_MAP_RELEASE:
752	  case GOMP_MAP_DELETE:
753	    GOACC_enter_exit_data (flags_m, 1, &hostaddrs[i], &sizes[i],
754				   &kinds[i], GOMP_ASYNC_SYNC, 0);
755	    break;
756
757	  case GOMP_MAP_FORCE_DEVICEPTR:
758	    break;
759
760	  case GOMP_MAP_ALLOC:
761	    if (!acc_is_present (hostaddrs[i], sizes[i]))
762	      GOACC_enter_exit_data (flags_m, 1, &hostaddrs[i], &sizes[i],
763				     &kinds[i], GOMP_ASYNC_SYNC, 0);
764	    break;
765
766	  case GOMP_MAP_TO:
767	    GOACC_enter_exit_data (flags_m, 1, &hostaddrs[i], &sizes[i],
768				   &kinds[i], GOMP_ASYNC_SYNC, 0);
769
770	    break;
771
772	  case GOMP_MAP_FROM:
773	    GOACC_enter_exit_data (flags_m, 1, &hostaddrs[i], &sizes[i],
774				   &kinds[i], GOMP_ASYNC_SYNC, 0);
775	    break;
776
777	  case GOMP_MAP_FORCE_PRESENT:
778	    if (!acc_is_present (hostaddrs[i], sizes[i]))
779	      gomp_fatal ("[%p,%ld] is not mapped", hostaddrs[i],
780			  (unsigned long) sizes[i]);
781	    break;
782
783	  default:
784	    assert (0);
785	    break;
786	}
787    }
788}
789