]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
openmp: Use libgomp memory allocation functions with unified shared memory.
authorHafiz Abid Qadeer <abidh@codesourcery.com>
Fri, 11 Mar 2022 12:50:26 +0000 (12:50 +0000)
committerHafiz Abid Qadeer <abidh@codesourcery.com>
Fri, 11 Mar 2022 23:03:59 +0000 (23:03 +0000)
This patches changes calls to malloc/free/calloc/realloc/aligned_alloc and
operator new to memory allocation functions in libgomp with
allocator=ompx_unified_shared_mem_alloc.  This helps existing code to benefit
from the unified shared memory.  The libgomp does the correct thing with all
the mapping constructs and there is no memory copies if the pointer is pointing
to unified shared memory.

We only replace replacable new operator and not the class member or placement new.

Backport of a patch posted at
https://gcc.gnu.org/pipermail/gcc-patches/2022-March/591353.html

gcc/ChangeLog:

* omp-low.c (usm_transform): New function.
(make_pass_usm_transform): Likewise.
(class pass_usm_transform): New.
* passes.def: Add pass_usm_transform.
* tree-pass.h (make_pass_usm_transform): New declaration.

gcc/testsuite/ChangeLog:

* c-c++-common/gomp/usm-2.c: New test.
* c-c++-common/gomp/usm-3.c: New test.
* g++.dg/gomp/usm-1.C: New test.
* g++.dg/gomp/usm-2.C: New test.
* g++.dg/gomp/usm-3.C: New test.
* gfortran.dg/gomp/usm-2.f90: New test.
* gfortran.dg/gomp/usm-3.f90: New test.

libgomp/ChangeLog:

* testsuite/libgomp.c/usm-6.c: New test.
* testsuite/libgomp.c++/usm-1.C: Likewise.

15 files changed:
gcc/ChangeLog.omp
gcc/omp-low.c
gcc/passes.def
gcc/testsuite/ChangeLog.omp
gcc/testsuite/c-c++-common/gomp/usm-2.c [new file with mode: 0644]
gcc/testsuite/c-c++-common/gomp/usm-3.c [new file with mode: 0644]
gcc/testsuite/g++.dg/gomp/usm-1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/gomp/usm-2.C [new file with mode: 0644]
gcc/testsuite/g++.dg/gomp/usm-3.C [new file with mode: 0644]
gcc/testsuite/gfortran.dg/gomp/usm-2.f90 [new file with mode: 0644]
gcc/testsuite/gfortran.dg/gomp/usm-3.f90 [new file with mode: 0644]
gcc/tree-pass.h
libgomp/ChangeLog.omp
libgomp/testsuite/libgomp.c++/usm-1.C [new file with mode: 0644]
libgomp/testsuite/libgomp.c/usm-6.c [new file with mode: 0644]

index 9e0a6f59155d8834c97f5fb08987161e3a2ba654..d740c1988512ae562cf976980d71bab649227e85 100644 (file)
@@ -1,3 +1,14 @@
+2022-03-11  Abid Qadeer  <abidh@codesourcery.com>
+
+       Backport of a patch posted at
+       https://gcc.gnu.org/pipermail/gcc-patches/2022-March/591353.html
+
+       * omp-low.c (usm_transform): New function.
+       (make_pass_usm_transform): Likewise.
+       (class pass_usm_transform): New.
+       * passes.def: Add pass_usm_transform.
+       * tree-pass.h (make_pass_usm_transform): New declaration.
+
 2022-03-10  Andrew Stubbs <ams@codesourcery.com>
 
        Backport of the patch posted at
index 16a986e8f85df2ca1d03267ddf410e08fcfb2c48..2adee3f4caa769eda78e47388764cf414a3bdc26 100644 (file)
@@ -15787,6 +15787,177 @@ make_pass_diagnose_omp_blocks (gcc::context *ctxt)
 {
   return new pass_diagnose_omp_blocks (ctxt);
 }
+
+/* Provide transformation required for using unified shared memory
+   by replacing calls to standard memory allocation functions with
+   function provided by the libgomp.  */
+
+static tree
+usm_transform (gimple_stmt_iterator *gsi_p, bool *,
+              struct walk_stmt_info *wi)
+{
+  gimple *stmt = gsi_stmt (*gsi_p);
+  /* ompx_unified_shared_mem_alloc is 10.  */
+  const unsigned int unified_shared_mem_alloc = 10;
+
+  switch (gimple_code (stmt))
+    {
+    case GIMPLE_CALL:
+      {
+       gcall *gs = as_a <gcall *> (stmt);
+       tree fndecl = gimple_call_fndecl (gs);
+       if (fndecl)
+         {
+           tree allocator = build_int_cst (pointer_sized_int_node,
+                                           unified_shared_mem_alloc);
+           const char *name = IDENTIFIER_POINTER (DECL_NAME (fndecl));
+           if ((strcmp (name, "malloc") == 0)
+                || (fndecl_built_in_p (fndecl, BUILT_IN_NORMAL)
+                    && DECL_FUNCTION_CODE (fndecl) == BUILT_IN_MALLOC)
+                || DECL_IS_REPLACEABLE_OPERATOR_NEW_P (fndecl))
+             {
+                 tree omp_alloc_type
+                   = build_function_type_list (ptr_type_node, size_type_node,
+                                               pointer_sized_int_node,
+                                               NULL_TREE);
+               tree repl = build_fn_decl ("omp_alloc", omp_alloc_type);
+               tree size = gimple_call_arg (gs, 0);
+               gimple *g = gimple_build_call (repl, 2, size, allocator);
+               gimple_call_set_lhs (g, gimple_call_lhs (gs));
+               gimple_set_location (g, gimple_location (stmt));
+               gsi_replace (gsi_p, g, true);
+             }
+           else if (strcmp (name, "aligned_alloc") == 0)
+             {
+               /*  May be we can also use this for new operator with
+                   std::align_val_t parameter.  */
+               tree omp_alloc_type
+                 = build_function_type_list (ptr_type_node, size_type_node,
+                                             size_type_node,
+                                             pointer_sized_int_node,
+                                             NULL_TREE);
+               tree repl = build_fn_decl ("omp_aligned_alloc",
+                                          omp_alloc_type);
+               tree align = gimple_call_arg (gs, 0);
+               tree size = gimple_call_arg (gs, 1);
+               gimple *g = gimple_build_call (repl, 3, align, size,
+                                              allocator);
+               gimple_call_set_lhs (g, gimple_call_lhs (gs));
+               gimple_set_location (g, gimple_location (stmt));
+               gsi_replace (gsi_p, g, true);
+             }
+           else if ((strcmp (name, "calloc") == 0)
+                     || (fndecl_built_in_p (fndecl, BUILT_IN_NORMAL)
+                         && DECL_FUNCTION_CODE (fndecl) == BUILT_IN_CALLOC))
+             {
+               tree omp_calloc_type
+                 = build_function_type_list (ptr_type_node, size_type_node,
+                                             size_type_node,
+                                             pointer_sized_int_node,
+                                             NULL_TREE);
+               tree repl = build_fn_decl ("omp_calloc", omp_calloc_type);
+               tree num = gimple_call_arg (gs, 0);
+               tree size = gimple_call_arg (gs, 1);
+               gimple *g = gimple_build_call (repl, 3, num, size, allocator);
+               gimple_call_set_lhs (g, gimple_call_lhs (gs));
+               gimple_set_location (g, gimple_location (stmt));
+               gsi_replace (gsi_p, g, true);
+             }
+           else if ((strcmp (name, "realloc") == 0)
+                     || (fndecl_built_in_p (fndecl, BUILT_IN_NORMAL)
+                         && DECL_FUNCTION_CODE (fndecl) == BUILT_IN_REALLOC))
+             {
+               tree omp_realloc_type
+                 = build_function_type_list (ptr_type_node, ptr_type_node,
+                                             size_type_node,
+                                             pointer_sized_int_node,
+                                             pointer_sized_int_node,
+                                             NULL_TREE);
+               tree repl = build_fn_decl ("omp_realloc", omp_realloc_type);
+               tree ptr = gimple_call_arg (gs, 0);
+               tree size = gimple_call_arg (gs, 1);
+               gimple *g = gimple_build_call (repl, 4, ptr, size, allocator,
+                                              allocator);
+               gimple_call_set_lhs (g, gimple_call_lhs (gs));
+               gimple_set_location (g, gimple_location (stmt));
+               gsi_replace (gsi_p, g, true);
+             }
+           else  if ((strcmp (name, "free") == 0)
+                      || (fndecl_built_in_p (fndecl, BUILT_IN_NORMAL)
+                          && DECL_FUNCTION_CODE (fndecl) == BUILT_IN_FREE)
+                      || (DECL_IS_OPERATOR_DELETE_P (fndecl)
+                          && DECL_IS_REPLACEABLE_OPERATOR (fndecl)))
+             {
+               tree omp_free_type
+                 = build_function_type_list (void_type_node, ptr_type_node,
+                                             pointer_sized_int_node,
+                                             NULL_TREE);
+               tree repl = build_fn_decl ("omp_free", omp_free_type);
+               tree ptr = gimple_call_arg (gs, 0);
+               gimple *g = gimple_build_call (repl, 2, ptr, allocator);
+               gimple_set_location (g, gimple_location (stmt));
+               gsi_replace (gsi_p, g, true);
+             }
+         }
+      }
+      break;
+
+    default:
+      break;
+    }
+
+  return NULL_TREE;
+}
+
+namespace {
+
+const pass_data pass_data_usm_transform =
+{
+  GIMPLE_PASS, /* type */
+  "usm_transform", /* name */
+  OPTGROUP_OMP, /* optinfo_flags */
+  TV_NONE, /* tv_id */
+  PROP_gimple_any, /* properties_required */
+  0, /* properties_provided */
+  0, /* properties_destroyed */
+  0, /* todo_flags_start */
+  0, /* todo_flags_finish */
+};
+
+class pass_usm_transform : public gimple_opt_pass
+{
+public:
+  pass_usm_transform (gcc::context *ctxt)
+    : gimple_opt_pass (pass_data_usm_transform, ctxt)
+  {}
+
+  /* opt_pass methods: */
+  virtual bool gate (function *)
+  {
+    return (flag_openmp || flag_openmp_simd)
+           && (flag_offload_memory == OFFLOAD_MEMORY_UNIFIED
+               || omp_requires_mask & OMP_REQUIRES_UNIFIED_SHARED_MEMORY);
+  }
+  virtual unsigned int execute (function *)
+  {
+    struct walk_stmt_info wi;
+    gimple_seq body = gimple_body (current_function_decl);
+
+    memset (&wi, 0, sizeof (wi));
+    walk_gimple_seq (body, usm_transform, NULL, &wi);
+
+    return 0;
+  }
+
+}; // class pass_usm_transform
+
+} // anon namespace
+
+gimple_opt_pass *
+make_pass_usm_transform (gcc::context *ctxt)
+{
+  return new pass_usm_transform (ctxt);
+}
 \f
 
 #include "gt-omp-low.h"
