summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJakub Jelinek <jakub@redhat.com>2020-11-12 21:38:04 +0100
committerJakub Jelinek <jakub@redhat.com>2020-11-12 21:38:04 +0100
commit6fcc3cac42998081dbbb1d3389bd42833ad9fdf4 (patch)
tree47f7063a9e3e929251e4859ae718688b08cbfceb
parent9106c51e57c06e88a0dddf994fb5432b4bbe68c0 (diff)
openmp: Implement allocate clause in omp lowering.
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.
-rw-r--r--gcc/builtin-types.def2
-rw-r--r--gcc/builtins.c2
-rw-r--r--gcc/fortran/f95-lang.c11
-rw-r--r--gcc/fortran/types.def5
-rw-r--r--gcc/gimplify.c61
-rw-r--r--gcc/omp-builtins.def9
-rw-r--r--gcc/omp-expand.c9
-rw-r--r--gcc/omp-low.c148
-rw-r--r--gcc/tree-ssa-ccp.c1
-rw-r--r--gcc/tree-ssa-dce.c41
-rw-r--r--libgomp/allocator.c42
-rw-r--r--libgomp/libgomp.map6
-rw-r--r--libgomp/libgomp_g.h5
-rw-r--r--libgomp/omp.h.in2
-rw-r--r--libgomp/testsuite/libgomp.c++/allocate-1.C194
-rw-r--r--libgomp/testsuite/libgomp.c-c++-common/allocate-1.c254
16 files changed, 739 insertions, 53 deletions
diff --git a/gcc/builtin-types.def b/gcc/builtin-types.def
index c46b1bc5cbd..4a82ee421be 100644
--- a/gcc/builtin-types.def
+++ b/gcc/builtin-types.def
@@ -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)
diff --git a/gcc/builtins.c b/gcc/builtins.c
index 4ec1766cffd..42c52a1925e 100644
--- a/gcc/builtins.c
+++ b/gcc/builtins.c
@@ -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 ";
diff --git a/gcc/fortran/f95-lang.c b/gcc/fortran/f95-lang.c
index 526b7219e4b..1a05144ac56 100644
--- a/gcc/fortran/f95-lang.c
+++ b/gcc/fortran/f95-lang.c
@@ -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],
diff --git a/gcc/fortran/types.def b/gcc/fortran/types.def
index 7b4925cdd7e..5736bbab601 100644
--- a/gcc/fortran/types.def
+++ b/gcc/fortran/types.def
@@ -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)
diff --git a/gcc/gimplify.c b/gcc/gimplify.c
index d18c43e3e0f..b861e17d8ae 100644
--- a/gcc/gimplify.c
+++ b/gcc/gimplify.c
@@ -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))
diff --git a/gcc/omp-builtins.def b/gcc/omp-builtins.def
index f461d60e52b..f9b78ed812f 100644
--- a/gcc/omp-builtins.def
+++ b/gcc/omp-builtins.def
@@ -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)
diff --git a/gcc/omp-expand.c b/gcc/omp-expand.c
index 6583c88e276..ddca3d33bdd 100644
--- a/gcc/omp-expand.c
+++ b/gcc/omp-expand.c
@@ -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);
diff --git a/gcc/omp-low.c b/gcc/omp-low.c
index 83ca5fc23e0..ed805e2e6d2 100644
--- a/gcc/omp-low.c
+++ b/gcc/omp-low.c
@@ -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);
}
@@ -1115,6 +1120,22 @@ scan_sharing_clauses (tree clauses, omp_context *ctx)
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
diff --git a/gcc/tree-ssa-ccp.c b/gcc/tree-ssa-ccp.c
index 23b2902ecfc..9a2ff6227b4 100644
--- a/gcc/tree-ssa-ccp.c
+++ b/gcc/tree-ssa-ccp.c
@@ -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
diff --git a/gcc/tree-ssa-dce.c b/gcc/tree-ssa-dce.c
index a0466127f9c..9fb156c120d 100644
--- a/gcc/tree-ssa-dce.c
+++ b/gcc/tree-ssa-dce.c
@@ -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;
}
diff --git a/libgomp/allocator.c b/libgomp/allocator.c
index 7166538b1de..279073309a0 100644
--- a/libgomp/allocator.c
+++ b/libgomp/allocator.c
@@ -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);
+}
diff --git a/libgomp/libgomp.map b/libgomp/libgomp.map
index c5f52f725d0..2c95f781fd5 100644
--- a/libgomp/libgomp.map
+++ b/libgomp/libgomp.map
@@ -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;
diff --git a/libgomp/libgomp_g.h b/libgomp/libgomp_g.h
index 59e3697bfd8..b20e186c02f 100644
--- a/libgomp/libgomp_g.h
+++ b/libgomp/libgomp_g.h
@@ -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, ...);
diff --git a/libgomp/omp.h.in b/libgomp/omp.h.in
index be7df6d283f..4424a16b40d 100644
--- a/libgomp/omp.h.in
+++ b/libgomp/omp.h.in
@@ -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
index 00000000000..ee89f31b6b3
--- /dev/null
+++ b/libgomp/testsuite/libgomp.c++/allocate-1.C
@@ -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
index 00000000000..532795f06f1
--- /dev/null
+++ b/libgomp/testsuite/libgomp.c-c++-common/allocate-1.c
@@ -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;
+}