diff --git a/gcc/attribs.cc b/gcc/attribs.cc index b8cb55b97df..229d8b32c1e 100644 --- a/gcc/attribs.cc +++ b/gcc/attribs.cc @@ -719,6 +719,12 @@ decl_attributes (tree *node, tree attributes, int flags, if (ns == NULL_TREE || !cxx11_attr_p) warning (OPT_Wattributes, "%qE attribute directive ignored", name); + else if ((flag_openmp || flag_openmp_simd) + && is_attribute_p ("omp", ns) + && is_attribute_p ("directive", name) + && (VAR_P (*node) + || TREE_CODE (*node) == FUNCTION_DECL)) + continue; else warning (OPT_Wattributes, "%<%E::%E%> scoped attribute directive ignored", diff --git a/gcc/c-family/c-omp.cc b/gcc/c-family/c-omp.cc index 9b7d7f789e3..95b6c1e623f 100644 --- a/gcc/c-family/c-omp.cc +++ b/gcc/c-family/c-omp.cc @@ -3306,6 +3306,8 @@ const struct c_omp_directive c_omp_directives[] = { C_OMP_DIR_STANDALONE, false }, { "for", nullptr, nullptr, PRAGMA_OMP_FOR, C_OMP_DIR_CONSTRUCT, true }, + /* { "groupprivate", nullptr, nullptr, PRAGMA_OMP_GROUPPRIVATE, + C_OMP_DIR_DECLARATIVE, false }, */ /* { "interop", nullptr, nullptr, PRAGMA_OMP_INTEROP, C_OMP_DIR_STANDALONE, false }, */ { "loop", nullptr, nullptr, PRAGMA_OMP_LOOP, diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index fd6bf9fd4a0..6e34952da99 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -7341,6 +7341,7 @@ extern tree cp_convert_range_for (tree, tree, tree, cp_decomp *, bool, extern void cp_convert_omp_range_for (tree &, tree &, tree &, tree &, tree &, tree &, tree &, tree &); extern void cp_finish_omp_range_for (tree, tree); +extern bool cp_maybe_parse_omp_decl (tree, tree); extern bool parsing_nsdmi (void); extern bool parsing_function_declarator (); extern bool parsing_default_capturing_generic_lambda_in_template (void); diff --git a/gcc/cp/decl2.cc b/gcc/cp/decl2.cc index 5dae6f3bbc0..113b03119ec 100644 --- a/gcc/cp/decl2.cc +++ b/gcc/cp/decl2.cc @@ -1782,16 +1782,34 @@ cplus_decl_attributes (tree *decl, tree attributes, int flags) { tree name = get_attribute_name (*pa); if (is_attribute_p ("directive", name) - || is_attribute_p ("sequence", name)) + || is_attribute_p ("sequence", name) + || is_attribute_p ("decl", name)) { - if (!diagnosed) + const char *p = NULL; + if (TREE_VALUE (*pa) == NULL_TREE) + p = IDENTIFIER_POINTER (name); + for (tree a = TREE_VALUE (*pa); a; a = TREE_CHAIN (a)) { - error ("% not allowed to be specified in this " - "context", name); + tree d = TREE_VALUE (a); + gcc_assert (TREE_CODE (d) == DEFERRED_PARSE); + if (TREE_PUBLIC (d) + && (VAR_P (*decl) + || TREE_CODE (*decl) == FUNCTION_DECL) + && cp_maybe_parse_omp_decl (*decl, d)) + continue; + p = TREE_PUBLIC (d) ? "decl" : "directive"; + } + if (p && !diagnosed) + { + error ("% not allowed to be specified in " + "this context", p); diagnosed = true; } - *pa = TREE_CHAIN (*pa); - continue; + if (p) + { + *pa = TREE_CHAIN (*pa); + continue; + } } } pa = &TREE_CHAIN (*pa); diff --git a/gcc/cp/name-lookup.cc b/gcc/cp/name-lookup.cc index e776bb868fd..a8b9229b29e 100644 --- a/gcc/cp/name-lookup.cc +++ b/gcc/cp/name-lookup.cc @@ -8402,12 +8402,24 @@ finish_using_directive (tree target, tree attribs) else if ((flag_openmp || flag_openmp_simd) && get_attribute_namespace (a) == omp_identifier && (is_attribute_p ("directive", name) - || is_attribute_p ("sequence", name))) + || is_attribute_p ("sequence", name) + || is_attribute_p ("decl", name))) { if (!diagnosed) - error ("% not allowed to be specified in this " - "context", name); - diagnosed = true; + { + if (tree ar = TREE_VALUE (a)) + { + tree d = TREE_VALUE (ar); + gcc_assert (TREE_CODE (d) == DEFERRED_PARSE); + error ("% not allowed to be specified in " + "this context", + TREE_PUBLIC (d) ? "decl" : "directive"); + } + else + error ("% not allowed to be specified in this " + "context", name); + diagnosed = true; + } } else warning (OPT_Wattributes, "%qD attribute directive ignored", name); diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc index 8808da3a842..8cac3dc94b9 100644 --- a/gcc/cp/parser.cc +++ b/gcc/cp/parser.cc @@ -12001,6 +12001,12 @@ cp_parser_handle_statement_omp_attributes (cp_parser *parser, tree attrs) parser->omp_attrs_forbidden_p = false; bad = true; } + else if (TREE_PUBLIC (d)) + { + error_at (first->location, + "OpenMP % attribute on a statement"); + bad = true; + } const char *directive[3] = {}; for (int i = 0; i < 3; i++) { @@ -12022,8 +12028,9 @@ cp_parser_handle_statement_omp_attributes (cp_parser *parser, tree attrs) if (dir == NULL) { error_at (first->location, - "unknown OpenMP directive name in %" - " attribute argument"); + "unknown OpenMP directive name in %qs attribute " + "argument", + TREE_PUBLIC (d) ? "omp::decl" : "omp::directive"); continue; } c_omp_directive_kind kind = dir->kind; @@ -29366,7 +29373,7 @@ cp_parser_gnu_attribute_list (cp_parser* parser, bool exactly_one /* = false */) parsing. */ static void -cp_parser_omp_directive_args (cp_parser *parser, tree attribute) +cp_parser_omp_directive_args (cp_parser *parser, tree attribute, bool decl_p) { cp_token *first = cp_lexer_peek_nth_token (parser->lexer, 2); if (first->type == CPP_CLOSE_PAREN) @@ -29393,6 +29400,8 @@ cp_parser_omp_directive_args (cp_parser *parser, tree attribute) tree arg = make_node (DEFERRED_PARSE); DEFPARSE_TOKENS (arg) = cp_token_cache_new (first, last); DEFPARSE_INSTANTIATIONS (arg) = nullptr; + if (decl_p) + TREE_PUBLIC (arg) = 1; TREE_VALUE (attribute) = tree_cons (NULL_TREE, arg, TREE_VALUE (attribute)); } @@ -29440,7 +29449,7 @@ cp_parser_omp_sequence_args (cp_parser *parser, tree attribute) cp_parser_required_error (parser, RT_OPEN_PAREN, false, UNKNOWN_LOCATION); else if (directive) - cp_parser_omp_directive_args (parser, attribute); + cp_parser_omp_directive_args (parser, attribute, false); else cp_parser_omp_sequence_args (parser, attribute); if (cp_lexer_next_token_is_not (parser->lexer, CPP_COMMA)) @@ -29592,7 +29601,8 @@ cp_parser_std_attribute (cp_parser *parser, tree attr_ns) if ((flag_openmp || flag_openmp_simd) && attr_ns == omp_identifier && (is_attribute_p ("directive", attr_id) - || is_attribute_p ("sequence", attr_id))) + || is_attribute_p ("sequence", attr_id) + || is_attribute_p ("decl", attr_id))) { error_at (token->location, "% attribute requires argument", attr_id); @@ -29636,7 +29646,14 @@ cp_parser_std_attribute (cp_parser *parser, tree attr_ns) { if (is_attribute_p ("directive", attr_id)) { - cp_parser_omp_directive_args (parser, attribute); + cp_parser_omp_directive_args (parser, attribute, false); + return attribute; + } + else if (is_attribute_p ("decl", attr_id)) + { + TREE_VALUE (TREE_PURPOSE (attribute)) + = get_identifier ("directive"); + cp_parser_omp_directive_args (parser, attribute, true); return attribute; } else if (is_attribute_p ("sequence", attr_id)) @@ -37912,6 +37929,21 @@ static tree cp_parser_omp_var_list (cp_parser *parser, enum omp_clause_code kind, tree list, bool allow_deref = false) { + if (parser->lexer->in_omp_decl_attribute) + { + if (kind) + { + location_t loc = cp_lexer_peek_token (parser->lexer)->location; + tree u = build_omp_clause (loc, kind); + OMP_CLAUSE_DECL (u) = parser->lexer->in_omp_decl_attribute; + OMP_CLAUSE_CHAIN (u) = list; + return u; + } + else + return tree_cons (parser->lexer->in_omp_decl_attribute, NULL_TREE, + list); + } + if (cp_parser_require (parser, CPP_OPEN_PAREN, RT_OPEN_PAREN)) return cp_parser_omp_var_list_no_open (parser, kind, list, NULL, allow_deref); @@ -47843,7 +47875,9 @@ cp_parser_late_parsing_omp_declare_simd (cp_parser *parser, tree attrs) { error_at (first->location, "unknown OpenMP directive name in " - "% attribute argument"); + "%qs attribute argument", + TREE_PUBLIC (d) + ? "omp::decl" : "omp::directive"); continue; } if (dir->id != PRAGMA_OMP_DECLARE @@ -47949,6 +47983,89 @@ cp_parser_late_parsing_omp_declare_simd (cp_parser *parser, tree attrs) return attrs; } +/* D should be DEFERRED_PARSE from omp::decl attribute. If it contains + a threadprivate, groupprivate, allocate or declare target directive, + return true and parse it for DECL. */ + +bool +cp_maybe_parse_omp_decl (tree decl, tree d) +{ + gcc_assert (TREE_CODE (d) == DEFERRED_PARSE); + cp_token *first = DEFPARSE_TOKENS (d)->first; + cp_token *last = DEFPARSE_TOKENS (d)->last; + const char *directive[3] = {}; + for (int j = 0; j < 3; j++) + { + tree id = NULL_TREE; + if (first + j == last) + break; + if (first[j].type == CPP_NAME) + id = first[j].u.value; + else if (first[j].type == CPP_KEYWORD) + id = ridpointers[(int) first[j].keyword]; + else + break; + directive[j] = IDENTIFIER_POINTER (id); + } + const c_omp_directive *dir = NULL; + if (directive[0]) + dir = c_omp_categorize_directive (directive[0], directive[1], + directive[2]); + if (dir == NULL) + { + error_at (first->location, + "unknown OpenMP directive name in " + "%qs attribute argument", "omp::decl"); + return false; + } + if (dir->id != PRAGMA_OMP_THREADPRIVATE + /* && dir->id != PRAGMA_OMP_GROUPPRIVATE */ + && dir->id != PRAGMA_OMP_ALLOCATE + && (dir->id != PRAGMA_OMP_DECLARE + || strcmp (directive[1], "target") != 0)) + return false; + + if (!flag_openmp && !dir->simd) + return true; + + cp_parser *parser = the_parser; + cp_lexer *lexer = cp_lexer_alloc (); + lexer->debugging_p = parser->lexer->debugging_p; + lexer->in_omp_decl_attribute = decl; + vec_safe_reserve (lexer->buffer, last - first + 3, true); + cp_token tok = {}; + tok.type = CPP_PRAGMA; + tok.keyword = RID_MAX; + tok.u.value = build_int_cst (NULL, dir->id); + tok.location = first->location; + lexer->buffer->quick_push (tok); + while (++first < last) + lexer->buffer->quick_push (*first); + tok = {}; + tok.type = CPP_PRAGMA_EOL; + tok.keyword = RID_MAX; + tok.location = last->location; + lexer->buffer->quick_push (tok); + tok = {}; + tok.type = CPP_EOF; + tok.keyword = RID_MAX; + tok.location = last->location; + lexer->buffer->quick_push (tok); + lexer->next = parser->lexer; + lexer->next_token = lexer->buffer->address (); + lexer->last_token = lexer->next_token + + lexer->buffer->length () + - 1; + lexer->in_omp_attribute_pragma = true; + parser->lexer = lexer; + /* Move the current source position to that of the first token in the + new lexer. */ + cp_lexer_set_source_position_from_token (lexer->next_token); + cp_parser_pragma (parser, pragma_external, NULL); + + return true; +} + /* Helper for cp_parser_omp_declare_target, handle one to or link clause on #pragma omp declare target. Return false if errors were reported. */ @@ -48048,7 +48165,8 @@ cp_parser_omp_declare_target (cp_parser *parser, cp_token *pragma_tok) clauses = cp_parser_omp_all_clauses (parser, OMP_DECLARE_TARGET_CLAUSE_MASK, "#pragma omp declare target", pragma_tok); - else if (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_PAREN)) + else if (parser->lexer->in_omp_decl_attribute + || cp_lexer_next_token_is (parser->lexer, CPP_OPEN_PAREN)) { clauses = cp_parser_omp_var_list (parser, OMP_CLAUSE_ENTER, clauses); diff --git a/gcc/cp/parser.h b/gcc/cp/parser.h index 6cbb9a8e031..9ba802194e4 100644 --- a/gcc/cp/parser.h +++ b/gcc/cp/parser.h @@ -107,6 +107,10 @@ struct GTY (()) cp_lexer { /* The next lexer in a linked list of lexers. */ struct cp_lexer *next; + /* Set for omp::decl attribute parsing to the decl to which it + appertains. */ + tree in_omp_decl_attribute; + /* True if we should output debugging information. */ bool debugging_p; diff --git a/gcc/testsuite/g++.dg/gomp/attrs-19.C b/gcc/testsuite/g++.dg/gomp/attrs-19.C new file mode 100644 index 00000000000..77e565a7889 --- /dev/null +++ b/gcc/testsuite/g++.dg/gomp/attrs-19.C @@ -0,0 +1,68 @@ +// { dg-do compile { target c++11 } } + +void foo1 (); + +void +foo () +{ + [[omp::decl (declare variant (foo1) match (construct={parallel,for}))]] + extern void foo2 (); + [[omp::sequence (directive (parallel), directive (for))]] + for (int i = 0; i < 5; i++) + foo2 (); + [[omp::decl (declare simd simdlen(4) linear(l) aligned(p:4) uniform(p) inbranch), + omp::directive (declare simd simdlen(8) notinbranch)]] + extern int foo3 (int l, int *p); + [[omp::directive (declare simd simdlen(4) linear(l) aligned(p:4) uniform(p) inbranch), + omp::decl (declare simd simdlen(8) notinbranch)]] + extern int foo4 (int l, int *p); + [[omp::decl (declare simd simdlen(4) linear(l) aligned(p:4) uniform(p) inbranch), + omp::decl (declare simd simdlen(8) notinbranch)]] + extern int foo5 (int l, int *p); +} + +void bar1 (); + +void +bar () +{ + [[using omp : decl (declare variant (bar1), match (construct={parallel,for}))]] // { dg-warning "attribute using prefix only available with" "" { target c++14_down } } + extern void bar2 (); + [[using omp : sequence (directive (parallel), directive (for))]] // { dg-warning "attribute using prefix only available with" "" { target c++14_down } } + for (int i = 0; i < 5; i++) + bar2 (); + [[omp::decl (declare simd, simdlen(4), linear(l), aligned(p:4),uniform(p),inbranch), + omp::directive (declare simd simdlen(8) notinbranch)]] + extern int bar3 (int l, int *p); + [[using omp : directive (declare simd,simdlen(4),linear(l),aligned(p:4),uniform(p),inbranch), // { dg-warning "attribute using prefix only available with" "" { target c++14_down } } + decl (declare simd, simdlen(8), notinbranch)]] + extern int bar4 (int l, int *p); + [[omp::decl (declare simd, simdlen(4), linear(l), aligned(p:4), uniform(p), inbranch), + omp::decl (declare simd, simdlen(8), notinbranch)]] + extern int bar5 (int l, int *p); +} + +struct S { S (); ~S (); int s; }; + +[[omp::decl (threadprivate)]] int t1, t2; +int x1, t3 [[omp::decl (threadprivate)]], x2, t4 [[omp::decl (threadprivate)]] [5]; +[[maybe_unused, omp::decl (threadprivate)]] int t5, t6; +[[using omp : decl (threadprivate)]] S t7, t8; // { dg-warning "attribute using prefix only available with" "" { target c++14_down } } +[[using omp : decl (declare target enter device_type (host))]] int d1, d2, d3 (int, int), d4; // { dg-warning "attribute using prefix only available with" "" { target c++14_down } } +int x3, d5 [[omp::decl (declare target, enter, device_type (any))]], d6 [[omp::decl (declare target link)]], x4; +int d7 [[omp::decl (declare target)]]; +[[using omp : decl (declare target), decl (declare target)]] int d8, d9; // { dg-warning "attribute using prefix only available with" "" { target c++14_down } } + +void +baz () +{ + [[omp::decl (threadprivate)]] static int t1, t2; + static int x1, t3 [[omp::decl (threadprivate)]], x2, t4 [[omp::decl (threadprivate)]] [5]; + [[maybe_unused, omp::decl (threadprivate)]] extern int t5, t6; + [[using omp : decl (declare target enter)]] extern int d1, d2, d3 (int, int), d4; // { dg-warning "attribute using prefix only available with" "" { target c++14_down } } + static int x3, d5 [[omp::decl (declare target, enter, device_type (any))]], d6 [[omp::decl (declare target link)]], x4; + ++t1; ++t2; + ++t3; ++t4[2]; + ++t5; ++t6; + ++d1; +} diff --git a/gcc/testsuite/g++.dg/gomp/attrs-20.C b/gcc/testsuite/g++.dg/gomp/attrs-20.C new file mode 100644 index 00000000000..86f8612ea61 --- /dev/null +++ b/gcc/testsuite/g++.dg/gomp/attrs-20.C @@ -0,0 +1,240 @@ +// { dg-do compile { target c++11 } } +// { dg-options "-fopenmp -ffat-lto-objects -fdump-tree-gimple" } + +extern "C" void abort (); + +[[omp::decl (declare simd, linear (l))]] extern int f1 (int l); +extern int f2 (int), f3 [[omp::decl (declare simd, uniform (m))]] (int m), f4 (int), z; +[[omp::decl (declare simd, linear (l), simdlen(4))]] extern int f5 [[omp::decl (declare simd uniform (l) simdlen (8) notinbranch)]] (int l); + +int +f1 (int l) +{ + return l; +} + +// { dg-final { scan-assembler-times "_ZGVbM4l__Z2f1i:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVbN4l__Z2f1i:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVcM4l__Z2f1i:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVcN4l__Z2f1i:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVdM8l__Z2f1i:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVdN8l__Z2f1i:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVeM16l__Z2f1i:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVeN16l__Z2f1i:" 1 { target { i?86-*-* x86_64-*-* } } } } + +int +f2 (int l) +{ + return l + 1; +} + +// { dg-final { scan-assembler-not "_ZGV\[a-zA-Z0-9]__Z2f2i:" { target { i?86-*-* x86_64-*-* } } } } + +int +f3 (int l) +{ + return l + 2; +} + +// { dg-final { scan-assembler-times "_ZGVbM4u__Z2f3i:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVbN4u__Z2f3i:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVcM4u__Z2f3i:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVcN4u__Z2f3i:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVdM8u__Z2f3i:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVdN8u__Z2f3i:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVeM16u__Z2f3i:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVeN16u__Z2f3i:" 1 { target { i?86-*-* x86_64-*-* } } } } + +int +f4 (int l) +{ + return l + 3; +} + +// { dg-final { scan-assembler-not "_ZGV\[a-zA-Z0-9]__Z2f4i:" { target { i?86-*-* x86_64-*-* } } } } + +int +f5 (int l) +{ // { dg-warning "GCC does not currently support simdlen 8 for type 'int'" "" { target aarch64*-*-* } .-1 } + return l + 4; +} + +// { dg-final { scan-assembler-times "_ZGVbM4l__Z2f5i:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVbN4l__Z2f5i:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVcM4l__Z2f5i:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVcN4l__Z2f5i:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVdM4l__Z2f5i:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVdN4l__Z2f5i:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVeM4l__Z2f5i:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVeN4l__Z2f5i:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVbN8u__Z2f5i:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVcN8u__Z2f5i:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVdN8u__Z2f5i:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVeN8u__Z2f5i:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-not "_ZGV\[bcde]M8u__Z2f5i:" { target { i?86-*-* x86_64-*-* } } } } + +[[omp::decl (declare simd, linear (l), simdlen(4), notinbranch), + omp::decl (declare simd, uniform (l), simdlen(4), inbranch)]] +int +f6 [[using omp : decl (declare simd uniform (l) simdlen (8), notinbranch), // { dg-warning "attribute using prefix only available with" "" { target c++14_down } } + decl (declare simd, linear (l), simdlen (8), inbranch)]] (int l) +{ // { dg-warning "GCC does not currently support simdlen 8 for type 'int'" "" { target aarch64*-*-* } .-2 } + return l + 5; +} + +// { dg-final { scan-assembler-times "_ZGVbM4u__Z2f6i:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVbN4l__Z2f6i:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVbM8l__Z2f6i:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVbN8u__Z2f6i:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVcM4u__Z2f6i:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVcN4l__Z2f6i:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVcM8l__Z2f6i:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVcN8u__Z2f6i:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVdM4u__Z2f6i:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVdN4l__Z2f6i:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVdM8l__Z2f6i:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVdN8u__Z2f6i:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVeM4u__Z2f6i:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVeN4l__Z2f6i:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVeM8l__Z2f6i:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVeN8u__Z2f6i:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-not "_ZGV\[bcde]M4l__Z2f6i:" { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-not "_ZGV\[bcde]N4u__Z2f6i:" { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-not "_ZGV\[bcde]M8u__Z2f6i:" { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-not "_ZGV\[bcde]N8l__Z2f6i:" { target { i?86-*-* x86_64-*-* } } } } + +int +f7 (int l) +{ + return l + 6; +} + +// { dg-final { scan-assembler-not "_ZGV\[a-zA-Z0-9]__Z2f7i:" { target { i?86-*-* x86_64-*-* } } } } + +int +f8 (int l) +{ + return l + 7; +} + +// { dg-final { scan-assembler-not "_ZGV\[a-zA-Z0-9]__Z2f8i:" { target { i?86-*-* x86_64-*-* } } } } + +[[omp::decl (declare variant (f7), match (construct={parallel})), + omp::decl (declare simd uniform (l), simdlen(4))]] +int +f9 [[omp::decl (declare simd uniform (l) simdlen (8)), + omp::decl (declare variant (f8) match (construct={parallel,for}))]] (int l) +{ // { dg-warning "GCC does not currently support simdlen 8 for type 'int'" "" { target aarch64*-*-* } .-2 } + return l + 8; +} + +// { dg-final { scan-assembler-times "_ZGVbM4u__Z2f9i:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVbN4u__Z2f9i:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVcM4u__Z2f9i:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVcN4u__Z2f9i:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVdM4u__Z2f9i:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVdN4u__Z2f9i:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVeM4u__Z2f9i:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVeN4u__Z2f9i:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVbM8u__Z2f9i:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVbN8u__Z2f9i:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVcM8u__Z2f9i:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVcN8u__Z2f9i:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVdM8u__Z2f9i:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVdN8u__Z2f9i:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVeM8u__Z2f9i:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVeN8u__Z2f9i:" 1 { target { i?86-*-* x86_64-*-* } } } } + +int z; + +void +test () +{ + [[omp::directive (parallel)]] + if (f9 (3) != 9) + abort (); + [[omp::directive (parallel for)]] + for (int i = 0; i < 1; i++) + if (f9 (4) != 11) + abort (); + if (f9 (5) != 13) + abort (); +} + +// { dg-final { scan-tree-dump-times " = f7 \\\(3\\\);" 1 "gimple" } } +// { dg-final { scan-tree-dump-times " = f8 \\\(4\\\);" 1 "gimple" } } +// { dg-final { scan-tree-dump-times " = f9 \\\(5\\\);" 1 "gimple" } } + +template +int +f10 (int x) +{ + return x + N; +} + +template [[omp::decl (declare simd, notinbranch)]] int f10<0> (int); + +// { dg-final { scan-assembler-times "_ZGVbN4v__Z3f10ILi0EEii:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVcN4v__Z3f10ILi0EEii:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVdN8v__Z3f10ILi0EEii:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVeN16v__Z3f10ILi0EEii:" 1 { target { i?86-*-* x86_64-*-* } } } } + +template int f10<1> [[omp::decl (declare simd inbranch linear(x))]] (int x); + +// { dg-final { scan-assembler-times "_ZGVbM4l__Z3f10ILi1EEii:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVcM4l__Z3f10ILi1EEii:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVdM8l__Z3f10ILi1EEii:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVeM16l__Z3f10ILi1EEii:" 1 { target { i?86-*-* x86_64-*-* } } } } + +template +int f11 (int); + +template <> [[omp::decl (declare simd, inbranch)]] int +f11<0> (int x) +{ + return x; +} + +// { dg-final { scan-assembler-times "_ZGVbM4v__Z3f11ILi0EEii:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVcM4v__Z3f11ILi0EEii:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVdM8v__Z3f11ILi0EEii:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVeM16v__Z3f11ILi0EEii:" 1 { target { i?86-*-* x86_64-*-* } } } } + +template <> int +f11<1> [[omp::decl (declare simd, notinbranch, linear (y))]] (int y) +{ + return y; +} + +// { dg-final { scan-assembler-times "_ZGVbN4l__Z3f11ILi1EEii:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVcN4l__Z3f11ILi1EEii:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVdN8l__Z3f11ILi1EEii:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVeN16l__Z3f11ILi1EEii:" 1 { target { i?86-*-* x86_64-*-* } } } } + +struct S +{ + [[omp::decl (declare simd, inbranch, uniform (this))]] int f12 (int x); + int f13 [[gnu::noinline, omp::decl (declare simd notinbranch uniform (this) linear (y))]] (int y) { return y; } +}; + +int +S::f12 (int x) +{ + return x; +} + +// { dg-final { scan-assembler-times "_ZGVbM4uv__ZN1S3f12Ei:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVcM4uv__ZN1S3f12Ei:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVdM8uv__ZN1S3f12Ei:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVeM16uv__ZN1S3f12Ei:" 1 { target { i?86-*-* x86_64-*-* } } } } + +// { dg-final { scan-assembler-times "_ZGVbN4ul__ZN1S3f13Ei:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVcN4ul__ZN1S3f13Ei:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVdN8ul__ZN1S3f13Ei:" 1 { target { i?86-*-* x86_64-*-* } } } } +// { dg-final { scan-assembler-times "_ZGVeN16ul__ZN1S3f13Ei:" 1 { target { i?86-*-* x86_64-*-* } } } } + +int +f14 (S &p, int x) +{ + return p.f13 (x); +} diff --git a/gcc/testsuite/g++.dg/gomp/attrs-21.C b/gcc/testsuite/g++.dg/gomp/attrs-21.C new file mode 100644 index 00000000000..46bdef268da --- /dev/null +++ b/gcc/testsuite/g++.dg/gomp/attrs-21.C @@ -0,0 +1,27 @@ +// { dg-do compile { target c++11 } } + +void +foo () +{ + [[omp::decl]] int v1; // { dg-error "'omp::decl' attribute requires argument" } + [[omp::decl ()]] int v2; // { dg-error "expected OpenMP directive name" } + // { dg-error "'omp::directive' not allowed to be specified in this context" "" { target *-*-* } .-1 } + [[omp::decl (nonexistent foobar)]] int v3; // { dg-error "unknown OpenMP directive name in 'omp::decl' attribute argument" } + // { dg-error "'omp::decl' not allowed to be specified in this context" "" { target *-*-* } .-1 } + [[omp::sequence(decl(threadprivate))]] int v4; // { dg-error "expected 'directive' or 'sequence'" } + // { dg-error "'omp::directive' not allowed to be specified in this context" "" { target *-*-* } .-1 } + [[omp::sequence(omp::decl(threadprivate))]] int v5; // { dg-error "expected 'directive' or 'sequence'" } + // { dg-error "'omp::directive' not allowed to be specified in this context" "" { target *-*-* } .-1 } + [[omp::decl (barrier)]]; // { dg-error "OpenMP 'omp::decl' attribute on a statement" } + [[omp::decl (parallel)]] {}; // { dg-error "OpenMP 'omp::decl' attribute on a statement" } + extern int [[omp::decl (threadprivate)]] *v6; // { dg-warning "attribute ignored" } + [[omp::decl (threadprivate (v5))]] static int v7; // { dg-error "expected end of line before '\\\(' token" } + extern int v8; + [[omp::decl (declare target (v8))]] static int v9; // { dg-error "expected end of line before '\\\(' token" } + [[omp::decl (declare target enter (v8))]] static int v10; // { dg-error "expected an OpenMP clause before '\\\(' token" } + [[omp::decl (declare target, link (v9))]] static int v11; // { dg-error "expected an OpenMP clause before '\\\(' token" } + [[omp::decl (declare target device_type (any))]] static int v12; // { dg-error "directive with only 'device_type' clause" } +} + +int i; +[[omp::decl (assume (i < 42))]]; // { dg-error "OpenMP 'omp::decl' attribute on a statement" } diff --git a/libgomp/libgomp.texi b/libgomp/libgomp.texi index c6cd825bbaa..f5cb5b643a2 100644 --- a/libgomp/libgomp.texi +++ b/libgomp/libgomp.texi @@ -444,7 +444,7 @@ Technical Report (TR) 11 is the first preview for OpenMP 6.0. @item Features deprecated in versions 5.2, 5.1 and 5.0 were removed @tab N/A @tab Backward compatibility @item The @code{decl} attribute was added to the C++ attribute syntax - @tab N @tab + @tab Y @tab @item @code{_ALL} suffix to the device-scope environment variables @tab P @tab Host device number wrongly accepted @item For Fortran, @emph{locator list} can be also function reference with