Commit d84ffc0a by Ilya Verbin Committed by Ilya Verbin

libgomp.h (gomp_device_state): New enum.

libgomp/
	* libgomp.h (gomp_device_state): New enum.
	(struct gomp_device_descr): Replace is_initialized with state.
	(gomp_fini_device): Remove declaration.
	* oacc-host.c (host_dispatch): Use state instead of is_initialized.
	* oacc-init.c (acc_init_1): Use state instead of is_initialized.
	(acc_shutdown_1): Likewise.  Inline gomp_fini_device.
	(acc_set_device_type): Use state instead of is_initialized.
	(acc_set_device_num): Likewise.
	* target.c (resolve_device): Use state instead of is_initialized.
	Do not initialize finalized device.
	(gomp_map_vars): Do nothing if device is finalized.
	(gomp_unmap_vars): Likewise.
	(gomp_update): Likewise.
	(GOMP_offload_register_ver): Use state instead of is_initialized.
	(GOMP_offload_unregister_ver): Likewise.
	(gomp_init_device): Likewise.
	(gomp_unload_device): Likewise.
	(gomp_fini_device): Remove.
	(gomp_get_target_fn_addr): Do nothing if device is finalized.
	(GOMP_target): Go to host fallback if device is finalized.
	(GOMP_target_ext): Likewise.
	(gomp_exit_data): Do nothing if device is finalized.
	(gomp_target_task_fn): Go to host fallback if device is finalized.
	(gomp_target_fini): New static function.
	(gomp_target_init): Use state instead of is_initialized.
	Call gomp_target_fini at exit.
liboffloadmic/
	* plugin/libgomp-plugin-intelmic.cpp (unregister_main_image): Remove.
	(register_main_image): Do not call unregister_main_image at exit.
	(GOMP_OFFLOAD_fini_device): Allow for OpenMP.  Unregister main image.

