]> git.ipfire.org Git - thirdparty/gcc.git/blobdiff - liboffloadmic/plugin/libgomp-plugin-intelmic.cpp
OpenACC 'acc_get_property' cleanup
[thirdparty/gcc.git] / liboffloadmic / plugin / libgomp-plugin-intelmic.cpp
index 28ddbc39db627aa9d0ced3d0863c21db460469ce..d1678d0514e91e775fff7fe361b861f706b53782 100644 (file)
@@ -1,10 +1,11 @@
 /* Plugin for offload execution on Intel MIC devices.
 
-   Copyright (C) 2014 Free Software Foundation, Inc.
+   Copyright (C) 2014-2016 Free Software Foundation, Inc.
 
    Contributed by Ilya Verbin <ilya.verbin@intel.com>.
 
-   This file is part of the GNU OpenMP Library (libgomp).
+   This file is part of the GNU Offloading and Multi Processing Library
+   (libgomp).
 
    Libgomp is free software; you can redistribute it and/or modify it
    under the terms of the GNU General Public License as published by
 #include <string.h>
 #include <utility>
 #include <vector>
-#include <libgomp_target.h>
+#include <map>
+#include "libgomp-plugin.h"
 #include "compiler_if_host.h"
 #include "main_target_image.h"
+#include "gomp-constants.h"
 
-#define LD_LIBRARY_PATH_ENV    "LD_LIBRARY_PATH"
-#define MIC_LD_LIBRARY_PATH_ENV        "MIC_LD_LIBRARY_PATH"
+#define OFFLOAD_ACTIVE_WAIT_ENV        "OFFLOAD_ACTIVE_WAIT"
 
 #ifdef DEBUG
 #define TRACE(...)                                         \
@@ -52,6 +54,43 @@ fprintf (stderr, "\n");                                          \
 #endif
 
 
+/* Start/end addresses of functions and global variables on a device.  */
+typedef std::vector<addr_pair> AddrVect;
+
+/* Addresses for one image and all devices.  */
+typedef std::vector<AddrVect> DevAddrVect;
+
+/* Addresses for all images and all devices.  */
+typedef std::map<const void *, DevAddrVect> ImgDevAddrMap;
+
+/* Image descriptor needed by __offload_[un]register_image.  */
+struct TargetImageDesc {
+  int64_t size;
+  /* 10 characters is enough for max int value.  */
+  char name[sizeof ("lib0000000000.so")];
+  char data[];
+};
+
+/* Image descriptors, indexed by a pointer obtained from libgomp.  */
+typedef std::map<const void *, TargetImageDesc *> ImgDescMap;
+
+
+/* Total number of available devices.  */
+static int num_devices;
+
+/* Total number of shared libraries with offloading to Intel MIC.  */
+static int num_images;
+
+/* Two dimensional array: one key is a pointer to image,
+   second key is number of device.  Contains a vector of pointer pairs.  */
+static ImgDevAddrMap *address_table;
+
+/* Descriptors of all images, registered in liboffloadmic.  */
+static ImgDescMap *image_descriptors;
+
+/* Thread-safe registration of the main image.  */
+static pthread_once_t main_image_is_registered = PTHREAD_ONCE_INIT;
+
 static VarDesc vd_host2tgt = {
   { 1, 1 },                  /* dst, src                             */
   { 1, 0 },                  /* in, out                              */
@@ -89,107 +128,112 @@ static VarDesc vd_tgt2host = {
 };
 
 
-/* Total number of shared libraries with offloading to Intel MIC.  */
-static int num_libraries;
-
-/* Pointers to the descriptors, containing pointers to host-side tables and to
-   target images.  */
-static std::vector< std::pair<void *, void *> > lib_descrs;
-
-/* Thread-safe registration of the main image.  */
-static pthread_once_t main_image_is_registered = PTHREAD_ONCE_INIT;
-
-
-/* Add path specified in LD_LIBRARY_PATH to MIC_LD_LIBRARY_PATH, which is
-   required by liboffloadmic.  */
 __attribute__((constructor))
 static void
-set_mic_lib_path (void)
+init (void)
 {
-  const char *ld_lib_path = getenv (LD_LIBRARY_PATH_ENV);
-  const char *mic_lib_path = getenv (MIC_LD_LIBRARY_PATH_ENV);
-
-  if (!ld_lib_path)
-    return;
+  const char *active_wait = getenv (OFFLOAD_ACTIVE_WAIT_ENV);
 
-  if (!mic_lib_path)
-    setenv (MIC_LD_LIBRARY_PATH_ENV, ld_lib_path, 1);
-  else
-    {
-      size_t len = strlen (mic_lib_path) + strlen (ld_lib_path) + 2;
-      bool use_alloca = len <= 2048;
-      char *mic_lib_path_new = (char *) (use_alloca ? alloca (len)
-                                                   : malloc (len));
-      if (!mic_lib_path_new)
-       {
-         fprintf (stderr, "%s: Can't allocate memory\n", __FILE__);
-         exit (1);
-       }
+  /* Disable active wait by default to avoid useless CPU usage.  */
+  if (!active_wait)
+    setenv (OFFLOAD_ACTIVE_WAIT_ENV, "0", 0);
 
-      sprintf (mic_lib_path_new, "%s:%s", mic_lib_path, ld_lib_path);
-      setenv (MIC_LD_LIBRARY_PATH_ENV, mic_lib_path_new, 1);
+  address_table = new ImgDevAddrMap;
+  image_descriptors = new ImgDescMap;
+  num_devices = _Offload_number_of_devices ();
+}
 
-      if (!use_alloca)
-       free (mic_lib_path_new);
-    }
+extern "C" const char *
+GOMP_OFFLOAD_get_name (void)
+{
+  const char *res = "intelmic";
+  TRACE ("(): return %s", res);
+  return res;
 }
 
-extern "C" enum offload_target_type
-GOMP_OFFLOAD_get_type (void)
+extern "C" unsigned int
+GOMP_OFFLOAD_get_caps (void)
 {
-  enum offload_target_type res = OFFLOAD_TARGET_TYPE_INTEL_MIC;
-  TRACE ("(): return %d", res);
+  unsigned int res = GOMP_OFFLOAD_CAP_OPENMP_400;
+  TRACE ("(): return %x", res);
   return res;
 }
 
 extern "C" int
-GOMP_OFFLOAD_get_num_devices (void)
+GOMP_OFFLOAD_get_type (void)
 {
-  int res = _Offload_number_of_devices ();
+  enum offload_target_type res = OFFLOAD_TARGET_TYPE_INTEL_MIC;
   TRACE ("(): return %d", res);
   return res;
 }
 
-/* This should be called from every shared library with offloading.  */
-extern "C" void
-GOMP_OFFLOAD_register_image (void *host_table, void *target_image)
+extern "C" int
+GOMP_OFFLOAD_get_num_devices (void)
 {
-  TRACE ("(host_table = %p, target_image = %p)", host_table, target_image);
-  lib_descrs.push_back (std::make_pair (host_table, target_image));
-  num_libraries++;
+  TRACE ("(): return %d", num_devices);
+  return num_devices;
 }
 
-static void
+static bool
 offload (const char *file, uint64_t line, int device, const char *name,
-        int num_vars, VarDesc *vars, VarDesc2 *vars2)
+        int num_vars, VarDesc *vars, const void **async_data)
 {
   OFFLOAD ofld = __offload_target_acquire1 (&device, file, line);
   if (ofld)
-    __offload_offload1 (ofld, name, 0, num_vars, vars, vars2, 0, NULL, NULL);
+    {
+      if (async_data == NULL)
+       return __offload_offload1 (ofld, name, 0, num_vars, vars, NULL, 0,
+                                  NULL, NULL);
+      else
+       {
+         OffloadFlags flags;
+         flags.flags = 0;
+         flags.bits.omp_async = 1;
+         return __offload_offload3 (ofld, name, 0, num_vars, vars, NULL, 0,
+                                    NULL, async_data, 0, NULL, flags, NULL);
+       }
+    }
   else
     {
-      fprintf (stderr, "%s:%d: Offload target acquire failed\n", file, line);
-      exit (1);
+      GOMP_PLUGIN_error ("%s:%d: Offload target acquire failed\n", file, line);
+      return false;
     }
 }
 
 static void
 register_main_image ()
 {
+  /* Do not check the return value, because old versions of liboffloadmic did
+     not have return values.  */
   __offload_register_image (&main_target_image);
+
+  /* liboffloadmic will call GOMP_PLUGIN_target_task_completion when
+     asynchronous task on target is completed.  */
+  __offload_register_task_callback (GOMP_PLUGIN_target_task_completion);
 }
 
-/* Load offload_target_main on target.  */
-extern "C" void
+/* liboffloadmic loads and runs offload_target_main on all available devices
+   during a first call to offload ().  */
+extern "C" bool
 GOMP_OFFLOAD_init_device (int device)
 {
-  TRACE ("");
+  TRACE ("(device = %d)", device);
   pthread_once (&main_image_is_registered, register_main_image);
-  offload (__FILE__, __LINE__, device, "__offload_target_init_proc", 0,
-          NULL, NULL);
+  return offload (__FILE__, __LINE__, device, "__offload_target_init_proc", 0,
+                 NULL, NULL);
 }
 
-static void
+extern "C" bool
+GOMP_OFFLOAD_fini_device (int device)
+{
+  TRACE ("(device = %d)", device);
+
+  /* liboffloadmic will finalize target processes on all available devices.  */
+  __offload_unregister_image (&main_target_image);
+  return true;
+}
+
+static bool
 get_target_table (int device, int &num_funcs, int &num_vars, void **&table)
 {
   VarDesc vd1[2] = { vd_tgt2host, vd_tgt2host };
@@ -197,10 +241,10 @@ get_target_table (int device, int &num_funcs, int &num_vars, void **&table)
   vd1[0].size = sizeof (num_funcs);
   vd1[1].ptr = &num_vars;
   vd1[1].size = sizeof (num_vars);
-  VarDesc2 vd1g[2] = { { "num_funcs", 0 }, { "num_vars", 0 } };
 
-  offload (__FILE__, __LINE__, device, "__offload_target_table_p1", 2,
-          vd1, vd1g);
+  if (!offload (__FILE__, __LINE__, device, "__offload_target_table_p1", 2,
+               vd1, NULL))
+    return false;
 
   int table_size = num_funcs + 2 * num_vars;
   if (table_size > 0)
@@ -211,237 +255,286 @@ get_target_table (int device, int &num_funcs, int &num_vars, void **&table)
       vd2 = vd_tgt2host;
       vd2.ptr = table;
       vd2.size = table_size * sizeof (void *);
-      VarDesc2 vd2g = { "table", 0 };
 
-      offload (__FILE__, __LINE__, device, "__offload_target_table_p2", 1,
-              &vd2, &vd2g);
+      return offload (__FILE__, __LINE__, device, "__offload_target_table_p2",
+                     1, &vd2, NULL);
     }