index d30442d343d17bcd5c6b7e6371d8e3deb2a447e3..2cf6a4b58476f3f46fa5a4239e9501c01436da87 100644 (file)
@@ -37,6 +37,7 @@ along with GCC; see the file COPYING3.  If not see
   NEXT_PASS (pass_omp_data_optimize);
   NEXT_PASS (pass_omp_oacc_kernels_decompose);
   NEXT_PASS (pass_lower_omp);
+  NEXT_PASS (pass_usm_transform);
   NEXT_PASS (pass_lower_cf);
   NEXT_PASS (pass_lower_tm);
   NEXT_PASS (pass_refactor_eh);
index eefd1cb9e43875343338db0c45d13899118139e3..067133e6b89817aa5c782c89f365191d9dc65374 100644 (file)
@@ -1,3 +1,16 @@
+2022-03-11  Abid Qadeer  <abidh@codesourcery.com>
+
+       Backport of a patch posted at
+       https://gcc.gnu.org/pipermail/gcc-patches/2022-March/591353.html
+
+       * c-c++-common/gomp/usm-2.c: New test.
+       * c-c++-common/gomp/usm-3.c: New test.
+       * g++.dg/gomp/usm-1.C: New test.
+       * g++.dg/gomp/usm-2.C: New test.
+       * g++.dg/gomp/usm-3.C: New test.
+       * gfortran.dg/gomp/usm-2.f90: New test.
+       * gfortran.dg/gomp/usm-3.f90: New test.
+
 2022-03-10  Andrew Stubbs <ams@codesourcery.com>
 
        Backport of the patch posted at
