diff --git a/gcc/c-family/c-omp.c b/gcc/c-family/c-omp.c index b606cf4b538..1f07a0a454b 100644 --- a/gcc/c-family/c-omp.c +++ b/gcc/c-family/c-omp.c @@ -2511,6 +2511,8 @@ c_omp_split_clauses (location_t loc, enum tree_code code, = OMP_CLAUSE_DECL (clauses); OMP_CLAUSE_ALLOCATE_ALLOCATOR (c) = OMP_CLAUSE_ALLOCATE_ALLOCATOR (clauses); + OMP_CLAUSE_ALLOCATE_ALIGN (c) + = OMP_CLAUSE_ALLOCATE_ALIGN (clauses); OMP_CLAUSE_CHAIN (c) = cclauses[s]; cclauses[s] = c; has_dup_allocate = true; diff --git a/gcc/c/c-parser.c b/gcc/c/c-parser.c index fb1399e300d..fa29d2c15fc 100644 --- a/gcc/c/c-parser.c +++ b/gcc/c/c-parser.c @@ -15305,7 +15305,15 @@ c_parser_omp_clause_aligned (c_parser *parser, tree list) /* OpenMP 5.0: allocate ( variable-list ) - allocate ( expression : variable-list ) */ + allocate ( expression : variable-list ) + + OpenMP 5.1: + allocate ( allocator-modifier : variable-list ) + allocate ( allocator-modifier , allocator-modifier : variable-list ) + + allocator-modifier: + allocator ( expression ) + align ( expression ) */ static tree c_parser_omp_clause_allocate (c_parser *parser, tree list) @@ -15313,6 +15321,7 @@ c_parser_omp_clause_allocate (c_parser *parser, tree list) location_t clause_loc = c_parser_peek_token (parser)->location; tree nl, c; tree allocator = NULL_TREE; + tree align = NULL_TREE; matching_parens parens; if (!parens.require_open (parser)) @@ -15323,17 +15332,128 @@ c_parser_omp_clause_allocate (c_parser *parser, tree list) || (c_parser_peek_2nd_token (parser)->type != CPP_COMMA && c_parser_peek_2nd_token (parser)->type != CPP_CLOSE_PAREN)) { - location_t expr_loc = c_parser_peek_token (parser)->location; - c_expr expr = c_parser_expr_no_commas (parser, NULL); - expr = convert_lvalue_to_rvalue (expr_loc, expr, false, true); - allocator = expr.value; - allocator = c_fully_fold (allocator, false, NULL); - tree orig_type - = expr.original_type ? expr.original_type : TREE_TYPE (allocator); - orig_type = TYPE_MAIN_VARIANT (orig_type); - if (!INTEGRAL_TYPE_P (TREE_TYPE (allocator)) - || TREE_CODE (orig_type) != ENUMERAL_TYPE - || TYPE_NAME (orig_type) != get_identifier ("omp_allocator_handle_t")) + bool has_modifiers = false; + tree orig_type = NULL_TREE; + if (c_parser_next_token_is (parser, CPP_NAME) + && c_parser_peek_2nd_token (parser)->type == CPP_OPEN_PAREN) + { + unsigned int n = 3; + const char *p + = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); + if ((strcmp (p, "allocator") == 0 || strcmp (p, "align") == 0) + && c_parser_check_balanced_raw_token_sequence (parser, &n) + && (c_parser_peek_nth_token_raw (parser, n)->type + == CPP_CLOSE_PAREN)) + { + if (c_parser_peek_nth_token_raw (parser, n + 1)->type + == CPP_COLON) + has_modifiers = true; + else if (c_parser_peek_nth_token_raw (parser, n + 1)->type + == CPP_COMMA + && (c_parser_peek_nth_token_raw (parser, n + 2)->type + == CPP_NAME) + && (c_parser_peek_nth_token_raw (parser, n + 3)->type + == CPP_OPEN_PAREN)) + { + c_token *tok = c_parser_peek_nth_token_raw (parser, n + 2); + const char *q = IDENTIFIER_POINTER (tok->value); + n += 4; + if ((strcmp (q, "allocator") == 0 + || strcmp (q, "align") == 0) + && c_parser_check_balanced_raw_token_sequence (parser, + &n) + && (c_parser_peek_nth_token_raw (parser, n)->type + == CPP_CLOSE_PAREN) + && (c_parser_peek_nth_token_raw (parser, n + 1)->type + == CPP_COLON)) + has_modifiers = true; + } + } + if (has_modifiers) + { + c_parser_consume_token (parser); + matching_parens parens2;; + parens2.require_open (parser); + location_t expr_loc = c_parser_peek_token (parser)->location; + c_expr expr = c_parser_expr_no_commas (parser, NULL); + expr = convert_lvalue_to_rvalue (expr_loc, expr, false, true); + if (strcmp (p, "allocator") == 0) + { + allocator = expr.value; + allocator = c_fully_fold (allocator, false, NULL); + orig_type = expr.original_type + ? expr.original_type : TREE_TYPE (allocator); + orig_type = TYPE_MAIN_VARIANT (orig_type); + } + else + { + align = expr.value; + align = c_fully_fold (align, false, NULL); + } + parens2.skip_until_found_close (parser); + if (c_parser_next_token_is (parser, CPP_COMMA)) + { + c_parser_consume_token (parser); + c_token *tok = c_parser_peek_token (parser); + const char *q = ""; + if (c_parser_next_token_is (parser, CPP_NAME)) + q = IDENTIFIER_POINTER (tok->value); + if (strcmp (q, "allocator") != 0 && strcmp (q, "align") != 0) + { + c_parser_error (parser, "expected % or " + "%"); + parens.skip_until_found_close (parser); + return list; + } + else if (strcmp (p, q) == 0) + { + error_at (tok->location, "duplicate %qs modifier", p); + parens.skip_until_found_close (parser); + return list; + } + c_parser_consume_token (parser); + if (!parens2.require_open (parser)) + { + parens.skip_until_found_close (parser); + return list; + } + expr_loc = c_parser_peek_token (parser)->location; + expr = c_parser_expr_no_commas (parser, NULL); + expr = convert_lvalue_to_rvalue (expr_loc, expr, false, + true); + if (strcmp (q, "allocator") == 0) + { + allocator = expr.value; + allocator = c_fully_fold (allocator, false, NULL); + orig_type = expr.original_type + ? expr.original_type : TREE_TYPE (allocator); + orig_type = TYPE_MAIN_VARIANT (orig_type); + } + else + { + align = expr.value; + align = c_fully_fold (align, false, NULL); + } + parens2.skip_until_found_close (parser); + } + } + } + if (!has_modifiers) + { + location_t expr_loc = c_parser_peek_token (parser)->location; + c_expr expr = c_parser_expr_no_commas (parser, NULL); + expr = convert_lvalue_to_rvalue (expr_loc, expr, false, true); + allocator = expr.value; + allocator = c_fully_fold (allocator, false, NULL); + orig_type = expr.original_type + ? expr.original_type : TREE_TYPE (allocator); + orig_type = TYPE_MAIN_VARIANT (orig_type); + } + if (allocator + && (!INTEGRAL_TYPE_P (TREE_TYPE (allocator)) + || TREE_CODE (orig_type) != ENUMERAL_TYPE + || (TYPE_NAME (orig_type) + != get_identifier ("omp_allocator_handle_t")))) { error_at (clause_loc, "% clause allocator expression " "has type %qT rather than " @@ -15341,6 +15461,16 @@ c_parser_omp_clause_allocate (c_parser *parser, tree list) TREE_TYPE (allocator)); allocator = NULL_TREE; } + if (align + && (!INTEGRAL_TYPE_P (TREE_TYPE (align)) + || !tree_fits_uhwi_p (align) + || !integer_pow2p (align))) + { + error_at (clause_loc, "% clause % modifier " + "argument needs to be positive constant " + "power of two integer expression"); + align = NULL_TREE; + } if (!c_parser_require (parser, CPP_COLON, "expected %<:%>")) { parens.skip_until_found_close (parser); @@ -15351,9 +15481,12 @@ c_parser_omp_clause_allocate (c_parser *parser, tree list) nl = c_parser_omp_variable_list (parser, clause_loc, OMP_CLAUSE_ALLOCATE, list); - if (allocator) + if (allocator || align) for (c = nl; c != list; c = OMP_CLAUSE_CHAIN (c)) - OMP_CLAUSE_ALLOCATE_ALLOCATOR (c) = allocator; + { + OMP_CLAUSE_ALLOCATE_ALLOCATOR (c) = allocator; + OMP_CLAUSE_ALLOCATE_ALIGN (c) = align; + } parens.skip_until_found_close (parser); return nl; diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index 62908daa5b7..26d925c15c5 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -38337,13 +38337,21 @@ cp_parser_omp_clause_aligned (cp_parser *parser, tree list) /* OpenMP 5.0: allocate ( variable-list ) - allocate ( expression : variable-list ) */ + allocate ( expression : variable-list ) + + OpenMP 5.1: + allocate ( allocator-modifier : variable-list ) + allocate ( allocator-modifier , allocator-modifier : variable-list ) + + allocator-modifier: + allocator ( expression ) + align ( expression ) */ static tree cp_parser_omp_clause_allocate (cp_parser *parser, tree list) { - tree nlist, c, allocator = NULL_TREE; - bool colon; + tree nlist, c, allocator = NULL_TREE, align = NULL_TREE; + bool colon, has_modifiers = false; matching_parens parens; if (!parens.require_open (parser)) @@ -38352,7 +38360,51 @@ cp_parser_omp_clause_allocate (cp_parser *parser, tree list) cp_parser_parse_tentatively (parser); bool saved_colon_corrects_to_scope_p = parser->colon_corrects_to_scope_p; parser->colon_corrects_to_scope_p = false; - allocator = cp_parser_assignment_expression (parser); + for (int mod = 0; mod < 2; mod++) + if (cp_lexer_next_token_is (parser->lexer, CPP_NAME) + && cp_lexer_nth_token_is (parser->lexer, 2, CPP_OPEN_PAREN)) + { + tree id = cp_lexer_peek_token (parser->lexer)->u.value; + const char *p = IDENTIFIER_POINTER (id); + if (strcmp (p, "allocator") != 0 && strcmp (p, "align") != 0) + break; + cp_lexer_consume_token (parser->lexer); + matching_parens parens2; + if (!parens2.require_open (parser)) + break; + if (strcmp (p, "allocator") == 0) + { + if (allocator != NULL_TREE) + break; + allocator = cp_parser_assignment_expression (parser); + } + else + { + if (align != NULL_TREE) + break; + align = cp_parser_assignment_expression (parser); + } + if (!parens2.require_close (parser)) + break; + if (cp_lexer_next_token_is (parser->lexer, CPP_COLON)) + { + has_modifiers = true; + break; + } + if (mod != 0 || cp_lexer_next_token_is_not (parser->lexer, CPP_COMMA)) + break; + cp_lexer_consume_token (parser->lexer); + } + else + break; + if (!has_modifiers) + { + cp_parser_abort_tentative_parse (parser); + align = NULL_TREE; + allocator = NULL_TREE; + cp_parser_parse_tentatively (parser); + allocator = cp_parser_assignment_expression (parser); + } parser->colon_corrects_to_scope_p = saved_colon_corrects_to_scope_p; if (cp_lexer_next_token_is (parser->lexer, CPP_COLON)) { @@ -38360,18 +38412,25 @@ cp_parser_omp_clause_allocate (cp_parser *parser, tree list) cp_lexer_consume_token (parser->lexer); if (allocator == error_mark_node) allocator = NULL_TREE; + if (align == error_mark_node) + align = NULL_TREE; } else { cp_parser_abort_tentative_parse (parser); allocator = NULL_TREE; + align = NULL_TREE; } nlist = cp_parser_omp_var_list_no_open (parser, OMP_CLAUSE_ALLOCATE, list, &colon); - for (c = nlist; c != list; c = OMP_CLAUSE_CHAIN (c)) - OMP_CLAUSE_ALLOCATE_ALLOCATOR (c) = allocator; + if (allocator || align) + for (c = nlist; c != list; c = OMP_CLAUSE_CHAIN (c)) + { + OMP_CLAUSE_ALLOCATE_ALLOCATOR (c) = allocator; + OMP_CLAUSE_ALLOCATE_ALIGN (c) = align; + } return nlist; } diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 048bbc4622d..28ba32f416c 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -17489,6 +17489,13 @@ tsubst_omp_clauses (tree clauses, enum c_omp_region_type ort, break; case OMP_CLAUSE_GANG: case OMP_CLAUSE_ALIGNED: + OMP_CLAUSE_DECL (nc) + = tsubst_omp_clause_decl (OMP_CLAUSE_DECL (oc), args, complain, + in_decl, NULL); + OMP_CLAUSE_OPERAND (nc, 1) + = tsubst_expr (OMP_CLAUSE_OPERAND (oc, 1), args, complain, + in_decl, /*integral_constant_expression_p=*/false); + break; case OMP_CLAUSE_ALLOCATE: OMP_CLAUSE_DECL (nc) = tsubst_omp_clause_decl (OMP_CLAUSE_DECL (oc), args, complain, @@ -17496,6 +17503,9 @@ tsubst_omp_clauses (tree clauses, enum c_omp_region_type ort, OMP_CLAUSE_OPERAND (nc, 1) = tsubst_expr (OMP_CLAUSE_OPERAND (oc, 1), args, complain, in_decl, /*integral_constant_expression_p=*/false); + OMP_CLAUSE_OPERAND (nc, 2) + = tsubst_expr (OMP_CLAUSE_OPERAND (oc, 2), args, complain, + in_decl, /*integral_constant_expression_p=*/false); break; case OMP_CLAUSE_LINEAR: OMP_CLAUSE_DECL (nc) diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c index 35a7b9f7b83..0d8e5fde834 100644 --- a/gcc/cp/semantics.c +++ b/gcc/cp/semantics.c @@ -7527,7 +7527,44 @@ finish_omp_clauses (tree clauses, enum c_omp_region_type ort) bitmap_set_bit (&aligned_head, DECL_UID (t)); allocate_seen = true; } - tree allocator; + tree allocator, align; + align = OMP_CLAUSE_ALLOCATE_ALIGN (c); + if (error_operand_p (align)) + { + remove = true; + break; + } + if (align) + { + if (!type_dependent_expression_p (align) + && !INTEGRAL_TYPE_P (TREE_TYPE (align))) + { + error_at (OMP_CLAUSE_LOCATION (c), + "% clause % modifier " + "argument needs to be positive constant " + "power of two integer expression"); + remove = true; + } + else + { + align = mark_rvalue_use (align); + if (!processing_template_decl) + { + align = maybe_constant_value (align); + if (TREE_CODE (align) != INTEGER_CST + || !tree_fits_uhwi_p (align) + || !integer_pow2p (align)) + { + error_at (OMP_CLAUSE_LOCATION (c), + "% clause % modifier " + "argument needs to be positive constant " + "power of two integer expression"); + remove = true; + } + } + } + OMP_CLAUSE_ALLOCATE_ALIGN (c) = align; + } allocator = OMP_CLAUSE_ALLOCATE_ALLOCATOR (c); if (error_operand_p (allocator)) { @@ -7552,6 +7589,7 @@ finish_omp_clauses (tree clauses, enum c_omp_region_type ort) "type %qT rather than %", TREE_TYPE (allocator)); remove = true; + break; } else { diff --git a/gcc/omp-low.c b/gcc/omp-low.c index 27a513e2539..26c5c0261e9 100644 --- a/gcc/omp-low.c +++ b/gcc/omp-low.c @@ -1161,14 +1161,17 @@ scan_sharing_clauses (tree clauses, omp_context *ctx) 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)))) + || !integer_onep (OMP_CLAUSE_ALLOCATE_ALLOCATOR (c)) + || OMP_CLAUSE_ALLOCATE_ALIGN (c) != NULL_TREE)) { if (ctx->allocate_map == NULL) ctx->allocate_map = new hash_map; - ctx->allocate_map->put (OMP_CLAUSE_DECL (c), - OMP_CLAUSE_ALLOCATE_ALLOCATOR (c) - ? OMP_CLAUSE_ALLOCATE_ALLOCATOR (c) - : integer_zero_node); + tree val = integer_zero_node; + if (OMP_CLAUSE_ALLOCATE_ALLOCATOR (c)) + val = OMP_CLAUSE_ALLOCATE_ALLOCATOR (c); + if (OMP_CLAUSE_ALLOCATE_ALIGN (c)) + val = build_tree_list (val, OMP_CLAUSE_ALLOCATE_ALIGN (c)); + ctx->allocate_map->put (OMP_CLAUSE_DECL (c), val); } for (c = clauses; c; c = OMP_CLAUSE_CHAIN (c)) @@ -4725,6 +4728,12 @@ lower_private_allocate (tree var, tree new_var, tree &allocator, return false; } + unsigned HOST_WIDE_INT ialign = 0; + if (TREE_CODE (allocator) == TREE_LIST) + { + ialign = tree_to_uhwi (TREE_VALUE (allocator)); + allocator = TREE_PURPOSE (allocator); + } if (TREE_CODE (allocator) != INTEGER_CST) allocator = build_outer_var_ref (allocator, ctx); allocator = fold_convert (pointer_sized_int_node, allocator); @@ -4739,21 +4748,21 @@ lower_private_allocate (tree var, tree new_var, tree &allocator, if (TYPE_P (new_var)) { ptr_type = build_pointer_type (new_var); - align = build_int_cst (size_type_node, TYPE_ALIGN_UNIT (new_var)); + ialign = MAX (ialign, TYPE_ALIGN_UNIT (new_var)); } else 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))); + ialign = MAX (ialign, TYPE_ALIGN_UNIT (TREE_TYPE (ptr_type))); } else { ptr_type = build_pointer_type (TREE_TYPE (new_var)); - align = build_int_cst (size_type_node, DECL_ALIGN_UNIT (new_var)); + ialign = MAX (ialign, DECL_ALIGN_UNIT (new_var)); if (sz == NULL_TREE) sz = fold_convert (size_type_node, DECL_SIZE_UNIT (new_var)); } + align = build_int_cst (size_type_node, ialign); if (TREE_CODE (sz) != INTEGER_CST) { tree szvar = create_tmp_var (size_type_node); @@ -5707,6 +5716,8 @@ lower_rec_input_clauses (tree clauses, gimple_seq *ilist, gimple_seq *dlist, if (tree *allocatep = ctx->allocate_map->get (var)) { allocator = *allocatep; + if (TREE_CODE (allocator) == TREE_LIST) + allocator = TREE_PURPOSE (allocator); if (TREE_CODE (allocator) != INTEGER_CST) allocator = build_outer_var_ref (allocator, ctx); allocator = fold_convert (pointer_sized_int_node, @@ -6025,6 +6036,8 @@ lower_rec_input_clauses (tree clauses, gimple_seq *ilist, gimple_seq *dlist, if (tree *allocatep = ctx->allocate_map->get (var)) { allocator = *allocatep; + if (TREE_CODE (allocator) == TREE_LIST) + allocator = TREE_PURPOSE (allocator); if (TREE_CODE (allocator) != INTEGER_CST) allocator = build_outer_var_ref (allocator, ctx); allocator = fold_convert (pointer_sized_int_node, @@ -12070,6 +12083,12 @@ create_task_copyfn (gomp_task *task_stmt, omp_context *ctx) if (tree *allocatorp = ctx->allocate_map->get (decl)) { tree allocator = *allocatorp; + HOST_WIDE_INT ialign = 0; + if (TREE_CODE (allocator) == TREE_LIST) + { + ialign = tree_to_uhwi (TREE_VALUE (allocator)); + allocator = TREE_PURPOSE (allocator); + } if (TREE_CODE (allocator) != INTEGER_CST) { n = splay_tree_lookup (ctx->sfield_map, @@ -12083,7 +12102,8 @@ create_task_copyfn (gomp_task *task_stmt, omp_context *ctx) allocator = fold_convert (pointer_sized_int_node, allocator); tree a = builtin_decl_explicit (BUILT_IN_GOMP_ALLOC); tree align = build_int_cst (size_type_node, - DECL_ALIGN_UNIT (decl)); + MAX (ialign, + DECL_ALIGN_UNIT (decl))); tree sz = TYPE_SIZE_UNIT (TREE_TYPE (TREE_TYPE (dst))); tree ptr = build_call_expr_loc (loc, a, 3, align, sz, allocator); diff --git a/gcc/testsuite/c-c++-common/gomp/allocate-6.c b/gcc/testsuite/c-c++-common/gomp/allocate-6.c new file mode 100644 index 00000000000..059fd722821 --- /dev/null +++ b/gcc/testsuite/c-c++-common/gomp/allocate-6.c @@ -0,0 +1,84 @@ +typedef enum omp_allocator_handle_t +#if __cplusplus >= 201103L +: __UINTPTR_TYPE__ +#endif +{ + omp_null_allocator = 0, + omp_default_mem_alloc = 1, + omp_large_cap_mem_alloc = 2, + omp_const_mem_alloc = 3, + omp_high_bw_mem_alloc = 4, + omp_low_lat_mem_alloc = 5, + omp_cgroup_mem_alloc = 6, + omp_pteam_mem_alloc = 7, + omp_thread_mem_alloc = 8, + __omp_allocator_handle_t_max__ = __UINTPTR_MAX__ +} omp_allocator_handle_t; + +int bar (int, int *, int); +omp_allocator_handle_t baz (void); + +void +foo (int x, int z) +{ + int y[16] = { 0 }, r = 0, i; + omp_allocator_handle_t h = baz (); + #pragma omp parallel allocate (align (sizeof (int)) : x) allocate (allocator (omp_default_mem_alloc) : y) \ + allocate (align (8), allocator ((omp_allocator_handle_t) omp_default_mem_alloc):z) firstprivate (x, y, z) + bar (x, y, z); + #pragma omp task private (x) firstprivate (z) allocate (allocator (omp_low_lat_mem_alloc) :x,z) + bar (0, &x, z); + #pragma omp taskwait + #pragma omp target teams distribute parallel for private (x) firstprivate (y) \ + allocate (allocator ((omp_allocator_handle_t)(omp_default_mem_alloc + 0)), align (16) : z) \ + allocate (allocator (omp_default_mem_alloc) : x, y) allocate (align (32), allocator (omp_low_lat_mem_alloc): r) \ + lastprivate (z) reduction(+:r) + for (i = 0; i < 64; i++) + { + z = bar (0, &x, 0); + r += bar (1, y, 0); + } + #pragma omp single private (x) allocate (allocator (h):x) + ; + #pragma omp single allocate (align (2 * sizeof (int)), allocator (*&h) : x) private (x) + ; + #pragma omp parallel shared (r, x, z) + #pragma omp single firstprivate (r) allocate (align (4) : x, r, z) private (x, z) + ; + #pragma omp for allocate (align (2 * 2 * 2) : x) private (x) + for (i = 0; i < 64; i++) + x = 1; + #pragma omp sections private (x) allocate (allocator (omp_low_lat_mem_alloc), align (8): x) + { + x = 1; + #pragma omp section + x = 2; + #pragma omp section + x = 3; + } + #pragma omp taskgroup task_reduction(+:r) allocate (allocator (omp_default_mem_alloc), align (__alignof (r)) : r) + #pragma omp task in_reduction(+:r) allocate (align (2 * sizeof (r)), allocator (omp_default_mem_alloc) : r) + r += bar (r, &r, 0); + #pragma omp teams private (x) firstprivate (y) allocate (allocator (h), align (8) : x, y) + bar (x, y, 0); + #pragma omp taskloop lastprivate (x) reduction (+:r) allocate (align (16), allocator (h) : x, r) + for (i = 0; i < 16; i++) + { + r += bar (0, &r, 0); + x = i; + } + #pragma omp taskgroup task_reduction(+:r) allocate (allocator (omp_default_mem_alloc), align (64) : r) + #pragma omp taskloop firstprivate (x) in_reduction (+:r) \ + allocate (allocator (omp_default_mem_alloc), align (128) : x, r) + for (i = 0; i < 16; i++) + r += bar (x, &r, 0); + #pragma omp taskwait +} + +void +qux (const omp_allocator_handle_t h) +{ + int x = 0; + #pragma omp parallel firstprivate (x) allocate (align (16), allocator (h): x) + x = 1; +} diff --git a/gcc/testsuite/c-c++-common/gomp/allocate-7.c b/gcc/testsuite/c-c++-common/gomp/allocate-7.c new file mode 100644 index 00000000000..d125d92d9ba --- /dev/null +++ b/gcc/testsuite/c-c++-common/gomp/allocate-7.c @@ -0,0 +1,41 @@ +typedef enum omp_allocator_handle_t +#if __cplusplus >= 201103L +: __UINTPTR_TYPE__ +#endif +{ + omp_null_allocator = 0, + omp_default_mem_alloc = 1, + omp_large_cap_mem_alloc = 2, + omp_const_mem_alloc = 3, + omp_high_bw_mem_alloc = 4, + omp_low_lat_mem_alloc = 5, + omp_cgroup_mem_alloc = 6, + omp_pteam_mem_alloc = 7, + omp_thread_mem_alloc = 8, + __omp_allocator_handle_t_max__ = __UINTPTR_MAX__ +} omp_allocator_handle_t; + +int bar (int *); +omp_allocator_handle_t baz (void); + +void +foo (int x, int z) +{ + int i; + #pragma omp parallel private (x) allocate (allocator (0.0) : x) /* { dg-error "'allocate' clause allocator expression has type 'double' rather than 'omp_allocator_handle_t'" } */ + bar (&x); + #pragma omp parallel private (x) allocate (allocator (0) : x) /* { dg-error "'allocate' clause allocator expression has type 'int' rather than 'omp_allocator_handle_t'" } */ + bar (&x); + #pragma omp parallel private (x) allocate (align (z) : x) /* { dg-error "'allocate' clause 'align' modifier argument needs to be positive constant power of two integer expression" } */ + bar (&x); + #pragma omp parallel private (x) allocate (align (16.0) : x) /* { dg-error "'allocate' clause 'align' modifier argument needs to be positive constant power of two integer expression" } */ + bar (&x); + #pragma omp parallel private (x) allocate (align (14) : x) /* { dg-error "'allocate' clause 'align' modifier argument needs to be positive constant power of two integer expression" } */ + bar (&x); + #pragma omp parallel private (x) allocate (align (0) : x) /* { dg-error "'allocate' clause 'align' modifier argument needs to be positive constant power of two integer expression" } */ + bar (&x); + #pragma omp parallel private (x) allocate (align (16), align (16) : x) /* { dg-error "expected|duplicate|declared|specified" } */ + bar (&x); /* { dg-warning "more than once" "" { target c++ } .-1 } */ + #pragma omp parallel private (x) allocate (allocator (omp_default_mem_alloc), allocator (omp_default_mem_alloc) : x) /* { dg-error "expected|duplicate|declared|specified" } */ + bar (&x); /* { dg-warning "more than once" "" { target c++ } .-1 } */ +} diff --git a/gcc/testsuite/g++.dg/gomp/allocate-4.C b/gcc/testsuite/g++.dg/gomp/allocate-4.C new file mode 100644 index 00000000000..dd5e5f0fed5 --- /dev/null +++ b/gcc/testsuite/g++.dg/gomp/allocate-4.C @@ -0,0 +1,108 @@ +// { dg-do compile } +// { dg-additional-options "-std=c++11" } + +typedef enum omp_allocator_handle_t +#if __cplusplus >= 201103L +: __UINTPTR_TYPE__ +#endif +{ + omp_null_allocator = 0, + omp_default_mem_alloc = 1, + omp_large_cap_mem_alloc = 2, + omp_const_mem_alloc = 3, + omp_high_bw_mem_alloc = 4, + omp_low_lat_mem_alloc = 5, + omp_cgroup_mem_alloc = 6, + omp_pteam_mem_alloc = 7, + omp_thread_mem_alloc = 8, + __omp_allocator_handle_t_max__ = __UINTPTR_MAX__ +} omp_allocator_handle_t; + +namespace N1 +{ + using ::omp_allocator_handle_t; + void + foo (const omp_allocator_handle_t h) + { + int x = 0; + #pragma omp parallel allocate (allocator (h): x) private (x) + x = 1; + } +} + +namespace N2 +{ + typedef enum omp_allocator_handle_t { my = 0 } omp_allocator_handle_t; + void + foo (omp_allocator_handle_t h) + { + int x = 0; + #pragma omp parallel allocate (allocator (h): x) private (x) // { dg-error "'allocate' clause allocator expression has type 'N2::omp_allocator_handle_t' rather than 'omp_allocator_handle_t'" } + x = 1; + } +} + +struct S +{ + void foo () + { + #pragma omp parallel allocate (allocator(omp_default_mem_alloc):s) firstprivate (s) + s++; + } + int s; +}; + +template +struct U +{ + int foo () + { + #pragma omp parallel allocate (allocator(omp_default_mem_alloc):s) firstprivate (s) + s++; + return 1; + } + T s; +}; + +template +int foo (T t) +{ + int x = 0; + #pragma omp parallel firstprivate (x) allocate (allocator(t), align (N): x) + x = 1; + return 0; +} + +template +int bar (T t) +{ + int x = 0; + #pragma omp parallel firstprivate (x) allocate (allocator(t): x) // { dg-error "'allocate' clause allocator expression has type 'int' rather than 'omp_allocator_handle_t'" } + x = 1; + return 0; +} + +template +int baz (T t) +{ + int x = 0; + #pragma omp parallel firstprivate (x) allocate (allocator(t), align (N): x) // { dg-error "'allocate' clause 'align' modifier argument needs to be positive constant power of two integer expression" } + x = 1; + return 0; +} + +template +int qux () +{ + int x = 0; + #pragma omp parallel firstprivate (x) allocate (align ((T) 16): x) // { dg-error "'allocate' clause 'align' modifier argument needs to be positive constant power of two integer expression" } + x = 1; + return 0; +} + +omp_allocator_handle_t h; +int a = foo (h); +int b = bar (0); +int c = U ().foo (); +int d = baz (h); +int e = qux (); diff --git a/gcc/tree-pretty-print.c b/gcc/tree-pretty-print.c index 7de12f33fef..35e567cbfaf 100644 --- a/gcc/tree-pretty-print.c +++ b/gcc/tree-pretty-print.c @@ -735,10 +735,23 @@ dump_omp_clause (pretty_printer *pp, tree clause, int spc, dump_flags_t flags) pp_string (pp, "allocate("); if (OMP_CLAUSE_ALLOCATE_ALLOCATOR (clause)) { + pp_string (pp, "allocator("); dump_generic_node (pp, OMP_CLAUSE_ALLOCATE_ALLOCATOR (clause), spc, flags, false); - pp_colon (pp); + pp_right_paren (pp); } + if (OMP_CLAUSE_ALLOCATE_ALIGN (clause)) + { + if (OMP_CLAUSE_ALLOCATE_ALLOCATOR (clause)) + pp_comma (pp); + pp_string (pp, "align("); + dump_generic_node (pp, OMP_CLAUSE_ALLOCATE_ALIGN (clause), + spc, flags, false); + pp_right_paren (pp); + } + if (OMP_CLAUSE_ALLOCATE_ALLOCATOR (clause) + || OMP_CLAUSE_ALLOCATE_ALIGN (clause)) + pp_colon (pp); dump_generic_node (pp, OMP_CLAUSE_DECL (clause), spc, flags, false); pp_right_paren (pp); diff --git a/gcc/tree.c b/gcc/tree.c index 994775d7314..561b9cd56bd 100644 --- a/gcc/tree.c +++ b/gcc/tree.c @@ -291,7 +291,7 @@ unsigned const char omp_clause_num_ops[] = 3, /* OMP_CLAUSE_LINEAR */ 1, /* OMP_CLAUSE_AFFINITY */ 2, /* OMP_CLAUSE_ALIGNED */ - 2, /* OMP_CLAUSE_ALLOCATE */ + 3, /* OMP_CLAUSE_ALLOCATE */ 1, /* OMP_CLAUSE_DEPEND */ 1, /* OMP_CLAUSE_NONTEMPORAL */ 1, /* OMP_CLAUSE_UNIFORM */ diff --git a/gcc/tree.h b/gcc/tree.h index 091ad3d3777..7d1257b7a75 100644 --- a/gcc/tree.h +++ b/gcc/tree.h @@ -1790,6 +1790,9 @@ class auto_suppress_location_wrappers #define OMP_CLAUSE_ALLOCATE_ALLOCATOR(NODE) \ OMP_CLAUSE_OPERAND (OMP_CLAUSE_SUBCODE_CHECK (NODE, OMP_CLAUSE_ALLOCATE), 1) +#define OMP_CLAUSE_ALLOCATE_ALIGN(NODE) \ + OMP_CLAUSE_OPERAND (OMP_CLAUSE_SUBCODE_CHECK (NODE, OMP_CLAUSE_ALLOCATE), 2) + /* True if an ALLOCATE clause was present on a combined or composite construct and the code for splitting the clauses has already performed checking if the listed variable has explicit privatization on the diff --git a/libgomp/testsuite/libgomp.c-c++-common/allocate-2.c b/libgomp/testsuite/libgomp.c-c++-common/allocate-2.c new file mode 100644 index 00000000000..e4cd09ae065 --- /dev/null +++ b/libgomp/testsuite/libgomp.c-c++-common/allocate-2.c @@ -0,0 +1,37 @@ +#include +#include +#include + +int zero; + +omp_allocator_handle_t +allocator (omp_allocator_handle_t h) +{ + if (zero) + return h; + else + abort (); +} + +omp_allocator_handle_t +align (int a) +{ + if (zero) + return omp_default_mem_alloc; + else + abort (); +} + +int +main () +{ + int x = 1, y = 2; + #pragma omp parallel num_threads(2) firstprivate (x, y) allocate (allocator (omp_default_mem_alloc) : x) allocate (align (16) : y) + { + if (x != 1 || y != 2) + abort (); + if ((((uintptr_t) &y) & 15) != 0) + abort (); + } + return 0; +} diff --git a/libgomp/testsuite/libgomp.c-c++-common/allocate-3.c b/libgomp/testsuite/libgomp.c-c++-common/allocate-3.c new file mode 100644 index 00000000000..ce1a045a407 --- /dev/null +++ b/libgomp/testsuite/libgomp.c-c++-common/allocate-3.c @@ -0,0 +1,405 @@ +#include +#include +#include + +struct S { int a, b; }; + +void +foo (int x, int *p, int *q, int px, 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 r2[4] = { 0, 0, 0, 0 }; + int xo = x; + struct S s = { 27, 29 }; + for (i = 0; i < 4; i++) + p[i] = 0; + for (i = 0; i < 3; i++) + q[i] = 0; + for (i = 0; i < x; i++) + w[i] = i; + #pragma omp parallel private (y, v) firstprivate (x) allocate (align (32) : x) allocate (align (128) : y) allocate (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 (); + if ((((uintptr_t) p1) & 31) != 0) + abort (); + if ((((uintptr_t) p2) & 127) != 0) + abort (); + } + x = xo; + #pragma omp teams + #pragma omp parallel private (y) firstprivate (x, w) allocate (allocator (h), align (32) : x) allocate (align (128), allocator (h):y) allocate(allocator(h):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 (); + if ((((uintptr_t) p1) & 31) != 0) + abort (); + if ((((uintptr_t) p2) & 127) != 0) + abort (); + } + x = xo; + #pragma omp parallel for private (y) firstprivate (x) allocate (allocator (h), align (32) : x, y, r) allocate (align (128), allocator (h) : 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 (); + if ((((uintptr_t) &x | (uintptr_t) &y | (uintptr_t) &r) & 31) != 0) + abort (); + if ((((uintptr_t) &l | (uintptr_t) &n) & 127) != 0) + abort (); + } + x = xo; + #pragma omp parallel + { + #pragma omp for lastprivate (l2) private (i1) allocate (allocator (h): l2, l3) allocate (allocator (h),align(16): 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 (); + if ((((uintptr_t) &i1) & 15) != 0) + abort (); + } + #pragma omp for collapse(2) lastprivate(l4, i2, j2) linear (n2:17) allocate (allocator (h), align (8): 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 (); + if ((((uintptr_t) &l4 | (uintptr_t) &n2 | (uintptr_t) &i2 | (uintptr_t) &j2) & 7) != 0) + abort (); + } + #pragma omp for collapse(2) lastprivate(l5, i3, j3) linear (n3:17) schedule (static, 3) allocate (align (16): 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 (); + if ((((uintptr_t) &l5 | (uintptr_t) &n3 | (uintptr_t) &i3 | (uintptr_t) &j3) & 15) != 0) + abort (); + } + #pragma omp for collapse(2) lastprivate(l6, i4, j4) linear (n4:17) schedule (dynamic) allocate (align (16), allocator (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 (); + if ((((uintptr_t) &l6 | (uintptr_t) &n4 | (uintptr_t) &i4 | (uintptr_t) &j4) & 15) != 0) + abort (); + } + #pragma omp for lastprivate (i5) allocate (align (32): i5) + for (i5 = 1; i5 < 17; i5 += 3) + { + if ((fl & 2) && (((uintptr_t) &i5) & 63) != 0) + abort (); + if ((((uintptr_t) &i5) & 31) != 0) + abort (); + } + #pragma omp for reduction(+:p[2:px], q[:3], r2) allocate(align (16), allocator (h): p, q, r2) + for (i = 0; i < 32; i++) + { + p[2] += i; + p[3] += 2 * i; + q[0] += 3 * i; + q[2] += 4 * i; + r2[0] += 5 * i; + r2[3] += 6 * i; + /* Can't really rely on alignment of &p[0], the implementation could + allocate the whole array or do what GCC does and allocate only part + of it. */ + if ((fl & 1) && (((uintptr_t) &q[0] | (uintptr_t) &r2[0]) & 63) != 0) + abort (); + if ((((uintptr_t) &q[0] | (uintptr_t) &r2[0]) & 15) != 0) + abort (); + } + #pragma omp task private(y) firstprivate(x) allocate(align (8) : x, y) + { + int *volatile p1 = &x; + int *volatile p2 = &y; + if (x != 42) + abort (); + p1[0]++; + p2[0] = 21; + if (x != 43 || y != 21) + abort (); + if ((fl & 2) && (((uintptr_t) p1 | (uintptr_t) p2) & 63) != 0) + abort (); + if ((((uintptr_t) p1 | (uintptr_t) p2) & 7) != 0) + abort (); + } + #pragma omp task private(y) firstprivate(x) allocate(allocator (h),align(32): x, y) + { + int *volatile p1 = &x; + int *volatile p2 = &y; + if (x != 42) + abort (); + p1[0]++; + p2[0] = 21; + if (x != 43 || y != 21) + abort (); + if ((fl & 1) && (((uintptr_t) p1 | (uintptr_t) p2) & 63) != 0) + abort (); + if ((((uintptr_t) p1 | (uintptr_t) p2) & 31) != 0) + abort (); + } + #pragma omp task private(y) firstprivate(s) allocate(align(16): s, y) + { + int *volatile p1 = &s.a; + int *volatile p2 = &s.b; + int *volatile p3 = &y; + if (s.a != 27 || s.b != 29) + abort (); + p1[0]++; + p2[0]++; + p3[0] = 21; + if (s.a != 28 || s.b != 30 || y != 21) + abort (); + if ((fl & 2) && (((uintptr_t) p1 | (uintptr_t) p3) & 63) != 0) + abort (); + if ((((uintptr_t) p1 | (uintptr_t) p3) & 15) != 0) + abort (); + } + #pragma omp task private(y) firstprivate(s) allocate(allocator (h): s, y) + { + int *volatile p1 = &s.a; + int *volatile p2 = &s.b; + int *volatile p3 = &y; + if (s.a != 27 || s.b != 29) + abort (); + p1[0]++; + p2[0]++; + p3[0] = 21; + if (s.a != 28 || s.b != 30 || y != 21) + abort (); + if ((fl & 1) && (((uintptr_t) p1 | (uintptr_t) p3) & 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 (); + if (p[2] != (32 * 31) / 2 || p[3] != 2 * (32 * 31) / 2 + || q[0] != 3 * (32 * 31) / 2 || q[2] != 4 * (32 * 31) / 2 + || r2[0] != 5 * (32 * 31) / 2 || r2[3] != 6 * (32 * 31) / 2) + 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; + struct S s = { 27, 29 }; + int xo = x; + #pragma omp parallel private (y) firstprivate (x) allocate (x, y) + { + if (x != 42) + abort (); + #pragma omp barrier + y = 1; + x++; + #pragma omp barrier + if (x != 43 || y != 1) + abort (); + } + x = xo; + #pragma omp teams + #pragma omp parallel private (y) firstprivate (x) allocate (allocator (h): x, y) + { + if (x != 42) + abort (); + #pragma omp barrier + y = 1; + x++; + #pragma omp barrier + if (x != 43 || y != 1) + abort (); + } + x = xo; + #pragma omp parallel for private (y) firstprivate (x) allocate (allocator (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; + } + x = xo; + #pragma omp parallel + { + #pragma omp for lastprivate (l2) private (i1) allocate (allocator (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 (allocator (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 (allocator (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) + ; + #pragma omp task private(y) firstprivate(x) allocate(x, y) + { + if (x != 42) + abort (); + x++; + y = 21; + if (x != 43 || y != 21) + abort (); + } + #pragma omp task private(y) firstprivate(x) allocate(allocator (h): x, y) + { + if (x != 42) + abort (); + x++; + y = 21; + if (x != 43 || y != 21) + abort (); + } + #pragma omp task private(y) firstprivate(s) allocate(s, y) + { + if (s.a != 27 || s.b != 29) + abort (); + s.a++; + s.b++; + y = 21; + if (s.a != 28 || s.b != 30 || y != 21) + abort (); + } + #pragma omp task private(y) firstprivate(s) allocate(allocator (h), align (16): s, y) + { + if (s.a != 27 || s.b != 29) + abort (); + s.a++; + s.b++; + y = 21; + if (s.a != 28 || s.b != 30 || y != 21) + 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 (); +} + +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); + int p[4], q[3]; + if (a == omp_null_allocator) + abort (); + omp_set_default_allocator (omp_default_mem_alloc); + foo (42, p, q, 2, omp_null_allocator, 0); + foo (42, p, q, 2, omp_default_mem_alloc, 0); + foo (42, p, q, 2, a, 1); + omp_set_default_allocator (a); + foo (42, p, q, 2, omp_null_allocator, 3); + foo (42, p, q, 2, omp_default_mem_alloc, 2); + bar (42, a); + omp_destroy_allocator (a); + return 0; +}