+  return true;
 }
 
-static void
-load_lib_and_get_table (int device, int lib_num, mapping_table *&table,
-                       int &table_size)
+/* Offload TARGET_IMAGE to all available devices and fill address_table with
+   corresponding target addresses.  */
+
+static bool
+offload_image (const void *target_image)
 {
-  struct TargetImage {
-    int64_t size;
-    /* 10 characters is enough for max int value.  */
-    char name[sizeof ("lib0000000000.so")];
-    char data[];
-  } __attribute__ ((packed));
-
-  void ***host_table_descr = (void ***) lib_descrs[lib_num].first;
-  void **host_func_start = host_table_descr[0];
-  void **host_func_end   = host_table_descr[1];
-  void **host_var_start  = host_table_descr[2];
-  void **host_var_end    = host_table_descr[3];
-
-  void **target_image_descr = (void **) lib_descrs[lib_num].second;
-  void *image_start = target_image_descr[0];
-  void *image_end   = target_image_descr[1];
-
-  TRACE ("() host_table_descr { %p, %p, %p, %p }", host_func_start,
-        host_func_end, host_var_start, host_var_end);
-  TRACE ("() target_image_descr { %p, %p }", image_start, image_end);
+  void *image_start = ((void **) target_image)[0];
+  void *image_end   = ((void **) target_image)[1];
+
+  TRACE ("(target_image = %p { %p, %p })",
+        target_image, image_start, image_end);
 
   int64_t image_size = (uintptr_t) image_end - (uintptr_t) image_start;
-  TargetImage *image
-    = (TargetImage *) malloc (sizeof (int64_t) + sizeof ("lib0000000000.so")
-                             + image_size);
+  TargetImageDesc *image = (TargetImageDesc *) malloc (offsetof (TargetImageDesc, data)
+                                                      + image_size);
   if (!image)
     {
-      fprintf (stderr, "%s: Can't allocate memory\n", __FILE__);
-      exit (1);
+      GOMP_PLUGIN_error ("%s: Can't allocate memory\n", __FILE__);
+      return false;
     }
 
   image->size = image_size;
-  sprintf (image->name, "lib%010d.so", lib_num);
+  sprintf (image->name, "lib%010d.so", num_images++);
   memcpy (image->data, image_start, image->size);
 
   TRACE ("() __offload_register_image %s { %p, %d }",
         image->name, image_start, image->size);
+  /* Do not check the return value, because old versions of liboffloadmic did
+     not have return values.  */
   __offload_register_image (image);
 
-  int tgt_num_funcs = 0;
-  int tgt_num_vars = 0;
-  void **tgt_table = NULL;
-  get_target_table (device, tgt_num_funcs, tgt_num_vars, tgt_table);
-  free (image);
-
-  /* The func table contains only addresses, the var table contains addresses
-     and corresponding sizes.  */
-  int host_num_funcs = host_func_end - host_func_start;
-  int host_num_vars  = (host_var_end - host_var_start) / 2;
-  TRACE ("() host_num_funcs = %d, tgt_num_funcs = %d",
-        host_num_funcs, tgt_num_funcs);
-  TRACE ("() host_num_vars = %d, tgt_num_vars = %d",
-        host_num_vars, tgt_num_vars);
-  if (host_num_funcs != tgt_num_funcs)
+  /* Receive tables for target_image from all devices.  */
+  DevAddrVect dev_table;
+  bool ret = true;
+  for (int dev = 0; dev < num_devices; dev++)
     {
-      fprintf (stderr, "%s: Can't map target functions\n", __FILE__);
-      exit (1);
-    }
-  if (host_num_vars != tgt_num_vars)
-    {
-      fprintf (stderr, "%s: Can't map target variables\n", __FILE__);
-      exit (1);
-    }
+      int num_funcs = 0;
+      int num_vars = 0;
+      void **table = NULL;
 
-  table = (mapping_table *) realloc (table, (table_size + host_num_funcs
-                                            + host_num_vars)
-                                           * sizeof (mapping_table));
-  if (table == NULL)
-    {
-      fprintf (stderr, "%s: Can't allocate memory\n", __FILE__);
-      exit (1);
-    }
+      ret &= get_target_table (dev, num_funcs, num_vars, table);
 
-  for (int i = 0; i < host_num_funcs; i++)
-    {
-      mapping_table t;
-      t.host_start = (uintptr_t) host_func_start[i];
-      t.host_end = t.host_start + 1;
-      t.tgt_start = (uintptr_t) tgt_table[i];
-      t.tgt_end = t.tgt_start + 1;
+      AddrVect curr_dev_table;
+
+      for (int i = 0; i < num_funcs; i++)
+       {
+         addr_pair tgt_addr;
+         tgt_addr.start = (uintptr_t) table[i];
+         tgt_addr.end = tgt_addr.start + 1;
+         TRACE ("() func %d:\t0x%llx..0x%llx", i,
+                tgt_addr.start, tgt_addr.end);
+         curr_dev_table.push_back (tgt_addr);
+       }
 
-      TRACE ("() lib %d, func %d:\t0x%llx -- 0x%llx",
-            lib_num, i, t.host_start, t.tgt_start);
+      for (int i = 0; i < num_vars; i++)
+       {
+         addr_pair tgt_addr;
+         tgt_addr.start = (uintptr_t) table[num_funcs+i*2];
+         tgt_addr.end = tgt_addr.start + (uintptr_t) table[num_funcs+i*2+1];
+         TRACE ("() var %d:\t0x%llx..0x%llx", i, tgt_addr.start, tgt_addr.end);
+         curr_dev_table.push_back (tgt_addr);
+       }
 
-      table[table_size++] = t;
+      dev_table.push_back (curr_dev_table);
+      delete [] table;
     }
 
-  for (int i = 0; i < host_num_vars * 2; i += 2)
+  address_table->insert (std::make_pair (target_image, dev_table));
+  image_descriptors->insert (std::make_pair (target_image, image));
+  return ret;
+}
+
+/* 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 unsigned version,
+                        const void *target_image, addr_pair **result)
+{
+  TRACE ("(device = %d, target_image = %p)", device, target_image);
+
+  if (GOMP_VERSION_DEV (version) > GOMP_VERSION_INTEL_MIC)
     {
-      mapping_table t;
-      t.host_start = (uintptr_t) host_var_start[i];
-      t.host_end = t.host_start + (uintptr_t) host_var_start[i+1];
-      t.tgt_start = (uintptr_t) tgt_table[tgt_num_funcs+i];
-      t.tgt_end = t.tgt_start + (uintptr_t) tgt_table[tgt_num_funcs+i+1];
+      GOMP_PLUGIN_error ("Offload data incompatible with intelmic plugin"
+                        " (expected %u, received %u)",
+                        GOMP_VERSION_INTEL_MIC, GOMP_VERSION_DEV (version));
+      return -1;
+    }
 
-      TRACE ("() lib %d, var %d:\t0x%llx (%d) -- 0x%llx (%d)", lib_num, i/2,
-            t.host_start, t.host_end - t.host_start,
-            t.tgt_start, t.tgt_end - t.tgt_start);
+  /* If target_image is already present in address_table, then there is no need
+     to offload it.  */
+  if (address_table->count (target_image) == 0)
+    {
+      /* If fail, return -1 as error code.  */
+      if (!offload_image (target_image))
+       return -1;
+    }
 
