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'll commit a version of this to gomp4 branch shortly.

nathan

2015-08-01  Nathan Sidwell  <nat...@codesourcery.com>

	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 (&register_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 (&register_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 (&register_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 (&register_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 <pthread.h>
 #include <cuda.h>
@@ -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 <stdint.h>
 #include <stdlib.h>
@@ -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

Reply via email to