Home | History | Annotate | Line # | Download | only in libgomp
oacc-parallel.c revision 1.1.1.10
      1 /* Copyright (C) 2013-2024 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
     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
    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   unsigned int i;
    112   struct splay_tree_key_s k;
    113   splay_tree_key tgt_fn_key;
    114   void (*tgt_fn);
    115   int async = GOMP_ASYNC_SYNC;
    116   unsigned dims[GOMP_DIM_MAX];
    117   unsigned tag;
    118 
    119 #ifdef HAVE_INTTYPES_H
    120   gomp_debug (0, "%s: mapnum=%"PRIu64", hostaddrs=%p, size=%p, kinds=%p\n",
    121 	      __FUNCTION__, (uint64_t) mapnum, hostaddrs, sizes, kinds);
    122 #else
    123   gomp_debug (0, "%s: mapnum=%lu, hostaddrs=%p, sizes=%p, kinds=%p\n",
    124 	      __FUNCTION__, (unsigned long) mapnum, hostaddrs, sizes, kinds);
    125 #endif
    126   goacc_lazy_initialize ();
    127 
    128   thr = goacc_thread ();
    129   acc_dev = thr->dev;
    130 
    131   bool profiling_p = GOACC_PROFILING_DISPATCH_P (true);
    132 
    133   acc_prof_info prof_info;
    134   if (profiling_p)
    135     {
    136       thr->prof_info = &prof_info;
    137 
    138       prof_info.event_type = acc_ev_compute_construct_start;
    139       prof_info.valid_bytes = _ACC_PROF_INFO_VALID_BYTES;
    140       prof_info.version = _ACC_PROF_INFO_VERSION;
    141       prof_info.device_type = acc_device_type (acc_dev->type);
    142       prof_info.device_number = acc_dev->target_id;
    143       prof_info.thread_id = -1;
    144       prof_info.async = async;
    145       prof_info.async_queue = prof_info.async;
    146       prof_info.src_file = NULL;
    147       prof_info.func_name = NULL;
    148       prof_info.line_no = -1;
    149       prof_info.end_line_no = -1;
    150       prof_info.func_line_no = -1;
    151       prof_info.func_end_line_no = -1;
    152     }
    153   acc_event_info compute_construct_event_info;
    154   if (profiling_p)
    155     {
    156       compute_construct_event_info.other_event.event_type
    157 	= prof_info.event_type;
    158       compute_construct_event_info.other_event.valid_bytes
    159 	= _ACC_OTHER_EVENT_INFO_VALID_BYTES;
    160       compute_construct_event_info.other_event.parent_construct
    161 	= acc_construct_parallel;
    162       compute_construct_event_info.other_event.implicit = 0;
    163       compute_construct_event_info.other_event.tool_info = NULL;
    164     }
    165   acc_api_info api_info;
    166   if (profiling_p)
    167     {
    168       thr->api_info = &api_info;
    169 
    170       api_info.device_api = acc_device_api_none;
    171       api_info.valid_bytes = _ACC_API_INFO_VALID_BYTES;
    172       api_info.device_type = prof_info.device_type;
    173       api_info.vendor = -1;
    174       api_info.device_handle = NULL;
    175       api_info.context_handle = NULL;
    176       api_info.async_handle = NULL;
    177     }
    178 
    179   if (profiling_p)
    180     goacc_profiling_dispatch (&prof_info, &compute_construct_event_info,
    181 			      &api_info);
    182 
    183   handle_ftn_pointers (mapnum, hostaddrs, sizes, kinds);
    184 
    185   /* Host fallback if "if" clause is false or if the current device is set to
    186      the host.  */
    187   if ((flags & GOACC_FLAG_HOST_FALLBACK)
    188       /* TODO: a proper pthreads based "multi-core CPU" local device
    189 	 implementation. Currently, this is still the same as host-fallback.  */
    190       || (flags & GOACC_FLAG_LOCAL_DEVICE))
    191     {
    192       prof_info.device_type = acc_device_host;
    193       api_info.device_type = prof_info.device_type;
    194       goacc_save_and_set_bind (acc_device_host);
    195       fn (hostaddrs);
    196       goacc_restore_bind ();
    197       goto out_prof;
    198     }
    199   else if (acc_device_type (acc_dev->type) == acc_device_host)
    200     {
    201       fn (hostaddrs);
    202       goto out_prof;
    203     }
    204 
    205   /* Default: let the runtime choose.  */
    206   for (i = 0; i != GOMP_DIM_MAX; i++)
    207     dims[i] = 0;
    208 
    209   va_start (ap, kinds);
    210   /* TODO: This will need amending when device_type is implemented.  */
    211   while ((tag = va_arg (ap, unsigned)) != 0)
    212     {
    213       if (GOMP_LAUNCH_DEVICE (tag))
    214 	gomp_fatal ("device_type '%d' offload parameters, libgomp is too old",
    215 		    GOMP_LAUNCH_DEVICE (tag));
    216 
    217       switch (GOMP_LAUNCH_CODE (tag))
    218 	{
    219 	case GOMP_LAUNCH_DIM:
    220 	  {
    221 	    unsigned mask = GOMP_LAUNCH_OP (tag);
    222 
    223 	    for (i = 0; i != GOMP_DIM_MAX; i++)
    224 	      if (mask & GOMP_DIM_MASK (i))
    225 		dims[i] = va_arg (ap, unsigned);
    226 	  }
    227 	  break;
    228 
    229 	case GOMP_LAUNCH_ASYNC:
    230 	  {
    231 	    /* Small constant values are encoded in the operand.  */
    232 	    async = GOMP_LAUNCH_OP (tag);
    233 
    234 	    if (async == GOMP_LAUNCH_OP_MAX)
    235 	      async = va_arg (ap, unsigned);
    236 
    237 	    if (profiling_p)
    238 	      {
    239 		prof_info.async = async;
    240 		prof_info.async_queue = prof_info.async;
    241 	      }
    242 
    243 	    break;
    244 	  }
    245 
    246 	case GOMP_LAUNCH_WAIT:
    247 	  {
    248 	    unsigned num_waits = GOMP_LAUNCH_OP (tag);
    249 	    goacc_wait (async, num_waits, &ap);
    250 	    break;
    251 	  }
    252 
    253 	default:
    254 	  gomp_fatal ("unrecognized offload code '%d',"
    255 		      " libgomp is too old", GOMP_LAUNCH_CODE (tag));
    256 	}
    257     }
    258   va_end (ap);
    259 
    260   if (!(acc_dev->capabilities & GOMP_OFFLOAD_CAP_NATIVE_EXEC))
    261     {
    262       k.host_start = (uintptr_t) fn;
    263       k.host_end = k.host_start + 1;
    264       gomp_mutex_lock (&acc_dev->lock);
    265       tgt_fn_key = splay_tree_lookup (&acc_dev->mem_map, &k);
    266       gomp_mutex_unlock (&acc_dev->lock);
    267 
    268       if (tgt_fn_key == NULL)
    269 	gomp_fatal ("target function wasn't mapped");
    270 
    271       tgt_fn = (void (*)) tgt_fn_key->tgt_offset;
    272     }
    273   else
    274     tgt_fn = (void (*)) fn;
    275 
    276   acc_event_info enter_exit_data_event_info;
    277   if (profiling_p)
    278     {
    279       prof_info.event_type = acc_ev_enter_data_start;
    280       enter_exit_data_event_info.other_event.event_type
    281 	= prof_info.event_type;
    282       enter_exit_data_event_info.other_event.valid_bytes
    283 	= _ACC_OTHER_EVENT_INFO_VALID_BYTES;
    284       enter_exit_data_event_info.other_event.parent_construct
    285 	= compute_construct_event_info.other_event.parent_construct;
    286       enter_exit_data_event_info.other_event.implicit = 1;
    287       enter_exit_data_event_info.other_event.tool_info = NULL;
    288       goacc_profiling_dispatch (&prof_info, &enter_exit_data_event_info,
    289 				&api_info);
    290     }
    291 
    292   goacc_aq aq = get_goacc_asyncqueue (async);
    293 
    294   struct target_mem_desc *tgt
    295     = goacc_map_vars (acc_dev, aq, mapnum, hostaddrs, NULL, sizes, kinds, true,
    296 		      GOMP_MAP_VARS_TARGET);
    297 
    298   if (profiling_p)
    299     {
    300       prof_info.event_type = acc_ev_enter_data_end;
    301       enter_exit_data_event_info.other_event.event_type
    302 	= prof_info.event_type;
    303       goacc_profiling_dispatch (&prof_info, &enter_exit_data_event_info,
    304 				&api_info);
    305     }
    306 
    307   void **devaddrs = (void **) tgt->tgt_start;
    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 (aq == NULL), this will unmap immediately.  */
    325   goacc_unmap_vars (tgt, true, aq);
    326 
    327   if (profiling_p)
    328     {
    329       prof_info.event_type = acc_ev_exit_data_end;
    330       enter_exit_data_event_info.other_event.event_type = prof_info.event_type;
    331       goacc_profiling_dispatch (&prof_info, &enter_exit_data_event_info,
    332 				&api_info);
    333     }
    334 
    335  out_prof:
    336   if (profiling_p)
    337     {
    338       prof_info.event_type = acc_ev_compute_construct_end;
    339       compute_construct_event_info.other_event.event_type
    340 	= prof_info.event_type;
    341       goacc_profiling_dispatch (&prof_info, &compute_construct_event_info,
    342 				&api_info);
    343 
    344       thr->prof_info = NULL;
    345       thr->api_info = NULL;
    346     }
    347 }
    348 
    349 /* Legacy entry point (GCC 5).  Only provide host fallback execution.  */
    350 
    351 void
    352 GOACC_parallel (int flags_m, void (*fn) (void *),
    353 		size_t mapnum, void **hostaddrs, size_t *sizes,
    354 		unsigned short *kinds,
    355 		int num_gangs, int num_workers, int vector_length,
    356 		int async, int num_waits, ...)
    357 {
    358   goacc_save_and_set_bind (acc_device_host);
    359   fn (hostaddrs);
    360   goacc_restore_bind ();
    361 }
    362 
    363 void
    364 GOACC_data_start (int flags_m, size_t mapnum,
    365 		  void **hostaddrs, size_t *sizes, unsigned short *kinds)
    366 {
    367   int flags = GOACC_FLAGS_UNMARSHAL (flags_m);
    368 
    369   struct target_mem_desc *tgt;
    370 
    371 #ifdef HAVE_INTTYPES_H
    372   gomp_debug (0, "%s: mapnum=%"PRIu64", hostaddrs=%p, size=%p, kinds=%p\n",
    373 	      __FUNCTION__, (uint64_t) mapnum, hostaddrs, sizes, kinds);
    374 #else
    375   gomp_debug (0, "%s: mapnum=%lu, hostaddrs=%p, sizes=%p, kinds=%p\n",
    376 	      __FUNCTION__, (unsigned long) mapnum, hostaddrs, sizes, kinds);
    377 #endif
    378 
    379   goacc_lazy_initialize ();
    380 
    381   struct goacc_thread *thr = goacc_thread ();
    382   struct gomp_device_descr *acc_dev = thr->dev;
    383 
    384   bool profiling_p = GOACC_PROFILING_DISPATCH_P (true);
    385 
    386   acc_prof_info prof_info;
    387   if (profiling_p)
    388     {
    389       thr->prof_info = &prof_info;
    390 
    391       prof_info.event_type = acc_ev_enter_data_start;
    392       prof_info.valid_bytes = _ACC_PROF_INFO_VALID_BYTES;
    393       prof_info.version = _ACC_PROF_INFO_VERSION;
    394       prof_info.device_type = acc_device_type (acc_dev->type);
    395       prof_info.device_number = acc_dev->target_id;
    396       prof_info.thread_id = -1;
    397       prof_info.async = acc_async_sync; /* Always synchronous.  */
    398       prof_info.async_queue = prof_info.async;
    399       prof_info.src_file = NULL;
    400       prof_info.func_name = NULL;
    401       prof_info.line_no = -1;
    402       prof_info.end_line_no = -1;
    403       prof_info.func_line_no = -1;
    404       prof_info.func_end_line_no = -1;
    405     }
    406   acc_event_info enter_data_event_info;
    407   if (profiling_p)
    408     {
    409       enter_data_event_info.other_event.event_type
    410 	= prof_info.event_type;
    411       enter_data_event_info.other_event.valid_bytes
    412 	= _ACC_OTHER_EVENT_INFO_VALID_BYTES;
    413       enter_data_event_info.other_event.parent_construct = acc_construct_data;
    414       for (int i = 0; i < mapnum; ++i)
    415 	if ((kinds[i] & 0xff) == GOMP_MAP_USE_DEVICE_PTR
    416 	    || (kinds[i] & 0xff) == GOMP_MAP_USE_DEVICE_PTR_IF_PRESENT)
    417 	  {
    418 	    /* If there is one such data mapping kind, then this is actually an
    419 	       OpenACC 'host_data' construct.  (GCC maps the OpenACC
    420 	       'host_data' construct to the OpenACC 'data' construct.)  Apart
    421 	       from artificial test cases (such as an OpenACC 'host_data'
    422 	       construct's (implicit) device initialization when there hasn't
    423 	       been any device data be set up before...), there can't really
    424 	       any meaningful events be generated from OpenACC 'host_data'
    425 	       constructs, though.  */
    426 	    enter_data_event_info.other_event.parent_construct
    427 	      = acc_construct_host_data;
    428 	    break;
    429 	  }
    430       enter_data_event_info.other_event.implicit = 0;
    431       enter_data_event_info.other_event.tool_info = NULL;
    432     }
    433   acc_api_info api_info;
    434   if (profiling_p)
    435     {
    436       thr->api_info = &api_info;
    437 
    438       api_info.device_api = acc_device_api_none;
    439       api_info.valid_bytes = _ACC_API_INFO_VALID_BYTES;
    440       api_info.device_type = prof_info.device_type;
    441       api_info.vendor = -1;
    442       api_info.device_handle = NULL;
    443       api_info.context_handle = NULL;
    444       api_info.async_handle = NULL;
    445     }
    446 
    447   if (profiling_p)
    448     goacc_profiling_dispatch (&prof_info, &enter_data_event_info, &api_info);
    449 
    450   /* Host fallback or 'do nothing'.  */
    451   if ((acc_dev->capabilities & GOMP_OFFLOAD_CAP_SHARED_MEM)
    452       || (flags & GOACC_FLAG_HOST_FALLBACK)
    453       || (flags & GOACC_FLAG_LOCAL_DEVICE))
    454     {
    455       prof_info.device_type = acc_device_host;
    456       api_info.device_type = prof_info.device_type;
    457       tgt = goacc_map_vars (NULL, NULL, 0, NULL, NULL, NULL, NULL, true, 0);
    458       tgt->prev = thr->mapped_data;
    459       thr->mapped_data = tgt;
    460 
    461       goto out_prof;
    462     }
    463 
    464   gomp_debug (0, "  %s: prepare mappings\n", __FUNCTION__);
    465   tgt = goacc_map_vars (acc_dev, NULL, mapnum, hostaddrs, NULL, sizes, kinds,
    466 			true, 0);
    467   gomp_debug (0, "  %s: mappings prepared\n", __FUNCTION__);
    468   tgt->prev = thr->mapped_data;
    469   thr->mapped_data = tgt;
    470 
    471  out_prof:
    472   if (profiling_p)
    473     {
    474       prof_info.event_type = acc_ev_enter_data_end;
    475       enter_data_event_info.other_event.event_type = prof_info.event_type;
    476       goacc_profiling_dispatch (&prof_info, &enter_data_event_info, &api_info);
    477 
    478       thr->prof_info = NULL;
    479       thr->api_info = NULL;
    480     }
    481 }
    482 
    483 void
    484 GOACC_data_end (void)
    485 {
    486   struct goacc_thread *thr = goacc_thread ();
    487   struct gomp_device_descr *acc_dev = thr->dev;
    488   struct target_mem_desc *tgt = thr->mapped_data;
    489 
    490   bool profiling_p = GOACC_PROFILING_DISPATCH_P (true);
    491 
    492   acc_prof_info prof_info;
    493   if (profiling_p)
    494     {
    495       thr->prof_info = &prof_info;
    496 
    497       prof_info.event_type = acc_ev_exit_data_start;
    498       prof_info.valid_bytes = _ACC_PROF_INFO_VALID_BYTES;
    499       prof_info.version = _ACC_PROF_INFO_VERSION;
    500       prof_info.device_type = acc_device_type (acc_dev->type);
    501       prof_info.device_number = acc_dev->target_id;
    502       prof_info.thread_id = -1;
    503       prof_info.async = acc_async_sync; /* Always synchronous.  */
    504       prof_info.async_queue = prof_info.async;
    505       prof_info.src_file = NULL;
    506       prof_info.func_name = NULL;
    507       prof_info.line_no = -1;
    508       prof_info.end_line_no = -1;
    509       prof_info.func_line_no = -1;
    510       prof_info.func_end_line_no = -1;
    511     }
    512   acc_event_info exit_data_event_info;
    513   if (profiling_p)
    514     {
    515       exit_data_event_info.other_event.event_type
    516 	= prof_info.event_type;
    517       exit_data_event_info.other_event.valid_bytes
    518 	= _ACC_OTHER_EVENT_INFO_VALID_BYTES;
    519       exit_data_event_info.other_event.parent_construct = acc_construct_data;
    520       exit_data_event_info.other_event.implicit = 0;
    521       exit_data_event_info.other_event.tool_info = NULL;
    522     }
    523   acc_api_info api_info;
    524   if (profiling_p)
    525     {
    526       thr->api_info = &api_info;
    527 
    528       api_info.device_api = acc_device_api_none;
    529       api_info.valid_bytes = _ACC_API_INFO_VALID_BYTES;
    530       api_info.device_type = prof_info.device_type;
    531       api_info.vendor = -1;
    532       api_info.device_handle = NULL;
    533       api_info.context_handle = NULL;
    534       api_info.async_handle = NULL;
    535     }
    536 
    537   if (profiling_p)
    538     goacc_profiling_dispatch (&prof_info, &exit_data_event_info, &api_info);
    539 
    540   gomp_debug (0, "  %s: restore mappings\n", __FUNCTION__);
    541   thr->mapped_data = tgt->prev;
    542   goacc_unmap_vars (tgt, true, NULL);
    543   gomp_debug (0, "  %s: mappings restored\n", __FUNCTION__);
    544 
    545   if (profiling_p)
    546     {
    547       prof_info.event_type = acc_ev_exit_data_end;
    548       exit_data_event_info.other_event.event_type = prof_info.event_type;
    549       goacc_profiling_dispatch (&prof_info, &exit_data_event_info, &api_info);
    550 
    551       thr->prof_info = NULL;
    552       thr->api_info = NULL;
    553     }
    554 }
    555 
    556 void
    557 GOACC_update (int flags_m, size_t mapnum,
    558 	      void **hostaddrs, size_t *sizes, unsigned short *kinds,
    559 	      int async, int num_waits, ...)
    560 {
    561   int flags = GOACC_FLAGS_UNMARSHAL (flags_m);
    562 
    563   size_t i;
    564 
    565   goacc_lazy_initialize ();
    566 
    567   struct goacc_thread *thr = goacc_thread ();
    568   struct gomp_device_descr *acc_dev = thr->dev;
    569 
    570   bool profiling_p = GOACC_PROFILING_DISPATCH_P (true);
    571 
    572   acc_prof_info prof_info;
    573   if (profiling_p)
    574     {
    575       thr->prof_info = &prof_info;
    576 
    577       prof_info.event_type = acc_ev_update_start;
    578       prof_info.valid_bytes = _ACC_PROF_INFO_VALID_BYTES;
    579       prof_info.version = _ACC_PROF_INFO_VERSION;
    580       prof_info.device_type = acc_device_type (acc_dev->type);
    581       prof_info.device_number = acc_dev->target_id;
    582       prof_info.thread_id = -1;
    583       prof_info.async = async;
    584       prof_info.async_queue = prof_info.async;
    585       prof_info.src_file = NULL;
    586       prof_info.func_name = NULL;
    587       prof_info.line_no = -1;
    588       prof_info.end_line_no = -1;
    589       prof_info.func_line_no = -1;
    590       prof_info.func_end_line_no = -1;
    591     }
    592   acc_event_info update_event_info;
    593   if (profiling_p)
    594     {
    595       update_event_info.other_event.event_type
    596 	= prof_info.event_type;
    597       update_event_info.other_event.valid_bytes
    598 	= _ACC_OTHER_EVENT_INFO_VALID_BYTES;
    599       update_event_info.other_event.parent_construct = acc_construct_update;
    600       update_event_info.other_event.implicit = 0;
    601       update_event_info.other_event.tool_info = NULL;
    602     }
    603   acc_api_info api_info;
    604   if (profiling_p)
    605     {
    606       thr->api_info = &api_info;
    607 
    608       api_info.device_api = acc_device_api_none;
    609       api_info.valid_bytes = _ACC_API_INFO_VALID_BYTES;
    610       api_info.device_type = prof_info.device_type;
    611       api_info.vendor = -1;
    612       api_info.device_handle = NULL;
    613       api_info.context_handle = NULL;
    614       api_info.async_handle = NULL;
    615     }
    616 
    617   if (profiling_p)
    618     goacc_profiling_dispatch (&prof_info, &update_event_info, &api_info);
    619 
    620   if ((acc_dev->capabilities & GOMP_OFFLOAD_CAP_SHARED_MEM)
    621       || (flags & GOACC_FLAG_HOST_FALLBACK))
    622     {
    623       prof_info.device_type = acc_device_host;
    624       api_info.device_type = prof_info.device_type;
    625 
    626       goto out_prof;
    627     }
    628 
    629   if (num_waits)
    630     {
    631       va_list ap;
    632 
    633       va_start (ap, num_waits);
    634       goacc_wait (async, num_waits, &ap);
    635       va_end (ap);
    636     }
    637 
    638   bool update_device = false;
    639   for (i = 0; i < mapnum; ++i)
    640     {
    641       unsigned char kind = kinds[i] & 0xff;
    642 
    643       switch (kind)
    644 	{
    645 	case GOMP_MAP_POINTER:
    646 	case GOMP_MAP_TO_PSET:
    647 	  break;
    648 
    649 	case GOMP_MAP_ALWAYS_POINTER:
    650 	  if (update_device)
    651 	    {
    652 	      /* Save the contents of the host pointer.  */
    653 	      void *dptr = acc_deviceptr (hostaddrs[i-1]);
    654 	      uintptr_t t = *(uintptr_t *) hostaddrs[i];
    655 
    656 	      /* Update the contents of the host pointer to reflect
    657 		 the value of the allocated device memory in the
    658 		 previous pointer.  */
    659 	      *(uintptr_t *) hostaddrs[i] = (uintptr_t)dptr;
    660 	      /* TODO: verify that we really cannot use acc_update_device_async
    661 		 here.  */
    662 	      acc_update_device (hostaddrs[i], sizeof (uintptr_t));
    663 
    664 	      /* Restore the host pointer.  */
    665 	      *(uintptr_t *) hostaddrs[i] = t;
    666 	      update_device = false;
    667 	    }
    668 	  break;
    669 
    670 	case GOMP_MAP_TO:
    671 	  if (!acc_is_present (hostaddrs[i], sizes[i]))
    672 	    {
    673 	      update_device = false;
    674 	      break;
    675 	    }
    676 	  /* Fallthru  */
    677 	case GOMP_MAP_FORCE_TO:
    678 	  update_device = true;
    679 	  acc_update_device_async (hostaddrs[i], sizes[i], async);
    680 	  break;
    681 
    682 	case GOMP_MAP_FROM:
    683 	  if (!acc_is_present (hostaddrs[i], sizes[i]))
    684 	    {
    685 	      update_device = false;
    686 	      break;
    687 	    }
    688 	  /* Fallthru  */
    689 	case GOMP_MAP_FORCE_FROM:
    690 	  update_device = false;
    691 	  acc_update_self_async (hostaddrs[i], sizes[i], async);
    692 	  break;
    693 
    694 	default:
    695 	  gomp_fatal (">>>> GOACC_update UNHANDLED kind 0x%.2x", kind);
    696 	  break;
    697 	}
    698     }
    699 
    700  out_prof:
    701   if (profiling_p)
    702     {
    703       prof_info.event_type = acc_ev_update_end;
    704       update_event_info.other_event.event_type = prof_info.event_type;
    705       goacc_profiling_dispatch (&prof_info, &update_event_info, &api_info);
    706 
    707       thr->prof_info = NULL;
    708       thr->api_info = NULL;
    709     }
    710 }
    711 
    712 
    713 /* Legacy entry point (GCC 5).  */
    714 
    715 int
    716 GOACC_get_num_threads (void)
    717 {
    718   return 1;
    719 }
    720 
    721 /* Legacy entry point (GCC 5).  */
    722 
    723 int
    724 GOACC_get_thread_num (void)
    725 {
    726   return 0;
    727 }
    728