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.129.124]) by sourceware.org (Postfix) with ESMTPS id 655C73858418 for ; Sat, 3 Sep 2022 10:50:21 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org 655C73858418 Authentication-Results: sourceware.org; dmarc=pass (p=none dis=none) header.from=redhat.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=redhat.com DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1662202220; h=from:from:reply-to:reply-to:subject:subject:date:date: message-id:message-id:to:to:cc:cc:mime-version:mime-version: content-type:content-type:resent-to:resent-from:resent-message-id; bh=Pxbb9js6R7Gge2IDhWC4sSmrzVBS1rnRORb14LTU5+I=; b=ZPDdAruhYdcZjXLW2fLtXrvv0nZpl4RsDqCfhghuMw+F4+weeHXyQ/ypamd0sAbvy2PmkM TIRU2Zsku8fbFHbUSMDElN+j8SwpuRehVhHauwgdAna4oWIXxBa3A+tcGoxFid1yT55kdp fJg0Bu3qG8x3InbAJM44WxQvnd2Vhg4= Received: from mimecast-mx02.redhat.com (mimecast-mx02.redhat.com [66.187.233.88]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id us-mta-347-EtZIsbPuMoKgNI3zj9Nr4g-1; Sat, 03 Sep 2022 06:50:19 -0400 X-MC-Unique: EtZIsbPuMoKgNI3zj9Nr4g-1 Received: from smtp.corp.redhat.com (int-mx01.intmail.prod.int.rdu2.redhat.com [10.11.54.1]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id 31151805AF5; Sat, 3 Sep 2022 10:50:19 +0000 (UTC) Received: from tucnak.zalov.cz (unknown [10.39.192.41]) by smtp.corp.redhat.com (Postfix) with ESMTPS id 5579140CF8E8; Sat, 3 Sep 2022 10:50:18 +0000 (UTC) Received: from tucnak.zalov.cz (localhost [127.0.0.1]) by tucnak.zalov.cz (8.17.1/8.17.1) with ESMTPS id 283AoF8n654468 (version=TLSv1.3 cipher=TLS_AES_256_GCM_SHA384 bits=256 verify=NOT); Sat, 3 Sep 2022 12:50:15 +0200 Received: (from jakub@localhost) by tucnak.zalov.cz (8.17.1/8.17.1/Submit) id 283AoEuZ654467; Sat, 3 Sep 2022 12:50:14 +0200 Resent-From: Jakub Jelinek Resent-Date: Sat, 3 Sep 2022 12:50:14 +0200 Resent-Message-ID: Resent-To: gcc-patches@gcc.gnu.org, Tobias Burnus Date: Sat, 3 Sep 2022 10:07:27 +0200 From: Jakub Jelinek To: gcc-patches@gcc.gnu.org Cc: Tobias Burnus Subject: [committed] openmp: Partial OpenMP 5.2 doacross and omp_cur_iteration support Message-ID: Reply-To: Jakub Jelinek MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.84 on 10.11.54.1 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=-4.0 required=5.0 tests=BAYES_00,DKIMWL_WL_HIGH,DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,RCVD_IN_DNSWL_LOW,SPF_HELO_NONE,SPF_NONE,TXREP,T_SCC_BODY_TEXT_LINE autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org List-Id: Hi! The following patch implements part of the OpenMP 5.2 changes related to ordered loops and with the assumed resolution of https://github.com/OpenMP/spec/issues/3302 issues. The changes are: 1) the depend clause on stand-alone ordered constructs has been renamed to doacross (because depend clause has different syntax on other constructs) with some syntax changes below, depend clause is deprecated (we'll deprecate stuff on the GCC side only when we have everything else from 5.2 implemented) depend(source) -> doacross(source:) or doacross(source:omp_cur_iteration) depend(sink:vec) -> doacross(sink:vec) (where vec has the same syntax as before) 2) in 5.1 and before it has been significant whether ordered clause has or doesn't have an argument, if it didn't, only block-associated ordered could appear in the body, if it did, only stand-alone ordered could appear in the body, all loops had to be perfectly nested, no associated range-based for loops, no linear clause on work-sharing loop and ordered clause with an argument wasn't allowed on composite for simd. In 5.2, whether ordered clause has or doesn't have an argument is insignificant (except for bugs in the standard, #3302 mentions those), if the argument is missing, it is simply treated as equal to collapse argument (if any, otherwise 1). The implementation better should be able to differentiate between ordered and doacross loops at compile time which previously was through the absence or presence of the argument, now it is done through looking at the body of the construct lexically and looking for stand-alone ordered constructs. If there are any, it is to be handled as doacross loop, otherwise it is ordered loop (but in that case ordered argument if present must be equal to collapse argument - 5.2 says instead it must be one, but that is clearly wrong and mentioned in #3302) - stand-alone ordered constructs must appear lexically in the body (and had to before as well). For the restrictions mentioned above, the for simd restriction is gone (stand-alone ordered can't appear in simd construct, so that is enough), and the other rules are expected to be changed into something related to presence of stand-alone ordered constructs in the body 3) 5.2 allows a new syntax, doacross(sink:omp_cur_iteration-1), which means wait for previous iteration in the iteration space of all the associated loops The following patch implements that, except that we sorry for now on the doacross(sink:omp_cur_iteration-1) syntax during omp expansion because library side isn't done yet for it. It doesn't implement it for the Fortran FE either. Incrementally, I'd like to change the way we differentiate between stand-alone and block-associated ordered constructs, because the current way of looking for presence of doacross clause doesn't work well if those clauses are removed because they had been invalid (wrong syntax or unknown variables in it etc.) and of course implement doacross(sink:omp_cur_iteration-1). Bootstrapped/regtested on x86_64-linux and i686-linux, committed to trunk. 2022-09-03 Jakub Jelinek gcc/ * tree-core.h (enum omp_clause_code): Add OMP_CLAUSE_DOACROSS. (enum omp_clause_depend_kind): Remove OMP_CLAUSE_DEPEND_SOURCE and OMP_CLAUSE_DEPEND_SINK, add OMP_CLAUSE_DEPEND_INVALID. (enum omp_clause_doacross_kind): New type. (struct tree_omp_clause): Add subcode.doacross_kind member. * tree.h (OMP_CLAUSE_DEPEND_SINK_NEGATIVE): Remove. (OMP_CLAUSE_DOACROSS_KIND): Define. (OMP_CLAUSE_DOACROSS_SINK_NEGATIVE): Define. (OMP_CLAUSE_DOACROSS_DEPEND): Define. (OMP_CLAUSE_ORDERED_DOACROSS): Define. * tree.cc (omp_clause_num_ops, omp_clause_code_name): Add OMP_CLAUSE_DOACROSS entries. * tree-nested.cc (convert_nonlocal_omp_clauses, convert_local_omp_clauses): Handle OMP_CLAUSE_DOACROSS. * tree-pretty-print.cc (dump_omp_clause): Don't handle OMP_CLAUSE_DEPEND_SOURCE and OMP_CLAUSE_DEPEND_SINK. Handle OMP_CLAUSE_DOACROSS. * gimplify.cc (gimplify_omp_depend): Don't handle OMP_CLAUSE_DEPEND_SOURCE and OMP_CLAUSE_DEPEND_SINK. (gimplify_scan_omp_clauses): Likewise. Handle OMP_CLAUSE_DOACROSS. (gimplify_adjust_omp_clauses): Handle OMP_CLAUSE_DOACROSS. (find_standalone_omp_ordered): New function. (gimplify_omp_for): When OMP_CLAUSE_ORDERED is present, search body for OMP_ORDERED with OMP_CLAUSE_DOACROSS and if found, set OMP_CLAUSE_ORDERED_DOACROSS. (gimplify_omp_ordered): Don't handle OMP_CLAUSE_DEPEND_SINK or OMP_CLAUSE_DEPEND_SOURCE, instead check OMP_CLAUSE_DOACROSS, adjust diagnostics that presence or absence of ordered clause parameter is irrelevant. Handle doacross(sink:omp_cur_iteration-1). Use actual user name of the clause - doacross or depend - in diagnostics. * omp-general.cc (omp_extract_for_data): Don't set fd->ordered if !OMP_CLAUSE_ORDERED_DOACROSS (t). If OMP_CLAUSE_ORDERED_DOACROSS (t) but !OMP_CLAUSE_ORDERED_EXPR (t), set fd->ordered to -1 and set it after the loop in that case to fd->collapse. * omp-low.cc (check_omp_nesting_restrictions): Don't handle OMP_CLAUSE_DEPEND_SOURCE nor OMP_CLAUSE_DEPEND_SINK, instead check OMP_CLAUSE_DOACROSS. Use actual user name of the clause - doacross or depend - in diagnostics. Diagnose mixing of stand-alone and block associated ordered constructs binding to the same loop. (lower_omp_ordered_clauses): Don't handle OMP_CLAUSE_DEPEND_SINK, instead handle OMP_CLAUSE_DOACROSS. (lower_omp_ordered): Look for OMP_CLAUSE_DOACROSS instead of OMP_CLAUSE_DEPEND. (lower_depend_clauses): Don't handle OMP_CLAUSE_DEPEND_SOURCE and OMP_CLAUSE_DEPEND_SINK. * omp-expand.cc (expand_omp_ordered_sink): Emit a sorry for doacross(sink:omp_cur_iteration-1). (expand_omp_ordered_source_sink): Use OMP_CLAUSE_DOACROSS_SINK_NEGATIVE instead of OMP_CLAUSE_DEPEND_SINK_NEGATIVE. Use actual user name of the clause - doacross or depend - in diagnostics. (expand_omp): Look for OMP_CLAUSE_DOACROSS clause instead of OMP_CLAUSE_DEPEND. (build_omp_regions_1): Likewise. (omp_make_gimple_edges): Likewise. * lto-streamer-out.cc (hash_tree): Handle OMP_CLAUSE_DOACROSS. * tree-streamer-in.cc (unpack_ts_omp_clause_value_fields): Likewise. * tree-streamer-out.cc (pack_ts_omp_clause_value_fields): Likewise. gcc/c-family/ * c-pragma.h (enum pragma_omp_clause): Add PRAGMA_OMP_CLAUSE_DOACROSS. * c-omp.cc (c_finish_omp_depobj): Check also for OMP_CLAUSE_DOACROSS clause and diagnose it. Don't handle OMP_CLAUSE_DEPEND_SOURCE and OMP_CLAUSE_DEPEND_SINK. Assert kind is not OMP_CLAUSE_DEPEND_INVALID. gcc/c/ * c-parser.cc (c_parser_omp_clause_name): Handle doacross. (c_parser_omp_clause_depend_sink): Renamed to ... (c_parser_omp_clause_doacross_sink): ... this. Add depend_p argument. Handle parsing of doacross(sink:omp_cur_iteration-1). Use OMP_CLAUSE_DOACROSS_SINK_NEGATIVE instead of OMP_CLAUSE_DEPEND_SINK_NEGATIVE, build OMP_CLAUSE_DOACROSS instead of OMP_CLAUSE_DEPEND and set OMP_CLAUSE_DOACROSS_DEPEND flag on it. (c_parser_omp_clause_depend): Use OMP_CLAUSE_DOACROSS_SINK and OMP_CLAUSE_DOACROSS_SOURCE instead of OMP_CLAUSE_DEPEND_SINK and OMP_CLAUSE_DEPEND_SOURCE, build OMP_CLAUSE_DOACROSS for depend(source) and set OMP_CLAUSE_DOACROSS_DEPEND on it. (c_parser_omp_clause_doacross): New function. (c_parser_omp_all_clauses): Handle PRAGMA_OMP_CLAUSE_DOACROSS. (c_parser_omp_depobj): Use OMP_CLAUSE_DEPEND_INVALID instead of OMP_CLAUSE_DEPEND_SOURCE. (c_parser_omp_for_loop): Don't diagnose here linear clause together with ordered with argument. (c_parser_omp_simd): Don't diagnose ordered clause with argument on for simd. (OMP_ORDERED_DEPEND_CLAUSE_MASK): Add PRAGMA_OMP_CLAUSE_DOACROSS. (c_parser_omp_ordered): Handle also doacross and adjust for it diagnostic wording. * c-typeck.cc (c_finish_omp_clauses): Handle OMP_CLAUSE_DOACROSS. Don't handle OMP_CLAUSE_DEPEND_SOURCE and OMP_CLAUSE_DEPEND_SINK. gcc/cp/ * parser.cc (cp_parser_omp_clause_name): Handle doacross. (cp_parser_omp_clause_depend_sink): Renamed to ... (cp_parser_omp_clause_doacross_sink): ... this. Add depend_p argument. Handle parsing of doacross(sink:omp_cur_iteration-1). Use OMP_CLAUSE_DOACROSS_SINK_NEGATIVE instead of OMP_CLAUSE_DEPEND_SINK_NEGATIVE, build OMP_CLAUSE_DOACROSS instead of OMP_CLAUSE_DEPEND and set OMP_CLAUSE_DOACROSS_DEPEND flag on it. (cp_parser_omp_clause_depend): Use OMP_CLAUSE_DOACROSS_SINK and OMP_CLAUSE_DOACROSS_SOURCE instead of OMP_CLAUSE_DEPEND_SINK and OMP_CLAUSE_DEPEND_SOURCE, build OMP_CLAUSE_DOACROSS for depend(source) and set OMP_CLAUSE_DOACROSS_DEPEND on it. (cp_parser_omp_clause_doacross): New function. (cp_parser_omp_all_clauses): Handle PRAGMA_OMP_CLAUSE_DOACROSS. (cp_parser_omp_depobj): Use OMP_CLAUSE_DEPEND_INVALID instead of OMP_CLAUSE_DEPEND_SOURCE. (cp_parser_omp_for_loop): Don't diagnose here linear clause together with ordered with argument. (cp_parser_omp_simd): Don't diagnose ordered clause with argument on for simd. (OMP_ORDERED_DEPEND_CLAUSE_MASK): Add PRAGMA_OMP_CLAUSE_DOACROSS. (cp_parser_omp_ordered): Handle also doacross and adjust for it diagnostic wording. * pt.cc (tsubst_omp_clause_decl): Use OMP_CLAUSE_DOACROSS_SINK_NEGATIVE instead of OMP_CLAUSE_DEPEND_SINK_NEGATIVE. (tsubst_omp_clauses): Handle OMP_CLAUSE_DOACROSS. (tsubst_expr): Use OMP_CLAUSE_DEPEND_INVALID instead of OMP_CLAUSE_DEPEND_SOURCE. * semantics.cc (cp_finish_omp_clause_depend_sink): Rename to ... (cp_finish_omp_clause_doacross_sink): ... this. (finish_omp_clauses): Handle OMP_CLAUSE_DOACROSS. Don't handle OMP_CLAUSE_DEPEND_SOURCE and OMP_CLAUSE_DEPEND_SINK. gcc/fortran/ * trans-openmp.cc (gfc_trans_omp_clauses): Use OMP_CLAUSE_DOACROSS_SINK_NEGATIVE instead of OMP_CLAUSE_DEPEND_SINK_NEGATIVE, build OMP_CLAUSE_DOACROSS clause instead of OMP_CLAUSE_DEPEND and set OMP_CLAUSE_DOACROSS_DEPEND on it. gcc/testsuite/ * c-c++-common/gomp/doacross-2.c: Adjust expected diagnostics. * c-c++-common/gomp/doacross-5.c: New test. * c-c++-common/gomp/doacross-6.c: New test. * c-c++-common/gomp/nesting-2.c: Adjust expected diagnostics. * c-c++-common/gomp/ordered-3.c: Likewise. * c-c++-common/gomp/sink-3.c: Likewise. * gfortran.dg/gomp/nesting-2.f90: Likewise. --- gcc/tree-core.h.jj 2022-08-30 12:29:00.055159930 +0200 +++ gcc/tree-core.h 2022-09-01 17:05:21.271096253 +0200 @@ -345,6 +345,9 @@ enum omp_clause_code { /* OpenMP clause: has_device_addr (variable-list). */ OMP_CLAUSE_HAS_DEVICE_ADDR, + /* OpenMP clause: doacross ({source,sink}:vec). */ + OMP_CLAUSE_DOACROSS, + /* Internal structure to hold OpenACC cache directive's variable-list. #pragma acc cache (variable-list). */ OMP_CLAUSE__CACHE_, @@ -1525,12 +1527,18 @@ enum omp_clause_depend_kind OMP_CLAUSE_DEPEND_INOUT, OMP_CLAUSE_DEPEND_MUTEXINOUTSET, OMP_CLAUSE_DEPEND_INOUTSET, - OMP_CLAUSE_DEPEND_SOURCE, - OMP_CLAUSE_DEPEND_SINK, OMP_CLAUSE_DEPEND_DEPOBJ, + OMP_CLAUSE_DEPEND_INVALID, OMP_CLAUSE_DEPEND_LAST }; +enum omp_clause_doacross_kind +{ + OMP_CLAUSE_DOACROSS_SOURCE, + OMP_CLAUSE_DOACROSS_SINK, + OMP_CLAUSE_DOACROSS_LAST +}; + enum omp_clause_proc_bind_kind { /* Numbers should match omp_proc_bind_t enum in omp.h. */ @@ -1620,6 +1628,7 @@ struct GTY(()) tree_omp_clause { enum omp_clause_default_kind default_kind; enum omp_clause_schedule_kind schedule_kind; enum omp_clause_depend_kind depend_kind; + enum omp_clause_doacross_kind doacross_kind; /* See include/gomp-constants.h for enum gomp_map_kind's values. */ unsigned int map_kind; enum omp_clause_proc_bind_kind proc_bind_kind; --- gcc/tree.h.jj 2022-08-30 12:29:00.109159197 +0200 +++ gcc/tree.h 2022-09-02 16:25:55.137047019 +0200 @@ -1722,9 +1722,16 @@ class auto_suppress_location_wrappers #define OMP_CLAUSE_DEPEND_KIND(NODE) \ (OMP_CLAUSE_SUBCODE_CHECK (NODE, OMP_CLAUSE_DEPEND)->omp_clause.subcode.depend_kind) -#define OMP_CLAUSE_DEPEND_SINK_NEGATIVE(NODE) \ +#define OMP_CLAUSE_DOACROSS_KIND(NODE) \ + (OMP_CLAUSE_SUBCODE_CHECK (NODE, OMP_CLAUSE_DOACROSS)->omp_clause.subcode.doacross_kind) + +#define OMP_CLAUSE_DOACROSS_SINK_NEGATIVE(NODE) \ TREE_PUBLIC (TREE_LIST_CHECK (NODE)) +/* True if DOACROSS clause is spelled as DEPEND. */ +#define OMP_CLAUSE_DOACROSS_DEPEND(NODE) \ + TREE_PROTECTED (OMP_CLAUSE_SUBCODE_CHECK (NODE, OMP_CLAUSE_DOACROSS)) + #define OMP_CLAUSE_MAP_KIND(NODE) \ ((enum gomp_map_kind) OMP_CLAUSE_SUBCODE_CHECK (NODE, OMP_CLAUSE_MAP)->omp_clause.subcode.map_kind) #define OMP_CLAUSE_SET_MAP_KIND(NODE, MAP_KIND) \ @@ -1786,6 +1793,11 @@ class auto_suppress_location_wrappers #define OMP_CLAUSE_ORDERED_EXPR(NODE) \ OMP_CLAUSE_OPERAND (OMP_CLAUSE_SUBCODE_CHECK (NODE, OMP_CLAUSE_ORDERED), 0) +/* True on an OMP_CLAUSE_ORDERED if stand-alone ordered construct is nested + inside of work-sharing loop the clause is on. */ +#define OMP_CLAUSE_ORDERED_DOACROSS(NODE) \ + (OMP_CLAUSE_SUBCODE_CHECK (NODE, OMP_CLAUSE_ORDERED)->base.public_flag) + /* True for unconstrained modifier on order(concurrent) clause. */ #define OMP_CLAUSE_ORDER_UNCONSTRAINED(NODE) \ (OMP_CLAUSE_SUBCODE_CHECK (NODE, OMP_CLAUSE_ORDER)->base.public_flag) --- gcc/tree.cc.jj 2022-08-26 09:18:25.403152829 +0200 +++ gcc/tree.cc 2022-09-01 17:06:13.675388950 +0200 @@ -294,6 +294,7 @@ unsigned const char omp_clause_num_ops[] 2, /* OMP_CLAUSE_TO */ 2, /* OMP_CLAUSE_MAP */ 1, /* OMP_CLAUSE_HAS_DEVICE_ADDR */ + 1, /* OMP_CLAUSE_DOACROSS */ 2, /* OMP_CLAUSE__CACHE_ */ 2, /* OMP_CLAUSE_GANG */ 1, /* OMP_CLAUSE_ASYNC */ @@ -384,6 +385,7 @@ const char * const omp_clause_code_name[ "to", "map", "has_device_addr", + "doacross", "_cache_", "gang", "async", --- gcc/tree-nested.cc.jj 2022-05-27 12:48:40.468486805 +0200 +++ gcc/tree-nested.cc 2022-09-01 16:33:36.866753040 +0200 @@ -1368,6 +1368,7 @@ convert_nonlocal_omp_clauses (tree *pcla case OMP_CLAUSE_IF: case OMP_CLAUSE_NUM_THREADS: case OMP_CLAUSE_DEPEND: + case OMP_CLAUSE_DOACROSS: case OMP_CLAUSE_DEVICE: case OMP_CLAUSE_NUM_TEAMS: case OMP_CLAUSE_THREAD_LIMIT: @@ -2157,6 +2158,7 @@ convert_local_omp_clauses (tree *pclause case OMP_CLAUSE_IF: case OMP_CLAUSE_NUM_THREADS: case OMP_CLAUSE_DEPEND: + case OMP_CLAUSE_DOACROSS: case OMP_CLAUSE_DEVICE: case OMP_CLAUSE_NUM_TEAMS: case OMP_CLAUSE_THREAD_LIMIT: --- gcc/tree-pretty-print.cc.jj 2022-08-30 12:29:00.073159685 +0200 +++ gcc/tree-pretty-print.cc 2022-09-02 10:18:32.740423679 +0200 @@ -831,34 +831,9 @@ dump_omp_clause (pretty_printer *pp, tre case OMP_CLAUSE_DEPEND_INOUTSET: name = "inoutset"; break; - case OMP_CLAUSE_DEPEND_SOURCE: - pp_string (pp, "source)"); - return; case OMP_CLAUSE_DEPEND_LAST: name = "__internal__"; break; - case OMP_CLAUSE_DEPEND_SINK: - pp_string (pp, "sink:"); - for (tree t = OMP_CLAUSE_DECL (clause); t; t = TREE_CHAIN (t)) - if (TREE_CODE (t) == TREE_LIST) - { - dump_generic_node (pp, TREE_VALUE (t), spc, flags, false); - if (TREE_PURPOSE (t) != integer_zero_node) - { - if (OMP_CLAUSE_DEPEND_SINK_NEGATIVE (t)) - pp_minus (pp); - else - pp_plus (pp); - dump_generic_node (pp, TREE_PURPOSE (t), spc, flags, - false); - } - if (TREE_CHAIN (t)) - pp_comma (pp); - } - else - gcc_unreachable (); - pp_right_paren (pp); - return; default: gcc_unreachable (); } @@ -885,6 +860,49 @@ dump_omp_clause (pretty_printer *pp, tre } break; + case OMP_CLAUSE_DOACROSS: + pp_string (pp, OMP_CLAUSE_DOACROSS_DEPEND (clause) + ? "depend(" : "doacross("); + switch (OMP_CLAUSE_DOACROSS_KIND (clause)) + { + case OMP_CLAUSE_DOACROSS_SOURCE: + if (OMP_CLAUSE_DOACROSS_DEPEND (clause)) + pp_string (pp, "source)"); + else + pp_string (pp, "source:)"); + break; + case OMP_CLAUSE_DOACROSS_SINK: + pp_string (pp, "sink:"); + if (OMP_CLAUSE_DECL (clause) == NULL_TREE) + { + pp_string (pp, "omp_cur_iteration-1)"); + break; + } + for (tree t = OMP_CLAUSE_DECL (clause); t; t = TREE_CHAIN (t)) + if (TREE_CODE (t) == TREE_LIST) + { + dump_generic_node (pp, TREE_VALUE (t), spc, flags, false); + if (TREE_PURPOSE (t) != integer_zero_node) + { + if (OMP_CLAUSE_DOACROSS_SINK_NEGATIVE (t)) + pp_minus (pp); + else + pp_plus (pp); + dump_generic_node (pp, TREE_PURPOSE (t), spc, flags, + false); + } + if (TREE_CHAIN (t)) + pp_comma (pp); + } + else + gcc_unreachable (); + pp_right_paren (pp); + break; + default: + gcc_unreachable (); + } + break; + case OMP_CLAUSE_MAP: pp_string (pp, "map("); switch (OMP_CLAUSE_MAP_KIND (clause)) --- gcc/gimplify.cc.jj 2022-08-30 12:28:59.986160866 +0200 +++ gcc/gimplify.cc 2022-09-02 16:45:27.083153954 +0200 @@ -8319,9 +8319,6 @@ gimplify_omp_depend (tree *list_p, gimpl case OMP_CLAUSE_DEPEND_INOUTSET: i = 4; break; - case OMP_CLAUSE_DEPEND_SOURCE: - case OMP_CLAUSE_DEPEND_SINK: - continue; default: gcc_unreachable (); } @@ -8560,9 +8557,6 @@ gimplify_omp_depend (tree *list_p, gimpl case OMP_CLAUSE_DEPEND_INOUTSET: i = 4; break; - case OMP_CLAUSE_DEPEND_SOURCE: - case OMP_CLAUSE_DEPEND_SINK: - continue; default: gcc_unreachable (); } @@ -10406,8 +10400,8 @@ gimplify_scan_omp_clauses (tree *list_p, gimplify_omp_affinity (list_p, pre_p); remove = true; break; - case OMP_CLAUSE_DEPEND: - if (OMP_CLAUSE_DEPEND_KIND (c) == OMP_CLAUSE_DEPEND_SINK) + case OMP_CLAUSE_DOACROSS: + if (OMP_CLAUSE_DOACROSS_KIND (c) == OMP_CLAUSE_DOACROSS_SINK) { tree deps = OMP_CLAUSE_DECL (c); while (deps && TREE_CODE (deps) == TREE_LIST) @@ -10418,10 +10412,12 @@ gimplify_scan_omp_clauses (tree *list_p, pre_p, NULL, is_gimple_val, fb_rvalue); deps = TREE_CHAIN (deps); } - break; } - else if (OMP_CLAUSE_DEPEND_KIND (c) == OMP_CLAUSE_DEPEND_SOURCE) - break; + else + gcc_assert (OMP_CLAUSE_DOACROSS_KIND (c) + == OMP_CLAUSE_DOACROSS_SOURCE); + break; + case OMP_CLAUSE_DEPEND: if (handled_depend_iterators == -1) handled_depend_iterators = gimplify_omp_depend (list_p, pre_p); if (handled_depend_iterators) @@ -11946,6 +11942,7 @@ gimplify_adjust_omp_clauses (gimple_seq case OMP_CLAUSE_SAFELEN: case OMP_CLAUSE_SIMDLEN: case OMP_CLAUSE_DEPEND: + case OMP_CLAUSE_DOACROSS: case OMP_CLAUSE_PRIORITY: case OMP_CLAUSE_GRAINSIZE: case OMP_CLAUSE_NUM_TASKS: @@ -12429,6 +12426,29 @@ gimplify_omp_taskloop_expr (tree type, t OMP_FOR_CLAUSES (orig_for_stmt) = c; } +/* Helper function of gimplify_omp_for, find OMP_ORDERED with + OMP_CLAUSE_DOACROSS clause inside of OMP_FOR's body. */ + +static tree +find_standalone_omp_ordered (tree *tp, int *walk_subtrees, void *) +{ + switch (TREE_CODE (*tp)) + { + case OMP_ORDERED: + if (omp_find_clause (OMP_ORDERED_CLAUSES (*tp), OMP_CLAUSE_DOACROSS)) + return *tp; + break; + case OMP_SIMD: + case OMP_PARALLEL: + case OMP_TARGET: + *walk_subtrees = 0; + break; + default: + break; + } + return NULL_TREE; +} + /* Gimplify the gross structure of an OMP_FOR statement. */ static enum gimplify_status @@ -12804,12 +12824,24 @@ gimplify_omp_for (tree *expr_p, gimple_s tree c = omp_find_clause (OMP_FOR_CLAUSES (for_stmt), OMP_CLAUSE_ORDERED); bool is_doacross = false; - if (c && OMP_CLAUSE_ORDERED_EXPR (c)) + if (c && walk_tree_without_duplicates (&OMP_FOR_BODY (for_stmt), + find_standalone_omp_ordered, NULL)) { + OMP_CLAUSE_ORDERED_DOACROSS (c) = 1; is_doacross = true; - gimplify_omp_ctxp->loop_iter_var.create (TREE_VEC_LENGTH - (OMP_FOR_INIT (for_stmt)) - * 2); + int len = TREE_VEC_LENGTH (OMP_FOR_INIT (for_stmt)); + gimplify_omp_ctxp->loop_iter_var.create (len * 2); + for (tree *pc = &OMP_FOR_CLAUSES (for_stmt); *pc; ) + if (OMP_CLAUSE_CODE (*pc) == OMP_CLAUSE_LINEAR) + { + error_at (OMP_CLAUSE_LOCATION (*pc), + "% clause may not be specified together " + "with % clause if stand-alone % " + "construct is nested in it"); + *pc = OMP_CLAUSE_CHAIN (*pc); + } + else + pc = &OMP_CLAUSE_CHAIN (*pc); } int collapse = 1, tile = 0; c = omp_find_clause (OMP_FOR_CLAUSES (for_stmt), OMP_CLAUSE_COLLAPSE); @@ -14882,21 +14914,22 @@ gimplify_omp_ordered (tree expr, gimple_ if (gimplify_omp_ctxp) { for (c = OMP_ORDERED_CLAUSES (expr); c; c = OMP_CLAUSE_CHAIN (c)) - if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_DEPEND - && gimplify_omp_ctxp->loop_iter_var.is_empty () - && (OMP_CLAUSE_DEPEND_KIND (c) == OMP_CLAUSE_DEPEND_SINK - || OMP_CLAUSE_DEPEND_KIND (c) == OMP_CLAUSE_DEPEND_SOURCE)) + if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_DOACROSS + && gimplify_omp_ctxp->loop_iter_var.is_empty ()) { error_at (OMP_CLAUSE_LOCATION (c), - "% construct with % clause must be " - "closely nested inside a loop with % clause " - "with a parameter"); + "% construct with %qs clause must be " + "closely nested inside a loop with % clause", + OMP_CLAUSE_DOACROSS_DEPEND (c) ? "depend" : "doacross"); failures++; } - else if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_DEPEND - && OMP_CLAUSE_DEPEND_KIND (c) == OMP_CLAUSE_DEPEND_SINK) + else if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_DOACROSS + && OMP_CLAUSE_DOACROSS_KIND (c) == OMP_CLAUSE_DOACROSS_SINK) { bool fail = false; + sink_c = c; + if (OMP_CLAUSE_DECL (c) == NULL_TREE) + continue; /* omp_cur_iteration - 1 */ for (decls = OMP_CLAUSE_DECL (c), i = 0; decls && TREE_CODE (decls) == TREE_LIST; decls = TREE_CHAIN (decls), ++i) @@ -14919,21 +14952,24 @@ gimplify_omp_ordered (tree expr, gimple_ if (!fail && i != gimplify_omp_ctxp->loop_iter_var.length () / 2) { error_at (OMP_CLAUSE_LOCATION (c), - "number of variables in % clause with " + "number of variables in %qs clause with " "% modifier does not match number of " - "iteration variables"); + "iteration variables", + OMP_CLAUSE_DOACROSS_DEPEND (c) + ? "depend" : "doacross"); failures++; } - sink_c = c; } - else if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_DEPEND - && OMP_CLAUSE_DEPEND_KIND (c) == OMP_CLAUSE_DEPEND_SOURCE) + else if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_DOACROSS + && OMP_CLAUSE_DOACROSS_KIND (c) == OMP_CLAUSE_DOACROSS_SOURCE) { if (source_c) { error_at (OMP_CLAUSE_LOCATION (c), - "more than one % clause with % " - "modifier on an % construct"); + "more than one %qs clause with % " + "modifier on an % construct", + OMP_CLAUSE_DOACROSS_DEPEND (source_c) + ? "depend" : "doacross"); failures++; } else @@ -14943,9 +14979,11 @@ gimplify_omp_ordered (tree expr, gimple_ if (source_c && sink_c) { error_at (OMP_CLAUSE_LOCATION (source_c), - "% clause with % modifier specified " - "together with % clauses with % modifier " - "on the same construct"); + "%qs clause with % modifier specified " + "together with %qs clauses with % modifier " + "on the same construct", + OMP_CLAUSE_DOACROSS_DEPEND (source_c) ? "depend" : "doacross", + OMP_CLAUSE_DOACROSS_DEPEND (sink_c) ? "depend" : "doacross"); failures++; } --- gcc/omp-general.cc.jj 2022-08-17 16:59:09.128546118 +0200 +++ gcc/omp-general.cc 2022-09-02 17:14:13.064761612 +0200 @@ -241,8 +241,13 @@ omp_extract_for_data (gomp_for *for_stmt break; case OMP_CLAUSE_ORDERED: fd->have_ordered = true; - if (OMP_CLAUSE_ORDERED_EXPR (t)) - fd->ordered = tree_to_shwi (OMP_CLAUSE_ORDERED_EXPR (t)); + if (OMP_CLAUSE_ORDERED_DOACROSS (t)) + { + if (OMP_CLAUSE_ORDERED_EXPR (t)) + fd->ordered = tree_to_shwi (OMP_CLAUSE_ORDERED_EXPR (t)); + else + fd->ordered = -1; + } break; case OMP_CLAUSE_SCHEDULE: gcc_assert (!distribute && !taskloop); @@ -301,6 +306,9 @@ omp_extract_for_data (gomp_for *for_stmt break; } + if (fd->ordered == -1) + fd->ordered = fd->collapse; + /* For order(reproducible:concurrent) schedule ({dynamic,guided,runtime}) we have either the option to expensively remember at runtime how we've distributed work from first loop and reuse that in following loops with --- gcc/omp-low.cc.jj 2022-08-30 12:29:00.039160147 +0200 +++ gcc/omp-low.cc 2022-09-02 18:33:16.041450721 +0200 @@ -3636,14 +3636,13 @@ check_omp_nesting_restrictions (gimple * break; case GIMPLE_OMP_TASK: for (c = gimple_omp_task_clauses (stmt); c; c = OMP_CLAUSE_CHAIN (c)) - if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_DEPEND - && (OMP_CLAUSE_DEPEND_KIND (c) == OMP_CLAUSE_DEPEND_SOURCE - || OMP_CLAUSE_DEPEND_KIND (c) == OMP_CLAUSE_DEPEND_SINK)) + if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_DOACROSS) { - enum omp_clause_depend_kind kind = OMP_CLAUSE_DEPEND_KIND (c); + enum omp_clause_doacross_kind kind = OMP_CLAUSE_DOACROSS_KIND (c); error_at (OMP_CLAUSE_LOCATION (c), - "% is only allowed in %", - kind == OMP_CLAUSE_DEPEND_SOURCE ? "source" : "sink"); + "%<%s(%s)%> is only allowed in %", + OMP_CLAUSE_DOACROSS_DEPEND (c) ? "depend" : "doacross", + kind == OMP_CLAUSE_DOACROSS_SOURCE ? "source" : "sink"); return false; } break; @@ -3651,43 +3650,30 @@ check_omp_nesting_restrictions (gimple * for (c = gimple_omp_ordered_clauses (as_a (stmt)); c; c = OMP_CLAUSE_CHAIN (c)) { - if (OMP_CLAUSE_CODE (c) != OMP_CLAUSE_DEPEND) + if (OMP_CLAUSE_CODE (c) != OMP_CLAUSE_DOACROSS) { - gcc_assert (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_THREADS - || OMP_CLAUSE_CODE (c) == OMP_CLAUSE_SIMD); - continue; - } - enum omp_clause_depend_kind kind = OMP_CLAUSE_DEPEND_KIND (c); - if (kind == OMP_CLAUSE_DEPEND_SOURCE - || kind == OMP_CLAUSE_DEPEND_SINK) - { - tree oclause; - /* Look for containing ordered(N) loop. */ - if (ctx == NULL - || gimple_code (ctx->stmt) != GIMPLE_OMP_FOR - || (oclause - = omp_find_clause (gimple_omp_for_clauses (ctx->stmt), - OMP_CLAUSE_ORDERED)) == NULL_TREE) - { - error_at (OMP_CLAUSE_LOCATION (c), - "% construct with % clause " - "must be closely nested inside an % " - "loop"); - return false; - } - else if (OMP_CLAUSE_ORDERED_EXPR (oclause) == NULL_TREE) + if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_DEPEND) { error_at (OMP_CLAUSE_LOCATION (c), - "% construct with % clause " - "must be closely nested inside a loop with " - "% clause with a parameter"); + "invalid depend kind in omp % %"); return false; } + gcc_assert (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_THREADS + || OMP_CLAUSE_CODE (c) == OMP_CLAUSE_SIMD); + continue; } - else + + tree oclause; + /* Look for containing ordered(N) loop. */ + if (ctx == NULL + || gimple_code (ctx->stmt) != GIMPLE_OMP_FOR + || (oclause + = omp_find_clause (gimple_omp_for_clauses (ctx->stmt), + OMP_CLAUSE_ORDERED)) == NULL_TREE) { error_at (OMP_CLAUSE_LOCATION (c), - "invalid depend kind in omp % %"); + "% construct with % clause " + "must be closely nested inside an % loop"); return false; } } @@ -3732,14 +3718,37 @@ check_omp_nesting_restrictions (gimple * "a loop region with an % clause"); return false; } - if (OMP_CLAUSE_ORDERED_EXPR (o) != NULL_TREE - && omp_find_clause (c, OMP_CLAUSE_DEPEND) == NULL_TREE) + if (omp_find_clause (c, OMP_CLAUSE_DOACROSS) == NULL_TREE) { - error_at (gimple_location (stmt), - "% region without % clause may " - "not be closely nested inside a loop region with " - "an % clause with a parameter"); - return false; + if (OMP_CLAUSE_ORDERED_DOACROSS (o)) + { + error_at (gimple_location (stmt), + "% construct without % or " + "% clauses must not have the same " + "binding region as % construct with " + "those clauses"); + return false; + } + else if (OMP_CLAUSE_ORDERED_EXPR (o)) + { + tree co + = omp_find_clause (gimple_omp_for_clauses (ctx->stmt), + OMP_CLAUSE_COLLAPSE); + HOST_WIDE_INT + o_n = tree_to_shwi (OMP_CLAUSE_ORDERED_EXPR (o)); + HOST_WIDE_INT c_n = 1; + if (co) + c_n = tree_to_shwi (OMP_CLAUSE_COLLAPSE_EXPR (co)); + if (o_n != c_n) + { + error_at (gimple_location (stmt), + "% construct without % " + "or % clauses binds to loop where " + "% argument %wd is different from " + "% argument %wd", c_n, o_n); + return false; + } + } } return true; case GIMPLE_OMP_TARGET: @@ -3793,14 +3802,12 @@ check_omp_nesting_restrictions (gimple * break; case GIMPLE_OMP_TARGET: for (c = gimple_omp_target_clauses (stmt); c; c = OMP_CLAUSE_CHAIN (c)) - if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_DEPEND - && (OMP_CLAUSE_DEPEND_KIND (c) == OMP_CLAUSE_DEPEND_SOURCE - || OMP_CLAUSE_DEPEND_KIND (c) == OMP_CLAUSE_DEPEND_SINK)) + if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_DOACROSS) { - enum omp_clause_depend_kind kind = OMP_CLAUSE_DEPEND_KIND (c); + enum omp_clause_doacross_kind kind = OMP_CLAUSE_DOACROSS_KIND (c); error_at (OMP_CLAUSE_LOCATION (c), "% is only allowed in %", - kind == OMP_CLAUSE_DEPEND_SOURCE ? "source" : "sink"); + kind == OMP_CLAUSE_DOACROSS_SOURCE ? "source" : "sink"); return false; } if (is_gimple_omp_offloaded (stmt) @@ -9743,8 +9750,8 @@ lower_omp_ordered_clauses (gimple_stmt_i tree *list_p = gimple_omp_ordered_clauses_ptr (ord_stmt); tree c = gimple_omp_ordered_clauses (ord_stmt); - if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_DEPEND - && OMP_CLAUSE_DEPEND_KIND (c) == OMP_CLAUSE_DEPEND_SINK) + if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_DOACROSS + && OMP_CLAUSE_DOACROSS_KIND (c) == OMP_CLAUSE_DOACROSS_SINK) { /* Merge depend clauses from multiple adjacent #pragma omp ordered depend(sink:...) constructs @@ -9766,8 +9773,8 @@ lower_omp_ordered_clauses (gimple_stmt_i gomp_ordered *ord_stmt2 = as_a (stmt); c = gimple_omp_ordered_clauses (ord_stmt2); if (c == NULL_TREE - || OMP_CLAUSE_CODE (c) != OMP_CLAUSE_DEPEND - || OMP_CLAUSE_DEPEND_KIND (c) != OMP_CLAUSE_DEPEND_SINK) + || OMP_CLAUSE_CODE (c) != OMP_CLAUSE_DOACROSS + || OMP_CLAUSE_DOACROSS_KIND (c) != OMP_CLAUSE_DOACROSS_SINK) break; while (*list_p) list_p = &OMP_CLAUSE_CHAIN (*list_p); @@ -9834,8 +9841,8 @@ lower_omp_ordered_clauses (gimple_stmt_i { bool remove = false; - gcc_assert (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_DEPEND); - if (OMP_CLAUSE_DEPEND_KIND (c) != OMP_CLAUSE_DEPEND_SINK) + gcc_assert (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_DOACROSS); + if (OMP_CLAUSE_DOACROSS_KIND (c) != OMP_CLAUSE_DOACROSS_SINK) goto next_ordered_clause; tree vec; @@ -9986,7 +9993,7 @@ lower_omp_ordered (gimple_stmt_iterator OMP_CLAUSE_THREADS); if (omp_find_clause (gimple_omp_ordered_clauses (ord_stmt), - OMP_CLAUSE_DEPEND)) + OMP_CLAUSE_DOACROSS)) { /* FIXME: This is needs to be moved to the expansion to verify various conditions only testable on cfg with dominators computed, and also @@ -12362,9 +12369,6 @@ lower_depend_clauses (tree *pclauses, gi case OMP_CLAUSE_DEPEND_INOUTSET: cnt[4]++; break; - case OMP_CLAUSE_DEPEND_SOURCE: - case OMP_CLAUSE_DEPEND_SINK: - /* FALLTHRU */ default: gcc_unreachable (); } --- gcc/omp-expand.cc.jj 2022-08-30 12:29:00.016160459 +0200 +++ gcc/omp-expand.cc 2022-09-02 18:18:37.253370510 +0200 @@ -3298,6 +3298,11 @@ expand_omp_ordered_sink (gimple_stmt_ite gimple_stmt_iterator gsi2 = *gsi; bool warned_step = false; + if (deps == NULL) + { + sorry_at (loc, "% not supported yet"); + return; + } for (i = 0; i < fd->ordered; i++) { tree step = NULL_TREE; @@ -3321,9 +3326,11 @@ expand_omp_ordered_sink (gimple_stmt_ite break; forward = tree_int_cst_sgn (step) != -1; } - if (forward ^ OMP_CLAUSE_DEPEND_SINK_NEGATIVE (deps)) - warning_at (loc, 0, "% clause with % modifier " - "waiting for lexically later iteration"); + if (forward ^ OMP_CLAUSE_DOACROSS_SINK_NEGATIVE (deps)) + warning_at (loc, 0, "%qs clause with % modifier " + "waiting for lexically later iteration", + OMP_CLAUSE_DOACROSS_DEPEND (c) + ? "depend" : "doacross"); break; } deps = TREE_CHAIN (deps); @@ -3377,13 +3384,13 @@ expand_omp_ordered_sink (gimple_stmt_ite tree co = fold_convert_loc (loc, itype, off); if (POINTER_TYPE_P (TREE_TYPE (fd->loops[i].v))) { - if (OMP_CLAUSE_DEPEND_SINK_NEGATIVE (deps)) + if (OMP_CLAUSE_DOACROSS_SINK_NEGATIVE (deps)) co = fold_build1_loc (loc, NEGATE_EXPR, itype, co); a = fold_build2_loc (loc, POINTER_PLUS_EXPR, TREE_TYPE (fd->loops[i].v), fd->loops[i].v, co); } - else if (OMP_CLAUSE_DEPEND_SINK_NEGATIVE (deps)) + else if (OMP_CLAUSE_DOACROSS_SINK_NEGATIVE (deps)) a = fold_build2_loc (loc, MINUS_EXPR, TREE_TYPE (fd->loops[i].v), fd->loops[i].v, co); else @@ -3392,13 +3399,13 @@ expand_omp_ordered_sink (gimple_stmt_ite if (step) { tree t1, t2; - if (OMP_CLAUSE_DEPEND_SINK_NEGATIVE (deps)) + if (OMP_CLAUSE_DOACROSS_SINK_NEGATIVE (deps)) t1 = fold_build2_loc (loc, GE_EXPR, boolean_type_node, a, fd->loops[i].n1); else t1 = fold_build2_loc (loc, LT_EXPR, boolean_type_node, a, fd->loops[i].n2); - if (OMP_CLAUSE_DEPEND_SINK_NEGATIVE (deps)) + if (OMP_CLAUSE_DOACROSS_SINK_NEGATIVE (deps)) t2 = fold_build2_loc (loc, LT_EXPR, boolean_type_node, a, fd->loops[i].n2); else @@ -3420,14 +3427,14 @@ expand_omp_ordered_sink (gimple_stmt_ite } else if (fd->loops[i].cond_code == LT_EXPR) { - if (OMP_CLAUSE_DEPEND_SINK_NEGATIVE (deps)) + if (OMP_CLAUSE_DOACROSS_SINK_NEGATIVE (deps)) t = fold_build2_loc (loc, GE_EXPR, boolean_type_node, a, fd->loops[i].n1); else t = fold_build2_loc (loc, LT_EXPR, boolean_type_node, a, fd->loops[i].n2); } - else if (OMP_CLAUSE_DEPEND_SINK_NEGATIVE (deps)) + else if (OMP_CLAUSE_DOACROSS_SINK_NEGATIVE (deps)) t = fold_build2_loc (loc, GT_EXPR, boolean_type_node, a, fd->loops[i].n2); else @@ -3459,9 +3466,11 @@ expand_omp_ordered_sink (gimple_stmt_ite build_int_cst (itype, 0)); if (integer_zerop (t) && !warned_step) { - warning_at (loc, 0, "% clause with % modifier " + warning_at (loc, 0, "%qs clause with % modifier " "refers to iteration never in the iteration " - "space"); + "space", + OMP_CLAUSE_DOACROSS_DEPEND (c) + ? "depend" : "doacross"); warned_step = true; } cond = fold_build2_loc (loc, BIT_AND_EXPR, boolean_type_node, @@ -3486,7 +3495,7 @@ expand_omp_ordered_sink (gimple_stmt_ite s)); else off = fold_build2_loc (loc, TRUNC_DIV_EXPR, itype, off, s); - if (OMP_CLAUSE_DEPEND_SINK_NEGATIVE (deps)) + if (OMP_CLAUSE_DOACROSS_SINK_NEGATIVE (deps)) off = fold_build1_loc (loc, NEGATE_EXPR, itype, off); off = fold_convert_loc (loc, fd->iter_type, off); if (i <= fd->collapse - 1 && fd->collapse > 1) @@ -3559,13 +3568,13 @@ expand_omp_ordered_source_sink (struct o tree c; for (c = gimple_omp_ordered_clauses (ord_stmt); c; c = OMP_CLAUSE_CHAIN (c)) - if (OMP_CLAUSE_DEPEND_KIND (c) == OMP_CLAUSE_DEPEND_SOURCE) + if (OMP_CLAUSE_DOACROSS_KIND (c) == OMP_CLAUSE_DOACROSS_SOURCE) break; if (c) expand_omp_ordered_source (&gsi, fd, counts, loc); for (c = gimple_omp_ordered_clauses (ord_stmt); c; c = OMP_CLAUSE_CHAIN (c)) - if (OMP_CLAUSE_DEPEND_KIND (c) == OMP_CLAUSE_DEPEND_SINK) + if (OMP_CLAUSE_DOACROSS_KIND (c) == OMP_CLAUSE_DOACROSS_SINK) expand_omp_ordered_sink (&gsi, fd, counts, c, loc); gsi_remove (&gsi, true); } @@ -10479,7 +10488,7 @@ expand_omp (struct omp_region *region) gomp_ordered *ord_stmt = as_a (last_stmt (region->entry)); if (omp_find_clause (gimple_omp_ordered_clauses (ord_stmt), - OMP_CLAUSE_DEPEND)) + OMP_CLAUSE_DOACROSS)) { /* We'll expand these when expanding corresponding worksharing region with ordered(n) clause. */ @@ -10609,7 +10618,7 @@ build_omp_regions_1 (basic_block bb, str else if (code == GIMPLE_OMP_ORDERED && omp_find_clause (gimple_omp_ordered_clauses (as_a (stmt)), - OMP_CLAUSE_DEPEND)) + OMP_CLAUSE_DOACROSS)) /* #pragma omp ordered depend is also just a stand-alone directive. */ region = NULL; @@ -10835,7 +10844,7 @@ omp_make_gimple_edges (basic_block bb, s fallthru = true; if (omp_find_clause (gimple_omp_ordered_clauses (as_a (last)), - OMP_CLAUSE_DEPEND)) + OMP_CLAUSE_DOACROSS)) cur_region = cur_region->outer; break; --- gcc/lto-streamer-out.cc.jj 2022-01-18 11:58:59.686980571 +0100 +++ gcc/lto-streamer-out.cc 2022-09-01 16:35:03.823584108 +0200 @@ -1553,6 +1553,9 @@ hash_tree (struct streamer_tree_cache_d case OMP_CLAUSE_DEPEND: val = OMP_CLAUSE_DEPEND_KIND (t); break; + case OMP_CLAUSE_DOACROSS: + val = OMP_CLAUSE_DOACROSS_KIND (t); + break; case OMP_CLAUSE_MAP: val = OMP_CLAUSE_MAP_KIND (t); break; --- gcc/tree-streamer-in.cc.jj 2022-05-09 09:09:20.817466314 +0200 +++ gcc/tree-streamer-in.cc 2022-09-01 16:32:09.156932116 +0200 @@ -453,6 +453,11 @@ unpack_ts_omp_clause_value_fields (class OMP_CLAUSE_DEPEND_KIND (expr) = bp_unpack_enum (bp, omp_clause_depend_kind, OMP_CLAUSE_DEPEND_LAST); break; + case OMP_CLAUSE_DOACROSS: + OMP_CLAUSE_DOACROSS_KIND (expr) + = bp_unpack_enum (bp, omp_clause_doacross_kind, + OMP_CLAUSE_DOACROSS_LAST); + break; case OMP_CLAUSE_MAP: OMP_CLAUSE_SET_MAP_KIND (expr, bp_unpack_enum (bp, gomp_map_kind, GOMP_MAP_LAST)); --- gcc/tree-streamer-out.cc.jj 2022-02-04 14:36:56.342586625 +0100 +++ gcc/tree-streamer-out.cc 2022-09-01 16:32:38.916532065 +0200 @@ -419,6 +419,10 @@ pack_ts_omp_clause_value_fields (struct bp_pack_enum (bp, omp_clause_depend_kind, OMP_CLAUSE_DEPEND_LAST, OMP_CLAUSE_DEPEND_KIND (expr)); break; + case OMP_CLAUSE_DOACROSS: + bp_pack_enum (bp, omp_clause_doacross_kind, OMP_CLAUSE_DOACROSS_LAST, + OMP_CLAUSE_DOACROSS_KIND (expr)); + break; case OMP_CLAUSE_MAP: bp_pack_enum (bp, gomp_map_kind, GOMP_MAP_LAST, OMP_CLAUSE_MAP_KIND (expr)); --- gcc/c-family/c-pragma.h.jj 2022-08-30 12:28:59.909161910 +0200 +++ gcc/c-family/c-pragma.h 2022-09-01 14:34:17.356367234 +0200 @@ -108,6 +108,7 @@ enum pragma_omp_clause { PRAGMA_OMP_CLAUSE_DEVICE, PRAGMA_OMP_CLAUSE_DEVICE_TYPE, PRAGMA_OMP_CLAUSE_DIST_SCHEDULE, + PRAGMA_OMP_CLAUSE_DOACROSS, PRAGMA_OMP_CLAUSE_ENTER, PRAGMA_OMP_CLAUSE_FILTER, PRAGMA_OMP_CLAUSE_FINAL, --- gcc/c-family/c-omp.cc.jj 2022-08-30 12:28:59.874162385 +0200 +++ gcc/c-family/c-omp.cc 2022-09-01 17:39:13.733664070 +0200 @@ -714,8 +714,17 @@ c_finish_omp_depobj (location_t loc, tre if (clause) { - gcc_assert (TREE_CODE (clause) == OMP_CLAUSE - && OMP_CLAUSE_CODE (clause) == OMP_CLAUSE_DEPEND); + gcc_assert (TREE_CODE (clause) == OMP_CLAUSE); + if (OMP_CLAUSE_CODE (clause) == OMP_CLAUSE_DOACROSS) + { + error_at (OMP_CLAUSE_LOCATION (clause), + "% is only allowed in %", + OMP_CLAUSE_DOACROSS_KIND (clause) + == OMP_CLAUSE_DOACROSS_SOURCE + ? "source" : "sink"); + return; + } + gcc_assert (OMP_CLAUSE_CODE (clause) == OMP_CLAUSE_DEPEND); if (OMP_CLAUSE_CHAIN (clause)) error_at (OMP_CLAUSE_LOCATION (clause), "more than one locator in % clause on % " @@ -727,13 +736,6 @@ c_finish_omp_depobj (location_t loc, tre "% dependence type specified in % " "clause on % construct"); return; - case OMP_CLAUSE_DEPEND_SOURCE: - case OMP_CLAUSE_DEPEND_SINK: - error_at (OMP_CLAUSE_LOCATION (clause), - "% is only allowed in %", - OMP_CLAUSE_DEPEND_KIND (clause) == OMP_CLAUSE_DEPEND_SOURCE - ? "source" : "sink"); - return; case OMP_CLAUSE_DEPEND_IN: case OMP_CLAUSE_DEPEND_OUT: case OMP_CLAUSE_DEPEND_INOUT: @@ -764,8 +766,8 @@ c_finish_omp_depobj (location_t loc, tre gcc_unreachable (); } } else - gcc_assert (kind != OMP_CLAUSE_DEPEND_SOURCE); + gcc_assert (kind != OMP_CLAUSE_DEPEND_INVALID); if (depobj == error_mark_node) return; --- gcc/c/c-parser.cc.jj 2022-09-01 09:37:58.008630749 +0200 +++ gcc/c/c-parser.cc 2022-09-02 15:52:03.948221268 +0200 @@ -12814,6 +12814,8 @@ c_parser_omp_clause_name (c_parser *pars result = PRAGMA_OMP_CLAUSE_DEVICE_TYPE; else if (!strcmp ("dist_schedule", p)) result = PRAGMA_OMP_CLAUSE_DIST_SCHEDULE; + else if (!strcmp ("doacross", p)) + result = PRAGMA_OMP_CLAUSE_DOACROSS; break; case 'e': if (!strcmp ("enter", p)) @@ -15962,8 +15964,8 @@ c_parser_omp_clause_simdlen (c_parser *p */ static tree -c_parser_omp_clause_depend_sink (c_parser *parser, location_t clause_loc, - tree list) +c_parser_omp_clause_doacross_sink (c_parser *parser, location_t clause_loc, + tree list, bool depend_p) { tree vec = NULL; if (c_parser_next_token_is_not (parser, CPP_NAME) @@ -15973,6 +15975,31 @@ c_parser_omp_clause_depend_sink (c_parse return list; } + if (!depend_p) + { + const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); + if (strcmp (p, "omp_cur_iteration") == 0 + && c_parser_peek_2nd_token (parser)->type == CPP_MINUS + && c_parser_peek_nth_token (parser, 3)->type == CPP_NUMBER + && c_parser_peek_nth_token (parser, 4)->type == CPP_CLOSE_PAREN) + { + tree val = c_parser_peek_nth_token (parser, 3)->value; + if (integer_onep (val) + && comptypes (TREE_TYPE (val), integer_type_node)) + { + c_parser_consume_token (parser); + c_parser_consume_token (parser); + c_parser_consume_token (parser); + tree u = build_omp_clause (clause_loc, OMP_CLAUSE_DOACROSS); + OMP_CLAUSE_DOACROSS_KIND (u) = OMP_CLAUSE_DOACROSS_SINK; + OMP_CLAUSE_CHAIN (u) = list; + return u; + } + } + } + + + while (c_parser_next_token_is (parser, CPP_NAME) && c_parser_peek_token (parser)->id_kind == C_ID_ID) { @@ -16018,7 +16045,7 @@ c_parser_omp_clause_depend_sink (c_parse { vec = tree_cons (addend, t, vec); if (neg) - OMP_CLAUSE_DEPEND_SINK_NEGATIVE (vec) = 1; + OMP_CLAUSE_DOACROSS_SINK_NEGATIVE (vec) = 1; } if (c_parser_next_token_is_not (parser, CPP_COMMA) @@ -16032,8 +16059,9 @@ c_parser_omp_clause_depend_sink (c_parse if (vec == NULL_TREE) return list; - tree u = build_omp_clause (clause_loc, OMP_CLAUSE_DEPEND); - OMP_CLAUSE_DEPEND_KIND (u) = OMP_CLAUSE_DEPEND_SINK; + tree u = build_omp_clause (clause_loc, OMP_CLAUSE_DOACROSS); + OMP_CLAUSE_DOACROSS_KIND (u) = OMP_CLAUSE_DOACROSS_SINK; + OMP_CLAUSE_DOACROSS_DEPEND (u) = depend_p; OMP_CLAUSE_DECL (u) = nreverse (vec); OMP_CLAUSE_CHAIN (u) = list; return u; @@ -16225,6 +16253,7 @@ c_parser_omp_clause_depend (c_parser *pa { location_t clause_loc = c_parser_peek_token (parser)->location; enum omp_clause_depend_kind kind = OMP_CLAUSE_DEPEND_LAST; + enum omp_clause_doacross_kind dkind = OMP_CLAUSE_DOACROSS_LAST; tree nl, c, iterators = NULL_TREE; matching_parens parens; @@ -16256,9 +16285,9 @@ c_parser_omp_clause_depend (c_parser *pa else if (strcmp ("depobj", p) == 0) kind = OMP_CLAUSE_DEPEND_DEPOBJ; else if (strcmp ("sink", p) == 0) - kind = OMP_CLAUSE_DEPEND_SINK; + dkind = OMP_CLAUSE_DOACROSS_SINK; else if (strcmp ("source", p) == 0) - kind = OMP_CLAUSE_DEPEND_SOURCE; + dkind = OMP_CLAUSE_DOACROSS_SOURCE; else goto invalid_kind; break; @@ -16268,18 +16297,20 @@ c_parser_omp_clause_depend (c_parser *pa c_parser_consume_token (parser); if (iterators - && (kind == OMP_CLAUSE_DEPEND_SOURCE || kind == OMP_CLAUSE_DEPEND_SINK)) + && (dkind == OMP_CLAUSE_DOACROSS_SOURCE + || dkind == OMP_CLAUSE_DOACROSS_SINK)) { pop_scope (); error_at (clause_loc, "% modifier incompatible with %qs", - kind == OMP_CLAUSE_DEPEND_SOURCE ? "source" : "sink"); + dkind == OMP_CLAUSE_DOACROSS_SOURCE ? "source" : "sink"); iterators = NULL_TREE; } - if (kind == OMP_CLAUSE_DEPEND_SOURCE) + if (dkind == OMP_CLAUSE_DOACROSS_SOURCE) { - c = build_omp_clause (clause_loc, OMP_CLAUSE_DEPEND); - OMP_CLAUSE_DEPEND_KIND (c) = kind; + c = build_omp_clause (clause_loc, OMP_CLAUSE_DOACROSS); + OMP_CLAUSE_DOACROSS_KIND (c) = dkind; + OMP_CLAUSE_DOACROSS_DEPEND (c) = 1; OMP_CLAUSE_DECL (c) = NULL_TREE; OMP_CLAUSE_CHAIN (c) = list; parens.skip_until_found_close (parser); @@ -16289,8 +16320,8 @@ c_parser_omp_clause_depend (c_parser *pa if (!c_parser_require (parser, CPP_COLON, "expected %<:%>")) goto resync_fail; - if (kind == OMP_CLAUSE_DEPEND_SINK) - nl = c_parser_omp_clause_depend_sink (parser, clause_loc, list); + if (dkind == OMP_CLAUSE_DOACROSS_SINK) + nl = c_parser_omp_clause_doacross_sink (parser, clause_loc, list, true); else { nl = c_parser_omp_variable_list (parser, clause_loc, @@ -16326,6 +16357,65 @@ c_parser_omp_clause_depend (c_parser *pa return list; } +/* OpenMP 5.2: + doacross ( source : ) + doacross ( source : omp_cur_iteration ) + + doacross ( sink : vec ) + doacross ( sink : omp_cur_iteration - logical_iteration ) */ + +static tree +c_parser_omp_clause_doacross (c_parser *parser, tree list) +{ + location_t clause_loc = c_parser_peek_token (parser)->location; + enum omp_clause_doacross_kind kind = OMP_CLAUSE_DOACROSS_LAST; + tree nl; + const char *p; + + matching_parens parens; + if (!parens.require_open (parser)) + return list; + + if (c_parser_next_token_is_not (parser, CPP_NAME)) + goto invalid_kind; + + p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); + if (strcmp ("sink", p) == 0) + kind = OMP_CLAUSE_DOACROSS_SINK; + else if (strcmp ("source", p) == 0) + kind = OMP_CLAUSE_DOACROSS_SOURCE; + else + goto invalid_kind; + + c_parser_consume_token (parser); + + if (!c_parser_require (parser, CPP_COLON, "expected %<:%>")) + goto resync_fail; + + if (kind == OMP_CLAUSE_DOACROSS_SOURCE) + { + if (c_parser_next_token_is (parser, CPP_NAME) + && strcmp (IDENTIFIER_POINTER (c_parser_peek_token (parser)->value), + "omp_cur_iteration") == 0) + c_parser_consume_token (parser); + nl = build_omp_clause (clause_loc, OMP_CLAUSE_DOACROSS); + OMP_CLAUSE_DOACROSS_KIND (nl) = OMP_CLAUSE_DOACROSS_SOURCE; + OMP_CLAUSE_DECL (nl) = NULL_TREE; + OMP_CLAUSE_CHAIN (nl) = list; + } + else + nl = c_parser_omp_clause_doacross_sink (parser, clause_loc, list, false); + + parens.skip_until_found_close (parser); + return nl; + + invalid_kind: + c_parser_error (parser, "invalid doacross kind"); + resync_fail: + parens.skip_until_found_close (parser); + return list; +} + /* OpenMP 4.0: map ( map-kind: variable-list ) map ( variable-list ) @@ -17243,6 +17333,10 @@ c_parser_omp_all_clauses (c_parser *pars clauses = c_parser_omp_clause_depend (parser, clauses); c_name = "depend"; break; + case PRAGMA_OMP_CLAUSE_DOACROSS: + clauses = c_parser_omp_clause_doacross (parser, clauses); + c_name = "doacross"; + break; case PRAGMA_OMP_CLAUSE_MAP: clauses = c_parser_omp_clause_map (parser, clauses); c_name = "map"; @@ -19187,7 +19281,7 @@ c_parser_omp_depobj (c_parser *parser) parens.skip_until_found_close (parser); tree clause = NULL_TREE; - enum omp_clause_depend_kind kind = OMP_CLAUSE_DEPEND_SOURCE; + enum omp_clause_depend_kind kind = OMP_CLAUSE_DEPEND_INVALID; location_t c_loc = c_parser_peek_token (parser)->location; if (c_parser_next_token_is (parser, CPP_NAME)) { @@ -19226,7 +19320,7 @@ c_parser_omp_depobj (c_parser *parser) else if (!strcmp ("inoutset", p2)) kind = OMP_CLAUSE_DEPEND_INOUTSET; } - if (kind == OMP_CLAUSE_DEPEND_SOURCE) + if (kind == OMP_CLAUSE_DEPEND_INVALID) { clause = error_mark_node; error_at (c2_loc, "expected %, %, %, " @@ -19238,7 +19332,7 @@ c_parser_omp_depobj (c_parser *parser) clause = error_mark_node; } } - if (!clause && kind == OMP_CLAUSE_DEPEND_SOURCE) + if (!clause && kind == OMP_CLAUSE_DEPEND_INVALID) { clause = error_mark_node; error_at (c_loc, "expected %, % or % clause"); @@ -19437,19 +19531,6 @@ c_parser_omp_for_loop (location_t loc, c = build_int_cst (NULL_TREE, collapse); ordered = collapse; } - if (ordered) - { - for (tree *pc = &clauses; *pc; ) - if (OMP_CLAUSE_CODE (*pc) == OMP_CLAUSE_LINEAR) - { - error_at (OMP_CLAUSE_LOCATION (*pc), - "% clause may not be specified together " - "with % clause with a parameter"); - *pc = OMP_CLAUSE_CHAIN (*pc); - } - else - pc = &OMP_CLAUSE_CHAIN (*pc); - } gcc_assert (tiling || (collapse >= 1 && ordered >= 0)); count = ordered ? ordered : collapse; @@ -19887,15 +19968,6 @@ c_parser_omp_simd (location_t loc, c_par { omp_split_clauses (loc, OMP_SIMD, mask, clauses, cclauses); clauses = cclauses[C_OMP_CLAUSE_SPLIT_SIMD]; - tree c = omp_find_clause (cclauses[C_OMP_CLAUSE_SPLIT_FOR], - OMP_CLAUSE_ORDERED); - if (c && OMP_CLAUSE_ORDERED_EXPR (c)) - { - error_at (OMP_CLAUSE_LOCATION (c), - "% clause with parameter may not be specified " - "on %qs construct", p_name); - OMP_CLAUSE_ORDERED_EXPR (c) = NULL_TREE; - } } block = c_begin_compound_stmt (true); @@ -20134,14 +20206,18 @@ c_parser_omp_masked (location_t loc, c_p # pragma omp ordered ordered-clauses new-line structured-block - # pragma omp ordered depend-clauses new-line */ + # pragma omp ordered depend-clauses new-line + + OpenMP 5.2 + # pragma omp ordered doacross-clauses new-line */ #define OMP_ORDERED_CLAUSE_MASK \ ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_THREADS) \ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_SIMD)) #define OMP_ORDERED_DEPEND_CLAUSE_MASK \ - (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEPEND) + ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEPEND) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DOACROSS)) static bool c_parser_omp_ordered (c_parser *parser, enum pragma_context context, @@ -20161,7 +20237,7 @@ c_parser_omp_ordered (c_parser *parser, { const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value); - if (!strcmp ("depend", p)) + if (!strcmp ("depend", p) || !strcmp ("doacross", p)) { if (!flag_openmp) /* flag_openmp_simd */ { @@ -20171,8 +20247,8 @@ c_parser_omp_ordered (c_parser *parser, if (context == pragma_stmt) { error_at (loc, - "%<#pragma omp ordered%> with % clause may " - "only be used in compound statements"); + "%<#pragma omp ordered%> with %qs clause may " + "only be used in compound statements", p); c_parser_skip_to_pragma_eol (parser, false); return true; } --- gcc/c/c-typeck.cc.jj 2022-09-01 09:37:58.014630667 +0200 +++ gcc/c/c-typeck.cc 2022-09-02 10:17:07.680560840 +0200 @@ -14834,15 +14834,11 @@ c_finish_omp_clauses (tree clauses, enum } break; - case OMP_CLAUSE_DEPEND: + case OMP_CLAUSE_DOACROSS: t = OMP_CLAUSE_DECL (c); if (t == NULL_TREE) - { - gcc_assert (OMP_CLAUSE_DEPEND_KIND (c) - == OMP_CLAUSE_DEPEND_SOURCE); - break; - } - if (OMP_CLAUSE_DEPEND_KIND (c) == OMP_CLAUSE_DEPEND_SINK) + break; + if (OMP_CLAUSE_DOACROSS_KIND (c) == OMP_CLAUSE_DOACROSS_SINK) { gcc_assert (TREE_CODE (t) == TREE_LIST); for (; t; t = TREE_CHAIN (t)) @@ -14870,7 +14866,8 @@ c_finish_omp_clauses (tree clauses, enum } break; } - /* FALLTHRU */ + gcc_unreachable (); + case OMP_CLAUSE_DEPEND: case OMP_CLAUSE_AFFINITY: t = OMP_CLAUSE_DECL (c); if (TREE_CODE (t) == TREE_LIST --- gcc/cp/parser.cc.jj 2022-08-26 09:18:25.255154767 +0200 +++ gcc/cp/parser.cc 2022-09-02 15:51:28.675690445 +0200 @@ -11979,14 +11979,18 @@ cp_parser_handle_statement_omp_attribute if (dir->id == PRAGMA_OMP_ORDERED) { /* ordered is C_OMP_DIR_CONSTRUCT only if it doesn't contain - depend clause. */ - if (directive[1] && strcmp (directive[1], "depend") == 0) + depend/doacross clause. */ + if (directive[1] + && (strcmp (directive[1], "depend") == 0 + || strcmp (directive[1], "doacross") == 0)) kind = C_OMP_DIR_STANDALONE; else if (first + 2 < last && first[1].type == CPP_COMMA && first[2].type == CPP_NAME - && strcmp (IDENTIFIER_POINTER (first[2].u.value), - "depend") == 0) + && (strcmp (IDENTIFIER_POINTER (first[2].u.value), + "depend") == 0 + || strcmp (IDENTIFIER_POINTER (first[2].u.value), + "doacross") == 0)) kind = C_OMP_DIR_STANDALONE; } else if (dir->id == PRAGMA_OMP_ERROR) @@ -36587,6 +36591,8 @@ cp_parser_omp_clause_name (cp_parser *pa result = PRAGMA_OMP_CLAUSE_DEVICE_TYPE; else if (!strcmp ("dist_schedule", p)) result = PRAGMA_OMP_CLAUSE_DIST_SCHEDULE; + else if (!strcmp ("doacross", p)) + result = PRAGMA_OMP_CLAUSE_DOACROSS; break; case 'e': if (!strcmp ("enter", p)) @@ -39314,8 +39320,8 @@ cp_parser_omp_clause_simdlen (cp_parser */ static tree -cp_parser_omp_clause_depend_sink (cp_parser *parser, location_t clause_loc, - tree list) +cp_parser_omp_clause_doacross_sink (cp_parser *parser, location_t clause_loc, + tree list, bool depend_p) { tree vec = NULL; @@ -39325,6 +39331,29 @@ cp_parser_omp_clause_depend_sink (cp_par return list; } + if (!depend_p) + { + tree id = cp_lexer_peek_token (parser->lexer)->u.value; + if (strcmp (IDENTIFIER_POINTER (id), "omp_cur_iteration") == 0 + && cp_lexer_nth_token_is (parser->lexer, 2, CPP_MINUS) + && cp_lexer_nth_token_is (parser->lexer, 3, CPP_NUMBER) + && cp_lexer_nth_token_is (parser->lexer, 4, CPP_CLOSE_PAREN)) + { + tree val = cp_lexer_peek_nth_token (parser->lexer, 3)->u.value; + if (integer_onep (val) + && same_type_p (TREE_TYPE (val), integer_type_node)) + { + cp_lexer_consume_token (parser->lexer); + cp_lexer_consume_token (parser->lexer); + cp_lexer_consume_token (parser->lexer); + tree u = build_omp_clause (clause_loc, OMP_CLAUSE_DOACROSS); + OMP_CLAUSE_DOACROSS_KIND (u) = OMP_CLAUSE_DOACROSS_SINK; + OMP_CLAUSE_CHAIN (u) = list; + return u; + } + } + } + while (cp_lexer_next_token_is (parser->lexer, CPP_NAME)) { location_t id_loc = cp_lexer_peek_token (parser->lexer)->location; @@ -39372,7 +39401,7 @@ cp_parser_omp_clause_depend_sink (cp_par { vec = tree_cons (addend, t, vec); if (neg) - OMP_CLAUSE_DEPEND_SINK_NEGATIVE (vec) = 1; + OMP_CLAUSE_DOACROSS_SINK_NEGATIVE (vec) = 1; } if (cp_lexer_next_token_is_not (parser->lexer, CPP_COMMA) @@ -39384,8 +39413,9 @@ cp_parser_omp_clause_depend_sink (cp_par if (vec) { - tree u = build_omp_clause (clause_loc, OMP_CLAUSE_DEPEND); - OMP_CLAUSE_DEPEND_KIND (u) = OMP_CLAUSE_DEPEND_SINK; + tree u = build_omp_clause (clause_loc, OMP_CLAUSE_DOACROSS); + OMP_CLAUSE_DOACROSS_KIND (u) = OMP_CLAUSE_DOACROSS_SINK; + OMP_CLAUSE_DOACROSS_DEPEND (u) = depend_p; OMP_CLAUSE_DECL (u) = nreverse (vec); OMP_CLAUSE_CHAIN (u) = list; return u; @@ -39634,6 +39664,7 @@ cp_parser_omp_clause_depend (cp_parser * { tree nlist, c, iterators = NULL_TREE; enum omp_clause_depend_kind kind = OMP_CLAUSE_DEPEND_LAST; + enum omp_clause_doacross_kind dkind = OMP_CLAUSE_DOACROSS_LAST; matching_parens parens; if (!parens.require_open (parser)) @@ -39667,9 +39698,9 @@ cp_parser_omp_clause_depend (cp_parser * else if (strcmp ("depobj", p) == 0) kind = OMP_CLAUSE_DEPEND_DEPOBJ; else if (strcmp ("sink", p) == 0) - kind = OMP_CLAUSE_DEPEND_SINK; + dkind = OMP_CLAUSE_DOACROSS_SINK; else if (strcmp ("source", p) == 0) - kind = OMP_CLAUSE_DEPEND_SOURCE; + dkind = OMP_CLAUSE_DOACROSS_SOURCE; else goto invalid_kind; break; @@ -39679,18 +39710,20 @@ cp_parser_omp_clause_depend (cp_parser * cp_lexer_consume_token (parser->lexer); if (iterators - && (kind == OMP_CLAUSE_DEPEND_SOURCE || kind == OMP_CLAUSE_DEPEND_SINK)) + && (dkind == OMP_CLAUSE_DOACROSS_SOURCE + || dkind == OMP_CLAUSE_DOACROSS_SINK)) { poplevel (0, 1, 0); error_at (loc, "% modifier incompatible with %qs", - kind == OMP_CLAUSE_DEPEND_SOURCE ? "source" : "sink"); + dkind == OMP_CLAUSE_DOACROSS_SOURCE ? "source" : "sink"); iterators = NULL_TREE; } - if (kind == OMP_CLAUSE_DEPEND_SOURCE) + if (dkind == OMP_CLAUSE_DOACROSS_SOURCE) { - c = build_omp_clause (loc, OMP_CLAUSE_DEPEND); - OMP_CLAUSE_DEPEND_KIND (c) = kind; + c = build_omp_clause (loc, OMP_CLAUSE_DOACROSS); + OMP_CLAUSE_DOACROSS_KIND (c) = dkind; + OMP_CLAUSE_DOACROSS_DEPEND (c) = 1; OMP_CLAUSE_DECL (c) = NULL_TREE; OMP_CLAUSE_CHAIN (c) = list; if (!parens.require_close (parser)) @@ -39703,9 +39736,9 @@ cp_parser_omp_clause_depend (cp_parser * if (!cp_parser_require (parser, CPP_COLON, RT_COLON)) goto resync_fail; - if (kind == OMP_CLAUSE_DEPEND_SINK) + if (dkind == OMP_CLAUSE_DOACROSS_SINK) { - nlist = cp_parser_omp_clause_depend_sink (parser, loc, list); + nlist = cp_parser_omp_clause_doacross_sink (parser, loc, list, true); if (!parens.require_close (parser)) cp_parser_skip_to_closing_parenthesis (parser, /*recovering=*/true, /*or_comma=*/false, @@ -39746,6 +39779,73 @@ cp_parser_omp_clause_depend (cp_parser * return list; } +/* OpenMP 5.2: + doacross ( source : ) + doacross ( source : omp_cur_iteration ) + + doacross ( sink : vec ) + doacross ( sink : omp_cur_iteration - logical_iteration ) */ + +static tree +cp_parser_omp_clause_doacross (cp_parser *parser, tree list, location_t loc) +{ + tree nlist; + enum omp_clause_doacross_kind kind = OMP_CLAUSE_DOACROSS_LAST; + + matching_parens parens; + if (!parens.require_open (parser)) + return list; + + if (cp_lexer_next_token_is_not (parser->lexer, CPP_NAME)) + { + invalid_kind: + cp_parser_error (parser, "invalid doacross kind"); + resync_fail: + cp_parser_skip_to_closing_parenthesis (parser, /*recovering=*/true, + /*or_comma=*/false, + /*consume_paren=*/true); + return list; + } + + tree id = cp_lexer_peek_token (parser->lexer)->u.value; + const char *p = IDENTIFIER_POINTER (id); + + if (strcmp ("sink", p) == 0) + kind = OMP_CLAUSE_DOACROSS_SINK; + else if (strcmp ("source", p) == 0) + kind = OMP_CLAUSE_DOACROSS_SOURCE; + else + goto invalid_kind; + + cp_lexer_consume_token (parser->lexer); + + if (!cp_parser_require (parser, CPP_COLON, RT_COLON)) + goto resync_fail; + + if (kind == OMP_CLAUSE_DOACROSS_SOURCE) + { + if (cp_lexer_next_token_is (parser->lexer, CPP_NAME)) + { + id = cp_lexer_peek_token (parser->lexer)->u.value; + p = IDENTIFIER_POINTER (id); + if (strcmp (p, "omp_cur_iteration") == 0) + cp_lexer_consume_token (parser->lexer); + } + nlist = build_omp_clause (loc, OMP_CLAUSE_DOACROSS); + OMP_CLAUSE_DOACROSS_KIND (nlist) = OMP_CLAUSE_DOACROSS_SOURCE; + OMP_CLAUSE_DECL (nlist) = NULL_TREE; + OMP_CLAUSE_CHAIN (nlist) = list; + } + else + nlist = cp_parser_omp_clause_doacross_sink (parser, loc, list, false); + + if (!parens.require_close (parser)) + cp_parser_skip_to_closing_parenthesis (parser, /*recovering=*/true, + /*or_comma=*/false, + /*consume_paren=*/true); + return nlist; +} + /* OpenMP 4.0: map ( map-kind : variable-list ) map ( variable-list ) @@ -40688,6 +40788,11 @@ cp_parser_omp_all_clauses (cp_parser *pa token->location); c_name = "depend"; break; + case PRAGMA_OMP_CLAUSE_DOACROSS: + clauses = cp_parser_omp_clause_doacross (parser, clauses, + token->location); + c_name = "doacross"; + break; case PRAGMA_OMP_CLAUSE_DETACH: clauses = cp_parser_omp_clause_detach (parser, clauses); c_name = "detach"; @@ -41926,7 +42031,7 @@ cp_parser_omp_depobj (cp_parser *parser, /*consume_paren=*/true); tree clause = NULL_TREE; - enum omp_clause_depend_kind kind = OMP_CLAUSE_DEPEND_SOURCE; + enum omp_clause_depend_kind kind = OMP_CLAUSE_DEPEND_INVALID; location_t c_loc = cp_lexer_peek_token (parser->lexer)->location; /* For now only in C++ attributes, do it always for OpenMP 5.1. */ if (parser->lexer->in_omp_attribute_pragma @@ -41974,7 +42079,7 @@ cp_parser_omp_depobj (cp_parser *parser, else if (!strcmp ("inoutset", p2)) kind = OMP_CLAUSE_DEPEND_INOUTSET; } - if (kind == OMP_CLAUSE_DEPEND_SOURCE) + if (kind == OMP_CLAUSE_DEPEND_INVALID) { clause = error_mark_node; error_at (c2_loc, "expected %, %, %, " @@ -41990,7 +42095,7 @@ cp_parser_omp_depobj (cp_parser *parser, clause = error_mark_node; } } - if (!clause && kind == OMP_CLAUSE_DEPEND_SOURCE) + if (!clause && kind == OMP_CLAUSE_DEPEND_INVALID) { clause = error_mark_node; error_at (c_loc, "expected %, % or % clause"); @@ -42822,19 +42927,6 @@ cp_parser_omp_for_loop (cp_parser *parse = build_int_cst (NULL_TREE, collapse); ordered = collapse; } - if (ordered) - { - for (tree *pc = &clauses; *pc; ) - if (OMP_CLAUSE_CODE (*pc) == OMP_CLAUSE_LINEAR) - { - error_at (OMP_CLAUSE_LOCATION (*pc), - "% clause may not be specified together " - "with % clause with a parameter"); - *pc = OMP_CLAUSE_CHAIN (*pc); - } - else - pc = &OMP_CLAUSE_CHAIN (*pc); - } gcc_assert (tiling || (collapse >= 1 && ordered >= 0)); count = ordered ? ordered : collapse; @@ -43286,15 +43378,6 @@ cp_parser_omp_simd (cp_parser *parser, c { cp_omp_split_clauses (loc, OMP_SIMD, mask, clauses, cclauses); clauses = cclauses[C_OMP_CLAUSE_SPLIT_SIMD]; - tree c = omp_find_clause (cclauses[C_OMP_CLAUSE_SPLIT_FOR], - OMP_CLAUSE_ORDERED); - if (c && OMP_CLAUSE_ORDERED_EXPR (c)) - { - error_at (OMP_CLAUSE_LOCATION (c), - "% clause with parameter may not be specified " - "on %qs construct", p_name); - OMP_CLAUSE_ORDERED_EXPR (c) = NULL_TREE; - } } keep_next_level (true); @@ -43556,7 +43639,8 @@ cp_parser_omp_masked (cp_parser *parser, | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_SIMD)) #define OMP_ORDERED_DEPEND_CLAUSE_MASK \ - (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEPEND) + ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEPEND) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DOACROSS)) static bool cp_parser_omp_ordered (cp_parser *parser, cp_token *pragma_tok, @@ -43575,7 +43659,7 @@ cp_parser_omp_ordered (cp_parser *parser tree id = cp_lexer_peek_nth_token (parser->lexer, n)->u.value; const char *p = IDENTIFIER_POINTER (id); - if (strcmp (p, "depend") == 0) + if (strcmp (p, "depend") == 0 || strcmp (p, "doacross") == 0) { if (!flag_openmp) /* flag_openmp_simd */ { @@ -43585,8 +43669,8 @@ cp_parser_omp_ordered (cp_parser *parser if (context == pragma_stmt) { error_at (pragma_tok->location, "%<#pragma omp ordered%> with " - "% clause may only be used in compound " - "statements"); + "%qs clause may only be used in compound " + "statements", p); cp_parser_skip_to_pragma_eol (parser, pragma_tok); return true; } --- gcc/cp/pt.cc.jj 2022-08-18 09:05:49.937120132 +0200 +++ gcc/cp/pt.cc 2022-09-01 18:35:47.558830758 +0200 @@ -17830,8 +17830,8 @@ tsubst_omp_clause_decl (tree decl, tree } /* Handle an OpenMP array section represented as a TREE_LIST (or - OMP_CLAUSE_DEPEND_KIND). An OMP_CLAUSE_DEPEND (with a depend - kind of OMP_CLAUSE_DEPEND_SINK) can also be represented as a + OMP_CLAUSE_DOACROSS_KIND). An OMP_CLAUSE_DOACROSS (with a depend + kind of OMP_CLAUSE_DOACROSS_SINK) can also be represented as a TREE_LIST. We can handle it exactly the same as an array section (purpose, value, and a chain), even though the nomenclature (low_bound, length, etc) is different. */ @@ -17849,8 +17849,8 @@ tsubst_omp_clause_decl (tree decl, tree && TREE_CHAIN (decl) == chain) return decl; tree ret = tree_cons (low_bound, length, chain); - OMP_CLAUSE_DEPEND_SINK_NEGATIVE (ret) - = OMP_CLAUSE_DEPEND_SINK_NEGATIVE (decl); + OMP_CLAUSE_DOACROSS_SINK_NEGATIVE (ret) + = OMP_CLAUSE_DOACROSS_SINK_NEGATIVE (decl); return ret; } tree ret = tsubst_expr (decl, args, complain, in_decl, @@ -17898,6 +17898,7 @@ tsubst_omp_clauses (tree clauses, enum c case OMP_CLAUSE_COPYPRIVATE: case OMP_CLAUSE_UNIFORM: case OMP_CLAUSE_DEPEND: + case OMP_CLAUSE_DOACROSS: case OMP_CLAUSE_AFFINITY: case OMP_CLAUSE_FROM: case OMP_CLAUSE_TO: @@ -19414,7 +19415,7 @@ tsubst_expr (tree t, tree args, tsubst_f r = RECUR (OMP_DEPOBJ_DEPOBJ (t)); if (OMP_DEPOBJ_CLAUSES (t) && OMP_DEPOBJ_CLAUSES (t) != error_mark_node) { - enum omp_clause_depend_kind kind = OMP_CLAUSE_DEPEND_SOURCE; + enum omp_clause_depend_kind kind = OMP_CLAUSE_DEPEND_INVALID; if (TREE_CODE (OMP_DEPOBJ_CLAUSES (t)) == OMP_CLAUSE) { tmp = tsubst_omp_clauses (OMP_DEPOBJ_CLAUSES (t), C_ORT_OMP, @@ -19432,7 +19433,7 @@ tsubst_expr (tree t, tree args, tsubst_f } else finish_omp_depobj (EXPR_LOCATION (t), r, - OMP_CLAUSE_DEPEND_SOURCE, + OMP_CLAUSE_DEPEND_INVALID, OMP_DEPOBJ_CLAUSES (t)); break; --- gcc/cp/semantics.cc.jj 2022-08-17 16:59:08.920548779 +0200 +++ gcc/cp/semantics.cc 2022-09-02 10:17:28.258285744 +0200 @@ -6477,13 +6477,13 @@ finish_omp_declare_simd_methods (tree t) } } -/* Adjust sink depend clause to take into account pointer offsets. +/* Adjust sink depend/doacross clause to take into account pointer offsets. Return TRUE if there was a problem processing the offset, and the whole clause should be removed. */ static bool -cp_finish_omp_clause_depend_sink (tree sink_clause) +cp_finish_omp_clause_doacross_sink (tree sink_clause) { tree t = OMP_CLAUSE_DECL (sink_clause); gcc_assert (TREE_CODE (t) == TREE_LIST); @@ -7795,21 +7795,18 @@ finish_omp_clauses (tree clauses, enum c } goto handle_field_decl; - case OMP_CLAUSE_DEPEND: + case OMP_CLAUSE_DOACROSS: t = OMP_CLAUSE_DECL (c); if (t == NULL_TREE) + break; + if (OMP_CLAUSE_DOACROSS_KIND (c) == OMP_CLAUSE_DOACROSS_SINK) { - gcc_assert (OMP_CLAUSE_DEPEND_KIND (c) - == OMP_CLAUSE_DEPEND_SOURCE); - break; - } - if (OMP_CLAUSE_DEPEND_KIND (c) == OMP_CLAUSE_DEPEND_SINK) - { - if (cp_finish_omp_clause_depend_sink (c)) + if (cp_finish_omp_clause_doacross_sink (c)) remove = true; break; } - /* FALLTHRU */ + gcc_unreachable (); + case OMP_CLAUSE_DEPEND: case OMP_CLAUSE_AFFINITY: t = OMP_CLAUSE_DECL (c); if (TREE_CODE (t) == TREE_LIST --- gcc/fortran/trans-openmp.cc.jj 2022-07-26 10:32:23.799270266 +0200 +++ gcc/fortran/trans-openmp.cc 2022-09-01 16:28:06.688191566 +0200 @@ -2897,7 +2897,7 @@ gfc_trans_omp_clauses (stmtblock_t *bloc } vec = tree_cons (addend, t, vec); if (neg) - OMP_CLAUSE_DEPEND_SINK_NEGATIVE (vec) = 1; + OMP_CLAUSE_DOACROSS_SINK_NEGATIVE (vec) = 1; } if (n->next == NULL || n->next->u.depend_op != OMP_DEPEND_SINK) @@ -2908,8 +2908,9 @@ gfc_trans_omp_clauses (stmtblock_t *bloc continue; tree node = build_omp_clause (input_location, - OMP_CLAUSE_DEPEND); - OMP_CLAUSE_DEPEND_KIND (node) = OMP_CLAUSE_DEPEND_SINK; + OMP_CLAUSE_DOACROSS); + OMP_CLAUSE_DOACROSS_KIND (node) = OMP_CLAUSE_DOACROSS_SINK; + OMP_CLAUSE_DOACROSS_DEPEND (node) = 1; OMP_CLAUSE_DECL (node) = nreverse (vec); omp_clauses = gfc_trans_add_clause (node, omp_clauses); continue; @@ -4254,8 +4255,9 @@ gfc_trans_omp_clauses (stmtblock_t *bloc if (clauses->depend_source) { - c = build_omp_clause (gfc_get_location (&where), OMP_CLAUSE_DEPEND); - OMP_CLAUSE_DEPEND_KIND (c) = OMP_CLAUSE_DEPEND_SOURCE; + c = build_omp_clause (gfc_get_location (&where), OMP_CLAUSE_DOACROSS); + OMP_CLAUSE_DOACROSS_KIND (c) = OMP_CLAUSE_DOACROSS_SOURCE; + OMP_CLAUSE_DOACROSS_DEPEND (c) = 1; omp_clauses = gfc_trans_add_clause (c, omp_clauses); } --- gcc/testsuite/c-c++-common/gomp/doacross-2.c.jj 2020-01-12 11:54:37.013404356 +0100 +++ gcc/testsuite/c-c++-common/gomp/doacross-2.c 2022-09-02 18:13:24.093620768 +0200 @@ -7,13 +7,13 @@ foo (void) #pragma omp for ordered(1) for (i = 0; i < 64; i++) { - #pragma omp ordered /* { dg-error "'ordered' region without 'depend' clause may not be closely nested inside a loop region with an 'ordered' clause with a parameter" } */ + #pragma omp ordered ; } #pragma omp for ordered(1) for (i = 0; i < 64; i++) { - #pragma omp ordered threads /* { dg-error "'ordered' region without 'depend' clause may not be closely nested inside a loop region with an 'ordered' clause with a parameter" } */ + #pragma omp ordered threads ; } } @@ -25,14 +25,20 @@ bar (void) #pragma omp for ordered for (i = 0; i < 64; i++) { - #pragma omp ordered depend(source) /* { dg-error "'ordered' construct with 'depend' clause must be closely nested inside a loop with 'ordered' clause with a parameter" } */ - #pragma omp ordered depend(sink: i - 1) /* { dg-error "'ordered' construct with 'depend' clause must be closely nested inside a loop with 'ordered' clause with a parameter" } */ + #pragma omp ordered depend(source) + #pragma omp ordered depend(sink: i - 1) + } + #pragma omp for ordered + for (i = 0; i < 64; i++) + { + #pragma omp ordered doacross(source:) + #pragma omp ordered doacross(sink: i - 1) } #pragma omp for for (i = 0; i < 64; i++) { - #pragma omp ordered depend(source) /* { dg-error "'ordered' construct with 'depend' clause must be closely nested inside a loop with 'ordered' clause with a parameter" } */ - #pragma omp ordered depend(sink: i - 1) /* { dg-error "'ordered' construct with 'depend' clause must be closely nested inside a loop with 'ordered' clause with a parameter" } */ + #pragma omp ordered depend(source) /* { dg-error "'ordered' construct with 'depend' clause must be closely nested inside a loop with 'ordered' clause" } */ + #pragma omp ordered depend(sink: i - 1) /* { dg-error "'ordered' construct with 'depend' clause must be closely nested inside a loop with 'ordered' clause" } */ } #pragma omp for for (i = 0; i < 64; i++) --- gcc/testsuite/c-c++-common/gomp/doacross-5.c.jj 2022-09-02 18:22:03.664570763 +0200 +++ gcc/testsuite/c-c++-common/gomp/doacross-5.c 2022-09-02 18:51:07.090930910 +0200 @@ -0,0 +1,94 @@ +void +foo (int n) +{ + int i; + #pragma omp for ordered + for (i = 0; i < 8; i += n) + { + #pragma omp ordered doacross(source:) + #pragma omp ordered doacross(sink: i - 2) + } +} + +void +bar (int n) +{ + int i, j; + #pragma omp for collapse(2) ordered(2) + for (i = 0; i < 8; i += n) + for (j = 0; j < 8; j += n) + { + #pragma omp ordered doacross(source:omp_cur_iteration) + #pragma omp ordered doacross(sink: i - 2, j + 2) + } +} + +void +baz (void) +{ + int i, j; + #pragma omp for ordered(1) + for (i = 0; i < 64; i++) + { + #pragma omp ordered /* { dg-error "'ordered' construct without 'doacross' or 'depend' clauses must not have the same binding region as 'ordered' construct with those clauses" } */ + ; + #pragma omp ordered doacross(source:) + #pragma omp ordered doacross(sink: i - 1) + } + #pragma omp for ordered + for (i = 0; i < 64; i++) + { + #pragma omp ordered doacross(source: omp_cur_iteration ) + #pragma omp ordered doacross(sink: i - 1) + #pragma omp ordered threads /* { dg-error "'ordered' construct without 'doacross' or 'depend' clauses must not have the same binding region as 'ordered' construct with those clauses" } */ + ; + } + #pragma omp for ordered(2) + for (i = 0; i < 8; i++) + for (j = 0; j < 8; j++) + { + #pragma omp ordered /* { dg-error "'ordered' construct without 'doacross' or 'depend' clauses binds to loop where 'collapse' argument 1 is different from 'ordered' argument 2" } */ + ; + } + #pragma omp for ordered(2) collapse(1) + for (i = 0; i < 8; i++) + for (j = 0; j < 8; j++) + { + #pragma omp ordered threads /* { dg-error "'ordered' construct without 'doacross' or 'depend' clauses binds to loop where 'collapse' argument 1 is different from 'ordered' argument 2" } */ + ; + } +} + +void +qux (void) +{ + int i, j = 0; + #pragma omp for ordered linear(j) + for (i = 0; i < 64; i++) + { + ++j; + #pragma omp ordered + ; + } + #pragma omp for ordered linear(j) /* { dg-error "'linear' clause may not be specified together with 'ordered' clause if stand-alone 'ordered' construct is nested in it" } */ + for (i = 0; i < 64; i++) + { + ++j; + #pragma omp ordered doacross(source:) + #pragma omp ordered doacross(sink:i-1) + } + #pragma omp for ordered(1) linear(j) + for (i = 0; i < 64; i++) + { + ++j; + #pragma omp ordered + ; + } + #pragma omp for ordered(1) linear(j) /* { dg-error "'linear' clause may not be specified together with 'ordered' clause if stand-alone 'ordered' construct is nested in it" } */ + for (i = 0; i < 64; i++) + { + ++j; + #pragma omp ordered doacross(source:) + #pragma omp ordered doacross(sink:i-1) + } +} --- gcc/testsuite/c-c++-common/gomp/doacross-6.c.jj 2022-09-02 18:38:41.584036829 +0200 +++ gcc/testsuite/c-c++-common/gomp/doacross-6.c 2022-09-02 19:04:38.568922196 +0200 @@ -0,0 +1,74 @@ +void +foo (int n) +{ + int i; + #pragma omp for ordered + for (i = 0; i < 8; i += n) + { + #pragma omp ordered doacross(source) /* { dg-error "expected ':' before '\\\)' token" } */ + } + #pragma omp for ordered + for (i = 0; i < 8; i += n) + { + #pragma omp ordered doacross(source:omp_current_iteration) /* { dg-error "expected '\\\)' before 'omp_current_iteration'" } */ + } + #pragma omp for ordered + for (i = 0; i < 8; i += n) + { + #pragma omp ordered doacross(source:i - 2) /* { dg-error "expected '\\\)' before 'i'" } */ + } + #pragma omp for ordered + for (i = 0; i < 8; i += n) + { + #pragma omp ordered doacross(sink) /* { dg-error "expected ':' before '\\\)' token" } */ + } +} + +void +bar (int n) +{ + int i; + #pragma omp for ordered + for (i = 0; i < 8; i += n) + { + #pragma omp ordered doacross(sink:omp_current_iteration - 1) /* { dg-error "'omp_current_iteration' undeclared \\\(first use in this function\\\)" "" { target c } } */ + } /* { dg-error "'omp_current_iteration' has not been declared" "" { target c++ } .-1 } */ + #pragma omp for ordered + for (i = 0; i < 8; i += n) + { + #pragma omp ordered doacross(sink:omp_cur_iteration) /* { dg-error "'omp_cur_iteration' undeclared \\\(first use in this function\\\)" "" { target c } } */ + } /* { dg-error "'omp_cur_iteration' has not been declared" "" { target c++ } .-1 } */ +} + +void +baz (int n) +{ + int i; + #pragma omp for ordered + for (i = 0; i < 8; i += n) + { + #pragma omp ordered doacross(sink:omp_cur_iteration + 1) /* { dg-error "'omp_cur_iteration' undeclared \\\(first use in this function\\\)" "" { target c } } */ + } /* { dg-error "'omp_cur_iteration' has not been declared" "" { target c++ } .-1 } */ +} + +void +qux (int n) +{ + int i; + #pragma omp for ordered + for (i = 0; i < 8; i += n) + { + #pragma omp ordered doacross(sink:omp_cur_iteration - (2 - 1)) /* { dg-error "'omp_cur_iteration' undeclared \\\(first use in this function\\\)" "" { target c } } */ + } /* { dg-error "expected integer before '\\\(' token" "" { target *-*-* } .-1 } */ +} /* { dg-error "'omp_cur_iteration' has not been declared" "" { target c++ } .-2 } */ + /* { dg-error "expected '\\\)' before '\\\(' token" "" { target c++ } .-3 } */ +void +corge (int n) +{ + int i; + #pragma omp for ordered + for (i = 0; i < 8; i += n) + { + #pragma omp ordered doacross(sink:omp_cur_iteration - 1LL) /* { dg-error "'omp_cur_iteration' undeclared \\\(first use in this function\\\)" "" { target c } } */ + } /* { dg-error "'omp_cur_iteration' has not been declared" "" { target c++ } .-1 } */ +} --- gcc/testsuite/c-c++-common/gomp/nesting-2.c.jj 2021-08-17 09:29:41.408204898 +0200 +++ gcc/testsuite/c-c++-common/gomp/nesting-2.c 2022-09-02 17:37:47.252606491 +0200 @@ -160,7 +160,14 @@ foo (void) for (i = 0; i < 64; i++) #pragma omp parallel { - #pragma omp ordered depend(source) /* { dg-error ".ordered. construct with .depend. clause must be closely nested inside a loop with .ordered. clause with a parameter" } */ - #pragma omp ordered depend(sink: i - 1) /* { dg-error ".ordered. construct with .depend. clause must be closely nested inside a loop with .ordered. clause with a parameter" } */ + #pragma omp ordered depend(source) /* { dg-error ".ordered. construct with .depend. clause must be closely nested inside a loop with .ordered. clause" } */ + #pragma omp ordered depend(sink: i - 1) /* { dg-error ".ordered. construct with .depend. clause must be closely nested inside a loop with .ordered. clause" } */ + } + #pragma omp for ordered(1) + for (i = 0; i < 64; i++) + #pragma omp parallel + { + #pragma omp ordered doacross(source:) /* { dg-error ".ordered. construct with .doacross. clause must be closely nested inside a loop with .ordered. clause" } */ + #pragma omp ordered doacross(sink: i - 1) /* { dg-error ".ordered. construct with .doacross. clause must be closely nested inside a loop with .ordered. clause" } */ } } --- gcc/testsuite/c-c++-common/gomp/ordered-3.c.jj 2020-01-12 11:54:37.014404341 +0100 +++ gcc/testsuite/c-c++-common/gomp/ordered-3.c 2022-09-02 17:47:30.751700196 +0200 @@ -47,29 +47,53 @@ foo (void) #pragma omp ordered threads, simd, threads, simd /* { dg-error "too many .threads. clauses" } */ ; /* { dg-error "too many .simd. clauses" "" { target *-*-* } .-1 } */ } - #pragma omp for simd ordered(1) /* { dg-error ".ordered. clause with parameter may not be specified on .#pragma omp for simd. construct" } */ + #pragma omp for simd ordered(1) for (i = 0; i < 64; i++) { - #pragma omp ordered depend(sink: i - 1) /* { dg-error "clause must be closely nested inside a loop with .ordered. clause with a parameter" } */ - #pragma omp ordered depend(source) /* { dg-error "clause must be closely nested inside a loop with .ordered. clause with a parameter" } */ + #pragma omp ordered depend(sink: i - 1) /* { dg-error "clause must be closely nested inside a loop with .ordered. clause" } */ + #pragma omp ordered depend(source) /* { dg-error "clause must be closely nested inside a loop with .ordered. clause" } */ } - #pragma omp parallel for simd ordered(1) /* { dg-error ".ordered. clause with parameter may not be specified on .#pragma omp parallel for simd. construct" } */ + #pragma omp for simd ordered(1) for (i = 0; i < 64; i++) { - #pragma omp ordered depend(sink: i - 1) /* { dg-error "clause must be closely nested inside a loop with .ordered. clause with a parameter" } */ - #pragma omp ordered depend(source) /* { dg-error "clause must be closely nested inside a loop with .ordered. clause with a parameter" } */ + #pragma omp ordered doacross(sink: i - 1) /* { dg-error "clause must be closely nested inside a loop with .ordered. clause" } */ + #pragma omp ordered doacross(source:omp_cur_iteration) /* { dg-error "clause must be closely nested inside a loop with .ordered. clause" } */ + } + #pragma omp parallel for simd ordered(1) + for (i = 0; i < 64; i++) + { + #pragma omp ordered depend(sink: i - 1) /* { dg-error "clause must be closely nested inside a loop with .ordered. clause" } */ + #pragma omp ordered depend(source) /* { dg-error "clause must be closely nested inside a loop with .ordered. clause" } */ + } + #pragma omp parallel for simd ordered(1) + for (i = 0; i < 64; i++) + { + #pragma omp ordered doacross(sink: i - 1) /* { dg-error "clause must be closely nested inside a loop with .ordered. clause" } */ + #pragma omp ordered doacross(source:) /* { dg-error "clause must be closely nested inside a loop with .ordered. clause" } */ + } + #pragma omp parallel for ordered + for (i = 0; i < 64; i++) + { + #pragma omp ordered depend(sink: i - 1) + #pragma omp ordered depend(source) } #pragma omp parallel for ordered for (i = 0; i < 64; i++) { - #pragma omp ordered depend(sink: i - 1) /* { dg-error "clause must be closely nested inside a loop with .ordered. clause with a parameter" } */ - #pragma omp ordered depend(source) /* { dg-error "clause must be closely nested inside a loop with .ordered. clause with a parameter" } */ + #pragma omp ordered doacross(sink: i - 1) + #pragma omp ordered doacross(source:) + } + #pragma omp parallel for + for (i = 0; i < 64; i++) + { + #pragma omp ordered depend(sink: i - 1) /* { dg-error "clause must be closely nested inside a loop with .ordered. clause" } */ + #pragma omp ordered depend(source) /* { dg-error "clause must be closely nested inside a loop with .ordered. clause" } */ } #pragma omp parallel for for (i = 0; i < 64; i++) { - #pragma omp ordered depend(sink: i - 1) /* { dg-error "clause must be closely nested inside a loop with .ordered. clause with a parameter" } */ - #pragma omp ordered depend(source) /* { dg-error "clause must be closely nested inside a loop with .ordered. clause with a parameter" } */ + #pragma omp ordered doacross(sink: i - 1) /* { dg-error "clause must be closely nested inside a loop with .ordered. clause" } */ + #pragma omp ordered doacross(source:) /* { dg-error "clause must be closely nested inside a loop with .ordered. clause" } */ } } --- gcc/testsuite/c-c++-common/gomp/sink-3.c.jj 2020-01-12 11:54:37.016404311 +0100 +++ gcc/testsuite/c-c++-common/gomp/sink-3.c 2022-09-02 18:09:01.480185433 +0200 @@ -14,7 +14,7 @@ foo () for (i=0; i < 100; ++i) { #pragma omp ordered depend(sink:poo-1,paa+1) /* { dg-error "poo.*declared.*paa.*declared" } */ - bar(&i); /* { dg-error "may not be closely nested" "" { target *-*-* } .-1 } */ + bar(&i); /* { dg-error "must not have the same binding region" "" { target *-*-* } .-1 } */ #pragma omp ordered depend(source) } } --- gcc/testsuite/gfortran.dg/gomp/nesting-2.f90.jj 2021-08-17 16:34:31.610102996 +0200 +++ gcc/testsuite/gfortran.dg/gomp/nesting-2.f90 2022-09-02 18:15:10.209180367 +0200 @@ -158,8 +158,8 @@ subroutine foo !$omp do ordered(1) do i = 0, 63 !$omp parallel - !$omp ordered depend(source) ! { dg-error ".ordered. construct with .depend. clause must be closely nested inside a loop with .ordered. clause with a parameter" } - !$omp ordered depend(sink: i - 1) ! { dg-error ".ordered. construct with .depend. clause must be closely nested inside a loop with .ordered. clause with a parameter" } + !$omp ordered depend(source) ! { dg-error ".ordered. construct with .depend. clause must be closely nested inside a loop with .ordered. clause" } + !$omp ordered depend(sink: i - 1) ! { dg-error ".ordered. construct with .depend. clause must be closely nested inside a loop with .ordered. clause" } !$omp end parallel end do end Jakub