aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Schwinge <thomas@codesourcery.com>2019-12-09 12:40:36 +0100
committerThomas Schwinge <tschwinge@gcc.gnu.org>2019-12-09 12:40:36 +0100
commit41f36f22f38285fef3b2166a00d4ec446fb96125 (patch)
tree502c8735398818d41c68770da6a248b171a009fe
parent6effebe10be2c53472db9eb573cdeeac312036c1 (diff)
downloadgcc-41f36f22f38285fef3b2166a00d4ec446fb96125.zip
gcc-41f36f22f38285fef3b2166a00d4ec446fb96125.tar.gz
gcc-41f36f22f38285fef3b2166a00d4ec446fb96125.tar.bz2
[PR92511] More testing for OpenACC "present" subarrays
In particular, "subset subarrays". libgomp/ PR libgomp/92511 * testsuite/libgomp.oacc-c-c++-common/copyin-devptr-1.c: Remove this file... * testsuite/libgomp.oacc-c-c++-common/copyin-devptr-2.c: ..., and this file... * testsuite/libgomp.oacc-c-c++-common/lib-22.c: ..., and this file... * testsuite/libgomp.oacc-c-c++-common/lib-30.c: ..., and this file... * testsuite/libgomp.oacc-c-c++-common/subset-subarray-mappings-1-r-p.c: ... with their content moved into, and extended in this new file. * testsuite/libgomp.oacc-c-c++-common/subset-subarray-mappings-1-d-a.c: New file. * testsuite/libgomp.oacc-c-c++-common/subset-subarray-mappings-1-d-p.c: Likewise. * testsuite/libgomp.oacc-c-c++-common/subset-subarray-mappings-1-r-a.c: Likewise. * testsuite/libgomp.oacc-c-c++-common/subset-subarray-mappings-2.c: Likewise. From-SVN: r279122
-rw-r--r--libgomp/ChangeLog20
-rw-r--r--libgomp/testsuite/libgomp.oacc-c-c++-common/copyin-devptr-1.c28
-rw-r--r--libgomp/testsuite/libgomp.oacc-c-c++-common/copyin-devptr-2.c35
-rw-r--r--libgomp/testsuite/libgomp.oacc-c-c++-common/lib-22.c33
-rw-r--r--libgomp/testsuite/libgomp.oacc-c-c++-common/lib-30.c30
-rw-r--r--libgomp/testsuite/libgomp.oacc-c-c++-common/subset-subarray-mappings-1-d-a.c7
-rw-r--r--libgomp/testsuite/libgomp.oacc-c-c++-common/subset-subarray-mappings-1-d-p.c7
-rw-r--r--libgomp/testsuite/libgomp.oacc-c-c++-common/subset-subarray-mappings-1-r-a.c7
-rw-r--r--libgomp/testsuite/libgomp.oacc-c-c++-common/subset-subarray-mappings-1-r-p.c514
-rw-r--r--libgomp/testsuite/libgomp.oacc-c-c++-common/subset-subarray-mappings-2.c115
10 files changed, 670 insertions, 126 deletions
diff --git a/libgomp/ChangeLog b/libgomp/ChangeLog
index 51a00a3..739a76d 100644
--- a/libgomp/ChangeLog
+++ b/libgomp/ChangeLog
@@ -1,5 +1,25 @@
2019-12-09 Thomas Schwinge <thomas@codesourcery.com>
+ PR libgomp/92511
+ * testsuite/libgomp.oacc-c-c++-common/copyin-devptr-1.c: Remove
+ this file...
+ * testsuite/libgomp.oacc-c-c++-common/copyin-devptr-2.c: ..., and
+ this file...
+ * testsuite/libgomp.oacc-c-c++-common/lib-22.c: ..., and this
+ file...
+ * testsuite/libgomp.oacc-c-c++-common/lib-30.c: ..., and this
+ file...
+ * testsuite/libgomp.oacc-c-c++-common/subset-subarray-mappings-1-r-p.c:
+ ... with their content moved into, and extended in this new file.
+ * testsuite/libgomp.oacc-c-c++-common/subset-subarray-mappings-1-d-a.c:
+ New file.
+ * testsuite/libgomp.oacc-c-c++-common/subset-subarray-mappings-1-d-p.c:
+ Likewise.
+ * testsuite/libgomp.oacc-c-c++-common/subset-subarray-mappings-1-r-a.c:
+ Likewise.
+ * testsuite/libgomp.oacc-c-c++-common/subset-subarray-mappings-2.c:
+ Likewise.
+
* testsuite/libgomp.oacc-c-c++-common/map-data-1.c: New file.
PR libgomp/92854
diff --git a/libgomp/testsuite/libgomp.oacc-c-c++-common/copyin-devptr-1.c b/libgomp/testsuite/libgomp.oacc-c-c++-common/copyin-devptr-1.c
deleted file mode 100644
index 7e50f3b..0000000
--- a/libgomp/testsuite/libgomp.oacc-c-c++-common/copyin-devptr-1.c
+++ /dev/null
@@ -1,28 +0,0 @@
-/* { dg-skip-if "" { *-*-* } { "-DACC_MEM_SHARED=1" } } */
-
-#include <openacc.h>
-#include <stdlib.h>
-#include <assert.h>
-#include <stdint.h>
-
-int main (int argc, char* argv[])
-{
- char *myblock = (char *) malloc (1024);
- int i;
- void *dst;
- for (i = 0; i < 1024; i++)
- myblock[i] = i;
- dst = acc_copyin (myblock, 1024);
- for (i = 0; i < 1024; i += 256)
- {
- void *partdst = acc_pcopyin (&myblock[i], 256);
- assert ((uintptr_t) partdst == (uintptr_t) dst + i);
- }
- for (i = 0; i < 1024; i += 256)
- acc_delete (&myblock[i], 256);
- assert (acc_is_present (myblock, 1024));
- acc_delete (myblock, 1024);
- assert (!acc_is_present (myblock, 1024));
- free (myblock);
- return 0;
-}
diff --git a/libgomp/testsuite/libgomp.oacc-c-c++-common/copyin-devptr-2.c b/libgomp/testsuite/libgomp.oacc-c-c++-common/copyin-devptr-2.c
deleted file mode 100644
index 00e7da1..0000000
--- a/libgomp/testsuite/libgomp.oacc-c-c++-common/copyin-devptr-2.c
+++ /dev/null
@@ -1,35 +0,0 @@
-/* { dg-skip-if "" { *-*-* } { "-DACC_MEM_SHARED=1" } } */
-
-#include <openacc.h>
-#include <stdlib.h>
-#include <assert.h>
-#include <stdint.h>
-
-int main (int argc, char* argv[])
-{
- char *block1 = (char *) malloc (1024);
- char *block2 = (char *) malloc (1024);
- char *block3 = (char *) malloc (1024);
- int i;
- void *dst;
- for (i = 0; i < 1024; i++)
- block1[i] = block2[i] = block3[i] = i;
- #pragma acc data copyin(block1[0:1024]) copyin(block2[0:1024]) \
- copyin(block3[0:1024])
- {
- dst = acc_deviceptr (block2);
- for (i = 0; i < 1024; i += 256)
- {
- void *partdst = acc_pcopyin (&block2[i], 256);
- assert ((uintptr_t) partdst == (uintptr_t) dst + i);
- }
- }
- assert (acc_is_present (block2, 1024));
- for (i = 0; i < 1024; i += 256)
- acc_delete (&block2[i], 256);
- assert (!acc_is_present (block2, 1024));
- free (block1);
- free (block2);
- free (block3);
- return 0;
-}
diff --git a/libgomp/testsuite/libgomp.oacc-c-c++-common/lib-22.c b/libgomp/testsuite/libgomp.oacc-c-c++-common/lib-22.c
deleted file mode 100644
index cb32bbc..0000000
--- a/libgomp/testsuite/libgomp.oacc-c-c++-common/lib-22.c
+++ /dev/null
@@ -1,33 +0,0 @@
-/* Exercise acc_copyin and acc_copyout on nvidia targets. */
-
-/* { dg-do run { target openacc_nvidia_accel_selected } } */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <openacc.h>
-
-int
-main (int argc, char **argv)
-{
- const int N = 256;
- int i;
- unsigned char *h;
-
- h = (unsigned char *) malloc (N);
-
- for (i = 0; i < N; i++)
- {
- h[i] = i;
- }
-
- (void) acc_copyin (h, N);
-
- fprintf (stderr, "CheCKpOInT\n");
- acc_copyout (h + 1, N - 1);
-
- free (h);
-
- return 0;
-}
-
-/* { dg-output "CheCKpOInT(\n|\r\n|\r).*" } */
diff --git a/libgomp/testsuite/libgomp.oacc-c-c++-common/lib-30.c b/libgomp/testsuite/libgomp.oacc-c-c++-common/lib-30.c
deleted file mode 100644
index d0e5ffb..0000000
--- a/libgomp/testsuite/libgomp.oacc-c-c++-common/lib-30.c
+++ /dev/null
@@ -1,30 +0,0 @@
-/* Exercise an invalid partial acc_delete on nvidia targets. */
-
-/* { dg-do run { target openacc_nvidia_accel_selected } } */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <openacc.h>
-
-int
-main (int argc, char **argv)
-{
- const int N = 256;
- unsigned char *h;
- void *d;
-
- h = (unsigned char *) malloc (N);
-
- d = acc_create (h, N);
- if (!d)
- abort ();
-
- fprintf (stderr, "CheCKpOInT\n");
- acc_delete (h, N - 2);
-
- free (h);
-
- return 0;
-}
-
-/* { dg-output "CheCKpOInT(\n|\r\n|\r).*" } */
diff --git a/libgomp/testsuite/libgomp.oacc-c-c++-common/subset-subarray-mappings-1-d-a.c b/libgomp/testsuite/libgomp.oacc-c-c++-common/subset-subarray-mappings-1-d-a.c
new file mode 100644
index 0000000..1d168c2
--- /dev/null
+++ b/libgomp/testsuite/libgomp.oacc-c-c++-common/subset-subarray-mappings-1-d-a.c
@@ -0,0 +1,7 @@
+/* Test "subset" subarray mappings
+ { dg-additional-options "-DOPENACC_DIRECTIVES" } using OpenACC directives,
+ { dg-additional-options "-DARRAYS" } using arrays. */
+
+/* { dg-skip-if "" { *-*-* } { "-DACC_MEM_SHARED=1" } } */
+
+#include "subset-subarray-mappings-1-r-p.c"
diff --git a/libgomp/testsuite/libgomp.oacc-c-c++-common/subset-subarray-mappings-1-d-p.c b/libgomp/testsuite/libgomp.oacc-c-c++-common/subset-subarray-mappings-1-d-p.c
new file mode 100644
index 0000000..68ed0ce
--- /dev/null
+++ b/libgomp/testsuite/libgomp.oacc-c-c++-common/subset-subarray-mappings-1-d-p.c
@@ -0,0 +1,7 @@
+/* Test "subset" subarray mappings
+ { dg-additional-options "-DOPENACC_DIRECTIVES" } using OpenACC directives,
+ { dg-additional-options "-DPOINTERS" } using pointers. */
+
+/* { dg-skip-if "" { *-*-* } { "-DACC_MEM_SHARED=1" } } */
+
+#include "subset-subarray-mappings-1-r-p.c"
diff --git a/libgomp/testsuite/libgomp.oacc-c-c++-common/subset-subarray-mappings-1-r-a.c b/libgomp/testsuite/libgomp.oacc-c-c++-common/subset-subarray-mappings-1-r-a.c
new file mode 100644
index 0000000..5c0fd04
--- /dev/null
+++ b/libgomp/testsuite/libgomp.oacc-c-c++-common/subset-subarray-mappings-1-r-a.c
@@ -0,0 +1,7 @@
+/* Test "subset" subarray mappings
+ { dg-additional-options "-DOPENACC_RUNTIME" } using OpenACC Runtime Library routines,
+ { dg-additional-options "-DARRAYS" } using arrays. */
+
+/* { dg-skip-if "" { *-*-* } { "-DACC_MEM_SHARED=1" } } */
+
+#include "subset-subarray-mappings-1-r-p.c"
diff --git a/libgomp/testsuite/libgomp.oacc-c-c++-common/subset-subarray-mappings-1-r-p.c b/libgomp/testsuite/libgomp.oacc-c-c++-common/subset-subarray-mappings-1-r-p.c
new file mode 100644
index 0000000..9b5d83c
--- /dev/null
+++ b/libgomp/testsuite/libgomp.oacc-c-c++-common/subset-subarray-mappings-1-r-p.c
@@ -0,0 +1,514 @@
+/* Test "subset" subarray mappings
+ { dg-additional-options "-DOPENACC_RUNTIME" } using OpenACC Runtime Library routines,
+ { dg-additional-options "-DPOINTERS" } using pointers. */
+
+/* { dg-skip-if "" { *-*-* } { "-DACC_MEM_SHARED=1" } } */
+
+#if OPENACC_RUNTIME
+#elif OPENACC_DIRECTIVES
+#else
+# error
+#endif
+
+#if POINTERS
+#elif ARRAYS
+#else
+# error
+#endif
+
+
+#include <openacc.h>
+#include <acc_prof.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <stdint.h>
+#include <stdbool.h>
+
+
+static bool cb_ev_alloc_expected;
+static size_t cb_ev_alloc_bytes;
+static const void *cb_ev_alloc_device_ptr;
+static void
+cb_ev_alloc (acc_prof_info *prof_info, acc_event_info *event_info, acc_api_info *api_info)
+{
+ assert (cb_ev_alloc_expected);
+ cb_ev_alloc_expected = false;
+
+ cb_ev_alloc_bytes = event_info->data_event.bytes;
+ cb_ev_alloc_device_ptr = event_info->data_event.device_ptr;
+}
+
+static bool cb_ev_free_expected;
+static const void *cb_ev_free_device_ptr;
+static void
+cb_ev_free (acc_prof_info *prof_info, acc_event_info *event_info, acc_api_info *api_info)
+{
+ assert (cb_ev_free_expected);
+ cb_ev_free_expected = false;
+
+ cb_ev_free_device_ptr = event_info->data_event.device_ptr;
+}
+
+
+/* Match the alignment processing that
+ 'libgomp/target.c:gomp_map_vars_internal' is doing; simplified, not
+ considering special alignment requirements of certain data types. */
+
+static size_t
+aligned_size (size_t tgt_size)
+{
+ size_t tgt_align = sizeof (void *);
+ return tgt_size + tgt_align - 1;
+}
+
+static const void *
+aligned_address (const void *tgt_start)
+{
+ size_t tgt_align = sizeof (void *);
+ return (void *) (((uintptr_t) tgt_start + tgt_align - 1) & ~(tgt_align - 1));
+}
+
+
+#define SIZE 1024
+#define SUBSET 32
+
+
+static void
+f1 (void)
+{
+ cb_ev_alloc_expected = false;
+ cb_ev_free_expected = false;
+ acc_prof_register (acc_ev_alloc, cb_ev_alloc, acc_reg);
+ acc_prof_register (acc_ev_free, cb_ev_free, acc_reg);
+
+#if POINTERS
+ char* myblock = (char *) malloc (SIZE);
+#else
+ char myblock[SIZE];
+#endif
+ int i;
+ void *dst;
+ for (i = 0; i < SIZE; i++)
+ myblock[i] = i;
+
+ cb_ev_alloc_expected = true;
+#if OPENACC_RUNTIME
+ dst = acc_copyin (myblock, SIZE);
+#else
+# if POINTERS
+# pragma acc enter data copyin (myblock[0:SIZE])
+# else
+# pragma acc enter data copyin (myblock)
+# endif
+ dst = acc_deviceptr (myblock);
+#endif
+ assert (dst);
+ assert (!cb_ev_alloc_expected);
+ assert (cb_ev_alloc_bytes == aligned_size (SIZE));
+ assert (aligned_address (cb_ev_alloc_device_ptr) == dst);
+ for (i = 0; i < SIZE; i += SUBSET)
+ {
+ void *partdst = acc_deviceptr (&myblock[i]);
+ assert ((uintptr_t) partdst == (uintptr_t) dst + i);
+ assert (acc_hostptr (partdst) == &myblock[i]);
+ }
+ for (i = 0; i < SIZE; i += SUBSET)
+ {
+ void *partdst;
+#if OPENACC_RUNTIME
+ partdst = acc_pcopyin (&myblock[i], SUBSET);
+#else
+# pragma acc enter data pcopyin (myblock[i:SUBSET])
+ partdst = acc_deviceptr (&myblock[i]);
+#endif
+ assert ((uintptr_t) partdst == (uintptr_t) dst + i);
+ }
+ /* Dereference first half. */
+ for (i = 0; i < 512; i += SUBSET)
+ {
+ assert (acc_is_present (&myblock[i], SUBSET));
+ assert (acc_is_present (myblock, SIZE));
+#if OPENACC_RUNTIME
+ acc_delete (&myblock[i], SUBSET);
+#else
+# pragma acc exit data delete (myblock[i:SUBSET])
+#endif
+ assert (acc_is_present (&myblock[i], SUBSET));
+ assert (acc_is_present (myblock, SIZE));
+ }
+ /* Dereference all. */
+#if OPENACC_RUNTIME
+ acc_delete (myblock, SIZE);
+#else
+# if POINTERS
+# pragma acc exit data delete (myblock[0:SIZE])
+# else
+# pragma acc exit data delete (myblock)
+# endif
+#endif
+ /* Expect it's still present. */
+ assert (acc_is_present (myblock, SIZE));
+ /* Dereference second half. */
+ for (i = 512; i < SIZE; i += SUBSET)
+ {
+ bool last = i >= SIZE - SUBSET;
+
+ assert (acc_is_present (&myblock[i], SUBSET));
+ assert (acc_is_present (myblock, SIZE));
+#if 0 //TODO PR92848
+ if (last)
+ cb_ev_free_expected = true;
+#endif
+#if OPENACC_RUNTIME
+ acc_delete (&myblock[i], SUBSET);
+#else
+# pragma acc exit data delete (myblock[i:SUBSET])
+#endif
+#if 0 //TODO PR92848
+ assert (!cb_ev_free_expected);
+ if (last)
+ assert (cb_ev_free_device_ptr == cb_ev_alloc_device_ptr);
+#endif
+ assert (acc_is_present (&myblock[i], SUBSET) != last);
+ assert (acc_is_present (myblock, SIZE) != last);
+ }
+ /* Expect it's all gone now. */
+ for (i = 512; i < SIZE; i += SUBSET)
+ assert (!acc_is_present (&myblock[i], SUBSET));
+ assert (!acc_is_present (myblock, SIZE));
+ assert (!acc_is_present (myblock, 1));
+
+#if POINTERS
+ free (myblock);
+#endif
+
+ acc_prof_unregister (acc_ev_alloc, cb_ev_alloc, acc_reg);
+ acc_prof_unregister (acc_ev_free, cb_ev_free, acc_reg);
+}
+
+
+static void
+f2 (void)
+{
+ cb_ev_alloc_expected = false;
+ cb_ev_free_expected = false;
+ acc_prof_register (acc_ev_alloc, cb_ev_alloc, acc_reg);
+ acc_prof_register (acc_ev_free, cb_ev_free, acc_reg);
+
+#if POINTERS
+ char *block1 = (char *) malloc (SIZE);
+ char *block2 = (char *) malloc (SIZE);
+ char *block3 = (char *) malloc (SIZE);
+#else
+ char block1[SIZE];
+ char block2[SIZE];
+ char block3[SIZE];
+#endif
+ int i;
+ for (i = 0; i < SIZE; i++)
+ block1[i] = block2[i] = block3[i] = i;
+
+ cb_ev_alloc_expected = true;
+#if POINTERS
+# pragma acc data copyin(block1[0:SIZE], block2[0:SIZE], block3[0:SIZE])
+#else
+# pragma acc data copyin(block1, block2, block3)
+#endif
+ {
+ void *block1_d = acc_deviceptr (block1);
+ void *block2_d = acc_deviceptr (block2);
+ void *block3_d = acc_deviceptr (block3);
+ assert (!cb_ev_alloc_expected);
+ /* 'block1', 'block2', 'block3' get mapped in one device memory object, in
+ reverse order. */
+ assert (cb_ev_alloc_bytes == aligned_size (3 * SIZE));
+ assert ((void *) ((uintptr_t) aligned_address (cb_ev_alloc_device_ptr) + 2 * SIZE) == block1_d);
+ assert ((void *) ((uintptr_t) aligned_address (cb_ev_alloc_device_ptr) + 1 * SIZE) == block2_d);
+ assert ((void *) ((uintptr_t) aligned_address (cb_ev_alloc_device_ptr) + 0 * SIZE) == block3_d);
+
+ for (i = 0; i < SIZE; i += SUBSET)
+ {
+ void *block2_part_d;
+#if OPENACC_RUNTIME
+ block2_part_d = acc_pcopyin (&block2[i], SUBSET);
+#else
+# pragma acc enter data pcopyin (block2[i:SUBSET])
+ block2_part_d = acc_deviceptr (&block2[i]);
+#endif
+ assert ((uintptr_t) block2_part_d == (uintptr_t) block2_d + i);
+ }
+ }
+ /* The mappings have been removed, but the device memory object has not yet
+ been 'free'd. */
+ assert (!acc_is_present (block1, SIZE));
+ assert (acc_is_present (block2, SIZE));
+ assert (!acc_is_present (block3, SIZE));
+ for (i = 0; i < SIZE; i += SUBSET)
+ {
+ bool last = i >= SIZE - SUBSET;
+
+ assert (acc_is_present (block2, SIZE));
+ if (last)
+ cb_ev_free_expected = true;
+#if OPENACC_RUNTIME
+ acc_delete (&block2[i], SUBSET);
+#else
+# pragma acc exit data delete (block2[i:SUBSET])
+#endif
+ assert (!cb_ev_free_expected);
+ if (last)
+ assert (cb_ev_free_device_ptr == cb_ev_alloc_device_ptr);
+ }
+ assert (!acc_is_present (block1, SIZE));
+ assert (!acc_is_present (block2, SIZE));
+ assert (!acc_is_present (block3, SIZE));
+
+#if POINTERS
+ free (block1);
+ free (block2);
+ free (block3);
+#endif
+
+ acc_prof_unregister (acc_ev_alloc, cb_ev_alloc, acc_reg);
+ acc_prof_unregister (acc_ev_free, cb_ev_free, acc_reg);
+}
+
+
+static void
+f3 ()
+{
+ cb_ev_alloc_expected = false;
+ cb_ev_free_expected = false;
+ acc_prof_register (acc_ev_alloc, cb_ev_alloc, acc_reg);
+ acc_prof_register (acc_ev_free, cb_ev_free, acc_reg);
+
+#if POINTERS
+ char *h = (char *) malloc (SIZE);
+#else
+ char h[SIZE];
+#endif
+
+ char *d1;
+ cb_ev_alloc_expected = true;
+#if OPENACC_RUNTIME
+ d1 = (char *) acc_present_or_create (h, SIZE);
+#else
+# if POINTERS
+# pragma acc enter data present_or_create (h[0:SIZE])
+# else
+# pragma acc enter data present_or_create (h)
+# endif
+ d1 = (char *) acc_deviceptr (h);
+#endif
+ assert (d1);
+ assert (!cb_ev_alloc_expected);
+ assert (cb_ev_alloc_bytes == aligned_size (SIZE));
+ assert (aligned_address (cb_ev_alloc_device_ptr) == d1);
+ assert (acc_is_present (h, SIZE));
+ assert (acc_is_present (&h[2], SIZE - 2));
+
+ char *d2;
+#if OPENACC_RUNTIME
+ d2 = (char *) acc_present_or_create (&h[2], SIZE - 2);
+#else
+# pragma acc enter data present_or_create (h[2:SIZE - 2])
+ d2 = (char *) acc_deviceptr (&h[2]);
+#endif
+ assert (d2);
+ assert (d1 == d2 - 2);
+ assert (acc_is_present (h, SIZE));
+ assert (acc_is_present (&h[2], SIZE - 2));
+
+ d2 = (char *) acc_deviceptr (&h[2]);
+ assert (d1 == d2 - 2);
+
+#if OPENACC_RUNTIME
+ acc_delete (&h[2], SIZE - 2);
+#else
+# pragma acc exit data delete (h[2:SIZE - 2])
+#endif
+ assert (acc_is_present (h, SIZE));
+ assert (acc_is_present (&h[2], SIZE - 2));
+
+#if 0 //TODO PR92848
+ cb_ev_free_expected = true;
+#endif
+#if OPENACC_RUNTIME
+ acc_delete (h, SIZE);
+#else
+# if POINTERS
+# pragma acc exit data delete (h[0:SIZE])
+# else
+# pragma acc exit data delete (h)
+# endif
+#endif
+#if 0 //TODO PR92848
+ assert (!cb_ev_free_expected);
+ assert (cb_ev_free_device_ptr == cb_ev_alloc_device_ptr);
+#endif
+
+ assert (!acc_is_present (h, SIZE));
+ assert (!acc_is_present (&h[2], SIZE - 2));
+ assert (!acc_is_present (h, 1));
+
+# if POINTERS
+ free (h);
+#endif
+
+ acc_prof_unregister (acc_ev_alloc, cb_ev_alloc, acc_reg);
+ acc_prof_unregister (acc_ev_free, cb_ev_free, acc_reg);
+}
+
+
+/* Based on what used to be 'libgomp.oacc-c-c++-common/lib-22.c'. */
+
+static void
+f_lib_22 (void)
+{
+ cb_ev_alloc_expected = false;
+ cb_ev_free_expected = false;
+ acc_prof_register (acc_ev_alloc, cb_ev_alloc, acc_reg);
+ acc_prof_register (acc_ev_free, cb_ev_free, acc_reg);
+
+ const int c0 = 0;
+ const int c1 = 1;
+
+#if POINTERS
+ char *h = (char *) malloc (SIZE);
+#else
+ char h[SIZE];
+#endif
+
+ memset (h, c0, SIZE);
+ void *d;
+ cb_ev_alloc_expected = true;
+#if OPENACC_RUNTIME
+ d = acc_copyin (h, SIZE);
+#else
+# if POINTERS
+# pragma acc enter data copyin (h[0:SIZE])
+# else
+# pragma acc enter data copyin (h)
+# endif
+ d = acc_deviceptr (h);
+#endif
+ assert (d);
+ assert (!cb_ev_alloc_expected);
+ assert (cb_ev_alloc_bytes == aligned_size (SIZE));
+ assert (aligned_address (cb_ev_alloc_device_ptr) == d);
+ /* Overwrite the local memory. */
+ memset (h, c1, SIZE);
+ /* Now 'copyout' not the whole but only a "subset" subarray, missing one
+ SUBSET at the beginning, and half a SUBSET at the end... */
+#if 0 //TODO PR92848
+ cb_ev_free_expected = true;
+#endif
+#if OPENACC_RUNTIME
+ acc_copyout (h + SUBSET, SIZE - SUBSET - SUBSET / 2);
+#else
+# pragma acc exit data copyout (h[SUBSET:SIZE - SUBSET - SUBSET / 2])
+#endif
+#if 0 //TODO PR92848
+ /* ..., yet, expect the device memory object to be 'free'd... */
+ assert (!cb_ev_free_expected);
+ assert (cb_ev_free_device_ptr == cb_ev_alloc_device_ptr);
+#endif
+ /* ..., and the mapping to be removed... */
+ assert (!acc_is_present (h, SIZE));
+ assert (!acc_is_present (&h[SUBSET], SIZE - SUBSET - SUBSET / 2));
+ assert (!acc_is_present (h, 1));
+ /* ..., but the 'copyout'ed device memory to correspond to just the "subset"
+ subarray. */
+ for (size_t i = 0; i < SIZE; ++i)
+ {
+ if (i < SUBSET)
+ assert (h[i] == c1);
+ else if (i < SIZE - SUBSET / 2)
+ assert (h[i] == c0);
+ else if (i < SIZE)
+ assert (h[i] == c1);
+ }
+
+#if POINTERS
+ free (h);
+#endif
+
+ acc_prof_unregister (acc_ev_alloc, cb_ev_alloc, acc_reg);
+ acc_prof_unregister (acc_ev_free, cb_ev_free, acc_reg);
+}
+
+
+/* Based on what used to be 'libgomp.oacc-c-c++-common/lib-30.c'. */
+
+static void
+f_lib_30 (void)
+{
+ cb_ev_alloc_expected = false;
+ cb_ev_free_expected = false;
+ acc_prof_register (acc_ev_alloc, cb_ev_alloc, acc_reg);
+ acc_prof_register (acc_ev_free, cb_ev_free, acc_reg);
+
+#if POINTERS
+ char *h = (char *) malloc (SIZE);
+#else
+ char h[SIZE];
+#endif
+ memset (h, 0, SIZE);
+
+ void *d;
+ cb_ev_alloc_expected = true;
+#if OPENACC_RUNTIME
+ d = acc_create (h, SIZE);
+#else
+# if POINTERS
+# pragma acc enter data create (h[0:SIZE])
+# else
+# pragma acc enter data create (h)
+# endif
+ d = acc_deviceptr (h);
+#endif
+ assert (d);
+ assert (!cb_ev_alloc_expected);
+ assert (cb_ev_alloc_bytes == aligned_size (SIZE));
+ assert (aligned_address (cb_ev_alloc_device_ptr) == d);
+
+ /* We 'delete' not the whole but only a "subset" subarray... */
+#if 0 //TODO PR92848
+ cb_ev_free_expected = true;
+#endif
+#if OPENACC_RUNTIME
+ acc_delete (h, SIZE - SUBSET);
+#else
+# pragma acc exit data delete (h[0:SIZE - SUBSET])
+#endif
+#if 0 //TODO PR92848
+ /* ..., yet, expect the device memory object to be 'free'd... */
+ assert (!cb_ev_free_expected);
+ assert (cb_ev_free_device_ptr == cb_ev_alloc_device_ptr);
+#endif
+ /* ..., and the mapping to be removed. */
+ assert (!acc_is_present (h, SIZE));
+ assert (!acc_is_present (h, SIZE - SUBSET));
+ assert (!acc_is_present (h, 1));
+
+#if POINTERS
+ free (h);
+#endif
+
+ acc_prof_unregister (acc_ev_alloc, cb_ev_alloc, acc_reg);
+ acc_prof_unregister (acc_ev_free, cb_ev_free, acc_reg);
+}
+
+
+int
+main ()
+{
+ f1 ();
+ f2 ();
+ f3 ();
+ f_lib_22 ();
+ f_lib_30 ();
+
+ return 0;
+}
diff --git a/libgomp/testsuite/libgomp.oacc-c-c++-common/subset-subarray-mappings-2.c b/libgomp/testsuite/libgomp.oacc-c-c++-common/subset-subarray-mappings-2.c
new file mode 100644
index 0000000..f4e18fa
--- /dev/null
+++ b/libgomp/testsuite/libgomp.oacc-c-c++-common/subset-subarray-mappings-2.c
@@ -0,0 +1,115 @@
+/* Test "subset" subarray mappings. */
+
+/* { dg-skip-if "" { *-*-* } { "-DACC_MEM_SHARED=1" } } */
+
+#include <openacc.h>
+#include <acc_prof.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <assert.h>
+
+
+static bool cb_ev_alloc_expected;
+static size_t cb_ev_alloc_bytes;
+static const void *cb_ev_alloc_device_ptr;
+static void
+cb_ev_alloc (acc_prof_info *prof_info, acc_event_info *event_info, acc_api_info *api_info)
+{
+ assert (cb_ev_alloc_expected);
+ cb_ev_alloc_expected = false;
+
+ cb_ev_alloc_bytes = event_info->data_event.bytes;
+ cb_ev_alloc_device_ptr = event_info->data_event.device_ptr;
+}
+
+static bool cb_ev_free_expected;
+static const void *cb_ev_free_device_ptr;
+static void
+cb_ev_free (acc_prof_info *prof_info, acc_event_info *event_info, acc_api_info *api_info)
+{
+ assert (cb_ev_free_expected);
+ cb_ev_free_expected = false;
+
+ cb_ev_free_device_ptr = event_info->data_event.device_ptr;
+}
+
+
+/* Match the alignment processing that
+ 'libgomp/target.c:gomp_map_vars_internal' is doing; simplified, not
+ considering special alignment requirements of certain data types. */
+
+static size_t
+aligned_size (size_t tgt_size)
+{
+ size_t tgt_align = sizeof (void *);
+ return tgt_size + tgt_align - 1;
+}
+
+static const void *
+aligned_address (const void *tgt_start)
+{
+ size_t tgt_align = sizeof (void *);
+ return (void *) (((uintptr_t) tgt_start + tgt_align - 1) & ~(tgt_align - 1));
+}
+
+
+#define SIZE 1024
+
+
+int
+main ()
+{
+ cb_ev_alloc_expected = false;
+ cb_ev_free_expected = false;
+ acc_prof_register (acc_ev_alloc, cb_ev_alloc, acc_reg);
+ acc_prof_register (acc_ev_free, cb_ev_free, acc_reg);
+
+ char *block1 = (char *) malloc (SIZE);
+ char *block2 = (char *) malloc (SIZE);
+ char *block3 = (char *) malloc (SIZE);
+ cb_ev_alloc_expected = true;
+#pragma acc data create (block1[0:SIZE], block2[0:SIZE], block3[0:SIZE])
+ {
+ void *s_block1_d = acc_deviceptr (&block1[1]);
+ void *s_block2_d = acc_deviceptr (&block2[20]);
+ void *s_block3_d = acc_deviceptr (&block3[300]);
+ assert (!cb_ev_alloc_expected);
+ /* 'block1', 'block2', 'block3' get mapped in one device memory object, in
+ reverse order. */
+ assert (cb_ev_alloc_bytes == aligned_size (3 * SIZE));
+ assert ((void *) ((uintptr_t) aligned_address (cb_ev_alloc_device_ptr) + 2 * SIZE + 1) == s_block1_d);
+ assert ((void *) ((uintptr_t) aligned_address (cb_ev_alloc_device_ptr) + 1 * SIZE + 20) == s_block2_d);
+ assert ((void *) ((uintptr_t) aligned_address (cb_ev_alloc_device_ptr) + 0 * SIZE + 300) == s_block3_d);
+
+ void *s_block1_p_d = acc_pcopyin (&block1[1], SIZE - 3);
+ void *s_block2_p_d = acc_pcopyin (&block2[20], SIZE - 33);
+ void *s_block3_p_d = acc_pcopyin (&block3[300], SIZE - 333);
+ assert (s_block1_p_d == s_block1_d);
+ assert (s_block2_p_d == s_block2_d);
+ assert (s_block3_p_d == s_block3_d);
+
+ acc_delete (block1, SIZE);
+ acc_delete (block2, SIZE);
+ acc_delete (block3, SIZE);
+ assert (acc_is_present (block1, SIZE));
+ assert (acc_is_present (block2, SIZE));
+ assert (acc_is_present (block3, SIZE));
+
+ cb_ev_free_expected = true;
+ }
+ assert (!cb_ev_free_expected);
+ assert (cb_ev_free_device_ptr == cb_ev_alloc_device_ptr);
+ assert (!acc_is_present (block1, SIZE));
+ assert (!acc_is_present (block2, SIZE));
+ assert (!acc_is_present (block3, SIZE));
+
+ free (block1);
+ free (block2);
+ free (block3);
+
+ acc_prof_unregister (acc_ev_alloc, cb_ev_alloc, acc_reg);
+ acc_prof_unregister (acc_ev_free, cb_ev_free, acc_reg);
+
+ return 0;
+}