diff --git a/gcc/testsuite/c-c++-common/gomp/usm-2.c b/gcc/testsuite/c-c++-common/gomp/usm-2.c
new file mode 100644 (file)
index 0000000..64dbb6b
--- /dev/null
@@ -0,0 +1,39 @@
+/* { dg-do compile } */
+/* { dg-additional-options "-fdump-tree-usm_transform" } */
+
+#pragma omp requires unified_shared_memory
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void *malloc (__SIZE_TYPE__);
+void *aligned_alloc (__SIZE_TYPE__, __SIZE_TYPE__);
+void *calloc(__SIZE_TYPE__, __SIZE_TYPE__);
+void *realloc(void *, __SIZE_TYPE__);
+void free (void *);
+
+#ifdef __cplusplus
+}
+#endif
+
+void
+foo ()
+{
+  void *p1 = malloc(20);
+  void *p2 = realloc(p1, 30);
+  void *p3 = calloc(4, 15);
+  void *p4 = aligned_alloc(16, 40);
+  free (p2);
+  free (p3);
+  free (p4);
+}
+
+/* { dg-final { scan-tree-dump-times "omp_alloc \\(20, 10\\)" 1 "usm_transform"  } } */
+/* { dg-final { scan-tree-dump-times "omp_realloc \\(.*, 30, 10, 10\\)" 1 "usm_transform"  } } */
+/* { dg-final { scan-tree-dump-times "omp_calloc \\(4, 15, 10\\)" 1 "usm_transform"  } } */
+/* { dg-final { scan-tree-dump-times "omp_aligned_alloc \\(16, 40, 10\\)" 1 "usm_transform"  } } */
+/* { dg-final { scan-tree-dump-times "omp_free" 3 "usm_transform"  } } */
+/* { dg-final { scan-tree-dump-not " free"  "usm_transform"  } } */
+/* { dg-final { scan-tree-dump-not " aligned_alloc"  "usm_transform"  } } */
+/* { dg-final { scan-tree-dump-not " malloc"  "usm_transform"  } } */
diff --git a/gcc/testsuite/c-c++-common/gomp/usm-3.c b/gcc/testsuite/c-c++-common/gomp/usm-3.c
new file mode 100644 (file)
index 0000000..934582e
--- /dev/null
@@ -0,0 +1,37 @@
+/* { dg-do compile } */
+/* { dg-additional-options "-foffload-memory=unified -fdump-tree-usm_transform" } */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void *malloc (__SIZE_TYPE__);
+void *aligned_alloc (__SIZE_TYPE__, __SIZE_TYPE__);
+void *calloc(__SIZE_TYPE__, __SIZE_TYPE__);
+void *realloc(void *, __SIZE_TYPE__);
+void free (void *);
+
+#ifdef __cplusplus
+}
+#endif
+
+void
+foo ()
+{
+  void *p1 = malloc(20);
+  void *p2 = realloc(p1, 30);
+  void *p3 = calloc(4, 15);
+  void *p4 = aligned_alloc(16, 40);
+  free (p2);
+  free (p3);
+  free (p4);
+}
+
+/* { dg-final { scan-tree-dump-times "omp_alloc \\(20, 10\\)" 1 "usm_transform"  } } */
+/* { dg-final { scan-tree-dump-times "omp_realloc \\(.*, 30, 10, 10\\)" 1 "usm_transform"  } } */
+/* { dg-final { scan-tree-dump-times "omp_calloc \\(4, 15, 10\\)" 1 "usm_transform"  } } */
+/* { dg-final { scan-tree-dump-times "omp_aligned_alloc \\(16, 40, 10\\)" 1 "usm_transform"  } } */
+/* { dg-final { scan-tree-dump-times "omp_free" 3 "usm_transform"  } } */
+/* { dg-final { scan-tree-dump-not " free"  "usm_transform"  } } */
+/* { dg-final { scan-tree-dump-not " aligned_alloc"  "usm_transform"  } } */
+/* { dg-final { scan-tree-dump-not " malloc"  "usm_transform"  } } */
diff --git a/gcc/testsuite/g++.dg/gomp/usm-1.C b/gcc/testsuite/g++.dg/gomp/usm-1.C
new file mode 100644 (file)
index 0000000..bd70a81
--- /dev/null
@@ -0,0 +1,32 @@
+// { dg-do compile }
+// { dg-options "-fopenmp -fdump-tree-usm_transform" }
+
+#pragma omp requires unified_shared_memory
+
+struct t1
+{
+  int a;
+  int b;
+};
+
+typedef unsigned char uint8_t;
+
+void
+foo (__SIZE_TYPE__ x, __SIZE_TYPE__ y)
+{
+  uint8_t *p1 = new uint8_t;
+  uint8_t *p2 = new uint8_t[20];
+  t1 *p3 = new t1;
+  t1 *p4 = new t1[y];
+  delete p1;
+  delete p3;
+  delete [] p2;
+  delete [] p4;
+}
+
+/* { dg-final { scan-tree-dump-times "omp_alloc \\(1, 10\\)" 1 "usm_transform"  } } */
+/* { dg-final { scan-tree-dump-times "omp_alloc \\(20, 10\\)" 1 "usm_transform"  } } */
+/* { dg-final { scan-tree-dump-times "omp_alloc" 4 "usm_transform"  } } */
+/* { dg-final { scan-tree-dump-times "omp_free" 4 "usm_transform"  } } */
+/* { dg-final { scan-tree-dump-not "operator new"  "usm_transform"  } } */
+/* { dg-final { scan-tree-dump-not "operator delete"  "usm_transform"  } } */
diff --git a/gcc/testsuite/g++.dg/gomp/usm-2.C b/gcc/testsuite/g++.dg/gomp/usm-2.C
new file mode 100644 (file)
index 0000000..f6ab155
--- /dev/null
@@ -0,0 +1,30 @@
+// { dg-do compile }
+// { dg-options "-fopenmp -foffload-memory=unified -fdump-tree-usm_transform" }
+
+struct t1
+{
+  int a;
+  int b;
+};
+
+typedef unsigned char uint8_t;
+
+void
+foo (__SIZE_TYPE__ x, __SIZE_TYPE__ y)
+{
+  uint8_t *p1 = new uint8_t;
+  uint8_t *p2 = new uint8_t[20];
+  t1 *p3 = new t1;
+  t1 *p4 = new t1[y];
+  delete p1;
+  delete p3;
+  delete [] p2;
+  delete [] p4;
+}
+
+/* { dg-final { scan-tree-dump-times "omp_alloc \\(1, 10\\)" 1 "usm_transform"  } } */
+/* { dg-final { scan-tree-dump-times "omp_alloc \\(20, 10\\)" 1 "usm_transform"  } } */
+/* { dg-final { scan-tree-dump-times "omp_alloc" 4 "usm_transform"  } } */
+/* { dg-final { scan-tree-dump-times "omp_free" 4 "usm_transform"  } } */
+/* { dg-final { scan-tree-dump-not "operator new"  "usm_transform"  } } */
+/* { dg-final { scan-tree-dump-not "operator delete"  "usm_transform"  } } */
diff --git a/gcc/testsuite/g++.dg/gomp/usm-3.C b/gcc/testsuite/g++.dg/gomp/usm-3.C
new file mode 100644 (file)
index 0000000..50ac930
--- /dev/null
@@ -0,0 +1,38 @@
+// { dg-do compile }
+// { dg-options "-fopenmp -fdump-tree-usm_transform" }
+
+#pragma omp requires unified_shared_memory
+
+#include <new>
+
+
+struct X {
+    static void* operator new(std::size_t count)
+    {
+      static char buf[10];
+      return &buf[0];
+    }
+    static void* operator new[](std::size_t count)
+    {
+      static char buf[10];
+      return &buf[0];
+    }
+    static void operator delete(void*)
+    {
+    }
+    static void operator delete[](void*)
+    {
+    }
+};
+void foo() {
+  X* p1 = new X;
+  delete p1;
+  X* p2 = new X[10];
+  delete[] p2;
+  unsigned char buf[24] ;
+  int *p3 = new (buf) int(3);
+  p3[0] = 1;
+}
+
+/* { dg-final { scan-tree-dump-not "omp_alloc"  "usm_transform"  } } */
+/* { dg-final { scan-tree-dump-not "omp_free"  "usm_transform"  } } */
diff --git a/gcc/testsuite/gfortran.dg/gomp/usm-2.f90 b/gcc/testsuite/gfortran.dg/gomp/usm-2.f90
new file mode 100644 (file)
index 0000000..dc77526
--- /dev/null
@@ -0,0 +1,16 @@
+! { dg-do compile }
+! { dg-additional-options "-fdump-tree-usm_transform" }
+
+!$omp requires unified_shared_memory
+end
+
+subroutine foo()
+  implicit none
+  integer, allocatable :: var1
+
+  allocate(var1)
+
+end subroutine
+
+! { dg-final { scan-tree-dump-times "omp_alloc" 1 "usm_transform"  } } 
+! { dg-final { scan-tree-dump-times "omp_free" 1 "usm_transform"  } } 
\ No newline at end of file
diff --git a/gcc/testsuite/gfortran.dg/gomp/usm-3.f90 b/gcc/testsuite/gfortran.dg/gomp/usm-3.f90
new file mode 100644 (file)
index 0000000..7983444
--- /dev/null
@@ -0,0 +1,13 @@
+! { dg-do compile }
+! { dg-additional-options "-foffload-memory=unified -fdump-tree-usm_transform" }
+
+subroutine foo()
+  implicit none
+  integer, allocatable :: var1
+
+  allocate(var1)
+
+end subroutine
+
+! { dg-final { scan-tree-dump-times "omp_alloc" 1 "usm_transform"  } } 
+! { dg-final { scan-tree-dump-times "omp_free" 1 "usm_transform"  } } 
\ No newline at end of file
index f7812c28eae0188158536ad51bc7b7603c584a45..d0ad867ce0a8ca4d788e11d21e9746243c0c8583 100644 (file)
@@ -422,6 +422,7 @@ extern gimple_opt_pass *make_pass_omp_expand_metadirective (gcc::context *ctxt);
 extern gimple_opt_pass *make_pass_lower_omp (gcc::context *ctxt);
 extern gimple_opt_pass *make_pass_omp_data_optimize (gcc::context *ctxt);
 extern gimple_opt_pass *make_pass_diagnose_omp_blocks (gcc::context *ctxt);
