openmp: Implement allocate clause in omp lowering.
authorJakub Jelinek <jakub@redhat.com>
Thu, 12 Nov 2020 20:38:04 +0000 (21:38 +0100)
committerJakub Jelinek <jakub@redhat.com>
Thu, 12 Nov 2020 20:38:04 +0000 (21:38 +0100)
For now, task/taskloop constructs aren't handled and C/C++ array reductions
and reductions with task or inscan modifiers need further work.
Instead of calling omp_alloc/omp_free (where the former doesn't have
alignment argument and omp_aligned_alloc is 5.1 only feature), this calls
GOMP_alloc/GOMP_free, so that the library can fail if it would fall back
into NULL (exception is zero length allocations).

2020-11-12  Jakub Jelinek  <jakub@redhat.com>

gcc/
* builtin-types.def (BT_FN_PTR_SIZE_SIZE_PTRMODE): New function type.
* omp-builtins.def (BUILT_IN_GOACC_DECLARE): Move earlier.
(BUILT_IN_GOMP_ALLOC, BUILT_IN_GOMP_FREE): New builtins.
* gimplify.c (gimplify_scan_omp_clauses): Force allocator into a
decl if it is not NULL, INTEGER_CST or decl.
(gimplify_adjust_omp_clauses): Clear GOVD_EXPLICIT on explicit clauses
which are being removed.  Remove allocate clauses for variables not seen
if they are private, firstprivate or linear too.  Call
omp_notice_variable on the allocator otherwise.
(gimplify_omp_for): Handle iterator vars mentioned in allocate clauses
similarly to non-is_gimple_reg iterators.
* omp-low.c (struct omp_context): Add allocate_map field.
(delete_omp_context): Delete it.
(scan_sharing_clauses): Fill it from allocate clauses.  Remove it
if mentioned also in shared clause.
(lower_private_allocate): New function.
(lower_rec_input_clauses): Handle allocate clause for privatized
variables, except for task/taskloop, C/C++ array reductions for now
and task/inscan variables.
(lower_send_shared_vars): Don't consider variables in allocate_map
as shared.
* omp-expand.c (expand_omp_for_generic, expand_omp_for_static_nochunk,
expand_omp_for_static_chunk): Use expand_omp_build_assign instead of
gimple_build_assign + gsi_insert_after.
* builtins.c (builtin_fnspec): Handle BUILTIN_GOMP_ALLOC and
BUILTIN_GOMP_FREE.
* tree-ssa-ccp.c (evaluate_stmt): Handle BUILTIN_GOMP_ALLOC.
* tree-ssa-dce.c (mark_stmt_if_obviously_necessary): Handle
BUILTIN_GOMP_ALLOC.
(mark_all_reaching_defs_necessary_1): Handle BUILTIN_GOMP_ALLOC
and BUILTIN_GOMP_FREE.
(propagate_necessity): Likewise.
gcc/fortran/
* f95-lang.c (ATTR_ALLOC_WARN_UNUSED_RESULT_SIZE_2_NOTHROW_LIST):
Define.
(gfc_init_builtin_functions): Add alloc_size and warn_unused_result
attributes to __builtin_GOMP_alloc.
* types.def (BT_PTRMODE): New primitive type.
(BT_FN_VOID_PTR_PTRMODE, BT_FN_PTR_SIZE_SIZE_PTRMODE): New function
types.
libgomp/
* libgomp.map (GOMP_alloc, GOMP_free): Export at GOMP_5.0.1.
* omp.h.in (omp_alloc): Add malloc and alloc_size attributes.
* libgomp_g.h (GOMP_alloc, GOMP_free): Declare.
* allocator.c (omp_aligned_alloc): New for now static function,
add alignment argument and handle it.
(omp_alloc): Reimplement using omp_aligned_alloc.
(GOMP_alloc, GOMP_free): New functions.
(omp_free): Add ialias.
* testsuite/libgomp.c-c++-common/allocate-1.c: New test.
* testsuite/libgomp.c++/allocate-1.C: New test.

16 files changed:
gcc/builtin-types.def
gcc/builtins.c
gcc/fortran/f95-lang.c
gcc/fortran/types.def
gcc/gimplify.c
gcc/omp-builtins.def
gcc/omp-expand.c
gcc/omp-low.c
gcc/tree-ssa-ccp.c
gcc/tree-ssa-dce.c
libgomp/allocator.c
libgomp/libgomp.map
libgomp/libgomp_g.h
libgomp/omp.h.in
libgomp/testsuite/libgomp.c++/allocate-1.C [new file with mode: 0644]
libgomp/testsuite/libgomp.c-c++-common/allocate-1.c [new file with mode: 0644]

index c46b1bc5cbd1fba03b033b8d44ba186570780c3f..4a82ee421bef42154ccd88e52f7a19f48b340c73 100644 (file)
@@ -637,6 +637,8 @@ DEF_FUNCTION_TYPE_3 (BT_FN_VOID_SIZE_SIZE_PTR, BT_VOID, BT_SIZE, BT_SIZE,
 DEF_FUNCTION_TYPE_3 (BT_FN_UINT_UINT_PTR_PTR, BT_UINT, BT_UINT, BT_PTR, BT_PTR)
 DEF_FUNCTION_TYPE_3 (BT_FN_PTR_PTR_CONST_SIZE_BOOL,
                     BT_PTR, BT_PTR, BT_CONST_SIZE, BT_BOOL)
+DEF_FUNCTION_TYPE_3 (BT_FN_PTR_SIZE_SIZE_PTRMODE,
+                    BT_PTR, BT_SIZE, BT_SIZE, BT_PTRMODE)
 
 DEF_FUNCTION_TYPE_4 (BT_FN_SIZE_CONST_PTR_SIZE_SIZE_FILEPTR,
                     BT_SIZE, BT_CONST_PTR, BT_SIZE, BT_SIZE, BT_FILEPTR)
index 4ec1766cffd4f5322026e34021d82b3742c021bb..42c52a1925ec1a6c012ee0f7d4eb08f341345aea 100644 (file)
@@ -13023,6 +13023,7 @@ builtin_fnspec (tree callee)
       case BUILT_IN_MALLOC:
       case BUILT_IN_ALIGNED_ALLOC:
       case BUILT_IN_CALLOC:
+      case BUILT_IN_GOMP_ALLOC:
        return "mC";
       CASE_BUILT_IN_ALLOCA:
        return "mc";
@@ -13044,6 +13045,7 @@ builtin_fnspec (tree callee)
         across it.  */
       case BUILT_IN_STACK_RESTORE:
       case BUILT_IN_FREE:
+      case BUILT_IN_GOMP_FREE:
        return ".co ";
       case BUILT_IN_VA_END:
        return ".cO ";
index 526b7219e4bd835fcfa8de14d672e72f592ad5bb..1a05144ac5682e2fa0517bdcf796cd2a8849855e 100644 (file)
@@ -531,7 +531,7 @@ gfc_builtin_function (tree decl)
   return decl;
 }
 
-/* So far we need just these 7 attribute types.  */
+/* So far we need just these 8 attribute types.  */
 #define ATTR_NULL                      0
 #define ATTR_LEAF_LIST                 (ECF_LEAF)
 #define ATTR_NOTHROW_LEAF_LIST         (ECF_NOTHROW | ECF_LEAF)
@@ -540,6 +540,8 @@ gfc_builtin_function (tree decl)
 #define ATTR_PURE_NOTHROW_LEAF_LIST    (ECF_NOTHROW | ECF_LEAF | ECF_PURE)
 #define ATTR_NOTHROW_LIST              (ECF_NOTHROW)
 #define ATTR_CONST_NOTHROW_LIST                (ECF_NOTHROW | ECF_CONST)