From-SVN: r231623
parent 755cd5a9
2015-12-14 Ilya Verbin <ilya.verbin@intel.com>
* libgomp.h (gomp_device_state): New enum.
(struct gomp_device_descr): Replace is_initialized with state.
(gomp_fini_device): Remove declaration.
* oacc-host.c (host_dispatch): Use state instead of is_initialized.
* oacc-init.c (acc_init_1): Use state instead of is_initialized.
(acc_shutdown_1): Likewise. Inline gomp_fini_device.
(acc_set_device_type): Use state instead of is_initialized.
(acc_set_device_num): Likewise.
* target.c (resolve_device): Use state instead of is_initialized.
Do not initialize finalized device.
(gomp_map_vars): Do nothing if device is finalized.
(gomp_unmap_vars): Likewise.
(gomp_update): Likewise.
(GOMP_offload_register_ver): Use state instead of is_initialized.
(GOMP_offload_unregister_ver): Likewise.
(gomp_init_device): Likewise.
(gomp_unload_device): Likewise.
(gomp_fini_device): Remove.
(gomp_get_target_fn_addr): Do nothing if device is finalized.
(GOMP_target): Go to host fallback if device is finalized.
(GOMP_target_ext): Likewise.
(gomp_exit_data): Do nothing if device is finalized.
(gomp_target_task_fn): Go to host fallback if device is finalized.
(gomp_target_fini): New static function.
(gomp_target_init): Use state instead of is_initialized.
Call gomp_target_fini at exit.
2015-12-09 Tom de Vries <tom@codesourcery.com> 2015-12-09 Tom de Vries <tom@codesourcery.com>
PR tree-optimization/68716 PR tree-optimization/68716
......
...@@ -888,6 +888,14 @@ typedef struct acc_dispatch_t ...@@ -888,6 +888,14 @@ typedef struct acc_dispatch_t
} cuda; } cuda;
} acc_dispatch_t; } acc_dispatch_t;
/* Various state of the accelerator device. */
enum gomp_device_state
{
GOMP_DEVICE_UNINITIALIZED,
GOMP_DEVICE_INITIALIZED,
GOMP_DEVICE_FINALIZED
};
/* This structure describes accelerator device. /* This structure describes accelerator device.
It contains name of the corresponding libgomp plugin, function handlers for It contains name of the corresponding libgomp plugin, function handlers for
interaction with the device, ID-number of the device, and information about interaction with the device, ID-number of the device, and information about
...@@ -933,8 +941,10 @@ struct gomp_device_descr ...@@ -933,8 +941,10 @@ struct gomp_device_descr
/* Mutex for the mutable data. */ /* Mutex for the mutable data. */
gomp_mutex_t lock; gomp_mutex_t lock;
/* Set to true when device is initialized. */ /* Current state of the device. OpenACC allows to move from INITIALIZED state
bool is_initialized; back to UNINITIALIZED state. OpenMP allows only to move from INITIALIZED
to FINALIZED state (at program shutdown). */
enum gomp_device_state state;
/* OpenACC-specific data and functions. */ /* OpenACC-specific data and functions. */
/* This is mutable because of its mutable data_environ and target_data /* This is mutable because of its mutable data_environ and target_data
...@@ -962,7 +972,6 @@ extern void gomp_copy_from_async (struct target_mem_desc *); ...@@ -962,7 +972,6 @@ extern void gomp_copy_from_async (struct target_mem_desc *);
extern void gomp_unmap_vars (struct target_mem_desc *, bool); extern void gomp_unmap_vars (struct target_mem_desc *, bool);
extern void gomp_init_device (struct gomp_device_descr *); extern void gomp_init_device (struct gomp_device_descr *);
extern void gomp_free_memmap (struct splay_tree_s *); extern void gomp_free_memmap (struct splay_tree_s *);
extern void gomp_fini_device (struct gomp_device_descr *);
extern void gomp_unload_device (struct gomp_device_descr *); extern void gomp_unload_device (struct gomp_device_descr *);
/* work.c */ /* work.c */
......
...@@ -222,7 +222,7 @@ static struct gomp_device_descr host_dispatch = ...@@ -222,7 +222,7 @@ static struct gomp_device_descr host_dispatch =
.mem_map = { NULL }, .mem_map = { NULL },
/* .lock initilized in goacc_host_init. */ /* .lock initilized in goacc_host_init. */
.is_initialized = false, .state = GOMP_DEVICE_UNINITIALIZED,
.openacc = { .openacc = {
.data_environ = NULL, .data_environ = NULL,
......
...@@ -225,7 +225,7 @@ acc_init_1 (acc_device_t d) ...@@ -225,7 +225,7 @@ acc_init_1 (acc_device_t d)
acc_dev = &base_dev[goacc_device_num]; acc_dev = &base_dev[goacc_device_num];
gomp_mutex_lock (&acc_dev->lock); gomp_mutex_lock (&acc_dev->lock);
if (acc_dev->is_initialized) if (acc_dev->state == GOMP_DEVICE_INITIALIZED)
{ {
gomp_mutex_unlock (&acc_dev->lock); gomp_mutex_unlock (&acc_dev->lock);
gomp_fatal ("device already active"); gomp_fatal ("device already active");
...@@ -306,10 +306,11 @@ acc_shutdown_1 (acc_device_t d) ...@@ -306,10 +306,11 @@ acc_shutdown_1 (acc_device_t d)
{ {
struct gomp_device_descr *acc_dev = &base_dev[i]; struct gomp_device_descr *acc_dev = &base_dev[i];
gomp_mutex_lock (&acc_dev->lock); gomp_mutex_lock (&acc_dev->lock);
if (acc_dev->is_initialized) if (acc_dev->state == GOMP_DEVICE_INITIALIZED)
{ {
devices_active = true; devices_active = true;
gomp_fini_device (acc_dev); acc_dev->fini_device_func (acc_dev->target_id);
acc_dev->state = GOMP_DEVICE_UNINITIALIZED;
} }
gomp_mutex_unlock (&acc_dev->lock); gomp_mutex_unlock (&acc_dev->lock);
} }
...@@ -506,7 +507,7 @@ acc_set_device_type (acc_device_t d) ...@@ -506,7 +507,7 @@ acc_set_device_type (acc_device_t d)
acc_dev = &base_dev[goacc_device_num]; acc_dev = &base_dev[goacc_device_num];
gomp_mutex_lock (&acc_dev->lock); gomp_mutex_lock (&acc_dev->lock);
if (!acc_dev->is_initialized) if (acc_dev->state == GOMP_DEVICE_UNINITIALIZED)
gomp_init_device (acc_dev); gomp_init_device (acc_dev);
gomp_mutex_unlock (&acc_dev->lock); gomp_mutex_unlock (&acc_dev->lock);
...@@ -608,7 +609,7 @@ acc_set_device_num (int ord, acc_device_t d) ...@@ -608,7 +609,7 @@ acc_set_device_num (int ord, acc_device_t d)
acc_dev = &base_dev[ord]; acc_dev = &base_dev[ord];
gomp_mutex_lock (&acc_dev->lock); gomp_mutex_lock (&acc_dev->lock);
if (!acc_dev->is_initialized) if (acc_dev->state == GOMP_DEVICE_UNINITIALIZED)
gomp_init_device (acc_dev); gomp_init_device (acc_dev);
gomp_mutex_unlock (&acc_dev->lock); gomp_mutex_unlock (&acc_dev->lock);
......
...@@ -118,8 +118,13 @@ resolve_device (int device_id) ...@@ -118,8 +118,13 @@ resolve_device (int device_id)
return NULL; return NULL;
gomp_mutex_lock (&devices[device_id].lock); gomp_mutex_lock (&devices[device_id].lock);
if (!devices[device_id].is_initialized) if (devices[device_id].state == GOMP_DEVICE_UNINITIALIZED)
gomp_init_device (&devices[device_id]); gomp_init_device (&devices[device_id]);
else if (devices[device_id].state == GOMP_DEVICE_FINALIZED)
{
gomp_mutex_unlock (&devices[device_id].lock);
return NULL;
}
gomp_mutex_unlock (&devices[device_id].lock); gomp_mutex_unlock (&devices[device_id].lock);
return &devices[device_id]; return &devices[device_id];
...@@ -356,6 +361,12 @@ gomp_map_vars (struct gomp_device_descr *devicep, size_t mapnum, ...@@ -356,6 +361,12 @@ gomp_map_vars (struct gomp_device_descr *devicep, size_t mapnum,
} }
gomp_mutex_lock (&devicep->lock); gomp_mutex_lock (&devicep->lock);
if (devicep->state == GOMP_DEVICE_FINALIZED)
{
gomp_mutex_unlock (&devicep->lock);
free (tgt);
return NULL;
}
for (i = 0; i < mapnum; i++) for (i = 0; i < mapnum; i++)
{ {
...@@ -834,6 +845,13 @@ gomp_unmap_vars (struct target_mem_desc *tgt, bool do_copyfrom) ...@@ -834,6 +845,13 @@ gomp_unmap_vars (struct target_mem_desc *tgt, bool do_copyfrom)
} }
gomp_mutex_lock (&devicep->lock); gomp_mutex_lock (&devicep->lock);
if (devicep->state == GOMP_DEVICE_FINALIZED)
{
gomp_mutex_unlock (&devicep->lock);
free (tgt->array);
free (tgt);
return;
}
size_t i; size_t i;
for (i = 0; i < tgt->list_count; i++) for (i = 0; i < tgt->list_count; i++)
...@@ -896,6 +914,12 @@ gomp_update (struct gomp_device_descr *devicep, size_t mapnum, void **hostaddrs, ...@@ -896,6 +914,12 @@ gomp_update (struct gomp_device_descr *devicep, size_t mapnum, void **hostaddrs,
return; return;
gomp_mutex_lock (&devicep->lock); gomp_mutex_lock (&devicep->lock);
if (devicep->state == GOMP_DEVICE_FINALIZED)
{
gomp_mutex_unlock (&devicep->lock);
return;
}
for (i = 0; i < mapnum; i++) for (i = 0; i < mapnum; i++)
if (sizes[i]) if (sizes[i])
{ {
...@@ -1106,7 +1130,8 @@ GOMP_offload_register_ver (unsigned version, const void *host_table, ...@@ -1106,7 +1130,8 @@ GOMP_offload_register_ver (unsigned version, const void *host_table,
{ {
struct gomp_device_descr *devicep = &devices[i]; struct gomp_device_descr *devicep = &devices[i];
gomp_mutex_lock (&devicep->lock); gomp_mutex_lock (&devicep->lock);
if (devicep->type == target_type && devicep->is_initialized) if (devicep->type == target_type
&& devicep->state == GOMP_DEVICE_INITIALIZED)
gomp_load_image_to_device (devicep, version, gomp_load_image_to_device (devicep, version,
host_table, target_data, true); host_table, target_data, true);
gomp_mutex_unlock (&devicep->lock); gomp_mutex_unlock (&devicep->lock);
...@@ -1150,7 +1175,8 @@ GOMP_offload_unregister_ver (unsigned version, const void *host_table, ...@@ -1150,7 +1175,8 @@ GOMP_offload_unregister_ver (unsigned version, const void *host_table,
{ {
struct gomp_device_descr *devicep = &devices[i]; struct gomp_device_descr *devicep = &devices[i];
gomp_mutex_lock (&devicep->lock); gomp_mutex_lock (&devicep->lock);
if (devicep->type == target_type && devicep->is_initialized) if (devicep->type == target_type
&& devicep->state == GOMP_DEVICE_INITIALIZED)
gomp_unload_image_from_device (devicep, version, gomp_unload_image_from_device (devicep, version,
host_table, target_data); host_table, target_data);
gomp_mutex_unlock (&devicep->lock); gomp_mutex_unlock (&devicep->lock);
...@@ -1193,13 +1219,13 @@ gomp_init_device (struct gomp_device_descr *devicep) ...@@ -1193,13 +1219,13 @@ gomp_init_device (struct gomp_device_descr *devicep)
false); false);
} }
devicep->is_initialized = true; devicep->state = GOMP_DEVICE_INITIALIZED;
} }
attribute_hidden void attribute_hidden void
gomp_unload_device (struct gomp_device_descr *devicep) gomp_unload_device (struct gomp_device_descr *devicep)
{ {
if (devicep->is_initialized) if (devicep->state == GOMP_DEVICE_INITIALIZED)
{ {
unsigned i; unsigned i;
...@@ -1231,18 +1257,6 @@ gomp_free_memmap (struct splay_tree_s *mem_map) ...@@ -1231,18 +1257,6 @@ gomp_free_memmap (struct splay_tree_s *mem_map)
} }
} }
/* This function de-initializes the target device, specified by DEVICEP.
DEVICEP must be locked on entry, and remains locked on return. */
attribute_hidden void
gomp_fini_device (struct gomp_device_descr *devicep)
{
if (devicep->is_initialized)
devicep->fini_device_func (devicep->target_id);
devicep->is_initialized = false;
}
/* Host fallback for GOMP_target{,_ext} routines. */ /* Host fallback for GOMP_target{,_ext} routines. */
static void static void
...@@ -1310,6 +1324,12 @@ gomp_get_target_fn_addr (struct gomp_device_descr *devicep, ...@@ -1310,6 +1324,12 @@ gomp_get_target_fn_addr (struct gomp_device_descr *devicep,
else else
{ {
gomp_mutex_lock (&devicep->lock); gomp_mutex_lock (&devicep->lock);
if (devicep->state == GOMP_DEVICE_FINALIZED)
{
gomp_mutex_unlock (&devicep->lock);
return NULL;
}
struct splay_tree_key_s k; struct splay_tree_key_s k;
k.host_start = (uintptr_t) host_fn; k.host_start = (uintptr_t) host_fn;
k.host_end = k.host_start + 1; k.host_end = k.host_start + 1;
...@@ -1339,12 +1359,12 @@ GOMP_target (int device, void (*fn) (void *), const void *unused, ...@@ -1339,12 +1359,12 @@ GOMP_target (int device, void (*fn) (void *), const void *unused,
{ {
struct gomp_device_descr *devicep = resolve_device (device); struct gomp_device_descr *devicep = resolve_device (device);
void *fn_addr;
if (devicep == NULL if (devicep == NULL
|| !(devicep->capabilities & GOMP_OFFLOAD_CAP_OPENMP_400)) || !(devicep->capabilities & GOMP_OFFLOAD_CAP_OPENMP_400)
|| !(fn_addr = gomp_get_target_fn_addr (devicep, fn)))
return gomp_target_fallback (fn, hostaddrs); return gomp_target_fallback (fn, hostaddrs);
void *fn_addr = gomp_get_target_fn_addr (devicep, fn);
struct target_mem_desc *tgt_vars struct target_mem_desc *tgt_vars
= gomp_map_vars (devicep, mapnum, hostaddrs, NULL, sizes, kinds, false, = gomp_map_vars (devicep, mapnum, hostaddrs, NULL, sizes, kinds, false,
GOMP_MAP_VARS_TARGET); GOMP_MAP_VARS_TARGET);
...@@ -1430,15 +1450,15 @@ GOMP_target_ext (int device, void (*fn) (void *), size_t mapnum, ...@@ -1430,15 +1450,15 @@ GOMP_target_ext (int device, void (*fn) (void *), size_t mapnum,
gomp_task_maybe_wait_for_dependencies (depend); gomp_task_maybe_wait_for_dependencies (depend);
} }
void *fn_addr;
if (devicep == NULL if (devicep == NULL
|| !(devicep->capabilities & GOMP_OFFLOAD_CAP_OPENMP_400)) || !(devicep->capabilities & GOMP_OFFLOAD_CAP_OPENMP_400)
|| !(fn_addr = gomp_get_target_fn_addr (devicep, fn)))
{ {
gomp_target_fallback_firstprivate (fn, mapnum, hostaddrs, sizes, kinds); gomp_target_fallback_firstprivate (fn, mapnum, hostaddrs, sizes, kinds);
return; return;
} }
void *fn_addr = gomp_get_target_fn_addr (devicep, fn);
struct target_mem_desc *tgt_vars struct target_mem_desc *tgt_vars
= gomp_map_vars (devicep, mapnum, hostaddrs, NULL, sizes, kinds, true, = gomp_map_vars (devicep, mapnum, hostaddrs, NULL, sizes, kinds, true,
GOMP_MAP_VARS_TARGET); GOMP_MAP_VARS_TARGET);
...@@ -1593,6 +1613,12 @@ gomp_exit_data (struct gomp_device_descr *devicep, size_t mapnum, ...@@ -1593,6 +1613,12 @@ gomp_exit_data (struct gomp_device_descr *devicep, size_t mapnum,
const int typemask = 0xff; const int typemask = 0xff;
size_t i; size_t i;
gomp_mutex_lock (&devicep->lock); gomp_mutex_lock (&devicep->lock);
if (devicep->state == GOMP_DEVICE_FINALIZED)
{
gomp_mutex_unlock (&devicep->lock);
return;
}
for (i = 0; i < mapnum; i++) for (i = 0; i < mapnum; i++)
{ {
struct splay_tree_key_s cur_node; struct splay_tree_key_s cur_node;
...@@ -1729,8 +1755,10 @@ gomp_target_task_fn (void *data) ...@@ -1729,8 +1755,10 @@ gomp_target_task_fn (void *data)
if (ttask->fn != NULL) if (ttask->fn != NULL)
{ {
void *fn_addr;
if (devicep == NULL if (devicep == NULL
|| !(devicep->capabilities & GOMP_OFFLOAD_CAP_OPENMP_400)) || !(devicep->capabilities & GOMP_OFFLOAD_CAP_OPENMP_400)
|| !(fn_addr = gomp_get_target_fn_addr (devicep, ttask->fn)))
{ {
ttask->state = GOMP_TARGET_TASK_FALLBACK; ttask->state = GOMP_TARGET_TASK_FALLBACK;
gomp_target_fallback_firstprivate (ttask->fn, ttask->mapnum, gomp_target_fallback_firstprivate (ttask->fn, ttask->mapnum,
...@@ -1745,7 +1773,6 @@ gomp_target_task_fn (void *data) ...@@ -1745,7 +1773,6 @@ gomp_target_task_fn (void *data)
return false; return false;
} }
void *fn_addr = gomp_get_target_fn_addr (devicep, ttask->fn);
ttask->tgt ttask->tgt
= gomp_map_vars (devicep, ttask->mapnum, ttask->hostaddrs, NULL, = gomp_map_vars (devicep, ttask->mapnum, ttask->hostaddrs, NULL,
ttask->sizes, ttask->kinds, true, ttask->sizes, ttask->kinds, true,
...@@ -2282,6 +2309,25 @@ gomp_load_plugin_for_device (struct gomp_device_descr *device, ...@@ -2282,6 +2309,25 @@ gomp_load_plugin_for_device (struct gomp_device_descr *device,
return 0; return 0;
} }
/* This function finalizes all initialized devices. */
static void
gomp_target_fini (void)
{
int i;
for (i = 0; i < num_devices; i++)
{
struct gomp_device_descr *devicep = &devices[i];
gomp_mutex_lock (&devicep->lock);
if (devicep->state == GOMP_DEVICE_INITIALIZED)
{
devicep->fini_device_func (devicep->target_id);
devicep->state = GOMP_DEVICE_FINALIZED;
}
gomp_mutex_unlock (&devicep->lock);
}
}
/* This function initializes the runtime needed for offloading. /* This function initializes the runtime needed for offloading.
It parses the list of offload targets and tries to load the plugins for It parses the list of offload targets and tries to load the plugins for
these targets. On return, the variables NUM_DEVICES and NUM_DEVICES_OPENMP these targets. On return, the variables NUM_DEVICES and NUM_DEVICES_OPENMP
...@@ -2341,7 +2387,7 @@ gomp_target_init (void) ...@@ -2341,7 +2387,7 @@ gomp_target_init (void)
/* current_device.capabilities has already been set. */ /* current_device.capabilities has already been set. */
current_device.type = current_device.get_type_func (); current_device.type = current_device.get_type_func ();
current_device.mem_map.root = NULL; current_device.mem_map.root = NULL;
current_device.is_initialized = false; current_device.state = GOMP_DEVICE_UNINITIALIZED;
current_device.openacc.data_environ = NULL; current_device.openacc.data_environ = NULL;
for (i = 0; i < new_num_devices; i++) for (i = 0; i < new_num_devices; i++)
{ {
...@@ -2387,6 +2433,9 @@ gomp_target_init (void) ...@@ -2387,6 +2433,9 @@ gomp_target_init (void)
if (devices[i].capabilities & GOMP_OFFLOAD_CAP_OPENACC_200) if (devices[i].capabilities & GOMP_OFFLOAD_CAP_OPENACC_200)
goacc_register (&devices[i]); goacc_register (&devices[i]);
} }
if (atexit (gomp_target_fini) != 0)
gomp_fatal ("atexit failed");
} }
#else /* PLUGIN_SUPPORT */ #else /* PLUGIN_SUPPORT */
......
2015-12-14 Ilya Verbin <ilya.verbin@intel.com>
* plugin/libgomp-plugin-intelmic.cpp (unregister_main_image): Remove.
(register_main_image): Do not call unregister_main_image at exit.
(GOMP_OFFLOAD_fini_device): Allow for OpenMP. Unregister main image.
2015-11-19 Ilya Verbin <ilya.verbin@intel.com> 2015-11-19 Ilya Verbin <ilya.verbin@intel.com>
* plugin/libgomp-plugin-intelmic.cpp (struct TargetImageDesc): New. * plugin/libgomp-plugin-intelmic.cpp (struct TargetImageDesc): New.
......
...@@ -231,12 +231,6 @@ offload (const char *file, uint64_t line, int device, const char *name, ...@@ -231,12 +231,6 @@ offload (const char *file, uint64_t line, int device, const char *name,
} }
static void static void
unregister_main_image ()
{
__offload_unregister_image (&main_target_image);
}
static void
register_main_image () register_main_image ()
{ {
/* Do not check the return value, because old versions of liboffloadmic did /* Do not check the return value, because old versions of liboffloadmic did
...@@ -246,12 +240,6 @@ register_main_image () ...@@ -246,12 +240,6 @@ register_main_image ()
/* liboffloadmic will call GOMP_PLUGIN_target_task_completion when /* liboffloadmic will call GOMP_PLUGIN_target_task_completion when
asynchronous task on target is completed. */ asynchronous task on target is completed. */
__offload_register_task_callback (GOMP_PLUGIN_target_task_completion); __offload_register_task_callback (GOMP_PLUGIN_target_task_completion);
if (atexit (unregister_main_image) != 0)
{
fprintf (stderr, "%s: atexit failed\n", __FILE__);
exit (1);
}
} }
/* liboffloadmic loads and runs offload_target_main on all available devices /* liboffloadmic loads and runs offload_target_main on all available devices
...@@ -269,8 +257,9 @@ extern "C" void ...@@ -269,8 +257,9 @@ extern "C" void
GOMP_OFFLOAD_fini_device (int device) GOMP_OFFLOAD_fini_device (int device)
{ {
TRACE ("(device = %d)", device); TRACE ("(device = %d)", device);
/* Unreachable for GOMP_OFFLOAD_CAP_OPENMP_400. */
abort (); /* liboffloadmic will finalize target processes on all available devices. */
__offload_unregister_image (&main_target_image);
} }
static void static void
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment