On Mon, Jul 06, 2015 at 22:42:10 +0200, Jakub Jelinek wrote:
> As has been clarified on omp-lang, we actually shouldn't be mapping or
> unmapping the pointer and/or reference, only the array slice itself, except
> in target construct (and even for that it is changing from mapping to
> private + pointer assignment).

I've updated this patch.  make check-target-libgomp passed.


libgomp/
        * target.c (gomp_map_vars_existing): Fix target address for 'always to'
        array sections.
        (gomp_unmap_vars): Decrement k->refcount when it is 1 and
        k->async_refcount is 0.
        (gomp_offload_image_to_device): Set tgt's refcount to infinity.
        (gomp_exit_data): New static function.
        (GOMP_target_enter_exit_data): Support mapping/unmapping.
        * testsuite/libgomp.c/target-11.c: Extend for testing 'always to' array
        sections.
        * testsuite/libgomp.c/target-20.c: New test.


diff --git a/libgomp/target.c b/libgomp/target.c
index ef74d43..ad375c9 100644
--- a/libgomp/target.c
+++ b/libgomp/target.c
@@ -191,7 +191,8 @@ gomp_map_vars_existing (struct gomp_device_descr *devicep, 
splay_tree_key oldn,
 
   if (GOMP_MAP_ALWAYS_TO_P (kind))
     devicep->host2dev_func (devicep->target_id,
-                           (void *) (oldn->tgt->tgt_start + oldn->tgt_offset),
+                           (void *) (oldn->tgt->tgt_start + oldn->tgt_offset
+                                     + newn->host_start - oldn->host_start),
                            (void *) newn->host_start,
                            newn->host_end - newn->host_start);
   if (oldn->refcount != REFCOUNT_INFINITY)
@@ -664,15 +665,18 @@ gomp_unmap_vars (struct target_mem_desc *tgt, bool 
do_copyfrom)
        continue;
 
       bool do_unmap = false;
-      if (k->refcount > 1)
+      if (k->refcount > 1 && k->refcount != REFCOUNT_INFINITY)
+       k->refcount--;
+      else if (k->refcount == 1)
        {
-         if (k->refcount != REFCOUNT_INFINITY)
-           k->refcount--;
+         if (k->async_refcount > 0)
+           k->async_refcount--;
+         else
+           {
+             k->refcount--;
+             do_unmap = true;
+           }
        }
-      else if (k->async_refcount > 0)
-       k->async_refcount--;
-      else
-       do_unmap = true;
 
       if ((do_unmap && do_copyfrom && tgt->list[i].copy_from)
          || tgt->list[i].always_copy_from)
@@ -798,7 +802,7 @@ gomp_offload_image_to_device (struct gomp_device_descr 
*devicep,
   /* Insert host-target address mapping into splay tree.  */
   struct target_mem_desc *tgt = gomp_malloc (sizeof (*tgt));
   tgt->array = gomp_malloc ((num_funcs + num_vars) * sizeof (*tgt->array));
-  tgt->refcount = 1;
+  tgt->refcount = REFCOUNT_INFINITY;
   tgt->tgt_start = 0;
   tgt->tgt_end = 0;
   tgt->to_free = NULL;
@@ -1241,6 +1245,62 @@ GOMP_target_update (int device, const void *unused, 
size_t mapnum,
   gomp_update (devicep, mapnum, hostaddrs, sizes, kinds, false);
 }
 
+static void
+gomp_exit_data (struct gomp_device_descr *devicep, size_t mapnum,
+               void **hostaddrs, size_t *sizes, unsigned short *kinds)
+{
+  const int typemask = 0xff;
+  size_t i;
+  gomp_mutex_lock (&devicep->lock);
+  for (i = 0; i < mapnum; i++)
+    {
+      struct splay_tree_key_s cur_node;
+      unsigned char kind = kinds[i] & typemask;
+      switch (kind)
+       {
+       case GOMP_MAP_FROM:
+       case GOMP_MAP_ALWAYS_FROM:
+       case GOMP_MAP_DELETE:
+       case GOMP_MAP_RELEASE:
+         cur_node.host_start = (uintptr_t) hostaddrs[i];
+         cur_node.host_end = cur_node.host_start + sizes[i];
+         splay_tree_key k = splay_tree_lookup (&devicep->mem_map, &cur_node);
+         if (!k)
+           continue;
+
+         if (k->refcount > 0 && k->refcount != REFCOUNT_INFINITY)
+           k->refcount--;
+         if (kind == GOMP_MAP_DELETE && k->refcount != REFCOUNT_INFINITY)
+           k->refcount = 0;
+
+         if ((kind == GOMP_MAP_FROM && k->refcount == 0)
+             || kind == GOMP_MAP_ALWAYS_FROM)
+           devicep->dev2host_func (devicep->target_id,
+                                   (void *) cur_node.host_start,
+                                   (void *) (k->tgt->tgt_start + k->tgt_offset
+                                             + cur_node.host_start
+                                             - k->host_start),
+                                   cur_node.host_end - cur_node.host_start);
+         if (k->refcount == 0)
+           {
+             splay_tree_remove (&devicep->mem_map, k);
+             if (k->tgt->refcount > 1)
+               k->tgt->refcount--;
+             else
+               gomp_unmap_tgt (k->tgt);
+           }
+
+         break;
+       default:
+         gomp_mutex_unlock (&devicep->lock);
+         gomp_fatal ("GOMP_target_enter_exit_data unhandled kind 0x%.2x",
+                     kind);
+       }
+    }
+
+  gomp_mutex_unlock (&devicep->lock);
+}
+
 void
 GOMP_target_enter_exit_data (int device, size_t mapnum, void **hostaddrs,
                             size_t *sizes, unsigned short *kinds)
@@ -1259,9 +1319,6 @@ GOMP_target_enter_exit_data (int device, size_t mapnum, 
void **hostaddrs,
     {
       unsigned char kind = kinds[i] & typemask;
 
-      if (kind == GOMP_MAP_POINTER || kind == GOMP_MAP_TO_PSET)
-       continue;
-
       if (kind == GOMP_MAP_ALLOC
          || kind == GOMP_MAP_TO
          || kind == GOMP_MAP_ALWAYS_TO)
@@ -1280,13 +1337,20 @@ GOMP_target_enter_exit_data (int device, size_t mapnum, 
void **hostaddrs,
     }
 
   if (is_enter_data)
-    {
-      /* TODO  */
-    }
+    for (i = 0; i < mapnum; i++)
+      {
+       struct target_mem_desc *tgt_var
+         = gomp_map_vars (devicep, 1, &hostaddrs[i], NULL, &sizes[i],
+                          &kinds[i], true, false);
+       tgt_var->refcount--;
+
+       /* If the variable was already mapped, tgt_var is not needed.  Otherwise
+          tgt_var will be freed by gomp_unmap_vars or gomp_exit_data.  */
+       if (tgt_var->refcount == 0)
+         free (tgt_var);
+      }
   else
-    {
-      /* TODO  */
-    }
+    gomp_exit_data (devicep, mapnum, hostaddrs, sizes, kinds);
 }
 
 void
diff --git a/libgomp/testsuite/libgomp.c/target-11.c 
b/libgomp/testsuite/libgomp.c/target-11.c
index b86097a..98882f0 100644
--- a/libgomp/testsuite/libgomp.c/target-11.c
+++ b/libgomp/testsuite/libgomp.c/target-11.c
@@ -9,6 +9,17 @@ void test_array_section (int *p)
 {
   #pragma omp target data map(alloc: p[0:N])
     {
+      int ok = 1;
+      for (int i = 10; i < 10 + 4; i++)
+       p[i] = 997 * i;
+
+      #pragma omp target map(always to:p[10:4]) map(tofrom: ok)
+       for (int i = 10; i < 10 + 4; i++)
+         if (p[i] != 997 * i)
+           ok = 0;
+
+      assert (ok);
+
       #pragma omp target map(always from:p[7:9])
        for (int i = 0; i < N; i++)
          p[i] = i;
diff --git a/libgomp/testsuite/libgomp.c/target-20.c 
b/libgomp/testsuite/libgomp.c/target-20.c
new file mode 100644
index 0000000..ec7e245
--- /dev/null
+++ b/libgomp/testsuite/libgomp.c/target-20.c
@@ -0,0 +1,111 @@
+/* { dg-require-effective-target offload_device } */
+
+#include <stdlib.h>
+#include <assert.h>
+
+#define N 40
+
+int sum;
+int var1 = 1;
+int var2 = 2;
+
+#pragma omp declare target
+int D[N];
+#pragma omp end declare target
+
+void enter_data (int *X)
+{
+  #pragma omp target enter data map(to: var1, var2, X[:N]) map(alloc: sum)
+}
+
+void exit_data_0 (int *D)
+{
+  #pragma omp target exit data map(delete: D[:N])
+}
+
+void exit_data_1 ()
+{
+  #pragma omp target exit data map(from: var1)
+}
+
+void exit_data_2 (int *X)
+{
+  #pragma omp target exit data map(from: var2) map(release: X[:N], sum)
+}
+
+void test_nested ()
+{
+  int X = 0, Y = 0, Z = 0;
+
+  #pragma omp target data map(from: X, Y, Z)
+    {
+      #pragma omp target data map(from: X, Y, Z)
+       {
+         #pragma omp target map(from: X, Y, Z)
+           X = Y = Z = 1337;
+         assert (X == 0);
+         assert (Y == 0);
+         assert (Z == 0);
+
+         #pragma omp target exit data map(from: X) map(release: Y)
+         assert (X == 0);
+         assert (Y == 0);
+
+         #pragma omp target exit data map(release: Y) map(delete: Z)
+         assert (Y == 0);
+         assert (Z == 0);
+       }
+      assert (X == 1337);
+      assert (Y == 0);
+      assert (Z == 0);
+
+      #pragma omp target map(from: X)
+       X = 2448;
+      assert (X == 2448);
+      assert (Y == 0);
+      assert (Z == 0);
+
+      X = 4896;
+    }
+  assert (X == 4896);
+  assert (Y == 0);
+  assert (Z == 0);
+}
+
+int main ()
+{
+  int *X = malloc (N * sizeof (int));
+  int *Y = malloc (N * sizeof (int));
+  X[10] = 10;
+  Y[20] = 20;
+  enter_data (X);
+
+  exit_data_0 (D); /* This should have no effect on D.  */
+
+  #pragma omp target map(alloc: var1, var2, X[:N]) map(to: Y[:N]) \
+    map(always from: sum)
+    {
+      var1 += X[10];
+      var2 += Y[20];
+      sum = var1 + var2;
+      D[sum]++;
+    }
+
+  assert (var1 == 1);
+  assert (var2 == 2);
+  assert (sum == 33);
+
+  exit_data_1 ();
+  assert (var1 == 11);
+  assert (var2 == 2);
+
+  exit_data_2 (X);
+  assert (var2 == 22);
+
+  free (X);
+  free (Y);
+
+  test_nested ();
+
+  return 0;
+}


  -- Ilya

Reply via email to