-      table[table_size++] = t;
+  AddrVect *curr_dev_table = &(*address_table)[target_image][device];
+  int table_size = curr_dev_table->size ();
+  addr_pair *table = (addr_pair *) malloc (table_size * sizeof (addr_pair));
+  if (table == NULL)
+    {
+      GOMP_PLUGIN_error ("%s: Can't allocate memory\n", __FILE__);
+      return -1;
     }
 
-  delete [] tgt_table;
+  std::copy (curr_dev_table->begin (), curr_dev_table->end (), table);
+  *result = table;
+  return table_size;
 }
 
-extern "C" int
-GOMP_OFFLOAD_get_table (int device, void *result)
+extern "C" bool
+GOMP_OFFLOAD_unload_image (int device, unsigned version,
+                          const void *target_image)
 {
-  TRACE ("(num_libraries = %d)", num_libraries);
+  if (GOMP_VERSION_DEV (version) > GOMP_VERSION_INTEL_MIC)
+    {
+      GOMP_PLUGIN_error ("Offload data incompatible with intelmic plugin"
+                        " (expected %u, received %u)",
+                        GOMP_VERSION_INTEL_MIC, GOMP_VERSION_DEV (version));
+      return false;
+    }
 
-  mapping_table *table = NULL;
-  int table_size = 0;
+  TRACE ("(device = %d, target_image = %p)", device, target_image);
 
-  for (int i = 0; i < num_libraries; i++)
-    load_lib_and_get_table (device, i, table, table_size);
+  /* liboffloadmic unloads the image from all available devices.  */
+  if (image_descriptors->count (target_image) > 0)
+    {
+      TargetImageDesc *image_desc = (*image_descriptors)[target_image];
+      __offload_unregister_image (image_desc);
+      free (image_desc);
 
-  *(void **) result = table;
-  return table_size;
+      address_table->erase (target_image);
+      image_descriptors->erase (target_image);
+    }
+  return true;
 }
 
 extern "C" void *
 GOMP_OFFLOAD_alloc (int device, size_t size)
 {
-  TRACE ("(size = %d)", size);
+  TRACE ("(device = %d, size = %d)", device, size);
 
   void *tgt_ptr;
-  VarDesc vd1[2] = { vd_host2tgt, vd_tgt2host };
-  vd1[0].ptr = &size;
-  vd1[0].size = sizeof (size);
-  vd1[1].ptr = &tgt_ptr;
-  vd1[1].size = sizeof (void *);
-  VarDesc2 vd1g[2] = { { "size", 0 }, { "tgt_ptr", 0 } };
+  VarDesc vd[2] = { vd_host2tgt, vd_tgt2host };
+  vd[0].ptr = &size;
+  vd[0].size = sizeof (size);
+  vd[1].ptr = &tgt_ptr;
+  vd[1].size = sizeof (void *);
 
-  offload (__FILE__, __LINE__, device, "__offload_target_alloc", 2, vd1, vd1g);
+  if (!offload (__FILE__, __LINE__, device, "__offload_target_alloc", 2,
+               vd, NULL))
+    return NULL;
 
   return tgt_ptr;
 }
 
