diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 1bac36655a9..6ed8deacea2 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,8 @@ +2015-08-24 Nathan Sidwell + + * config/nvptx/mkoffload.c (process): Replace + GOMP_offload_{,un}register with GOMP_offload_{,un}register_ver. + 2015-08-24 H.J. Lu PR target/67329 diff --git a/gcc/config/nvptx/mkoffload.c b/gcc/config/nvptx/mkoffload.c index 1e154c8412c..ba0454e537a 100644 --- a/gcc/config/nvptx/mkoffload.c +++ b/gcc/config/nvptx/mkoffload.c @@ -881,10 +881,10 @@ process (FILE *in, FILE *out) "extern \"C\" {\n" "#endif\n"); - fprintf (out, "extern void GOMP_offload_register" - " (const void *, int, const void *);\n"); - fprintf (out, "extern void GOMP_offload_unregister" - " (const void *, int, const void *);\n"); + fprintf (out, "extern void GOMP_offload_register_ver" + " (unsigned, const void *, int, const void *);\n"); + fprintf (out, "extern void GOMP_offload_unregister_ver" + " (unsigned, const void *, int, const void *);\n"); fprintf (out, "#ifdef __cplusplus\n" "}\n" @@ -894,15 +894,19 @@ process (FILE *in, FILE *out) fprintf (out, "static __attribute__((constructor)) void init (void)\n" "{\n" - " GOMP_offload_register (__OFFLOAD_TABLE__, %d/*NVIDIA_PTX*/,\n" - " &target_data);\n" - "};\n", GOMP_DEVICE_NVIDIA_PTX); + " GOMP_offload_register_ver (%#x, __OFFLOAD_TABLE__," + "%d/*NVIDIA_PTX*/, &target_data);\n" + "};\n", + GOMP_VERSION_PACK (GOMP_VERSION, GOMP_VERSION_NVIDIA_PTX), + GOMP_DEVICE_NVIDIA_PTX); fprintf (out, "static __attribute__((destructor)) void fini (void)\n" "{\n" - " GOMP_offload_unregister (__OFFLOAD_TABLE__, %d/*NVIDIA_PTX*/,\n" - " &target_data);\n" - "};\n", GOMP_DEVICE_NVIDIA_PTX); + " GOMP_offload_unregister_ver (%#x, __OFFLOAD_TABLE__," + "%d/*NVIDIA_PTX*/, &target_data);\n" + "};\n", + GOMP_VERSION_PACK (GOMP_VERSION, GOMP_VERSION_NVIDIA_PTX), + GOMP_DEVICE_NVIDIA_PTX); } static void diff --git a/include/ChangeLog b/include/ChangeLog index 6962f858844..c5dd5381a83 100644 --- a/include/ChangeLog +++ b/include/ChangeLog @@ -1,3 +1,9 @@ +2015-08-24 Nathan Sidwell + + * gomp-constants.h (GOMP_VERSION, GOMP_VERSION_NVIDIA_PTX, + GOMP_VERSION_INTEL_MIC): New. + (GOMP_VERSION_PACK, GOMP_VERSION_LIB, GOMP_VERSION_DEV): New. + 2015-08-14 Pierre-Marie de Rodat * dwarf2.def (DW_AT_GNU_bias): New attribute. diff --git a/include/gomp-constants.h b/include/gomp-constants.h index 807e672741a..6e6a8b127a5 100644 --- a/include/gomp-constants.h +++ b/include/gomp-constants.h @@ -113,4 +113,13 @@ enum gomp_map_kind #define GOMP_DEVICE_ICV -1 #define GOMP_DEVICE_HOST_FALLBACK -2 +/* Versions of libgomp and device-specific plugins. */ +#define GOMP_VERSION 0 +#define GOMP_VERSION_NVIDIA_PTX 0 +#define GOMP_VERSION_INTEL_MIC 0 + +#define GOMP_VERSION_PACK(LIB, DEV) (((LIB) << 16) | (DEV)) +#define GOMP_VERSION_LIB(PACK) (((PACK) >> 16) & 0xffff) +#define GOMP_VERSION_DEV(PACK) ((PACK) & 0xffff) + #endif diff --git a/libgomp/ChangeLog b/libgomp/ChangeLog index 7bb4fafb05f..39c67aff423 100644 --- a/libgomp/ChangeLog +++ b/libgomp/ChangeLog @@ -1,3 +1,35 @@ +2015-08-24 Nathan Sidwell + + libgomp/ + * libgomp.map: Add 4.0.2 version. + * target.c (offload_image_descr): Add version field. + (gomp_load_image_to_device): Add version argument. Adjust plugin + call. Improve load mismatch diagnostic. + (gomp_unload_image_from_device): Add version argument. Adjust plugin + call. + (GOMP_offload_regster): Make stub function, move bulk to ... + (GOMP_offload_register_ver): ... here. Process version argument. + (GOMP_offload_unregister): Make stub function, move bulk to ... + (GOMP_offload_unregister_ver): ... here. Process version argument. + (gomp_init_device): Process version field. + (gomp_unload_device): Process version field. + (gomp_load_plugin_for_device): Reimplement DLSYM & DLSYM_OPT + macros. Check plugin version. + * libgomp.h (gomp_device_descr): Add version function field. Adjust + loader and unloader types. + * oacc-host.c: Include gomp-constants.h. + (host_version): New. + (host_load_image, host_unload_image): Adjust. + (host_dispatch): Add host_version. + * plugin/plugin-nvptx.c: Include gomp-constants.h. + (GOMP_OFFLOAD_version): New. + (GOMP_OFFLOAD_load_image): Add version arg and check it. + (GOMP_OFFLOAD_unload_image): Likewise. + * plugin/plugin-host.c: Include gomp-constants.h. + (GOMP_OFFLOAD_version): New. + (GOMP_OFFLOAD_load_image): Add version arg. + (GOMP_OFFLOAD_unload_image): Likewise. + 2015-08-24 Tom de Vries PR tree-optimization/65468 diff --git a/libgomp/libgomp.h b/libgomp/libgomp.h index ac40e2aa510..62454b8527a 100644 --- a/libgomp/libgomp.h +++ b/libgomp/libgomp.h @@ -748,8 +748,9 @@ struct gomp_device_descr int (*get_num_devices_func) (void); void (*init_device_func) (int); void (*fini_device_func) (int); - int (*load_image_func) (int, const void *, struct addr_pair **); - void (*unload_image_func) (int, const void *); + unsigned (*version_func) (void); + int (*load_image_func) (int, unsigned, const void *, struct addr_pair **); + void (*unload_image_func) (int, unsigned, const void *); void *(*alloc_func) (int, size_t); void (*free_func) (int, void *); void *(*dev2host_func) (int, void *, const void *, size_t); diff --git a/libgomp/libgomp.map b/libgomp/libgomp.map index 2b2b953e489..ec3c3c1c637 100644 --- a/libgomp/libgomp.map +++ b/libgomp/libgomp.map @@ -234,6 +234,12 @@ GOMP_4.0.1 { GOMP_offload_unregister; } GOMP_4.0; +GOMP_4.0.2 { + global: + GOMP_offload_register_ver; + GOMP_offload_unregister_ver; +} GOMP_4.0.1; + OACC_2.0 { global: acc_get_num_devices; diff --git a/libgomp/oacc-host.c b/libgomp/oacc-host.c index 17a5102042b..55bb16b278a 100644 --- a/libgomp/oacc-host.c +++ b/libgomp/oacc-host.c @@ -28,6 +28,7 @@ #include "libgomp.h" #include "oacc-int.h" +#include "gomp-constants.h" #include #include @@ -69,8 +70,15 @@ host_fini_device (int n __attribute__ ((unused))) { } +static unsigned +host_version (void) +{ + return GOMP_VERSION; +} + static int host_load_image (int n __attribute__ ((unused)), + unsigned v __attribute__ ((unused)), const void *t __attribute__ ((unused)), struct addr_pair **r __attribute__ ((unused))) { @@ -79,6 +87,7 @@ host_load_image (int n __attribute__ ((unused)), static void host_unload_image (int n __attribute__ ((unused)), + unsigned v __attribute__ ((unused)), const void *t __attribute__ ((unused))) { } @@ -206,6 +215,7 @@ static struct gomp_device_descr host_dispatch = .get_num_devices_func = host_get_num_devices, .init_device_func = host_init_device, .fini_device_func = host_fini_device, + .version_func = host_version, .load_image_func = host_load_image, .unload_image_func = host_unload_image, .alloc_func = host_alloc, diff --git a/libgomp/plugin/plugin-nvptx.c b/libgomp/plugin/plugin-nvptx.c index d02a3fd4b9c..a2f950db580 100644 --- a/libgomp/plugin/plugin-nvptx.c +++ b/libgomp/plugin/plugin-nvptx.c @@ -36,6 +36,7 @@ #include "libgomp-plugin.h" #include "oacc-ptx.h" #include "oacc-plugin.h" +#include "gomp-constants.h" #include #include @@ -1570,11 +1571,20 @@ typedef struct nvptx_tdata size_t fn_num; } nvptx_tdata_t; +/* Return the libgomp version number we're compatible with. There is + no requirement for cross-version compatibility. */ + +unsigned +GOMP_OFFLOAD_version (void) +{ + return GOMP_VERSION; +} + /* Load the (partial) program described by TARGET_DATA to device number ORD. Allocate and return TARGET_TABLE. */ int -GOMP_OFFLOAD_load_image (int ord, const void *target_data, +GOMP_OFFLOAD_load_image (int ord, unsigned version, const void *target_data, struct addr_pair **target_table) { CUmodule module; @@ -1587,6 +1597,11 @@ GOMP_OFFLOAD_load_image (int ord, const void *target_data, struct ptx_image_data *new_image; struct ptx_device *dev; + if (GOMP_VERSION_DEV (version) > GOMP_VERSION_NVIDIA_PTX) + GOMP_PLUGIN_fatal ("Offload data incompatible with PTX plugin" + " (expected %u, received %u)", + GOMP_VERSION_NVIDIA_PTX, GOMP_VERSION_DEV (version)); + GOMP_OFFLOAD_init_device (ord); dev = ptx_devices[ord]; @@ -1656,11 +1671,14 @@ GOMP_OFFLOAD_load_image (int ord, const void *target_data, function descriptors allocated by G_O_load_image. */ void -GOMP_OFFLOAD_unload_image (int ord, const void *target_data) +GOMP_OFFLOAD_unload_image (int ord, unsigned version, const void *target_data) { struct ptx_image_data *image, **prev_p; struct ptx_device *dev = ptx_devices[ord]; + if (GOMP_VERSION_DEV (version) > GOMP_VERSION_NVIDIA_PTX) + return; + pthread_mutex_lock (&dev->image_lock); for (prev_p = &dev->images; (image = *prev_p) != 0; prev_p = &image->next) if (image->target_data == target_data) diff --git a/libgomp/target.c b/libgomp/target.c index 7b3d0f9572d..758ece5d78c 100644 --- a/libgomp/target.c +++ b/libgomp/target.c @@ -56,6 +56,7 @@ static gomp_mutex_t register_lock; It contains type of the target device, pointer to host table descriptor, and pointer to target data. */ struct offload_image_descr { + unsigned version; enum offload_target_type type; const void *host_table; const void *target_data; @@ -642,7 +643,7 @@ gomp_update (struct gomp_device_descr *devicep, size_t mapnum, void **hostaddrs, emitting variable and functions in the same order. */ static void -gomp_load_image_to_device (struct gomp_device_descr *devicep, +gomp_load_image_to_device (struct gomp_device_descr *devicep, unsigned version, const void *host_table, const void *target_data, bool is_register_lock) { @@ -658,16 +659,20 @@ gomp_load_image_to_device (struct gomp_device_descr *devicep, /* Load image to device and get target addresses for the image. */ struct addr_pair *target_table = NULL; - int i, num_target_entries - = devicep->load_image_func (devicep->target_id, target_data, - &target_table); + int i, num_target_entries; + + num_target_entries + = devicep->load_image_func (devicep->target_id, version, + target_data, &target_table); if (num_target_entries != num_funcs + num_vars) { gomp_mutex_unlock (&devicep->lock); if (is_register_lock) gomp_mutex_unlock (®ister_lock); - gomp_fatal ("Can't map target functions or variables"); + gomp_fatal ("Cannot map target functions or variables" + " (expected %u, have %u)", num_funcs + num_vars, + num_target_entries); } /* Insert host-target address mapping into splay tree. */ @@ -732,6 +737,7 @@ gomp_load_image_to_device (struct gomp_device_descr *devicep, static void gomp_unload_image_from_device (struct gomp_device_descr *devicep, + unsigned version, const void *host_table, const void *target_data) { void **host_func_table = ((void ***) host_table)[0]; @@ -756,8 +762,8 @@ gomp_unload_image_from_device (struct gomp_device_descr *devicep, k.host_end = k.host_start + 1; node = splay_tree_lookup (&devicep->mem_map, &k); } - - devicep->unload_image_func (devicep->target_id, target_data); + + devicep->unload_image_func (devicep->target_id, version, target_data); /* Remove mappings from splay tree. */ for (j = 0; j < num_funcs; j++) @@ -786,10 +792,15 @@ gomp_unload_image_from_device (struct gomp_device_descr *devicep, the target, and TARGET_DATA needed by target plugin. */ void -GOMP_offload_register (const void *host_table, int target_type, - const void *target_data) +GOMP_offload_register_ver (unsigned version, const void *host_table, + int target_type, const void *target_data) { int i; + + if (GOMP_VERSION_LIB (version) > GOMP_VERSION) + gomp_fatal ("Library too old for offload (version %u < %u)", + GOMP_VERSION, GOMP_VERSION_LIB (version)); + gomp_mutex_lock (®ister_lock); /* Load image to all initialized devices. */ @@ -798,7 +809,8 @@ GOMP_offload_register (const void *host_table, int target_type, struct gomp_device_descr *devicep = &devices[i]; gomp_mutex_lock (&devicep->lock); if (devicep->type == target_type && devicep->is_initialized) - gomp_load_image_to_device (devicep, host_table, target_data, true); + gomp_load_image_to_device (devicep, version, + host_table, target_data, true); gomp_mutex_unlock (&devicep->lock); } @@ -807,6 +819,7 @@ GOMP_offload_register (const void *host_table, int target_type, = gomp_realloc_unlock (offload_images, (num_offload_images + 1) * sizeof (struct offload_image_descr)); + offload_images[num_offload_images].version = version; offload_images[num_offload_images].type = target_type; offload_images[num_offload_images].host_table = host_table; offload_images[num_offload_images].target_data = target_data; @@ -815,13 +828,20 @@ GOMP_offload_register (const void *host_table, int target_type, gomp_mutex_unlock (®ister_lock); } +void +GOMP_offload_register (const void *host_table, int target_type, + const void *target_data) +{ + GOMP_offload_register_ver (0, host_table, target_type, target_data); +} + /* This function should be called from every offload image while unloading. It gets the descriptor of the host func and var tables HOST_TABLE, TYPE of the target, and TARGET_DATA needed by target plugin. */ void -GOMP_offload_unregister (const void *host_table, int target_type, - const void *target_data) +GOMP_offload_unregister_ver (unsigned version, const void *host_table, + int target_type, const void *target_data) { int i; @@ -833,7 +853,8 @@ GOMP_offload_unregister (const void *host_table, int target_type, struct gomp_device_descr *devicep = &devices[i]; gomp_mutex_lock (&devicep->lock); if (devicep->type == target_type && devicep->is_initialized) - gomp_unload_image_from_device (devicep, host_table, target_data); + gomp_unload_image_from_device (devicep, version, + host_table, target_data); gomp_mutex_unlock (&devicep->lock); } @@ -848,6 +869,13 @@ GOMP_offload_unregister (const void *host_table, int target_type, gomp_mutex_unlock (®ister_lock); } +void +GOMP_offload_unregister (const void *host_table, int target_type, + const void *target_data) +{ + GOMP_offload_unregister_ver (0, host_table, target_type, target_data); +} + /* This function initializes the target device, specified by DEVICEP. DEVICEP must be locked on entry, and remains locked on return. */ @@ -862,8 +890,9 @@ gomp_init_device (struct gomp_device_descr *devicep) { struct offload_image_descr *image = &offload_images[i]; if (image->type == devicep->type) - gomp_load_image_to_device (devicep, image->host_table, - image->target_data, false); + gomp_load_image_to_device (devicep, image->version, + image->host_table, image->target_data, + false); } devicep->is_initialized = true; @@ -881,7 +910,8 @@ gomp_unload_device (struct gomp_device_descr *devicep) { struct offload_image_descr *image = &offload_images[i]; if (image->type == devicep->type) - gomp_unload_image_from_device (devicep, image->host_table, + gomp_unload_image_from_device (devicep, image->version, + image->host_table, image->target_data); } } @@ -1085,43 +1115,29 @@ gomp_load_plugin_for_device (struct gomp_device_descr *device, const char *plugin_name) { const char *err = NULL, *last_missing = NULL; - int optional_present, optional_total; - - /* Clear any existing error. */ - dlerror (); void *plugin_handle = dlopen (plugin_name, RTLD_LAZY); if (!plugin_handle) - { - err = dlerror (); - goto out; - } + goto dl_fail; /* Check if all required functions are available in the plugin and store - their handlers. */ + their handlers. None of the symbols can legitimately be NULL, + so we don't need to check dlerror all the time. */ #define DLSYM(f) \ - do \ - { \ - device->f##_func = dlsym (plugin_handle, "GOMP_OFFLOAD_" #f); \ - err = dlerror (); \ - if (err != NULL) \ - goto out; \ - } \ - while (0) - /* Similar, but missing functions are not an error. */ -#define DLSYM_OPT(f, n) \ - do \ - { \ - const char *tmp_err; \ - device->f##_func = dlsym (plugin_handle, "GOMP_OFFLOAD_" #n); \ - tmp_err = dlerror (); \ - if (tmp_err == NULL) \ - optional_present++; \ - else \ - last_missing = #n; \ - optional_total++; \ - } \ - while (0) + if (!(device->f##_func = dlsym (plugin_handle, "GOMP_OFFLOAD_" #f))) \ + goto dl_fail + /* Similar, but missing functions are not an error. Return false if + failed, true otherwise. */ +#define DLSYM_OPT(f, n) \ + ((device->f##_func = dlsym (plugin_handle, "GOMP_OFFLOAD_" #n)) \ + || (last_missing = #n, 0)) + + DLSYM (version); + if (device->version_func () != GOMP_VERSION) + { + err = "plugin version mismatch"; + goto fail; + } DLSYM (get_name); DLSYM (get_caps); @@ -1140,53 +1156,57 @@ gomp_load_plugin_for_device (struct gomp_device_descr *device, DLSYM (run); if (device->capabilities & GOMP_OFFLOAD_CAP_OPENACC_200) { - optional_present = optional_total = 0; - DLSYM_OPT (openacc.exec, openacc_parallel); - DLSYM_OPT (openacc.register_async_cleanup, - openacc_register_async_cleanup); - DLSYM_OPT (openacc.async_test, openacc_async_test); - DLSYM_OPT (openacc.async_test_all, openacc_async_test_all); - DLSYM_OPT (openacc.async_wait, openacc_async_wait); - DLSYM_OPT (openacc.async_wait_async, openacc_async_wait_async); - DLSYM_OPT (openacc.async_wait_all, openacc_async_wait_all); - DLSYM_OPT (openacc.async_wait_all_async, openacc_async_wait_all_async); - DLSYM_OPT (openacc.async_set_async, openacc_async_set_async); - DLSYM_OPT (openacc.create_thread_data, openacc_create_thread_data); - DLSYM_OPT (openacc.destroy_thread_data, openacc_destroy_thread_data); - /* Require all the OpenACC handlers if we have - GOMP_OFFLOAD_CAP_OPENACC_200. */ - if (optional_present != optional_total) + if (!DLSYM_OPT (openacc.exec, openacc_parallel) + || !DLSYM_OPT (openacc.register_async_cleanup, + openacc_register_async_cleanup) + || !DLSYM_OPT (openacc.async_test, openacc_async_test) + || !DLSYM_OPT (openacc.async_test_all, openacc_async_test_all) + || !DLSYM_OPT (openacc.async_wait, openacc_async_wait) + || !DLSYM_OPT (openacc.async_wait_async, openacc_async_wait_async) + || !DLSYM_OPT (openacc.async_wait_all, openacc_async_wait_all) + || !DLSYM_OPT (openacc.async_wait_all_async, + openacc_async_wait_all_async) + || !DLSYM_OPT (openacc.async_set_async, openacc_async_set_async) + || !DLSYM_OPT (openacc.create_thread_data, + openacc_create_thread_data) + || !DLSYM_OPT (openacc.destroy_thread_data, + openacc_destroy_thread_data)) { + /* Require all the OpenACC handlers if we have + GOMP_OFFLOAD_CAP_OPENACC_200. */ err = "plugin missing OpenACC handler function"; - goto out; + goto fail; } - optional_present = optional_total = 0; - DLSYM_OPT (openacc.cuda.get_current_device, - openacc_get_current_cuda_device); - DLSYM_OPT (openacc.cuda.get_current_context, - openacc_get_current_cuda_context); - DLSYM_OPT (openacc.cuda.get_stream, openacc_get_cuda_stream); - DLSYM_OPT (openacc.cuda.set_stream, openacc_set_cuda_stream); - /* Make sure all the CUDA functions are there if any of them are. */ - if (optional_present && optional_present != optional_total) + + unsigned cuda = 0; + cuda += DLSYM_OPT (openacc.cuda.get_current_device, + openacc_get_current_cuda_device); + cuda += DLSYM_OPT (openacc.cuda.get_current_context, + openacc_get_current_cuda_context); + cuda += DLSYM_OPT (openacc.cuda.get_stream, openacc_get_cuda_stream); + cuda += DLSYM_OPT (openacc.cuda.set_stream, openacc_set_cuda_stream); + if (cuda && cuda != 4) { + /* Make sure all the CUDA functions are there if any of them are. */ err = "plugin missing OpenACC CUDA handler function"; - goto out; + goto fail; } } #undef DLSYM #undef DLSYM_OPT - out: - if (err != NULL) - { - gomp_error ("while loading %s: %s", plugin_name, err); - if (last_missing) - gomp_error ("missing function was %s", last_missing); - if (plugin_handle) - dlclose (plugin_handle); - } - return err == NULL; + return 1; + + dl_fail: + err = dlerror (); + fail: + gomp_error ("while loading %s: %s", plugin_name, err); + if (last_missing) + gomp_error ("missing function was %s", last_missing); + if (plugin_handle) + dlclose (plugin_handle); + + return 0; } /* This function initializes the runtime needed for offloading. diff --git a/liboffloadmic/ChangeLog b/liboffloadmic/ChangeLog index 73c711587cb..67a3f6aee5d 100644 --- a/liboffloadmic/ChangeLog +++ b/liboffloadmic/ChangeLog @@ -1,3 +1,9 @@ +2015-08-24 Nathan Sidwell + + * plugin/libgomp-plugin-intelmic.cpp (GOMP_OFFLOAD_version): New. + (GOMP_OFFLOAD_load_image): Add version arg and check it. + (GOMP_OFFLOAD_unload_image): Likewise. + 2015-08-24 Thomas Schwinge * plugin/Makefile.am (include_src_dir): Set. diff --git a/liboffloadmic/plugin/libgomp-plugin-intelmic.cpp b/liboffloadmic/plugin/libgomp-plugin-intelmic.cpp index aa2d7c69bcd..fde7d9e3820 100644 --- a/liboffloadmic/plugin/libgomp-plugin-intelmic.cpp +++ b/liboffloadmic/plugin/libgomp-plugin-intelmic.cpp @@ -328,12 +328,26 @@ offload_image (const void *target_image) free (image); } +/* Return the libgomp version number we're compatible with. There is + no requirement for cross-version compatibility. */ + +extern "C" unsigned +GOMP_OFFLOAD_version (void) +{ + return GOMP_VERSION; +} + extern "C" int -GOMP_OFFLOAD_load_image (int device, const void *target_image, - addr_pair **result) +GOMP_OFFLOAD_load_image (int device, const unsigned version, + void *target_image, addr_pair **result) { TRACE ("(device = %d, target_image = %p)", device, target_image); + if (GOMP_VERSION_DEV (version) > GOMP_VERSION_INTEL_MIC) + GOMP_PLUGIN_fatal ("Offload data incompatible with intelmic plugin" + " (expected %u, received %u)", + GOMP_VERSION_INTEL_MIC, GOMP_VERSION_DEV (version)); + /* If target_image is already present in address_table, then there is no need to offload it. */ if (address_table->count (target_image) == 0) @@ -354,8 +368,12 @@ GOMP_OFFLOAD_load_image (int device, const void *target_image, } extern "C" void -GOMP_OFFLOAD_unload_image (int device, const void *target_image) +GOMP_OFFLOAD_unload_image (int device, unsigned version, + const void *target_image) { + if (GOMP_VERSION_DEV (version) > GOMP_VERSION_INTEL_MIC) + return; + TRACE ("(device = %d, target_image = %p)", device, target_image); /* TODO: Currently liboffloadmic doesn't support __offload_unregister_image