diff --git a/gcc/c/c-parser.cc b/gcc/c/c-parser.cc index a681438cbbe..fe01f955e21 100644 --- a/gcc/c/c-parser.cc +++ b/gcc/c/c-parser.cc @@ -20967,20 +20967,22 @@ c_parser_omp_allocate (c_parser *parser) if (TREE_STATIC (var)) { if (allocator == NULL_TREE && allocator_loc == UNKNOWN_LOCATION) - error_at (loc, "% clause required for " - "static variable %qD", var); + { + error_at (loc, + "% clause required for " + "static variable %qD", var); + continue; + } else if (allocator && (wi::to_widest (allocator) < 1 - || wi::to_widest (allocator) > 8)) - /* 8 = largest predefined memory allocator. */ - error_at (allocator_loc, - "% 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; + || wi::to_widest (allocator) > GOMP_OMP_PREDEF_ALLOC_MAX) + && (wi::to_widest (allocator) < GOMP_OMPX_PREDEF_ALLOC_MIN + || wi::to_widest (allocator) > GOMP_OMPX_PREDEF_ALLOC_MAX)) + { + error_at (allocator_loc, + "% clause requires a predefined allocator as " + "%qD is static", var); + } } if (allocator) { @@ -20988,6 +20990,9 @@ c_parser_omp_allocate (c_parser *parser) = {EXPR_LOC_OR_LOC (allocator, OMP_CLAUSE_LOCATION (nl)), var}; walk_tree (&allocator, c_check_omp_allocate_allocator_r, &data, NULL); } + if (alignment) + SET_DECL_ALIGN (var, BITS_PER_UNIT * MAX (tree_to_uhwi (alignment), + DECL_ALIGN_UNIT (var))); DECL_ATTRIBUTES (var) = tree_cons (get_identifier ("omp allocate"), build_tree_list (allocator, alignment), DECL_ATTRIBUTES (var)); diff --git a/gcc/fortran/openmp.cc b/gcc/fortran/openmp.cc index 2d5c4305d2a..d9ccae8a11f 100644 --- a/gcc/fortran/openmp.cc +++ b/gcc/fortran/openmp.cc @@ -7857,9 +7857,12 @@ is_predefined_allocator (gfc_expr *expr) && expr->ts.kind == gfc_c_intptr_kind && expr->expr_type == EXPR_CONSTANT && ((mpz_sgn (expr->value.integer) > 0 - && mpz_cmp_si (expr->value.integer, 8) <= 0) - || (mpz_cmp_si (expr->value.integer, 200) >= 0 - && mpz_cmp_si (expr->value.integer, 200) <= 0))); + && mpz_cmp_si (expr->value.integer, + GOMP_OMP_PREDEF_ALLOC_MAX) <= 0) + || (mpz_cmp_si (expr->value.integer, + GOMP_OMPX_PREDEF_ALLOC_MIN) >= 0 + && mpz_cmp_si (expr->value.integer, + GOMP_OMPX_PREDEF_ALLOC_MAX) <= 0))); } /* Resolve declarative ALLOCATE statement. Note: Common block vars only appear diff --git a/gcc/fortran/trans-common.cc b/gcc/fortran/trans-common.cc index e714342c3c0..481d468040e 100644 --- a/gcc/fortran/trans-common.cc +++ b/gcc/fortran/trans-common.cc @@ -1219,6 +1219,10 @@ translate_common (gfc_common_head *common, gfc_symbol *var_list) align = 1; saw_equiv = false; + if (var_list->attr.omp_allocate) + gfc_error ("Sorry, !$OMP allocate for COMMON block variable %qs at %L " + "not supported", common->name, &common->where); + /* Add symbols to the segment. */ for (sym = var_list; sym; sym = sym->common_next) { diff --git a/gcc/fortran/trans-decl.cc b/gcc/fortran/trans-decl.cc index 8231bd255d6..2586c6d7a79 100644 --- a/gcc/fortran/trans-decl.cc +++ b/gcc/fortran/trans-decl.cc @@ -821,6 +821,23 @@ gfc_finish_var_decl (tree decl, gfc_symbol * sym) && (TREE_STATIC (decl) || DECL_EXTERNAL (decl))) set_decl_tls_model (decl, decl_default_tls_model (decl)); + if (sym->attr.omp_allocate && TREE_STATIC (decl)) + { + struct gfc_omp_namelist *n; + for (n = sym->ns->omp_allocate; n; n = n->next) + if (n->sym == sym) + break; + tree alloc = gfc_conv_constant_to_tree (n->u2.allocator); + tree align = (n->u.align ? gfc_conv_constant_to_tree (n->u.align) + : NULL_TREE); + if (align != NULL_TREE) + SET_DECL_ALIGN (decl, MAX (tree_to_uhwi (align), + DECL_ALIGN_UNIT (decl)) * BITS_PER_UNIT); + DECL_ATTRIBUTES (decl) + = tree_cons (get_identifier ("omp allocate"), + build_tree_list (alloc, align), DECL_ATTRIBUTES (decl)); + } + /* Mark weak variables. */ if (sym->attr.ext_attr & (1 << EXT_ATTR_WEAK)) declare_weak (decl); @@ -5251,71 +5268,55 @@ gfc_trans_deferred_vars (gfc_symbol * proc_sym, gfc_wrapped_block * block) se.expr = NULL_TREE; for (struct gfc_omp_namelist *n = omp_ns ? omp_ns->omp_allocate : NULL; n; n = n->next) - if (!TREE_STATIC (n->sym->backend_decl)) - { - tree align = (n->u.align ? gfc_conv_constant_to_tree (n->u.align) - : NULL_TREE); - if (last_allocator != n->u2.allocator) - { - location_t loc = input_location; - gfc_init_se (&se, NULL); - if (n->u2.allocator) - { - input_location = gfc_get_location (&n->u2.allocator->where); - gfc_conv_expr (&se, n->u2.allocator); - } - /* We need to evalulate non-constants - also to find the location - after which the GOMP_alloc has to be added to - also as BLOCK - does not yield a new BIND_EXPR_BODY. */ - if (n->u2.allocator - && (!(CONSTANT_CLASS_P (se.expr) && DECL_P (se.expr)) - || se.pre.head || se.post.head)) - { - stmtblock_t tmpblock; - gfc_init_block (&tmpblock); - se.expr = gfc_evaluate_now (se.expr, &tmpblock); - /* First post then pre because the new code is inserted - at the top. */ - gfc_add_init_cleanup (block, gfc_finish_block (&se.post), NULL); - gfc_add_init_cleanup (block, gfc_finish_block (&tmpblock), - NULL); - gfc_add_init_cleanup (block, gfc_finish_block (&se.pre), NULL); - } - last_allocator = n->u2.allocator; - input_location = loc; - } - - /* 'omp allocate( {purpose: allocator, value: align}, - {purpose: init-stmtlist, value: cleanup-stmtlist}, - {purpose: size-var, value: last-size-expr}} - where init-stmt/cleanup-stmt is the STATEMENT list to find the - try-final block; last-size-expr is to find the location after - which to add the code and 'size-var' is for the proper size, cf. - gfc_trans_auto_array_allocation - either or both of the latter - can be NULL. */ - tree tmp = lookup_attribute ("omp allocate", - DECL_ATTRIBUTES (n->sym->backend_decl)); - tmp = TREE_VALUE (tmp); - TREE_PURPOSE (tmp) = se.expr; - TREE_VALUE (tmp) = align; - TREE_PURPOSE (TREE_CHAIN (tmp)) = init_stmtlist; - TREE_VALUE (TREE_CHAIN (tmp)) = cleanup_stmtlist; - } - else if (n->sym->attr.in_common) - { - gfc_error ("Sorry, !$OMP allocate for COMMON block variable %qs at %L " - "not supported", n->sym->common_block->name, - &n->sym->common_block->where); - break; - } - else - { - gfc_error ("Sorry, !$OMP allocate for variable %qs at %L with SAVE " - "attribute not yet implemented", n->sym->name, - &n->sym->declared_at); - /* FIXME: Remember to handle last_allocator. */ - break; - } + { + tree align = (n->u.align ? gfc_conv_constant_to_tree (n->u.align) : NULL_TREE); + if (last_allocator != n->u2.allocator) + { + location_t loc = input_location; + gfc_init_se (&se, NULL); + if (n->u2.allocator) + { + input_location = gfc_get_location (&n->u2.allocator->where); + gfc_conv_expr (&se, n->u2.allocator); + } + /* We need to evalulate non-constants - also to find the location + after which the GOMP_alloc has to be added to - also as BLOCK + does not yield a new BIND_EXPR_BODY. */ + if (n->u2.allocator + && (!(CONSTANT_CLASS_P (se.expr) && DECL_P (se.expr)) + || se.pre.head || se.post.head)) + { + stmtblock_t tmpblock; + gfc_init_block (&tmpblock); + se.expr = gfc_evaluate_now (se.expr, &tmpblock); + /* First post then pre because the new code is inserted + at the top. */ + gfc_add_init_cleanup (block, gfc_finish_block (&se.post), NULL); + gfc_add_init_cleanup (block, gfc_finish_block (&tmpblock), + NULL); + gfc_add_init_cleanup (block, gfc_finish_block (&se.pre), NULL); + } + last_allocator = n->u2.allocator; + input_location = loc; + } + if (TREE_STATIC (n->sym->backend_decl)) + continue; + /* 'omp allocate( {purpose: allocator, value: align}, + {purpose: init-stmtlist, value: cleanup-stmtlist}, + {purpose: size-var, value: last-size-expr}} + where init-stmt/cleanup-stmt is the STATEMENT list to find the + try-final block; last-size-expr is to find the location after + which to add the code and 'size-var' is for the proper size, cf. + gfc_trans_auto_array_allocation - either or both of the latter + can be NULL. */ + tree tmp = lookup_attribute ("omp allocate", + DECL_ATTRIBUTES (n->sym->backend_decl)); + tmp = TREE_VALUE (tmp); + TREE_PURPOSE (tmp) = se.expr; + TREE_VALUE (tmp) = align; + TREE_PURPOSE (TREE_CHAIN (tmp)) = init_stmtlist; + TREE_VALUE (TREE_CHAIN (tmp)) = cleanup_stmtlist; + } gfc_init_block (&tmpblock); diff --git a/gcc/gimplify.cc b/gcc/gimplify.cc index 6cdc70d2130..3f602469d57 100644 --- a/gcc/gimplify.cc +++ b/gcc/gimplify.cc @@ -1396,6 +1396,7 @@ gimplify_bind_expr (tree *expr_p, gimple_seq *pre_p) if (flag_openmp && !is_global_var (t) + && !TREE_STATIC (t) && DECL_CONTEXT (t) == current_function_decl && TREE_USED (t) && (attr = lookup_attribute ("omp allocate", DECL_ATTRIBUTES (t))) @@ -1427,11 +1428,17 @@ gimplify_bind_expr (tree *expr_p, gimple_seq *pre_p) "% directive for %qD inside a target " "region must specify an % clause", t); /* Skip for omp_default_mem_alloc (= 1), - unless align is present. */ + unless align is present. For C/C++, there should be always a + statement list following if TREE_USED, except for, e.g., using + this decl in a static_assert; in that case, only a single + DECL_EXPR remains, which can be skipped here. */ else if (!errorcount && (align != NULL_TREE || alloc == NULL_TREE - || !integer_onep (alloc))) + || !integer_onep (alloc)) + && (lang_GNU_Fortran () + || (TREE_CODE (BIND_EXPR_BODY (bind_expr)) + != DECL_EXPR))) { /* Fortran might already use a pointer type internally; use that pointer except for type(C_ptr) and type(C_funptr); @@ -13326,6 +13333,17 @@ gimplify_scan_omp_clauses (tree *list_p, gimple_seq *pre_p, break; case OMP_CLAUSE_ALLOCATE: + decl = OMP_CLAUSE_ALLOCATE_ALLOCATOR (c); + if (decl + && TREE_CODE (decl) == INTEGER_CST + && wi::eq_p (wi::to_widest (decl), GOMP_OMP_PREDEF_ALLOC_THREADS) + && (code == OMP_TARGET || code == OMP_TASK || code == OMP_TASKLOOP)) + warning_at (OMP_CLAUSE_LOCATION (c), OPT_Wopenmp, + "allocator with access trait set to % " + "results in undfined behavior for %qs directive", + code == OMP_TARGET ? "target" + : (code == OMP_TASK + ? "task" : "taskloop")); decl = OMP_CLAUSE_DECL (c); if (error_operand_p (decl)) { diff --git a/gcc/testsuite/c-c++-common/gomp/allocate-18.c b/gcc/testsuite/c-c++-common/gomp/allocate-18.c new file mode 100644 index 00000000000..4182f7ee37e --- /dev/null +++ b/gcc/testsuite/c-c++-common/gomp/allocate-18.c @@ -0,0 +1,59 @@ +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; + +void test0 () +{ + int A1[5]; + #pragma omp allocate(A1) align(128) allocator(omp_default_mem_alloc) + /* { dg-message "sorry, unimplemented: '#pragma omp allocate' not yet supported" "" { target c++ } .-1 } */ + + #ifndef __cplusplus + _Static_assert (_Alignof(A1) == 128, "wrong alignment"); + #elif __cplusplus >= 201103L + static_assert (alignof(A1) == 128, "wrong alignment"); /* { dg-bogus "static assertion failed: wrong alignment" "" { xfail { c++ && { ! c++98_only } } } } */ + #endif +} + +void +test1 () +{ + int x[5]; + #pragma omp parallel allocate(omp_thread_mem_alloc: x) firstprivate(x) + x[0] = 1; + + #pragma omp target allocate(omp_thread_mem_alloc: x) firstprivate(x) /* uses_allocators(omp_thread_mem_alloc) */ + /* { dg-warning "allocator with access trait set to 'thread' results in undfined behavior for 'target' directive \\\[-Wopenmp\\\]" "" { target *-*-* } .-1 } */ + x[0] = 1; + + #pragma omp taskloop allocate(omp_thread_mem_alloc: x) firstprivate(x) + /* { dg-warning "allocator with access trait set to 'thread' results in undfined behavior for 'taskloop' directive \\\[-Wopenmp\\\]" "" { target *-*-* } .-1 } */ + for (int i = 0; i < 5; i++) + x[i] = i; + + #pragma omp parallel master taskloop simd allocate(omp_thread_mem_alloc: x) firstprivate(x) + /* { dg-warning "allocator with access trait set to 'thread' results in undfined behavior for 'taskloop' directive \\\[-Wopenmp\\\]" "" { target *-*-* } .-1 } */ + for (int i = 0; i < 5; i++) + x[i] = i; + + #pragma omp parallel + #pragma omp masked + { + #pragma omp task allocate(omp_thread_mem_alloc: x) firstprivate(x) + /* { dg-warning "allocator with access trait set to 'thread' results in undfined behavior for 'task' directive \\\[-Wopenmp\\\]" "" { target *-*-* } .-1 } */ + x[0] = 1; + } +} diff --git a/gcc/testsuite/c-c++-common/gomp/allocate-19.c b/gcc/testsuite/c-c++-common/gomp/allocate-19.c new file mode 100644 index 00000000000..ad3493d8c17 --- /dev/null +++ b/gcc/testsuite/c-c++-common/gomp/allocate-19.c @@ -0,0 +1,69 @@ +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, + ompx_gnu_pinned_bogus_1 = 9, + ompx_gnu_pinned_bogus_2 = 199, + ompx_gnu_pinned_mem_alloc = 200, + ompx_gnu_pinned_bogus_3 = 2001, + __omp_allocator_handle_t_max__ = __UINTPTR_MAX__ +} omp_allocator_handle_t; + +static int A1[5] = {1,2,3,4,5}; +#pragma omp allocate(A1) align(128) allocator(omp_default_mem_alloc) +/* { dg-message "sorry, unimplemented: '#pragma omp allocate' not yet supported" "" { target c++ } .-1 } */ + +#ifndef __cplusplus +_Static_assert (_Alignof(A1) == 128, "wrong alignment"); +#elif __cplusplus >= 201103L +static_assert (alignof(A1) == 128, "wrong alignment"); /* { dg-bogus "static assertion failed: wrong alignment" "" { xfail { c++ && { ! c++98_only } } } } */ +#endif + + +static int *ptr; +#pragma omp allocate(ptr) align(2) allocator(omp_default_mem_alloc) +/* { dg-message "sorry, unimplemented: '#pragma omp allocate' not yet supported" "" { target c++ } .-1 } */ + +#ifndef __cplusplus +_Static_assert (_Alignof(ptr) == _Alignof(int*), "wrong alignment"); +#elif __cplusplus >= 201103L +static_assert (alignof(ptr) == alignof(int*), "wrong alignment"); +#endif + + +int * +get () +{ + static int q = 0; + #pragma omp allocate(q) align(1024) allocator(omp_default_mem_alloc) + /* { dg-message "sorry, unimplemented: '#pragma omp allocate' not yet supported" "" { target c++ } .-1 } */ + +#ifndef __cplusplus + _Static_assert (_Alignof(q) == 1024, "wrong alignment"); +#elif __cplusplus >= 201103L + static_assert (alignof(q) == 1024, "wrong alignment"); /* { dg-bogus "static assertion failed: wrong alignment" "" { xfail { c++ && { ! c++98_only } } } } */ +#endif + + q += 1; + return &A1[q]; +} + +static int invalid1, okay1, invalid2, invalid3; +#pragma omp allocate(invalid1) align(128) allocator(ompx_gnu_pinned_bogus_1) /* { dg-error "'allocator' clause requires a predefined allocator as 'invalid1' is static" "" { xfail c++ } } */ +#pragma omp allocate(okay1) align(128) allocator(ompx_gnu_pinned_mem_alloc) /* Okay */ +#pragma omp allocate(invalid2) align(128) allocator(ompx_gnu_pinned_bogus_2) /* { dg-error "'allocator' clause requires a predefined allocator as 'invalid2' is static" "" { xfail c++ } } */ +#pragma omp allocate(invalid3) align(128) allocator(ompx_gnu_pinned_bogus_3) /* { dg-error "'allocator' clause requires a predefined allocator as 'invalid3' is static" "" { xfail c++ } } */ +/* { dg-message "sorry, unimplemented: '#pragma omp allocate' not yet supported" "" { target c++ } .-4 } */ +/* { dg-message "sorry, unimplemented: '#pragma omp allocate' not yet supported" "" { target c++ } .-4 } */ +/* { dg-message "sorry, unimplemented: '#pragma omp allocate' not yet supported" "" { target c++ } .-4 } */ +/* { dg-message "sorry, unimplemented: '#pragma omp allocate' not yet supported" "" { target c++ } .-4 } */ diff --git a/gcc/testsuite/c-c++-common/gomp/allocate-9.c b/gcc/testsuite/c-c++-common/gomp/allocate-9.c index 31382748be6..f37a11185f7 100644 --- a/gcc/testsuite/c-c++-common/gomp/allocate-9.c +++ b/gcc/testsuite/c-c++-common/gomp/allocate-9.c @@ -18,7 +18,11 @@ typedef enum omp_allocator_handle_t static int A[5] = {1,2,3,4,5}; -int B, C, D; +static int A2[5] = {1,2,3,4,5}; +static int A3[5] = {1,2,3,4,5}; +static int A4[5] = {1,2,3,4,5}; +static int A5[5] = {1,2,3,4,5}; +int B, C, C2, D; /* If the following fails because of added predefined allocators, please update - c/c-parser.c's c_parser_omp_allocate @@ -30,46 +34,45 @@ int B, C, D; #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) +#pragma omp allocate(A2) 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-error "'allocator' clause required for static variable 'A2'" "" { 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 } */ +#pragma omp allocate(A3) 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' not yet supported" "" { target c++ } .-1 } */ + /* allocator missing (required as A is static) */ -#pragma omp allocate(A) align(32) /* { dg-error "'allocator' clause required for static variable 'A'" "" { xfail c++ } } */ +#pragma omp allocate(A4) align(32) /* { dg-error "'allocator' clause required for static variable 'A4'" "" { 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 } */ + +#pragma omp allocate(C) allocator((omp_allocator_handle_t) 2) /* OK: omp_large_cap_mem_alloc */ +/* { dg-message "sorry, unimplemented: '#pragma omp allocate' not yet supported" "" { target c++ } .-1 } */ + + +#pragma omp allocate(A5) align(32) allocator(omp_null_allocator) /* { dg-error "'allocator' clause requires a predefined allocator as 'A5' is static" "" { xfail c++ } } */ +/* { dg-message "sorry, unimplemented: '#pragma omp allocate' not yet supported" "" { target c++ } .-1 } */ + +#pragma omp allocate(C2) align(32) allocator(omp_large_cap_mem_alloc) +/* { dg-message "sorry, unimplemented: '#pragma omp allocate' not yet supported" "" { target c++ } .-1 } */ + // 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 } 21 } */ -/* { dg-message "sorry, unimplemented: '#pragma omp allocate' not yet supported" "" { target c++ } .-2 } */ +/* { dg-message "sorry, unimplemented: '#pragma omp allocate' not yet supported" "" { target c++ } .-1 } */ +/* { dg-note "declared here" "" { target c } 25 } */ return A[0]; } @@ -83,8 +86,8 @@ int g() { 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 } */ +/* { dg-message "sorry, unimplemented: '#pragma omp allocate' not yet supported" "" { target c++ } .-1 } */ +/* { dg-note "declared here" "" { target c } .-9 } */ return c2+a2+b2; } } diff --git a/gcc/testsuite/gfortran.dg/gomp/allocate-15.f90 b/gcc/testsuite/gfortran.dg/gomp/allocate-15.f90 index a0690a56394..e3ef841442b 100644 --- a/gcc/testsuite/gfortran.dg/gomp/allocate-15.f90 +++ b/gcc/testsuite/gfortran.dg/gomp/allocate-15.f90 @@ -30,7 +30,7 @@ end integer function allocators() result(res) use m - integer, save :: a(5) = [1,2,3,4,5] ! { dg-error "Sorry, !.OMP allocate for variable 'a' at .1. with SAVE attribute not yet implemented" } + integer, save :: a(5) = [1,2,3,4,5] !$omp allocate(a) allocator(omp_high_bw_mem_alloc) res = a(4) end diff --git a/gcc/testsuite/gfortran.dg/gomp/allocate-4.f90 b/gcc/testsuite/gfortran.dg/gomp/allocate-4.f90 index b93a37c780c..ee5fc8e6fa4 100644 --- a/gcc/testsuite/gfortran.dg/gomp/allocate-4.f90 +++ b/gcc/testsuite/gfortran.dg/gomp/allocate-4.f90 @@ -39,7 +39,7 @@ integer :: a,b,c(n),d(5),e(2) !$omp allocate( e ) allocator( omp_high_bw_mem_alloc ) !saved vars -integer, save :: k,l,m(5),r(2) ! { dg-error "Sorry, !.OMP allocate for variable 'k' at .1. with SAVE attribute not yet implemented" } +integer, save :: k,l,m(5),r(2) !$omp allocate(k) align(16) , allocator (omp_large_cap_mem_alloc) !$omp allocate ( l ) allocator (omp_large_cap_mem_alloc) , align ( 32) !$omp allocate (m) align( 128 ),allocator( omp_high_bw_mem_alloc ) @@ -47,8 +47,8 @@ integer, save :: k,l,m(5),r(2) ! { dg-error "Sorry, !.OMP allocate for variable !common /block/ integer :: q,x,y(2),z(5) -common /com1/ q,x -common /com2/ y,z +common /com1/ q,x ! { dg-error "Sorry, !.OMP allocate for COMMON block variable 'com1' at .1. not supported" } +common /com2/ y,z ! { dg-error "Sorry, !.OMP allocate for COMMON block variable 'com2' at .1. not supported" } !$omp allocate ( / com1/) align( 128 ) allocator( omp_high_bw_mem_alloc ) !$omp allocate(/com2 / ) allocator( omp_high_bw_mem_alloc ) end diff --git a/gcc/testsuite/gfortran.dg/gomp/allocate-clause.f90 b/gcc/testsuite/gfortran.dg/gomp/allocate-clause.f90 new file mode 100644 index 00000000000..3548538c3c1 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/gomp/allocate-clause.f90 @@ -0,0 +1,61 @@ +module omp_lib_kinds + use iso_c_binding, only: c_int, c_intptr_t + implicit none + private :: c_int, c_intptr_t + integer, parameter :: omp_allocator_handle_kind = c_intptr_t + + integer (kind=omp_allocator_handle_kind), & + parameter :: omp_null_allocator = 0 + integer (kind=omp_allocator_handle_kind), & + parameter :: omp_default_mem_alloc = 1 + integer (kind=omp_allocator_handle_kind), & + parameter :: omp_large_cap_mem_alloc = 2 + integer (kind=omp_allocator_handle_kind), & + parameter :: omp_const_mem_alloc = 3 + integer (kind=omp_allocator_handle_kind), & + parameter :: omp_high_bw_mem_alloc = 4 + integer (kind=omp_allocator_handle_kind), & + parameter :: omp_low_lat_mem_alloc = 5 + integer (kind=omp_allocator_handle_kind), & + parameter :: omp_cgroup_mem_alloc = 6 + integer (kind=omp_allocator_handle_kind), & + parameter :: omp_pteam_mem_alloc = 7 + integer (kind=omp_allocator_handle_kind), & + parameter :: omp_thread_mem_alloc = 8 +end module + +subroutine test1 () + use omp_lib_kinds + implicit none + integer :: x(5), i + + !$omp parallel allocate(omp_thread_mem_alloc: x) firstprivate(x) + x(1) = 1 + !$omp end parallel + + !$omp target allocate(omp_thread_mem_alloc: x) firstprivate(x) ! uses_allocators(omp_thread_mem_alloc) + ! { dg-warning "allocator with access trait set to 'thread' results in undfined behavior for 'target' directive \\\[-Wopenmp\\\]" "" { target *-*-* } .-1 } + x(1) = 1 + !$omp end target + + !$omp taskloop allocate(omp_thread_mem_alloc: x) firstprivate(x) + ! { dg-warning "allocator with access trait set to 'thread' results in undfined behavior for 'taskloop' directive \\\[-Wopenmp\\\]" "" { target *-*-* } .-1 } + do i = 1, 5 + x(i) = i + end do + + !$omp parallel master taskloop simd allocate(omp_thread_mem_alloc: x) firstprivate(x) + ! { dg-warning "allocator with access trait set to 'thread' results in undfined behavior for 'taskloop' directive \\\[-Wopenmp\\\]" "" { target *-*-* } .-1 } + do i = 1, 5 + x(i) = i + end do + + !$omp parallel + !$omp masked + !$omp task allocate(omp_thread_mem_alloc: x) firstprivate(x) + ! { dg-warning "allocator with access trait set to 'thread' results in undfined behavior for 'task' directive \\\[-Wopenmp\\\]" "" { target *-*-* } .-1 } + x(1) = 1 + !$omp end task + !$omp end masked + !$omp end parallel +end diff --git a/gcc/testsuite/gfortran.dg/gomp/allocate-pinned-1.f90 b/gcc/testsuite/gfortran.dg/gomp/allocate-pinned-1.f90 index 0e6619b7853..46789dd375e 100644 --- a/gcc/testsuite/gfortran.dg/gomp/allocate-pinned-1.f90 +++ b/gcc/testsuite/gfortran.dg/gomp/allocate-pinned-1.f90 @@ -11,6 +11,6 @@ subroutine f () use m implicit none ! The "Sorry" is here temporarily only to avoid excess error failures. - integer, save :: i ! { dg-error "Sorry, !.OMP allocate for variable 'i' at .1. with SAVE attribute not yet implemented" } + integer, save :: i !$omp allocate(i) allocator(ompx_gnu_pinned_mem_alloc) end diff --git a/gcc/testsuite/gfortran.dg/gomp/allocate-static-2.f90 b/gcc/testsuite/gfortran.dg/gomp/allocate-static-2.f90 new file mode 100644 index 00000000000..3e4768e613f --- /dev/null +++ b/gcc/testsuite/gfortran.dg/gomp/allocate-static-2.f90 @@ -0,0 +1,52 @@ +module omp_lib_kinds + use iso_c_binding, only: c_int, c_intptr_t + implicit none + private :: c_int, c_intptr_t + integer, parameter :: omp_allocator_handle_kind = c_intptr_t + + integer (kind=omp_allocator_handle_kind), & + parameter :: omp_null_allocator = 0 + integer (kind=omp_allocator_handle_kind), & + parameter :: omp_default_mem_alloc = 1 + integer (kind=omp_allocator_handle_kind), & + parameter :: omp_large_cap_mem_alloc = 2 + integer (kind=omp_allocator_handle_kind), & + parameter :: omp_const_mem_alloc = 3 + integer (kind=omp_allocator_handle_kind), & + parameter :: omp_high_bw_mem_alloc = 4 + integer (kind=omp_allocator_handle_kind), & + parameter :: omp_low_lat_mem_alloc = 5 + integer (kind=omp_allocator_handle_kind), & + parameter :: omp_cgroup_mem_alloc = 6 + integer (kind=omp_allocator_handle_kind), & + parameter :: omp_pteam_mem_alloc = 7 + integer (kind=omp_allocator_handle_kind), & + parameter :: omp_thread_mem_alloc = 8 +end module + +module m +use omp_lib_kinds, only: omp_default_mem_alloc +implicit none +integer a,b +common /foo/ a,b ! { dg-error "Sorry, !.OMP allocate for COMMON block variable 'foo' at .1. not supported" } +!$omp allocate(/foo/) align(128) allocator(omp_default_mem_alloc) +end + +subroutine sub +use omp_lib_kinds +implicit none +integer a,b +common /foo/ a,b ! { dg-error "Sorry, !.OMP allocate for COMMON block variable 'foo' at .1. not supported" } +!$omp allocate(/foo/) align(128) allocator(omp_default_mem_alloc) +end + +subroutine outer +contains +subroutine inner +use omp_lib_kinds +implicit none +integer a,b +common /foo/ a,b ! { dg-error "Sorry, !.OMP allocate for COMMON block variable 'foo' at .1. not supported" } +!$omp allocate(/foo/) align(128) allocator(omp_default_mem_alloc) +end +end diff --git a/gcc/testsuite/gfortran.dg/gomp/allocate-static.f90 b/gcc/testsuite/gfortran.dg/gomp/allocate-static.f90 new file mode 100644 index 00000000000..e43dae5793f --- /dev/null +++ b/gcc/testsuite/gfortran.dg/gomp/allocate-static.f90 @@ -0,0 +1,62 @@ +! { dg-do run } + +module omp_lib_kinds + use iso_c_binding, only: c_int, c_intptr_t + implicit none + private :: c_int, c_intptr_t + integer, parameter :: omp_allocator_handle_kind = c_intptr_t + + integer (kind=omp_allocator_handle_kind), & + parameter :: omp_null_allocator = 0 + integer (kind=omp_allocator_handle_kind), & + parameter :: omp_default_mem_alloc = 1 + integer (kind=omp_allocator_handle_kind), & + parameter :: omp_large_cap_mem_alloc = 2 + integer (kind=omp_allocator_handle_kind), & + parameter :: omp_const_mem_alloc = 3 + integer (kind=omp_allocator_handle_kind), & + parameter :: omp_high_bw_mem_alloc = 4 + integer (kind=omp_allocator_handle_kind), & + parameter :: omp_low_lat_mem_alloc = 5 + integer (kind=omp_allocator_handle_kind), & + parameter :: omp_cgroup_mem_alloc = 6 + integer (kind=omp_allocator_handle_kind), & + parameter :: omp_pteam_mem_alloc = 7 + integer (kind=omp_allocator_handle_kind), & + parameter :: omp_thread_mem_alloc = 8 +end module + +module m + use iso_c_binding, only: c_intptr_t + use omp_lib_kinds, only: omp_default_mem_alloc + implicit none (type, external) + + integer(c_intptr_t) :: intptr + + integer :: A(4) = [1,2,3,4] + !$omp allocate(A) align(128) allocator(omp_default_mem_alloc) +contains + subroutine f() + integer :: B(4) = [1,2,3,4] + !$omp allocate(B) align(256) allocator(omp_default_mem_alloc) + + if (mod (transfer (loc (A), intptr), 128_c_intptr_t) /= 0) stop 1 + if (mod (transfer (loc (B), intptr), 256_c_intptr_t) /= 0) stop 2 + + call inner() + contains + subroutine inner() + integer :: C(4) = [1,2,3,4] + !$omp allocate(C) align(1024) allocator(omp_default_mem_alloc) + if (mod (transfer (loc (A), intptr), 128_c_intptr_t) /= 0) stop 3 + if (mod (transfer (loc (B), intptr), 256_c_intptr_t) /= 0) stop 4 + if (mod (transfer (loc (C), intptr), 1024_c_intptr_t) /= 0) stop 5 + end + end +end + +use m +implicit none (type, external) +if (mod (transfer (loc (A), intptr), 128_c_intptr_t) /= 0) stop 6 +call f() +end diff --git a/include/gomp-constants.h b/include/gomp-constants.h index 9618727888d..3091496495d 100644 --- a/include/gomp-constants.h +++ b/include/gomp-constants.h @@ -382,6 +382,14 @@ enum gomp_map_kind #define GOMP_DEPEND_MUTEXINOUTSET 4 #define GOMP_DEPEND_INOUTSET 5 +/* Predefined allocator value ranges. */ +#define GOMP_OMP_PREDEF_ALLOC_MAX 8 +#define GOMP_OMPX_PREDEF_ALLOC_MIN 200 +#define GOMP_OMPX_PREDEF_ALLOC_MAX 200 + +/* Predefined allocator with access == thread. */ +#define GOMP_OMP_PREDEF_ALLOC_THREADS 8 + /* Flag values for OpenMP 'requires' directive features. */ // compiler use only: OMP_REQUIRES_ATOMIC_DEFAULT_MEM_ORDER 0xf #define GOMP_REQUIRES_UNIFIED_ADDRESS 0x10 diff --git a/libgomp/allocator.c b/libgomp/allocator.c index 91aa58e162b..f960e274a22 100644 --- a/libgomp/allocator.c +++ b/libgomp/allocator.c @@ -102,6 +102,15 @@ GOMP_is_alloc (void *ptr) #define ompx_gnu_min_predefined_alloc ompx_gnu_pinned_mem_alloc #define ompx_gnu_max_predefined_alloc ompx_gnu_pinned_mem_alloc +_Static_assert (GOMP_OMP_PREDEF_ALLOC_MAX == omp_thread_mem_alloc, + "GOMP_OMP_PREDEF_ALLOC_MAX == omp_thread_mem_alloc"); +_Static_assert (GOMP_OMPX_PREDEF_ALLOC_MIN == ompx_gnu_min_predefined_alloc, + "GOMP_OMP_PREDEF_ALLOC_MAX == omp_thread_mem_alloc"); +_Static_assert (GOMP_OMPX_PREDEF_ALLOC_MAX == ompx_gnu_max_predefined_alloc, + "GOMP_OMP_PREDEF_ALLOC_MAX == omp_thread_mem_alloc"); +_Static_assert (GOMP_OMP_PREDEF_ALLOC_THREADS == omp_thread_mem_alloc, + "GOMP_OMP_PREDEF_ALLOC_THREADS == omp_thread_mem_alloc"); + /* These macros may be overridden in config//allocator.c. The defaults (no override) are to return NULL for pinned memory requests and pass through to the regular OS calls otherwise. diff --git a/libgomp/libgomp.texi b/libgomp/libgomp.texi index c6464ece32e..bad06e143dc 100644 --- a/libgomp/libgomp.texi +++ b/libgomp/libgomp.texi @@ -233,9 +233,9 @@ The OpenMP 4.5 specification is fully supported. @tab Y @tab See also @ref{Memory allocation} @item Memory management routines @tab Y @tab @item @code{allocate} directive @tab P - @tab Only C for stack/automatic and Fortran for stack/automatic - and allocatable/pointer variables -@item @code{allocate} clause @tab P @tab Initial support + @tab C++ unsupported; see also @ref{Memory allocation} +@item @code{allocate} clause @tab P @tab Clause has no effect on @code{target} + (@uref{https://gcc.gnu.org/PR113436,PR113436}) @item @code{use_device_addr} clause on @code{target data} @tab Y @tab @item @code{ancestor} modifier on @code{device} clause @tab Y @tab @item Implicit declare target directive @tab Y @tab @@ -306,7 +306,7 @@ The OpenMP 4.5 specification is fully supported. @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 P - @tab Only C and Fortran (and not for static variables) + @tab Only C and Fortran @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 @@ -6414,14 +6414,14 @@ The description below applies to: constant expression with value @code{omp_default_mem_alloc} and no @code{align} modifier has been specified. (In that case, the normal @code{malloc} allocation is used.) +@item The @code{allocate} directive for variables in static memory; while + the alignment is honored, the normal static memory is used. @item Using the @code{allocate} directive for automatic/stack variables, except when the @code{allocator} clause is a constant expression with value @code{omp_default_mem_alloc} and no @code{align} clause has been specified. (In that case, the normal allocation is used: stack allocation and, sometimes for Fortran, also @code{malloc} [depending on flags such as @option{-fstack-arrays}].) -@item Using the @code{allocate} directive for variable in static memory is - currently not supported (compile time error). @item In Fortran, the @code{allocators} directive and the executable @code{allocate} directive for Fortran pointers and allocatables is supported, but requires that files containing those directives has to be @@ -6433,7 +6433,8 @@ The description below applies to: For the available predefined allocators and, as applicable, their associated predefined memory spaces and for the available traits and their default values, see @ref{OMP_ALLOCATOR}. Predefined allocators without an associated memory -space use the @code{omp_default_mem_space} memory space. +space use the @code{omp_default_mem_space} memory space. See additionally +@ref{Offload-Target Specifics}. For the memory spaces, the following applies: @itemize