-extern "C" void
+extern "C" bool
 GOMP_OFFLOAD_free (int device, void *tgt_ptr)
 {
-  TRACE ("(tgt_ptr = %p)", tgt_ptr);
+  TRACE ("(device = %d, tgt_ptr = %p)", device, tgt_ptr);
 
-  VarDesc vd1 = vd_host2tgt;
-  vd1.ptr = &tgt_ptr;
-  vd1.size = sizeof (void *);
-  VarDesc2 vd1g = { "tgt_ptr", 0 };
+  VarDesc vd = vd_host2tgt;
+  vd.ptr = &tgt_ptr;
+  vd.size = sizeof (void *);
 
-  offload (__FILE__, __LINE__, device, "__offload_target_free", 1, &vd1, &vd1g);
+  return offload (__FILE__, __LINE__, device, "__offload_target_free", 1,
+                 &vd, NULL);
 }
 
-extern "C" void *
+extern "C" bool
 GOMP_OFFLOAD_host2dev (int device, void *tgt_ptr, const void *host_ptr,
                       size_t size)
 {
-  TRACE ("(tgt_ptr = %p, host_ptr = %p, size = %d)", tgt_ptr, host_ptr, size);
+  TRACE ("(device = %d, tgt_ptr = %p, host_ptr = %p, size = %d)",
+        device, tgt_ptr, host_ptr, size);
   if (!size)
-    return tgt_ptr;
+    return true;
 
   VarDesc vd1[2] = { vd_host2tgt, vd_host2tgt };
   vd1[0].ptr = &tgt_ptr;
   vd1[0].size = sizeof (void *);
   vd1[1].ptr = &size;
   vd1[1].size = sizeof (size);
-  VarDesc2 vd1g[2] = { { "tgt_ptr", 0 }, { "size", 0 } };
 
-  offload (__FILE__, __LINE__, device, "__offload_target_host2tgt_p1", 2,
-          vd1, vd1g);
+  if (!offload (__FILE__, __LINE__, device, "__offload_target_host2tgt_p1", 2,
+               vd1, NULL))
+    return false;
 
   VarDesc vd2 = vd_host2tgt;
   vd2.ptr = (void *) host_ptr;
   vd2.size = size;
-  VarDesc2 vd2g = { "var", 0 };
-
-  offload (__FILE__, __LINE__, device, "__offload_target_host2tgt_p2", 1,
-          &vd2, &vd2g);
 
-  return tgt_ptr;
+  return offload (__FILE__, __LINE__, device, "__offload_target_host2tgt_p2", 1,
+                 &vd2, NULL);
 }
 
