This adds support for #pragma omp allocate(var-list) [allocator(..) align(..)]
While the spec permits stack and static variables, this patch only adds support for stack variables - keeping the 'sorry' for static variables. It is also only C as I wanted to get this out before updating C++ parsing. However, if disable the 'sorry' + add the attribute, it will also work for C++. For Fortran, there is no expression associated with the declaration such that it will not work with the gimplify.cc patch (it cannot find the place to add it); however, I have a mostly working version for FE generated support for stack _and_ static variables. The main RFC question for this patch is whether to generate the GOMP_alloc/free calls also for !TREE_USED() or not. This patch avoids this to aid removal of such stack variables, but one could also argue otherwise. Thoughts, comments, remarks? Tobias ----------------- Siemens Electronic Design Automation GmbH; Anschrift: Arnulfstraße 201, 80634 München; Gesellschaft mit beschränkter Haftung; Geschäftsführer: Thomas Heurung, Frank Thürauf; Sitz der Gesellschaft: München; Registergericht München, HRB 106955
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(-) diff --git a/gcc/c/c-parser.cc b/gcc/c/c-parser.cc index cae10ba9c80..a04fd474a28 100644 --- a/gcc/c/c-parser.cc +++ b/gcc/c/c-parser.cc @@ -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; diff --git a/gcc/gimplify.cc b/gcc/gimplify.cc index a49b50bc857..e48eb404bcb 100644 --- a/gcc/gimplify.cc +++ b/gcc/gimplify.cc @@ -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; diff --git a/gcc/testsuite/c-c++-common/gomp/allocate-10.c b/gcc/testsuite/c-c++-common/gomp/allocate-10.c new file mode 100644 index 00000000000..6fe16b1eb03 --- /dev/null +++ b/gcc/testsuite/c-c++-common/gomp/allocate-10.c @@ -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 */ +} diff --git a/gcc/testsuite/c-c++-common/gomp/allocate-5.c b/gcc/testsuite/c-c++-common/gomp/allocate-5.c index 8a9181205f7..de1efc6832d 100644 --- a/gcc/testsuite/c-c++-common/gomp/allocate-5.c +++ b/gcc/testsuite/c-c++-common/gomp/allocate-5.c @@ -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 } */ } diff --git a/gcc/testsuite/c-c++-common/gomp/allocate-9.c b/gcc/testsuite/c-c++-common/gomp/allocate-9.c new file mode 100644 index 00000000000..e782b48bdf4 --- /dev/null +++ b/gcc/testsuite/c-c++-common/gomp/allocate-9.c @@ -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; +} diff --git a/gcc/testsuite/c-c++-common/gomp/directive-1.c b/gcc/testsuite/c-c++-common/gomp/directive-1.c index fc441538778..21ca319b9f9 100644 --- a/gcc/testsuite/c-c++-common/gomp/directive-1.c +++ b/gcc/testsuite/c-c++-common/gomp/directive-1.c @@ -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 } } */ diff --git a/libgomp/libgomp.texi b/libgomp/libgomp.texi index 4aad8cc52f4..6dab873337e 100644 --- a/libgomp/libgomp.texi +++ b/libgomp/libgomp.texi @@ -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 diff --git a/libgomp/testsuite/libgomp.c-c++-common/allocate-4.c b/libgomp/testsuite/libgomp.c-c++-common/allocate-4.c new file mode 100644 index 00000000000..ebfdc78a56b --- /dev/null +++ b/libgomp/testsuite/libgomp.c-c++-common/allocate-4.c @@ -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; +}