From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) by sourceware.org (Postfix) with ESMTP id ABAB03858007 for ; Mon, 26 Jul 2021 07:24:55 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org ABAB03858007 Received: from mimecast-mx01.redhat.com (mimecast-mx01.redhat.com [209.132.183.4]) (Using TLS) by relay.mimecast.com with ESMTP id us-mta-272-1B9SErvXMKyPZPaVNyrJew-1; Mon, 26 Jul 2021 03:24:53 -0400 X-MC-Unique: 1B9SErvXMKyPZPaVNyrJew-1 Received: from smtp.corp.redhat.com (int-mx02.intmail.prod.int.phx2.redhat.com [10.5.11.12]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx01.redhat.com (Postfix) with ESMTPS id 1D0FD106F8C0 for ; Mon, 26 Jul 2021 07:24:53 +0000 (UTC) Received: from tucnak.zalov.cz (ovpn-112-143.ams2.redhat.com [10.36.112.143]) by smtp.corp.redhat.com (Postfix) with ESMTPS id 98DAC60C0F for ; Mon, 26 Jul 2021 07:24:52 +0000 (UTC) Received: from tucnak.zalov.cz (localhost [127.0.0.1]) by tucnak.zalov.cz (8.16.1/8.16.1) with ESMTPS id 16Q7OnWC2892047 (version=TLSv1.3 cipher=TLS_AES_256_GCM_SHA384 bits=256 verify=NOT) for ; Mon, 26 Jul 2021 09:24:49 +0200 Received: (from jakub@localhost) by tucnak.zalov.cz (8.16.1/8.16.1/Submit) id 16Q7OnEb2892046 for gcc-patches@gcc.gnu.org; Mon, 26 Jul 2021 09:24:49 +0200 Date: Mon, 26 Jul 2021 09:24:48 +0200 From: Jakub Jelinek To: gcc-patches@gcc.gnu.org Subject: [committed] openmp: Add support for omp attributes section and scan directives Message-ID: <20210726072448.GS2380545@tucnak> Reply-To: Jakub Jelinek MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.79 on 10.5.11.12 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com Content-Type: text/plain; charset=us-ascii Content-Disposition: inline X-Spam-Status: No, score=-6.0 required=5.0 tests=BAYES_00, DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, RCVD_IN_DNSWL_LOW, RCVD_IN_MSPIKE_H4, RCVD_IN_MSPIKE_WL, SPF_HELO_NONE, SPF_NONE, TXREP autolearn=ham autolearn_force=no version=3.4.4 X-Spam-Checker-Version: SpamAssassin 3.4.4 (2020-01-24) on server2.sourceware.org X-BeenThere: gcc-patches@gcc.gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Gcc-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 26 Jul 2021 07:24:58 -0000 Hi! 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. Bootstrapped/regtested on x86_64-linux and i686-linux, committed to trunk. 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. --- gcc/cp/parser.h.jj 2021-07-23 09:37:23.615877596 +0200 +++ gcc/cp/parser.h 2021-07-23 19:17:58.125904410 +0200 @@ -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; }; --- gcc/cp/parser.c.jj 2021-07-23 09:37:23.619877539 +0200 +++ gcc/cp/parser.c 2021-07-23 19:31:58.739126553 +0200 @@ -11901,10 +11901,9 @@ cp_parser_statement (cp_parser* parser, 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, 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, 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, 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) - { - gcc_assert (parser->lexer != lexer); + if (parser->lexer != lexer + && lexer->in_omp_attribute_pragma + && (!in_omp_attribute_pragma || lexer->orphan_p)) + { + 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 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 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 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 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 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); --- gcc/testsuite/g++.dg/gomp/attrs-1.C.jj 2021-07-02 21:59:12.000000000 +0200 +++ gcc/testsuite/g++.dg/gomp/attrs-1.C 2021-07-23 16:08:44.127837193 +0200 @@ -146,17 +146,17 @@ bar (int d, int m, int i1, int i2, int i 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, i 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; --- gcc/testsuite/g++.dg/gomp/attrs-2.C.jj 2021-07-02 21:59:12.360171614 +0200 +++ gcc/testsuite/g++.dg/gomp/attrs-2.C 2021-07-23 16:22:33.067502407 +0200 @@ -146,17 +146,17 @@ bar (int d, int m, int i1, int i2, int i 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, i 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; --- gcc/testsuite/g++.dg/gomp/attrs-6.C.jj 2021-07-23 16:32:01.317725952 +0200 +++ gcc/testsuite/g++.dg/gomp/attrs-6.C 2021-07-23 16:31:56.084797574 +0200 @@ -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; +} --- gcc/testsuite/g++.dg/gomp/attrs-7.C.jj 2021-07-23 16:35:59.784462163 +0200 +++ gcc/testsuite/g++.dg/gomp/attrs-7.C 2021-07-23 19:45:29.817340912 +0200 @@ -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; +} --- gcc/testsuite/g++.dg/gomp/attrs-8.C.jj 2021-07-23 17:43:03.524318758 +0200 +++ gcc/testsuite/g++.dg/gomp/attrs-8.C 2021-07-23 17:44:13.698356914 +0200 @@ -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))]]; +} Jakub