-extern "C" void *
+extern "C" bool
 GOMP_OFFLOAD_dev2host (int device, void *host_ptr, const void *tgt_ptr,
                       size_t size)
 {
-  TRACE ("(host_ptr = %p, tgt_ptr = %p, size = %d)", host_ptr, tgt_ptr, size);
+  TRACE ("(device = %d, host_ptr = %p, tgt_ptr = %p, size = %d)",
+        device, host_ptr, tgt_ptr, size);
   if (!size)
-    return host_ptr;
+    return true;
 
   VarDesc vd1[2] = { vd_host2tgt, vd_host2tgt };
   vd1[0].ptr = &tgt_ptr;
   vd1[0].size = sizeof (void *);
   vd1[1].ptr = &size;
   vd1[1].size = sizeof (size);
-  VarDesc2 vd1g[2] = { { "tgt_ptr", 0 }, { "size", 0 } };
 
-  offload (__FILE__, __LINE__, device, "__offload_target_tgt2host_p1", 2,
-          vd1, vd1g);
+  if (!offload (__FILE__, __LINE__, device, "__offload_target_tgt2host_p1", 2,
+               vd1, NULL))
+    return false;
 
   VarDesc vd2 = vd_tgt2host;
   vd2.ptr = (void *) host_ptr;
   vd2.size = size;
-  VarDesc2 vd2g = { "var", 0 };
 
-  offload (__FILE__, __LINE__, device, "__offload_target_tgt2host_p2", 1,
-          &vd2, &vd2g);
+  return offload (__FILE__, __LINE__, device, "__offload_target_tgt2host_p2", 1,
+                 &vd2, NULL);
+}
 
