OpenMP (C only): omp allocate - handle stack vars, improve diagnostic
The 'allocate' directive can be used for both stack and static variables.
While the parser in C and C++ was pre-existing, it missed several
diagnostics, which this commit adds - for now only for C.
Additionally, it stopped with a sorry after parsing.
For C only, the sorry is now restricted to static variables, the stack
variable declarations are now tagged by the 'omp allocate' attribute and
in gimplify_bind_expr the GOMP_alloc/GOMP_free allocation will now be
added.
Follow up: Add the same parser additions for C++ and update the testcases.
And add Fortran support, where also parsing support exists, where also
diagnostic updates are required.
gcc/c/ChangeLog:
* c-parser.cc (c_parser_omp_construct): Move call to
c_parser_omp_allocate to ...
(c_parser_pragma): ... here.
(c_parser_omp_allocate): Avoid ICE is allocator could not
be parsed; set 'omp allocate' attribute for stack variables
and only reject stack variables; add several additional
restriction checks.
gcc/ChangeLog:
* gimplify.cc (gimplify_bind_expr): Convert 'omp allocate'
var-decl attribute to GOMP_alloc/GOMP_free calls.
libgomp/ChangeLog:
* libgomp.texi (Impl.Status): Mark allocate directive as 'P'.
(OMP_ALLOCATOR): Fix name of ICV variable.
* testsuite/libgomp.c-c++-common/allocate-4.c: New test.
gcc/testsuite/ChangeLog:
* c-c++-common/gomp/allocate-5.c: Fix testcase; make some
dg-messages for 'sorry' as c++, only.
* c-c++-common/gomp/directive-1.c: Make a 'sorry' c++ only.
* c-c++-common/gomp/allocate-10.c: New test.
* c-c++-common/gomp/allocate-9.c: New test.
gcc/c/c-parser.cc | 73 ++++++++++++++---
gcc/gimplify.cc | 82 +++++++++++++++----
gcc/testsuite/c-c++-common/gomp/allocate-10.c | 46 +++++++++++
gcc/testsuite/c-c++-common/gomp/allocate-5.c | 58 ++++++-------
gcc/testsuite/c-c++-common/gomp/allocate-9.c | 94 ++++++++++++++++++++++
gcc/testsuite/c-c++-common/gomp/directive-1.c | 2 +-
libgomp/libgomp.texi | 7 +-
.../testsuite/libgomp.c-c++-common/allocate-4.c | 75 +++++++++++++++++
8 files changed, 377 insertions(+), 60 deletions(-)
@@ -1679,6 +1679,7 @@ static bool c_parser_omp_declare (c_parser *, enum pragma_context);
static void c_parser_omp_requires (c_parser *);
static bool c_parser_omp_error (c_parser *, enum pragma_context);
static void c_parser_omp_assumption_clauses (c_parser *, bool);
+static void c_parser_omp_allocate (c_parser *);
static void c_parser_omp_assumes (c_parser *);
static bool c_parser_omp_ordered (c_parser *, enum pragma_context, bool *);
static void c_parser_oacc_routine (c_parser *, enum pragma_context);
@@ -13620,6 +13621,10 @@ c_parser_pragma (c_parser *parser, enum pragma_context context, bool *if_p)
c_parser_omp_requires (parser);
return false;
+ case PRAGMA_OMP_ALLOCATE:
+ c_parser_omp_allocate (parser);
+ return false;
+
case PRAGMA_OMP_ASSUMES:
if (context != pragma_external)
{
@@ -19316,10 +19321,13 @@ c_parser_oacc_wait (location_t loc, c_parser *parser, char *p_name)
align (constant-expression)] */
static void
-c_parser_omp_allocate (location_t loc, c_parser *parser)
+c_parser_omp_allocate (c_parser *parser)
{
tree alignment = NULL_TREE;
tree allocator = NULL_TREE;
+ c_parser_consume_pragma (parser);
+ location_t loc = c_parser_peek_token (parser)->location;
+ location_t allocator_loc = UNKNOWN_LOCATION;
tree nl = c_parser_omp_var_list_parens (parser, OMP_CLAUSE_ALLOCATE, NULL_TREE);
do
{
@@ -19344,7 +19352,9 @@ c_parser_omp_allocate (location_t loc, c_parser *parser)
c_expr expr = c_parser_expr_no_commas (parser, NULL);
expr = convert_lvalue_to_rvalue (expr_loc, expr, false, true);
expr_loc = c_parser_peek_token (parser)->location;
- if (p[2] == 'i' && alignment)
+ if (expr.value == error_mark_node)
+ ;
+ else if (p[2] == 'i' && alignment)
{
error_at (expr_loc, "too many %qs clauses", "align");
break;
@@ -19371,6 +19381,7 @@ c_parser_omp_allocate (location_t loc, c_parser *parser)
else
{
allocator = c_fully_fold (expr.value, false, NULL);
+ allocator_loc = expr_loc;
tree orig_type
= expr.original_type ? expr.original_type : TREE_TYPE (allocator);
orig_type = TYPE_MAIN_VARIANT (orig_type);
@@ -19390,14 +19401,53 @@ c_parser_omp_allocate (location_t loc, c_parser *parser)
} while (true);
c_parser_skip_to_pragma_eol (parser);
- if (allocator || alignment)
- for (tree c = nl; c != NULL_TREE; c = OMP_CLAUSE_CHAIN (c))
- {
- OMP_CLAUSE_ALLOCATE_ALLOCATOR (c) = allocator;
- OMP_CLAUSE_ALLOCATE_ALIGN (c) = alignment;
- }
-
- sorry_at (loc, "%<#pragma omp allocate%> not yet supported");
+ for (tree c = nl; c != NULL_TREE; c = OMP_CLAUSE_CHAIN (c))
+ {
+ tree var = OMP_CLAUSE_DECL (c);
+ if (TREE_CODE (var) == PARM_DECL)
+ {
+ error_at (OMP_CLAUSE_LOCATION (nl),
+ "function parameter %qD may not appear as list item in an "
+ "%<allocate%> directive", var);
+ continue;
+ }
+ if (!c_check_in_current_scope (var))
+ {
+ error_at (OMP_CLAUSE_LOCATION (nl),
+ "%<allocate%> directive must be in the same scope as %qD",
+ var);
+ inform (DECL_SOURCE_LOCATION (var), "declared here");
+ continue;
+ }
+ if (lookup_attribute ("omp allocate", DECL_ATTRIBUTES (var)))
+ {
+ error_at (OMP_CLAUSE_LOCATION (nl),
+ "%qD already appeared as list item in an "
+ "%<allocate%> directive", var);
+ continue;
+ }
+ if (TREE_STATIC (var))
+ {
+ if (allocator == NULL_TREE && allocator_loc == UNKNOWN_LOCATION)
+ error_at (loc, "%<allocator%> clause required for "
+ "static variable %qD", var);
+ else if (allocator
+ && (tree_int_cst_sgn (allocator) != 1
+ || tree_to_shwi (allocator) > 8))
+ /* 8 = largest predefined memory allocator. */
+ error_at (allocator_loc,
+ "%<allocator%> clause requires a predefined allocator as "
+ "%qD is static", var);
+ else
+ sorry_at (OMP_CLAUSE_LOCATION (nl),
+ "%<#pragma omp allocate%> for static variables like "
+ "%qD not yet supported", var);
+ continue;
+ }
+ DECL_ATTRIBUTES (var) = tree_cons (get_identifier ("omp allocate"),
+ build_tree_list (allocator, alignment),
+ DECL_ATTRIBUTES (var));
+ }
}
/* OpenMP 2.5:
@@ -24894,9 +24944,6 @@ c_parser_omp_construct (c_parser *parser, bool *if_p)
strcpy (p_name, "#pragma wait");
stmt = c_parser_oacc_wait (loc, parser, p_name);
break;
- case PRAGMA_OMP_ALLOCATE:
- c_parser_omp_allocate (loc, parser);
- return;
case PRAGMA_OMP_ATOMIC:
c_parser_omp_atomic (loc, parser, false);
return;
@@ -1364,6 +1364,44 @@ gimplify_bind_expr (tree *expr_p, gimple_seq *pre_p)
{
struct gimplify_omp_ctx *ctx = gimplify_omp_ctxp;
+ tree attr;
+ if (flag_openmp
+ && !is_global_var (t)
+ && DECL_CONTEXT (t) == current_function_decl
+ && TREE_USED (t)
+ && (attr = lookup_attribute ("omp allocate", DECL_ATTRIBUTES (t)))
+ != NULL_TREE)
+ {
+ tree v = create_tmp_var_raw (build_pointer_type (TREE_TYPE (t)));
+ DECL_IGNORED_P (v) = 0;
+ tree tmp = build_fold_indirect_ref (v);
+ TREE_THIS_NOTRAP (tmp) = 1;
+ SET_DECL_VALUE_EXPR (t, tmp);
+ DECL_HAS_VALUE_EXPR_P (t) = 1;
+ attr = TREE_VALUE (attr);
+ tree sz = TYPE_SIZE_UNIT (TREE_TYPE (t));
+ tree alloc = (TREE_PURPOSE (attr)
+ ? TREE_PURPOSE (attr)
+ : build_zero_cst (ptr_type_node));
+ tree align = (TREE_VALUE (attr)
+ ? TREE_VALUE (attr) : build_zero_cst (size_type_node));
+ tmp = builtin_decl_explicit (BUILT_IN_GOMP_ALLOC);
+ tmp = build_call_expr_loc (DECL_SOURCE_LOCATION (t), tmp, 3, align, sz, alloc);
+ tmp = fold_build2_loc (DECL_SOURCE_LOCATION (t), MODIFY_EXPR, TREE_TYPE (v), v,
+ fold_convert (TREE_TYPE (v), tmp));
+ gcc_assert (BIND_EXPR_BODY (bind_expr) != NULL_TREE
+ && TREE_CODE (BIND_EXPR_BODY (bind_expr)) == STATEMENT_LIST);
+ tree_stmt_iterator e = tsi_start (BIND_EXPR_BODY (bind_expr));
+ while (!tsi_end_p (e))
+ {
+ if (EXPR_LOCATION (*e) == DECL_SOURCE_LOCATION (t))
+ break;
+ ++e;
+ }
+ gcc_assert (!tsi_end_p (e));
+ tsi_link_before (&e, tmp, TSI_SAME_STMT);
+ }
+
/* Mark variable as local. */
if (ctx && ctx->region_type != ORT_NONE && !DECL_EXTERNAL (t))
{
@@ -1446,22 +1484,6 @@ gimplify_bind_expr (tree *expr_p, gimple_seq *pre_p)
cleanup = NULL;
stack_save = NULL;
- /* If the code both contains VLAs and calls alloca, then we cannot reclaim
- the stack space allocated to the VLAs. */
- if (gimplify_ctxp->save_stack && !gimplify_ctxp->keep_stack)
- {
- gcall *stack_restore;
-
- /* Save stack on entry and restore it on exit. Add a try_finally
- block to achieve this. */
- build_stack_save_restore (&stack_save, &stack_restore);
-
- gimple_set_location (stack_save, start_locus);
- gimple_set_location (stack_restore, end_locus);
-
- gimplify_seq_add_stmt (&cleanup, stack_restore);
- }
-
/* Add clobbers for all variables that go out of scope. */
for (t = BIND_EXPR_VARS (bind_expr); t ; t = DECL_CHAIN (t))
{
@@ -1469,6 +1491,17 @@ gimplify_bind_expr (tree *expr_p, gimple_seq *pre_p)
&& !is_global_var (t)
&& DECL_CONTEXT (t) == current_function_decl)
{
+ if (flag_openmp
+ && DECL_HAS_VALUE_EXPR_P (t)
+ && TREE_USED (t)
+ && lookup_attribute ("omp allocate", DECL_ATTRIBUTES (t)))
+ {
+ tree tmp = builtin_decl_explicit (BUILT_IN_GOMP_FREE);
+ tmp = build_call_expr_loc (end_locus, tmp, 2,
+ TREE_OPERAND (DECL_VALUE_EXPR (t), 0),
+ build_zero_cst (ptr_type_node));
+ gimplify_and_add (tmp, &cleanup);
+ }
if (!DECL_HARD_REGISTER (t)
&& !TREE_THIS_VOLATILE (t)
&& !DECL_HAS_VALUE_EXPR_P (t)
@@ -1525,6 +1558,23 @@ gimplify_bind_expr (tree *expr_p, gimple_seq *pre_p)
gimplify_ctxp->live_switch_vars->remove (t);
}
+ /* If the code both contains VLAs and calls alloca, then we cannot reclaim
+ the stack space allocated to the VLAs. */
+ if (gimplify_ctxp->save_stack && !gimplify_ctxp->keep_stack)
+ {
+ gcall *stack_restore;
+
+ /* Save stack on entry and restore it on exit. Add a try_finally
+ block to achieve this. */
+ build_stack_save_restore (&stack_save, &stack_restore);
+
+ gimple_set_location (stack_save, start_locus);
+ gimple_set_location (stack_restore, end_locus);
+
+ gimplify_seq_add_stmt (&cleanup, stack_restore);
+ }
+
+
if (ret_clauses)
{
gomp_target *stmt;
new file mode 100644
@@ -0,0 +1,46 @@
+/* TODO: enable for C++ once implemented. */
+/* { dg-do compile { target c } } */
+/* { dg-additional-options "-Wall -fdump-tree-gimple" } */
+
+typedef enum omp_allocator_handle_t
+{
+ omp_default_mem_alloc = 1,
+ __omp_allocator_handle_t_max__ = __UINTPTR_MAX__
+} omp_allocator_handle_t;
+
+void
+f()
+{
+ int n;
+ int A[n]; /* { dg-warning "'n' is used uninitialized" } */
+ /* { dg-warning "unused variable 'A'" "" { target *-*-* } .-1 } */
+}
+
+void
+h1()
+{
+ omp_allocator_handle_t my_handle;
+ int B1[3]; /* { dg-warning "'my_handle' is used uninitialized" } */
+ /* { dg-warning "variable 'B1' set but not used" "" { target *-*-* } .-1 } */
+ #pragma omp allocate(B1) allocator(my_handle)
+ B1[0] = 5;
+ /* { dg-final { scan-tree-dump-times "__builtin_GOMP_alloc" 1 "gimple" } } */
+ /* { dg-final { scan-tree-dump-times "D.\[0-9\]+ = __builtin_GOMP_alloc \\(0, 12, my_handle\\);" 1 "gimple" } } */
+ /* { dg-final { scan-tree-dump-times "__builtin_GOMP_free \\(D.\[0-9\]+, 0B\\);" 1 "gimple" } } */
+}
+
+void
+h2()
+{
+ omp_allocator_handle_t my_handle;
+ int B2[3]; /* { dg-warning "unused variable 'B2'" } */
+ #pragma omp allocate(B2) allocator(my_handle) /* No warning as 'B2' is unused */
+}
+
+void
+h3()
+{
+ omp_allocator_handle_t my_handle;
+ int B3[3] = {1,2,3}; /* { dg-warning "unused variable 'B3'" } */
+ #pragma omp allocate(B3) allocator(my_handle) /* No warning as 'B3' is unused */
+}
@@ -19,59 +19,63 @@ void
foo ()
{
int a, b;
+ static int c;
omp_allocator_handle_t my_allocator;
-#pragma omp allocate (a) /* { dg-message "sorry, unimplemented: '#pragma omp allocate' not yet supported" } */
-#pragma omp allocate (b) allocator(my_allocator) /* { dg-message "sorry, unimplemented: '#pragma omp allocate' not yet supported" } */
+#pragma omp allocate (a) /* { dg-message "sorry, unimplemented: '#pragma omp allocate' not yet supported" "" { target c++ } } */
+#pragma omp allocate (b) allocator(my_allocator) /* { dg-message "sorry, unimplemented: '#pragma omp allocate' not yet supported" "" { target c++ } } */
+#pragma omp allocate(c) align(32)
+ /* { dg-message "'allocator' clause required for static variable 'c'" "" { target c } .-1 } */
+ /* { dg-message "sorry, unimplemented: '#pragma omp allocate' not yet supported" "" { target c++ } .-2 } */
}
void
bar ()
{
- int a, b;
+ int a, a2, b;
omp_allocator_handle_t my_allocator;
#pragma omp allocate /* { dg-error "expected '\\(' before end of line" } */
- /* { dg-message "sorry, unimplemented: '#pragma omp allocate' not yet supported" "" { target *-*-* } .-1 } */
+ /* { dg-message "sorry, unimplemented: '#pragma omp allocate' not yet supported" "" { target c++ } .-1 } */
#pragma omp allocate allocator(my_allocator) /* { dg-error "expected '\\(' before 'allocator'" } */
- /* { dg-message "sorry, unimplemented: '#pragma omp allocate' not yet supported" "" { target *-*-* } .-1 } */
+ /* { dg-message "sorry, unimplemented: '#pragma omp allocate' not yet supported" "" { target c++ } .-1 } */
#pragma omp allocate(a) foo(my_allocator) /* { dg-error "expected 'allocator'" } */
/* { dg-error "expected end of line before '\\(' token" "" { target *-*-* } .-1 } */
- /* { dg-message "sorry, unimplemented: '#pragma omp allocate' not yet supported" "" { target *-*-* } .-2 } */
-#pragma omp allocate(a) allocator(b) /* { dg-error "'allocator' clause allocator expression has type 'int' rather than 'omp_allocator_handle_t'" "todo: cp/semantics.c" { xfail c++ } } */
- /* { dg-message "sorry, unimplemented: '#pragma omp allocate' not yet supported" "" { target *-*-* } .-1 } */
+ /* { dg-message "sorry, unimplemented: '#pragma omp allocate' not yet supported" "" { target c++ } .-2 } */
+#pragma omp allocate(a2) allocator(b) /* { dg-error "'allocator' clause allocator expression has type 'int' rather than 'omp_allocator_handle_t'" "todo: cp/semantics.c" { xfail c++ } } */
+ /* { dg-message "sorry, unimplemented: '#pragma omp allocate' not yet supported" "" { target c++ } .-1 } */
}
void
align_test ()
{
- int i;
- #pragma omp allocate(i) allocator(omp_default_mem_alloc), align(32)
- /* { dg-message "sorry, unimplemented: '#pragma omp allocate' not yet supported" "" { target *-*-* } .-1 } */
- #pragma omp allocate(i) align ( 32 ),allocator(omp_default_mem_alloc)
- /* { dg-message "sorry, unimplemented: '#pragma omp allocate' not yet supported" "" { target *-*-* } .-1 } */
- #pragma omp allocate(i),allocator(omp_default_mem_alloc) align(32)
- /* { dg-message "sorry, unimplemented: '#pragma omp allocate' not yet supported" "" { target *-*-* } .-1 } */
- #pragma omp allocate(i) align ( 32 ) allocator(omp_default_mem_alloc)
- /* { dg-message "sorry, unimplemented: '#pragma omp allocate' not yet supported" "" { target *-*-* } .-1 } */
+ int i1,i2,i3,i4,i5,i6;
+ #pragma omp allocate(i1) allocator(omp_default_mem_alloc), align(32)
+ /* { dg-message "sorry, unimplemented: '#pragma omp allocate' not yet supported" "" { target c++ } .-1 } */
+ #pragma omp allocate(i2) align ( 32 ),allocator(omp_default_mem_alloc)
+ /* { dg-message "sorry, unimplemented: '#pragma omp allocate' not yet supported" "" { target c++ } .-1 } */
+ #pragma omp allocate(i3),allocator(omp_default_mem_alloc) align(32)
+ /* { dg-message "sorry, unimplemented: '#pragma omp allocate' not yet supported" "" { target c++ } .-1 } */
+ #pragma omp allocate(i4) align ( 32 ) allocator(omp_default_mem_alloc)
+ /* { dg-message "sorry, unimplemented: '#pragma omp allocate' not yet supported" "" { target c++ } .-1 } */
- #pragma omp allocate(i) allocator ( omp_high_bw_mem_alloc ), align ( 32 ) allocator(omp_default_mem_alloc)
+ #pragma omp allocate(i5) allocator ( omp_high_bw_mem_alloc ), align ( 32 ) allocator(omp_default_mem_alloc)
/* { dg-error "too many 'allocator' clauses" "" { target *-*-* } .-1 } */
/* { dg-error "expected end of line before '\\)' token" "" { target *-*-* } .-2 } */
- /* { dg-message "sorry, unimplemented: '#pragma omp allocate' not yet supported" "" { target *-*-* } .-3 } */
- #pragma omp allocate(i) align ( 32 ), align(32) allocator(omp_default_mem_alloc)
+ /* { dg-message "sorry, unimplemented: '#pragma omp allocate' not yet supported" "" { target c++ } .-3 } */
+ #pragma omp allocate(i6) align ( 32 ), align(32) allocator(omp_default_mem_alloc)
/* { dg-error "too many 'align' clauses" "" { target *-*-* } .-1 } */
/* { dg-error "expected end of line before '\\)' token" "" { target *-*-* } .-2 } */
- /* { dg-message "sorry, unimplemented: '#pragma omp allocate' not yet supported" "" { target *-*-* } .-3 } */
+ /* { dg-message "sorry, unimplemented: '#pragma omp allocate' not yet supported" "" { target c++ } .-3 } */
}
void
align_test2 ()
{
- int i;
+ int i, i2,i3;
#pragma omp allocate(i) align (32.0) /* { dg-error "'align' clause argument needs to be positive constant power of two integer expression" } */
- /* { dg-message "sorry, unimplemented: '#pragma omp allocate' not yet supported" "" { target *-*-* } .-1 } */
- #pragma omp allocate(i) align ( 31 ) /* { dg-error "'align' clause argument needs to be positive constant power of two integer expression" } */
- /* { dg-message "sorry, unimplemented: '#pragma omp allocate' not yet supported" "" { target *-*-* } .-1 } */
- #pragma omp allocate(i) align ( -32 ) /* { dg-error "'align' clause argument needs to be positive constant power of two integer expression" } */
- /* { dg-message "sorry, unimplemented: '#pragma omp allocate' not yet supported" "" { target *-*-* } .-1 } */
+ /* { dg-message "sorry, unimplemented: '#pragma omp allocate' not yet supported" "" { target c++ } .-1 } */
+ #pragma omp allocate(i2) align ( 31 ) /* { dg-error "'align' clause argument needs to be positive constant power of two integer expression" } */
+ /* { dg-message "sorry, unimplemented: '#pragma omp allocate' not yet supported" "" { target c++ } .-1 } */
+ #pragma omp allocate(i3) align ( -32 ) /* { dg-error "'align' clause argument needs to be positive constant power of two integer expression" } */
+ /* { dg-message "sorry, unimplemented: '#pragma omp allocate' not yet supported" "" { target c++ } .-1 } */
}
new file mode 100644
@@ -0,0 +1,94 @@
+typedef enum omp_allocator_handle_t
+{
+ 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,
+ __ompx_last_mem_alloc = omp_thread_mem_alloc,
+ __omp_allocator_handle_t_max__ = __UINTPTR_MAX__
+} omp_allocator_handle_t;
+
+
+static int A[5] = {1,2,3,4,5};
+int B, C, D;
+
+/* If the following fails bacause of added predefined allocators, please update
+ - c/c-parser.c's c_parser_omp_allocate
+ - fortran/openmp.cc's is_predefined_allocator
+ - libgomp/env.c's parse_allocator
+ - libgomp/libgomp.texi (document the new values - multiple locations)
+ + ensure that the memory-spaces are also up to date. */
+
+#pragma omp allocate(A) align(32) allocator((omp_allocator_handle_t) 9) /* { dg-error "'allocator' clause requires a predefined allocator as 'A' is static" "" { xfail c++ } } */
+/* { dg-message "sorry, unimplemented: '#pragma omp allocate' not yet supported" "" { target c++ } .-1 } */
+
+
+// typo in allocator name:
+#pragma omp allocate(A) allocator(omp_low_latency_mem_alloc)
+/* { dg-error "'omp_low_latency_mem_alloc' undeclared here \\(not in a function\\); did you mean 'omp_low_lat_mem_alloc'\\?" "" { target c } .-1 } */
+/* { dg-error "'omp_low_latency_mem_alloc' was not declared in this scope; did you mean 'omp_low_lat_mem_alloc'\\?" "" { target c++ } .-2 } */
+/* { dg-error "'allocator' clause required for static variable 'A'" "" { target c } .-3 } */
+/* { dg-message "sorry, unimplemented: '#pragma omp allocate' not yet supported" "" { target c++ } .-4 } */
+
+/* align be const multiple of 2 */
+#pragma omp allocate(A) align(31) allocator(omp_default_mem_alloc) /* { dg-error "'align' clause argument needs to be positive constant power of two integer expression" } */
+/* { dg-message "sorry, unimplemented: '#pragma omp allocate' for static variables like 'A' not yet supported" "" { target c } .-1 } */
+/* { dg-message "sorry, unimplemented: '#pragma omp allocate' not yet supported" "" { target c++ } .-2 } */
+
+/* allocator missing (required as A is static) */
+#pragma omp allocate(A) align(32) /* { dg-error "'allocator' clause required for static variable 'A'" "" { xfail c++ } } */
+/* { dg-message "sorry, unimplemented: '#pragma omp allocate' not yet supported" "" { target c++ } .-1 } */
+
+/* "expression in the clause must be a constant expression that evaluates to one of the
+ predefined memory allocator values -> omp_low_lat_mem_alloc" */
+#pragma omp allocate(B) allocator((omp_allocator_handle_t) (omp_high_bw_mem_alloc+1)) align(32) /* OK: omp_low_lat_mem_alloc */
+/* { dg-message "sorry, unimplemented: '#pragma omp allocate' for static variables like 'B' not yet supported" "" { target c } .-1 } */
+/* { dg-message "sorry, unimplemented: '#pragma omp allocate' not yet supported" "" { target c++ } .-2 } */
+
+#pragma omp allocate(C) allocator((omp_allocator_handle_t) 2) /* OK: omp_large_cap_mem_alloc */
+/* { dg-message "sorry, unimplemented: '#pragma omp allocate' for static variables like 'C' not yet supported" "" { target c } .-1 } */
+/* { dg-message "sorry, unimplemented: '#pragma omp allocate' not yet supported" "" { target c++ } .-2 } */
+
+#pragma omp allocate(A) align(32) allocator(omp_null_allocator) /* { dg-error "'allocator' clause requires a predefined allocator as 'A' is static" "" { xfail c++ } } */
+/* { dg-message "sorry, unimplemented: '#pragma omp allocate' not yet supported" "" { target c++ } .-1 } */
+
+#pragma omp allocate(C) align(32) allocator(omp_large_cap_mem_alloc) /* { dg-error "'C' already appeared as list item in an 'allocate' directive" "" { xfail *-*-* } } */
+/* { dg-message "sorry, unimplemented: '#pragma omp allocate' for static variables like 'C' not yet supported" "" { target c } .-1 } */
+/* { dg-message "sorry, unimplemented: '#pragma omp allocate' not yet supported" "" { target c++ } .-2 } */
+
+// allocate directive in same TU
+int f()
+{
+ #pragma omp allocate(D) align(32) allocator(omp_large_cap_mem_alloc) /* { dg-error "'allocate' directive must be in the same scope as 'D'" "" { xfail c++ } } */
+/* { dg-note "declared here" "" { target c } 18 } */
+/* { dg-message "sorry, unimplemented: '#pragma omp allocate' not yet supported" "" { target c++ } .-2 } */
+ return A[0];
+}
+
+int g()
+{
+ int a2=1, b2=2;
+ #pragma omp allocate(a2)
+/* { dg-message "sorry, unimplemented: '#pragma omp allocate' not yet supported" "" { target c++ } .-1 } */
+ #pragma omp allocate(a2) /* { dg-error "'a2' already appeared as list item in an 'allocate' directive" "" { xfail c++ } } */
+/* { dg-message "sorry, unimplemented: '#pragma omp allocate' not yet supported" "" { target c++ } .-1 } */
+ {
+ int c2=3;
+ #pragma omp allocate(c2, b2) /* { dg-error "'allocate' directive must be in the same scope as 'b2'" "" { xfail c++ } } */
+/* { dg-note "declared here" "" { target c } .-8 } */
+/* { dg-message "sorry, unimplemented: '#pragma omp allocate' not yet supported" "" { target c++ } .-2 } */
+ return c2+a2+b2;
+ }
+}
+
+int h(int q)
+{
+ #pragma omp allocate(q) /* { dg-error "function parameter 'q' may not appear as list item in an 'allocate' directive" "" { xfail c++ } } */
+/* { dg-message "sorry, unimplemented: '#pragma omp allocate' not yet supported" "" { target c++ } .-1 } */
+ return q;
+}
@@ -19,7 +19,7 @@ foo (void)
int i, k = 0, l = 0;
#pragma omp allocate, (i) /* { dg-error "expected '\\\(' before ',' token" } */
/* { dg-error "expected end of line before ',' token" "" { target c++ } .-1 } */
- /* { dg-message "not yet supported" "" { target *-*-* } .-2 } */
+ /* { dg-message "not yet supported" "" { target c++ } .-2 } */
#pragma omp critical, (bar) /* { dg-error "expected an OpenMP clause before '\\\(' token" } */
;
#pragma omp flush, (k, l) /* { dg-error "expected '\\\(' or end of line before ',' token" "" { target c } } */
@@ -225,7 +225,7 @@ The OpenMP 4.5 specification is fully supported.
@item Predefined memory spaces, memory allocators, allocator traits
@tab Y @tab See also @ref{Memory allocation}
@item Memory management routines @tab Y @tab
-@item @code{allocate} directive @tab N @tab
+@item @code{allocate} directive @tab P @tab Only C, only stack variables
@item @code{allocate} clause @tab P @tab Initial support
@item @code{use_device_addr} clause on @code{target data} @tab Y @tab
@item @code{ancestor} modifier on @code{device} clause @tab Y @tab
@@ -296,7 +296,8 @@ The OpenMP 4.5 specification is fully supported.
@item Loop transformation constructs @tab N @tab
@item @code{strict} modifier in the @code{grainsize} and @code{num_tasks}
clauses of the @code{taskloop} construct @tab Y @tab
-@item @code{align} clause in @code{allocate} directive @tab N @tab
+@item @code{align} clause in @code{allocate} directive @tab P
+ @tab Only C (and only stack variables)
@item @code{align} modifier in @code{allocate} clause @tab Y @tab
@item @code{thread_limit} clause to @code{target} construct @tab Y @tab
@item @code{has_device_addr} clause to @code{target} construct @tab Y @tab
@@ -2204,7 +2205,7 @@ variable is not set.
@section @env{OMP_ALLOCATOR} -- Set the default allocator
@cindex Environment Variable
@table @asis
-@item @emph{ICV:} @var{available-devices-var}
+@item @emph{ICV:} @var{def-allocator-var}
@item @emph{Scope:} data environment
@item @emph{Description}:
Sets the default allocator that is used when no allocator has been specified
new file mode 100644
@@ -0,0 +1,75 @@
+/* TODO: enable for C++ once implemented. */
+/* { dg-do run { target c } } */
+/* { dg-additional-options "-fdump-tree-gimple" } */
+
+#include <omp.h>
+#include <stdint.h>
+
+/* { dg-final { scan-tree-dump-times "__builtin_GOMP_free \\(D.\[0-9\]+, 0B\\);" 5 "gimple" } } */
+
+int one ()
+{
+ int sum = 0;
+ #pragma omp allocate(sum)
+ /* { dg-final { scan-tree-dump-times "D.\[0-9\]+ = __builtin_GOMP_alloc \\(0, 4, 0B\\);" 1 "gimple" } } */
+
+ /* NOTE: Initializer cannot be omp_init_allocator - as 'A' is
+ in the same scope and the auto-omp_free comes later than
+ any omp_destroy_allocator. */
+ omp_allocator_handle_t my_allocator = omp_low_lat_mem_alloc;
+ int n = 25;
+ int A[n];
+ #pragma omp allocate(A) align(128) allocator(my_allocator)
+ /* { dg-final { scan-tree-dump-times "D.\[0-9\]+ = __builtin_GOMP_alloc \\(128, _\[0-9\]+, my_allocator\\);" 1 "gimple" } } */
+
+ if (((intptr_t)A) % 128 != 0)
+ __builtin_abort ();
+ for (int i = 0; i < n; ++i)
+ A[i] = i;
+
+ omp_alloctrait_t traits[1] = { { omp_atk_alignment, 64 } };
+ my_allocator = omp_init_allocator(omp_low_lat_mem_space,1,traits);
+ {
+ int B[n] = { };
+ int C[5] = {1,2,3,4,5};
+ #pragma omp allocate(B,C) allocator(my_allocator)
+ /* { dg-final { scan-tree-dump-times "D.\[0-9\]+ = __builtin_GOMP_alloc \\(0, _\[0-9\]+, my_allocator\\);" 1 "gimple" } } */
+ /* { dg-final { scan-tree-dump-times "D.\[0-9\]+ = __builtin_GOMP_alloc \\(0, 20, my_allocator\\);" 1 "gimple" } } */
+
+ int D[5] = {11,22,33,44,55};
+ #pragma omp allocate(D) align(256)
+ /* { dg-final { scan-tree-dump-times "D.\[0-9\]+ = __builtin_GOMP_alloc \\(256, 20, 0B\\);" 1 "gimple" } } */
+
+ if (((intptr_t) B) % 64 != 0)
+ __builtin_abort ();
+ if (((intptr_t) C) % 64 != 0)
+ __builtin_abort ();
+ if (((intptr_t) D) % 64 != 0)
+ __builtin_abort ();
+
+ for (int i = 0; i < 5; ++i)
+ {
+ if (C[i] != i+1)
+ __builtin_abort ();
+ if (D[i] != i+1 + 10*(i+1))
+ __builtin_abort ();
+ }
+
+ for (int i = 0; i < n; ++i)
+ {
+ if (B[i] != 0)
+ __builtin_abort ();
+ sum += A[i]+B[i]+C[i%5]+D[i%5];
+ }
+ }
+ omp_destroy_allocator (my_allocator);
+ return sum;
+}
+
+int
+main ()
+{
+ if (one () != 1200)
+ __builtin_abort ();
+ return 0;
+}