+#define ATTR_ALLOC_WARN_UNUSED_RESULT_SIZE_2_NOTHROW_LIST \
+                                       (ECF_NOTHROW)
 
 static void
 gfc_define_builtin (const char *name, tree type, enum built_in_function code,
@@ -1236,6 +1238,13 @@ gfc_init_builtin_functions (void)
 #undef DEF_GOACC_BUILTIN
 #undef DEF_GOACC_BUILTIN_COMPILER
 #undef DEF_GOMP_BUILTIN
+      tree gomp_alloc = builtin_decl_explicit (BUILT_IN_GOMP_ALLOC);
+      tree two = build_int_cst (integer_type_node, 2);
+      DECL_ATTRIBUTES (gomp_alloc)
+       = tree_cons (get_identifier ("warn_unused_result"), NULL_TREE,
+                    tree_cons (get_identifier ("alloc_size"),
+                               build_tree_list (NULL_TREE, two),
+                               DECL_ATTRIBUTES (gomp_alloc)));
     }
 
   gfc_define_builtin ("__builtin_trap", builtin_types[BT_FN_VOID],
index 7b4925cdd7ef8113f4838346818e4d86a1c24b4f..5736bbab6017a27d538078378ef298980789cea7 100644 (file)
@@ -70,6 +70,7 @@ DEF_PRIMITIVE_TYPE (BT_CONST_VOLATILE_PTR,
                    build_pointer_type
                     (build_qualified_type (void_type_node,
                                          TYPE_QUAL_VOLATILE|TYPE_QUAL_CONST)))
+DEF_PRIMITIVE_TYPE (BT_PTRMODE, (*lang_hooks.types.type_for_mode)(ptr_mode, 0))
 DEF_POINTER_TYPE (BT_PTR_LONG, BT_LONG)
 DEF_POINTER_TYPE (BT_PTR_ULONGLONG, BT_ULONGLONG)
 DEF_POINTER_TYPE (BT_PTR_PTR, BT_PTR)
@@ -117,6 +118,8 @@ DEF_FUNCTION_TYPE_2 (BT_FN_BOOL_SIZE_CONST_VPTR, BT_BOOL, BT_SIZE,
                     BT_CONST_VOLATILE_PTR)
 DEF_FUNCTION_TYPE_2 (BT_FN_BOOL_INT_BOOL, BT_BOOL, BT_INT, BT_BOOL)
 DEF_FUNCTION_TYPE_2 (BT_FN_VOID_UINT_UINT, BT_VOID, BT_UINT, BT_UINT)
+DEF_FUNCTION_TYPE_2 (BT_FN_VOID_PTR_PTRMODE,
+                    BT_VOID, BT_PTR, BT_PTRMODE)
 
 DEF_POINTER_TYPE (BT_PTR_FN_VOID_PTR_PTR, BT_FN_VOID_PTR_PTR)
 
@@ -149,6 +152,8 @@ DEF_FUNCTION_TYPE_3 (BT_FN_VOID_VPTR_I16_INT, BT_VOID, BT_VOLATILE_PTR, BT_I16,
 DEF_FUNCTION_TYPE_3 (BT_FN_VOID_SIZE_SIZE_PTR, BT_VOID, BT_SIZE, BT_SIZE,
                     BT_PTR)
 DEF_FUNCTION_TYPE_3 (BT_FN_UINT_UINT_PTR_PTR, BT_UINT, BT_UINT, BT_PTR, BT_PTR)
+DEF_FUNCTION_TYPE_3 (BT_FN_PTR_SIZE_SIZE_PTRMODE,
+                    BT_PTR, BT_SIZE, BT_SIZE, BT_PTRMODE)
 
 DEF_FUNCTION_TYPE_4 (BT_FN_VOID_OMPFN_PTR_UINT_UINT,
                      BT_VOID, BT_PTR_FN_VOID_PTR, BT_PTR, BT_UINT, BT_UINT)
index d18c43e3e0fe2648a722f18bea8f3afb45897fd8..b861e17d8aead9dce8f782b93383c0cb6932b224 100644 (file)
@@ -9904,10 +9904,12 @@ gimplify_scan_omp_clauses (tree *list_p, gimple_seq *pre_p,
              remove = true;
              break;
            }
+         else if (OMP_CLAUSE_ALLOCATE_ALLOCATOR (c) == NULL_TREE
+                  || (TREE_CODE (OMP_CLAUSE_ALLOCATE_ALLOCATOR (c))
+                      == INTEGER_CST))
+           ;
          else if (code == OMP_TASKLOOP
-                  && OMP_CLAUSE_ALLOCATE_ALLOCATOR (c)
-                  && (TREE_CODE (OMP_CLAUSE_ALLOCATE_ALLOCATOR (c))
-                      != INTEGER_CST))
+                  || !DECL_P (OMP_CLAUSE_ALLOCATE_ALLOCATOR (c)))
            OMP_CLAUSE_ALLOCATE_ALLOCATOR (c)
              = get_initialized_tmp_var (OMP_CLAUSE_ALLOCATE_ALLOCATOR (c),
                                         pre_p, NULL, false);
@@ -10475,6 +10477,8 @@ gimplify_adjust_omp_clauses (gimple_seq *pre_p, gimple_seq body, tree *list_p,
                       && omp_shared_to_firstprivate_optimizable_decl_p (decl))
                omp_mark_stores (gimplify_omp_ctxp->outer_context, decl);
            }
+         else
+           n->value &= ~GOVD_EXPLICIT;
          break;
 
        case OMP_CLAUSE_LASTPRIVATE:
@@ -10774,6 +10778,41 @@ gimplify_adjust_omp_clauses (gimple_seq *pre_p, gimple_seq body, tree *list_p,
              && omp_shared_to_firstprivate_optimizable_decl_p (decl))
            omp_mark_stores (gimplify_omp_ctxp->outer_context, decl);
          break;
+
+       case OMP_CLAUSE_ALLOCATE:
+         decl = OMP_CLAUSE_DECL (c);
+         n = splay_tree_lookup (ctx->variables, (splay_tree_key) decl);
+         if (n != NULL && !(n->value & GOVD_SEEN))
+           {
+             if ((n->value & (GOVD_PRIVATE | GOVD_FIRSTPRIVATE | GOVD_LINEAR))
+                 != 0
+                 && (n->value & (GOVD_REDUCTION | GOVD_LASTPRIVATE)) == 0)
+               remove = true;
+           }
+         if (!remove
+             && OMP_CLAUSE_ALLOCATE_ALLOCATOR (c)
+             && TREE_CODE (OMP_CLAUSE_ALLOCATE_ALLOCATOR (c)) != INTEGER_CST
+             && ((ctx->region_type & (ORT_PARALLEL | ORT_TARGET)) != 0
+                 || (ctx->region_type & ORT_TASKLOOP) == ORT_TASK
+                 || (ctx->region_type & ORT_HOST_TEAMS) == ORT_HOST_TEAMS))
+           {
+             tree allocator = OMP_CLAUSE_ALLOCATE_ALLOCATOR (c);
+             n = splay_tree_lookup (ctx->variables, (splay_tree_key) allocator);
+             if (n == NULL)
+               {
+                 enum omp_clause_default_kind default_kind
+                   = ctx->default_kind;
+                 ctx->default_kind = OMP_CLAUSE_DEFAULT_FIRSTPRIVATE;
+                 omp_notice_variable (ctx, OMP_CLAUSE_ALLOCATE_ALLOCATOR (c),
+                                      true);
+                 ctx->default_kind = default_kind;
+               }
+             else
+               omp_notice_variable (ctx, OMP_CLAUSE_ALLOCATE_ALLOCATOR (c),
+                                    true);
+           }
+         break;
+
        case OMP_CLAUSE_COPYIN:
        case OMP_CLAUSE_COPYPRIVATE:
        case OMP_CLAUSE_IF:
@@ -10823,7 +10862,6 @@ gimplify_adjust_omp_clauses (gimple_seq *pre_p, gimple_seq body, tree *list_p,
        case OMP_CLAUSE_FINALIZE:
        case OMP_CLAUSE_INCLUSIVE:
        case OMP_CLAUSE_EXCLUSIVE:
-       case OMP_CLAUSE_ALLOCATE:
          break;
 
        default:
@@ -11623,6 +11661,15 @@ gimplify_omp_for (tree *expr_p, gimple_seq *pre_p)
   c = omp_find_clause (OMP_FOR_CLAUSES (for_stmt), OMP_CLAUSE_TILE);
   if (c)
     tile = list_length (OMP_CLAUSE_TILE_LIST (c));
+  c = omp_find_clause (OMP_FOR_CLAUSES (for_stmt), OMP_CLAUSE_ALLOCATE);
+  hash_set<tree> *allocate_uids = NULL;
+  if (c)
+    {
+      allocate_uids = new hash_set<tree>;
+      for (; c; c = OMP_CLAUSE_CHAIN (c))
+       if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_ALLOCATE)
+         allocate_uids->add (OMP_CLAUSE_DECL (c));
+    }
   for (i = 0; i < TREE_VEC_LENGTH (OMP_FOR_INIT (for_stmt)); i++)
     {
       t = TREE_VEC_ELT (OMP_FOR_INIT (for_stmt), i);
@@ -11949,12 +11996,13 @@ gimplify_omp_for (tree *expr_p, gimple_seq *pre_p)
         as an iteration counter.  This is valid, since DECL cannot be
         modified in the body of the loop.  Similarly for any iteration vars
         in simd with collapse > 1 where the iterator vars must be
-        lastprivate.  */
+        lastprivate.  And similarly for vars mentioned in allocate clauses.  */
       if (orig_for_stmt != for_stmt)
        var = decl;
       else if (!is_gimple_reg (decl)
               || (ort == ORT_SIMD
-                  && TREE_VEC_LENGTH (OMP_FOR_INIT (for_stmt)) > 1))
+                  && TREE_VEC_LENGTH (OMP_FOR_INIT (for_stmt)) > 1)
+              || (allocate_uids && allocate_uids->contains (decl)))
        {
          struct gimplify_omp_ctx *ctx = gimplify_omp_ctxp;
          /* Make sure omp_add_variable is not called on it prematurely.
@@ -12181,6 +12229,7 @@ gimplify_omp_for (tree *expr_p, gimple_seq *pre_p)
     }
 
   BITMAP_FREE (has_decl_expr);
+  delete allocate_uids;
 
   if (TREE_CODE (orig_for_stmt) == OMP_TASKLOOP
       || (loop_p && orig_for_stmt == for_stmt))
index f461d60e52b8d21faff4f8ff66d72be29aa76993..f9b78ed812fd933b0a4a99b06cdd10ee910ee4e9 100644 (file)
@@ -47,6 +47,8 @@ DEF_GOACC_BUILTIN (BUILT_IN_GOACC_UPDATE, "GOACC_update",
 DEF_GOACC_BUILTIN (BUILT_IN_GOACC_WAIT, "GOACC_wait",
                   BT_FN_VOID_INT_INT_VAR,
                   ATTR_NOTHROW_LIST)
+DEF_GOACC_BUILTIN (BUILT_IN_GOACC_DECLARE, "GOACC_declare",
+                  BT_FN_VOID_INT_SIZE_PTR_PTR_PTR, ATTR_NOTHROW_LIST)
 
 DEF_GOACC_BUILTIN_COMPILER (BUILT_IN_ACC_ON_DEVICE, "acc_on_device",
                            BT_FN_INT_INT, ATTR_CONST_NOTHROW_LEAF_LIST)
@@ -444,5 +446,8 @@ DEF_GOMP_BUILTIN (BUILT_IN_GOMP_TASK_REDUCTION_REMAP,
 DEF_GOMP_BUILTIN (BUILT_IN_GOMP_WORKSHARE_TASK_REDUCTION_UNREGISTER,
                  "GOMP_workshare_task_reduction_unregister",
                  BT_FN_VOID_BOOL, ATTR_NOTHROW_LEAF_LIST)
-DEF_GOACC_BUILTIN (BUILT_IN_GOACC_DECLARE, "GOACC_declare",
-                  BT_FN_VOID_INT_SIZE_PTR_PTR_PTR, ATTR_NOTHROW_LIST)
+DEF_GOMP_BUILTIN (BUILT_IN_GOMP_ALLOC,
+                 "GOMP_alloc", BT_FN_PTR_SIZE_SIZE_PTRMODE,
+                 ATTR_ALLOC_WARN_UNUSED_RESULT_SIZE_2_NOTHROW_LIST)
+DEF_GOMP_BUILTIN (BUILT_IN_GOMP_FREE,
+                 "GOMP_free", BT_FN_VOID_PTR_PTRMODE, ATTR_NOTHROW_LEAF_LIST)
index 6583c88e2765b533aa4c26f42894a1ec6f86b313..ddca3d33bdd3fbadcb7af9308a9a2dddf3de7343 100644 (file)
@@ -4255,8 +4255,7 @@ expand_omp_for_generic (struct omp_region *region,
                           : POINTER_PLUS_EXPR, TREE_TYPE (t), v, a);
          t = force_gimple_operand_gsi (&gsi, t, true, NULL_TREE,
                                        false, GSI_CONTINUE_LINKING);
-         assign_stmt = gimple_build_assign (dest, t);
-         gsi_insert_after (&gsi, assign_stmt, GSI_CONTINUE_LINKING);
+         expand_omp_build_assign (&gsi, dest, t, true);
        }
   if (fd->collapse > 1)
     expand_omp_for_init_vars (fd, &gsi, counts, NULL, inner_stmt, startvar);
@@ -5250,8 +5249,7 @@ expand_omp_for_static_nochunk (struct omp_region *region,
                           : POINTER_PLUS_EXPR, TREE_TYPE (t), t, a);
          t = force_gimple_operand_gsi (&gsi, t, true, NULL_TREE,
                                        false, GSI_CONTINUE_LINKING);
-         assign_stmt = gimple_build_assign (dest, t);
-         gsi_insert_after (&gsi, assign_stmt, GSI_CONTINUE_LINKING);
+         expand_omp_build_assign (&gsi, dest, t, true);
        }
   if (fd->collapse > 1)
     {
@@ -5974,8 +5972,7 @@ expand_omp_for_static_chunk (struct omp_region *region,
                           : POINTER_PLUS_EXPR, TREE_TYPE (t), v, a);
          t = force_gimple_operand_gsi (&gsi, t, true, NULL_TREE,
                                        false, GSI_CONTINUE_LINKING);
-         assign_stmt = gimple_build_assign (dest, t);
-         gsi_insert_after (&gsi, assign_stmt, GSI_CONTINUE_LINKING);
+         expand_omp_build_assign (&gsi, dest, t, true);
        }
   if (fd->collapse > 1)
     expand_omp_for_init_vars (fd, &gsi, counts, NULL, inner_stmt, startvar);
index 83ca5fc23e0471da5a5776c0871203e5726c0732..ed805e2e6d2af97b28eb9c9d82dc2a03775641a9 100644 (file)
@@ -126,6 +126,10 @@ struct omp_context
      corresponding tracking loop iteration variables.  */
   hash_map<tree, tree> *lastprivate_conditional_map;
 
+  /* And a hash map from the allocate variables to their corresponding
+     allocators.  */
+  hash_map<tree, tree> *allocate_map;
+
   /* A tree_list of the reduction clauses in this context. This is
     only used for checking the consistency of OpenACC reduction
     clauses in scan_omp_for and is not guaranteed to contain a valid
@@ -1043,6 +1047,7 @@ delete_omp_context (splay_tree_value value)
     }
 
   delete ctx->lastprivate_conditional_map;
+  delete ctx->allocate_map;
 
   XDELETE (ctx);
 }
@@ -1114,6 +1119,22 @@ scan_sharing_clauses (tree clauses, omp_context *ctx)
   tree c, decl;
   bool scan_array_reductions = false;
 
+  for (c = clauses; c; c = OMP_CLAUSE_CHAIN (c))
+    if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_ALLOCATE
+       && (OMP_CLAUSE_ALLOCATE_ALLOCATOR (c) == NULL_TREE
+           /* omp_default_mem_alloc is 1 */
+           || !integer_onep (OMP_CLAUSE_ALLOCATE_ALLOCATOR (c))))
+      {
+       if (is_task_ctx (ctx))
+         continue; /* For now.  */
+       if (ctx->allocate_map == NULL)
+         ctx->allocate_map = new hash_map<tree, tree>;
+       ctx->allocate_map->put (OMP_CLAUSE_DECL (c),
+                               OMP_CLAUSE_ALLOCATE_ALLOCATOR (c)
+                               ? OMP_CLAUSE_ALLOCATE_ALLOCATOR (c)
+                               : integer_zero_node);
+      }
+
   for (c = clauses; c; c = OMP_CLAUSE_CHAIN (c))
     {
       bool by_ref;
@@ -1130,6 +1151,8 @@ scan_sharing_clauses (tree clauses, omp_context *ctx)
 
        case OMP_CLAUSE_SHARED:
          decl = OMP_CLAUSE_DECL (c);
+         if (ctx->allocate_map && ctx->allocate_map->get (decl))
+           ctx->allocate_map->remove (decl);
          /* Ignore shared directives in teams construct inside of
             target construct.  */
          if (gimple_code (ctx->stmt) == GIMPLE_OMP_TEAMS
@@ -4358,6 +4381,68 @@ task_reduction_read (gimple_seq *ilist, tree tskred_temp, tree type,
   return v;
 }
 
+/* Lower early initialization of privatized variable NEW_VAR
+   if it needs an allocator (has allocate clause).  */
+
+static bool
+lower_private_allocate (tree var, tree new_var, tree &allocator,
+                       tree &allocate_ptr, gimple_seq *ilist,
+                       omp_context *ctx, bool is_ref, tree size)
+{
+  if (allocator)
+    return false;
+  gcc_assert (allocate_ptr == NULL_TREE);
+  if (ctx->allocate_map && DECL_P (new_var))
+    if (tree *allocatorp = ctx->allocate_map->get (var))
+      allocator = *allocatorp;
+  if (allocator == NULL_TREE)
+    return false;
+  if (!is_ref && omp_is_reference (var))
+    return false;
+
+  if (TREE_CODE (allocator) != INTEGER_CST)
+    allocator = build_outer_var_ref (allocator, ctx);
+  allocator = fold_convert (pointer_sized_int_node, allocator);
+  if (TREE_CODE (allocator) != INTEGER_CST)
+    {
+      tree var = create_tmp_var (TREE_TYPE (allocator));
+      gimplify_assign (var, allocator, ilist);
+      allocator = var;
+    }
+
+  tree ptr_type, align, sz;
+  if (is_ref)
+    {
+      ptr_type = build_pointer_type (TREE_TYPE (TREE_TYPE (new_var)));
+      align = build_int_cst (size_type_node,
+                            TYPE_ALIGN_UNIT (TREE_TYPE (ptr_type)));
+      sz = size;
+    }
+  else
+    {
+      ptr_type = build_pointer_type (TREE_TYPE (new_var));
+      align = build_int_cst (size_type_node, DECL_ALIGN_UNIT (new_var));
+      sz = fold_convert (size_type_node, DECL_SIZE_UNIT (new_var));
+    }
+  if (TREE_CODE (sz) != INTEGER_CST)
+    {
+      tree szvar = create_tmp_var (size_type_node);
+      gimplify_assign (szvar, sz, ilist);
+      sz = szvar;
+    }
+  allocate_ptr = create_tmp_var (ptr_type);
+  tree a = builtin_decl_explicit (BUILT_IN_GOMP_ALLOC);
+  gimple *g = gimple_build_call (a, 3, align, sz, allocator);
+  gimple_call_set_lhs (g, allocate_ptr);
+  gimple_seq_add_stmt (ilist, g);
+  if (!is_ref)
+    {
+      SET_DECL_VALUE_EXPR (new_var, build_simple_mem_ref (allocate_ptr));
+      DECL_HAS_VALUE_EXPR_P (new_var) = 1;
+    }
+  return true;
+}
+
 /* Generate code to implement the input clauses, FIRSTPRIVATE and COPYIN,
    from the receiver (aka child) side and initializers for REFERENCE_TYPE
    private variables.  Initialization statements go in ILIST, while calls
@@ -4523,6 +4608,7 @@ lower_rec_input_clauses (tree clauses, gimple_seq *ilist, gimple_seq *dlist,
          bool task_reduction_p = false;
          bool task_reduction_needs_orig_p = false;
          tree cond = NULL_TREE;
+         tree allocator, allocate_ptr;
 
          switch (c_kind)
            {
@@ -4659,6 +4745,8 @@ lower_rec_input_clauses (tree clauses, gimple_seq *ilist, gimple_seq *dlist,
          if (task_reduction_p != (pass >= 2))
            continue;
 
+         allocator = NULL_TREE;
+         allocate_ptr = NULL_TREE;
          new_var = var = OMP_CLAUSE_DECL (c);
          if ((c_kind == OMP_CLAUSE_REDUCTION
               || c_kind == OMP_CLAUSE_IN_REDUCTION)
@@ -5195,8 +5283,7 @@ lower_rec_input_clauses (tree clauses, gimple_seq *ilist, gimple_seq *dlist,
 
              if (c_kind != OMP_CLAUSE_FIRSTPRIVATE || !is_task_ctx (ctx))
                {
-                 gcall *stmt;
-                 tree tmp, atmp;
+                 tree tmp;
 
                  ptr = DECL_VALUE_EXPR (new_var);
                  gcc_assert (TREE_CODE (ptr) == INDIRECT_REF);
@@ -5204,16 +5291,25 @@ lower_rec_input_clauses (tree clauses, gimple_seq *ilist, gimple_seq *dlist,
                  gcc_assert (DECL_P (ptr));
                  x = TYPE_SIZE_UNIT (TREE_TYPE (new_var));
 
-                 /* void *tmp = __builtin_alloca */
-                 atmp = builtin_decl_explicit (BUILT_IN_ALLOCA_WITH_ALIGN);
-                 stmt = gimple_build_call (atmp, 2, x,
-                                           size_int (DECL_ALIGN (var)));
-                 cfun->calls_alloca = 1;
-                 tmp = create_tmp_var_raw (ptr_type_node);
-                 gimple_add_tmp_var (tmp);
-                 gimple_call_set_lhs (stmt, tmp);
-
-                 gimple_seq_add_stmt (ilist, stmt);
+                 if (lower_private_allocate (var, new_var, allocator,
+                                             allocate_ptr, ilist, ctx,
+                                             false, x))
+                   tmp = allocate_ptr;
+                 else
+                   {
+                     /* void *tmp = __builtin_alloca */
+                     tree atmp
+                       = builtin_decl_explicit (BUILT_IN_ALLOCA_WITH_ALIGN);
+                     gcall *stmt
+                       = gimple_build_call (atmp, 2, x,
+                                            size_int (DECL_ALIGN (var)));
+                     cfun->calls_alloca = 1;
+                     tmp = create_tmp_var_raw (ptr_type_node);
+                     gimple_add_tmp_var (tmp);
+                     gimple_call_set_lhs (stmt, tmp);
+
+                     gimple_seq_add_stmt (ilist, stmt);
+                   }
 
                  x = fold_convert_loc (clause_loc, TREE_TYPE (ptr), tmp);
                  gimplify_assign (ptr, x, ilist);
@@ -5237,6 +5333,10 @@ lower_rec_input_clauses (tree clauses, gimple_seq *ilist, gimple_seq *dlist,
                  x = build_receiver_ref (var, false, ctx);
                  x = build_fold_addr_expr_loc (clause_loc, x);
                }
+             else if (lower_private_allocate (var, new_var, allocator,
+                                              allocate_ptr,
+                                              ilist, ctx, true, x))
+               x = allocate_ptr;
              else if (TREE_CONSTANT (x))
                {
                  /* For reduction in SIMD loop, defer adding the
@@ -5349,6 +5449,8 @@ lower_rec_input_clauses (tree clauses, gimple_seq *ilist, gimple_seq *dlist,
              tree nx;
              bool copy_ctor;
              copy_ctor = false;
+             lower_private_allocate (var, new_var, allocator, allocate_ptr,
+                                     ilist, ctx, false, NULL_TREE);
              nx = unshare_expr (new_var);
              if (is_simd
                  && OMP_CLAUSE_CODE (c) == OMP_CLAUSE_LASTPRIVATE
@@ -5494,6 +5596,13 @@ lower_rec_input_clauses (tree clauses, gimple_seq *ilist, gimple_seq *dlist,
              x = lang_hooks.decls.omp_clause_dtor (c, new_var);
              if (x)
                gimplify_and_add (x, dlist);
+             if (allocator)
+               {
+                 tree f = builtin_decl_explicit (BUILT_IN_GOMP_FREE);
+                 gimple *g
+                   = gimple_build_call (f, 2, allocate_ptr, allocator);
+                 gimple_seq_add_stmt (dlist, g);
+               }
              break;
 
            case OMP_CLAUSE_LINEAR:
@@ -5535,6 +5644,8 @@ lower_rec_input_clauses (tree clauses, gimple_seq *ilist, gimple_seq *dlist,
                  goto do_dtor;
                }
            do_firstprivate:
+             lower_private_allocate (var, new_var, allocator, allocate_ptr,
+                                     ilist, ctx, false, NULL_TREE);
              x = build_outer_var_ref (var, ctx);
              if (is_simd)
                {
@@ -5722,6 +5833,9 @@ lower_rec_input_clauses (tree clauses, gimple_seq *ilist, gimple_seq *dlist,
                    }
                  else
                    {
+                     lower_private_allocate (var, new_var, allocator,
+                                             allocate_ptr, ilist, ctx, false,
+                                             NULL_TREE);
                      x = build_outer_var_ref (var, ctx);
 
                      if (omp_is_reference (var)
@@ -6118,6 +6232,9 @@ lower_rec_input_clauses (tree clauses, gimple_seq *ilist, gimple_seq *dlist,
                    }
                  else
                    {
+                     lower_private_allocate (var, new_var, allocator,
+                                             allocate_ptr, ilist, ctx,
+                                             false, NULL_TREE);
                      if (omp_is_reference (var) && is_simd)
                        handle_simd_reference (clause_loc, new_vard, ilist);
                      if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_REDUCTION
@@ -6132,6 +6249,8 @@ lower_rec_input_clauses (tree clauses, gimple_seq *ilist, gimple_seq *dlist,
                          ref = build_outer_var_ref (var, ctx);
                          gimplify_assign (ref, x, dlist);
                        }
+                     if (allocator)
+                       goto do_dtor;
                    }
                }
              break;
@@ -7488,7 +7607,10 @@ lower_send_shared_vars (gimple_seq *ilist, gimple_seq *olist, omp_context *ctx)
        continue;
 
       nvar = maybe_lookup_decl (ovar, ctx);
-      if (!nvar || !DECL_HAS_VALUE_EXPR_P (nvar))
+      if (!nvar
+         || !DECL_HAS_VALUE_EXPR_P (nvar)
+         || (ctx->allocate_map
+             && ctx->allocate_map->get (ovar)))
        continue;
 
       /* If CTX is a nested parallel directive.  Find the immediately
index 23b2902ecfca822b0d467d4f6dd8d45440c13a55..9a2ff6227b4627ecce05560c54ff070ad3d01e47 100644 (file)
@@ -1972,6 +1972,7 @@ evaluate_stmt (gimple *stmt)
              break;
 
            case BUILT_IN_ALIGNED_ALLOC:
+           case BUILT_IN_GOMP_ALLOC:
              {
                tree align = get_constant_value (gimple_call_arg (stmt, 0));
                if (align
index a0466127f9c8fce2b243d64357be1bb69564eac8..9fb156c120d937f0fd43fbf5ff4192cda6f55e8f 100644 (file)
@@ -239,6 +239,7 @@ mark_stmt_if_obviously_necessary (gimple *stmt, bool aggressive)
            CASE_BUILT_IN_ALLOCA:
            case BUILT_IN_STRDUP:
            case BUILT_IN_STRNDUP:
+           case BUILT_IN_GOMP_ALLOC:
              return;
 
            default:;
@@ -605,6 +606,8 @@ mark_all_reaching_defs_necessary_1 (ao_ref *ref ATTRIBUTE_UNUSED,
          case BUILT_IN_CALLOC:
          CASE_BUILT_IN_ALLOCA:
          case BUILT_IN_FREE:
+         case BUILT_IN_GOMP_ALLOC:
+         case BUILT_IN_GOMP_FREE:
            return false;
 
          default:;
@@ -879,7 +882,8 @@ propagate_necessity (bool aggressive)
               && gimple_call_from_new_or_delete (as_a <gcall *> (stmt))
               && gimple_call_operator_delete_p (as_a <gcall *> (stmt)));
          if (is_delete_operator
-             || gimple_call_builtin_p (stmt, BUILT_IN_FREE))
+             || gimple_call_builtin_p (stmt, BUILT_IN_FREE)
+             || gimple_call_builtin_p (stmt, BUILT_IN_GOMP_FREE))
            {
              tree ptr = gimple_call_arg (stmt, 0);
              gcall *def_stmt;
@@ -892,27 +896,26 @@ propagate_necessity (bool aggressive)
                  && ((DECL_BUILT_IN_CLASS (def_callee) == BUILT_IN_NORMAL
                       && (DECL_FUNCTION_CODE (def_callee) == BUILT_IN_ALIGNED_ALLOC
                           || DECL_FUNCTION_CODE (def_callee) == BUILT_IN_MALLOC
-                          || DECL_FUNCTION_CODE (def_callee) == BUILT_IN_CALLOC))
+                          || DECL_FUNCTION_CODE (def_callee) == BUILT_IN_CALLOC
+                          || DECL_FUNCTION_CODE (def_callee) == BUILT_IN_GOMP_ALLOC))
                      || (DECL_IS_REPLACEABLE_OPERATOR_NEW_P (def_callee)
                          && gimple_call_from_new_or_delete (def_stmt))))
                {
-                 if (is_delete_operator)
-                   {
-                     if (!valid_new_delete_pair_p (def_stmt, stmt))
-                       mark_operand_necessary (gimple_call_arg (stmt, 0));
-
-                     /* Delete operators can have alignment and (or) size
-                        as next arguments.  When being a SSA_NAME, they
-                        must be marked as necessary.  */
-                     if (gimple_call_num_args (stmt) >= 2)
-                       for (unsigned i = 1; i < gimple_call_num_args (stmt);
-                            i++)
-                         {
-                           tree arg = gimple_call_arg (stmt, i);
-                           if (TREE_CODE (arg) == SSA_NAME)
-                             mark_operand_necessary (arg);
-                         }
-                   }
+                 if (is_delete_operator
+                     && !valid_new_delete_pair_p (def_stmt, stmt))
+                   mark_operand_necessary (gimple_call_arg (stmt, 0));
+
+                 /* Delete operators can have alignment and (or) size
+                    as next arguments.  When being a SSA_NAME, they
+                    must be marked as necessary.  Similarly GOMP_free.  */
+                 if (gimple_call_num_args (stmt) >= 2)
+                   for (unsigned i = 1; i < gimple_call_num_args (stmt);
+                        i++)
+                     {
+                       tree arg = gimple_call_arg (stmt, i);
+                       if (TREE_CODE (arg) == SSA_NAME)
+                         mark_operand_necessary (arg);
+                     }
 
                  continue;
                }
index 7166538b1de4f5a4e4d794cd0876c4dcee6c204f..279073309a0c6dd7629954b3b0a190f5f52e4a06 100644 (file)
@@ -205,11 +205,12 @@ omp_destroy_allocator (omp_allocator_handle_t allocator)
 ialias (omp_init_allocator)
 ialias (omp_destroy_allocator)
 
-void *
-omp_alloc (size_t size, omp_allocator_handle_t allocator)
+static void *
+omp_aligned_alloc (size_t alignment, size_t size,
+                  omp_allocator_handle_t allocator)
 {
   struct omp_allocator_data *allocator_data;
-  size_t alignment, new_size;
+  size_t new_size;
   void *ptr, *ret;
 
   if (__builtin_expect (size == 0, 0))
@@ -227,12 +228,14 @@ retry:
   if (allocator > omp_max_predefined_alloc)
     {
       allocator_data = (struct omp_allocator_data *) allocator;
-      alignment = allocator_data->alignment;
+      if (alignment < allocator_data->alignment)
+       alignment = allocator_data->alignment;
     }
   else
     {
       allocator_data = NULL;
-      alignment = sizeof (void *);
+      if (alignment < sizeof (void *))
+       alignment = sizeof (void *);
     }
 
   new_size = sizeof (struct omp_mem_header);
@@ -339,6 +342,27 @@ fail:
   return NULL;
 }
 
+void *
+omp_alloc (size_t size, omp_allocator_handle_t allocator)
+{
+  return omp_aligned_alloc (1, size, allocator);
+}
+
+/* Like omp_aligned_alloc, but apply on top of that:
+   "For allocations that arise from this ... the null_fb value of the
+   fallback allocator trait behaves as if the abort_fb had been specified."  */
+
+void *
+GOMP_alloc (size_t alignment, size_t size, uintptr_t allocator)
+{
+  void *ret = omp_aligned_alloc (alignment, size,
+                                (omp_allocator_handle_t) allocator);
+  if (__builtin_expect (ret == NULL, 0) && size)
+    gomp_fatal ("Out of memory allocating %lu bytes",
+               (unsigned long) size);
+  return ret;
+}
+
 void
 omp_free (void *ptr, omp_allocator_handle_t allocator)
 {
@@ -366,3 +390,11 @@ omp_free (void *ptr, omp_allocator_handle_t allocator)
     }
   free (data->ptr);
 }