-  return host_ptr;
+extern "C" bool
+GOMP_OFFLOAD_dev2dev (int device, void *dst_ptr, const void *src_ptr,
+                     size_t size)
+{
+  TRACE ("(device = %d, dst_ptr = %p, src_ptr = %p, size = %d)",
+        device, dst_ptr, src_ptr, size);
+  if (!size)
+    return true;
+
+  VarDesc vd[3] = { vd_host2tgt, vd_host2tgt, vd_host2tgt };
+  vd[0].ptr = &dst_ptr;
+  vd[0].size = sizeof (void *);
+  vd[1].ptr = &src_ptr;
+  vd[1].size = sizeof (void *);
+  vd[2].ptr = &size;
+  vd[2].size = sizeof (size);
+
+  return offload (__FILE__, __LINE__, device, "__offload_target_tgt2tgt", 3,
+                 vd, NULL);
 }
 
 extern "C" void
-GOMP_OFFLOAD_run (int device, void *tgt_fn, void *tgt_vars)
+GOMP_OFFLOAD_async_run (int device, void *tgt_fn, void *tgt_vars,
+                       void **, void *async_data)
 {
-  TRACE ("(tgt_fn = %p, tgt_vars = %p)", tgt_fn, tgt_vars);
+  TRACE ("(device = %d, tgt_fn = %p, tgt_vars = %p, async_data = %p)", device,
+        tgt_fn, tgt_vars, async_data);
 
-  VarDesc vd1[2] = { vd_host2tgt, vd_host2tgt };
-  vd1[0].ptr = &tgt_fn;
-  vd1[0].size = sizeof (void *);
-  vd1[1].ptr = &tgt_vars;
-  vd1[1].size = sizeof (void *);
-  VarDesc2 vd1g[2] = { { "tgt_fn", 0 }, { "tgt_vars", 0 } };
+  VarDesc vd[2] = { vd_host2tgt, vd_host2tgt };
+  vd[0].ptr = &tgt_fn;
+  vd[0].size = sizeof (void *);
+  vd[1].ptr = &tgt_vars;
+  vd[1].size = sizeof (void *);
+
+  offload (__FILE__, __LINE__, device, "__offload_target_run", 2, vd,
+          (const void **) async_data);
+}
+
+extern "C" void
+GOMP_OFFLOAD_run (int device, void *tgt_fn, void *tgt_vars, void **)
+{
+  TRACE ("(device = %d, tgt_fn = %p, tgt_vars = %p)", device, tgt_fn, tgt_vars);
 
-  offload (__FILE__, __LINE__, device, "__offload_target_run", 2, vd1, vd1g);
+  GOMP_OFFLOAD_async_run (device, tgt_fn, tgt_vars, NULL, NULL);
 }