+extern gimple_opt_pass *make_pass_usm_transform (gcc::context *ctxt);
 extern gimple_opt_pass *make_pass_expand_omp (gcc::context *ctxt);
 extern gimple_opt_pass *make_pass_expand_omp_ssa (gcc::context *ctxt);
 extern gimple_opt_pass *make_pass_omp_target_link (gcc::context *ctxt);
index 4ee313a1f6bb7385496468fd31b6e13b490b5e1d..7cdb6d44f4c9bbb7a74b3572eecda57477ea319b 100644 (file)
@@ -1,3 +1,11 @@
+2022-03-11  Abid Qadeer  <abidh@codesourcery.com>
+
+       Backport of a patch posted at
+       https://gcc.gnu.org/pipermail/gcc-patches/2022-March/591353.html
+
+       * testsuite/libgomp.c/usm-6.c: New test.
+       * testsuite/libgomp.c++/usm-1.C: Likewise.
+
 2022-03-11  Andrew Stubbs <ams@codesourcery.com>
 
        Backport of the patch posted at
diff --git a/libgomp/testsuite/libgomp.c++/usm-1.C b/libgomp/testsuite/libgomp.c++/usm-1.C
new file mode 100644 (file)
index 0000000..fea25e5
--- /dev/null
@@ -0,0 +1,54 @@
+/* { dg-do run } */
+/* { dg-skip-if "Only valid for nvptx" { ! offload_target_nvptx } } */
+#include <stdint.h>
+
+#pragma omp requires unified_shared_memory
+
+int g1 = 0;
+
+struct s1
+{
+  s1() { a = g1++;}
+  ~s1() { g1--;}
+  int a;
+};
+
+int
+main ()
+{
+  s1 *p1 = new s1;
+  s1 *p2 = new s1[10];
+
+  if (!p1 || !p2 || p1->a != 0)
+    __builtin_abort ();
+
+  for (int i = 0; i < 10; i++)
+    if (p2[i].a != i+1)
+      __builtin_abort ();
+
+  uintptr_t pp1 = (uintptr_t)p1;
+  uintptr_t pp2 = (uintptr_t)p2;
+
+#pragma omp target firstprivate(pp1, pp2)
+    {
+      s1 *t1 = (s1*)pp1;
+      s1 *t2 = (s1*)pp2;
+      if (t1->a != 0)
+       __builtin_abort ();
+
+      for (int i = 0; i < 10; i++)
+       if (t2[i].a != i+1)
+         __builtin_abort ();
+
+      t1->a = 42;
+    }
+
+  if (p1->a != 42)
+    __builtin_abort ();
+
+  delete [] p2;
+  delete p1;
+  if (g1 != 0)
+    __builtin_abort ();
+  return 0;
+}
diff --git a/libgomp/testsuite/libgomp.c/usm-6.c b/libgomp/testsuite/libgomp.c/usm-6.c
new file mode 100644 (file)
index 0000000..d2c828f
--- /dev/null
@@ -0,0 +1,83 @@
+/* { dg-do run } */
+/* { dg-skip-if "Only valid for nvptx" { ! offload_target_nvptx } } */
+
+#include <stdint.h>
+#include <stdlib.h>
+
+/* On old systems, the declaraition may not be present in stdlib.h which
+   will generate a warning.  This function is going to be replaced with
+   omp_aligned_alloc so the purpose of this declaration is to avoid that
+   warning.  */
+void *aligned_alloc(size_t alignment, size_t size);
+
+#pragma omp requires unified_shared_memory
+
+int
+main ()
+{
+  int *a = (int *) malloc(sizeof(int)*2);
+  int *b = (int *) calloc(sizeof(int), 3);
+  int *c = (int *) realloc(NULL, sizeof(int) * 4);
+  int *d = (int *) aligned_alloc(32, sizeof(int));
+  if (!a || !b || !c || !d)
+    __builtin_abort ();
+
+  a[0] = 42;
+  a[1] = 43;
+  b[0] = 52;
+  b[1] = 53;
+  b[2] = 54;
+  c[0] = 62;
+  c[1] = 63;
+  c[2] = 64;
+  c[3] = 65;
+
+  uintptr_t a_p = (uintptr_t)a;
+  uintptr_t b_p = (uintptr_t)b;
+  uintptr_t c_p = (uintptr_t)c;
+  uintptr_t d_p = (uintptr_t)d;
+
+  if (d_p & 31 != 0)
+    __builtin_abort ();
+
+#pragma omp target enter data map(to:a[0:2])
+
+#pragma omp target is_device_ptr(c)
+    {
+      if (a[0] != 42 || a_p != (uintptr_t)a)
+       __builtin_abort ();
+      if (b[0] != 52 || b[2] != 54 || b_p != (uintptr_t)b)
+       __builtin_abort ();
+      if (c[0] != 62 || c[3] != 65 || c_p != (uintptr_t)c)
+       __builtin_abort ();
+      if (d_p != (uintptr_t)d)
+       __builtin_abort ();
+      a[0] = 72;
+      b[0] = 82;
+      c[0] = 92;
+    }
+
+#pragma omp target
+    {
+      if (a[1] != 43 || a_p != (uintptr_t)a)
+       __builtin_abort ();
+      if (b[1] != 53 || b_p != (uintptr_t)b)
+       __builtin_abort ();
+      if (c[1] != 63 || c[2] != 64 || c_p != (uintptr_t)c)
+       __builtin_abort ();
+      a[1] = 73;
+      b[1] = 83;
+      c[1] = 93;
+    }
+
+#pragma omp target exit data map(delete:a[0:2])
+
+  if (a[0] != 72 || a[1] != 73
+      || b[0] != 82 || b[1] != 83
+      || c[0] != 92 || c[1] != 93)
+       __builtin_abort ();
+  free(a);
+  free(b);
+  free(c);
+  return 0;
+}