On 10/30/19 11:12 AM, Jakub Jelinek wrote:
I believe it is easier to handle it at the same spot as we do it e.g. for C/C++ pointer attachments (where we create the same clauses regardless of the exact construct and then drop them later), in particular in gimplify_scan_omp_clauses. […]

I concur. Semantically, it is not identical – but I think still okay.

For 'omp exit data', 'to:'/'alloc:' mapping does not make sense and it not handled in libgomp's gomp_exit_data. Hence, I exclude GOMP_MAP_POINTER (dump: 'alloc:') and GOMP_MAP_TO_PSET (dump: 'to:'). – Those are only internally used, hence, user-specified 'alloc:' will get diagnosed.

['delete:'/'release:' in other directives than 'exit data' doesn't make much sense. Other directives accept it but their libgomp function silently ignore it.]

'omp update': The gomp_update function only handles GOMP_MAP_COPY_TO_P and GOMP_MAP_COPY_FROM_P (and silently ignores others). Both macros have !((X) & GOMP_MAP_FLAG_SPECIAL). Hence, we can save a few bytes and avoid calling 'omp update' with GOMP_MAP_POINTER and GOMP_MAP_TO_PSET.

[TO_PSET only appears in gfc_trans_omp_clauses (once); POINTER appears there and in gfc_omp_finish_clause and in c/c-typeck.c's handle_omp_array_sections but only if "(ort != C_ORT_OMP && ort != C_ORT_ACC)".]


I moved trans-openmp.c change to gimplify.c and left the test case unchanged. Then, I bootstrapped on a non-offloading system and regtested it also with a nvptx system.

Tobias

 	gcc/
	* gimplify.c (gimplify_scan_omp_clauses): Remove FE-generated
	GOMP_MAP_TO_PSET and GOMP_MAP_POINTER mapping for 'target update'
	and 'target exit data'.

	libgomp/
	* testsuite/libgomp.fortran/target9.f90: New.

diff --git a/gcc/gimplify.c b/gcc/gimplify.c
index fdf6b695003..12ed3f8eb21 100644
--- a/gcc/gimplify.c
+++ b/gcc/gimplify.c
@@ -8590,6 +8590,17 @@ gimplify_scan_omp_clauses (tree *list_p, gimple_seq *pre_p,
 	    default:
 	      break;
 	    }
+	  /* For Fortran, not only the pointer to the data is mapped but also
+	     the address of the pointer, the array descriptor etc.; for
+	     'exit data' - and in particular for 'delete:' - having an 'alloc:'
+	     does not make sense.  Likewise, for 'update' only transferring the
+	     data itself is needed as the rest has been handled in previous
+	     directives.  */
+	  if ((code == OMP_TARGET_EXIT_DATA || code == OMP_TARGET_UPDATE)
+	      && (OMP_CLAUSE_MAP_KIND (c) == GOMP_MAP_POINTER
+		  || OMP_CLAUSE_MAP_KIND (c) == GOMP_MAP_TO_PSET))
+	    remove = true;
+
 	  if (remove)
 	    break;
 	  if (DECL_P (decl) && outer_ctx && (region_type & ORT_ACC))
diff --git a/libgomp/testsuite/libgomp.fortran/target9.f90 b/libgomp/testsuite/libgomp.fortran/target9.f90
new file mode 100644
index 00000000000..91d60a33307
--- /dev/null
+++ b/libgomp/testsuite/libgomp.fortran/target9.f90
@@ -0,0 +1,123 @@
+! { dg-require-effective-target offload_device_nonshared_as } */
+
+module target_test
+  implicit none (type, external)
+  integer, parameter :: N = 40
+  integer :: sum
+  integer :: var1 = 1
+  integer :: var2 = 2
+
+  !$omp declare target to(D)
+  integer :: D(N) = 0
+contains
+  subroutine enter_data (X)
+    integer :: X(:)
+    !$omp target enter data map(to: var1, var2, X) map(alloc: sum)
+  end subroutine enter_data
+
+  subroutine exit_data_0 (D)
+    integer :: D(N)
+    !$omp target exit data map(delete: D)
+  end subroutine exit_data_0
+
+  subroutine exit_data_1 ()
+    !$omp target exit data map(from: var1)
+  end subroutine exit_data_1
+
+  subroutine exit_data_2 (X)
+    integer :: X(N)
+    !$omp target exit data map(from: var2) map(release: X, sum)
+  end subroutine exit_data_2
+
+  subroutine exit_data_3 (p, idx)
+    integer :: p(:)
+    integer, value :: idx
+    !$omp target exit data map(from: p(idx))
+  end subroutine exit_data_3
+
+  subroutine test_nested ()
+    integer :: X, Y, Z
+    X = 0
+    Y = 0
+    Z = 0
+
+    !$omp target data map(from: X, Y, Z)
+      !$omp target data map(from: X, Y, Z)
+        !$omp target map(from: X, Y, Z)
+          X = 1337
+          Y = 1337
+          Z = 1337
+        !$omp end target
+        if (X /= 0) stop 11
+        if (Y /= 0) stop 12
+        if (Z /= 0) stop 13
+
+        !$omp target exit data map(from: X) map(release: Y)
+        if (X /= 0) stop 14
+        if (Y /= 0) stop 15
+
+        !$omp target exit data map(release: Y) map(delete: Z)
+        if (Y /= 0) stop 16
+        if (Z /= 0) stop 17
+      !$omp end target data
+      if (X /= 1337) stop 18
+      if (Y /= 0) stop 19
+      if (Z /= 0) stop 20
+
+      !$omp target map(from: X)
+        X = 2448
+      !$omp end target
+      if (X /= 2448) stop 21
+      if (Y /= 0) stop 22
+      if (Z /= 0) stop 23
+
+      X = 4896
+    !$omp end target data
+    if (X /= 4896) stop 24
+    if (Y /= 0) stop 25
+    if (Z /= 0) stop 26
+  end subroutine test_nested
+end module target_test
+
+program main
+  use target_test
+  implicit none (type, external)
+
+  integer, allocatable :: X(:)
+  integer, pointer, contiguous :: Y(:)
+
+
+  allocate(X(N), Y(N))
+  X(10) = 10
+  Y(20) = 20
+  call enter_data (X)
+
+  call exit_data_0 (D)  ! This should have no effect on D.
+
+  !$omp target map(alloc: var1, var2, X) map(to: Y) map(always, from: sum)
+    var1 = var1 + X(10)
+    var2 = var2 + Y(20)
+    sum = var1 + var2
+    D(sum) = D(sum) + 1
+  !$omp end target
+
+  if (var1 /= 1) stop 1
+  if (var2 /= 2) stop 2
+  if (sum /= 33) stop 3
+
+  call exit_data_1 ()
+  if (var1 /= 11) stop 4
+  if (var2 /= 2) stop 5
+
+  ! Increase refcount of already mapped X(1:N).
+  !$omp target enter data map(alloc: X(16:17))
+
+  call exit_data_2 (X)
+  if (var2 /= 22) stop 6
+
+  call exit_data_3 (X, 5) ! Unmap X(1:N).
+
+  deallocate (X, Y)
+
+  call test_nested ()
+end program main

Reply via email to