From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: by sourceware.org (Postfix, from userid 2153) id F19673858007; Mon, 26 Jul 2021 07:16:59 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org F19673858007 MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Content-Type: text/plain; charset="utf-8" From: Jakub Jelinek To: gcc-cvs@gcc.gnu.org Subject: [gcc r12-2506] openmp: Add support for omp attributes section and scan directives X-Act-Checkin: gcc X-Git-Author: Jakub Jelinek X-Git-Refname: refs/heads/master X-Git-Oldrev: 124bb55777c280a85d0c72ec13e293a32917a6b9 X-Git-Newrev: acf9d1fd806fabf62dfe232439b11263c191e32d Message-Id: <20210726071659.F19673858007@sourceware.org> Date: Mon, 26 Jul 2021 07:16:59 +0000 (GMT) X-BeenThere: gcc-cvs@gcc.gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Gcc-cvs mailing list List-Unsubscribe: , List-Archive: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 26 Jul 2021 07:17:00 -0000 https://gcc.gnu.org/g:acf9d1fd806fabf62dfe232439b11263c191e32d commit r12-2506-gacf9d1fd806fabf62dfe232439b11263c191e32d Author: Jakub Jelinek Date: Mon Jul 26 09:13:47 2021 +0200 openmp: Add support for omp attributes section and scan directives This patch adds support for expressing the section and scan directives using the attribute syntax and additionally fixes some bugs in the attribute syntax directive handling. For now it requires that the scan and section directives appear as the only attribute, not combined with other OpenMP or non-OpenMP attributes on the same statement. 2021-07-26 Jakub Jelinek * parser.h (struct cp_lexer): Add orphan_p member. * parser.c (cp_parser_statement): Don't change in_omp_attribute_pragma upon restart from CPP_PRAGMA handling. Fix up condition when a lexer should be destroyed and adjust saved_tokens if it records tokens from the to be destroyed lexer. (cp_parser_omp_section_scan): New function. (cp_parser_omp_scan_loop_body): Use it. If parser->lexer->in_omp_attribute_pragma, allow optional comma after scan. (cp_parser_omp_sections_scope): Use cp_parser_omp_section_scan. * g++.dg/gomp/attrs-1.C: Use attribute syntax even for section and scan directives. * g++.dg/gomp/attrs-2.C: Likewise. * g++.dg/gomp/attrs-6.C: New test. * g++.dg/gomp/attrs-7.C: New test. * g++.dg/gomp/attrs-8.C: New test. Diff: --- gcc/cp/parser.c | 105 ++++++++++++++++++++++++++++++++++-- gcc/cp/parser.h | 4 ++ gcc/testsuite/g++.dg/gomp/attrs-1.C | 12 ++--- gcc/testsuite/g++.dg/gomp/attrs-2.C | 12 ++--- gcc/testsuite/g++.dg/gomp/attrs-6.C | 50 +++++++++++++++++ gcc/testsuite/g++.dg/gomp/attrs-7.C | 64 ++++++++++++++++++++++ gcc/testsuite/g++.dg/gomp/attrs-8.C | 10 ++++ 7 files changed, 240 insertions(+), 17 deletions(-) diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index 18905cf0fbd..976e2e7ac0f 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -11901,10 +11901,9 @@ cp_parser_statement (cp_parser* parser, tree in_statement_expr, tree statement, std_attrs = NULL_TREE; cp_token *token; location_t statement_location, attrs_loc; - bool in_omp_attribute_pragma; + bool in_omp_attribute_pragma = parser->lexer->in_omp_attribute_pragma; restart: - in_omp_attribute_pragma = parser->lexer->in_omp_attribute_pragma; if (if_p != NULL) *if_p = false; /* There is no statement yet. */ @@ -11951,6 +11950,7 @@ cp_parser_statement (cp_parser* parser, tree in_statement_expr, the statement. */ cp_parser_label_for_labeled_statement (parser, std_attrs); in_compound = false; + in_omp_attribute_pragma = parser->lexer->in_omp_attribute_pragma; goto restart; case RID_IF: @@ -12034,6 +12034,7 @@ cp_parser_statement (cp_parser* parser, tree in_statement_expr, cp_parser_label_for_labeled_statement (parser, std_attrs); in_compound = false; + in_omp_attribute_pragma = parser->lexer->in_omp_attribute_pragma; goto restart; } } @@ -12058,13 +12059,28 @@ cp_parser_statement (cp_parser* parser, tree in_statement_expr, cp_parser_pragma (parser, pragma_compound, if_p); else if (!cp_parser_pragma (parser, pragma_stmt, if_p)) do_restart = true; - if (lexer->in_omp_attribute_pragma && !in_omp_attribute_pragma) + if (parser->lexer != lexer + && lexer->in_omp_attribute_pragma + && (!in_omp_attribute_pragma || lexer->orphan_p)) { - gcc_assert (parser->lexer != lexer); + if (saved_tokens.lexer == lexer) + { + if (saved_tokens.commit) + cp_lexer_commit_tokens (lexer); + gcc_assert (lexer->saved_tokens.length () == saved_tokens.len); + saved_tokens.lexer = parser->lexer; + saved_tokens.commit = false; + saved_tokens.len = parser->lexer->saved_tokens.length (); + } cp_lexer_destroy (lexer); + lexer = parser->lexer; } if (do_restart) goto restart; + if (parser->lexer == lexer + && lexer->in_omp_attribute_pragma + && !in_omp_attribute_pragma) + parser->lexer->orphan_p = true; return; } else if (token->type == CPP_EOF) @@ -40775,6 +40791,77 @@ cp_finish_omp_range_for (tree orig, tree begin) cp_finish_decomp (decl, decomp_first_name, decomp_cnt); } +/* Return true if next tokens contain a standard attribute that contains + omp::directive (DIRECTIVE). */ + +static bool +cp_parser_omp_section_scan (cp_parser *parser, const char *directive, + bool tentative) +{ + size_t n = cp_parser_skip_attributes_opt (parser, 1), i; + if (n < 10) + return false; + for (i = 5; i < n - 4; i++) + if (cp_lexer_nth_token_is (parser->lexer, i, CPP_NAME) + && cp_lexer_nth_token_is (parser->lexer, i + 1, CPP_OPEN_PAREN) + && cp_lexer_nth_token_is (parser->lexer, i + 2, CPP_NAME)) + { + tree first = cp_lexer_peek_nth_token (parser->lexer, i)->u.value; + tree second = cp_lexer_peek_nth_token (parser->lexer, i + 2)->u.value; + if (strcmp (IDENTIFIER_POINTER (first), "directive")) + continue; + if (strcmp (IDENTIFIER_POINTER (second), directive) == 0) + break; + } + if (i == n - 4) + return false; + cp_parser_parse_tentatively (parser); + location_t first_loc = cp_lexer_peek_token (parser->lexer)->location; + location_t last_loc + = cp_lexer_peek_nth_token (parser->lexer, n - 1)->location; + location_t middle_loc = UNKNOWN_LOCATION; + tree std_attrs = cp_parser_std_attribute_spec_seq (parser); + int cnt = 0; + bool seen = false; + for (tree attr = std_attrs; attr; attr = TREE_CHAIN (attr)) + if (get_attribute_namespace (attr) == omp_identifier + && is_attribute_p ("directive", get_attribute_name (attr))) + { + for (tree a = TREE_VALUE (attr); a; a = TREE_CHAIN (a)) + { + tree d = TREE_VALUE (a); + gcc_assert (TREE_CODE (d) == DEFERRED_PARSE); + cp_token *first = DEFPARSE_TOKENS (d)->first; + cnt++; + if (first->type == CPP_NAME + && strcmp (IDENTIFIER_POINTER (first->u.value), + directive) == 0) + { + seen = true; + if (middle_loc == UNKNOWN_LOCATION) + middle_loc = first->location; + } + } + } + if (!seen || tentative) + { + cp_parser_abort_tentative_parse (parser); + return seen; + } + if (cnt != 1 || TREE_CHAIN (std_attrs)) + { + error_at (make_location (first_loc, last_loc, middle_loc), + "%<[[omp::directive(%s)]]%> must be the only specified " + "attribute on a statement", directive); + cp_parser_abort_tentative_parse (parser); + return false; + } + if (!cp_parser_parse_definitely (parser)) + return false; + cp_parser_handle_statement_omp_attributes (parser, std_attrs); + return true; +} + /* OpenMP 5.0: scan-loop-body: @@ -40793,6 +40880,7 @@ cp_parser_omp_scan_loop_body (cp_parser *parser) substmt = build2 (OMP_SCAN, void_type_node, substmt, NULL_TREE); add_stmt (substmt); + cp_parser_omp_section_scan (parser, "scan", false); cp_token *tok = cp_lexer_peek_token (parser->lexer); if (cp_parser_pragma_kind (tok) == PRAGMA_OMP_SCAN) { @@ -40800,6 +40888,10 @@ cp_parser_omp_scan_loop_body (cp_parser *parser) cp_lexer_consume_token (parser->lexer); + if (parser->lexer->in_omp_attribute_pragma + && cp_lexer_next_token_is (parser->lexer, CPP_COMMA)) + cp_lexer_consume_token (parser->lexer); + if (cp_lexer_next_token_is (parser->lexer, CPP_NAME)) { tree id = cp_lexer_peek_token (parser->lexer)->u.value; @@ -41623,7 +41715,8 @@ cp_parser_omp_sections_scope (cp_parser *parser) stmt = push_stmt_list (); if (cp_parser_pragma_kind (cp_lexer_peek_token (parser->lexer)) - != PRAGMA_OMP_SECTION) + != PRAGMA_OMP_SECTION + && !cp_parser_omp_section_scan (parser, "section", true)) { substmt = cp_parser_omp_structured_block (parser, NULL, false); substmt = build1 (OMP_SECTION, void_type_node, substmt); @@ -41638,6 +41731,8 @@ cp_parser_omp_sections_scope (cp_parser *parser) if (tok->type == CPP_EOF) break; + if (cp_parser_omp_section_scan (parser, "section", false)) + tok = cp_lexer_peek_token (parser->lexer); if (cp_parser_pragma_kind (tok) == PRAGMA_OMP_SECTION) { cp_lexer_consume_token (parser->lexer); diff --git a/gcc/cp/parser.h b/gcc/cp/parser.h index 6fdd214788a..e62742db95d 100644 --- a/gcc/cp/parser.h +++ b/gcc/cp/parser.h @@ -117,6 +117,10 @@ struct GTY (()) cp_lexer { /* True if we're in the context of OpenMP directives written as C++11 attributes turned into pragma. */ bool in_omp_attribute_pragma; + + /* True for in_omp_attribute_pragma lexer that should be destroyed + when it is no longer in use. */ + bool orphan_p; }; diff --git a/gcc/testsuite/g++.dg/gomp/attrs-1.C b/gcc/testsuite/g++.dg/gomp/attrs-1.C index c2734a17c5a..6bbdcac7fba 100644 --- a/gcc/testsuite/g++.dg/gomp/attrs-1.C +++ b/gcc/testsuite/g++.dg/gomp/attrs-1.C @@ -146,17 +146,17 @@ bar (int d, int m, int i1, int i2, int i3, int p, int *idp, int s, private (p) firstprivate (f) if (parallel: i2) default(shared) shared(s) copyin(t) reduction(+:r) num_threads (nth) proc_bind(spread) lastprivate (l) allocate (f))]] { - #pragma omp section + [[omp::directive (section)]] {} - #pragma omp section + [[omp::sequence (omp::directive (section))]] {} } [[omp::directive (sections private (p) firstprivate (f) reduction(+:r) lastprivate (l) allocate (f) nowait)]] { ; - #pragma omp section + [[omp::sequence (sequence (directive (section)))]] ; - #pragma omp section + [[omp::directive (section)]] {} } [[omp::directive (barrier)]]; @@ -539,14 +539,14 @@ garply (int a, int *c, int *d, int *e, int *f) for (i = 0; i < 64; i++) { d[i] = a; - #pragma omp scan exclusive (a) + [[omp::directive (scan exclusive (a))]] a += c[i]; } [[omp::directive (simd reduction (inscan, +: a))]] for (i = 0; i < 64; i++) { a += c[i]; - #pragma omp scan inclusive (a) + [[omp::sequence (omp::sequence (omp::directive (scan inclusive (a))))]] d[i] = a; } return a; diff --git a/gcc/testsuite/g++.dg/gomp/attrs-2.C b/gcc/testsuite/g++.dg/gomp/attrs-2.C index 1eb626330c4..189dc6b1859 100644 --- a/gcc/testsuite/g++.dg/gomp/attrs-2.C +++ b/gcc/testsuite/g++.dg/gomp/attrs-2.C @@ -146,17 +146,17 @@ bar (int d, int m, int i1, int i2, int i3, int p, int *idp, int s, private (p),firstprivate (f),if (parallel: i2),default(shared),shared(s),copyin(t),reduction(+:r),num_threads (nth),proc_bind(spread), lastprivate (l),allocate (f))]] { - #pragma omp section + [[using omp:directive (section)]] {} - #pragma omp section + [[omp::sequence (omp::directive (section))]] {} } [[omp::directive (sections, private (p),firstprivate (f),reduction(+:r),lastprivate (l),allocate (f),nowait)]] { ; - #pragma omp section + [[omp::sequence (sequence (directive (section)))]] ; - #pragma omp section + [[omp::directive (section)]] {} } [[omp::directive (barrier)]]; @@ -539,14 +539,14 @@ garply (int a, int *c, int *d, int *e, int *f) for (i = 0; i < 64; i++) { d[i] = a; - #pragma omp scan exclusive (a) + [[omp::directive (scan, exclusive (a))]] a += c[i]; } [[omp::directive (simd, reduction (inscan, +: a))]] for (i = 0; i < 64; i++) { a += c[i]; - #pragma omp scan inclusive (a) + [[using omp : sequence (sequence (directive (scan inclusive (a))))]] d[i] = a; } return a; diff --git a/gcc/testsuite/g++.dg/gomp/attrs-6.C b/gcc/testsuite/g++.dg/gomp/attrs-6.C new file mode 100644 index 00000000000..30b47e1ac15 --- /dev/null +++ b/gcc/testsuite/g++.dg/gomp/attrs-6.C @@ -0,0 +1,50 @@ +// { dg-do compile { target c++11 } } + +void +foo () +{ + int a[10] = {}; + #pragma omp parallel sections + { + #pragma omp section + a[0]++; + [[omp::directive (section)]] { + a[1]++; + } [[omp::directive (section)]] + a[2]++; + #pragma omp section + { a[3]++; } + } + [[omp::directive (parallel sections)]] + { + #pragma omp section + a[0]++; + [[omp::directive (section)]] { + a[1]++; + } [[omp::directive (section)]] + a[2]++; + #pragma omp section + { a[3]++; } + } +} + +int +bar (int a, int *c, int *d, int *e, int *f) +{ + int i; + #pragma omp simd reduction (inscan, +: a) + for (i = 0; i < 64; i++) + { + d[i] = a; + [[omp::directive (scan, exclusive (a))]] + a += c[i]; + } + [[omp::directive (simd reduction (inscan, +: a))]] + for (i = 0; i < 64; i++) + { + a += c[i]; + #pragma omp scan inclusive (a) + d[i] = a; + } + return a; +} diff --git a/gcc/testsuite/g++.dg/gomp/attrs-7.C b/gcc/testsuite/g++.dg/gomp/attrs-7.C new file mode 100644 index 00000000000..598c32ae03f --- /dev/null +++ b/gcc/testsuite/g++.dg/gomp/attrs-7.C @@ -0,0 +1,64 @@ +// { dg-do compile { target c++11 } } + +void +foo () +{ + + [[omp::directive (parallel sections)]] + { + [[omp::directive (parallel)]]; + [[omp::sequence (directive (section), directive (flush))]]; // { dg-error "must be the only specified attribute on a statement" } + // { dg-error "#pragma omp section" "" { target *-*-* } .-1 } + // { dg-error "#pragma omp flush" "" { target *-*-* } .-2 } + [[omp::sequence (directive (flush), omp::directive (section))]]; // { dg-error "must be the only specified attribute on a statement" } + // { dg-error "#pragma omp section" "" { target *-*-* } .-1 } + // { dg-error "#pragma omp flush" "" { target *-*-* } .-2 } + [[gnu::cold, omp::directive (section)]]; // { dg-error "must be the only specified attribute on a statement" } + // { dg-error "#pragma omp section" "" { target *-*-* } .-1 } + [[omp::directive (section)]] [[gnu::cold]]; // { dg-error "must be the only specified attribute on a statement" } + // { dg-error "#pragma omp section" "" { target *-*-* } .-1 } + [[omp::directive (section foo)]]; // { dg-error "expected end of line before 'foo'" } + } +} + +int +bar (int a, int *c, int *d, int *e, int *f) +{ + int i; + [[omp::directive (parallel for reduction (inscan, +: a))]] // { dg-error "'a' specified in 'inscan' 'reduction' clause but not in 'scan' directive clause" } + for (i = 0; i < 64; i++) + { + d[i] = a; + [[omp::sequence (omp::directive (parallel), omp::directive (scan, exclusive (a)))]] // { dg-error "must be the only specified attribute on a statement" } + a += c[i]; // { dg-error "#pragma omp scan" "" { target *-*-* } .-1 } + } + [[omp::directive (parallel for reduction (inscan, +: a))]] // { dg-error "'a' specified in 'inscan' 'reduction' clause but not in 'scan' directive clause" } + for (i = 0; i < 64; i++) + { + a += c[i]; + [[omp::sequence (directive (scan inclusive (a)), directive (critical))]] // { dg-error "must be the only specified attribute on a statement" } + d[i] = a; // { dg-error "#pragma omp scan" "" { target *-*-* } .-1 } + } + [[omp::directive (parallel for reduction (inscan, +: a))]] // { dg-error "'a' specified in 'inscan' 'reduction' clause but not in 'scan' directive clause" } + for (i = 0; i < 64; i++) + { + d[i] = a; + [[gnu::cold]] [[omp::directive (scan, exclusive (a))]] // { dg-error "must be the only specified attribute on a statement" } + a += c[i]; // { dg-error "#pragma omp scan" "" { target *-*-* } .-1 } + } + [[omp::directive (parallel for reduction (inscan, +: a))]] // { dg-error "'a' specified in 'inscan' 'reduction' clause but not in 'scan' directive clause" } + for (i = 0; i < 64; i++) + { + d[i] = a; + [[omp::directive (scan, exclusive (a)), gnu::cold]] // { dg-error "must be the only specified attribute on a statement" } + a += c[i]; // { dg-error "#pragma omp scan" "" { target *-*-* } .-1 } + } + [[omp::directive (parallel for reduction (inscan, +: a))]] // { dg-error "'a' specified in 'inscan' 'reduction' clause but not in 'scan' directive clause" } + for (i = 0; i < 64; i++) + { + d[i] = a; + [[omp::directive (scan)]] // { dg-error "expected 'inclusive' or 'exclusive' clause before end of line" } + a += c[i]; + } + return a; +} diff --git a/gcc/testsuite/g++.dg/gomp/attrs-8.C b/gcc/testsuite/g++.dg/gomp/attrs-8.C new file mode 100644 index 00000000000..30cfe998dcf --- /dev/null +++ b/gcc/testsuite/g++.dg/gomp/attrs-8.C @@ -0,0 +1,10 @@ +// { dg-do compile { target c++11 } } + +void +foo () +{ + // Unsure if this shouldn't be invalid, whether we shouldn't require + // that each standalone directive sits on its own empty statement. + [[omp::sequence (omp::directive (barrier), omp::directive (barrier))]]; + [[omp::sequence (omp::directive (taskyield), omp::directive (taskwait))]]; +}