+
+ialias (omp_free)
+
+void
+GOMP_free (void *ptr, uintptr_t allocator)
+{
+  return omp_free (ptr, (omp_allocator_handle_t) allocator);
+}
index c5f52f725d06b498b626c93c1c8b077f3a86fd00..2c95f781fd5c70f5ace28cc5ad5814a044171600 100644 (file)
@@ -359,6 +359,12 @@ GOMP_5.0 {
        GOMP_workshare_task_reduction_unregister;
 } GOMP_4.5;
 
+GOMP_5.0.1 {
+  global:
+       GOMP_alloc;
+       GOMP_free;
+} GOMP_5.0;
+
 OACC_2.0 {
   global:
        acc_get_num_devices;
index 59e3697bfd8d9890459f5841cbadfd8d0cff2731..b20e186c02f9b367bf16d723fb90994f2cff79bf 100644 (file)
@@ -357,6 +357,11 @@ extern void GOMP_teams (unsigned int, unsigned int);
 extern void GOMP_teams_reg (void (*) (void *), void *, unsigned, unsigned,
                            unsigned);
 
+/* allocator.c */
+
+extern void *GOMP_alloc (size_t, size_t, uintptr_t);
+extern void GOMP_free (void *, uintptr_t);
+
 /* oacc-async.c */
 
 extern void GOACC_wait (int, int, ...);
index be7df6d283f1c487ddd2d4e898fb050d3b7ae190..4424a16b40d37ef26850063c22356123c0e7ddb9 100644 (file)
@@ -281,7 +281,7 @@ extern void omp_set_default_allocator (omp_allocator_handle_t) __GOMP_NOTHROW;
 extern omp_allocator_handle_t omp_get_default_allocator (void) __GOMP_NOTHROW;
 extern void *omp_alloc (__SIZE_TYPE__,
                        omp_allocator_handle_t __GOMP_DEFAULT_NULL_ALLOCATOR)
-  __GOMP_NOTHROW;
+  __GOMP_NOTHROW __attribute__((__malloc__, __alloc_size__ (1)));
 extern void omp_free (void *,
                      omp_allocator_handle_t __GOMP_DEFAULT_NULL_ALLOCATOR)
   __GOMP_NOTHROW;
diff --git a/libgomp/testsuite/libgomp.c++/allocate-1.C b/libgomp/testsuite/libgomp.c++/allocate-1.C
new file mode 100644 (file)
index 0000000..ee89f31
--- /dev/null
@@ -0,0 +1,194 @@
+#include <omp.h>
+#include <stdlib.h>
+#include <stdint.h>
+
+void
+foo (int &x, int &y, int &r, int &l, int (&l2)[4], int &l3, int &n, omp_allocator_handle_t h, int fl)
+{
+  int i;
+  typedef int T[x];
+  T v, w;
+  T &v2 = v;
+  T &w2 = w;
+  int xo = x;
+  for (i = 0; i < x; i++)
+    w[i] = i;
+  #pragma omp parallel private (y, v2) firstprivate (x) allocate (x, y, v2)
+  {
+    int *volatile p1 = &x;
+    int *volatile p2 = &y;
+    if (x != 42)
+      abort ();
+    #pragma omp barrier
+    *p2 = 1;
+    p1[0]++;
+    v2[0] = 7;
+    v2[41] = 8;
+    #pragma omp barrier
+    if (x != 43 || y != 1)
+      abort ();
+    if (v2[0] != 7 || v2[41] != 8)
+      abort ();
+    if ((fl & 2) && (((uintptr_t) p1 | (uintptr_t) p2
+       | (uintptr_t) &v2[0]) & 63) != 0)
+      abort ();
+  }
+  x = xo;
+  #pragma omp teams
+  #pragma omp parallel private (y) firstprivate (x, w2) allocate (h: x, y, w2)
+  {
+    int *volatile p1 = &x;
+    int *volatile p2 = &y;
+    if (x != 42 || w2[17] != 17 || w2[41] != 41)
+      abort ();
+    #pragma omp barrier
+    *p2 = 1;
+    p1[0]++;
+    w2[19]++;
+    #pragma omp barrier
+    if (x != 43 || y != 1 || w2[19] != 20)
+      abort ();
+    if ((fl & 1) && (((uintptr_t) p1 | (uintptr_t) p2
+                     | (uintptr_t) &w2[0]) & 63) != 0)
+      abort ();
+  }
+  x = xo;
+  #pragma omp parallel for private (y) firstprivate (x) allocate (h: x, y, r, l, n) reduction(+: r) lastprivate (l) linear (n: 16)
+  for (i = 0; i < 64; i++)
+    {
+      if (x != 42)
+       abort ();
+      y = 1;
+      l = i;
+      n += y + 15;
+      r += i;
+      if ((fl & 1) && (((uintptr_t) &x | (uintptr_t) &y | (uintptr_t) &r
+                       | (uintptr_t) &l | (uintptr_t) &n) & 63) != 0)
+       abort ();
+    }
+  #pragma omp parallel
+  {
+    #pragma omp for lastprivate (l2) allocate (h: l2, l3) lastprivate (conditional: l3)
+    for (i = 0; i < 64; i++)
+      {
+       l2[0] = i;
+       l2[1] = i + 1;
+       l2[2] = i + 2;
+       l2[3] = i + 3;
+       if (i < 37)
+         l3 = i;
+       if ((fl & 1) && (((uintptr_t) &l2[0] | (uintptr_t) &l3) & 63) != 0)
+         abort ();
+      }
+  }
+  if (r != 64 * 63 / 2 || l != 63 || n != 8 + 16 * 64)
+    abort ();
+  if (l2[0] != 63 || l2[1] != 63 + 1 || l2[2] != 63 + 2 || l2[3] != 63 + 3 || l3 != 36)
+    abort ();
+}
+
+void
+bar (int &x, int &y, int &r, int &l, int (&l2)[4], int &l3, int &n, omp_allocator_handle_t h)
+{
+  int i;
+  typedef int T[x];
+  T v, w;
+  T &v2 = v;
+  T &w2 = w;
+  int xo = x;
+  for (i = 0; i < x; i++)
+    w[i] = i;
+  #pragma omp parallel private (y, v2) firstprivate (x) allocate (x, y, v2)
+  {
+    int *volatile p1 = &x;
+    int *volatile p2 = &y;
+    if (x != 42)
+      abort ();
+    #pragma omp barrier
+    *p2 = 1;
+    p1[0]++;
+    v2[0] = 7;
+    v2[41] = 8;
+    #pragma omp barrier
+    if (x != 43 || y != 1)
+      abort ();
+    if (v2[0] != 7 || v2[41] != 8)
+      abort ();
+  }
+  x = xo;
+  #pragma omp teams
+  #pragma omp parallel private (y) firstprivate (x, w2) allocate (h: x, y, w2)
+  {
+    int *volatile p1 = &x;
+    int *volatile p2 = &y;
+    if (x != 42 || w2[17] != 17 || w2[41] != 41)
+      abort ();
+    #pragma omp barrier
+    *p2 = 1;
+    p1[0]++;
+    #pragma omp barrier
+    if (x != 43 || y != 1)
+      abort ();
+  }
+  x = xo;
+  #pragma omp parallel for private (y) firstprivate (x) allocate (h: x, y, r, l, n) reduction(+: r) lastprivate (l) linear (n: 16)
+  for (i = 0; i < 64; i++)
+    {
+      if (x != 42)
+       abort ();
+      y = 1;
+      l = i;
+      n += y + 15;
+      r += i;
+    }
+  #pragma omp parallel
+  {
+    #pragma omp for lastprivate (l2) allocate (h: l2, l3) lastprivate (conditional: l3)
+    for (i = 0; i < 64; i++)
+      {
+       l2[0] = i;
+       l2[1] = i + 1;
+       l2[2] = i + 2;
+       l2[3] = i + 3;
+       if (i < 37)
+         l3 = i;
+      }
+  }
+  if (r != 64 * 63 / 2 || l != 63 || n != 8 + 16 * 64)
+    abort ();
+  if (l2[0] != 63 || l2[1] != 63 + 1 || l2[2] != 63 + 2 || l2[3] != 63 + 3 || l3 != 36)
+    abort ();
+}
+
+int
+main ()
+{
+  omp_alloctrait_t traits[3]
+    = { { omp_atk_alignment, 64 },
+       { omp_atk_fallback, omp_atv_null_fb } };
+  omp_allocator_handle_t a
+    = omp_init_allocator (omp_default_mem_space, 2, traits);
+  if (a == omp_null_allocator)
+    abort ();
+  omp_set_default_allocator (omp_default_mem_alloc);
+  int x = 42, y = 0, r = 0, l, l2[4], l3, n = 8;
+  foo (x, y, r, l, l2, l3, n, omp_null_allocator, 0);
+  x = 42; y = 0; r = 0; l = -1; l2[0] = -1; l2[1] = -1;
+  l2[2] = -1; l2[3] = -1; n = 8;
+  foo (x, y, r, l, l2, l3, n, omp_default_mem_alloc, 0);
+  x = 42; y = 0; r = 0; l = -1; l2[0] = -1; l2[1] = -1;
+  l2[2] = -1; l2[3] = -1; n = 8;
+  foo (x, y, r, l, l2, l3, n, a, 1);
+  x = 42; y = 0; r = 0; l = -1; l2[0] = -1; l2[1] = -1;
+  l2[2] = -1; l2[3] = -1; n = 8;
+  omp_set_default_allocator (a);
+  foo (x, y, r, l, l2, l3, n, omp_null_allocator, 3);
+  x = 42; y = 0; r = 0; l = -1; l2[0] = -1; l2[1] = -1;
+  l2[2] = -1; l2[3] = -1; n = 8;
+  foo (x, y, r, l, l2, l3, n, omp_default_mem_alloc, 2);
+  x = 42; y = 0; r = 0; l = -1; l2[0] = -1; l2[1] = -1;
+  l2[2] = -1; l2[3] = -1; n = 8;
+  bar (x, y, r, l, l2, l3, n, a);
+  omp_destroy_allocator (a);
+  return 0;
+}
diff --git a/libgomp/testsuite/libgomp.c-c++-common/allocate-1.c b/libgomp/testsuite/libgomp.c-c++-common/allocate-1.c
new file mode 100644 (file)
index 0000000..532795f
--- /dev/null
@@ -0,0 +1,254 @@
+#include <omp.h>
+#include <stdlib.h>
+#include <stdint.h>
+
+void
+foo (int x, omp_allocator_handle_t h, int fl)
+{
+  int y = 0, r = 0, i, i1, l, l2[4], l3, n = 8;
+  int i2, j2, n2 = 9, l4;
+  int i3, j3, n3 = 10, l5;
+  int i4, j4, n4 = 11, l6;
+  int i5;
+  int v[x], w[x];
+  int xo = x;
+  for (i = 0; i < x; i++)
+    w[i] = i;
+  #pragma omp parallel private (y, v) firstprivate (x) allocate (x, y, v)
+  {
+    int *volatile p1 = &x;
+    int *volatile p2 = &y;
+    if (x != 42)
+      abort ();
+    #pragma omp barrier
+    *p2 = 1;
+    p1[0]++;
+    v[0] = 7;
+    v[41] = 8;
+    #pragma omp barrier
+    if (x != 43 || y != 1)
+      abort ();
+    if (v[0] != 7 || v[41] != 8)
+      abort ();
+    if ((fl & 2) && (((uintptr_t) p1 | (uintptr_t) p2
+       | (uintptr_t) &v[0]) & 63) != 0)
+      abort ();
+  }
+  x = xo;
+  #pragma omp teams
+  #pragma omp parallel private (y) firstprivate (x, w) allocate (h: x, y, w)
+  {
+    int *volatile p1 = &x;
+    int *volatile p2 = &y;
+    if (x != 42 || w[17] != 17 || w[41] != 41)
+      abort ();
+    #pragma omp barrier
+    *p2 = 1;
+    p1[0]++;
+    w[19]++;
+    #pragma omp barrier
+    if (x != 43 || y != 1 || w[19] != 20)
+      abort ();
+    if ((fl & 1) && (((uintptr_t) p1 | (uintptr_t) p2
+                     | (uintptr_t) &w[0]) & 63) != 0)
+      abort ();
+  }
+  x = xo;
+  #pragma omp parallel for private (y) firstprivate (x) allocate (h: x, y, r, l, n) reduction(+: r) lastprivate (l) linear (n: 16)
+  for (i = 0; i < 64; i++)
+    {
+      if (x != 42)
+       abort ();
+      y = 1;
+      l = i;
+      n += y + 15;
+      r += i;
+      if ((fl & 1) && (((uintptr_t) &x | (uintptr_t) &y | (uintptr_t) &r
+                       | (uintptr_t) &l | (uintptr_t) &n) & 63) != 0)
+       abort ();
+    }
+  #pragma omp parallel
+  {
+    #pragma omp for lastprivate (l2) private (i1) allocate (h: l2, l3, i1) lastprivate (conditional: l3)
+    for (i1 = 0; i1 < 64; i1++)
+      {
+       l2[0] = i1;
+       l2[1] = i1 + 1;
+       l2[2] = i1 + 2;
+       l2[3] = i1 + 3;
+       if (i1 < 37)
+         l3 = i1;
+       if ((fl & 1) && (((uintptr_t) &l2[0] | (uintptr_t) &l3 | (uintptr_t) &i1) & 63) != 0)
+         abort ();
+      }
+    #pragma omp for collapse(2) lastprivate(l4, i2, j2) linear (n2:17) allocate (h: n2, l4, i2, j2)
+    for (i2 = 3; i2 < 5; i2++)
+      for (j2 = 17; j2 < 22; j2 += 2)
+       {
+         n2 += 17;
+         l4 = i2 * 31 + j2;
+         if ((fl & 1) && (((uintptr_t) &l4 | (uintptr_t) &n2
+                           | (uintptr_t) &i2 | (uintptr_t) &j2) & 63) != 0)
+           abort ();
+       }
+    #pragma omp for collapse(2) lastprivate(l5, i3, j3) linear (n3:17) schedule (static, 3) allocate (n3, l5, i3, j3)
+    for (i3 = 3; i3 < 5; i3++)
+      for (j3 = 17; j3 < 23; j3 += 2)
+       {
+         n3 += 17;
+         l5 = i3 * 31 + j3;
+         if ((fl & 2) && (((uintptr_t) &l5 | (uintptr_t) &n3
+                           | (uintptr_t) &i3 | (uintptr_t) &j3) & 63) != 0)
+           abort ();
+       }
+    #pragma omp for collapse(2) lastprivate(l6, i4, j4) linear (n4:17) schedule (dynamic) allocate (h: n4, l6, i4, j4)
+    for (i4 = 3; i4 < 5; i4++)
+      for (j4 = 17; j4 < 22; j4 += 2)
+       {
+         n4 += 17;
+         l6 = i4 * 31 + j4;
+         if ((fl & 1) && (((uintptr_t) &l6 | (uintptr_t) &n4
+                           | (uintptr_t) &i4 | (uintptr_t) &j4) & 63) != 0)
+           abort ();
+       }
+    #pragma omp for lastprivate (i5) allocate (i5)
+    for (i5 = 1; i5 < 17; i5 += 3)
+      {
+       if ((fl & 2) && (((uintptr_t) &i5) & 63) != 0)
+         abort ();
+      }
+  }
+  if (r != 64 * 63 / 2 || l != 63 || n != 8 + 16 * 64)
+    abort ();
+  if (l2[0] != 63 || l2[1] != 63 + 1 || l2[2] != 63 + 2 || l2[3] != 63 + 3 || l3 != 36)
+    abort ();
+  if (i2 != 5 || j2 != 23 || n2 != 9 + 6 * 17 || l4 != 4 * 31 + 21)
+    abort ();
+  if (i3 != 5 || j3 != 23 || n3 != 10 + 6 * 17 || l5 != 4 * 31 + 21)
+    abort ();
+  if (i4 != 5 || j4 != 23 || n4 != 11 + 6 * 17 || l6 != 4 * 31 + 21)
+    abort ();
+  if (i5 != 19)
+    abort ();
+}
+
+void
+bar (int x, omp_allocator_handle_t h)
+{
+  int y = 0, r = 0, i, i1, l, l2[4], l3, n = 8;
+  int i2, j2, n2 = 9, l4;
+  int i3, j3, n3 = 10, l5;
+  int i4, j4, n4 = 11, l6;
+  int i5;
+  int xo = x;
+  #pragma omp parallel private (y) firstprivate (x) allocate (x, y)
+  {
+    int *volatile p1 = &x;
+    int *volatile p2 = &y;
+    if (x != 42)
+      abort ();
+    #pragma omp barrier
+    *p2 = 1;
+    p1[0]++;
+    #pragma omp barrier
+    if (x != 43 || y != 1)
+      abort ();
+  }
+  x = xo;
+  #pragma omp teams
+  #pragma omp parallel private (y) firstprivate (x) allocate (h: x, y)
+  {
+    int *volatile p1 = &x;
+    int *volatile p2 = &y;
+    if (x != 42)
+      abort ();
+    #pragma omp barrier
+    *p2 = 1;
+    p1[0]++;
+    #pragma omp barrier
+    if (x != 43 || y != 1)
+      abort ();
+  }
+  x = xo;
+  #pragma omp parallel for private (y) firstprivate (x) allocate (h: x, y, r, l, n) reduction(+: r) lastprivate (l) linear (n: 16)
+  for (i = 0; i < 64; i++)
+    {
+      if (x != 42)
+       abort ();
+      y = 1;
+      l = i;
+      n += y + 15;
+      r += i;
+    }
+  #pragma omp parallel
+  {
+    #pragma omp for lastprivate (l2) private (i1) allocate (h: l2, l3, i1) lastprivate (conditional: l3)
+    for (i1 = 0; i1 < 64; i1++)
+      {
+       l2[0] = i1;
+       l2[1] = i1 + 1;
+       l2[2] = i1 + 2;
+       l2[3] = i1 + 3;
+       if (i1 < 37)
+         l3 = i1;
+      }
+    #pragma omp for collapse(2) lastprivate(l4, i2, j2) linear (n2:17) allocate (h: n2, l4, i2, j2)
+    for (i2 = 3; i2 < 5; i2++)
+      for (j2 = 17; j2 < 22; j2 += 2)
+       {
+         n2 += 17;
+         l4 = i2 * 31 + j2;
+       }
+    #pragma omp for collapse(2) lastprivate(l5, i3, j3) linear (n3:17) schedule (static, 3) allocate (n3, l5, i3, j3)
+    for (i3 = 3; i3 < 5; i3++)
+      for (j3 = 17; j3 < 23; j3 += 2)
+       {
+         n3 += 17;
+         l5 = i3 * 31 + j3;
+       }
+    #pragma omp for collapse(2) lastprivate(l6, i4, j4) linear (n4:17) schedule (dynamic) allocate (h: n4, l6, i4, j4)
+    for (i4 = 3; i4 < 5; i4++)
+      for (j4 = 17; j4 < 22; j4 += 2)
+       {
+         n4 += 17;
+         l6 = i4 * 31 + j4;
+       }
+    #pragma omp for lastprivate (i5) allocate (i5)
+    for (i5 = 1; i5 < 17; i5 += 3)
+      ;
+  }
+  if (r != 64 * 63 / 2 || l != 63 || n != 8 + 16 * 64)
+    abort ();
+  if (l2[0] != 63 || l2[1] != 63 + 1 || l2[2] != 63 + 2 || l2[3] != 63 + 3 || l3 != 36)
+    abort ();
+  if (i2 != 5 || j2 != 23 || n2 != 9 + 6 * 17 || l4 != 4 * 31 + 21)
+    abort ();
+  if (i3 != 5 || j3 != 23 || n3 != 10 + 6 * 17 || l5 != 4 * 31 + 21)
+    abort ();
+  if (i4 != 5 || j4 != 23 || n4 != 11 + 6 * 17 || l6 != 4 * 31 + 21)
+    abort ();
+  if (i5 != 19)
+    abort ();
+}
+
+int
+main ()
+{
+  omp_alloctrait_t traits[3]
+    = { { omp_atk_alignment, 64 },
+       { omp_atk_fallback, omp_atv_null_fb } };
+  omp_allocator_handle_t a
+    = omp_init_allocator (omp_default_mem_space, 2, traits);
+  if (a == omp_null_allocator)
+    abort ();
+  omp_set_default_allocator (omp_default_mem_alloc);
+  foo (42, omp_null_allocator, 0);
+  foo (42, omp_default_mem_alloc, 0);
+  foo (42, a, 1);
+  omp_set_default_allocator (a);
+  foo (42, omp_null_allocator, 3);
+  foo (42, omp_default_mem_alloc, 2);
+  bar (42, a);
+  omp_destroy_allocator (a);
+  return 0;
+}