From patchwork Tue Aug 4 16:17:53 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Thomas Schwinge X-Patchwork-Id: 503696 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id EF4D9140307 for ; Wed, 5 Aug 2015 02:19:07 +1000 (AEST) Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=gcc.gnu.org header.i=@gcc.gnu.org header.b=dY2qJT68; dkim-atps=neutral DomainKey-Signature: a=rsa-sha1; c=nofws; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:from :to:cc:subject:in-reply-to:references:date:message-id :mime-version:content-type; q=dns; s=default; b=ioNJs0OEX8AzrqNW ZeH+FRAFrYvh3Uzc1r06tHMszMRbvKqz772M1WYotmHcYl8WJtTi1WkgX8aSy8yr KX6uYvMB2LgMKBT3e8CA6W6uzIVVamQx/Avsgz8zTWB0l2Xmc91uhxxeo0oLi/rQ TxjAw0FfP7AOI+RwOCIb6w2HkMU= DKIM-Signature: v=1; a=rsa-sha1; c=relaxed; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:from :to:cc:subject:in-reply-to:references:date:message-id :mime-version:content-type; s=default; bh=kXBAwMKw4NixqTJSJFOUH0 Wr4X0=; b=dY2qJT68Bb96QfB87Tqc4CHvjwjZZRxLTukzP5/Ybp8qgUb4vghnUz LN5rNgpmvW4Jtl/kn6Mu8ZWaO+k+R9tVUfs/M0FppQrdeLoeRSGvkUGyZmlcKnXZ 1ydIIEeU/MYyPYFhOTp+wbEnweNP62M5RmAEL6AZfQ8BUX+S/pXPk= Received: (qmail 60707 invoked by alias); 4 Aug 2015 16:19:00 -0000 Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Delivered-To: mailing list gcc-patches@gcc.gnu.org Received: (qmail 60696 invoked by uid 89); 4 Aug 2015 16:18:59 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-0.5 required=5.0 tests=AWL, BAYES_50, KAM_ASCII_DIVIDERS, RCVD_IN_DNSWL_LOW, SPF_PASS autolearn=no version=3.3.2 X-HELO: relay1.mentorg.com Received: from relay1.mentorg.com (HELO relay1.mentorg.com) (192.94.38.131) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Tue, 04 Aug 2015 16:18:54 +0000 Received: from nat-ies.mentorg.com ([192.94.31.2] helo=SVR-IES-FEM-02.mgc.mentorg.com) by relay1.mentorg.com with esmtp id 1ZMevS-0000o7-BG from Thomas_Schwinge@mentor.com ; Tue, 04 Aug 2015 09:18:50 -0700 Received: from feldtkeller.schwinge.homeip.net (137.202.0.76) by SVR-IES-FEM-02.mgc.mentorg.com (137.202.0.106) with Microsoft SMTP Server id 14.3.224.2; Tue, 4 Aug 2015 17:18:04 +0100 From: Thomas Schwinge To: Jakub Jelinek CC: Nathan Sidwell , , GCC Patches Subject: Re: offload data version number In-Reply-To: <55BD5F0F.6040801@acm.org> References: <55AE483D.9050702@acm.org> <55AE637A.8040504@acm.org> <55B23E54.4070504@acm.org> <20150724163016.GT1780@tucnak.redhat.com> <55B26ABE.5000804@acm.org> <55B2916E.5040705@acm.org> <55BB6728.7030607@acm.org> <55BB6BD9.7050305@acm.org> <20150731161011.GE1780@tucnak.redhat.com> <55BD5F0F.6040801@acm.org> User-Agent: Notmuch/0.9-101-g81dad07 (http://notmuchmail.org) Emacs/24.4.1 (i586-pc-linux-gnu) Date: Tue, 4 Aug 2015 18:17:53 +0200 Message-ID: <878u9rm3im.fsf@kepler.schwinge.homeip.net> MIME-Version: 1.0 Hi! Nathan's patch is waiting for trunk approval: On Sat, 1 Aug 2015 20:06:39 -0400, Nathan Sidwell wrote: > On 07/31/15 12:10, Jakub Jelinek wrote: > > > This will hopefully be just GOMP_4.1 instead in the end, but it can > > change when gomp-4_1-branch is merged to trunk, we don't guarantee > > ABI stability at this point. > > Sure. > > > I'd prefer version to go after devicep argument rather than before. > Fixed. > > > And really don't have ver_func vs. unver_func, just a single > > callback that will take the version argument too (again, if possible > > after target_id). > > Fixed (& elsewhere). The patch should be checked for intelmic if possible > (Ilya?). The changes there are very mechanical so I'm not expecting a problem. > > We don't need to make the initial value of GOMP_VERSION non-zero, because the > absence of the GOMP_OFFLOAD_version func will distinguish out of date plugins at > this point. > > > >> + > >> + if (DLSYM_OPT (version, version)) > > > > I'd prefer requiring version always (i.e. DLSYM (version); > > plus the v != GOMP_VERSION checking). > > Fixed. > > ok? I'd found one "infrastructure-class" problem in the libgomp intelmic plugin build, which I addressed on gomp-4_0-branch in r226497, , patch again attached here, for easy reference (applies to trunk as-is): 0001-Fix-intelmic-libgomp-plugin-build.patch. Then, for convenience, I'm also again attaching Nathan's patch: trunk-version-4.patch. Nathan, for the trunk commit, I suggest you simply merge my patch into yours. Grüße, Thomas 2015-08-01 Nathan Sidwell gcc/ * config/nvptx/mkoffload.c (process): Replace GOMP_offload_{,un}register with GOMP_offload_{,un}register_ver. 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 (host_dispatch): Adjust. * 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. * oacc-host.c (host_dispatch): Init version field. liboffloadmic/ * plugin/libgomp-plugin-intelmic.cpp (GOMP_OFFLOAD_version): New. (GOMP_OFFLOAD_load_image): Add version arg and check it. (GOMP_OFFLOAD_unload_image): Likewise. include/ * gomp-constants.h (GOMP_VERSION, GOMP_VERSION_NVIDIA_PTX, GOMP_VERSION_INTEL_MIC): New. (GOMP_VERSION_PACK, GOMP_VERSION_LIB, GOMP_VERSION_DEV): New. Index: gcc/config/nvptx/mkoffload.c =================================================================== --- gcc/config/nvptx/mkoffload.c (revision 226462) +++ gcc/config/nvptx/mkoffload.c (working copy) @@ -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 Index: libgomp/libgomp.map =================================================================== --- libgomp/libgomp.map (revision 226462) +++ libgomp/libgomp.map (working copy) @@ -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; Index: libgomp/target.c =================================================================== --- libgomp/target.c (revision 226462) +++ libgomp/target.c (working copy) @@ -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 *d 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_d /* 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_d 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 go 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 go 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_ 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_ = 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_ 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 *hos 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 *hos 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_des { 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_d { 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 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 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. Index: libgomp/libgomp.h =================================================================== --- libgomp/libgomp.h (revision 226462) +++ libgomp/libgomp.h (working copy) @@ -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); Index: libgomp/plugin/plugin-nvptx.c =================================================================== --- libgomp/plugin/plugin-nvptx.c (revision 226462) +++ libgomp/plugin/plugin-nvptx.c (working copy) @@ -36,6 +36,7 @@ #include "libgomp-plugin.h" #include "oacc-ptx.h" #include "oacc-plugin.h" +#include "gomp-constants.h" #include #include @@ -1644,11 +1645,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; @@ -1661,6 +1671,11 @@ GOMP_OFFLOAD_load_image (int ord, const 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]; @@ -1730,11 +1745,14 @@ GOMP_OFFLOAD_load_image (int ord, const 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) Index: libgomp/plugin/plugin-host.c =================================================================== --- libgomp/plugin/plugin-host.c (revision 226462) +++ libgomp/plugin/plugin-host.c (working copy) @@ -39,6 +39,7 @@ #include "libgomp.h" #include "oacc-int.h" #endif +#include "gomp-constants.h" #include #include @@ -109,8 +110,15 @@ GOMP_OFFLOAD_fini_device (int n __attrib { } +STATIC unsigned +GOMP_OFFLOAD_version (void) +{ + return GOMP_VERSION; +} + STATIC int GOMP_OFFLOAD_load_image (int n __attribute__ ((unused)), + unsigned v __attribute__ ((unused)), const void *t __attribute__ ((unused)), struct addr_pair **r __attribute__ ((unused))) { @@ -119,6 +127,7 @@ GOMP_OFFLOAD_load_image (int n __attribu STATIC void GOMP_OFFLOAD_unload_image (int n __attribute__ ((unused)), + unsigned v __attribute__ ((unused)), const void *t __attribute__ ((unused))) { } Index: libgomp/oacc-host.c =================================================================== --- libgomp/oacc-host.c (revision 226462) +++ libgomp/oacc-host.c (working copy) @@ -45,6 +45,7 @@ static struct gomp_device_descr host_dis .get_num_devices_func = GOMP_OFFLOAD_get_num_devices, .init_device_func = GOMP_OFFLOAD_init_device, .fini_device_func = GOMP_OFFLOAD_fini_device, + .version_func = GOMP_OFFLOAD_version, .load_image_func = GOMP_OFFLOAD_load_image, .unload_image_func = GOMP_OFFLOAD_unload_image, .alloc_func = GOMP_OFFLOAD_alloc, Index: liboffloadmic/plugin/libgomp-plugin-intelmic.cpp =================================================================== --- liboffloadmic/plugin/libgomp-plugin-intelmic.cpp (revision 226462) +++ liboffloadmic/plugin/libgomp-plugin-intelmic.cpp (working copy) @@ -327,12 +327,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) @@ -353,8 +367,12 @@ GOMP_OFFLOAD_load_image (int device, con } 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 Index: include/gomp-constants.h =================================================================== --- include/gomp-constants.h (revision 226462) +++ include/gomp-constants.h (working copy) @@ -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