xref: /netbsd-src/external/gpl3/gcc.old/dist/libgomp/oacc-parallel.c (revision 8feb0f0b7eaff0608f8350bbfa3098827b4bb91b)
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 
53 static void
handle_ftn_pointers(size_t mapnum,void ** hostaddrs,size_t * sizes,unsigned short * kinds)54 handle_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 
101 void
GOACC_parallel_keyed(int flags_m,void (* fn)(void *),size_t mapnum,void ** hostaddrs,size_t * sizes,unsigned short * kinds,...)102 GOACC_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 
354 void
GOACC_parallel(int flags_m,void (* fn)(void *),size_t mapnum,void ** hostaddrs,size_t * sizes,unsigned short * kinds,int num_gangs,int num_workers,int vector_length,int async,int num_waits,...)355 GOACC_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 
366 void
GOACC_data_start(int flags_m,size_t mapnum,void ** hostaddrs,size_t * sizes,unsigned short * kinds)367 GOACC_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 
486 void
GOACC_data_end(void)487 GOACC_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 
559 void
GOACC_update(int flags_m,size_t mapnum,void ** hostaddrs,size_t * sizes,unsigned short * kinds,int async,int num_waits,...)560 GOACC_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 
718 int
GOACC_get_num_threads(void)719 GOACC_get_num_threads (void)
720 {
721   return 1;
722 }
723 
724 /* Legacy entry point (GCC 5).  */
725 
726 int
GOACC_get_thread_num(void)727 GOACC_get_thread_num (void)
728 {
729   return 0;
730 }
731 
732 void
GOACC_declare(int flags_m,size_t mapnum,void ** hostaddrs,size_t * sizes,unsigned short * kinds)733 GOACC_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