From patchwork Thu Nov 25 14:07:17 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Julian Brown X-Patchwork-Id: 1559728 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=gcc.gnu.org (client-ip=8.43.85.97; helo=sourceware.org; envelope-from=gcc-patches-bounces+incoming=patchwork.ozlabs.org@gcc.gnu.org; receiver=) Received: from sourceware.org (ip-8-43-85-97.sourceware.org [8.43.85.97]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by bilbo.ozlabs.org (Postfix) with ESMTPS id 4J0KTw2fltz9sVc for ; Fri, 26 Nov 2021 01:08:20 +1100 (AEDT) Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 3F1C03858036 for ; Thu, 25 Nov 2021 14:08:18 +0000 (GMT) X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from esa2.mentor.iphmx.com (esa2.mentor.iphmx.com [68.232.141.98]) by sourceware.org (Postfix) with ESMTPS id EB2B33858D3C for ; Thu, 25 Nov 2021 14:07:37 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org EB2B33858D3C Authentication-Results: sourceware.org; dmarc=none (p=none dis=none) header.from=codesourcery.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=mentor.com IronPort-SDR: i/9nk6h+91t4zlzPuxISusZ1ctOSc9XtV1K9ACRZ0gBY1DRfrrCzNUd+mD4ljjBCuw0ReD2Vfi bx96+71ESpWdbJ7D9cJ3zcx7HeOz0j9O6+rvAyX8kbz/V6gmfg9R9DXD0Q7ZPH+Q6n/PjhEnSZ n9m8W3zLnY0fKnuo0J53wf80LH6Ehwf2Bn5+ExSi54ejLcj39vpJwC87PQ+EVwbeD42X1pfxBd l7HQg1y9Vl32OPPOhLnI7+COgozGUv0ACg94NQIG2tIgM4ecwZweZf0w3x+LulURneyQxNBG0K RZoRnrBxM2bstHBOaK18TwjF X-IronPort-AV: E=Sophos;i="5.87,263,1631606400"; d="scan'208";a="68920765" Received: from orw-gwy-02-in.mentorg.com ([192.94.38.167]) by esa2.mentor.iphmx.com with ESMTP; 25 Nov 2021 06:07:36 -0800 IronPort-SDR: 8sBnKCVUtQ4Iku52ZBTN2uHaVD9Zgi5n8x7iK/nyYEA2SgGK5xgLXNf927RfStS2vRxFRTcZxR ghzUqKzvzB0Pf0F3NIAuSHz21SwV5a6nNN8zUKzNKAkpCLMSj54nfAT4QepJ4OT6nDqU7jAW4O 7fpYmmoJWPasl6dRmUB93yQT31OM/Qe5z1+RVGQ1xp2a6tLKrxn/qT1ub8/vNNqTd1izyYSLWu 6aTLdJ8WRqDhlanUBOlga3/3JcZhypX6u0pRch9+/dVdAhRNS7slAlyMkFfFMqOJsVXqpaBLvP BMQ= From: Julian Brown To: Subject: [PATCH 01/16] Rewrite GOMP_MAP_ATTACH_DETACH mappings unconditionally Date: Thu, 25 Nov 2021 06:07:17 -0800 Message-ID: <20211125140720.108885-2-julian@codesourcery.com> X-Mailer: git-send-email 2.29.2 In-Reply-To: <20211125140720.108885-1-julian@codesourcery.com> References: <20211125140720.108885-1-julian@codesourcery.com> MIME-Version: 1.0 X-Originating-IP: [137.202.0.90] X-ClientProxiedBy: svr-ies-mbx-12.mgc.mentorg.com (139.181.222.12) To SVR-IES-MBX-04.mgc.mentorg.com (139.181.222.4) X-Spam-Status: No, score=-11.8 required=5.0 tests=BAYES_00, GIT_PATCH_0, HEADER_FROM_DIFFERENT_DOMAINS, KAM_DMARC_STATUS, KAM_SHORT, SPF_HELO_PASS, SPF_PASS, 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: , Cc: Jakub Jelinek , Thomas Schwinge Errors-To: gcc-patches-bounces+incoming=patchwork.ozlabs.org@gcc.gnu.org Sender: "Gcc-patches" It never makes sense for a GOMP_MAP_ATTACH_DETACH mapping to survive beyond gimplify.c, so this patch rewrites such mappings to GOMP_MAP_ATTACH or GOMP_MAP_DETACH unconditionally (rather than checking for a list of types of OpenACC or OpenMP constructs), in cases where it hasn't otherwise been done already in the preceding code. Previously posted here: https://gcc.gnu.org/pipermail/gcc-patches/2021-May/570399.html https://gcc.gnu.org/pipermail/gcc-patches/2021-June/571711.html (og11) OK? Thanks, Julian 2021-06-02 Julian Brown gcc/ * gimplify.c (gimplify_scan_omp_clauses): Simplify condition for changing GOMP_MAP_ATTACH_DETACH to GOMP_MAP_ATTACH or GOMP_MAP_DETACH. --- gcc/gimplify.c | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/gcc/gimplify.c b/gcc/gimplify.c index 4cd62270a10..8d8735ae4c1 100644 --- a/gcc/gimplify.c +++ b/gcc/gimplify.c @@ -9965,15 +9965,7 @@ gimplify_scan_omp_clauses (tree *list_p, gimple_seq *pre_p, skip_map_struct: ; } - else if ((code == OACC_ENTER_DATA - || code == OACC_EXIT_DATA - || code == OACC_DATA - || code == OACC_PARALLEL - || code == OACC_KERNELS - || code == OACC_SERIAL - || code == OMP_TARGET_ENTER_DATA - || code == OMP_TARGET_EXIT_DATA) - && OMP_CLAUSE_MAP_KIND (c) == GOMP_MAP_ATTACH_DETACH) + else if (OMP_CLAUSE_MAP_KIND (c) == GOMP_MAP_ATTACH_DETACH) { gomp_map_kind k = ((code == OACC_EXIT_DATA || code == OMP_TARGET_EXIT_DATA) From patchwork Thu Nov 25 14:07:18 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Julian Brown X-Patchwork-Id: 1559729 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=gcc.gnu.org (client-ip=2620:52:3:1:0:246e:9693:128c; helo=sourceware.org; envelope-from=gcc-patches-bounces+incoming=patchwork.ozlabs.org@gcc.gnu.org; receiver=) Received: from sourceware.org (server2.sourceware.org [IPv6:2620:52:3:1:0:246e:9693:128c]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by bilbo.ozlabs.org (Postfix) with ESMTPS id 4J0KVV2N2Zz9sVc for ; Fri, 26 Nov 2021 01:08:50 +1100 (AEDT) Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 8E86A385842A for ; Thu, 25 Nov 2021 14:08:47 +0000 (GMT) X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from esa2.mentor.iphmx.com (esa2.mentor.iphmx.com [68.232.141.98]) by sourceware.org (Postfix) with ESMTPS id 60707385841A for ; Thu, 25 Nov 2021 14:07:40 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org 60707385841A Authentication-Results: sourceware.org; dmarc=none (p=none dis=none) header.from=codesourcery.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=mentor.com IronPort-SDR: Y+kdwXDD5kcD44AG8Q2wLKcGBEv27hedmLkc8ugcL+SwiKdil5d0QHMZli/bqYYdpqOsHMd8ph O4WtNc7SUx0nLL/bIgJ85e/rbXWHEjucj+Ixqa//vGERWSpMK4VdyhQC86+jE/H4/W6yUNNlNu fncQT8J06oeuPMytKq0i/4XPgip0miE/ZgKnIWlngZzoz/73S+6ySeDDZ1P9ExRT7Qn0TKsBKx PoL4j7+R+A0LXh2UKKCep+xgzx9Fyn2m/BX36Fl4+bWkuTFJx0SNAuMQgQUZNh49F7zC+2ZYzp TSG0rTxy5GXSOh+c7RdSLdcc X-IronPort-AV: E=Sophos;i="5.87,263,1631606400"; d="scan'208";a="68920767" Received: from orw-gwy-02-in.mentorg.com ([192.94.38.167]) by esa2.mentor.iphmx.com with ESMTP; 25 Nov 2021 06:07:39 -0800 IronPort-SDR: LMCGdGT2bZTYRoRVXth5Rv9cqmyst12pmv9vSlkgNAGmJs+mu70bv6SKPeGpeckLELYbnacisv U2i5I9mbzvR/eYVPgDSYRbSd94NqTmcBBBwjZtkyV1tVG7QgiONnXNfZjmB9E8MHTuqPSXnC8p 39RjgzOIAHsNbL8Lz6sBKG2JaLBUhGOTlM/ZCILBY68bGG4N60ib8S1NB05frIYpgOjaHGvAgr 8K5gGtHUDUh7lGeH8bgq9KEApoOGKVDYbJrXLM4ioJJROBL9Ze/2rHlgQ5/D7Ow5RDTNHDQRni YQU= From: Julian Brown To: Subject: [PATCH 02/16] OpenMP/OpenACC: Move array_ref/indirect_ref handling code out of extract_base_bit_offset Date: Thu, 25 Nov 2021 06:07:18 -0800 Message-ID: <20211125140720.108885-3-julian@codesourcery.com> X-Mailer: git-send-email 2.29.2 In-Reply-To: <20211125140720.108885-1-julian@codesourcery.com> References: <20211125140720.108885-1-julian@codesourcery.com> MIME-Version: 1.0 X-Originating-IP: [137.202.0.90] X-ClientProxiedBy: svr-ies-mbx-12.mgc.mentorg.com (139.181.222.12) To SVR-IES-MBX-04.mgc.mentorg.com (139.181.222.4) X-Spam-Status: No, score=-11.8 required=5.0 tests=BAYES_00, GIT_PATCH_0, HEADER_FROM_DIFFERENT_DOMAINS, KAM_DMARC_STATUS, KAM_SHORT, SPF_HELO_PASS, SPF_PASS, 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: , Cc: Jakub Jelinek , Thomas Schwinge Errors-To: gcc-patches-bounces+incoming=patchwork.ozlabs.org@gcc.gnu.org Sender: "Gcc-patches" This patch slightly cleans up the semantics of extract_base_bit_offset, in that the stripping of ARRAY_REFS/INDIRECT_REFS out of extract_base_bit_offset is moved back into the (two) call sites of the function. This is done in preparation for follow-on patches that extend the function. Previously posted for the og11 branch here (patch & reversion/rework): https://gcc.gnu.org/pipermail/gcc-patches/2021-June/571712.html https://gcc.gnu.org/pipermail/gcc-patches/2021-June/571884.html OK? Thanks, Julian 2021-06-03 Julian Brown gcc/ * gimplify.c (extract_base_bit_offset): Don't look through ARRAY_REFs or INDIRECT_REFs here. (build_struct_group): Reinstate previous behaviour for handling ARRAY_REFs/INDIRECT_REFs. --- gcc/gimplify.c | 59 +++++++++++++++++++++++++------------------------- 1 file changed, 29 insertions(+), 30 deletions(-) diff --git a/gcc/gimplify.c b/gcc/gimplify.c index 8d8735ae4c1..1baea68920b 100644 --- a/gcc/gimplify.c +++ b/gcc/gimplify.c @@ -8675,31 +8675,7 @@ extract_base_bit_offset (tree base, tree *base_ref, poly_int64 *bitposp, poly_offset_int poffset; if (base_ref) - { - *base_ref = NULL_TREE; - - while (TREE_CODE (base) == ARRAY_REF) - base = TREE_OPERAND (base, 0); - - if (TREE_CODE (base) == INDIRECT_REF) - base = TREE_OPERAND (base, 0); - } - else - { - if (TREE_CODE (base) == ARRAY_REF) - { - while (TREE_CODE (base) == ARRAY_REF) - base = TREE_OPERAND (base, 0); - if (TREE_CODE (base) != COMPONENT_REF - || TREE_CODE (TREE_TYPE (base)) != ARRAY_TYPE) - return NULL_TREE; - } - else if (TREE_CODE (base) == INDIRECT_REF - && TREE_CODE (TREE_OPERAND (base, 0)) == COMPONENT_REF - && (TREE_CODE (TREE_TYPE (TREE_OPERAND (base, 0))) - == REFERENCE_TYPE)) - base = TREE_OPERAND (base, 0); - } + *base_ref = NULL_TREE; base = get_inner_reference (base, &bitsize, &bitpos, &offset, &mode, &unsignedp, &reversep, &volatilep); @@ -9673,12 +9649,17 @@ gimplify_scan_omp_clauses (tree *list_p, gimple_seq *pre_p, poly_offset_int offset1; poly_int64 bitpos1; tree tree_offset1; - tree base_ref; + tree base_ref, ocd = OMP_CLAUSE_DECL (c); - tree base - = extract_base_bit_offset (OMP_CLAUSE_DECL (c), &base_ref, - &bitpos1, &offset1, - &tree_offset1); + while (TREE_CODE (ocd) == ARRAY_REF) + ocd = TREE_OPERAND (ocd, 0); + + if (TREE_CODE (ocd) == INDIRECT_REF) + ocd = TREE_OPERAND (ocd, 0); + + tree base = extract_base_bit_offset (ocd, &base_ref, + &bitpos1, &offset1, + &tree_offset1); bool do_map_struct = (base == decl && !tree_offset1); @@ -9871,6 +9852,24 @@ gimplify_scan_omp_clauses (tree *list_p, gimple_seq *pre_p, poly_offset_int offsetn; poly_int64 bitposn; tree tree_offsetn; + + if (TREE_CODE (sc_decl) == ARRAY_REF) + { + while (TREE_CODE (sc_decl) == ARRAY_REF) + sc_decl = TREE_OPERAND (sc_decl, 0); + if (TREE_CODE (sc_decl) != COMPONENT_REF + || (TREE_CODE (TREE_TYPE (sc_decl)) + != ARRAY_TYPE)) + break; + } + else if (TREE_CODE (sc_decl) == INDIRECT_REF + && (TREE_CODE (TREE_OPERAND (sc_decl, 0)) + == COMPONENT_REF) + && (TREE_CODE (TREE_TYPE + (TREE_OPERAND (sc_decl, 0))) + == REFERENCE_TYPE)) + sc_decl = TREE_OPERAND (sc_decl, 0); + tree base = extract_base_bit_offset (sc_decl, NULL, &bitposn, &offsetn, From patchwork Thu Nov 25 14:07:19 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Julian Brown X-Patchwork-Id: 1559730 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=gcc.gnu.org (client-ip=2620:52:3:1:0:246e:9693:128c; helo=sourceware.org; envelope-from=gcc-patches-bounces+incoming=patchwork.ozlabs.org@gcc.gnu.org; receiver=) Received: from sourceware.org (server2.sourceware.org [IPv6:2620:52:3:1:0:246e:9693:128c]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by bilbo.ozlabs.org (Postfix) with ESMTPS id 4J0KWB0ZkTz9sVc for ; Fri, 26 Nov 2021 01:09:26 +1100 (AEDT) Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id ED4813858020 for ; Thu, 25 Nov 2021 14:09:23 +0000 (GMT) X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from esa2.mentor.iphmx.com (esa2.mentor.iphmx.com [68.232.141.98]) by sourceware.org (Postfix) with ESMTPS id C099D385800A for ; Thu, 25 Nov 2021 14:07:44 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org C099D385800A Authentication-Results: sourceware.org; dmarc=none (p=none dis=none) header.from=codesourcery.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=mentor.com IronPort-SDR: V6IgUS6oJy0fpMpZBkZ34MwPp6CJ5jXW/TDyY/6escDnN5sn0QT6SJE0a4B3F/1ofqCUAFlnnX jpzhHuwUcOOOKq9Y7W5umZslw/k2asYwZEdzCG+lObq2Yr+Nght2arRMMZsvty1sCnJ1YvMccv WT0dSI94A2pnmer3PO4hxtVIjOOUtpxv3hkBg0wi6Kph9YSmAB+8KfuRlM3ytKmXCqYiEYrkns Z0AmVduS9uSQO+hwMZuPfxXl1qniiDMANdgA2EDIz9uiq6/cPbOyhehhOCfn2i+bXmiC4oK1fO 1GPlpgczGH0oBkqo0uF3KBSx X-IronPort-AV: E=Sophos;i="5.87,263,1631606400"; d="scan'208";a="68920769" Received: from orw-gwy-02-in.mentorg.com ([192.94.38.167]) by esa2.mentor.iphmx.com with ESMTP; 25 Nov 2021 06:07:43 -0800 IronPort-SDR: ITorw8c9uQZOPyVQaKL8o6zYVPs55yZ+QdvRWEb8peoeczwBtJHYGxSetyiFjhSOwXY1Cwcrzs OE8q2ZKVLmOtCW1v3W4Kv01Roorv1WjWtgTkE9JMV4gTukzdtWDl3FwU5eFeqVmMLZXBMBACj8 7Orlks1wWzNSvx3i7FYce/B+gE0VLtqtCcx/7FoQM+iykVCOYvXfM0srWPlzvijBVGZGQr6FIT jhgTekV0ZnV1yoz8uoyNnwvao3WVZsUbWkOrlz4w60HEWLu88x0GHpnxEKilzaxKcIb79sgN1C qgI= From: Julian Brown To: Subject: [PATCH 03/16] OpenACC/OpenMP: Refactor struct lowering in gimplify.c Date: Thu, 25 Nov 2021 06:07:19 -0800 Message-ID: <20211125140720.108885-4-julian@codesourcery.com> X-Mailer: git-send-email 2.29.2 In-Reply-To: <20211125140720.108885-1-julian@codesourcery.com> References: <20211125140720.108885-1-julian@codesourcery.com> MIME-Version: 1.0 X-Originating-IP: [137.202.0.90] X-ClientProxiedBy: svr-ies-mbx-12.mgc.mentorg.com (139.181.222.12) To SVR-IES-MBX-04.mgc.mentorg.com (139.181.222.4) X-Spam-Status: No, score=-11.4 required=5.0 tests=BAYES_00, GIT_PATCH_0, HEADER_FROM_DIFFERENT_DOMAINS, KAM_ASCII_DIVIDERS, KAM_DMARC_STATUS, KAM_SHORT, SPF_HELO_PASS, SPF_PASS, 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: , Cc: Jakub Jelinek , Thomas Schwinge Errors-To: gcc-patches-bounces+incoming=patchwork.ozlabs.org@gcc.gnu.org Sender: "Gcc-patches" (Previously submitted here: https://gcc.gnu.org/pipermail/gcc-patches/2021-May/570398.html) This patch is a second attempt at refactoring struct component mapping handling for OpenACC/OpenMP during gimplification, after the patch I posted here: https://gcc.gnu.org/pipermail/gcc-patches/2018-November/510503.html And improved here, post-review: https://gcc.gnu.org/pipermail/gcc-patches/2019-November/533394.html This patch goes further, in that the struct-handling code is outlined into its own function (to create the "GOMP_MAP_STRUCT" node and the sorted list of nodes immediately following it, from a set of mappings of components of a given struct or derived type). I've also gone through the list-handling code and attempted to add comments documenting how it works to the best of my understanding, and broken out a couple of helper functions in order to (hopefully) have the code self-document better also. OK? Thanks, Julian 2021-06-02 Julian Brown gcc/ * gimplify.c (insert_struct_comp_map): Refactor function into... (build_struct_comp_nodes): This new function. Remove list handling and improve self-documentation. (insert_node_after, move_node_after, move_nodes_after, move_concat_nodes_after): New helper functions. (build_struct_group): New function to build up GOMP_MAP_STRUCT node groups to map struct components. Outlined from... (gimplify_scan_omp_clauses): Here. Call above function. --- gcc/gimplify.c | 976 +++++++++++++++++++++++++++++++------------------ 1 file changed, 611 insertions(+), 365 deletions(-) diff --git a/gcc/gimplify.c b/gcc/gimplify.c index 1baea68920b..c5e058d6d1f 100644 --- a/gcc/gimplify.c +++ b/gcc/gimplify.c @@ -8588,73 +8588,66 @@ gimplify_omp_depend (tree *list_p, gimple_seq *pre_p) return 1; } -/* Insert a GOMP_MAP_ALLOC or GOMP_MAP_RELEASE node following a - GOMP_MAP_STRUCT mapping. C is an always_pointer mapping. STRUCT_NODE is - the struct node to insert the new mapping after (when the struct node is - initially created). PREV_NODE is the first of two or three mappings for a - pointer, and is either: - - the node before C, when a pair of mappings is used, e.g. for a C/C++ - array section. - - not the node before C. This is true when we have a reference-to-pointer - type (with a mapping for the reference and for the pointer), or for - Fortran derived-type mappings with a GOMP_MAP_TO_PSET. - If SCP is non-null, the new node is inserted before *SCP. - if SCP is null, the new node is inserted before PREV_NODE. - The return type is: - - PREV_NODE, if SCP is non-null. - - The newly-created ALLOC or RELEASE node, if SCP is null. - - The second newly-created ALLOC or RELEASE node, if we are mapping a - reference to a pointer. */ +/* For a set of mappings describing an array section pointed to by a struct + (or derived type, etc.) component, create an "alloc" or "release" node to + insert into a list following a GOMP_MAP_STRUCT node. For some types of + mapping (e.g. Fortran arrays with descriptors), an additional mapping may + be created that is inserted into the list of mapping nodes attached to the + directive being processed -- not part of the sorted list of nodes after + GOMP_MAP_STRUCT. + + CODE is the code of the directive being processed. GRP_START and GRP_END + are the first and last of two or three nodes representing this array section + mapping (e.g. a data movement node like GOMP_MAP_{TO,FROM}, optionally a + GOMP_MAP_TO_PSET, and finally a GOMP_MAP_ALWAYS_POINTER). EXTRA_NODE is + filled with the additional node described above, if needed. + + This function does not add the new nodes to any lists itself. It is the + responsibility of the caller to do that. */ static tree -insert_struct_comp_map (enum tree_code code, tree c, tree struct_node, - tree prev_node, tree *scp) +build_struct_comp_nodes (enum tree_code code, tree grp_start, tree grp_end, + tree *extra_node) { enum gomp_map_kind mkind = (code == OMP_TARGET_EXIT_DATA || code == OACC_EXIT_DATA) ? GOMP_MAP_RELEASE : GOMP_MAP_ALLOC; - tree c2 = build_omp_clause (OMP_CLAUSE_LOCATION (c), OMP_CLAUSE_MAP); - tree cl = scp ? prev_node : c2; + gcc_assert (grp_start != grp_end); + + tree c2 = build_omp_clause (OMP_CLAUSE_LOCATION (grp_end), OMP_CLAUSE_MAP); OMP_CLAUSE_SET_MAP_KIND (c2, mkind); - OMP_CLAUSE_DECL (c2) = unshare_expr (OMP_CLAUSE_DECL (c)); - OMP_CLAUSE_CHAIN (c2) = scp ? *scp : prev_node; - if (OMP_CLAUSE_CHAIN (prev_node) != c - && OMP_CLAUSE_CODE (OMP_CLAUSE_CHAIN (prev_node)) == OMP_CLAUSE_MAP - && (OMP_CLAUSE_MAP_KIND (OMP_CLAUSE_CHAIN (prev_node)) - == GOMP_MAP_TO_PSET)) - OMP_CLAUSE_SIZE (c2) = OMP_CLAUSE_SIZE (OMP_CLAUSE_CHAIN (prev_node)); + OMP_CLAUSE_DECL (c2) = unshare_expr (OMP_CLAUSE_DECL (grp_end)); + OMP_CLAUSE_CHAIN (c2) = NULL_TREE; + tree grp_mid = NULL_TREE; + if (OMP_CLAUSE_CHAIN (grp_start) != grp_end) + grp_mid = OMP_CLAUSE_CHAIN (grp_start); + + if (grp_mid + && OMP_CLAUSE_CODE (grp_mid) == OMP_CLAUSE_MAP + && OMP_CLAUSE_MAP_KIND (grp_mid) == GOMP_MAP_TO_PSET) + OMP_CLAUSE_SIZE (c2) = OMP_CLAUSE_SIZE (grp_mid); else OMP_CLAUSE_SIZE (c2) = TYPE_SIZE_UNIT (ptr_type_node); - if (struct_node) - OMP_CLAUSE_CHAIN (struct_node) = c2; - /* We might need to create an additional mapping if we have a reference to a - pointer (in C++). Don't do this if we have something other than a - GOMP_MAP_ALWAYS_POINTER though, i.e. a GOMP_MAP_TO_PSET. */ - if (OMP_CLAUSE_CHAIN (prev_node) != c - && OMP_CLAUSE_CODE (OMP_CLAUSE_CHAIN (prev_node)) == OMP_CLAUSE_MAP - && ((OMP_CLAUSE_MAP_KIND (OMP_CLAUSE_CHAIN (prev_node)) - == GOMP_MAP_ALWAYS_POINTER) - || (OMP_CLAUSE_MAP_KIND (OMP_CLAUSE_CHAIN (prev_node)) - == GOMP_MAP_ATTACH_DETACH))) + if (grp_mid + && OMP_CLAUSE_CODE (grp_mid) == OMP_CLAUSE_MAP + && (OMP_CLAUSE_MAP_KIND (grp_mid) == GOMP_MAP_ALWAYS_POINTER + || OMP_CLAUSE_MAP_KIND (grp_mid) == GOMP_MAP_ATTACH_DETACH)) { - tree c4 = OMP_CLAUSE_CHAIN (prev_node); - tree c3 = build_omp_clause (OMP_CLAUSE_LOCATION (c), OMP_CLAUSE_MAP); + tree c3 + = build_omp_clause (OMP_CLAUSE_LOCATION (grp_end), OMP_CLAUSE_MAP); OMP_CLAUSE_SET_MAP_KIND (c3, mkind); - OMP_CLAUSE_DECL (c3) = unshare_expr (OMP_CLAUSE_DECL (c4)); + OMP_CLAUSE_DECL (c3) = unshare_expr (OMP_CLAUSE_DECL (grp_mid)); OMP_CLAUSE_SIZE (c3) = TYPE_SIZE_UNIT (ptr_type_node); - OMP_CLAUSE_CHAIN (c3) = prev_node; - if (!scp) - OMP_CLAUSE_CHAIN (c2) = c3; - else - cl = c3; + OMP_CLAUSE_CHAIN (c3) = NULL_TREE; + + *extra_node = c3; } + else + *extra_node = NULL_TREE; - if (scp) - *scp = c2; - - return cl; + return c2; } /* Strip ARRAY_REFS or an indirect ref off BASE, find the containing object, @@ -8992,6 +8985,558 @@ omp_lastprivate_for_combined_outer_constructs (struct gimplify_omp_ctx *octx, omp_notice_variable (octx, decl, true); } +/* Link node NEWNODE so it is pointed to by chain INSERT_AT. NEWNODE's chain + is linked to the previous node pointed to by INSERT_AT. */ + +static tree * +insert_node_after (tree newnode, tree *insert_at) +{ + OMP_CLAUSE_CHAIN (newnode) = *insert_at; + *insert_at = newnode; + return &OMP_CLAUSE_CHAIN (newnode); +} + +/* Move NODE (which is currently pointed to by the chain OLD_POS) so it is + pointed to by chain MOVE_AFTER instead. */ + +static void +move_node_after (tree node, tree *old_pos, tree *move_after) +{ + gcc_assert (node == *old_pos); + *old_pos = OMP_CLAUSE_CHAIN (node); + OMP_CLAUSE_CHAIN (node) = *move_after; + *move_after = node; +} + +/* Move nodes from FIRST_PTR (pointed to by previous node's chain) to + LAST_NODE to after MOVE_AFTER chain. Similar to below function, but no + new nodes are prepended to the list before splicing into the new position. + Return the position we should continue scanning the list at, or NULL to + stay where we were. */ + +static tree * +move_nodes_after (tree *first_ptr, tree last_node, tree *move_after) +{ + if (first_ptr == move_after) + return NULL; + + tree tmp = *first_ptr; + *first_ptr = OMP_CLAUSE_CHAIN (last_node); + OMP_CLAUSE_CHAIN (last_node) = *move_after; + *move_after = tmp; + + return first_ptr; +} + +/* Concatenate two lists described by [FIRST_NEW, LAST_NEW_TAIL] and + [FIRST_PTR, LAST_NODE], and insert them in the OMP clause list after chain + pointer MOVE_AFTER. + + The latter list was previously part of the OMP clause list, and the former + (prepended) part is comprised of new nodes. + + We start with a list of nodes starting with a struct mapping node. We + rearrange the list so that new nodes starting from FIRST_NEW and whose last + node's chain is LAST_NEW_TAIL comes directly after MOVE_AFTER, followed by + the group of mapping nodes we are currently processing (from the chain + FIRST_PTR to LAST_NODE). The return value is the pointer to the next chain + we should continue processing from, or NULL to stay where we were. + + The transformation (in the case where MOVE_AFTER and FIRST_PTR are + different) is worked through below. Here we are processing LAST_NODE, and + FIRST_PTR points at the preceding mapping clause: + + #. mapping node chain + --------------------------------------------------- + A. struct_node [->B] + B. comp_1 [->C] + C. comp_2 [->D (move_after)] + D. map_to_3 [->E] + E. attach_3 [->F (first_ptr)] + F. map_to_4 [->G (continue_at)] + G. attach_4 (last_node) [->H] + H. ... + + *last_new_tail = *first_ptr; + + I. new_node (first_new) [->F (last_new_tail)] + + *first_ptr = OMP_CLAUSE_CHAIN (last_node) + + #. mapping node chain + ---------------------------------------------------- + A. struct_node [->B] + B. comp_1 [->C] + C. comp_2 [->D (move_after)] + D. map_to_3 [->E] + E. attach_3 [->H (first_ptr)] + F. map_to_4 [->G (continue_at)] + G. attach_4 (last_node) [->H] + H. ... + + I. new_node (first_new) [->F (last_new_tail)] + + OMP_CLAUSE_CHAIN (last_node) = *move_after; + + #. mapping node chain + --------------------------------------------------- + A. struct_node [->B] + B. comp_1 [->C] + C. comp_2 [->D (move_after)] + D. map_to_3 [->E] + E. attach_3 [->H (continue_at)] + F. map_to_4 [->G] + G. attach_4 (last_node) [->D] + H. ... + + I. new_node (first_new) [->F (last_new_tail)] + + *move_after = first_new; + + #. mapping node chain + --------------------------------------------------- + A. struct_node [->B] + B. comp_1 [->C] + C. comp_2 [->I (move_after)] + D. map_to_3 [->E] + E. attach_3 [->H (continue_at)] + F. map_to_4 [->G] + G. attach_4 (last_node) [->D] + H. ... + I. new_node (first_new) [->F (last_new_tail)] + + or, in order: + + #. mapping node chain + --------------------------------------------------- + A. struct_node [->B] + B. comp_1 [->C] + C. comp_2 [->I (move_after)] + I. new_node (first_new) [->F (last_new_tail)] + F. map_to_4 [->G] + G. attach_4 (last_node) [->D] + D. map_to_3 [->E] + E. attach_3 [->H (continue_at)] + H. ... +*/ + +static tree * +move_concat_nodes_after (tree first_new, tree *last_new_tail, tree *first_ptr, + tree last_node, tree *move_after) +{ + tree *continue_at = NULL; + *last_new_tail = *first_ptr; + if (first_ptr == move_after) + *move_after = first_new; + else + { + *first_ptr = OMP_CLAUSE_CHAIN (last_node); + continue_at = first_ptr; + OMP_CLAUSE_CHAIN (last_node) = *move_after; + *move_after = first_new; + } + return continue_at; +} + +/* Mapping struct members causes an additional set of nodes to be created, + starting with GOMP_MAP_STRUCT followed by a number of mappings equal to the + number of members being mapped, in order of ascending position (address or + bitwise). + + We scan through the list of mapping clauses, calling this function for each + struct member mapping we find, and build up the list of mappings after the + initial GOMP_MAP_STRUCT node. For pointer members, these will be + newly-created ALLOC nodes. For non-pointer members, the existing mapping is + moved into place in the sorted list. + + struct { + int *a; + int *b; + int c; + int *d; + }; + + #pragma (acc|omp directive) copy(struct.a[0:n], struct.b[0:n], struct.c, + struct.d[0:n]) + + GOMP_MAP_STRUCT (4) + [GOMP_MAP_FIRSTPRIVATE_REFERENCE -- for refs to structs] + GOMP_MAP_ALLOC (struct.a) + GOMP_MAP_ALLOC (struct.b) + GOMP_MAP_TO (struct.c) + GOMP_MAP_ALLOC (struct.d) + ... + + In the case where we are mapping references to pointers, or in Fortran if + we are mapping an array with a descriptor, additional nodes may be created + after the struct node list also. + + The return code is: + - DECL, if we just created the initial GOMP_MAP_STRUCT node. + - NULL_TREE, if we inserted the new struct member successfully. + - error_mark_node if an error occurred. + + *CONT is set to TRUE if we should skip further processing and move to the + next node. PREV_LIST_P and LIST_P may be modified by the function when a + list rearrangement has taken place. */ + +static tree +build_struct_group (struct gimplify_omp_ctx *ctx, + enum omp_region_type region_type, enum tree_code code, + tree decl, tree *pd, bool component_ref_p, + unsigned int *flags, tree c, + hash_map *&struct_map_to_clause, + hash_map *&struct_seen_clause, + tree *&prev_list_p, tree *&list_p, gimple_seq *pre_p, + bool *cont) +{ + poly_offset_int coffset; + poly_int64 cbitpos; + tree base_ref, tree_coffset; + tree ocd = OMP_CLAUSE_DECL (c); + + while (TREE_CODE (ocd) == ARRAY_REF) + ocd = TREE_OPERAND (ocd, 0); + + if (TREE_CODE (ocd) == INDIRECT_REF) + ocd = TREE_OPERAND (ocd, 0); + + tree base = extract_base_bit_offset (ocd, &base_ref, + &cbitpos, &coffset, &tree_coffset); + + bool do_map_struct = (base == decl && !tree_coffset); + + /* Here, DECL is usually a DECL_P, unless we have chained indirect member + accesses, e.g. mystruct->a->b. In that case it'll be the "mystruct->a" + part. */ + splay_tree_node n + = (DECL_P (decl) + ? splay_tree_lookup (ctx->variables, (splay_tree_key) decl) + : NULL); + bool ptr = (OMP_CLAUSE_MAP_KIND (c) == GOMP_MAP_ALWAYS_POINTER); + bool attach_detach = (OMP_CLAUSE_MAP_KIND (c) == GOMP_MAP_ATTACH_DETACH); + bool attach = (OMP_CLAUSE_MAP_KIND (c) == GOMP_MAP_ATTACH + || OMP_CLAUSE_MAP_KIND (c) == GOMP_MAP_DETACH); + bool has_attachments = false; + + /* For OpenACC, pointers in structs should trigger an attach action. */ + if (attach_detach + && ((region_type & (ORT_ACC | ORT_TARGET | ORT_TARGET_DATA)) + || code == OMP_TARGET_ENTER_DATA + || code == OMP_TARGET_EXIT_DATA)) + { + /* Turn a GOMP_MAP_ATTACH_DETACH clause into a GOMP_MAP_ATTACH or + GOMP_MAP_DETACH clause after we have detected a case that needs a + GOMP_MAP_STRUCT mapping added. */ + gomp_map_kind k + = ((code == OACC_EXIT_DATA || code == OMP_TARGET_EXIT_DATA) + ? GOMP_MAP_DETACH : GOMP_MAP_ATTACH); + OMP_CLAUSE_SET_MAP_KIND (c, k); + has_attachments = true; + } + + /* We currently don't handle non-constant offset accesses wrt to + GOMP_MAP_STRUCT elements. */ + if (!do_map_struct) + return NULL_TREE; + + /* Nor for attach_detach for OpenMP. */ + if ((code == OMP_TARGET + || code == OMP_TARGET_DATA + || code == OMP_TARGET_UPDATE + || code == OMP_TARGET_ENTER_DATA + || code == OMP_TARGET_EXIT_DATA) + && attach_detach) + { + if (DECL_P (decl)) + { + if (struct_seen_clause == NULL) + struct_seen_clause = new hash_map; + if (!struct_seen_clause->get (decl)) + struct_seen_clause->put (decl, list_p); + } + + return NULL_TREE; + } + + if ((DECL_P (decl) && (n == NULL || (n->value & GOVD_MAP) == 0)) + || (!DECL_P (decl) + && (!struct_map_to_clause + || struct_map_to_clause->get (decl) == NULL))) + { + tree l = build_omp_clause (OMP_CLAUSE_LOCATION (c), OMP_CLAUSE_MAP); + gomp_map_kind k = attach ? GOMP_MAP_FORCE_PRESENT : GOMP_MAP_STRUCT; + + OMP_CLAUSE_SET_MAP_KIND (l, k); + + if (base_ref) + OMP_CLAUSE_DECL (l) = unshare_expr (base_ref); + else + { + OMP_CLAUSE_DECL (l) = unshare_expr (decl); + if (!DECL_P (OMP_CLAUSE_DECL (l)) + && (gimplify_expr (&OMP_CLAUSE_DECL (l), pre_p, NULL, + is_gimple_lvalue, fb_lvalue) == GS_ERROR)) + return error_mark_node; + } + OMP_CLAUSE_SIZE (l) + = (!attach ? size_int (1) + : (DECL_P (OMP_CLAUSE_DECL (l)) + ? DECL_SIZE_UNIT (OMP_CLAUSE_DECL (l)) + : TYPE_SIZE_UNIT (TREE_TYPE (OMP_CLAUSE_DECL (l))))); + if (struct_map_to_clause == NULL) + struct_map_to_clause = new hash_map; + struct_map_to_clause->put (decl, l); + + if (ptr || attach_detach) + { + tree extra_node; + tree alloc_node + = build_struct_comp_nodes (code, *prev_list_p, c, &extra_node); + OMP_CLAUSE_CHAIN (l) = alloc_node; + + tree **sc = (struct_seen_clause + ? struct_seen_clause->get (decl) + : NULL); + tree *insert_node_pos = sc ? *sc : prev_list_p; + + if (extra_node) + { + OMP_CLAUSE_CHAIN (extra_node) = *insert_node_pos; + OMP_CLAUSE_CHAIN (alloc_node) = extra_node; + } + else + OMP_CLAUSE_CHAIN (alloc_node) = *insert_node_pos; + + *insert_node_pos = l; + prev_list_p = NULL; + } + else + list_p = insert_node_after (l, list_p); + + /* Handle pointers to structs and references to structs: these cases + have an additional GOMP_MAP_FIRSTPRIVATE_{REFERENCE,POINTER} node + inserted after the GOMP_MAP_STRUCT node. References to pointers + use GOMP_MAP_FIRSTPRIVATE_REFERENCE. */ + if (base_ref && code == OMP_TARGET) + { + tree c2 = build_omp_clause (OMP_CLAUSE_LOCATION (c), + OMP_CLAUSE_MAP); + enum gomp_map_kind mkind + = GOMP_MAP_FIRSTPRIVATE_REFERENCE; + OMP_CLAUSE_SET_MAP_KIND (c2, mkind); + OMP_CLAUSE_DECL (c2) = decl; + OMP_CLAUSE_SIZE (c2) = size_zero_node; + OMP_CLAUSE_CHAIN (c2) = OMP_CLAUSE_CHAIN (l); + OMP_CLAUSE_CHAIN (l) = c2; + } + *flags = GOVD_MAP | GOVD_EXPLICIT; + if (GOMP_MAP_ALWAYS_P (OMP_CLAUSE_MAP_KIND (c)) || ptr || attach_detach) + *flags |= GOVD_SEEN; + if (has_attachments) + *flags |= GOVD_MAP_HAS_ATTACHMENTS; + + /* If this is a *pointer-to-struct expression, make sure a + firstprivate map of the base-pointer exists. */ + if (component_ref_p + && ((TREE_CODE (decl) == MEM_REF + && integer_zerop (TREE_OPERAND (decl, 1))) + || INDIRECT_REF_P (decl)) + && DECL_P (TREE_OPERAND (decl, 0)) + && !splay_tree_lookup (ctx->variables, + ((splay_tree_key) TREE_OPERAND (decl, 0)))) + { + decl = TREE_OPERAND (decl, 0); + tree c2 = build_omp_clause (OMP_CLAUSE_LOCATION (c), OMP_CLAUSE_MAP); + enum gomp_map_kind mkind = GOMP_MAP_FIRSTPRIVATE_POINTER; + OMP_CLAUSE_SET_MAP_KIND (c2, mkind); + OMP_CLAUSE_DECL (c2) = decl; + OMP_CLAUSE_SIZE (c2) = size_zero_node; + OMP_CLAUSE_CHAIN (c2) = OMP_CLAUSE_CHAIN (c); + OMP_CLAUSE_CHAIN (c) = c2; + } + + return decl; + } + else if (struct_map_to_clause) + { + tree *osc = struct_map_to_clause->get (decl); + tree *sc = NULL, *scp = NULL; + if (n && (GOMP_MAP_ALWAYS_P (OMP_CLAUSE_MAP_KIND (c)) + || ptr + || attach_detach)) + n->value |= GOVD_SEEN; + sc = &OMP_CLAUSE_CHAIN (*osc); + /* The struct mapping might be immediately followed by a + FIRSTPRIVATE_REFERENCE if it is a reference. (This added node is + removed in omp-low.c after it has been processed there.) */ + if (*sc != c + && OMP_CLAUSE_MAP_KIND (*sc) == GOMP_MAP_FIRSTPRIVATE_REFERENCE) + sc = &OMP_CLAUSE_CHAIN (*sc); + for (; *sc != c; sc = &OMP_CLAUSE_CHAIN (*sc)) + if ((ptr || attach_detach) && sc == prev_list_p) + break; + else if (TREE_CODE (OMP_CLAUSE_DECL (*sc)) != COMPONENT_REF + && TREE_CODE (OMP_CLAUSE_DECL (*sc)) != INDIRECT_REF + && TREE_CODE (OMP_CLAUSE_DECL (*sc)) != ARRAY_REF) + break; + else + { + tree sc_decl = OMP_CLAUSE_DECL (*sc); + poly_offset_int offset; + poly_int64 bitpos; + tree tree_offset; + + if (TREE_CODE (sc_decl) == ARRAY_REF) + { + while (TREE_CODE (sc_decl) == ARRAY_REF) + sc_decl = TREE_OPERAND (sc_decl, 0); + if (TREE_CODE (sc_decl) != COMPONENT_REF + || TREE_CODE (TREE_TYPE (sc_decl)) != ARRAY_TYPE) + break; + } + else if (TREE_CODE (sc_decl) == INDIRECT_REF + && TREE_CODE (TREE_OPERAND (sc_decl, 0)) == COMPONENT_REF + && (TREE_CODE (TREE_TYPE (TREE_OPERAND (sc_decl, 0))) + == REFERENCE_TYPE)) + sc_decl = TREE_OPERAND (sc_decl, 0); + + tree base = extract_base_bit_offset (sc_decl, NULL, &bitpos, + &offset, &tree_offset); + if (base != decl) + break; + if (scp) + continue; + if ((region_type & ORT_ACC) != 0) + { + /* This duplicate checking code is currently only enabled for + OpenACC. */ + tree d1 = OMP_CLAUSE_DECL (*sc); + tree d2 = OMP_CLAUSE_DECL (c); + while (TREE_CODE (d1) == ARRAY_REF) + d1 = TREE_OPERAND (d1, 0); + while (TREE_CODE (d2) == ARRAY_REF) + d2 = TREE_OPERAND (d2, 0); + if (TREE_CODE (d1) == INDIRECT_REF) + d1 = TREE_OPERAND (d1, 0); + if (TREE_CODE (d2) == INDIRECT_REF) + d2 = TREE_OPERAND (d2, 0); + while (TREE_CODE (d1) == COMPONENT_REF) + if (TREE_CODE (d2) == COMPONENT_REF + && TREE_OPERAND (d1, 1) == TREE_OPERAND (d2, 1)) + { + d1 = TREE_OPERAND (d1, 0); + d2 = TREE_OPERAND (d2, 0); + } + else + break; + if (d1 == d2) + { + error_at (OMP_CLAUSE_LOCATION (c), + "%qE appears more than once in map clauses", + OMP_CLAUSE_DECL (c)); + return error_mark_node; + } + } + if (maybe_lt (coffset, offset) + || (known_eq (coffset, offset) + && maybe_lt (cbitpos, bitpos))) + { + if (ptr || attach_detach) + scp = sc; + else + break; + } + } + + if (!attach) + OMP_CLAUSE_SIZE (*osc) + = size_binop (PLUS_EXPR, OMP_CLAUSE_SIZE (*osc), size_one_node); + if (ptr || attach_detach) + { + tree cl = NULL_TREE, extra_node; + tree alloc_node = build_struct_comp_nodes (code, *prev_list_p, c, + &extra_node); + tree *tail_chain = NULL; + + /* Here, we have: + + c : the currently-processed node. + prev_list_p : pointer to the first node in a pointer mapping group + up to and including C. + sc : pointer to the chain for the end of the struct component + list. + scp : pointer to the chain for the sorted position at which we + should insert in the middle of the struct component list + (else NULL to insert at end). + alloc_node : the "alloc" node for the structure (pointer-type) + component. We insert at SCP (if present), else SC + (the end of the struct component list). + extra_node : a newly-synthesized node for an additional indirect + pointer mapping or a Fortran pointer set, if needed. + cl : first node to prepend before prev_list_p. + tail_chain : pointer to chain of last prepended node. + + The general idea is we move the nodes for this struct mapping + together: the alloc node goes into the sorted list directly after + the struct mapping, and any extra nodes (together with the nodes + mapping arrays pointed to by struct components) get moved after + that list. When SCP is NULL, we insert the nodes at SC, i.e. at + the end of the struct component mapping list. It's important that + the alloc_node comes first in that case because it's part of the + sorted component mapping list (but subsequent nodes are not!). */ + + if (scp) + insert_node_after (alloc_node, scp); + + /* Make [cl,tail_chain] a list of the alloc node (if we haven't + already inserted it) and the extra_node (if it is present). The + list can be empty if we added alloc_node above and there is no + extra node. */ + if (scp && extra_node) + { + cl = extra_node; + tail_chain = &OMP_CLAUSE_CHAIN (extra_node); + } + else if (extra_node) + { + OMP_CLAUSE_CHAIN (alloc_node) = extra_node; + cl = alloc_node; + tail_chain = &OMP_CLAUSE_CHAIN (extra_node); + } + else if (!scp) + { + cl = alloc_node; + tail_chain = &OMP_CLAUSE_CHAIN (alloc_node); + } + + tree *continue_at + = cl ? move_concat_nodes_after (cl, tail_chain, prev_list_p, c, sc) + : move_nodes_after (prev_list_p, c, sc); + + prev_list_p = NULL; + + if (continue_at) + { + list_p = continue_at; + *cont = true; + } + } + else if (*sc != c) + { + if (gimplify_expr (pd, pre_p, NULL, is_gimple_lvalue, fb_lvalue) + == GS_ERROR) + return error_mark_node; + /* In the non-pointer case, the mapping clause itself is moved into + the correct position in the struct component list, which in this + case is just SC. */ + move_node_after (c, list_p, sc); + *cont = true; + } + } + return NULL_TREE; +} + /* Scan the OMP clauses in *LIST_P, installing mappings into a new and previous omp contexts. */ @@ -9645,324 +10190,25 @@ gimplify_scan_omp_clauses (tree *list_p, gimple_seq *pre_p, } } } - - poly_offset_int offset1; - poly_int64 bitpos1; - tree tree_offset1; - tree base_ref, ocd = OMP_CLAUSE_DECL (c); - - while (TREE_CODE (ocd) == ARRAY_REF) - ocd = TREE_OPERAND (ocd, 0); - - if (TREE_CODE (ocd) == INDIRECT_REF) - ocd = TREE_OPERAND (ocd, 0); - - tree base = extract_base_bit_offset (ocd, &base_ref, - &bitpos1, &offset1, - &tree_offset1); - - bool do_map_struct = (base == decl && !tree_offset1); - - splay_tree_node n - = (DECL_P (decl) - ? splay_tree_lookup (ctx->variables, - (splay_tree_key) decl) - : NULL); - bool ptr = (OMP_CLAUSE_MAP_KIND (c) - == GOMP_MAP_ALWAYS_POINTER); - bool attach_detach = (OMP_CLAUSE_MAP_KIND (c) - == GOMP_MAP_ATTACH_DETACH); - bool attach = OMP_CLAUSE_MAP_KIND (c) == GOMP_MAP_ATTACH - || OMP_CLAUSE_MAP_KIND (c) == GOMP_MAP_DETACH; - bool has_attachments = false; - /* For OpenACC, pointers in structs should trigger an - attach action. */ - if (attach_detach - && ((region_type & (ORT_ACC | ORT_TARGET | ORT_TARGET_DATA)) - || code == OMP_TARGET_ENTER_DATA - || code == OMP_TARGET_EXIT_DATA)) - + bool cont = false; + tree add_decl + = build_struct_group (ctx, region_type, code, decl, pd, + component_ref_p, &flags, c, + struct_map_to_clause, + struct_seen_clause, prev_list_p, + list_p, pre_p, &cont); + if (add_decl == error_mark_node) { - /* Turn a GOMP_MAP_ATTACH_DETACH clause into a - GOMP_MAP_ATTACH or GOMP_MAP_DETACH clause after we - have detected a case that needs a GOMP_MAP_STRUCT - mapping added. */ - gomp_map_kind k - = ((code == OACC_EXIT_DATA || code == OMP_TARGET_EXIT_DATA) - ? GOMP_MAP_DETACH : GOMP_MAP_ATTACH); - OMP_CLAUSE_SET_MAP_KIND (c, k); - has_attachments = true; + remove = true; + break; } - - /* We currently don't handle non-constant offset accesses wrt to - GOMP_MAP_STRUCT elements. */ - if (!do_map_struct) - goto skip_map_struct; - - /* Nor for attach_detach for OpenMP. */ - if ((code == OMP_TARGET - || code == OMP_TARGET_DATA - || code == OMP_TARGET_UPDATE - || code == OMP_TARGET_ENTER_DATA - || code == OMP_TARGET_EXIT_DATA) - && attach_detach) + else if (add_decl && DECL_P (add_decl)) { - if (DECL_P (decl)) - { - if (struct_seen_clause == NULL) - struct_seen_clause - = new hash_map; - if (!struct_seen_clause->get (decl)) - struct_seen_clause->put (decl, list_p); - } - - goto skip_map_struct; + decl = add_decl; + goto do_add_decl; } - - if ((DECL_P (decl) - && (n == NULL || (n->value & GOVD_MAP) == 0)) - || (!DECL_P (decl) - && (!struct_map_to_clause - || struct_map_to_clause->get (decl) == NULL))) - { - tree l = build_omp_clause (OMP_CLAUSE_LOCATION (c), - OMP_CLAUSE_MAP); - gomp_map_kind k = attach ? GOMP_MAP_FORCE_PRESENT - : GOMP_MAP_STRUCT; - - OMP_CLAUSE_SET_MAP_KIND (l, k); - if (base_ref) - OMP_CLAUSE_DECL (l) = unshare_expr (base_ref); - else - { - OMP_CLAUSE_DECL (l) = unshare_expr (decl); - if (!DECL_P (OMP_CLAUSE_DECL (l)) - && (gimplify_expr (&OMP_CLAUSE_DECL (l), - pre_p, NULL, is_gimple_lvalue, - fb_lvalue) - == GS_ERROR)) - { - remove = true; - break; - } - } - OMP_CLAUSE_SIZE (l) - = (!attach - ? size_int (1) - : DECL_P (OMP_CLAUSE_DECL (l)) - ? DECL_SIZE_UNIT (OMP_CLAUSE_DECL (l)) - : TYPE_SIZE_UNIT (TREE_TYPE (OMP_CLAUSE_DECL (l)))); - if (struct_map_to_clause == NULL) - struct_map_to_clause - = new hash_map; - struct_map_to_clause->put (decl, l); - if (ptr || attach_detach) - { - tree **sc = (struct_seen_clause - ? struct_seen_clause->get (decl) - : NULL); - tree *insert_node_pos = sc ? *sc : prev_list_p; - - insert_struct_comp_map (code, c, l, *insert_node_pos, - NULL); - *insert_node_pos = l; - prev_list_p = NULL; - } - else - { - OMP_CLAUSE_CHAIN (l) = c; - *list_p = l; - list_p = &OMP_CLAUSE_CHAIN (l); - } - if (base_ref && code == OMP_TARGET) - { - tree c2 = build_omp_clause (OMP_CLAUSE_LOCATION (c), - OMP_CLAUSE_MAP); - enum gomp_map_kind mkind - = GOMP_MAP_FIRSTPRIVATE_REFERENCE; - OMP_CLAUSE_SET_MAP_KIND (c2, mkind); - OMP_CLAUSE_DECL (c2) = decl; - OMP_CLAUSE_SIZE (c2) = size_zero_node; - OMP_CLAUSE_CHAIN (c2) = OMP_CLAUSE_CHAIN (l); - OMP_CLAUSE_CHAIN (l) = c2; - } - flags = GOVD_MAP | GOVD_EXPLICIT; - if (GOMP_MAP_ALWAYS_P (OMP_CLAUSE_MAP_KIND (c)) - || ptr - || attach_detach) - flags |= GOVD_SEEN; - if (has_attachments) - flags |= GOVD_MAP_HAS_ATTACHMENTS; - - /* If this is a *pointer-to-struct expression, make sure a - firstprivate map of the base-pointer exists. */ - if (component_ref_p - && ((TREE_CODE (decl) == MEM_REF - && integer_zerop (TREE_OPERAND (decl, 1))) - || INDIRECT_REF_P (decl)) - && DECL_P (TREE_OPERAND (decl, 0)) - && !splay_tree_lookup (ctx->variables, - ((splay_tree_key) - TREE_OPERAND (decl, 0)))) - { - decl = TREE_OPERAND (decl, 0); - tree c2 = build_omp_clause (OMP_CLAUSE_LOCATION (c), - OMP_CLAUSE_MAP); - enum gomp_map_kind mkind - = GOMP_MAP_FIRSTPRIVATE_POINTER; - OMP_CLAUSE_SET_MAP_KIND (c2, mkind); - OMP_CLAUSE_DECL (c2) = decl; - OMP_CLAUSE_SIZE (c2) = size_zero_node; - OMP_CLAUSE_CHAIN (c2) = OMP_CLAUSE_CHAIN (c); - OMP_CLAUSE_CHAIN (c) = c2; - } - - if (DECL_P (decl)) - goto do_add_decl; - } - else if (struct_map_to_clause) - { - tree *osc = struct_map_to_clause->get (decl); - tree *sc = NULL, *scp = NULL; - if (n != NULL - && (GOMP_MAP_ALWAYS_P (OMP_CLAUSE_MAP_KIND (c)) - || ptr - || attach_detach)) - n->value |= GOVD_SEEN; - sc = &OMP_CLAUSE_CHAIN (*osc); - if (*sc != c - && (OMP_CLAUSE_MAP_KIND (*sc) - == GOMP_MAP_FIRSTPRIVATE_REFERENCE)) - sc = &OMP_CLAUSE_CHAIN (*sc); - /* Here "prev_list_p" is the end of the inserted - alloc/release nodes after the struct node, OSC. */ - for (; *sc != c; sc = &OMP_CLAUSE_CHAIN (*sc)) - if ((ptr || attach_detach) && sc == prev_list_p) - break; - else if (TREE_CODE (OMP_CLAUSE_DECL (*sc)) - != COMPONENT_REF - && (TREE_CODE (OMP_CLAUSE_DECL (*sc)) - != INDIRECT_REF) - && (TREE_CODE (OMP_CLAUSE_DECL (*sc)) - != ARRAY_REF)) - break; - else - { - tree sc_decl = OMP_CLAUSE_DECL (*sc); - poly_offset_int offsetn; - poly_int64 bitposn; - tree tree_offsetn; - - if (TREE_CODE (sc_decl) == ARRAY_REF) - { - while (TREE_CODE (sc_decl) == ARRAY_REF) - sc_decl = TREE_OPERAND (sc_decl, 0); - if (TREE_CODE (sc_decl) != COMPONENT_REF - || (TREE_CODE (TREE_TYPE (sc_decl)) - != ARRAY_TYPE)) - break; - } - else if (TREE_CODE (sc_decl) == INDIRECT_REF - && (TREE_CODE (TREE_OPERAND (sc_decl, 0)) - == COMPONENT_REF) - && (TREE_CODE (TREE_TYPE - (TREE_OPERAND (sc_decl, 0))) - == REFERENCE_TYPE)) - sc_decl = TREE_OPERAND (sc_decl, 0); - - tree base - = extract_base_bit_offset (sc_decl, NULL, - &bitposn, &offsetn, - &tree_offsetn); - if (base != decl) - break; - if (scp) - continue; - if ((region_type & ORT_ACC) != 0) - { - /* This duplicate checking code is currently only - enabled for OpenACC. */ - tree d1 = OMP_CLAUSE_DECL (*sc); - tree d2 = OMP_CLAUSE_DECL (c); - while (TREE_CODE (d1) == ARRAY_REF) - d1 = TREE_OPERAND (d1, 0); - while (TREE_CODE (d2) == ARRAY_REF) - d2 = TREE_OPERAND (d2, 0); - if (TREE_CODE (d1) == INDIRECT_REF) - d1 = TREE_OPERAND (d1, 0); - if (TREE_CODE (d2) == INDIRECT_REF) - d2 = TREE_OPERAND (d2, 0); - while (TREE_CODE (d1) == COMPONENT_REF) - if (TREE_CODE (d2) == COMPONENT_REF - && TREE_OPERAND (d1, 1) - == TREE_OPERAND (d2, 1)) - { - d1 = TREE_OPERAND (d1, 0); - d2 = TREE_OPERAND (d2, 0); - } - else - break; - if (d1 == d2) - { - error_at (OMP_CLAUSE_LOCATION (c), - "%qE appears more than once in map " - "clauses", OMP_CLAUSE_DECL (c)); - remove = true; - break; - } - } - if (maybe_lt (offset1, offsetn) - || (known_eq (offset1, offsetn) - && maybe_lt (bitpos1, bitposn))) - { - if (ptr || attach_detach) - scp = sc; - else - break; - } - } - if (remove) - break; - if (!attach) - OMP_CLAUSE_SIZE (*osc) - = size_binop (PLUS_EXPR, OMP_CLAUSE_SIZE (*osc), - size_one_node); - if (ptr || attach_detach) - { - tree cl = insert_struct_comp_map (code, c, NULL, - *prev_list_p, scp); - if (sc == prev_list_p) - { - *sc = cl; - prev_list_p = NULL; - } - else - { - *prev_list_p = OMP_CLAUSE_CHAIN (c); - list_p = prev_list_p; - prev_list_p = NULL; - OMP_CLAUSE_CHAIN (c) = *sc; - *sc = cl; - continue; - } - } - else if (*sc != c) - { - if (gimplify_expr (pd, pre_p, NULL, is_gimple_lvalue, - fb_lvalue) - == GS_ERROR) - { - remove = true; - break; - } - *list_p = OMP_CLAUSE_CHAIN (c); - OMP_CLAUSE_CHAIN (c) = *sc; - *sc = c; - continue; - } - } - skip_map_struct: - ; + if (cont) + continue; } else if (OMP_CLAUSE_MAP_KIND (c) == GOMP_MAP_ATTACH_DETACH) { From patchwork Thu Nov 25 14:07:20 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Julian Brown X-Patchwork-Id: 1559731 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=gcc.gnu.org (client-ip=2620:52:3:1:0:246e:9693:128c; helo=sourceware.org; envelope-from=gcc-patches-bounces+incoming=patchwork.ozlabs.org@gcc.gnu.org; receiver=) Received: from sourceware.org (server2.sourceware.org [IPv6:2620:52:3:1:0:246e:9693:128c]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by bilbo.ozlabs.org (Postfix) with ESMTPS id 4J0KWt4Vpnz9sVc for ; Fri, 26 Nov 2021 01:10:02 +1100 (AEDT) Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 8858A3858002 for ; Thu, 25 Nov 2021 14:10:00 +0000 (GMT) X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from esa2.mentor.iphmx.com (esa2.mentor.iphmx.com [68.232.141.98]) by sourceware.org (Postfix) with ESMTPS id 63D343858004 for ; Thu, 25 Nov 2021 14:07:48 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org 63D343858004 Authentication-Results: sourceware.org; dmarc=none (p=none dis=none) header.from=codesourcery.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=mentor.com IronPort-SDR: zCFGKrFSjr00ue3lKJAzBkp2xKXUFxIoDpViFVHcHdKOmloIp1s58Y2tNS41ndIOl+dbVEetm1 mn7QtQeuo88Sov7sTnS9+56E9Ax9DN545hr6HBPK85CEgFsoMwz5yOicLt/CPq94kz/18yYG0A SDkVC7Zhh6dQHJVP7o1MMs4rb7Gyg9nKusQh3M5W7V3QmoPsBrxr+xTYhR5wE4YWMbHaBpgV3F zHBPunfij2pFztyyQ80pf3vDMF0pCSzLo1CF5tA2Tu9IEGrTR6Ysd2aBQPgvqf/De78h8aFvA4 0f1PD22YPPuaU1Dodz0StLBW X-IronPort-AV: E=Sophos;i="5.87,263,1631606400"; d="scan'208";a="68920770" Received: from orw-gwy-02-in.mentorg.com ([192.94.38.167]) by esa2.mentor.iphmx.com with ESMTP; 25 Nov 2021 06:07:46 -0800 IronPort-SDR: WpK1hYXxOniBNeH+0nHsBAqcMQKCDoaq42bGCETD4DGb8yGAznjk/PqMhgaZT45ISIa+PDHVkc 7kG2IklWmLq4k12tqoqRjFUO9OwaG3gdOQ6ituxIUOXEOadjBnOxkzheu1RNIGktsqTchE/LSf RLkfWZUMKHn5V7L+rW8IIW1iz/Z/jGrgKBsjuhUSpsYlExeNKIeIYB7JxuHeKyztHs650AhVD3 kdEClrPgRh2nAqTU8HRHvyQ6gPaZLw0sj8H+XwQDWNVi/4JeIejP6th6AWjfWIQlaQoWnRyFbT ar4= From: Julian Brown To: Subject: [PATCH 04/16] OpenACC: Rework indirect struct handling in gimplify.c Date: Thu, 25 Nov 2021 06:07:20 -0800 Message-ID: <20211125140720.108885-5-julian@codesourcery.com> X-Mailer: git-send-email 2.29.2 In-Reply-To: <20211125140720.108885-1-julian@codesourcery.com> References: <20211125140720.108885-1-julian@codesourcery.com> MIME-Version: 1.0 X-Originating-IP: [137.202.0.90] X-ClientProxiedBy: svr-ies-mbx-12.mgc.mentorg.com (139.181.222.12) To SVR-IES-MBX-04.mgc.mentorg.com (139.181.222.4) X-Spam-Status: No, score=-11.8 required=5.0 tests=BAYES_00, GIT_PATCH_0, HEADER_FROM_DIFFERENT_DOMAINS, KAM_DMARC_STATUS, KAM_SHORT, SPF_HELO_PASS, SPF_PASS, 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: , Cc: Jakub Jelinek , Thomas Schwinge Errors-To: gcc-patches-bounces+incoming=patchwork.ozlabs.org@gcc.gnu.org Sender: "Gcc-patches" (Previously posted here: https://gcc.gnu.org/pipermail/gcc-patches/2021-May/570400.html) This patch reworks indirect struct handling in gimplify.c (i.e. for struct components mapped with "mystruct->a[0:n]", "mystruct->b", etc.), for OpenACC. The key observation leading to these changes was that component mappings of references-to-structures is already implemented and working, and indirect struct component handling via a pointer can work quite similarly. That lets us remove some earlier, special-case handling for mapping indirect struct component accesses for OpenACC, which required the pointed-to struct to be manually mapped before the indirect component mapping. With this patch, you can map struct components directly (e.g. an array slice "mystruct->a[0:n]") just like you can map a non-indirect struct component slice ("mystruct.a[0:n]"). Both references-to-pointers (with the former syntax) and references to structs (with the latter syntax) work now. For Fortran class pointers, we no longer re-use GOMP_MAP_TO_PSET for the class metadata (the structure that points to the class data and vptr) -- it is instead treated as any other struct. For C++, the struct handling also works for class members ("this->foo"), without having to explicitly map "this[:1]" first. For OpenACC, we permit chained indirect component references ("mystruct->a->b[0:n]"), though only the last part of such mappings will trigger an attach/detach operation. To properly use such a construct on the target, you must still manually map "mystruct->a[:1]" first -- but there's no need to map "mystruct[:1]" explicitly before that. This version of the patch avoids altering code paths for OpenMP, where possible. (Those are dealt with by later patches in this series.) OK? Thanks, Julian 2021-06-02 Julian Brown gcc/fortran/ * trans-openmp.c (gfc_trans_omp_clauses): Don't create GOMP_MAP_TO_PSET mappings for class metadata, nor GOMP_MAP_POINTER mappings for POINTER_TYPE_P decls. gcc/ * gimplify.c (extract_base_bit_offset): Add BASE_IND and OPENMP parameters. Handle pointer-typed indirect references for OpenACC alongside reference-typed ones. (strip_components_and_deref, aggregate_base_p): New functions. (build_struct_group): Add pointer type indirect ref handling, including chained references, for OpenACC. Also handle references to structs for OpenACC. Conditionalise bits for OpenMP only where appropriate. (gimplify_scan_omp_clauses): Rework pointer-type indirect structure access handling to work more like the reference-typed handling for OpenACC only. * omp-low.c (scan_sharing_clauses): Handle pointer-type indirect struct references, and references to pointers to structs also. gcc/testsuite/ * g++.dg/goacc/member-array-acc.C: New test. * g++.dg/gomp/member-array-omp.C: New test. libgomp/ * testsuite/libgomp.oacc-c-c++-common/deep-copy-15.c: New test. * testsuite/libgomp.oacc-c-c++-common/deep-copy-16.c: New test. * testsuite/libgomp.oacc-c++/deep-copy-17.C: New test. --- gcc/fortran/trans-openmp.c | 20 +- gcc/gimplify.c | 214 +++++++++++++--- gcc/omp-low.c | 16 +- gcc/testsuite/g++.dg/goacc/member-array-acc.C | 13 + gcc/testsuite/g++.dg/gomp/member-array-omp.C | 13 + .../testsuite/libgomp.oacc-c++/deep-copy-17.C | 101 ++++++++ .../libgomp.oacc-c-c++-common/deep-copy-15.c | 68 ++++++ .../libgomp.oacc-c-c++-common/deep-copy-16.c | 231 ++++++++++++++++++ 8 files changed, 618 insertions(+), 58 deletions(-) create mode 100644 gcc/testsuite/g++.dg/goacc/member-array-acc.C create mode 100644 gcc/testsuite/g++.dg/gomp/member-array-omp.C create mode 100644 libgomp/testsuite/libgomp.oacc-c++/deep-copy-17.C create mode 100644 libgomp/testsuite/libgomp.oacc-c-c++-common/deep-copy-15.c create mode 100644 libgomp/testsuite/libgomp.oacc-c-c++-common/deep-copy-16.c diff --git a/gcc/fortran/trans-openmp.c b/gcc/fortran/trans-openmp.c index 7d761e90dd7..508e02306e9 100644 --- a/gcc/fortran/trans-openmp.c +++ b/gcc/fortran/trans-openmp.c @@ -3034,30 +3034,16 @@ gfc_trans_omp_clauses (stmtblock_t *block, gfc_omp_clauses *clauses, tree present = gfc_omp_check_optional_argument (decl, true); if (openacc && n->sym->ts.type == BT_CLASS) { - tree type = TREE_TYPE (decl); if (n->sym->attr.optional) sorry ("optional class parameter"); - if (POINTER_TYPE_P (type)) - { - node4 = build_omp_clause (input_location, - OMP_CLAUSE_MAP); - OMP_CLAUSE_SET_MAP_KIND (node4, GOMP_MAP_POINTER); - OMP_CLAUSE_DECL (node4) = decl; - OMP_CLAUSE_SIZE (node4) = size_int (0); - decl = build_fold_indirect_ref (decl); - } tree ptr = gfc_class_data_get (decl); ptr = build_fold_indirect_ref (ptr); OMP_CLAUSE_DECL (node) = ptr; OMP_CLAUSE_SIZE (node) = gfc_class_vtab_size_get (decl); node2 = build_omp_clause (input_location, OMP_CLAUSE_MAP); - OMP_CLAUSE_SET_MAP_KIND (node2, GOMP_MAP_TO_PSET); - OMP_CLAUSE_DECL (node2) = decl; - OMP_CLAUSE_SIZE (node2) = TYPE_SIZE_UNIT (type); - node3 = build_omp_clause (input_location, OMP_CLAUSE_MAP); - OMP_CLAUSE_SET_MAP_KIND (node3, GOMP_MAP_ATTACH_DETACH); - OMP_CLAUSE_DECL (node3) = gfc_class_data_get (decl); - OMP_CLAUSE_SIZE (node3) = size_int (0); + OMP_CLAUSE_SET_MAP_KIND (node2, GOMP_MAP_ATTACH_DETACH); + OMP_CLAUSE_DECL (node2) = gfc_class_data_get (decl); + OMP_CLAUSE_SIZE (node2) = size_int (0); goto finalize_map_clause; } else if (POINTER_TYPE_P (TREE_TYPE (decl)) diff --git a/gcc/gimplify.c b/gcc/gimplify.c index c5e058d6d1f..fcc278d07cf 100644 --- a/gcc/gimplify.c +++ b/gcc/gimplify.c @@ -8658,8 +8658,9 @@ build_struct_comp_nodes (enum tree_code code, tree grp_start, tree grp_end, has array type, else return NULL. */ static tree -extract_base_bit_offset (tree base, tree *base_ref, poly_int64 *bitposp, - poly_offset_int *poffsetp, tree *offsetp) +extract_base_bit_offset (tree base, tree *base_ind, tree *base_ref, + poly_int64 *bitposp, poly_offset_int *poffsetp, + tree *offsetp, bool openmp) { tree offset; poly_int64 bitsize, bitpos; @@ -8667,20 +8668,38 @@ extract_base_bit_offset (tree base, tree *base_ref, poly_int64 *bitposp, int unsignedp, reversep, volatilep = 0; poly_offset_int poffset; + if (base_ind) + *base_ind = NULL_TREE; + if (base_ref) *base_ref = NULL_TREE; base = get_inner_reference (base, &bitsize, &bitpos, &offset, &mode, &unsignedp, &reversep, &volatilep); - tree orig_base = base; - + if (!openmp + && (TREE_CODE (base) == INDIRECT_REF + || (TREE_CODE (base) == MEM_REF + && integer_zerop (TREE_OPERAND (base, 1)))) + && TREE_CODE (TREE_TYPE (TREE_OPERAND (base, 0))) == POINTER_TYPE) + { + if (base_ind) + *base_ind = base; + base = TREE_OPERAND (base, 0); + } if ((TREE_CODE (base) == INDIRECT_REF || (TREE_CODE (base) == MEM_REF && integer_zerop (TREE_OPERAND (base, 1)))) && DECL_P (TREE_OPERAND (base, 0)) && TREE_CODE (TREE_TYPE (TREE_OPERAND (base, 0))) == REFERENCE_TYPE) - base = TREE_OPERAND (base, 0); + { + if (base_ref) + *base_ref = base; + base = TREE_OPERAND (base, 0); + } + + if (!openmp) + STRIP_NOPS (base); if (offset && poly_int_tree_p (offset)) { @@ -8697,10 +8716,6 @@ extract_base_bit_offset (tree base, tree *base_ref, poly_int64 *bitposp, *poffsetp = poffset; *offsetp = offset; - /* Set *BASE_REF if BASE was a dereferenced reference variable. */ - if (base_ref && orig_base != base) - *base_ref = orig_base; - return base; } @@ -8727,6 +8742,48 @@ is_or_contains_p (tree expr, tree base_ptr) return operand_equal_p (expr, base_ptr); } +/* Remove COMPONENT_REFS and indirections from EXPR. */ + +static tree +strip_components_and_deref (tree expr) +{ + while (TREE_CODE (expr) == COMPONENT_REF + || TREE_CODE (expr) == INDIRECT_REF + || (TREE_CODE (expr) == MEM_REF + && integer_zerop (TREE_OPERAND (expr, 1)))) + expr = TREE_OPERAND (expr, 0); + + return expr; +} + +/* Return TRUE if EXPR is something we will use as the base of an aggregate + access, either: + + - a DECL_P. + - a struct component with no indirection ("a.b.c"). + - a struct component with indirection ("a->b->c"). +*/ + +static bool +aggregate_base_p (tree expr) +{ + while (TREE_CODE (expr) == COMPONENT_REF + && (DECL_P (TREE_OPERAND (expr, 0)) + || (TREE_CODE (TREE_OPERAND (expr, 0)) == COMPONENT_REF))) + expr = TREE_OPERAND (expr, 0); + + if (DECL_P (expr)) + return true; + + if (TREE_CODE (expr) == COMPONENT_REF + && (TREE_CODE (TREE_OPERAND (expr, 0)) == INDIRECT_REF + || (TREE_CODE (TREE_OPERAND (expr, 0)) == MEM_REF + && integer_zerop (TREE_OPERAND (TREE_OPERAND (expr, 0), 1))))) + return true; + + return false; +} + /* Implement OpenMP 5.x map ordering rules for target directives. There are several rules, and with some level of ambiguity, hopefully we can at least collect the complexity here in one place. */ @@ -9192,8 +9249,9 @@ build_struct_group (struct gimplify_omp_ctx *ctx, { poly_offset_int coffset; poly_int64 cbitpos; - tree base_ref, tree_coffset; + tree base_ind, base_ref, tree_coffset; tree ocd = OMP_CLAUSE_DECL (c); + bool openmp = !(region_type & ORT_ACC); while (TREE_CODE (ocd) == ARRAY_REF) ocd = TREE_OPERAND (ocd, 0); @@ -9201,8 +9259,8 @@ build_struct_group (struct gimplify_omp_ctx *ctx, if (TREE_CODE (ocd) == INDIRECT_REF) ocd = TREE_OPERAND (ocd, 0); - tree base = extract_base_bit_offset (ocd, &base_ref, - &cbitpos, &coffset, &tree_coffset); + tree base = extract_base_bit_offset (ocd, &base_ind, &base_ref, &cbitpos, + &coffset, &tree_coffset, openmp); bool do_map_struct = (base == decl && !tree_coffset); @@ -9241,12 +9299,7 @@ build_struct_group (struct gimplify_omp_ctx *ctx, return NULL_TREE; /* Nor for attach_detach for OpenMP. */ - if ((code == OMP_TARGET - || code == OMP_TARGET_DATA - || code == OMP_TARGET_UPDATE - || code == OMP_TARGET_ENTER_DATA - || code == OMP_TARGET_EXIT_DATA) - && attach_detach) + if (openmp && attach_detach) { if (DECL_P (decl)) { @@ -9269,12 +9322,15 @@ build_struct_group (struct gimplify_omp_ctx *ctx, OMP_CLAUSE_SET_MAP_KIND (l, k); - if (base_ref) + if (!openmp && base_ind) + OMP_CLAUSE_DECL (l) = unshare_expr (base_ind); + else if (base_ref) OMP_CLAUSE_DECL (l) = unshare_expr (base_ref); else { OMP_CLAUSE_DECL (l) = unshare_expr (decl); - if (!DECL_P (OMP_CLAUSE_DECL (l)) + if (openmp + && !DECL_P (OMP_CLAUSE_DECL (l)) && (gimplify_expr (&OMP_CLAUSE_DECL (l), pre_p, NULL, is_gimple_lvalue, fb_lvalue) == GS_ERROR)) return error_mark_node; @@ -9330,6 +9386,48 @@ build_struct_group (struct gimplify_omp_ctx *ctx, OMP_CLAUSE_CHAIN (c2) = OMP_CLAUSE_CHAIN (l); OMP_CLAUSE_CHAIN (l) = c2; } + else if (!openmp + && (base_ind || base_ref) + && (region_type & ORT_TARGET)) + { + tree c2 = build_omp_clause (OMP_CLAUSE_LOCATION (c), OMP_CLAUSE_MAP); + enum gomp_map_kind mkind = base_ref ? GOMP_MAP_FIRSTPRIVATE_REFERENCE + : GOMP_MAP_FIRSTPRIVATE_POINTER; + OMP_CLAUSE_SET_MAP_KIND (c2, mkind); + OMP_CLAUSE_SIZE (c2) = size_zero_node; + tree sdecl = strip_components_and_deref (decl); + if (DECL_P (decl) + && (POINTER_TYPE_P (TREE_TYPE (sdecl)) + || TREE_CODE (TREE_TYPE (sdecl)) == REFERENCE_TYPE)) + { + /* Insert after struct node. */ + OMP_CLAUSE_CHAIN (c2) = OMP_CLAUSE_CHAIN (l); + OMP_CLAUSE_DECL (c2) = decl; + OMP_CLAUSE_CHAIN (l) = c2; + } + else + { + /* If the ultimate base for this component access is not a + pointer or reference, that means it is a struct component + access itself. Insert a node to be processed on the next + iteration of our caller's loop, which will subsequently be + turned into a new GOMP_MAP_STRUCT mapping itself. + + We need to do this else the non-DECL_P base won't be + rewritten correctly in the offloaded region. */ + tree c2 = build_omp_clause (OMP_CLAUSE_LOCATION (c), + OMP_CLAUSE_MAP); + OMP_CLAUSE_SET_MAP_KIND (c2, GOMP_MAP_FORCE_PRESENT); + OMP_CLAUSE_DECL (c2) = unshare_expr (decl); + OMP_CLAUSE_SIZE (c2) = (DECL_P (decl) + ? DECL_SIZE_UNIT (decl) + : TYPE_SIZE_UNIT (TREE_TYPE (decl))); + tree *next_node = &OMP_CLAUSE_CHAIN (*list_p); + OMP_CLAUSE_CHAIN (c2) = *next_node; + *next_node = c2; + return NULL_TREE; + } + } *flags = GOVD_MAP | GOVD_EXPLICIT; if (GOMP_MAP_ALWAYS_P (OMP_CLAUSE_MAP_KIND (c)) || ptr || attach_detach) *flags |= GOVD_SEEN; @@ -9338,7 +9436,8 @@ build_struct_group (struct gimplify_omp_ctx *ctx, /* If this is a *pointer-to-struct expression, make sure a firstprivate map of the base-pointer exists. */ - if (component_ref_p + if (openmp + && component_ref_p && ((TREE_CODE (decl) == MEM_REF && integer_zerop (TREE_OPERAND (decl, 1))) || INDIRECT_REF_P (decl)) @@ -9368,10 +9467,12 @@ build_struct_group (struct gimplify_omp_ctx *ctx, n->value |= GOVD_SEEN; sc = &OMP_CLAUSE_CHAIN (*osc); /* The struct mapping might be immediately followed by a - FIRSTPRIVATE_REFERENCE if it is a reference. (This added node is - removed in omp-low.c after it has been processed there.) */ + FIRSTPRIVATE_POINTER and/or FIRSTPRIVATE_REFERENCE -- if it's an + indirect access or a reference, or both. (This added node is removed + in omp-low.c after it has been processed there.) */ if (*sc != c - && OMP_CLAUSE_MAP_KIND (*sc) == GOMP_MAP_FIRSTPRIVATE_REFERENCE) + && (OMP_CLAUSE_MAP_KIND (*sc) == GOMP_MAP_FIRSTPRIVATE_POINTER + || OMP_CLAUSE_MAP_KIND (*sc) == GOMP_MAP_FIRSTPRIVATE_REFERENCE)) sc = &OMP_CLAUSE_CHAIN (*sc); for (; *sc != c; sc = &OMP_CLAUSE_CHAIN (*sc)) if ((ptr || attach_detach) && sc == prev_list_p) @@ -9401,9 +9502,10 @@ build_struct_group (struct gimplify_omp_ctx *ctx, == REFERENCE_TYPE)) sc_decl = TREE_OPERAND (sc_decl, 0); - tree base = extract_base_bit_offset (sc_decl, NULL, &bitpos, - &offset, &tree_offset); - if (base != decl) + tree base = extract_base_bit_offset (sc_decl, NULL, NULL, + &bitpos, &offset, + &tree_offset, openmp); + if (!base || !operand_equal_p (base, decl, 0)) break; if (scp) continue; @@ -9524,8 +9626,9 @@ build_struct_group (struct gimplify_omp_ctx *ctx, } else if (*sc != c) { - if (gimplify_expr (pd, pre_p, NULL, is_gimple_lvalue, fb_lvalue) - == GS_ERROR) + if (openmp + && (gimplify_expr (pd, pre_p, NULL, is_gimple_lvalue, fb_lvalue) + == GS_ERROR)) return error_mark_node; /* In the non-pointer case, the mapping clause itself is moved into the correct position in the struct component list, which in this @@ -10027,10 +10130,43 @@ gimplify_scan_omp_clauses (tree *list_p, gimple_seq *pre_p, tree indir_base = NULL_TREE; tree orig_decl = decl; tree decl_ref = NULL_TREE; - if ((region_type & (ORT_ACC | ORT_TARGET | ORT_TARGET_DATA)) != 0 - && TREE_CODE (*pd) == COMPONENT_REF - && OMP_CLAUSE_MAP_KIND (c) == GOMP_MAP_ATTACH_DETACH - && code != OACC_UPDATE) + if ((region_type & ORT_ACC) && TREE_CODE (decl) == COMPONENT_REF) + { + /* Strip off component refs from RHS of e.g. "a->b->c.d.e" + (which would leave "a->b" in that case). This is intended + to be equivalent to the base finding done by + get_inner_reference. */ + while (TREE_CODE (decl) == COMPONENT_REF + && (DECL_P (TREE_OPERAND (decl, 0)) + || (TREE_CODE (TREE_OPERAND (decl, 0)) + == COMPONENT_REF))) + decl = TREE_OPERAND (decl, 0); + + if (TREE_CODE (decl) == COMPONENT_REF) + decl = TREE_OPERAND (decl, 0); + + /* Strip off RHS from "a->b". */ + if ((TREE_CODE (decl) == INDIRECT_REF + || (TREE_CODE (decl) == MEM_REF + && integer_zerop (TREE_OPERAND (decl, 1)))) + && (TREE_CODE (TREE_TYPE (TREE_OPERAND (decl, 0))) + == POINTER_TYPE)) + decl = TREE_OPERAND (decl, 0); + + /* Strip off RHS from "a_ref.b" (where a_ref is + reference-typed). */ + if (TREE_CODE (decl) == INDIRECT_REF + && DECL_P (TREE_OPERAND (decl, 0)) + && (TREE_CODE (TREE_TYPE (TREE_OPERAND (decl, 0))) + == REFERENCE_TYPE)) + decl = TREE_OPERAND (decl, 0); + + STRIP_NOPS (decl); + } + else if ((region_type & (ORT_TARGET | ORT_TARGET_DATA)) != 0 + && TREE_CODE (*pd) == COMPONENT_REF + && OMP_CLAUSE_MAP_KIND (c) == GOMP_MAP_ATTACH_DETACH + && code != OACC_UPDATE) { while (TREE_CODE (decl) == COMPONENT_REF) { @@ -10133,11 +10269,13 @@ gimplify_scan_omp_clauses (tree *list_p, gimple_seq *pre_p, if (code == OACC_UPDATE && OMP_CLAUSE_MAP_KIND (c) == GOMP_MAP_ATTACH_DETACH) OMP_CLAUSE_SET_MAP_KIND (c, GOMP_MAP_ALWAYS_POINTER); - if ((DECL_P (decl) - || (component_ref_p - && (INDIRECT_REF_P (decl) - || TREE_CODE (decl) == MEM_REF - || TREE_CODE (decl) == ARRAY_REF))) + if ((((region_type & ORT_ACC) && aggregate_base_p (decl)) + || (!(region_type & ORT_ACC) + && (DECL_P (decl) + || (component_ref_p + && (INDIRECT_REF_P (decl) + || TREE_CODE (decl) == MEM_REF + || TREE_CODE (decl) == ARRAY_REF))))) && OMP_CLAUSE_MAP_KIND (c) != GOMP_MAP_TO_PSET && OMP_CLAUSE_MAP_KIND (c) != GOMP_MAP_ATTACH && OMP_CLAUSE_MAP_KIND (c) != GOMP_MAP_DETACH diff --git a/gcc/omp-low.c b/gcc/omp-low.c index 707cc4606c8..bb459e6273e 100644 --- a/gcc/omp-low.c +++ b/gcc/omp-low.c @@ -1571,8 +1571,10 @@ scan_sharing_clauses (tree clauses, omp_context *ctx) if (TREE_CODE (decl) == COMPONENT_REF || (TREE_CODE (decl) == INDIRECT_REF && TREE_CODE (TREE_OPERAND (decl, 0)) == COMPONENT_REF - && (TREE_CODE (TREE_TYPE (TREE_OPERAND (decl, 0))) - == REFERENCE_TYPE))) + && (((TREE_CODE (TREE_TYPE (TREE_OPERAND (decl, 0))) + == REFERENCE_TYPE) + || (TREE_CODE (TREE_TYPE (TREE_OPERAND (decl, 0))) + == POINTER_TYPE))))) break; if (DECL_SIZE (decl) && TREE_CODE (DECL_SIZE (decl)) != INTEGER_CST) @@ -13749,6 +13751,7 @@ lower_omp_target (gimple_stmt_iterator *gsi_p, omp_context *ctx) if (OMP_CLAUSE_MAP_KIND (c) == GOMP_MAP_FIRSTPRIVATE_REFERENCE) is_ref = false; bool ref_to_array = false; + bool ref_to_ptr = false; if (is_ref) { type = TREE_TYPE (type); @@ -13767,6 +13770,12 @@ lower_omp_target (gimple_stmt_iterator *gsi_p, omp_context *ctx) new_var = decl2; type = TREE_TYPE (new_var); } + else if (TREE_CODE (type) == REFERENCE_TYPE + && TREE_CODE (TREE_TYPE (type)) == POINTER_TYPE) + { + type = TREE_TYPE (type); + ref_to_ptr = true; + } x = build_receiver_ref (OMP_CLAUSE_DECL (prev), false, ctx); x = fold_convert_loc (clause_loc, type, x); if (!integer_zerop (OMP_CLAUSE_SIZE (c))) @@ -13783,7 +13792,8 @@ lower_omp_target (gimple_stmt_iterator *gsi_p, omp_context *ctx) if (ref_to_array) x = fold_convert_loc (clause_loc, TREE_TYPE (new_var), x); gimplify_expr (&x, &new_body, NULL, is_gimple_val, fb_rvalue); - if (is_ref && !ref_to_array) + if ((is_ref && !ref_to_array) + || ref_to_ptr) { tree t = create_tmp_var_raw (type, get_name (var)); gimple_add_tmp_var (t); diff --git a/gcc/testsuite/g++.dg/goacc/member-array-acc.C b/gcc/testsuite/g++.dg/goacc/member-array-acc.C new file mode 100644 index 00000000000..e0c11570f5d --- /dev/null +++ b/gcc/testsuite/g++.dg/goacc/member-array-acc.C @@ -0,0 +1,13 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-fdump-tree-gimple" } */ + +struct Foo { + float *a; + void init(int N) { + a = new float[N]; + #pragma acc enter data create(a[0:N]) + } +}; +int main() { Foo x; x.init(1024); } + +/* { dg-final { scan-tree-dump {struct:\*\(struct Foo \*\) this \[len: 1\]\) map\(alloc:\(\(struct Foo \*\) this\)->a \[len: [0-9]+\]\) map\(alloc:\*_[0-9]+ \[len: _[0-9]+\]\) map\(attach:\(\(struct Foo \*\) this\)->a \[bias: 0\]\)} "gimple" } } */ diff --git a/gcc/testsuite/g++.dg/gomp/member-array-omp.C b/gcc/testsuite/g++.dg/gomp/member-array-omp.C new file mode 100644 index 00000000000..a53aa44592d --- /dev/null +++ b/gcc/testsuite/g++.dg/gomp/member-array-omp.C @@ -0,0 +1,13 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-fdump-tree-gimple" } */ + +struct Foo { + float *a; + void init(int N) { + a = new float[N]; + #pragma omp target enter data map(alloc:a[0:N]) + } +}; +int main() { Foo x; x.init(1024); } + +/* { dg-final { scan-tree-dump {map\(alloc:\*_[0-9]+ \[len: _[0-9]+\]\) map\(attach:this->a \[bias: 0\]\)} "gimple" } } */ diff --git a/libgomp/testsuite/libgomp.oacc-c++/deep-copy-17.C b/libgomp/testsuite/libgomp.oacc-c++/deep-copy-17.C new file mode 100644 index 00000000000..dacbb520f3d --- /dev/null +++ b/libgomp/testsuite/libgomp.oacc-c++/deep-copy-17.C @@ -0,0 +1,101 @@ +#include + +/* Test attach/detach operation with pointers and references to structs. */ + +typedef struct mystruct { + int *a; + int b; + int *c; + int d; + int *e; +} mystruct; + +void str (void) +{ + int a[10], c[10], e[10]; + mystruct m = { .a = a, .c = c, .e = e }; + a[0] = 5; + c[0] = 7; + e[0] = 9; + #pragma acc parallel copy(m.a[0:10], m.b, m.c[0:10], m.d, m.e[0:10]) + { + m.a[0] = m.c[0] + m.e[0]; + } + assert (m.a[0] == 7 + 9); +} + +void strp (void) +{ + int *a = new int[10]; + int *c = new int[10]; + int *e = new int[10]; + mystruct *m = new mystruct; + m->a = a; + m->c = c; + m->e = e; + a[0] = 6; + c[0] = 8; + e[0] = 10; + #pragma acc parallel copy(m->a[0:10], m->b, m->c[0:10], m->d, m->e[0:10]) + { + m->a[0] = m->c[0] + m->e[0]; + } + assert (m->a[0] == 8 + 10); + delete m; + delete[] a; + delete[] c; + delete[] e; +} + +void strr (void) +{ + int *a = new int[10]; + int *c = new int[10]; + int *e = new int[10]; + mystruct m; + mystruct &n = m; + n.a = a; + n.c = c; + n.e = e; + a[0] = 7; + c[0] = 9; + e[0] = 11; + #pragma acc parallel copy(n.a[0:10], n.b, n.c[0:10], n.d, n.e[0:10]) + { + n.a[0] = n.c[0] + n.e[0]; + } + assert (n.a[0] == 9 + 11); + delete[] a; + delete[] c; + delete[] e; +} + +void strrp (void) +{ + int a[10], c[10], e[10]; + mystruct *m = new mystruct; + mystruct *&n = m; + n->a = a; + n->b = 3; + n->c = c; + n->d = 5; + n->e = e; + a[0] = 8; + c[0] = 10; + e[0] = 12; + #pragma acc parallel copy(n->a[0:10], n->c[0:10], n->e[0:10]) + { + n->a[0] = n->c[0] + n->e[0]; + } + assert (n->a[0] == 10 + 12); + delete m; +} + +int main (int argc, char *argv[]) +{ + str (); + strp (); + strr (); + strrp (); + return 0; +} diff --git a/libgomp/testsuite/libgomp.oacc-c-c++-common/deep-copy-15.c b/libgomp/testsuite/libgomp.oacc-c-c++-common/deep-copy-15.c new file mode 100644 index 00000000000..27fe1a9d07d --- /dev/null +++ b/libgomp/testsuite/libgomp.oacc-c-c++-common/deep-copy-15.c @@ -0,0 +1,68 @@ +#include + +/* Test multiple struct dereferences on one directive, and slices starting at + non-zero. */ + +typedef struct { + int *a; + int *b; + int *c; +} mystruct; + +int main(int argc, char* argv[]) +{ + const int N = 1024; + mystruct *m = (mystruct *) malloc (sizeof (*m)); + int i; + + m->a = (int *) malloc (N * sizeof (int)); + m->b = (int *) malloc (N * sizeof (int)); + m->c = (int *) malloc (N * sizeof (int)); + + for (i = 0; i < N; i++) + { + m->a[i] = 0; + m->b[i] = 0; + m->c[i] = 0; + } + + for (int i = 0; i < 99; i++) + { + int j; +#pragma acc parallel loop copy(m->a[0:N]) + for (j = 0; j < N; j++) + m->a[j]++; +#pragma acc parallel loop copy(m->b[0:N], m->c[5:N-10]) + for (j = 0; j < N; j++) + { + m->b[j]++; + if (j > 5 && j < N - 5) + m->c[j]++; + } + } + + for (i = 0; i < N; i++) + { + if (m->a[i] != 99) + abort (); + if (m->b[i] != 99) + abort (); + if (i > 5 && i < N-5) + { + if (m->c[i] != 99) + abort (); + } + else + { + if (m->c[i] != 0) + abort (); + } + } + + free (m->a); + free (m->b); + free (m->c); + free (m); + + return 0; +} diff --git a/libgomp/testsuite/libgomp.oacc-c-c++-common/deep-copy-16.c b/libgomp/testsuite/libgomp.oacc-c-c++-common/deep-copy-16.c new file mode 100644 index 00000000000..a7308e8c98b --- /dev/null +++ b/libgomp/testsuite/libgomp.oacc-c-c++-common/deep-copy-16.c @@ -0,0 +1,231 @@ +#include + +/* Test mapping chained indirect struct accesses, mixed in different ways. */ + +typedef struct { + int *a; + int b; + int *c; +} str1; + +typedef struct { + int d; + int *e; + str1 *f; +} str2; + +typedef struct { + int g; + int h; + str2 *s2; +} str3; + +typedef struct { + str3 m; + str3 n; +} str4; + +void +zero_arrays (str4 *s, int N) +{ + for (int i = 0; i < N; i++) + { + s->m.s2->e[i] = 0; + s->m.s2->f->a[i] = 0; + s->m.s2->f->c[i] = 0; + s->n.s2->e[i] = 0; + s->n.s2->f->a[i] = 0; + s->n.s2->f->c[i] = 0; + } +} + +void +alloc_s2 (str2 **s, int N) +{ + (*s) = (str2 *) malloc (sizeof (str2)); + (*s)->f = (str1 *) malloc (sizeof (str1)); + (*s)->e = (int *) malloc (sizeof (int) * N); + (*s)->f->a = (int *) malloc (sizeof (int) * N); + (*s)->f->c = (int *) malloc (sizeof (int) * N); +} + +int main (int argc, char* argv[]) +{ + const int N = 1024; + str4 p, *q; + int i; + + alloc_s2 (&p.m.s2, N); + alloc_s2 (&p.n.s2, N); + q = (str4 *) malloc (sizeof (str4)); + alloc_s2 (&q->m.s2, N); + alloc_s2 (&q->n.s2, N); + + zero_arrays (&p, N); + + for (int i = 0; i < 99; i++) + { +#pragma acc enter data copyin(p.m.s2[:1]) +#pragma acc parallel loop copy(p.m.s2->e[:N]) + for (int j = 0; j < N; j++) + p.m.s2->e[j]++; +#pragma acc exit data delete(p.m.s2[:1]) + } + + for (i = 0; i < N; i++) + if (p.m.s2->e[i] != 99) + abort (); + + zero_arrays (&p, N); + + for (int i = 0; i < 99; i++) + { +#pragma acc enter data copyin(p.m.s2[:1]) +#pragma acc enter data copyin(p.m.s2->f[:1]) +#pragma acc parallel loop copy(p.m.s2->f->a[:N]) copy(p.m.s2->f->c[:N]) + for (int j = 0; j < N; j++) + { + p.m.s2->f->a[j]++; + p.m.s2->f->c[j]++; + } +#pragma acc exit data delete(p.m.s2->f[:1]) +#pragma acc exit data delete(p.m.s2[:1]) + } + + for (i = 0; i < N; i++) + if (p.m.s2->f->a[i] != 99 || p.m.s2->f->c[i] != 99) + abort (); + + zero_arrays (&p, N); + + for (int i = 0; i < 99; i++) + { +#pragma acc enter data copyin(p.m.s2[:1]) copyin(p.n.s2[:1]) +#pragma acc enter data copyin(p.m.s2->f[:1]) copyin(p.n.s2->f[:1]) +#pragma acc parallel loop copy(p.m.s2->f->a[:N]) copy(p.m.s2->f->c[:N]) \ + copy(p.n.s2->f->a[:N]) copy(p.n.s2->f->c[:N]) + for (int j = 0; j < N; j++) + { + p.m.s2->f->a[j]++; + p.m.s2->f->c[j]++; + p.n.s2->f->a[j]++; + p.n.s2->f->c[j]++; + } +#pragma acc exit data delete(p.m.s2->f[:1]) delete(p.n.s2->f[:1]) +#pragma acc exit data delete(p.m.s2[:1]) delete(p.n.s2[:1]) + } + + for (i = 0; i < N; i++) + if (p.m.s2->f->a[i] != 99 || p.m.s2->f->c[i] != 99 + || p.n.s2->f->a[i] != 99 || p.n.s2->f->c[i] != 99) + abort (); + + zero_arrays (&p, N); + + for (int i = 0; i < 99; i++) + { +#pragma acc enter data copyin(p.m.s2[:1]) copyin(p.n.s2[:1]) +#pragma acc enter data copyin(p.n.s2->e[:N]) copyin(p.n.s2->f[:1]) \ + copyin(p.m.s2->f[:1]) +#pragma acc parallel loop copy(p.m.s2->f->a[:N]) copy(p.n.s2->f->a[:N]) + for (int j = 0; j < N; j++) + { + p.m.s2->f->a[j]++; + p.n.s2->f->a[j]++; + p.n.s2->e[j]++; + } +#pragma acc exit data delete(p.m.s2->f[:1]) delete(p.n.s2->f[:1]) \ + copyout(p.n.s2->e[:N]) +#pragma acc exit data delete(p.m.s2[:1]) delete(p.n.s2[:1]) + } + + for (i = 0; i < N; i++) + if (p.m.s2->f->a[i] != 99 || p.n.s2->f->a[i] != 99 + || p.n.s2->e[i] != 99) + abort (); + + zero_arrays (q, N); + + for (int i = 0; i < 99; i++) + { +#pragma acc enter data copyin(q->m.s2[:1]) +#pragma acc parallel loop copy(q->m.s2->e[:N]) + for (int j = 0; j < N; j++) + q->m.s2->e[j]++; +#pragma acc exit data delete(q->m.s2[:1]) + } + + for (i = 0; i < N; i++) + if (q->m.s2->e[i] != 99) + abort (); + + zero_arrays (q, N); + + for (int i = 0; i < 99; i++) + { +#pragma acc enter data copyin(q->m.s2[:1]) +#pragma acc enter data copyin(q->m.s2->f[:1]) +#pragma acc parallel loop copy(q->m.s2->f->a[:N]) copy(q->m.s2->f->c[:N]) + for (int j = 0; j < N; j++) + { + q->m.s2->f->a[j]++; + q->m.s2->f->c[j]++; + } +#pragma acc exit data delete(q->m.s2->f[:1]) +#pragma acc exit data delete(q->m.s2[:1]) + } + + for (i = 0; i < N; i++) + if (q->m.s2->f->a[i] != 99 || q->m.s2->f->c[i] != 99) + abort (); + + zero_arrays (q, N); + + for (int i = 0; i < 99; i++) + { +#pragma acc enter data copyin(q->m.s2[:1]) copyin(q->n.s2[:1]) +#pragma acc enter data copyin(q->m.s2->f[:1]) copyin(q->n.s2->f[:1]) +#pragma acc parallel loop copy(q->m.s2->f->a[:N]) copy(q->m.s2->f->c[:N]) \ + copy(q->n.s2->f->a[:N]) copy(q->n.s2->f->c[:N]) + for (int j = 0; j < N; j++) + { + q->m.s2->f->a[j]++; + q->m.s2->f->c[j]++; + q->n.s2->f->a[j]++; + q->n.s2->f->c[j]++; + } +#pragma acc exit data delete(q->m.s2->f[:1]) delete(q->n.s2->f[:1]) +#pragma acc exit data delete(q->m.s2[:1]) delete(q->n.s2[:1]) + } + + for (i = 0; i < N; i++) + if (q->m.s2->f->a[i] != 99 || q->m.s2->f->c[i] != 99 + || q->n.s2->f->a[i] != 99 || q->n.s2->f->c[i] != 99) + abort (); + + zero_arrays (q, N); + + for (int i = 0; i < 99; i++) + { +#pragma acc enter data copyin(q->m.s2[:1]) copyin(q->n.s2[:1]) +#pragma acc enter data copyin(q->n.s2->e[:N]) copyin(q->m.s2->f[:1]) \ + copyin(q->n.s2->f[:1]) +#pragma acc parallel loop copy(q->m.s2->f->a[:N]) copy(q->n.s2->f->a[:N]) + for (int j = 0; j < N; j++) + { + q->m.s2->f->a[j]++; + q->n.s2->f->a[j]++; + q->n.s2->e[j]++; + } +#pragma acc exit data delete(q->m.s2->f[:1]) delete(q->n.s2->f[:1]) \ + copyout(q->n.s2->e[:N]) +#pragma acc exit data delete(q->m.s2[:1]) delete(q->n.s2[:1]) + } + + for (i = 0; i < N; i++) + if (q->m.s2->f->a[i] != 99 || q->n.s2->f->a[i] != 99 + || q->n.s2->e[i] != 99) + abort (); + + return 0; +} From patchwork Thu Nov 25 14:08:39 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Julian Brown X-Patchwork-Id: 1559732 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=gcc.gnu.org (client-ip=2620:52:3:1:0:246e:9693:128c; helo=sourceware.org; envelope-from=gcc-patches-bounces+incoming=patchwork.ozlabs.org@gcc.gnu.org; receiver=) Received: from sourceware.org (server2.sourceware.org [IPv6:2620:52:3:1:0:246e:9693:128c]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by bilbo.ozlabs.org (Postfix) with ESMTPS id 4J0KYx2KPZz9sVc for ; Fri, 26 Nov 2021 01:11:49 +1100 (AEDT) Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 4C6C2385843B for ; Thu, 25 Nov 2021 14:11:47 +0000 (GMT) X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from esa4.mentor.iphmx.com (esa4.mentor.iphmx.com [68.232.137.252]) by sourceware.org (Postfix) with ESMTPS id AF87A385843F for ; Thu, 25 Nov 2021 14:08:53 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org AF87A385843F Authentication-Results: sourceware.org; dmarc=none (p=none dis=none) header.from=codesourcery.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=mentor.com IronPort-SDR: yLXA0i34hcm9ecfre1RSC64HOZznMGq21YVLuFMOE7KP6v7Ceaim8g1TzffhetwIYEaismWKHt 5QYKPoyzXY+uH8GUxWSZ5qlYxXt1+FXZ66JLLKJPLf14etE/NiRlq2JGO5vgvG5BiA609j9uSN CnP/p71LNGcf0vNsna92TQ0F7i5IsjhqU211j5z2qp4AZ5Xczb4cN3wSAZ8Ov/kEZ/M8DerRa3 FPo/BJRdlyy4UV0cW6ZT1/XsyEEbvhy4wVh4Frd6MOBepe9T/RUH1SElD37G9SNklXNc12boql MbDcuRWgxlHbdLjLsJyXh/s2 X-IronPort-AV: E=Sophos;i="5.87,263,1631606400"; d="scan'208";a="68932309" Received: from orw-gwy-02-in.mentorg.com ([192.94.38.167]) by esa4.mentor.iphmx.com with ESMTP; 25 Nov 2021 06:08:52 -0800 IronPort-SDR: aTuhWWNi1bhi2qtUGyAMsPTux7fY1ieOaBeMd9sUmmWonV3dG7uAz1Rxd7HqZ53Sh9hodKKidg IxygOn/VM7esTu0ziEMTcQ8z0QeeAc8oQP0rCQXuDjXoeEkgy4pJQtSPw5U3bO8xcWwZAC4GU7 4VFLqEhJ2P8LqoXfiWfxWQY7bYGaJufpH5I0qSoKMPqFWItILNMezqXRvILmnA+EZM2YZzwmtR cPrJF/m8yEeHD9YeuF3ugIqAft1cETvxceC82OE4R44bFC7w9h2skIROO1EjjI97WBdMiz50rZ uPk= From: Julian Brown To: Subject: [PATCH 05/16] Remove base_ind/base_ref handling from extract_base_bit_offset Date: Thu, 25 Nov 2021 06:08:39 -0800 Message-ID: <20211125140843.111405-1-julian@codesourcery.com> X-Mailer: git-send-email 2.29.2 MIME-Version: 1.0 X-Originating-IP: [137.202.0.90] X-ClientProxiedBy: SVR-IES-MBX-08.mgc.mentorg.com (139.181.222.8) To SVR-IES-MBX-04.mgc.mentorg.com (139.181.222.4) X-Spam-Status: No, score=-11.8 required=5.0 tests=BAYES_00, GIT_PATCH_0, HEADER_FROM_DIFFERENT_DOMAINS, KAM_DMARC_STATUS, KAM_SHORT, SPF_HELO_PASS, SPF_PASS, 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: , Cc: Jakub Jelinek , Thomas Schwinge Errors-To: gcc-patches-bounces+incoming=patchwork.ozlabs.org@gcc.gnu.org Sender: "Gcc-patches" In preparation for follow-up patches extending struct dereference handling for OpenMP, this patch removes base_ind/base_ref handling from gimplify.c:extract_base_bit_offset. This arguably simplifies some of the code around the callers of the function also, though subsequent patches modify those parts further. (This one has already been approved, pending approval of the rest of the series: https://gcc.gnu.org/pipermail/gcc-patches/2021-October/581426.html) 2021-09-29 Julian Brown gcc/ * gimplify.c (extract_base_bit_offset): Remove BASE_IND, BASE_REF and OPENMP parameters. (strip_indirections): New function. (build_struct_group): Update calls to extract_base_bit_offset. Rearrange indirect/reference handling accordingly. Use extracted base instead of passed-in decl when grouping component accesses together. --- gcc/gimplify.c | 109 ++++++++++++++++++++++++++----------------------- 1 file changed, 57 insertions(+), 52 deletions(-) diff --git a/gcc/gimplify.c b/gcc/gimplify.c index fcc278d07cf..73b839daa09 100644 --- a/gcc/gimplify.c +++ b/gcc/gimplify.c @@ -8658,9 +8658,8 @@ build_struct_comp_nodes (enum tree_code code, tree grp_start, tree grp_end, has array type, else return NULL. */ static tree -extract_base_bit_offset (tree base, tree *base_ind, tree *base_ref, - poly_int64 *bitposp, poly_offset_int *poffsetp, - tree *offsetp, bool openmp) +extract_base_bit_offset (tree base, poly_int64 *bitposp, + poly_offset_int *poffsetp, tree *offsetp) { tree offset; poly_int64 bitsize, bitpos; @@ -8668,38 +8667,12 @@ extract_base_bit_offset (tree base, tree *base_ind, tree *base_ref, int unsignedp, reversep, volatilep = 0; poly_offset_int poffset; - if (base_ind) - *base_ind = NULL_TREE; - - if (base_ref) - *base_ref = NULL_TREE; + STRIP_NOPS (base); base = get_inner_reference (base, &bitsize, &bitpos, &offset, &mode, &unsignedp, &reversep, &volatilep); - if (!openmp - && (TREE_CODE (base) == INDIRECT_REF - || (TREE_CODE (base) == MEM_REF - && integer_zerop (TREE_OPERAND (base, 1)))) - && TREE_CODE (TREE_TYPE (TREE_OPERAND (base, 0))) == POINTER_TYPE) - { - if (base_ind) - *base_ind = base; - base = TREE_OPERAND (base, 0); - } - if ((TREE_CODE (base) == INDIRECT_REF - || (TREE_CODE (base) == MEM_REF - && integer_zerop (TREE_OPERAND (base, 1)))) - && DECL_P (TREE_OPERAND (base, 0)) - && TREE_CODE (TREE_TYPE (TREE_OPERAND (base, 0))) == REFERENCE_TYPE) - { - if (base_ref) - *base_ref = base; - base = TREE_OPERAND (base, 0); - } - - if (!openmp) - STRIP_NOPS (base); + STRIP_NOPS (base); if (offset && poly_int_tree_p (offset)) { @@ -8756,6 +8729,17 @@ strip_components_and_deref (tree expr) return expr; } +static tree +strip_indirections (tree expr) +{ + while (TREE_CODE (expr) == INDIRECT_REF + || (TREE_CODE (expr) == MEM_REF + && integer_zerop (TREE_OPERAND (expr, 1)))) + expr = TREE_OPERAND (expr, 0); + + return expr; +} + /* Return TRUE if EXPR is something we will use as the base of an aggregate access, either: @@ -9249,7 +9233,7 @@ build_struct_group (struct gimplify_omp_ctx *ctx, { poly_offset_int coffset; poly_int64 cbitpos; - tree base_ind, base_ref, tree_coffset; + tree tree_coffset; tree ocd = OMP_CLAUSE_DECL (c); bool openmp = !(region_type & ORT_ACC); @@ -9259,10 +9243,25 @@ build_struct_group (struct gimplify_omp_ctx *ctx, if (TREE_CODE (ocd) == INDIRECT_REF) ocd = TREE_OPERAND (ocd, 0); - tree base = extract_base_bit_offset (ocd, &base_ind, &base_ref, &cbitpos, - &coffset, &tree_coffset, openmp); + tree base = extract_base_bit_offset (ocd, &cbitpos, &coffset, &tree_coffset); + tree sbase; - bool do_map_struct = (base == decl && !tree_coffset); + if (openmp) + { + if (TREE_CODE (base) == INDIRECT_REF + && TREE_CODE (TREE_TYPE (TREE_OPERAND (base, 0))) == REFERENCE_TYPE) + sbase = strip_indirections (base); + else + sbase = base; + } + else + { + sbase = strip_indirections (base); + + STRIP_NOPS (sbase); + } + + bool do_map_struct = (sbase == decl && !tree_coffset); /* Here, DECL is usually a DECL_P, unless we have chained indirect member accesses, e.g. mystruct->a->b. In that case it'll be the "mystruct->a" @@ -9322,19 +9321,12 @@ build_struct_group (struct gimplify_omp_ctx *ctx, OMP_CLAUSE_SET_MAP_KIND (l, k); - if (!openmp && base_ind) - OMP_CLAUSE_DECL (l) = unshare_expr (base_ind); - else if (base_ref) - OMP_CLAUSE_DECL (l) = unshare_expr (base_ref); - else - { - OMP_CLAUSE_DECL (l) = unshare_expr (decl); - if (openmp - && !DECL_P (OMP_CLAUSE_DECL (l)) - && (gimplify_expr (&OMP_CLAUSE_DECL (l), pre_p, NULL, - is_gimple_lvalue, fb_lvalue) == GS_ERROR)) - return error_mark_node; - } + OMP_CLAUSE_DECL (l) = unshare_expr (base); + if (openmp + && !DECL_P (OMP_CLAUSE_DECL (l)) + && (gimplify_expr (&OMP_CLAUSE_DECL (l), pre_p, NULL, + is_gimple_lvalue, fb_lvalue) == GS_ERROR)) + return error_mark_node; OMP_CLAUSE_SIZE (l) = (!attach ? size_int (1) : (DECL_P (OMP_CLAUSE_DECL (l)) @@ -9370,6 +9362,20 @@ build_struct_group (struct gimplify_omp_ctx *ctx, else list_p = insert_node_after (l, list_p); + bool base_ref + = (TREE_CODE (base) == INDIRECT_REF + && ((TREE_CODE (TREE_TYPE (TREE_OPERAND (base, 0))) + == REFERENCE_TYPE) + || ((TREE_CODE (TREE_OPERAND (base, 0)) == INDIRECT_REF) + && (TREE_CODE (TREE_TYPE (TREE_OPERAND + (TREE_OPERAND (base, 0), 0))) + == REFERENCE_TYPE)))); + bool base_ind = ((TREE_CODE (base) == INDIRECT_REF + || (TREE_CODE (base) == MEM_REF + && integer_zerop (TREE_OPERAND (base, 1)))) + && (TREE_CODE (TREE_TYPE (TREE_OPERAND (base, 0))) + == POINTER_TYPE)); + /* Handle pointers to structs and references to structs: these cases have an additional GOMP_MAP_FIRSTPRIVATE_{REFERENCE,POINTER} node inserted after the GOMP_MAP_STRUCT node. References to pointers @@ -9502,10 +9508,9 @@ build_struct_group (struct gimplify_omp_ctx *ctx, == REFERENCE_TYPE)) sc_decl = TREE_OPERAND (sc_decl, 0); - tree base = extract_base_bit_offset (sc_decl, NULL, NULL, - &bitpos, &offset, - &tree_offset, openmp); - if (!base || !operand_equal_p (base, decl, 0)) + tree base2 = extract_base_bit_offset (sc_decl, &bitpos, &offset, + &tree_offset); + if (!base2 || !operand_equal_p (base2, base, 0)) break; if (scp) continue; From patchwork Thu Nov 25 14:08:40 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Julian Brown X-Patchwork-Id: 1559733 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=gcc.gnu.org (client-ip=2620:52:3:1:0:246e:9693:128c; helo=sourceware.org; envelope-from=gcc-patches-bounces+incoming=patchwork.ozlabs.org@gcc.gnu.org; receiver=) Received: from sourceware.org (server2.sourceware.org [IPv6:2620:52:3:1:0:246e:9693:128c]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by bilbo.ozlabs.org (Postfix) with ESMTPS id 4J0KZW317Pz9sVc for ; Fri, 26 Nov 2021 01:12:19 +1100 (AEDT) Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 0B03E3858003 for ; Thu, 25 Nov 2021 14:12:17 +0000 (GMT) X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from esa4.mentor.iphmx.com (esa4.mentor.iphmx.com [68.232.137.252]) by sourceware.org (Postfix) with ESMTPS id A01A6385800F for ; Thu, 25 Nov 2021 14:08:55 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org A01A6385800F Authentication-Results: sourceware.org; dmarc=none (p=none dis=none) header.from=codesourcery.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=mentor.com IronPort-SDR: 5rYaIBL05nTh6ufC0T6TVJocy27QcUt5W357lWDOxRMtApKHF7JEI2XZrlQtxKBTghXPeo9NXp qg5xuqBb2y+Jru/tGk7PpC31hPZusmzgHZkO447En4NJsEsFxNVf8B0TWBeBYeJMO1RACpnSWj zB45iBJyDsiziRrYyM75cygdPzcQbp5/MmIaRxMMCR5OqS+SE8ZuCMd/clP9NKcztKFiHNdiVN DaUNT73iVxz9K5A6tTV/mNJBy52qYif1jLuPiiw570nAJflJ4sZwD4uY64lgoIYKQPPcCU8GkC mfpRt+r8aSnX3c6QWTRkxhF/ X-IronPort-AV: E=Sophos;i="5.87,263,1631606400"; d="scan'208";a="68932311" Received: from orw-gwy-02-in.mentorg.com ([192.94.38.167]) by esa4.mentor.iphmx.com with ESMTP; 25 Nov 2021 06:08:55 -0800 IronPort-SDR: tYcXC5EZENwX4jTOe3mFu107CBcLB7SRJZJPBAnwjWwHDr0+jGgh60LXOyAFn8jQLRRZQwB9uy ZCf0uUqt+MRDXMNoHx1MNGLs/YQTMeVUYd/kMygTpcWY7uDVO+5jnrPx1PHT92YPZOSo5edjvk 6i6T4KwCSIkWR8gzoSFHejV5IB3c29RLB+w2diwaDTUYkPv4rIlxSBc8SguBi2XyPmOMTwZuHl NjCQ+cVtd+Js0Q/nfSq3OUgp26H3tzDCF47ncBU/9IpSIk1bzCQI3va3vwqy0SJScG8UAGE2VO +GY= From: Julian Brown To: Subject: [PATCH 06/16] OpenMP 5.0: Clause ordering for OpenMP 5.0 (topological sorting by base pointer) Date: Thu, 25 Nov 2021 06:08:40 -0800 Message-ID: <20211125140843.111405-2-julian@codesourcery.com> X-Mailer: git-send-email 2.29.2 In-Reply-To: <20211125140843.111405-1-julian@codesourcery.com> References: <20211125140843.111405-1-julian@codesourcery.com> MIME-Version: 1.0 X-Originating-IP: [137.202.0.90] X-ClientProxiedBy: SVR-IES-MBX-08.mgc.mentorg.com (139.181.222.8) To SVR-IES-MBX-04.mgc.mentorg.com (139.181.222.4) X-Spam-Status: No, score=-11.8 required=5.0 tests=BAYES_00, GIT_PATCH_0, HEADER_FROM_DIFFERENT_DOMAINS, KAM_DMARC_STATUS, KAM_SHORT, SPF_HELO_PASS, SPF_PASS, 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: , Cc: Jakub Jelinek , Thomas Schwinge Errors-To: gcc-patches-bounces+incoming=patchwork.ozlabs.org@gcc.gnu.org Sender: "Gcc-patches" This patch reimplements the omp_target_reorder_clauses function in anticipation of supporting "deeper" struct mappings (that is, with several structure dereference operators, or similar). The idea is that in place of the (possibly quadratic) algorithm in omp_target_reorder_clauses that greedily moves clauses containing addresses that are subexpressions of other addresses before those other addresses, we employ a topological sort algorithm to calculate a proper order for map clauses. This should run in linear time, and hopefully handles degenerate cases where multiple "levels" of indirect accesses are present on a given directive. The new method also takes care to keep clause groups together, addressing the concerns raised in: https://gcc.gnu.org/pipermail/gcc-patches/2021-May/570501.html To figure out if some given clause depends on a base pointer in another clause, we strip off the outer layers of the address expression, and check (via a tree_operand_hash hash table we have built) if the result is a "base pointer" as defined in OpenMP 5.0 (1.2.6 Data Terminology). There are some subtleties involved, however: - We must treat MEM_REF with zero offset the same as INDIRECT_REF. This should probably be fixed in the front ends instead so we always use a canonical form (probably INDIRECT_REF). The following patch shows one instance of the problem, but there may be others: https://gcc.gnu.org/pipermail/gcc-patches/2021-May/571382.html - Mapping a whole struct implies mapping each of that struct's elements, which may be base pointers. Because those base pointers aren't necessarily explicitly referenced in the directive in question, we treat the whole-struct mapping as a dependency instead. This version of the patch fixes a bug in omp_reorder_mapping_groups, relative to the last version posted. OK? Thanks, Julian 2021-11-23 Julian Brown gcc/ * gimplify.c (is_or_contains_p, omp_target_reorder_clauses): Delete functions. (omp_tsort_mark): Add enum. (omp_mapping_group): Add struct. (debug_mapping_group, omp_get_base_pointer, omp_get_attachment, omp_group_last, omp_gather_mapping_groups, omp_group_base, omp_index_mapping_groups, omp_containing_struct, omp_tsort_mapping_groups_1, omp_tsort_mapping_groups, omp_segregate_mapping_groups, omp_reorder_mapping_groups): New functions. (gimplify_scan_omp_clauses): Call above functions instead of omp_target_reorder_clauses, unless we've seen an error. * omp-low.c (scan_sharing_clauses): Avoid strict test if we haven't sorted mapping groups. gcc/testsuite/ * g++.dg/gomp/target-lambda-1.C: Adjust expected output. * g++.dg/gomp/target-this-3.C: Likewise. * g++.dg/gomp/target-this-4.C: Likewise. --- gcc/gimplify.c | 807 +++++++++++++++++++- gcc/omp-low.c | 7 +- gcc/testsuite/g++.dg/gomp/target-lambda-1.C | 6 +- gcc/testsuite/g++.dg/gomp/target-this-3.C | 4 +- gcc/testsuite/g++.dg/gomp/target-this-4.C | 4 +- 5 files changed, 791 insertions(+), 37 deletions(-) diff --git a/gcc/gimplify.c b/gcc/gimplify.c index 73b839daa09..6778fb25e45 100644 --- a/gcc/gimplify.c +++ b/gcc/gimplify.c @@ -8692,29 +8692,6 @@ extract_base_bit_offset (tree base, poly_int64 *bitposp, return base; } -/* Returns true if EXPR is or contains (as a sub-component) BASE_PTR. */ - -static bool -is_or_contains_p (tree expr, tree base_ptr) -{ - if ((TREE_CODE (expr) == INDIRECT_REF && TREE_CODE (base_ptr) == MEM_REF) - || (TREE_CODE (expr) == MEM_REF && TREE_CODE (base_ptr) == INDIRECT_REF)) - return operand_equal_p (TREE_OPERAND (expr, 0), - TREE_OPERAND (base_ptr, 0)); - while (!operand_equal_p (expr, base_ptr)) - { - if (TREE_CODE (base_ptr) == COMPOUND_EXPR) - base_ptr = TREE_OPERAND (base_ptr, 1); - if (TREE_CODE (base_ptr) == COMPONENT_REF - || TREE_CODE (base_ptr) == POINTER_PLUS_EXPR - || TREE_CODE (base_ptr) == SAVE_EXPR) - base_ptr = TREE_OPERAND (base_ptr, 0); - else - break; - } - return operand_equal_p (expr, base_ptr); -} - /* Remove COMPONENT_REFS and indirections from EXPR. */ static tree @@ -8768,6 +8745,7 @@ aggregate_base_p (tree expr) return false; } +#if 0 /* Implement OpenMP 5.x map ordering rules for target directives. There are several rules, and with some level of ambiguity, hopefully we can at least collect the complexity here in one place. */ @@ -8947,6 +8925,761 @@ omp_target_reorder_clauses (tree *list_p) } } } +#endif + + +enum omp_tsort_mark { + UNVISITED, + TEMPORARY, + PERMANENT +}; + +struct omp_mapping_group { + tree *grp_start; + tree grp_end; + omp_tsort_mark mark; + struct omp_mapping_group *sibling; + struct omp_mapping_group *next; +}; + +__attribute__((used)) static void +debug_mapping_group (omp_mapping_group *grp) +{ + tree tmp = OMP_CLAUSE_CHAIN (grp->grp_end); + OMP_CLAUSE_CHAIN (grp->grp_end) = NULL; + debug_generic_expr (*grp->grp_start); + OMP_CLAUSE_CHAIN (grp->grp_end) = tmp; +} + +/* Return the OpenMP "base pointer" of an expression EXPR, or NULL if there + isn't one. This needs improvement. */ + +static tree +omp_get_base_pointer (tree expr) +{ + while (TREE_CODE (expr) == ARRAY_REF) + expr = TREE_OPERAND (expr, 0); + + while (TREE_CODE (expr) == COMPONENT_REF + && (DECL_P (TREE_OPERAND (expr, 0)) + || (TREE_CODE (TREE_OPERAND (expr, 0)) == COMPONENT_REF) + || TREE_CODE (TREE_OPERAND (expr, 0)) == INDIRECT_REF + || (TREE_CODE (TREE_OPERAND (expr, 0)) == MEM_REF + && integer_zerop (TREE_OPERAND (TREE_OPERAND (expr, 0), 1))) + || TREE_CODE (TREE_OPERAND (expr, 0)) == ARRAY_REF)) + { + expr = TREE_OPERAND (expr, 0); + + while (TREE_CODE (expr) == ARRAY_REF) + expr = TREE_OPERAND (expr, 0); + + if (TREE_CODE (expr) == INDIRECT_REF || TREE_CODE (expr) == MEM_REF) + break; + } + + if (DECL_P (expr)) + return NULL_TREE; + + if (TREE_CODE (expr) == INDIRECT_REF + || TREE_CODE (expr) == MEM_REF) + { + expr = TREE_OPERAND (expr, 0); + while (TREE_CODE (expr) == COMPOUND_EXPR) + expr = TREE_OPERAND (expr, 1); + if (TREE_CODE (expr) == POINTER_PLUS_EXPR) + expr = TREE_OPERAND (expr, 0); + if (TREE_CODE (expr) == SAVE_EXPR) + expr = TREE_OPERAND (expr, 0); + STRIP_NOPS (expr); + return expr; + } + + return NULL_TREE; +} + +/* An attach or detach operation depends directly on the address being + attached/detached. Return that address, or none if there are no + attachments/detachments. */ + +static tree +omp_get_attachment (omp_mapping_group *grp) +{ + tree node = *grp->grp_start; + + switch (OMP_CLAUSE_MAP_KIND (node)) + { + case GOMP_MAP_TO: + case GOMP_MAP_FROM: + case GOMP_MAP_TOFROM: + case GOMP_MAP_ALWAYS_FROM: + case GOMP_MAP_ALWAYS_TO: + case GOMP_MAP_ALWAYS_TOFROM: + case GOMP_MAP_FORCE_FROM: + case GOMP_MAP_FORCE_TO: + case GOMP_MAP_FORCE_TOFROM: + case GOMP_MAP_FORCE_PRESENT: + case GOMP_MAP_ALLOC: + case GOMP_MAP_RELEASE: + case GOMP_MAP_DELETE: + case GOMP_MAP_FORCE_ALLOC: + if (node == grp->grp_end) + return NULL_TREE; + + node = OMP_CLAUSE_CHAIN (node); + if (node && OMP_CLAUSE_MAP_KIND (node) == GOMP_MAP_TO_PSET) + { + gcc_assert (node != grp->grp_end); + node = OMP_CLAUSE_CHAIN (node); + } + if (node) + switch (OMP_CLAUSE_MAP_KIND (node)) + { + case GOMP_MAP_POINTER: + case GOMP_MAP_ALWAYS_POINTER: + case GOMP_MAP_FIRSTPRIVATE_POINTER: + case GOMP_MAP_FIRSTPRIVATE_REFERENCE: + case GOMP_MAP_POINTER_TO_ZERO_LENGTH_ARRAY_SECTION: + return NULL_TREE; + + case GOMP_MAP_ATTACH_DETACH: + case GOMP_MAP_ATTACH_ZERO_LENGTH_ARRAY_SECTION: + return OMP_CLAUSE_DECL (node); + + default: + internal_error ("unexpected mapping node"); + } + return error_mark_node; + + case GOMP_MAP_TO_PSET: + gcc_assert (node != grp->grp_end); + node = OMP_CLAUSE_CHAIN (node); + if (OMP_CLAUSE_MAP_KIND (node) == GOMP_MAP_ATTACH + || OMP_CLAUSE_MAP_KIND (node) == GOMP_MAP_DETACH) + return OMP_CLAUSE_DECL (node); + else + internal_error ("unexpected mapping node"); + return error_mark_node; + + case GOMP_MAP_ATTACH: + case GOMP_MAP_DETACH: + node = OMP_CLAUSE_CHAIN (node); + if (!node || *grp->grp_start == grp->grp_end) + return OMP_CLAUSE_DECL (*grp->grp_start); + if (OMP_CLAUSE_MAP_KIND (node) == GOMP_MAP_FIRSTPRIVATE_POINTER + || OMP_CLAUSE_MAP_KIND (node) == GOMP_MAP_FIRSTPRIVATE_REFERENCE) + return OMP_CLAUSE_DECL (*grp->grp_start); + else + internal_error ("unexpected mapping node"); + return error_mark_node; + + case GOMP_MAP_STRUCT: + case GOMP_MAP_FORCE_DEVICEPTR: + case GOMP_MAP_DEVICE_RESIDENT: + case GOMP_MAP_LINK: + case GOMP_MAP_IF_PRESENT: + case GOMP_MAP_FIRSTPRIVATE: + case GOMP_MAP_FIRSTPRIVATE_INT: + case GOMP_MAP_USE_DEVICE_PTR: + case GOMP_MAP_ATTACH_ZERO_LENGTH_ARRAY_SECTION: + return NULL_TREE; + + default: + internal_error ("unexpected mapping node"); + } + + return error_mark_node; +} + +/* Given a pointer START_P to the start of a group of related (e.g. pointer) + mappings, return the chain pointer to the end of that group in the list. */ + +static tree * +omp_group_last (tree *start_p) +{ + tree c = *start_p, nc, *grp_last_p = start_p; + + gcc_assert (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_MAP); + + nc = OMP_CLAUSE_CHAIN (c); + + if (!nc || OMP_CLAUSE_CODE (nc) != OMP_CLAUSE_MAP) + return grp_last_p; + + switch (OMP_CLAUSE_MAP_KIND (c)) + { + default: + while (nc + && OMP_CLAUSE_CODE (nc) == OMP_CLAUSE_MAP + && (OMP_CLAUSE_MAP_KIND (nc) == GOMP_MAP_FIRSTPRIVATE_REFERENCE + || OMP_CLAUSE_MAP_KIND (nc) == GOMP_MAP_FIRSTPRIVATE_POINTER + || OMP_CLAUSE_MAP_KIND (nc) == GOMP_MAP_ATTACH_DETACH + || OMP_CLAUSE_MAP_KIND (nc) == GOMP_MAP_POINTER + || (OMP_CLAUSE_MAP_KIND (nc) + == GOMP_MAP_POINTER_TO_ZERO_LENGTH_ARRAY_SECTION) + || (OMP_CLAUSE_MAP_KIND (nc) + == GOMP_MAP_ATTACH_ZERO_LENGTH_ARRAY_SECTION) + || OMP_CLAUSE_MAP_KIND (nc) == GOMP_MAP_ALWAYS_POINTER + || OMP_CLAUSE_MAP_KIND (nc) == GOMP_MAP_TO_PSET)) + { + grp_last_p = &OMP_CLAUSE_CHAIN (c); + c = nc; + tree nc2 = OMP_CLAUSE_CHAIN (nc); + if (nc2 + && OMP_CLAUSE_CODE (nc2) == OMP_CLAUSE_MAP + && (OMP_CLAUSE_MAP_KIND (nc) + == GOMP_MAP_POINTER_TO_ZERO_LENGTH_ARRAY_SECTION) + && OMP_CLAUSE_MAP_KIND (nc2) == GOMP_MAP_ATTACH) + { + grp_last_p = &OMP_CLAUSE_CHAIN (nc); + c = nc2; + nc2 = OMP_CLAUSE_CHAIN (nc2); + } + nc = nc2; + } + break; + + case GOMP_MAP_ATTACH: + case GOMP_MAP_DETACH: + /* This is a weird artifact of how directives are parsed: bare attach or + detach clauses get a subsequent (meaningless) FIRSTPRIVATE_POINTER or + FIRSTPRIVATE_REFERENCE node. FIXME. */ + if (nc + && OMP_CLAUSE_CODE (nc) == OMP_CLAUSE_MAP + && (OMP_CLAUSE_MAP_KIND (nc) == GOMP_MAP_FIRSTPRIVATE_REFERENCE + || OMP_CLAUSE_MAP_KIND (nc) == GOMP_MAP_FIRSTPRIVATE_POINTER)) + grp_last_p = &OMP_CLAUSE_CHAIN (c); + break; + + case GOMP_MAP_TO_PSET: + if (OMP_CLAUSE_CODE (nc) == OMP_CLAUSE_MAP + && (OMP_CLAUSE_MAP_KIND (nc) == GOMP_MAP_ATTACH + || OMP_CLAUSE_MAP_KIND (nc) == GOMP_MAP_DETACH)) + grp_last_p = &OMP_CLAUSE_CHAIN (c); + break; + } + + return grp_last_p; +} + +/* Walk through LIST_P, and return a list of groups of mappings found (e.g. + OMP_CLAUSE_MAP with GOMP_MAP_{TO/FROM/TOFROM} followed by one or two + associated GOMP_MAP_POINTER mappings). Return a vector of omp_mapping_group + if we have more than one such group, else return NULL. */ + +static vec * +omp_gather_mapping_groups (tree *list_p) +{ + vec *groups = new vec (); + + for (tree *cp = list_p; *cp; cp = &OMP_CLAUSE_CHAIN (*cp)) + { + if (OMP_CLAUSE_CODE (*cp) != OMP_CLAUSE_MAP) + continue; + + tree *grp_last_p = omp_group_last (cp); + omp_mapping_group grp; + + grp.grp_start = cp; + grp.grp_end = *grp_last_p; + grp.mark = UNVISITED; + grp.sibling = NULL; + grp.next = NULL; + groups->safe_push (grp); + + cp = grp_last_p; + } + + if (groups->length () > 0) + return groups; + else + { + delete groups; + return NULL; + } +} + +/* A pointer mapping group GRP may define a block of memory starting at some + base address, and maybe also define a firstprivate pointer or firstprivate + reference that points to that block. The return value is a node containing + the former, and the *FIRSTPRIVATE pointer is set if we have the latter. + If we define several base pointers, i.e. for a GOMP_MAP_STRUCT mapping, + return the number of consecutive chained nodes in CHAINED. */ + +static tree +omp_group_base (omp_mapping_group *grp, unsigned int *chained, + tree *firstprivate) +{ + tree node = *grp->grp_start; + + *firstprivate = NULL_TREE; + *chained = 1; + + switch (OMP_CLAUSE_MAP_KIND (node)) + { + case GOMP_MAP_TO: + case GOMP_MAP_FROM: + case GOMP_MAP_TOFROM: + case GOMP_MAP_ALWAYS_FROM: + case GOMP_MAP_ALWAYS_TO: + case GOMP_MAP_ALWAYS_TOFROM: + case GOMP_MAP_FORCE_FROM: + case GOMP_MAP_FORCE_TO: + case GOMP_MAP_FORCE_TOFROM: + case GOMP_MAP_FORCE_PRESENT: + case GOMP_MAP_ALLOC: + case GOMP_MAP_RELEASE: + case GOMP_MAP_DELETE: + case GOMP_MAP_FORCE_ALLOC: + if (node == grp->grp_end) + return node; + + node = OMP_CLAUSE_CHAIN (node); + if (node && OMP_CLAUSE_MAP_KIND (node) == GOMP_MAP_TO_PSET) + { + gcc_assert (node != grp->grp_end); + node = OMP_CLAUSE_CHAIN (node); + } + if (node) + switch (OMP_CLAUSE_MAP_KIND (node)) + { + case GOMP_MAP_POINTER: + case GOMP_MAP_FIRSTPRIVATE_POINTER: + case GOMP_MAP_FIRSTPRIVATE_REFERENCE: + case GOMP_MAP_POINTER_TO_ZERO_LENGTH_ARRAY_SECTION: + *firstprivate = OMP_CLAUSE_DECL (node); + return *grp->grp_start; + + case GOMP_MAP_ALWAYS_POINTER: + case GOMP_MAP_ATTACH_DETACH: + case GOMP_MAP_ATTACH_ZERO_LENGTH_ARRAY_SECTION: + return *grp->grp_start; + + default: + internal_error ("unexpected mapping node"); + } + else + internal_error ("unexpected mapping node"); + return error_mark_node; + + case GOMP_MAP_TO_PSET: + gcc_assert (node != grp->grp_end); + node = OMP_CLAUSE_CHAIN (node); + if (OMP_CLAUSE_MAP_KIND (node) == GOMP_MAP_ATTACH + || OMP_CLAUSE_MAP_KIND (node) == GOMP_MAP_DETACH) + return NULL_TREE; + else + internal_error ("unexpected mapping node"); + return error_mark_node; + + case GOMP_MAP_ATTACH: + case GOMP_MAP_DETACH: + node = OMP_CLAUSE_CHAIN (node); + if (!node || *grp->grp_start == grp->grp_end) + return NULL_TREE; + if (OMP_CLAUSE_MAP_KIND (node) == GOMP_MAP_FIRSTPRIVATE_POINTER + || OMP_CLAUSE_MAP_KIND (node) == GOMP_MAP_FIRSTPRIVATE_REFERENCE) + { + /* We're mapping the base pointer itself in a bare attach or detach + node. This is a side effect of how parsing works, and the mapping + will be removed anyway (at least for enter/exit data directives). + We should ignore the mapping here. FIXME. */ + return NULL_TREE; + } + else + internal_error ("unexpected mapping node"); + return error_mark_node; + + case GOMP_MAP_FORCE_DEVICEPTR: + case GOMP_MAP_DEVICE_RESIDENT: + case GOMP_MAP_LINK: + case GOMP_MAP_IF_PRESENT: + case GOMP_MAP_FIRSTPRIVATE: + case GOMP_MAP_FIRSTPRIVATE_INT: + case GOMP_MAP_USE_DEVICE_PTR: + case GOMP_MAP_ATTACH_ZERO_LENGTH_ARRAY_SECTION: + return NULL_TREE; + + case GOMP_MAP_FIRSTPRIVATE_POINTER: + case GOMP_MAP_FIRSTPRIVATE_REFERENCE: + case GOMP_MAP_POINTER: + case GOMP_MAP_ALWAYS_POINTER: + case GOMP_MAP_POINTER_TO_ZERO_LENGTH_ARRAY_SECTION: + /* These shouldn't appear by themselves. */ + if (!seen_error ()) + internal_error ("unexpected pointer mapping node"); + return error_mark_node; + + default: + gcc_unreachable (); + } + + return error_mark_node; +} + +/* Given a vector of omp_mapping_groups, build a hash table so we can look up + nodes by tree_operand_hash. */ + +static hash_map * +omp_index_mapping_groups (vec *groups) +{ + hash_map *grpmap + = new hash_map; + + omp_mapping_group *grp; + unsigned int i; + + FOR_EACH_VEC_ELT (*groups, i, grp) + { + tree fpp; + unsigned int chained; + tree node = omp_group_base (grp, &chained, &fpp); + + if (node == error_mark_node || (!node && !fpp)) + continue; + + for (unsigned j = 0; + node && j < chained; + node = OMP_CLAUSE_CHAIN (node), j++) + { + tree decl = OMP_CLAUSE_DECL (node); + + /* Sometimes we see zero-offset MEM_REF instead of INDIRECT_REF, + meaning node-hash lookups don't work. This is a workaround for + that, but ideally we should just create the INDIRECT_REF at + source instead. FIXME. */ + if (TREE_CODE (decl) == MEM_REF + && integer_zerop (TREE_OPERAND (decl, 1))) + decl = build1 (INDIRECT_REF, TREE_TYPE (decl), + TREE_OPERAND (decl, 0)); + + omp_mapping_group **prev = grpmap->get (decl); + + if (prev && *prev == grp) + /* Empty. */; + else if (prev) + { + /* Mapping the same thing twice is normally diagnosed as an error, + but can happen under some circumstances, e.g. in pr99928-16.c, + the directive: + + #pragma omp target simd reduction(+:a[:3]) \ + map(always, tofrom: a[:6]) + ... + + will result in two "a[0]" mappings (of different sizes). */ + + grp->sibling = (*prev)->sibling; + (*prev)->sibling = grp; + } + else + grpmap->put (decl, grp); + } + + if (!fpp) + continue; + + omp_mapping_group **prev = grpmap->get (fpp); + if (prev) + { + grp->sibling = (*prev)->sibling; + (*prev)->sibling = grp; + } + else + grpmap->put (fpp, grp); + } + return grpmap; +} + +/* Find the immediately-containing struct for a component ref (etc.) + expression EXPR. */ + +static tree +omp_containing_struct (tree expr) +{ + tree expr0 = expr; + + STRIP_NOPS (expr); + + tree expr1 = expr; + + /* FIXME: other types of accessors? */ + while (TREE_CODE (expr) == ARRAY_REF) + expr = TREE_OPERAND (expr, 0); + + if (TREE_CODE (expr) == COMPONENT_REF) + { + if (DECL_P (TREE_OPERAND (expr, 0)) + || TREE_CODE (TREE_OPERAND (expr, 0)) == COMPONENT_REF + || TREE_CODE (TREE_OPERAND (expr, 0)) == INDIRECT_REF + || (TREE_CODE (TREE_OPERAND (expr, 0)) == MEM_REF + && integer_zerop (TREE_OPERAND (TREE_OPERAND (expr, 0), 1))) + || TREE_CODE (TREE_OPERAND (expr, 0)) == ARRAY_REF) + expr = TREE_OPERAND (expr, 0); + else + internal_error ("unhandled component"); + } + + return (expr == expr1) ? expr0 : expr; +} + +/* Helper function for omp_tsort_mapping_groups. Returns TRUE on success, or + FALSE on error. */ + +static bool +omp_tsort_mapping_groups_1 (omp_mapping_group ***outlist, + vec *groups, + hash_map + *grpmap, + omp_mapping_group *grp) +{ + if (grp->mark == PERMANENT) + return true; + if (grp->mark == TEMPORARY) + { + fprintf (stderr, "when processing group:\n"); + debug_mapping_group (grp); + internal_error ("base pointer cycle detected"); + return false; + } + grp->mark = TEMPORARY; + + tree attaches_to = omp_get_attachment (grp); + + if (attaches_to) + { + omp_mapping_group **basep = grpmap->get (attaches_to); + + if (basep) + { + gcc_assert (*basep != grp); + for (omp_mapping_group *w = *basep; w; w = w->sibling) + if (!omp_tsort_mapping_groups_1 (outlist, groups, grpmap, w)) + return false; + } + } + + tree decl = OMP_CLAUSE_DECL (*grp->grp_start); + + while (decl) + { + tree base = omp_get_base_pointer (decl); + + if (!base) + break; + + omp_mapping_group **innerp = grpmap->get (base); + + /* We should treat whole-structure mappings as if all (pointer, in this + case) members are mapped as individual list items. Check if we have + such a whole-structure mapping, if we don't have an explicit reference + to the pointer member itself. */ + if (!innerp && TREE_CODE (base) == COMPONENT_REF) + { + base = omp_containing_struct (base); + innerp = grpmap->get (base); + + if (!innerp + && TREE_CODE (base) == MEM_REF + && integer_zerop (TREE_OPERAND (base, 1))) + { + tree ind = TREE_OPERAND (base, 0); + ind = build1 (INDIRECT_REF, TREE_TYPE (base), ind); + innerp = grpmap->get (ind); + } + } + + if (innerp && *innerp != grp) + { + for (omp_mapping_group *w = *innerp; w; w = w->sibling) + if (!omp_tsort_mapping_groups_1 (outlist, groups, grpmap, w)) + return false; + break; + } + + decl = base; + } + + grp->mark = PERMANENT; + + /* Emit grp to output list. */ + + **outlist = grp; + *outlist = &grp->next; + + return true; +} + +/* Topologically sort GROUPS, so that OMP 5.0-defined base pointers come + before mappings that use those pointers. This is an implementation of the + depth-first search algorithm, described e.g. at: + + https://en.wikipedia.org/wiki/Topological_sorting +*/ + +static omp_mapping_group * +omp_tsort_mapping_groups (vec *groups, + hash_map + *grpmap) +{ + omp_mapping_group *grp, *outlist = NULL, **cursor; + unsigned int i; + + cursor = &outlist; + + FOR_EACH_VEC_ELT (*groups, i, grp) + { + if (grp->mark != PERMANENT) + if (!omp_tsort_mapping_groups_1 (&cursor, groups, grpmap, grp)) + return NULL; + } + + return outlist; +} + +/* Split INLIST into two parts, moving groups corresponding to + ALLOC/RELEASE/DELETE mappings to one list, and other mappings to another. + The former list is then appended to the latter. Each sub-list retains the + order of the original list. */ + +static omp_mapping_group * +omp_segregate_mapping_groups (omp_mapping_group *inlist) +{ + omp_mapping_group *ard_groups = NULL, *tf_groups = NULL; + omp_mapping_group **ard_tail = &ard_groups, **tf_tail = &tf_groups; + + for (omp_mapping_group *w = inlist; w;) + { + tree c = *w->grp_start; + omp_mapping_group *next = w->next; + + gcc_assert (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_MAP); + + switch (OMP_CLAUSE_MAP_KIND (c)) + { + case GOMP_MAP_ALLOC: + case GOMP_MAP_RELEASE: + case GOMP_MAP_DELETE: + *ard_tail = w; + w->next = NULL; + ard_tail = &w->next; + break; + + default: + *tf_tail = w; + w->next = NULL; + tf_tail = &w->next; + } + + w = next; + } + + /* Now splice the lists together... */ + *tf_tail = ard_groups; + + return tf_groups; +} + +/* Given a list LIST_P containing groups of mappings given by GROUPS, reorder + those groups based on the output list of omp_tsort_mapping_groups -- + singly-linked, threaded through each element's NEXT pointer starting at + HEAD. Each list element appears exactly once in that linked list. + + Each element of GROUPS may correspond to one or several mapping nodes. + Node groups are kept together, and in the reordered list, the positions of + the original groups are reused for the positions of the reordered list. + Hence if we have e.g. + + {to ptr ptr} firstprivate {tofrom ptr} ... + ^ ^ ^ + first group non-"map" second group + + and say the second group contains a base pointer for the first so must be + moved before it, the resulting list will contain: + + {tofrom ptr} firstprivate {to ptr ptr} ... + ^ prev. second group ^ prev. first group +*/ + +static tree * +omp_reorder_mapping_groups (vec *groups, + omp_mapping_group *head, + tree *list_p) +{ + omp_mapping_group *grp; + unsigned int i; + unsigned numgroups = groups->length (); + auto_vec old_heads (numgroups); + auto_vec old_headps (numgroups); + auto_vec new_heads (numgroups); + auto_vec old_succs (numgroups); + bool map_at_start = (list_p == (*groups)[0].grp_start); + + tree *new_grp_tail = NULL; + + /* Stash the start & end nodes of each mapping group before we start + modifying the list. */ + FOR_EACH_VEC_ELT (*groups, i, grp) + { + old_headps.quick_push (grp->grp_start); + old_heads.quick_push (*grp->grp_start); + old_succs.quick_push (OMP_CLAUSE_CHAIN (grp->grp_end)); + } + + /* And similarly, the heads of the groups in the order we want to rearrange + the list to. */ + for (omp_mapping_group *w = head; w; w = w->next) + new_heads.quick_push (*w->grp_start); + + FOR_EACH_VEC_ELT (*groups, i, grp) + { + gcc_assert (head); + + if (new_grp_tail && old_succs[i - 1] == old_heads[i]) + { + /* a {b c d} {e f g} h i j (original) + --> + a {k l m} {e f g} h i j (inserted new group on last iter) + --> + a {k l m} {n o p} h i j (this time, chain last group to new one) + ^new_grp_tail + */ + *new_grp_tail = new_heads[i]; + } + else if (new_grp_tail) + { + /* a {b c d} e {f g h} i j k (original) + --> + a {l m n} e {f g h} i j k (gap after last iter's group) + --> + a {l m n} e {o p q} h i j (chain last group to old successor) + ^new_grp_tail + */ + *new_grp_tail = old_succs[i - 1]; + *old_headps[i] = new_heads[i]; + } + else + { + /* The first inserted group -- point to new group, and leave end + open. + a {b c d} e f + --> + a {g h i... + */ + *grp->grp_start = new_heads[i]; + } + + new_grp_tail = &OMP_CLAUSE_CHAIN (head->grp_end); + + head = head->next; + } + + if (new_grp_tail) + *new_grp_tail = old_succs[numgroups - 1]; + + gcc_assert (!head); + + return map_at_start ? (*groups)[0].grp_start : list_p; +} /* DECL is supposed to have lastprivate semantics in the outer contexts of combined/composite constructs, starting with OCTX. @@ -9689,11 +10422,29 @@ gimplify_scan_omp_clauses (tree *list_p, gimple_seq *pre_p, break; } - if (code == OMP_TARGET - || code == OMP_TARGET_DATA - || code == OMP_TARGET_ENTER_DATA - || code == OMP_TARGET_EXIT_DATA) - omp_target_reorder_clauses (list_p); + /* Topological sorting may fail if we have duplicate nodes, which + we should have detected and shown an error for already. Skip + sorting in that case. */ + if (!seen_error () + && (code == OMP_TARGET + || code == OMP_TARGET_DATA + || code == OMP_TARGET_ENTER_DATA + || code == OMP_TARGET_EXIT_DATA)) + { + vec *groups; + groups = omp_gather_mapping_groups (list_p); + if (groups) + { + hash_map *grpmap; + grpmap = omp_index_mapping_groups (groups); + omp_mapping_group *outlist + = omp_tsort_mapping_groups (groups, grpmap); + outlist = omp_segregate_mapping_groups (outlist); + list_p = omp_reorder_mapping_groups (groups, outlist, list_p); + delete grpmap; + delete groups; + } + } while ((c = *list_p) != NULL) { diff --git a/gcc/omp-low.c b/gcc/omp-low.c index bb459e6273e..133798f691f 100644 --- a/gcc/omp-low.c +++ b/gcc/omp-low.c @@ -1537,8 +1537,11 @@ scan_sharing_clauses (tree clauses, omp_context *ctx) { /* If this is an offloaded region, an attach operation should only exist when the pointer variable is mapped in a prior - clause. */ - if (is_gimple_omp_offloaded (ctx->stmt)) + clause. + If we had an error, we may not have attempted to sort clauses + properly, so avoid the test. */ + if (is_gimple_omp_offloaded (ctx->stmt) + && !seen_error ()) gcc_assert (maybe_lookup_decl (decl, ctx) || (is_global_var (maybe_lookup_decl_in_outer_ctx (decl, ctx)) diff --git a/gcc/testsuite/g++.dg/gomp/target-lambda-1.C b/gcc/testsuite/g++.dg/gomp/target-lambda-1.C index 7f83f92ec93..150f286e312 100644 --- a/gcc/testsuite/g++.dg/gomp/target-lambda-1.C +++ b/gcc/testsuite/g++.dg/gomp/target-lambda-1.C @@ -87,8 +87,8 @@ int main (void) return 0; } -/* { dg-final { scan-tree-dump {#pragma omp target num_teams.* firstprivate\(b\) map\(alloc:MEM.* \[len: 0\]\) map\(firstprivate:iptr \[pointer assign, bias: 0\]\) map\(alloc:MEM.* \[len: 0\]\) map\(firstprivate:this \[pointer assign, bias: 0\]\) map\(to:\*__closure \[len: [0-9]+\]\) map\(firstprivate:__closure \[pointer assign, bias: 0\]\) map\(tofrom:\*_[0-9]+ \[len: [0-9]+\]\) map\(always_pointer:__closure->__this \[pointer assign, bias: 0\]\) map\(attach_zero_length_array_section:__closure->__iptr \[bias: 0\]\) map\(attach_zero_length_array_section:_[0-9]+->ptr \[bias: 0\]\) map\(from:mapped \[len: [0-9]+\]\) map\(alloc:\*_[0-9]+ \[len: 0\]\) map\(alloc:\*_[0-9]+ \[len: 0\]\)} "gimple" } } */ +/* { dg-final { scan-tree-dump {#pragma omp target num_teams.* firstprivate\(b\) map\(alloc:MEM.* \[len: 0\]\) map\(firstprivate:iptr \[pointer assign, bias: 0\]\) map\(alloc:MEM.* \[len: 0\]\) map\(firstprivate:this \[pointer assign, bias: 0\]\) map\(to:\*__closure \[len: [0-9]+\]\) map\(firstprivate:__closure \[pointer assign, bias: 0\]\) map\(struct:\*__closure \[len: 1\]\) map\(alloc:__closure->__this \[len: [0-9]+\]\) map\(tofrom:\*_[0-9]+ \[len: [0-9]+\]\) map\(always_pointer:__closure->__this \[pointer assign, bias: 0\]\) map\(from:mapped \[len: [0-9]+\]\) map\(alloc:\*_[0-9]+ \[len: 0\]\) map\(attach_zero_length_array_section:__closure->__iptr \[bias: 0\]\) map\(alloc:\*_[0-9]+ \[len: 0\]\) map\(attach_zero_length_array_section:_[0-9]+->ptr \[bias: 0\]\)} "gimple" } } */ -/* { dg-final { scan-tree-dump {#pragma omp target num_teams.* firstprivate\(end\) firstprivate\(begin\) map\(to:loop \[len: [0-9]+\]\) map\(attach_zero_length_array_section:loop\.__data1 \[bias: 0\]\) map\(alloc:\*_[0-9]+ \[len: 0\]\)} "gimple" } } */ +/* { dg-final { scan-tree-dump {#pragma omp target num_teams.* firstprivate\(end\) firstprivate\(begin\) map\(to:loop \[len: [0-9]+\]\) map\(alloc:\*_[0-9]+ \[len: 0\]\) map\(attach_zero_length_array_section:loop\.__data1 \[bias: 0\]\)} "gimple" } } */ -/* { dg-final { scan-tree-dump {#pragma omp target num_teams.* firstprivate\(end\) firstprivate\(begin\) map\(to:loop \[len: [0-9]+\]\) map\(attach_zero_length_array_section:loop\.__data2 \[bias: 0\]\) map\(alloc:\*_[0-9]+ \[len: 0\]\)} "gimple" } } */ +/* { dg-final { scan-tree-dump {#pragma omp target num_teams.* firstprivate\(end\) firstprivate\(begin\) map\(to:loop \[len: [0-9]+\]\) map\(alloc:\*_[0-9]+ \[len: 0\]\) map\(attach_zero_length_array_section:loop\.__data2 \[bias: 0\]\)} "gimple" } } */ diff --git a/gcc/testsuite/g++.dg/gomp/target-this-3.C b/gcc/testsuite/g++.dg/gomp/target-this-3.C index 91cfbd6ef20..bc2cc0b297d 100644 --- a/gcc/testsuite/g++.dg/gomp/target-this-3.C +++ b/gcc/testsuite/g++.dg/gomp/target-this-3.C @@ -100,6 +100,6 @@ int main (void) return 0; } -/* { dg-final { scan-tree-dump {#pragma omp target num_teams.* map\(alloc:MEM.* \[len: 0\]\) map\(firstprivate:this \[pointer assign, bias: 0\]\) firstprivate\(n\) map\(tofrom:\*this \[len: [0-9]+\]\) map\(firstprivate:this \[pointer assign, bias: 0\]\) map\(alloc:\*_[0-9]+ \[pointer assign, zero-length array section, bias: 0\]\) map\(attach:this->refptr \[bias: 0\]\) map\(from:mapped \[len: [0-9]+\]\)} "gimple" } } */ +/* { dg-final { scan-tree-dump {#pragma omp target num_teams.* firstprivate\(n\) map\(tofrom:\*this \[len: [0-9]+\]\) map\(firstprivate:this \[pointer assign, bias: 0\]\) map\(from:mapped \[len: [0-9]+\]\) map\(alloc:\*_[0-9+] \[len: 0\]\) map\(alloc:\*_[0-9]+ \[pointer assign, zero-length array section, bias: 0\]\) map\(attach:this->refptr \[bias: 0\]\)} "gimple" } } */ -/* { dg-final { scan-tree-dump {#pragma omp target num_teams.* map\(alloc:MEM.* \[len: 0\]\) map\(firstprivate:this \[pointer assign, bias: 0\]\) firstprivate\(n\) map\(tofrom:\*this \[len: [0-9]+\]\) map\(firstprivate:this \[pointer assign, bias: 0\]\) map\(attach_zero_length_array_section:this->ptr \[bias: 0\]\) map\(from:mapped \[len: [0-9]+\]\) map\(alloc:\*_[0-9]+ \[len: 0\]\)} "gimple" } } */ +/* { dg-final { scan-tree-dump {#pragma omp target num_teams.* firstprivate\(n\) map\(tofrom:\*this \[len: [0-9]+\]\) map\(firstprivate:this \[pointer assign, bias: 0\]\) map\(from:mapped \[len: [0-9]+\]\) map\(alloc:\*_[0-9]+ \[len: 0\]\) map\(attach_zero_length_array_section:this->ptr \[bias: 0\]\)} "gimple" } } */ diff --git a/gcc/testsuite/g++.dg/gomp/target-this-4.C b/gcc/testsuite/g++.dg/gomp/target-this-4.C index e4b2a71bbb4..8166f43ad42 100644 --- a/gcc/testsuite/g++.dg/gomp/target-this-4.C +++ b/gcc/testsuite/g++.dg/gomp/target-this-4.C @@ -102,6 +102,6 @@ int main (void) return 0; } -/* { dg-final { scan-tree-dump {#pragma omp target num_teams.* firstprivate\(n\) map\(alloc:MEM.* \[len: 0\]\) map\(firstprivate:this \[pointer assign, bias: 0\]\) map\(to:\*__closure \[len: [0-9]+\]\) map\(firstprivate:__closure \[pointer assign, bias: 0\]\) map\(tofrom:\*_[0-9]+ \[len: [0-9]+\]\) map\(always_pointer:__closure->__this \[pointer assign, bias: 0\]\) map\(attach_zero_length_array_section:_[0-9]+->ptr \[bias: 0\]\) map\(from:mapped \[len: [0-9]+\]\) map\(alloc:\*_[0-9]+ \[len: 0\]\)} "gimple" } } */ +/* { dg-final { scan-tree-dump {#pragma omp target num_teams.* firstprivate\(n\) map\(alloc:MEM.* \[len: 0\]\) map\(firstprivate:this \[pointer assign, bias: 0\]\) map\(to:\*__closure \[len: [0-9]+\]\) map\(firstprivate:__closure \[pointer assign, bias: 0\]\) map\(struct:\*__closure \[len: 1\]\) map\(alloc:__closure->__this \[len: [0-9]+\]\) map\(tofrom:\*_[0-9]+ \[len: [0-9]+\]\) map\(always_pointer:__closure->__this \[pointer assign, bias: 0\]\) map\(from:mapped \[len: 1\]\) map\(alloc:\*_[0-9]+ \[len: 0\]\) map\(attach_zero_length_array_section:_[0-9]+->ptr \[bias: 0\]\)} "gimple" } } */ -/* { dg-final { scan-tree-dump {#pragma omp target num_teams.* firstprivate\(n\) map\(alloc:MEM.* \[len: 0\]\) map\(firstprivate:this \[pointer assign, bias: 0\]\) map\(to:\*__closure \[len: [0-9]+\]\) map\(firstprivate:__closure \[pointer assign, bias: 0\]\) map\(tofrom:\*_[0-9]+ \[len: [0-9]+\]\) map\(always_pointer:__closure->__this \[pointer assign, bias: 0\]\) map\(alloc:\*_[0-9]+ \[pointer assign, zero-length array section, bias: 0\]\) map\(attach:_[0-9]+->refptr \[bias: 0\]\) map\(from:mapped \[len: [0-9]+\]\) map\(alloc:\*_[0-9]+ \[len: 0\]\)} "gimple" } } */ +/* { dg-final { scan-tree-dump {#pragma omp target num_teams.* firstprivate\(n\) map\(alloc:MEM.* \[len: 0\]\) map\(firstprivate:this \[pointer assign, bias: 0\]\) map\(to:\*__closure \[len: [0-9]+\]\) map\(firstprivate:__closure \[pointer assign, bias: 0\]\) map\(struct:\*__closure \[len: 1\]\) map\(alloc:__closure->__this \[len: [0-9]+\]\) map\(tofrom:\*_[0-9]+ \[len: [0-9]+\]\) map\(always_pointer:__closure->__this \[pointer assign, bias: 0\]\) map\(from:mapped \[len: [0-9]+\]\) map\(alloc:\*_[0-9]+ \[len: 0\]\) map\(alloc:\*_[0-9]+ \[pointer assign, zero-length array section, bias: 0\]\) map\(attach:_[0-9]+->refptr \[bias: 0\]\)} "gimple" } } */ From patchwork Thu Nov 25 14:08:41 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Julian Brown X-Patchwork-Id: 1559734 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=gcc.gnu.org (client-ip=8.43.85.97; helo=sourceware.org; envelope-from=gcc-patches-bounces+incoming=patchwork.ozlabs.org@gcc.gnu.org; receiver=) Received: from sourceware.org (ip-8-43-85-97.sourceware.org [8.43.85.97]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by bilbo.ozlabs.org (Postfix) with ESMTPS id 4J0KbF3Vq1z9sVc for ; Fri, 26 Nov 2021 01:12:56 +1100 (AEDT) Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 3C4523857827 for ; Thu, 25 Nov 2021 14:12:53 +0000 (GMT) X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from esa4.mentor.iphmx.com (esa4.mentor.iphmx.com [68.232.137.252]) by sourceware.org (Postfix) with ESMTPS id 8642F3857C52 for ; Thu, 25 Nov 2021 14:08:59 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org 8642F3857C52 Authentication-Results: sourceware.org; dmarc=none (p=none dis=none) header.from=codesourcery.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=mentor.com IronPort-SDR: YbjB9g/JxQgQfVsHZyyT1NKhzGb1qq4Mua5+HqrOu5flHvmAeNacmvYdLq2IrmMb6qWMAbWHdN nJO5sHPNlhTwwi+ri2lRPZtWKrYIb+xBEJDWKxPMRXK2wisY4wR2JXazazibP3siARbN2KtvJY 7XvcdrXgp8Dj1Kl55Rj5hT2sHgA3NtI6y1YVy4aXpuVlPNzEj9EwgJVPJRMvGmPmkd/6qJHeNb dhbruGmnvMT78Z8KYQ1RBFRMb1DUigz2dCDcj4N1Ag6qObPa+b7zJWOwcZpMRTepuB3E0AkI13 rreB4I+7yVrratsqwgMFqthT X-IronPort-AV: E=Sophos;i="5.87,263,1631606400"; d="scan'208";a="68932313" Received: from orw-gwy-02-in.mentorg.com ([192.94.38.167]) by esa4.mentor.iphmx.com with ESMTP; 25 Nov 2021 06:08:58 -0800 IronPort-SDR: Zybz1t1Hg7tJFWJPQPZyeqKfw7QtgxGt0fb923GIWdEUOmod7ASTG5Qa45Z3d/jkvcOAX9GaSG yJopWi3KZv77zSQeTHp2Oju4It92z3iCSU5zqqwuFCTs7MVgo3szyIn5oU9+fKy1s9JCTS8aEP O4lCSsQflqgJkYxFjPQx8KjnFjpR+PaQfnHnTgxt1yKA+scJcoIZjRQAkhzwgAwOO5p3wA0HO6 y+ajpu+jkcJdBwFUORSF3qgYvSRATvftVg+0vfrvFussi6WBv3Aw8qt1uH7OmifXkNg8PmCnHz m94= From: Julian Brown To: Subject: [PATCH 07/16] Remove omp_target_reorder_clauses Date: Thu, 25 Nov 2021 06:08:41 -0800 Message-ID: <20211125140843.111405-3-julian@codesourcery.com> X-Mailer: git-send-email 2.29.2 In-Reply-To: <20211125140843.111405-1-julian@codesourcery.com> References: <20211125140843.111405-1-julian@codesourcery.com> MIME-Version: 1.0 X-Originating-IP: [137.202.0.90] X-ClientProxiedBy: SVR-IES-MBX-08.mgc.mentorg.com (139.181.222.8) To SVR-IES-MBX-04.mgc.mentorg.com (139.181.222.4) X-Spam-Status: No, score=-11.8 required=5.0 tests=BAYES_00, GIT_PATCH_0, HEADER_FROM_DIFFERENT_DOMAINS, KAM_DMARC_STATUS, SPF_HELO_PASS, SPF_PASS, 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: , Cc: Jakub Jelinek , Thomas Schwinge Errors-To: gcc-patches-bounces+incoming=patchwork.ozlabs.org@gcc.gnu.org Sender: "Gcc-patches" This patch has been split out from the previous one to avoid a confusingly-interleaved diff. The two patches should probably be committed squashed together. 2021-10-01 Julian Brown gcc/ * gimplify.c (omp_target_reorder_clauses): Delete. --- gcc/gimplify.c | 183 ------------------------------------------------- 1 file changed, 183 deletions(-) diff --git a/gcc/gimplify.c b/gcc/gimplify.c index 6778fb25e45..fb923f05314 100644 --- a/gcc/gimplify.c +++ b/gcc/gimplify.c @@ -8745,189 +8745,6 @@ aggregate_base_p (tree expr) return false; } -#if 0 -/* Implement OpenMP 5.x map ordering rules for target directives. There are - several rules, and with some level of ambiguity, hopefully we can at least - collect the complexity here in one place. */ - -static void -omp_target_reorder_clauses (tree *list_p) -{ - /* Collect refs to alloc/release/delete maps. */ - auto_vec ard; - tree *cp = list_p; - while (*cp != NULL_TREE) - if (OMP_CLAUSE_CODE (*cp) == OMP_CLAUSE_MAP - && (OMP_CLAUSE_MAP_KIND (*cp) == GOMP_MAP_ALLOC - || OMP_CLAUSE_MAP_KIND (*cp) == GOMP_MAP_RELEASE - || OMP_CLAUSE_MAP_KIND (*cp) == GOMP_MAP_DELETE)) - { - /* Unlink cp and push to ard. */ - tree c = *cp; - tree nc = OMP_CLAUSE_CHAIN (c); - *cp = nc; - ard.safe_push (c); - - /* Any associated pointer type maps should also move along. */ - while (*cp != NULL_TREE - && OMP_CLAUSE_CODE (*cp) == OMP_CLAUSE_MAP - && (OMP_CLAUSE_MAP_KIND (*cp) == GOMP_MAP_FIRSTPRIVATE_REFERENCE - || OMP_CLAUSE_MAP_KIND (*cp) == GOMP_MAP_FIRSTPRIVATE_POINTER - || OMP_CLAUSE_MAP_KIND (*cp) == GOMP_MAP_ATTACH_DETACH - || OMP_CLAUSE_MAP_KIND (*cp) == GOMP_MAP_POINTER - || OMP_CLAUSE_MAP_KIND (*cp) == GOMP_MAP_ALWAYS_POINTER - || OMP_CLAUSE_MAP_KIND (*cp) == GOMP_MAP_TO_PSET)) - { - c = *cp; - nc = OMP_CLAUSE_CHAIN (c); - *cp = nc; - ard.safe_push (c); - } - } - else - cp = &OMP_CLAUSE_CHAIN (*cp); - - /* Link alloc/release/delete maps to the end of list. */ - for (unsigned int i = 0; i < ard.length (); i++) - { - *cp = ard[i]; - cp = &OMP_CLAUSE_CHAIN (ard[i]); - } - *cp = NULL_TREE; - - /* OpenMP 5.0 requires that pointer variables are mapped before - its use as a base-pointer. */ - auto_vec atf; - for (tree *cp = list_p; *cp; cp = &OMP_CLAUSE_CHAIN (*cp)) - if (OMP_CLAUSE_CODE (*cp) == OMP_CLAUSE_MAP) - { - /* Collect alloc, to, from, to/from clause tree pointers. */ - gomp_map_kind k = OMP_CLAUSE_MAP_KIND (*cp); - if (k == GOMP_MAP_ALLOC - || k == GOMP_MAP_TO - || k == GOMP_MAP_FROM - || k == GOMP_MAP_TOFROM - || k == GOMP_MAP_ALWAYS_TO - || k == GOMP_MAP_ALWAYS_FROM - || k == GOMP_MAP_ALWAYS_TOFROM) - atf.safe_push (cp); - } - - for (unsigned int i = 0; i < atf.length (); i++) - if (atf[i]) - { - tree *cp = atf[i]; - tree decl = OMP_CLAUSE_DECL (*cp); - if (TREE_CODE (decl) == INDIRECT_REF || TREE_CODE (decl) == MEM_REF) - { - tree base_ptr = TREE_OPERAND (decl, 0); - STRIP_TYPE_NOPS (base_ptr); - for (unsigned int j = i + 1; j < atf.length (); j++) - if (atf[j]) - { - tree *cp2 = atf[j]; - tree decl2 = OMP_CLAUSE_DECL (*cp2); - - decl2 = OMP_CLAUSE_DECL (*cp2); - if (is_or_contains_p (decl2, base_ptr)) - { - /* Move *cp2 to before *cp. */ - tree c = *cp2; - *cp2 = OMP_CLAUSE_CHAIN (c); - OMP_CLAUSE_CHAIN (c) = *cp; - *cp = c; - - if (*cp2 != NULL_TREE - && OMP_CLAUSE_CODE (*cp2) == OMP_CLAUSE_MAP - && OMP_CLAUSE_MAP_KIND (*cp2) == GOMP_MAP_ALWAYS_POINTER) - { - tree c2 = *cp2; - *cp2 = OMP_CLAUSE_CHAIN (c2); - OMP_CLAUSE_CHAIN (c2) = OMP_CLAUSE_CHAIN (c); - OMP_CLAUSE_CHAIN (c) = c2; - } - - atf[j] = NULL; - } - } - } - } - - /* For attach_detach map clauses, if there is another map that maps the - attached/detached pointer, make sure that map is ordered before the - attach_detach. */ - atf.truncate (0); - for (tree *cp = list_p; *cp; cp = &OMP_CLAUSE_CHAIN (*cp)) - if (OMP_CLAUSE_CODE (*cp) == OMP_CLAUSE_MAP) - { - /* Collect alloc, to, from, to/from clauses, and - always_pointer/attach_detach clauses. */ - gomp_map_kind k = OMP_CLAUSE_MAP_KIND (*cp); - if (k == GOMP_MAP_ALLOC - || k == GOMP_MAP_TO - || k == GOMP_MAP_FROM - || k == GOMP_MAP_TOFROM - || k == GOMP_MAP_ALWAYS_TO - || k == GOMP_MAP_ALWAYS_FROM - || k == GOMP_MAP_ALWAYS_TOFROM - || k == GOMP_MAP_ATTACH_DETACH - || k == GOMP_MAP_ALWAYS_POINTER) - atf.safe_push (cp); - } - - for (unsigned int i = 0; i < atf.length (); i++) - if (atf[i]) - { - tree *cp = atf[i]; - tree ptr = OMP_CLAUSE_DECL (*cp); - STRIP_TYPE_NOPS (ptr); - if (OMP_CLAUSE_MAP_KIND (*cp) == GOMP_MAP_ATTACH_DETACH) - for (unsigned int j = i + 1; j < atf.length (); j++) - { - tree *cp2 = atf[j]; - tree decl2 = OMP_CLAUSE_DECL (*cp2); - if (OMP_CLAUSE_MAP_KIND (*cp2) != GOMP_MAP_ATTACH_DETACH - && OMP_CLAUSE_MAP_KIND (*cp2) != GOMP_MAP_ALWAYS_POINTER - && is_or_contains_p (decl2, ptr)) - { - /* Move *cp2 to before *cp. */ - tree c = *cp2; - *cp2 = OMP_CLAUSE_CHAIN (c); - OMP_CLAUSE_CHAIN (c) = *cp; - *cp = c; - atf[j] = NULL; - - /* If decl2 is of the form '*decl2_opnd0', and followed by an - ALWAYS_POINTER or ATTACH_DETACH of 'decl2_opnd0', move the - pointer operation along with *cp2. This can happen for C++ - reference sequences. */ - if (j + 1 < atf.length () - && (TREE_CODE (decl2) == INDIRECT_REF - || TREE_CODE (decl2) == MEM_REF)) - { - tree *cp3 = atf[j + 1]; - tree decl3 = OMP_CLAUSE_DECL (*cp3); - tree decl2_opnd0 = TREE_OPERAND (decl2, 0); - if ((OMP_CLAUSE_MAP_KIND (*cp3) == GOMP_MAP_ALWAYS_POINTER - || OMP_CLAUSE_MAP_KIND (*cp3) == GOMP_MAP_ATTACH_DETACH) - && operand_equal_p (decl3, decl2_opnd0)) - { - /* Also move *cp3 to before *cp. */ - c = *cp3; - *cp2 = OMP_CLAUSE_CHAIN (c); - OMP_CLAUSE_CHAIN (c) = *cp; - *cp = c; - atf[j + 1] = NULL; - j += 1; - } - } - } - } - } -} -#endif - - enum omp_tsort_mark { UNVISITED, TEMPORARY, From patchwork Thu Nov 25 14:08:42 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Julian Brown X-Patchwork-Id: 1559735 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=gcc.gnu.org (client-ip=2620:52:3:1:0:246e:9693:128c; helo=sourceware.org; envelope-from=gcc-patches-bounces+incoming=patchwork.ozlabs.org@gcc.gnu.org; receiver=) Received: from sourceware.org (server2.sourceware.org [IPv6:2620:52:3:1:0:246e:9693:128c]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by bilbo.ozlabs.org (Postfix) with ESMTPS id 4J0Kbn4ht5z9sVc for ; Fri, 26 Nov 2021 01:13:25 +1100 (AEDT) Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 8D0C73858D3C for ; Thu, 25 Nov 2021 14:13:23 +0000 (GMT) X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from esa4.mentor.iphmx.com (esa4.mentor.iphmx.com [68.232.137.252]) by sourceware.org (Postfix) with ESMTPS id 8B9853858038 for ; Thu, 25 Nov 2021 14:09:03 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org 8B9853858038 Authentication-Results: sourceware.org; dmarc=none (p=none dis=none) header.from=codesourcery.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=mentor.com IronPort-SDR: fIIfeMsMjleJJjH5SIKg6jLhjV30FqpjA8qMx8USfJo95nbe/PDINK5fvOXuvie6eQpkEcBFew nnQrYB5PtFf12c5PHzS/prDlKqtRgLWrcJENy6H7KU7Pe1tBOGCcLbCkP3xj5HOh4fMcz3ySB4 lZIVF4BrdTEeTilrAeER13zrujeOfL4i03G8Ii5Ce0mIQkxZJ+tQ1wWeHJQ6kb5yyl1E4BskZd Exa0DAozidzCCRIMZ3mAHYb5rljmV1001JFjKByWdobhVnoweaLwCbqEben4z8gT3gwHL3fpuI 6eUsJwcQ05gJj3P9P0ai9N4m X-IronPort-AV: E=Sophos;i="5.87,263,1631606400"; d="scan'208";a="68932317" Received: from orw-gwy-02-in.mentorg.com ([192.94.38.167]) by esa4.mentor.iphmx.com with ESMTP; 25 Nov 2021 06:09:02 -0800 IronPort-SDR: LgLgHDnoo0bH3fTJZey6453ePhMNHwNVwI460bmwEdNyYmwEEspDbRx3P+CgJGfuVn/HdrVHlj XI+jpTKmiGbJtDa9ystj9x5rCVGbexbe8Jri+fyF9cu2nAUrojDBTJfpCKxBo2blLbEZwQzzEz 2ULmAX8CtGoHzEmeZL8QCQJPItB4ECtZh4R7JaHN38N+Tky1nFnsbN1x7Brikz2FPrlpvI+Zsx NDD35basoJGsYrd7Q6KAsxQ6k4J6KPVIxDfVw6J/am89k0jsvyMerb290QnftLE6XZV6zf1+hi 4Xk= From: Julian Brown To: Subject: [PATCH 08/16] OpenMP/OpenACC: Hoist struct sibling list handling in gimplification Date: Thu, 25 Nov 2021 06:08:42 -0800 Message-ID: <20211125140843.111405-4-julian@codesourcery.com> X-Mailer: git-send-email 2.29.2 In-Reply-To: <20211125140843.111405-1-julian@codesourcery.com> References: <20211125140843.111405-1-julian@codesourcery.com> MIME-Version: 1.0 X-Originating-IP: [137.202.0.90] X-ClientProxiedBy: SVR-IES-MBX-08.mgc.mentorg.com (139.181.222.8) To SVR-IES-MBX-04.mgc.mentorg.com (139.181.222.4) X-Spam-Status: No, score=-11.8 required=5.0 tests=BAYES_00, GIT_PATCH_0, HEADER_FROM_DIFFERENT_DOMAINS, KAM_DMARC_STATUS, SPF_HELO_PASS, SPF_PASS, 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: , Cc: Jakub Jelinek , Thomas Schwinge Errors-To: gcc-patches-bounces+incoming=patchwork.ozlabs.org@gcc.gnu.org Sender: "Gcc-patches" This patch lifts struct sibling-list handling out of the main loop in gimplify_scan_omp_clauses. The reasons for this are several: first, it means that we can subject created sibling list groups to topological sorting (see previous patch) so base-pointer data dependencies are handled correctly. Secondly, it means that in the first pass gathering up sibling lists from parsed OpenMP/OpenACC clauses, we don't need to worry about gimplifying: that means we can see struct bases & components we need to sort sibling lists properly, even when we're using a non-DECL_P struct base. Gimplification proper still happens in the main loop in gimplify_scan_omp_clauses. Thirdly, because we use more than one pass through the clause list and gather appropriate data, we can tell if we're mapping a whole struct in a different node, and avoid building struct sibling lists for that struct appropriately. Fourthly, we can re-use the node grouping functions from the previous patch, and thus mostly avoid the "prev_list_p" handling in gimplify_scan_omp_clauses that tracks the first node in such groups at present. Some redundant code has been removed and code paths for OpenACC/OpenMP are now shared where appropriate, though OpenACC doesn't do the topological sorting of nodes (yet?). OK? Thanks, Julian 2021-09-29 Julian Brown gcc/ * gimplify.c (gimplify_omp_var_data): Remove GOVD_MAP_HAS_ATTACHMENTS. (extract_base_bit_offset): Remove OFFSETP parameter. (strip_components_and_deref): Extend with POINTER_PLUS_EXPR and COMPOUND_EXPR handling. (aggregate_base_p): Remove. (omp_group_last, omp_group_base): Add GOMP_MAP_STRUCT handling. (build_struct_group): Remove CTX, DECL, PD, COMPONENT_REF_P, FLAGS, STRUCT_SEEN_CLAUSE, PRE_P, CONT parameters. Replace PREV_LIST_P and C parameters with GRP_START_P and GRP_END. Add INNER. Update calls to extract_base_bit_offset. Remove gimplification of clauses for OpenMP. Rework inner struct handling for OpenACC. Don't use context's variables splay tree. (omp_build_struct_sibling_lists): New function, extracted from gimplify_scan_omp_clauses and refactored. (gimplify_scan_omp_clauses): Call above function to handle struct sibling lists. Remove STRUCT_MAP_TO_CLAUSE, STRUCT_SEEN_CLAUSE, STRUCT_DEREF_SET. Rework flag handling, adding decl for struct variables. (gimplify_adjust_omp_clauses_1): Remove GOVD_MAP_HAS_ATTACHMENTS handling, unused now. gcc/testsuite/ * g++.dg/goacc/member-array-acc.C: Update expected output. * g++.dg/gomp/target-3.C: Likewise. * g++.dg/gomp/target-lambda-1.C: Likewise. * g++.dg/gomp/target-this-2.C: Likewise. * g++.dg/gomp/target-this-4.C: Likewise. --- gcc/gimplify.c | 943 ++++++++---------- gcc/testsuite/g++.dg/goacc/member-array-acc.C | 2 +- gcc/testsuite/g++.dg/gomp/target-3.C | 4 +- gcc/testsuite/g++.dg/gomp/target-lambda-1.C | 2 +- gcc/testsuite/g++.dg/gomp/target-this-2.C | 2 +- gcc/testsuite/g++.dg/gomp/target-this-4.C | 4 +- 6 files changed, 410 insertions(+), 547 deletions(-) diff --git a/gcc/gimplify.c b/gcc/gimplify.c index fb923f05314..56f0aaaf979 100644 --- a/gcc/gimplify.c +++ b/gcc/gimplify.c @@ -125,10 +125,6 @@ enum gimplify_omp_var_data /* Flag for GOVD_REDUCTION: inscan seen in {in,ex}clusive clause. */ GOVD_REDUCTION_INSCAN = 0x2000000, - /* Flag for GOVD_MAP: (struct) vars that have pointer attachments for - fields. */ - GOVD_MAP_HAS_ATTACHMENTS = 0x4000000, - /* Flag for GOVD_FIRSTPRIVATE: OMP_CLAUSE_FIRSTPRIVATE_IMPLICIT. */ GOVD_FIRSTPRIVATE_IMPLICIT = 0x8000000, @@ -8659,7 +8655,7 @@ build_struct_comp_nodes (enum tree_code code, tree grp_start, tree grp_end, static tree extract_base_bit_offset (tree base, poly_int64 *bitposp, - poly_offset_int *poffsetp, tree *offsetp) + poly_offset_int *poffsetp) { tree offset; poly_int64 bitsize, bitpos; @@ -8687,7 +8683,6 @@ extract_base_bit_offset (tree base, poly_int64 *bitposp, *bitposp = bitpos; *poffsetp = poffset; - *offsetp = offset; return base; } @@ -8700,8 +8695,15 @@ strip_components_and_deref (tree expr) while (TREE_CODE (expr) == COMPONENT_REF || TREE_CODE (expr) == INDIRECT_REF || (TREE_CODE (expr) == MEM_REF - && integer_zerop (TREE_OPERAND (expr, 1)))) - expr = TREE_OPERAND (expr, 0); + && integer_zerop (TREE_OPERAND (expr, 1))) + || TREE_CODE (expr) == POINTER_PLUS_EXPR + || TREE_CODE (expr) == COMPOUND_EXPR) + if (TREE_CODE (expr) == COMPOUND_EXPR) + expr = TREE_OPERAND (expr, 1); + else + expr = TREE_OPERAND (expr, 0); + + STRIP_NOPS (expr); return expr; } @@ -8717,34 +8719,6 @@ strip_indirections (tree expr) return expr; } -/* Return TRUE if EXPR is something we will use as the base of an aggregate - access, either: - - - a DECL_P. - - a struct component with no indirection ("a.b.c"). - - a struct component with indirection ("a->b->c"). -*/ - -static bool -aggregate_base_p (tree expr) -{ - while (TREE_CODE (expr) == COMPONENT_REF - && (DECL_P (TREE_OPERAND (expr, 0)) - || (TREE_CODE (TREE_OPERAND (expr, 0)) == COMPONENT_REF))) - expr = TREE_OPERAND (expr, 0); - - if (DECL_P (expr)) - return true; - - if (TREE_CODE (expr) == COMPONENT_REF - && (TREE_CODE (TREE_OPERAND (expr, 0)) == INDIRECT_REF - || (TREE_CODE (TREE_OPERAND (expr, 0)) == MEM_REF - && integer_zerop (TREE_OPERAND (TREE_OPERAND (expr, 0), 1))))) - return true; - - return false; -} - enum omp_tsort_mark { UNVISITED, TEMPORARY, @@ -8973,6 +8947,18 @@ omp_group_last (tree *start_p) || OMP_CLAUSE_MAP_KIND (nc) == GOMP_MAP_DETACH)) grp_last_p = &OMP_CLAUSE_CHAIN (c); break; + + case GOMP_MAP_STRUCT: + { + unsigned HOST_WIDE_INT num_mappings + = tree_to_uhwi (OMP_CLAUSE_SIZE (c)); + if (OMP_CLAUSE_MAP_KIND (nc) == GOMP_MAP_FIRSTPRIVATE_POINTER + || OMP_CLAUSE_MAP_KIND (nc) == GOMP_MAP_FIRSTPRIVATE_REFERENCE) + grp_last_p = &OMP_CLAUSE_CHAIN (*grp_last_p); + for (unsigned i = 0; i < num_mappings; i++) + grp_last_p = &OMP_CLAUSE_CHAIN (*grp_last_p); + } + break; } return grp_last_p; @@ -9106,6 +9092,21 @@ omp_group_base (omp_mapping_group *grp, unsigned int *chained, internal_error ("unexpected mapping node"); return error_mark_node; + case GOMP_MAP_STRUCT: + { + unsigned HOST_WIDE_INT num_mappings + = tree_to_uhwi (OMP_CLAUSE_SIZE (node)); + node = OMP_CLAUSE_CHAIN (node); + if (OMP_CLAUSE_MAP_KIND (node) == GOMP_MAP_FIRSTPRIVATE_POINTER + || OMP_CLAUSE_MAP_KIND (node) == GOMP_MAP_FIRSTPRIVATE_REFERENCE) + { + *firstprivate = OMP_CLAUSE_DECL (node); + node = OMP_CLAUSE_CHAIN (node); + } + *chained = num_mappings; + return node; + } + case GOMP_MAP_FORCE_DEVICEPTR: case GOMP_MAP_DEVICE_RESIDENT: case GOMP_MAP_LINK: @@ -9771,21 +9772,16 @@ move_concat_nodes_after (tree first_new, tree *last_new_tail, tree *first_ptr, next node. PREV_LIST_P and LIST_P may be modified by the function when a list rearrangement has taken place. */ -static tree -build_struct_group (struct gimplify_omp_ctx *ctx, - enum omp_region_type region_type, enum tree_code code, - tree decl, tree *pd, bool component_ref_p, - unsigned int *flags, tree c, +static tree * +build_struct_group (enum omp_region_type region_type, enum tree_code code, hash_map *&struct_map_to_clause, - hash_map *&struct_seen_clause, - tree *&prev_list_p, tree *&list_p, gimple_seq *pre_p, - bool *cont) + tree *grp_start_p, tree grp_end, tree *inner) { poly_offset_int coffset; poly_int64 cbitpos; - tree tree_coffset; - tree ocd = OMP_CLAUSE_DECL (c); + tree ocd = OMP_CLAUSE_DECL (grp_end); bool openmp = !(region_type & ORT_ACC); + tree *continue_at = NULL; while (TREE_CODE (ocd) == ARRAY_REF) ocd = TREE_OPERAND (ocd, 0); @@ -9793,90 +9789,31 @@ build_struct_group (struct gimplify_omp_ctx *ctx, if (TREE_CODE (ocd) == INDIRECT_REF) ocd = TREE_OPERAND (ocd, 0); - tree base = extract_base_bit_offset (ocd, &cbitpos, &coffset, &tree_coffset); - tree sbase; + tree base = extract_base_bit_offset (ocd, &cbitpos, &coffset); - if (openmp) - { - if (TREE_CODE (base) == INDIRECT_REF - && TREE_CODE (TREE_TYPE (TREE_OPERAND (base, 0))) == REFERENCE_TYPE) - sbase = strip_indirections (base); - else - sbase = base; - } - else - { - sbase = strip_indirections (base); + bool ptr = (OMP_CLAUSE_MAP_KIND (grp_end) == GOMP_MAP_ALWAYS_POINTER); + bool attach_detach = ((OMP_CLAUSE_MAP_KIND (grp_end) + == GOMP_MAP_ATTACH_DETACH) + || (OMP_CLAUSE_MAP_KIND (grp_end) + == GOMP_MAP_ATTACH_ZERO_LENGTH_ARRAY_SECTION)); + bool attach = (OMP_CLAUSE_MAP_KIND (grp_end) == GOMP_MAP_ATTACH + || OMP_CLAUSE_MAP_KIND (grp_end) == GOMP_MAP_DETACH); - STRIP_NOPS (sbase); - } - - bool do_map_struct = (sbase == decl && !tree_coffset); - - /* Here, DECL is usually a DECL_P, unless we have chained indirect member - accesses, e.g. mystruct->a->b. In that case it'll be the "mystruct->a" - part. */ - splay_tree_node n - = (DECL_P (decl) - ? splay_tree_lookup (ctx->variables, (splay_tree_key) decl) - : NULL); - bool ptr = (OMP_CLAUSE_MAP_KIND (c) == GOMP_MAP_ALWAYS_POINTER); - bool attach_detach = (OMP_CLAUSE_MAP_KIND (c) == GOMP_MAP_ATTACH_DETACH); - bool attach = (OMP_CLAUSE_MAP_KIND (c) == GOMP_MAP_ATTACH - || OMP_CLAUSE_MAP_KIND (c) == GOMP_MAP_DETACH); - bool has_attachments = false; - - /* For OpenACC, pointers in structs should trigger an attach action. */ - if (attach_detach - && ((region_type & (ORT_ACC | ORT_TARGET | ORT_TARGET_DATA)) - || code == OMP_TARGET_ENTER_DATA - || code == OMP_TARGET_EXIT_DATA)) - { - /* Turn a GOMP_MAP_ATTACH_DETACH clause into a GOMP_MAP_ATTACH or - GOMP_MAP_DETACH clause after we have detected a case that needs a - GOMP_MAP_STRUCT mapping added. */ - gomp_map_kind k - = ((code == OACC_EXIT_DATA || code == OMP_TARGET_EXIT_DATA) - ? GOMP_MAP_DETACH : GOMP_MAP_ATTACH); - OMP_CLAUSE_SET_MAP_KIND (c, k); - has_attachments = true; - } - - /* We currently don't handle non-constant offset accesses wrt to - GOMP_MAP_STRUCT elements. */ - if (!do_map_struct) - return NULL_TREE; - - /* Nor for attach_detach for OpenMP. */ + /* FIXME: If we're not mapping the base pointer in some other clause on this + directive, I think we want to create ALLOC/RELEASE here -- i.e. not + early-exit. */ if (openmp && attach_detach) - { - if (DECL_P (decl)) - { - if (struct_seen_clause == NULL) - struct_seen_clause = new hash_map; - if (!struct_seen_clause->get (decl)) - struct_seen_clause->put (decl, list_p); - } + return NULL; - return NULL_TREE; - } - - if ((DECL_P (decl) && (n == NULL || (n->value & GOVD_MAP) == 0)) - || (!DECL_P (decl) - && (!struct_map_to_clause - || struct_map_to_clause->get (decl) == NULL))) + if (!struct_map_to_clause || struct_map_to_clause->get (base) == NULL) { - tree l = build_omp_clause (OMP_CLAUSE_LOCATION (c), OMP_CLAUSE_MAP); + tree l = build_omp_clause (OMP_CLAUSE_LOCATION (grp_end), OMP_CLAUSE_MAP); gomp_map_kind k = attach ? GOMP_MAP_FORCE_PRESENT : GOMP_MAP_STRUCT; OMP_CLAUSE_SET_MAP_KIND (l, k); OMP_CLAUSE_DECL (l) = unshare_expr (base); - if (openmp - && !DECL_P (OMP_CLAUSE_DECL (l)) - && (gimplify_expr (&OMP_CLAUSE_DECL (l), pre_p, NULL, - is_gimple_lvalue, fb_lvalue) == GS_ERROR)) - return error_mark_node; + OMP_CLAUSE_SIZE (l) = (!attach ? size_int (1) : (DECL_P (OMP_CLAUSE_DECL (l)) @@ -9884,19 +9821,17 @@ build_struct_group (struct gimplify_omp_ctx *ctx, : TYPE_SIZE_UNIT (TREE_TYPE (OMP_CLAUSE_DECL (l))))); if (struct_map_to_clause == NULL) struct_map_to_clause = new hash_map; - struct_map_to_clause->put (decl, l); + struct_map_to_clause->put (base, l); if (ptr || attach_detach) { tree extra_node; tree alloc_node - = build_struct_comp_nodes (code, *prev_list_p, c, &extra_node); + = build_struct_comp_nodes (code, *grp_start_p, grp_end, + &extra_node); OMP_CLAUSE_CHAIN (l) = alloc_node; - tree **sc = (struct_seen_clause - ? struct_seen_clause->get (decl) - : NULL); - tree *insert_node_pos = sc ? *sc : prev_list_p; + tree *insert_node_pos = grp_start_p; if (extra_node) { @@ -9907,131 +9842,89 @@ build_struct_group (struct gimplify_omp_ctx *ctx, OMP_CLAUSE_CHAIN (alloc_node) = *insert_node_pos; *insert_node_pos = l; - prev_list_p = NULL; } else - list_p = insert_node_after (l, list_p); - - bool base_ref - = (TREE_CODE (base) == INDIRECT_REF - && ((TREE_CODE (TREE_TYPE (TREE_OPERAND (base, 0))) - == REFERENCE_TYPE) - || ((TREE_CODE (TREE_OPERAND (base, 0)) == INDIRECT_REF) - && (TREE_CODE (TREE_TYPE (TREE_OPERAND - (TREE_OPERAND (base, 0), 0))) - == REFERENCE_TYPE)))); - bool base_ind = ((TREE_CODE (base) == INDIRECT_REF - || (TREE_CODE (base) == MEM_REF - && integer_zerop (TREE_OPERAND (base, 1)))) - && (TREE_CODE (TREE_TYPE (TREE_OPERAND (base, 0))) - == POINTER_TYPE)); - - /* Handle pointers to structs and references to structs: these cases - have an additional GOMP_MAP_FIRSTPRIVATE_{REFERENCE,POINTER} node - inserted after the GOMP_MAP_STRUCT node. References to pointers - use GOMP_MAP_FIRSTPRIVATE_REFERENCE. */ - if (base_ref && code == OMP_TARGET) { - tree c2 = build_omp_clause (OMP_CLAUSE_LOCATION (c), - OMP_CLAUSE_MAP); - enum gomp_map_kind mkind - = GOMP_MAP_FIRSTPRIVATE_REFERENCE; - OMP_CLAUSE_SET_MAP_KIND (c2, mkind); - OMP_CLAUSE_DECL (c2) = decl; - OMP_CLAUSE_SIZE (c2) = size_zero_node; - OMP_CLAUSE_CHAIN (c2) = OMP_CLAUSE_CHAIN (l); - OMP_CLAUSE_CHAIN (l) = c2; + gcc_assert (*grp_start_p == grp_end); + grp_start_p = insert_node_after (l, grp_start_p); } - else if (!openmp - && (base_ind || base_ref) - && (region_type & ORT_TARGET)) + + tree noind = strip_indirections (base); + + if (!openmp + && (region_type & ORT_TARGET) + && TREE_CODE (noind) == COMPONENT_REF) { - tree c2 = build_omp_clause (OMP_CLAUSE_LOCATION (c), OMP_CLAUSE_MAP); + /* The base for this component access is a struct component access + itself. Insert a node to be processed on the next iteration of + our caller's loop, which will subsequently be turned into a new, + inner GOMP_MAP_STRUCT mapping. + + We need to do this else the non-DECL_P base won't be + rewritten correctly in the offloaded region. */ + tree c2 = build_omp_clause (OMP_CLAUSE_LOCATION (grp_end), + OMP_CLAUSE_MAP); + OMP_CLAUSE_SET_MAP_KIND (c2, GOMP_MAP_FORCE_PRESENT); + OMP_CLAUSE_DECL (c2) = unshare_expr (noind); + OMP_CLAUSE_SIZE (c2) = TYPE_SIZE_UNIT (TREE_TYPE (noind)); + *inner = c2; + return NULL; + } + + tree sdecl = strip_components_and_deref (base); + + if (POINTER_TYPE_P (TREE_TYPE (sdecl)) && (region_type & ORT_TARGET)) + { + tree c2 = build_omp_clause (OMP_CLAUSE_LOCATION (grp_end), + OMP_CLAUSE_MAP); + bool base_ref + = (TREE_CODE (base) == INDIRECT_REF + && ((TREE_CODE (TREE_TYPE (TREE_OPERAND (base, 0))) + == REFERENCE_TYPE) + || ((TREE_CODE (TREE_OPERAND (base, 0)) + == INDIRECT_REF) + && (TREE_CODE (TREE_TYPE (TREE_OPERAND + (TREE_OPERAND (base, 0), 0))) + == REFERENCE_TYPE)))); enum gomp_map_kind mkind = base_ref ? GOMP_MAP_FIRSTPRIVATE_REFERENCE : GOMP_MAP_FIRSTPRIVATE_POINTER; OMP_CLAUSE_SET_MAP_KIND (c2, mkind); - OMP_CLAUSE_SIZE (c2) = size_zero_node; - tree sdecl = strip_components_and_deref (decl); - if (DECL_P (decl) - && (POINTER_TYPE_P (TREE_TYPE (sdecl)) - || TREE_CODE (TREE_TYPE (sdecl)) == REFERENCE_TYPE)) - { - /* Insert after struct node. */ - OMP_CLAUSE_CHAIN (c2) = OMP_CLAUSE_CHAIN (l); - OMP_CLAUSE_DECL (c2) = decl; - OMP_CLAUSE_CHAIN (l) = c2; - } - else - { - /* If the ultimate base for this component access is not a - pointer or reference, that means it is a struct component - access itself. Insert a node to be processed on the next - iteration of our caller's loop, which will subsequently be - turned into a new GOMP_MAP_STRUCT mapping itself. - - We need to do this else the non-DECL_P base won't be - rewritten correctly in the offloaded region. */ - tree c2 = build_omp_clause (OMP_CLAUSE_LOCATION (c), - OMP_CLAUSE_MAP); - OMP_CLAUSE_SET_MAP_KIND (c2, GOMP_MAP_FORCE_PRESENT); - OMP_CLAUSE_DECL (c2) = unshare_expr (decl); - OMP_CLAUSE_SIZE (c2) = (DECL_P (decl) - ? DECL_SIZE_UNIT (decl) - : TYPE_SIZE_UNIT (TREE_TYPE (decl))); - tree *next_node = &OMP_CLAUSE_CHAIN (*list_p); - OMP_CLAUSE_CHAIN (c2) = *next_node; - *next_node = c2; - return NULL_TREE; - } - } - *flags = GOVD_MAP | GOVD_EXPLICIT; - if (GOMP_MAP_ALWAYS_P (OMP_CLAUSE_MAP_KIND (c)) || ptr || attach_detach) - *flags |= GOVD_SEEN; - if (has_attachments) - *flags |= GOVD_MAP_HAS_ATTACHMENTS; - - /* If this is a *pointer-to-struct expression, make sure a - firstprivate map of the base-pointer exists. */ - if (openmp - && component_ref_p - && ((TREE_CODE (decl) == MEM_REF - && integer_zerop (TREE_OPERAND (decl, 1))) - || INDIRECT_REF_P (decl)) - && DECL_P (TREE_OPERAND (decl, 0)) - && !splay_tree_lookup (ctx->variables, - ((splay_tree_key) TREE_OPERAND (decl, 0)))) - { - decl = TREE_OPERAND (decl, 0); - tree c2 = build_omp_clause (OMP_CLAUSE_LOCATION (c), OMP_CLAUSE_MAP); - enum gomp_map_kind mkind = GOMP_MAP_FIRSTPRIVATE_POINTER; - OMP_CLAUSE_SET_MAP_KIND (c2, mkind); - OMP_CLAUSE_DECL (c2) = decl; - OMP_CLAUSE_SIZE (c2) = size_zero_node; - OMP_CLAUSE_CHAIN (c2) = OMP_CLAUSE_CHAIN (c); - OMP_CLAUSE_CHAIN (c) = c2; + OMP_CLAUSE_DECL (c2) = sdecl; + tree baddr = build_fold_addr_expr (base); + baddr = fold_convert_loc (OMP_CLAUSE_LOCATION (grp_end), + ptrdiff_type_node, baddr); + /* This isn't going to be good enough when we add support for more + complicated lvalue expressions. FIXME. */ + if (TREE_CODE (TREE_TYPE (sdecl)) == REFERENCE_TYPE + && TREE_CODE (TREE_TYPE (TREE_TYPE (sdecl))) == POINTER_TYPE) + sdecl = build_simple_mem_ref (sdecl); + tree decladdr = fold_convert_loc (OMP_CLAUSE_LOCATION (grp_end), + ptrdiff_type_node, sdecl); + OMP_CLAUSE_SIZE (c2) + = fold_build2_loc (OMP_CLAUSE_LOCATION (grp_end), MINUS_EXPR, + ptrdiff_type_node, baddr, decladdr); + /* Insert after struct node. */ + OMP_CLAUSE_CHAIN (c2) = OMP_CLAUSE_CHAIN (l); + OMP_CLAUSE_CHAIN (l) = c2; } - return decl; + return NULL; } else if (struct_map_to_clause) { - tree *osc = struct_map_to_clause->get (decl); + tree *osc = struct_map_to_clause->get (base); tree *sc = NULL, *scp = NULL; - if (n && (GOMP_MAP_ALWAYS_P (OMP_CLAUSE_MAP_KIND (c)) - || ptr - || attach_detach)) - n->value |= GOVD_SEEN; sc = &OMP_CLAUSE_CHAIN (*osc); /* The struct mapping might be immediately followed by a FIRSTPRIVATE_POINTER and/or FIRSTPRIVATE_REFERENCE -- if it's an indirect access or a reference, or both. (This added node is removed in omp-low.c after it has been processed there.) */ - if (*sc != c + if (*sc != grp_end && (OMP_CLAUSE_MAP_KIND (*sc) == GOMP_MAP_FIRSTPRIVATE_POINTER || OMP_CLAUSE_MAP_KIND (*sc) == GOMP_MAP_FIRSTPRIVATE_REFERENCE)) sc = &OMP_CLAUSE_CHAIN (*sc); - for (; *sc != c; sc = &OMP_CLAUSE_CHAIN (*sc)) - if ((ptr || attach_detach) && sc == prev_list_p) + for (; *sc != grp_end; sc = &OMP_CLAUSE_CHAIN (*sc)) + if ((ptr || attach_detach) && sc == grp_start_p) break; else if (TREE_CODE (OMP_CLAUSE_DECL (*sc)) != COMPONENT_REF && TREE_CODE (OMP_CLAUSE_DECL (*sc)) != INDIRECT_REF @@ -10042,7 +9935,6 @@ build_struct_group (struct gimplify_omp_ctx *ctx, tree sc_decl = OMP_CLAUSE_DECL (*sc); poly_offset_int offset; poly_int64 bitpos; - tree tree_offset; if (TREE_CODE (sc_decl) == ARRAY_REF) { @@ -10058,8 +9950,7 @@ build_struct_group (struct gimplify_omp_ctx *ctx, == REFERENCE_TYPE)) sc_decl = TREE_OPERAND (sc_decl, 0); - tree base2 = extract_base_bit_offset (sc_decl, &bitpos, &offset, - &tree_offset); + tree base2 = extract_base_bit_offset (sc_decl, &bitpos, &offset); if (!base2 || !operand_equal_p (base2, base, 0)) break; if (scp) @@ -10069,7 +9960,7 @@ build_struct_group (struct gimplify_omp_ctx *ctx, /* This duplicate checking code is currently only enabled for OpenACC. */ tree d1 = OMP_CLAUSE_DECL (*sc); - tree d2 = OMP_CLAUSE_DECL (c); + tree d2 = OMP_CLAUSE_DECL (grp_end); while (TREE_CODE (d1) == ARRAY_REF) d1 = TREE_OPERAND (d1, 0); while (TREE_CODE (d2) == ARRAY_REF) @@ -10089,10 +9980,10 @@ build_struct_group (struct gimplify_omp_ctx *ctx, break; if (d1 == d2) { - error_at (OMP_CLAUSE_LOCATION (c), + error_at (OMP_CLAUSE_LOCATION (grp_end), "%qE appears more than once in map clauses", - OMP_CLAUSE_DECL (c)); - return error_mark_node; + OMP_CLAUSE_DECL (grp_end)); + return NULL; } } if (maybe_lt (coffset, offset) @@ -10112,15 +10003,15 @@ build_struct_group (struct gimplify_omp_ctx *ctx, if (ptr || attach_detach) { tree cl = NULL_TREE, extra_node; - tree alloc_node = build_struct_comp_nodes (code, *prev_list_p, c, - &extra_node); + tree alloc_node = build_struct_comp_nodes (code, *grp_start_p, + grp_end, &extra_node); tree *tail_chain = NULL; /* Here, we have: - c : the currently-processed node. - prev_list_p : pointer to the first node in a pointer mapping group - up to and including C. + grp_end : the last (or only) node in this group. + grp_start_p : pointer to the first node in a pointer mapping group + up to and including GRP_END. sc : pointer to the chain for the end of the struct component list. scp : pointer to the chain for the sorted position at which we @@ -10131,7 +10022,7 @@ build_struct_group (struct gimplify_omp_ctx *ctx, (the end of the struct component list). extra_node : a newly-synthesized node for an additional indirect pointer mapping or a Fortran pointer set, if needed. - cl : first node to prepend before prev_list_p. + cl : first node to prepend before grp_start_p. tail_chain : pointer to chain of last prepended node. The general idea is we move the nodes for this struct mapping @@ -10167,32 +10058,180 @@ build_struct_group (struct gimplify_omp_ctx *ctx, tail_chain = &OMP_CLAUSE_CHAIN (alloc_node); } - tree *continue_at - = cl ? move_concat_nodes_after (cl, tail_chain, prev_list_p, c, sc) - : move_nodes_after (prev_list_p, c, sc); - - prev_list_p = NULL; - - if (continue_at) - { - list_p = continue_at; - *cont = true; - } + continue_at + = cl ? move_concat_nodes_after (cl, tail_chain, grp_start_p, + grp_end, sc) + : move_nodes_after (grp_start_p, grp_end, sc); } - else if (*sc != c) + else if (*sc != grp_end) { - if (openmp - && (gimplify_expr (pd, pre_p, NULL, is_gimple_lvalue, fb_lvalue) - == GS_ERROR)) - return error_mark_node; + gcc_assert (*grp_start_p == grp_end); + + /* We are moving the current node back to a previous struct node: + the node that used to point to the current node will now point to + the next node. */ + continue_at = grp_start_p; /* In the non-pointer case, the mapping clause itself is moved into the correct position in the struct component list, which in this case is just SC. */ - move_node_after (c, list_p, sc); - *cont = true; + move_node_after (grp_end, grp_start_p, sc); } } - return NULL_TREE; + return continue_at; +} + +/* Scan through GROUPS, and create sorted structure sibling lists without + gimplifying. */ + +static bool +omp_build_struct_sibling_lists (enum tree_code code, + enum omp_region_type region_type, + vec *groups, + hash_map + *grpmap) +{ + unsigned i; + omp_mapping_group *grp; + hash_map *struct_map_to_clause = NULL; + bool success = true; + tree *new_next = NULL; + tree *tail = &OMP_CLAUSE_CHAIN ((*groups)[groups->length () - 1].grp_end); + + FOR_EACH_VEC_ELT (*groups, i, grp) + { + tree c = grp->grp_end; + tree decl = OMP_CLAUSE_DECL (c); + tree *grp_start_p = new_next ? new_next : grp->grp_start; + tree grp_end = grp->grp_end; + + new_next = NULL; + + if (DECL_P (decl)) + continue; + + if (OMP_CLAUSE_CHAIN (*grp_start_p) + && OMP_CLAUSE_CHAIN (*grp_start_p) != grp_end) + { + /* Don't process an array descriptor that isn't inside a derived type + as a struct (the GOMP_MAP_POINTER following will have the form + "var.data", but such mappings are handled specially). */ + tree grpmid = OMP_CLAUSE_CHAIN (*grp_start_p); + if (OMP_CLAUSE_CODE (grpmid) == OMP_CLAUSE_MAP + && OMP_CLAUSE_MAP_KIND (grpmid) == GOMP_MAP_TO_PSET + && DECL_P (OMP_CLAUSE_DECL (grpmid))) + continue; + } + + tree d = decl; + if (TREE_CODE (d) == ARRAY_REF) + { + while (TREE_CODE (d) == ARRAY_REF) + d = TREE_OPERAND (d, 0); + if (TREE_CODE (d) == COMPONENT_REF + && TREE_CODE (TREE_TYPE (d)) == ARRAY_TYPE) + decl = d; + } + if (d == decl + && TREE_CODE (decl) == INDIRECT_REF + && TREE_CODE (TREE_OPERAND (decl, 0)) == COMPONENT_REF + && (TREE_CODE (TREE_TYPE (TREE_OPERAND (decl, 0))) + == REFERENCE_TYPE) + && (OMP_CLAUSE_MAP_KIND (c) + != GOMP_MAP_POINTER_TO_ZERO_LENGTH_ARRAY_SECTION)) + decl = TREE_OPERAND (decl, 0); + + STRIP_NOPS (decl); + + if (TREE_CODE (decl) != COMPONENT_REF) + continue; + + omp_mapping_group **wholestruct = NULL; + tree wsdecl = omp_containing_struct (OMP_CLAUSE_DECL (c)); + + if (!(region_type & ORT_ACC) && wsdecl != OMP_CLAUSE_DECL (c)) + { + wholestruct = grpmap->get (wsdecl); + if (!wholestruct + && TREE_CODE (wsdecl) == MEM_REF + && integer_zerop (TREE_OPERAND (wsdecl, 1))) + { + tree deref = TREE_OPERAND (wsdecl, 0); + deref = build1 (INDIRECT_REF, TREE_TYPE (wsdecl), deref); + wholestruct = grpmap->get (deref); + } + } + + if (wholestruct) + { + + if (*grp_start_p == grp_end) + { + /* Remove the whole of this mapping -- redundant. */ + new_next = grp_start_p; + *grp_start_p = OMP_CLAUSE_CHAIN (grp_end); + } + + continue; + } + + if (OMP_CLAUSE_MAP_KIND (c) != GOMP_MAP_TO_PSET + && OMP_CLAUSE_MAP_KIND (c) != GOMP_MAP_ATTACH + && OMP_CLAUSE_MAP_KIND (c) != GOMP_MAP_DETACH + && code != OACC_UPDATE + && code != OMP_TARGET_UPDATE) + { + if (error_operand_p (decl)) + { + success = false; + goto error_out; + } + + tree stype = TREE_TYPE (decl); + if (TREE_CODE (stype) == REFERENCE_TYPE) + stype = TREE_TYPE (stype); + if (TYPE_SIZE_UNIT (stype) == NULL + || TREE_CODE (TYPE_SIZE_UNIT (stype)) != INTEGER_CST) + { + error_at (OMP_CLAUSE_LOCATION (c), + "mapping field %qE of variable length " + "structure", OMP_CLAUSE_DECL (c)); + success = false; + goto error_out; + } + + tree inner = NULL_TREE; + + new_next = build_struct_group (region_type, code, + struct_map_to_clause, grp_start_p, + grp_end, &inner); + + if (inner) + { + if (new_next && *new_next == NULL_TREE) + *new_next = inner; + else + *tail = inner; + + OMP_CLAUSE_CHAIN (inner) = NULL_TREE; + + omp_mapping_group newgrp; + newgrp.grp_start = new_next ? new_next : tail; + newgrp.grp_end = inner; + newgrp.mark = UNVISITED; + newgrp.sibling = NULL; + newgrp.next = NULL; + groups->safe_push (newgrp); + + tail = &OMP_CLAUSE_CHAIN (inner); + } + } + } + +error_out: + if (struct_map_to_clause) + delete struct_map_to_clause; + + return success; } /* Scan the OMP clauses in *LIST_P, installing mappings into a new @@ -10205,9 +10244,6 @@ gimplify_scan_omp_clauses (tree *list_p, gimple_seq *pre_p, { struct gimplify_omp_ctx *ctx, *outer_ctx; tree c; - hash_map *struct_map_to_clause = NULL; - hash_map *struct_seen_clause = NULL; - hash_set *struct_deref_set = NULL; tree *prev_list_p = NULL, *orig_list_p = list_p; int handled_depend_iterators = -1; int nowait = -1; @@ -10239,14 +10275,10 @@ gimplify_scan_omp_clauses (tree *list_p, gimple_seq *pre_p, break; } - /* Topological sorting may fail if we have duplicate nodes, which - we should have detected and shown an error for already. Skip - sorting in that case. */ - if (!seen_error () - && (code == OMP_TARGET - || code == OMP_TARGET_DATA - || code == OMP_TARGET_ENTER_DATA - || code == OMP_TARGET_EXIT_DATA)) + if (code == OMP_TARGET + || code == OMP_TARGET_DATA + || code == OMP_TARGET_ENTER_DATA + || code == OMP_TARGET_EXIT_DATA) { vec *groups; groups = omp_gather_mapping_groups (list_p); @@ -10254,12 +10286,46 @@ gimplify_scan_omp_clauses (tree *list_p, gimple_seq *pre_p, { hash_map *grpmap; grpmap = omp_index_mapping_groups (groups); - omp_mapping_group *outlist - = omp_tsort_mapping_groups (groups, grpmap); - outlist = omp_segregate_mapping_groups (outlist); - list_p = omp_reorder_mapping_groups (groups, outlist, list_p); + + omp_build_struct_sibling_lists (code, region_type, groups, grpmap); + + omp_mapping_group *outlist = NULL; + + /* Topological sorting may fail if we have duplicate nodes, which + we should have detected and shown an error for already. Skip + sorting in that case. */ + if (seen_error ()) + goto failure; + delete grpmap; delete groups; + + /* Rebuild now we have struct sibling lists. */ + groups = omp_gather_mapping_groups (list_p); + grpmap = omp_index_mapping_groups (groups); + + outlist = omp_tsort_mapping_groups (groups, grpmap); + outlist = omp_segregate_mapping_groups (outlist); + list_p = omp_reorder_mapping_groups (groups, outlist, list_p); + + failure: + delete grpmap; + delete groups; + } + } + else if (region_type & ORT_ACC) + { + vec *groups; + groups = omp_gather_mapping_groups (list_p); + if (groups) + { + hash_map *grpmap; + grpmap = omp_index_mapping_groups (groups); + + omp_build_struct_sibling_lists (code, region_type, groups, grpmap); + + delete groups; + delete grpmap; } } @@ -10668,6 +10734,28 @@ gimplify_scan_omp_clauses (tree *list_p, gimple_seq *pre_p, GOVD_FIRSTPRIVATE | GOVD_SEEN); } + if (OMP_CLAUSE_MAP_KIND (c) == GOMP_MAP_STRUCT) + { + tree base = strip_components_and_deref (decl); + if (DECL_P (base)) + { + decl = base; + splay_tree_node n + = splay_tree_lookup (ctx->variables, + (splay_tree_key) decl); + if (seen_error () + && n + && (n->value & (GOVD_MAP | GOVD_FIRSTPRIVATE)) != 0) + { + remove = true; + break; + } + flags = GOVD_MAP | GOVD_EXPLICIT; + + goto do_add_decl; + } + } + if (TREE_CODE (decl) == TARGET_EXPR) { if (gimplify_expr (&OMP_CLAUSE_DECL (c), pre_p, NULL, @@ -10698,143 +10786,6 @@ gimplify_scan_omp_clauses (tree *list_p, gimple_seq *pre_p, pd = &TREE_OPERAND (decl, 0); decl = TREE_OPERAND (decl, 0); } - bool indir_p = false; - bool component_ref_p = false; - tree indir_base = NULL_TREE; - tree orig_decl = decl; - tree decl_ref = NULL_TREE; - if ((region_type & ORT_ACC) && TREE_CODE (decl) == COMPONENT_REF) - { - /* Strip off component refs from RHS of e.g. "a->b->c.d.e" - (which would leave "a->b" in that case). This is intended - to be equivalent to the base finding done by - get_inner_reference. */ - while (TREE_CODE (decl) == COMPONENT_REF - && (DECL_P (TREE_OPERAND (decl, 0)) - || (TREE_CODE (TREE_OPERAND (decl, 0)) - == COMPONENT_REF))) - decl = TREE_OPERAND (decl, 0); - - if (TREE_CODE (decl) == COMPONENT_REF) - decl = TREE_OPERAND (decl, 0); - - /* Strip off RHS from "a->b". */ - if ((TREE_CODE (decl) == INDIRECT_REF - || (TREE_CODE (decl) == MEM_REF - && integer_zerop (TREE_OPERAND (decl, 1)))) - && (TREE_CODE (TREE_TYPE (TREE_OPERAND (decl, 0))) - == POINTER_TYPE)) - decl = TREE_OPERAND (decl, 0); - - /* Strip off RHS from "a_ref.b" (where a_ref is - reference-typed). */ - if (TREE_CODE (decl) == INDIRECT_REF - && DECL_P (TREE_OPERAND (decl, 0)) - && (TREE_CODE (TREE_TYPE (TREE_OPERAND (decl, 0))) - == REFERENCE_TYPE)) - decl = TREE_OPERAND (decl, 0); - - STRIP_NOPS (decl); - } - else if ((region_type & (ORT_TARGET | ORT_TARGET_DATA)) != 0 - && TREE_CODE (*pd) == COMPONENT_REF - && OMP_CLAUSE_MAP_KIND (c) == GOMP_MAP_ATTACH_DETACH - && code != OACC_UPDATE) - { - while (TREE_CODE (decl) == COMPONENT_REF) - { - decl = TREE_OPERAND (decl, 0); - component_ref_p = true; - if (((TREE_CODE (decl) == MEM_REF - && integer_zerop (TREE_OPERAND (decl, 1))) - || INDIRECT_REF_P (decl)) - && (TREE_CODE (TREE_TYPE (TREE_OPERAND (decl, 0))) - == POINTER_TYPE)) - { - indir_p = true; - indir_base = decl; - decl = TREE_OPERAND (decl, 0); - STRIP_NOPS (decl); - } - if (TREE_CODE (decl) == INDIRECT_REF - && DECL_P (TREE_OPERAND (decl, 0)) - && (TREE_CODE (TREE_TYPE (TREE_OPERAND (decl, 0))) - == REFERENCE_TYPE)) - { - decl_ref = decl; - decl = TREE_OPERAND (decl, 0); - } - } - } - else if (TREE_CODE (decl) == COMPONENT_REF - && (OMP_CLAUSE_MAP_KIND (c) - != GOMP_MAP_ATTACH_ZERO_LENGTH_ARRAY_SECTION)) - { - component_ref_p = true; - while (TREE_CODE (decl) == COMPONENT_REF) - decl = TREE_OPERAND (decl, 0); - if (TREE_CODE (decl) == INDIRECT_REF - && DECL_P (TREE_OPERAND (decl, 0)) - && (TREE_CODE (TREE_TYPE (TREE_OPERAND (decl, 0))) - == REFERENCE_TYPE)) - decl = TREE_OPERAND (decl, 0); - } - if (decl != orig_decl && DECL_P (decl) && indir_p) - { - gomp_map_kind k - = ((code == OACC_EXIT_DATA || code == OMP_TARGET_EXIT_DATA) - ? GOMP_MAP_DETACH : GOMP_MAP_ATTACH); - /* We have a dereference of a struct member. Make this an - attach/detach operation, and ensure the base pointer is - mapped as a FIRSTPRIVATE_POINTER. */ - OMP_CLAUSE_SET_MAP_KIND (c, k); - flags = GOVD_MAP | GOVD_SEEN | GOVD_EXPLICIT; - tree next_clause = OMP_CLAUSE_CHAIN (c); - if (k == GOMP_MAP_ATTACH - && code != OACC_ENTER_DATA - && code != OMP_TARGET_ENTER_DATA - && (!next_clause - || (OMP_CLAUSE_CODE (next_clause) != OMP_CLAUSE_MAP) - || (OMP_CLAUSE_MAP_KIND (next_clause) - != GOMP_MAP_POINTER) - || OMP_CLAUSE_DECL (next_clause) != decl) - && (!struct_deref_set - || !struct_deref_set->contains (decl)) - && (!struct_map_to_clause - || !struct_map_to_clause->get (indir_base))) - { - if (!struct_deref_set) - struct_deref_set = new hash_set (); - /* As well as the attach, we also need a - FIRSTPRIVATE_POINTER clause to properly map the - pointer to the struct base. */ - tree c2 = build_omp_clause (OMP_CLAUSE_LOCATION (c), - OMP_CLAUSE_MAP); - OMP_CLAUSE_SET_MAP_KIND (c2, GOMP_MAP_ALLOC); - OMP_CLAUSE_MAP_MAYBE_ZERO_LENGTH_ARRAY_SECTION (c2) - = 1; - tree charptr_zero - = build_int_cst (build_pointer_type (char_type_node), - 0); - OMP_CLAUSE_DECL (c2) - = build2 (MEM_REF, char_type_node, - decl_ref ? decl_ref : decl, charptr_zero); - OMP_CLAUSE_SIZE (c2) = size_zero_node; - tree c3 = build_omp_clause (OMP_CLAUSE_LOCATION (c), - OMP_CLAUSE_MAP); - OMP_CLAUSE_SET_MAP_KIND (c3, - GOMP_MAP_FIRSTPRIVATE_POINTER); - OMP_CLAUSE_DECL (c3) = decl; - OMP_CLAUSE_SIZE (c3) = size_zero_node; - tree mapgrp = *prev_list_p; - *prev_list_p = c2; - OMP_CLAUSE_CHAIN (c3) = mapgrp; - OMP_CLAUSE_CHAIN (c2) = c3; - - struct_deref_set->add (decl); - } - goto do_add_decl; - } /* An "attach/detach" operation on an update directive should behave as a GOMP_MAP_ALWAYS_POINTER. Beware that unlike attach or detach map kinds, GOMP_MAP_ALWAYS_POINTER @@ -10842,91 +10793,49 @@ gimplify_scan_omp_clauses (tree *list_p, gimple_seq *pre_p, if (code == OACC_UPDATE && OMP_CLAUSE_MAP_KIND (c) == GOMP_MAP_ATTACH_DETACH) OMP_CLAUSE_SET_MAP_KIND (c, GOMP_MAP_ALWAYS_POINTER); - if ((((region_type & ORT_ACC) && aggregate_base_p (decl)) - || (!(region_type & ORT_ACC) - && (DECL_P (decl) - || (component_ref_p - && (INDIRECT_REF_P (decl) - || TREE_CODE (decl) == MEM_REF - || TREE_CODE (decl) == ARRAY_REF))))) - && OMP_CLAUSE_MAP_KIND (c) != GOMP_MAP_TO_PSET - && OMP_CLAUSE_MAP_KIND (c) != GOMP_MAP_ATTACH - && OMP_CLAUSE_MAP_KIND (c) != GOMP_MAP_DETACH - && code != OACC_UPDATE - && code != OMP_TARGET_UPDATE) + + if (OMP_CLAUSE_MAP_KIND (c) == GOMP_MAP_ATTACH_DETACH) { - if (error_operand_p (decl)) + if (TREE_CODE (TREE_TYPE (OMP_CLAUSE_DECL (c))) + == ARRAY_TYPE) + remove = true; + else { - remove = true; - break; + gomp_map_kind k = ((code == OACC_EXIT_DATA + || code == OMP_TARGET_EXIT_DATA) + ? GOMP_MAP_DETACH : GOMP_MAP_ATTACH); + OMP_CLAUSE_SET_MAP_KIND (c, k); } - - tree stype = TREE_TYPE (decl); - if (TREE_CODE (stype) == REFERENCE_TYPE) - stype = TREE_TYPE (stype); - if (TYPE_SIZE_UNIT (stype) == NULL - || TREE_CODE (TYPE_SIZE_UNIT (stype)) != INTEGER_CST) - { - error_at (OMP_CLAUSE_LOCATION (c), - "mapping field %qE of variable length " - "structure", OMP_CLAUSE_DECL (c)); - remove = true; - break; - } - - if (OMP_CLAUSE_MAP_KIND (c) == GOMP_MAP_ALWAYS_POINTER - || OMP_CLAUSE_MAP_KIND (c) == GOMP_MAP_ATTACH_DETACH) - { - /* Error recovery. */ - if (prev_list_p == NULL) - { - remove = true; - break; - } - - /* The below prev_list_p based error recovery code is - currently no longer valid for OpenMP. */ - if (code != OMP_TARGET - && code != OMP_TARGET_DATA - && code != OMP_TARGET_UPDATE - && code != OMP_TARGET_ENTER_DATA - && code != OMP_TARGET_EXIT_DATA - && OMP_CLAUSE_CHAIN (*prev_list_p) != c) - { - tree ch = OMP_CLAUSE_CHAIN (*prev_list_p); - if (ch == NULL_TREE || OMP_CLAUSE_CHAIN (ch) != c) - { - remove = true; - break; - } - } - } - bool cont = false; - tree add_decl - = build_struct_group (ctx, region_type, code, decl, pd, - component_ref_p, &flags, c, - struct_map_to_clause, - struct_seen_clause, prev_list_p, - list_p, pre_p, &cont); - if (add_decl == error_mark_node) - { - remove = true; - break; - } - else if (add_decl && DECL_P (add_decl)) - { - decl = add_decl; - goto do_add_decl; - } - if (cont) - continue; } - else if (OMP_CLAUSE_MAP_KIND (c) == GOMP_MAP_ATTACH_DETACH) + + tree cref = decl; + + while (TREE_CODE (cref) == ARRAY_REF) + cref = TREE_OPERAND (cref, 0); + + if (TREE_CODE (cref) == INDIRECT_REF) + cref = TREE_OPERAND (cref, 0); + + if (TREE_CODE (cref) == COMPONENT_REF) { - gomp_map_kind k = ((code == OACC_EXIT_DATA - || code == OMP_TARGET_EXIT_DATA) - ? GOMP_MAP_DETACH : GOMP_MAP_ATTACH); - OMP_CLAUSE_SET_MAP_KIND (c, k); + tree base = cref; + while (base && !DECL_P (base)) + { + tree innerbase = omp_get_base_pointer (base); + if (!innerbase) + break; + base = innerbase; + } + if (base + && DECL_P (base) + && GOMP_MAP_ALWAYS_P (OMP_CLAUSE_MAP_KIND (c)) + && POINTER_TYPE_P (TREE_TYPE (base))) + { + splay_tree_node n + = splay_tree_lookup (ctx->variables, + (splay_tree_key) base); + n->value |= GOVD_SEEN; + } } if (code == OMP_TARGET && OMP_CLAUSE_MAP_IN_REDUCTION (c)) @@ -11044,24 +10953,6 @@ gimplify_scan_omp_clauses (tree *list_p, gimple_seq *pre_p, break; } - /* If this was of the form map(*pointer_to_struct), then the - 'pointer_to_struct' DECL should be considered deref'ed. */ - if ((OMP_CLAUSE_MAP_KIND (c) == GOMP_MAP_ALLOC - || GOMP_MAP_COPY_TO_P (OMP_CLAUSE_MAP_KIND (c)) - || GOMP_MAP_COPY_FROM_P (OMP_CLAUSE_MAP_KIND (c))) - && INDIRECT_REF_P (orig_decl) - && DECL_P (TREE_OPERAND (orig_decl, 0)) - && TREE_CODE (TREE_TYPE (orig_decl)) == RECORD_TYPE) - { - tree ptr = TREE_OPERAND (orig_decl, 0); - if (!struct_deref_set || !struct_deref_set->contains (ptr)) - { - if (!struct_deref_set) - struct_deref_set = new hash_set (); - struct_deref_set->add (ptr); - } - } - if (!remove && OMP_CLAUSE_MAP_KIND (c) != GOMP_MAP_ALWAYS_POINTER && OMP_CLAUSE_MAP_KIND (c) != GOMP_MAP_ATTACH_DETACH @@ -11078,28 +10969,6 @@ gimplify_scan_omp_clauses (tree *list_p, gimple_seq *pre_p, break; } - else - { - /* DECL_P (decl) == true */ - tree *sc; - if (struct_map_to_clause - && (sc = struct_map_to_clause->get (decl)) != NULL - && OMP_CLAUSE_MAP_KIND (*sc) == GOMP_MAP_STRUCT - && decl == OMP_CLAUSE_DECL (*sc)) - { - /* We have found a map of the whole structure after a - leading GOMP_MAP_STRUCT has been created, so refill the - leading clause into a map of the whole structure - variable, and remove the current one. - TODO: we should be able to remove some maps of the - following structure element maps if they are of - compatible TO/FROM/ALLOC type. */ - OMP_CLAUSE_SET_MAP_KIND (*sc, OMP_CLAUSE_MAP_KIND (c)); - OMP_CLAUSE_SIZE (*sc) = unshare_expr (OMP_CLAUSE_SIZE (c)); - remove = true; - break; - } - } flags = GOVD_MAP | GOVD_EXPLICIT; if (OMP_CLAUSE_MAP_KIND (c) == GOMP_MAP_ALWAYS_TO || OMP_CLAUSE_MAP_KIND (c) == GOMP_MAP_ALWAYS_TOFROM) @@ -11756,12 +11625,6 @@ gimplify_scan_omp_clauses (tree *list_p, gimple_seq *pre_p, ctx->clauses = *orig_list_p; gimplify_omp_ctxp = ctx; - if (struct_seen_clause) - delete struct_seen_clause; - if (struct_map_to_clause) - delete struct_map_to_clause; - if (struct_deref_set) - delete struct_deref_set; } /* Return true if DECL is a candidate for shared to firstprivate @@ -11910,8 +11773,6 @@ gimplify_adjust_omp_clauses_1 (splay_tree_node n, void *data) return 0; if ((flags & GOVD_SEEN) == 0) return 0; - if ((flags & GOVD_MAP_HAS_ATTACHMENTS) != 0) - return 0; if (flags & GOVD_DEBUG_PRIVATE) { gcc_assert ((flags & GOVD_DATA_SHARE_CLASS) == GOVD_SHARED); diff --git a/gcc/testsuite/g++.dg/goacc/member-array-acc.C b/gcc/testsuite/g++.dg/goacc/member-array-acc.C index e0c11570f5d..9993768ef20 100644 --- a/gcc/testsuite/g++.dg/goacc/member-array-acc.C +++ b/gcc/testsuite/g++.dg/goacc/member-array-acc.C @@ -10,4 +10,4 @@ struct Foo { }; int main() { Foo x; x.init(1024); } -/* { dg-final { scan-tree-dump {struct:\*\(struct Foo \*\) this \[len: 1\]\) map\(alloc:\(\(struct Foo \*\) this\)->a \[len: [0-9]+\]\) map\(alloc:\*_[0-9]+ \[len: _[0-9]+\]\) map\(attach:\(\(struct Foo \*\) this\)->a \[bias: 0\]\)} "gimple" } } */ +/* { dg-final { scan-tree-dump {struct:\*\(struct Foo \*\) this \[len: 1\]\) map\(alloc:this->a \[len: [0-9]+\]\) map\(alloc:\*_[0-9]+ \[len: _[0-9]+\]\) map\(attach:this->a \[bias: 0\]\)} "gimple" } } */ diff --git a/gcc/testsuite/g++.dg/gomp/target-3.C b/gcc/testsuite/g++.dg/gomp/target-3.C index f4d40ec8e4b..432f02614d8 100644 --- a/gcc/testsuite/g++.dg/gomp/target-3.C +++ b/gcc/testsuite/g++.dg/gomp/target-3.C @@ -33,4 +33,6 @@ T::bar (int x) template struct T<0>; -/* { dg-final { scan-tree-dump-times "map\\(struct:\\*this \\\[len: 2\\\]\\) map\\(alloc:this->a \\\[len: \[0-9\]+\\\]\\) map\\(alloc:this->b \\\[len: \[0-9\]+\\\]\\)" 4 "gimple" } } */ +/* { dg-final { scan-tree-dump-times "map\\(struct:\\*\\(struct S \\*\\) this \\\[len: 2\\\]\\) map\\(alloc:this->a \\\[len: \[0-9\]+\\\]\\) map\\(alloc:this->b \\\[len: \[0-9\]+\\\]\\)" 2 "gimple" } } */ + +/* { dg-final { scan-tree-dump-times "map\\(struct:\\*\\(struct T \\*\\) this \\\[len: 2\\\]\\) map\\(alloc:this->a \\\[len: \[0-9\]+\\\]\\) map\\(alloc:this->b \\\[len: \[0-9\]+\\\]\\)" 2 "gimple" } } */ diff --git a/gcc/testsuite/g++.dg/gomp/target-lambda-1.C b/gcc/testsuite/g++.dg/gomp/target-lambda-1.C index 150f286e312..bff7fa7c669 100644 --- a/gcc/testsuite/g++.dg/gomp/target-lambda-1.C +++ b/gcc/testsuite/g++.dg/gomp/target-lambda-1.C @@ -87,7 +87,7 @@ int main (void) return 0; } -/* { dg-final { scan-tree-dump {#pragma omp target num_teams.* firstprivate\(b\) map\(alloc:MEM.* \[len: 0\]\) map\(firstprivate:iptr \[pointer assign, bias: 0\]\) map\(alloc:MEM.* \[len: 0\]\) map\(firstprivate:this \[pointer assign, bias: 0\]\) map\(to:\*__closure \[len: [0-9]+\]\) map\(firstprivate:__closure \[pointer assign, bias: 0\]\) map\(struct:\*__closure \[len: 1\]\) map\(alloc:__closure->__this \[len: [0-9]+\]\) map\(tofrom:\*_[0-9]+ \[len: [0-9]+\]\) map\(always_pointer:__closure->__this \[pointer assign, bias: 0\]\) map\(from:mapped \[len: [0-9]+\]\) map\(alloc:\*_[0-9]+ \[len: 0\]\) map\(attach_zero_length_array_section:__closure->__iptr \[bias: 0\]\) map\(alloc:\*_[0-9]+ \[len: 0\]\) map\(attach_zero_length_array_section:_[0-9]+->ptr \[bias: 0\]\)} "gimple" } } */ +/* { dg-final { scan-tree-dump {#pragma omp target num_teams.* firstprivate\(b\) map\(alloc:MEM.* \[len: 0\]\) map\(firstprivate:iptr \[pointer assign, bias: 0\]\) map\(alloc:MEM.* \[len: 0\]\) map\(firstprivate:this \[pointer assign, bias: 0\]\) map\(to:\*__closure \[len: [0-9]+\]\) map\(firstprivate:__closure \[pointer assign, bias: 0\]\) map\(tofrom:\*_[0-9]+ \[len: [0-9]+\]\) map\(always_pointer:__closure->__this \[pointer assign, bias: 0\]\) map\(from:mapped \[len: [0-9]+\]\) map\(alloc:\*_[0-9]+ \[len: 0\]\) map\(attach_zero_length_array_section:__closure->__iptr \[bias: 0\]\) map\(alloc:\*_[0-9]+ \[len: 0\]\) map\(attach_zero_length_array_section:_[0-9]+->ptr \[bias: 0\]\)} "gimple" } } */ /* { dg-final { scan-tree-dump {#pragma omp target num_teams.* firstprivate\(end\) firstprivate\(begin\) map\(to:loop \[len: [0-9]+\]\) map\(alloc:\*_[0-9]+ \[len: 0\]\) map\(attach_zero_length_array_section:loop\.__data1 \[bias: 0\]\)} "gimple" } } */ diff --git a/gcc/testsuite/g++.dg/gomp/target-this-2.C b/gcc/testsuite/g++.dg/gomp/target-this-2.C index 8a76bb836f8..cc08e7e8693 100644 --- a/gcc/testsuite/g++.dg/gomp/target-this-2.C +++ b/gcc/testsuite/g++.dg/gomp/target-this-2.C @@ -46,4 +46,4 @@ int main (void) return 0; } -/* { dg-final { scan-tree-dump {#pragma omp target num_teams.* firstprivate\(n\) map\(alloc:MEM.* \[len: 0\]\) map\(firstprivate:this \[pointer assign, bias: 0\]\) firstprivate\(m\) map\(to:\*__closure \[len: [0-9]+\]\) map\(firstprivate:__closure \[pointer assign, bias: 0\]\) map\(tofrom:\*_[0-9]+ \[len: [0-9]+\]\) map\(always_pointer:__closure->__this \[pointer assign, bias: 0\]\) map\(from:v \[len: [0-9]+\]\)} "gimple" } } */ +/* { dg-final { scan-tree-dump {map\(alloc:MEM\[\(char \*\)_[0-9]+\] \[len: [0-9]+\]\) map\(firstprivate:this \[pointer assign, bias: 0\]\) firstprivate\(m\) map\(to:\*__closure \[len: [0-9]+\]\) map\(firstprivate:__closure \[pointer assign, bias: 0\]\) map\(tofrom:\*_[0-9]+ \[len: [0-9]+\]\) map\(always_pointer:__closure->__this \[pointer assign, bias: 0\]\) map\(from:v \[len: [0-9]+\]\)} "gimple" } } */ diff --git a/gcc/testsuite/g++.dg/gomp/target-this-4.C b/gcc/testsuite/g++.dg/gomp/target-this-4.C index 8166f43ad42..9ade3cc0b2b 100644 --- a/gcc/testsuite/g++.dg/gomp/target-this-4.C +++ b/gcc/testsuite/g++.dg/gomp/target-this-4.C @@ -102,6 +102,6 @@ int main (void) return 0; } -/* { dg-final { scan-tree-dump {#pragma omp target num_teams.* firstprivate\(n\) map\(alloc:MEM.* \[len: 0\]\) map\(firstprivate:this \[pointer assign, bias: 0\]\) map\(to:\*__closure \[len: [0-9]+\]\) map\(firstprivate:__closure \[pointer assign, bias: 0\]\) map\(struct:\*__closure \[len: 1\]\) map\(alloc:__closure->__this \[len: [0-9]+\]\) map\(tofrom:\*_[0-9]+ \[len: [0-9]+\]\) map\(always_pointer:__closure->__this \[pointer assign, bias: 0\]\) map\(from:mapped \[len: 1\]\) map\(alloc:\*_[0-9]+ \[len: 0\]\) map\(attach_zero_length_array_section:_[0-9]+->ptr \[bias: 0\]\)} "gimple" } } */ +/* { dg-final { scan-tree-dump {#pragma omp target num_teams.* firstprivate\(n\) map\(alloc:MEM.* \[len: 0\]\) map\(firstprivate:this \[pointer assign, bias: 0\]\) map\(to:\*__closure \[len: [0-9]+\]\) map\(firstprivate:__closure \[pointer assign, bias: 0\]\) map\(tofrom:\*_[0-9]+ \[len: [0-9]+\]\) map\(always_pointer:__closure->__this \[pointer assign, bias: 0\]\) map\(from:mapped \[len: 1\]\) map\(alloc:\*_[0-9]+ \[len: 0\]\) map\(attach_zero_length_array_section:_[0-9]+->ptr \[bias: 0\]\)} "gimple" } } */ -/* { dg-final { scan-tree-dump {#pragma omp target num_teams.* firstprivate\(n\) map\(alloc:MEM.* \[len: 0\]\) map\(firstprivate:this \[pointer assign, bias: 0\]\) map\(to:\*__closure \[len: [0-9]+\]\) map\(firstprivate:__closure \[pointer assign, bias: 0\]\) map\(struct:\*__closure \[len: 1\]\) map\(alloc:__closure->__this \[len: [0-9]+\]\) map\(tofrom:\*_[0-9]+ \[len: [0-9]+\]\) map\(always_pointer:__closure->__this \[pointer assign, bias: 0\]\) map\(from:mapped \[len: [0-9]+\]\) map\(alloc:\*_[0-9]+ \[len: 0\]\) map\(alloc:\*_[0-9]+ \[pointer assign, zero-length array section, bias: 0\]\) map\(attach:_[0-9]+->refptr \[bias: 0\]\)} "gimple" } } */ +/* { dg-final { scan-tree-dump {#pragma omp target num_teams.* firstprivate\(n\) map\(alloc:MEM.* \[len: 0\]\) map\(firstprivate:this \[pointer assign, bias: 0\]\) map\(to:\*__closure \[len: [0-9]+\]\) map\(firstprivate:__closure \[pointer assign, bias: 0\]\) map\(tofrom:\*_[0-9]+ \[len: [0-9]+\]\) map\(always_pointer:__closure->__this \[pointer assign, bias: 0\]\) map\(from:mapped \[len: [0-9]+\]\) map\(alloc:\*_[0-9]+ \[len: 0\]\) map\(alloc:\*_[0-9]+ \[pointer assign, zero-length array section, bias: 0\]\) map\(attach:_[0-9]+->refptr \[bias: 0\]\)} "gimple" } } */ From patchwork Thu Nov 25 14:08:43 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Julian Brown X-Patchwork-Id: 1559736 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=gcc.gnu.org (client-ip=8.43.85.97; helo=sourceware.org; envelope-from=gcc-patches-bounces+incoming=patchwork.ozlabs.org@gcc.gnu.org; receiver=) Received: from sourceware.org (server2.sourceware.org [8.43.85.97]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by bilbo.ozlabs.org (Postfix) with ESMTPS id 4J0KcV0qKsz9sVc for ; Fri, 26 Nov 2021 01:14:02 +1100 (AEDT) Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id D7460385BF81 for ; Thu, 25 Nov 2021 14:13:59 +0000 (GMT) X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from esa4.mentor.iphmx.com (esa4.mentor.iphmx.com [68.232.137.252]) by sourceware.org (Postfix) with ESMTPS id E8B283858424 for ; Thu, 25 Nov 2021 14:09:08 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org E8B283858424 Authentication-Results: sourceware.org; dmarc=none (p=none dis=none) header.from=codesourcery.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=mentor.com IronPort-SDR: 0zDhyCIABMIxlHFWNdsHR+SEPcdmup0IdDanR7Pp5Utyu9u1Xq4bhKmjii4tLztkKNUDn1Z93N zbkKlR+uAY15O3uqmRLLssvbOffQJJQlbiP4BZ+syHALfkj4RikKoBhuk8tSLPnqQCCrd68Gfb hwzTFw5a0A54tbh9cyERizGeleXeO1A509hID/YeQobZePxrrH/PsRi0q8Ys8Gsa0+P7Lit9lq bOXOygg6FCBMIuKZVOCPGgd5FnUbSy895XV4+jWxIQMhADENjglX9EkYWVWfS/J/4ldG2EF+XB +ZTdKHkTtfw60cV9ifBaXBr0 X-IronPort-AV: E=Sophos;i="5.87,263,1631606400"; d="scan'208";a="68932318" Received: from orw-gwy-02-in.mentorg.com ([192.94.38.167]) by esa4.mentor.iphmx.com with ESMTP; 25 Nov 2021 06:09:03 -0800 IronPort-SDR: Cy6/qvQQHJ17WWWjDBpr5t6hZsGT9C8be22WnZl5XuM8PDWVi2LWdy8mjTzSxlk+QXIB0S1OCC e/AOKD9z+hs/5XAolw2Xu9DbJlZoZ0eAuRKDTMgOxRF/a0YSc/4M4sgUj5XKzUe/hzMwSaqGzc xeq5Ko5OeJkDlMp2zzye1dMG8zM2DC2q2j4iS3kJJ7hf01P7QEA/tiFcJXHOLI0k1Q21j2le3R rdpCyFz2W2mkrkvTpsTQYfPxC/XzcTc2XQ+QQ//AY4V++zLS2siX9K1HYmPUYVdWVq8z+MyEsI q10= From: Julian Brown To: Subject: [PATCH 09/16] OpenMP: Allow array ref components for C & C++ Date: Thu, 25 Nov 2021 06:08:43 -0800 Message-ID: <20211125140843.111405-5-julian@codesourcery.com> X-Mailer: git-send-email 2.29.2 In-Reply-To: <20211125140843.111405-1-julian@codesourcery.com> References: <20211125140843.111405-1-julian@codesourcery.com> MIME-Version: 1.0 X-Originating-IP: [137.202.0.90] X-ClientProxiedBy: SVR-IES-MBX-08.mgc.mentorg.com (139.181.222.8) To SVR-IES-MBX-04.mgc.mentorg.com (139.181.222.4) X-Spam-Status: No, score=-11.8 required=5.0 tests=BAYES_00, GIT_PATCH_0, HEADER_FROM_DIFFERENT_DOMAINS, KAM_DMARC_STATUS, SPF_HELO_PASS, SPF_PASS, 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: , Cc: Jakub Jelinek , Thomas Schwinge Errors-To: gcc-patches-bounces+incoming=patchwork.ozlabs.org@gcc.gnu.org Sender: "Gcc-patches" This patch fixes parsing for struct components that are array references in OMP clauses in both the C and C++ front ends. OK? Thanks, Julian 2021-09-29 Julian Brown gcc/c/ * c-typeck.c (c_finish_omp_clauses): Allow ARRAY_REF components. gcc/cp/ * semantics.c (finish_omp_clauses): Allow ARRAY_REF components. --- gcc/c/c-typeck.c | 3 ++- gcc/cp/semantics.c | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/gcc/c/c-typeck.c b/gcc/c/c-typeck.c index ee6362d4274..4d156f6d3ec 100644 --- a/gcc/c/c-typeck.c +++ b/gcc/c/c-typeck.c @@ -14918,7 +14918,8 @@ c_finish_omp_clauses (tree clauses, enum c_omp_region_type ort) { t = TREE_OPERAND (t, 0); if (TREE_CODE (t) == MEM_REF - || TREE_CODE (t) == INDIRECT_REF) + || TREE_CODE (t) == INDIRECT_REF + || TREE_CODE (t) == ARRAY_REF) { t = TREE_OPERAND (t, 0); STRIP_NOPS (t); diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c index 50f95751d1c..e882c302f31 100644 --- a/gcc/cp/semantics.c +++ b/gcc/cp/semantics.c @@ -7910,7 +7910,8 @@ finish_omp_clauses (tree clauses, enum c_omp_region_type ort) if (REFERENCE_REF_P (t)) t = TREE_OPERAND (t, 0); if (TREE_CODE (t) == MEM_REF - || TREE_CODE (t) == INDIRECT_REF) + || TREE_CODE (t) == INDIRECT_REF + || TREE_CODE (t) == ARRAY_REF) { t = TREE_OPERAND (t, 0); STRIP_NOPS (t); From patchwork Thu Nov 25 14:10:09 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Julian Brown X-Patchwork-Id: 1559737 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=gcc.gnu.org (client-ip=8.43.85.97; helo=sourceware.org; envelope-from=gcc-patches-bounces+incoming=patchwork.ozlabs.org@gcc.gnu.org; receiver=) Received: from sourceware.org (server2.sourceware.org [8.43.85.97]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by bilbo.ozlabs.org (Postfix) with ESMTPS id 4J0Kf53mLfz9sVc for ; Fri, 26 Nov 2021 01:15:25 +1100 (AEDT) Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 51623385C40B for ; Thu, 25 Nov 2021 14:15:23 +0000 (GMT) X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from esa2.mentor.iphmx.com (esa2.mentor.iphmx.com [68.232.141.98]) by sourceware.org (Postfix) with ESMTPS id 810073857C56 for ; Thu, 25 Nov 2021 14:10:23 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org 810073857C56 Authentication-Results: sourceware.org; dmarc=none (p=none dis=none) header.from=codesourcery.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=mentor.com IronPort-SDR: n0YaoVga6K6zcfwDv4yacIDCq7JlM+ymzvceA4c69RytQJBSQ2yiVzUD5YkakF9D8lGE98DG55 mVgFlnrMCuCdTxarL9iX4QdusA6Lhpft0JD2tpeoGaVtGGflfzkMZ6/PlTR2t8D55kQ6jZxF17 Yf1DpZfTRfvb/wcQKd5Sx+7OGPw8zx2xTaPG7JgDoCFzanteHr/WJ16nUC33PjW0BipZDMyYeI YPvzNc27T6z92/sdn44mxppKfMLg2Ie+4bWH6faoX85NmtfAaJgHJMAJRnuSZV6I704TJYyEO4 EQnh/UMOC0Rm+XVCmWgUsOtK X-IronPort-AV: E=Sophos;i="5.87,263,1631606400"; d="scan'208";a="68920866" Received: from orw-gwy-02-in.mentorg.com ([192.94.38.167]) by esa2.mentor.iphmx.com with ESMTP; 25 Nov 2021 06:10:22 -0800 IronPort-SDR: i9AzXoZ45NUBQrNmgGOpDhdvotj+ZPWgPmgwNzPphqJQ3YHS0grcNf5+vO3bO+/fJ79K02ksEF o8jBOayfVBm8UBG6VDDaWc6gXFlY9s0X8ipSo0+LV0/K6fBjaMhYNcd491givGP4XUvrk8ypL+ GldoMdbiwJwWTLNMxqHi5D9iS96oNF7r3cLBYHSKXDu1OqMFKMsrIos3xzICS/3MGMblzsf7WR HmAhukUVxNkUR8WF5MZQep5oSjC/sjiMOH2M8tfwQ6PW0MdkuViSmF4N+ERqFSTQMJpCDCl97C DII= From: Julian Brown To: Subject: [PATCH 10/16] OpenMP: Fix non-zero attach/detach bias for struct dereferences Date: Thu, 25 Nov 2021 06:10:09 -0800 Message-ID: <20211125141013.113782-1-julian@codesourcery.com> X-Mailer: git-send-email 2.29.2 MIME-Version: 1.0 X-Originating-IP: [137.202.0.90] X-ClientProxiedBy: svr-ies-mbx-15.mgc.mentorg.com (139.181.222.15) To SVR-IES-MBX-04.mgc.mentorg.com (139.181.222.4) X-Spam-Status: No, score=-11.8 required=5.0 tests=BAYES_00, GIT_PATCH_0, HEADER_FROM_DIFFERENT_DOMAINS, KAM_DMARC_STATUS, SPF_HELO_PASS, SPF_PASS, 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: , Cc: Jakub Jelinek , Thomas Schwinge Errors-To: gcc-patches-bounces+incoming=patchwork.ozlabs.org@gcc.gnu.org Sender: "Gcc-patches" This patch fixes attach/detach operations for OpenMP that have a non-zero bias: these can occur if we have a mapping such as: #pragma omp target map(mystruct->a.b[idx].c[:arrsz]) i.e. where there is an offset between the attachment point ("mystruct" here) and the pointed-to data. (The "b" and "c" members would be array types here, not pointers themselves). In this example the difference (thus bias encoded in the attach/detach node) will be something like: (uintptr_t) &mystruct->a.b[idx].c[0] - (uintptr_t) &mystruct->a OK? Thanks, Julian 2021-09-29 Julian Brown gcc/c-family/ * c-common.h (c_omp_decompose_attachable_address): Add prototype. * c-omp.c (c_omp_decompose_attachable_address): New function. gcc/c/ * c-typeck.c (handle_omp_array_sections): Handle attach/detach for struct dereferences with non-zero bias. gcc/cp/ * semantics.c (handle_omp_array_section): Handle attach/detach for struct dereferences with non-zero bias. libgomp/ * testsuite/libgomp.c++/baseptrs-3.C: Add test (XFAILed for now). * testsuite/libgomp.c-c++-common/baseptrs-1.c: Add test. * testsuite/libgomp.c-c++-common/baseptrs-2.c: Add test. --- gcc/c-family/c-common.h | 1 + gcc/c-family/c-omp.c | 42 ++++ gcc/c/c-typeck.c | 12 +- gcc/cp/semantics.c | 14 +- libgomp/testsuite/libgomp.c++/baseptrs-3.C | 182 ++++++++++++++++++ .../libgomp.c-c++-common/baseptrs-1.c | 50 +++++ .../libgomp.c-c++-common/baseptrs-2.c | 70 +++++++ 7 files changed, 364 insertions(+), 7 deletions(-) create mode 100644 libgomp/testsuite/libgomp.c++/baseptrs-3.C create mode 100644 libgomp/testsuite/libgomp.c-c++-common/baseptrs-1.c create mode 100644 libgomp/testsuite/libgomp.c-c++-common/baseptrs-2.c diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h index d5dad99ff97..dd103d8eecd 100644 --- a/gcc/c-family/c-common.h +++ b/gcc/c-family/c-common.h @@ -1251,6 +1251,7 @@ extern tree c_omp_check_context_selector (location_t, tree); extern void c_omp_mark_declare_variant (location_t, tree, tree); extern const char *c_omp_map_clause_name (tree, bool); extern void c_omp_adjust_map_clauses (tree, bool); +extern tree c_omp_decompose_attachable_address (tree t, tree *virtbase); enum c_omp_directive_kind { C_OMP_DIR_STANDALONE, diff --git a/gcc/c-family/c-omp.c b/gcc/c-family/c-omp.c index 3f84fd1b5cb..a90696fe706 100644 --- a/gcc/c-family/c-omp.c +++ b/gcc/c-family/c-omp.c @@ -3113,6 +3113,48 @@ c_omp_adjust_map_clauses (tree clauses, bool is_target) } } +tree +c_omp_decompose_attachable_address (tree t, tree *virtbase) +{ + *virtbase = t; + + /* It's already a pointer. Just use that. */ + if (POINTER_TYPE_P (TREE_TYPE (t))) + return NULL_TREE; + + /* Otherwise, look for a base pointer deeper within the expression. */ + + while (TREE_CODE (t) == COMPONENT_REF + && (TREE_CODE (TREE_OPERAND (t, 0)) == COMPONENT_REF + || TREE_CODE (TREE_OPERAND (t, 0)) == ARRAY_REF)) + { + t = TREE_OPERAND (t, 0); + while (TREE_CODE (t) == ARRAY_REF) + t = TREE_OPERAND (t, 0); + } + + + *virtbase = t; + + if (TREE_CODE (t) != COMPONENT_REF) + return NULL_TREE; + + t = TREE_OPERAND (t, 0); + + tree attach_pt = NULL_TREE; + + if ((TREE_CODE (t) == INDIRECT_REF + || TREE_CODE (t) == MEM_REF) + && TREE_CODE (TREE_TYPE (TREE_OPERAND (t, 0))) == POINTER_TYPE) + { + attach_pt = TREE_OPERAND (t, 0); + if (TREE_CODE (attach_pt) == POINTER_PLUS_EXPR) + attach_pt = TREE_OPERAND (attach_pt, 0); + } + + return attach_pt; +} + static const struct c_omp_directive omp_directives[] = { /* Keep this alphabetically sorted by the first word. Non-null second/third if any should precede null ones. */ diff --git a/gcc/c/c-typeck.c b/gcc/c/c-typeck.c index 4d156f6d3ec..cfac7d0a2b5 100644 --- a/gcc/c/c-typeck.c +++ b/gcc/c/c-typeck.c @@ -13799,9 +13799,15 @@ handle_omp_array_sections (tree c, enum c_omp_region_type ort) if (size) size = c_fully_fold (size, false, NULL); OMP_CLAUSE_SIZE (c) = size; + tree virtbase = t; + tree attach_pt + = ((ort != C_ORT_ACC) + ? c_omp_decompose_attachable_address (t, &virtbase) + : NULL_TREE); if (OMP_CLAUSE_CODE (c) != OMP_CLAUSE_MAP || (TREE_CODE (t) == COMPONENT_REF - && TREE_CODE (TREE_TYPE (t)) == ARRAY_TYPE)) + && TREE_CODE (TREE_TYPE (t)) == ARRAY_TYPE + && !attach_pt)) return false; gcc_assert (OMP_CLAUSE_MAP_KIND (c) != GOMP_MAP_FORCE_DEVICEPTR); switch (OMP_CLAUSE_MAP_KIND (c)) @@ -13834,10 +13840,10 @@ handle_omp_array_sections (tree c, enum c_omp_region_type ort) if (OMP_CLAUSE_MAP_KIND (c2) != GOMP_MAP_FIRSTPRIVATE_POINTER && !c_mark_addressable (t)) return false; - OMP_CLAUSE_DECL (c2) = t; + OMP_CLAUSE_DECL (c2) = attach_pt ? attach_pt : t; t = build_fold_addr_expr (first); t = fold_convert_loc (OMP_CLAUSE_LOCATION (c), ptrdiff_type_node, t); - tree ptr = OMP_CLAUSE_DECL (c2); + tree ptr = virtbase; if (!POINTER_TYPE_P (TREE_TYPE (ptr))) ptr = build_fold_addr_expr (ptr); t = fold_build2_loc (OMP_CLAUSE_LOCATION (c), MINUS_EXPR, diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c index e882c302f31..068c0c69e58 100644 --- a/gcc/cp/semantics.c +++ b/gcc/cp/semantics.c @@ -5620,9 +5620,16 @@ handle_omp_array_sections (tree c, enum c_omp_region_type ort) OMP_CLAUSE_SIZE (c) = size; if (TREE_CODE (t) == FIELD_DECL) t = finish_non_static_data_member (t, NULL_TREE, NULL_TREE); + + tree virtbase = t; + tree attach_pt + = ((ort != C_ORT_ACC) + ? c_omp_decompose_attachable_address (t, &virtbase) + : NULL_TREE); if (OMP_CLAUSE_CODE (c) != OMP_CLAUSE_MAP || (TREE_CODE (t) == COMPONENT_REF - && TREE_CODE (TREE_TYPE (t)) == ARRAY_TYPE)) + && TREE_CODE (TREE_TYPE (t)) == ARRAY_TYPE + && !attach_pt)) return false; switch (OMP_CLAUSE_MAP_KIND (c)) { @@ -5684,12 +5691,11 @@ handle_omp_array_sections (tree c, enum c_omp_region_type ort) if (OMP_CLAUSE_MAP_KIND (c2) != GOMP_MAP_FIRSTPRIVATE_POINTER && !cxx_mark_addressable (t)) return false; - OMP_CLAUSE_DECL (c2) = t; + OMP_CLAUSE_DECL (c2) = attach_pt ? attach_pt : t; t = build_fold_addr_expr (first); t = fold_convert_loc (OMP_CLAUSE_LOCATION (c), ptrdiff_type_node, t); - tree ptr = OMP_CLAUSE_DECL (c2); - ptr = convert_from_reference (ptr); + tree ptr = convert_from_reference (virtbase); if (!INDIRECT_TYPE_P (TREE_TYPE (ptr))) ptr = build_fold_addr_expr (ptr); t = fold_build2_loc (OMP_CLAUSE_LOCATION (c), MINUS_EXPR, diff --git a/libgomp/testsuite/libgomp.c++/baseptrs-3.C b/libgomp/testsuite/libgomp.c++/baseptrs-3.C new file mode 100644 index 00000000000..cabeb7c2b7a --- /dev/null +++ b/libgomp/testsuite/libgomp.c++/baseptrs-3.C @@ -0,0 +1,182 @@ +/* { dg-xfail-if "fails to parse correctly" { *-*-* } } */ + +#include +#include +#include + +struct sa +{ + int *ptr; +}; + +struct sb +{ + int arr[10]; +}; + +struct sc +{ + sa &a; + sb &b; + sc (sa &my_a, sb &my_b) : a(my_a), b(my_b) {} +}; + +void +foo () +{ + sa my_a; + sb my_b; + + my_a.ptr = (int *) malloc (sizeof (int) * 10); + sc my_c(my_a, my_b); + + memset (my_c.a.ptr, 0, sizeof (int) * 10); + + #pragma omp target map (my_c.a.ptr, my_c.a.ptr[:10]) + { + for (int i = 0; i < 10; i++) + my_c.a.ptr[i] = i; + } + + for (int i = 0; i < 10; i++) + assert (my_c.a.ptr[i] == i); + + memset (my_c.b.arr, 0, sizeof (int) * 10); + + #pragma omp target map (my_c.b.arr[:10]) + { + for (int i = 0; i < 10; i++) + my_c.b.arr[i] = i; + } + + for (int i = 0; i < 10; i++) + assert (my_c.b.arr[i] == i); + + free (my_a.ptr); +} + +void +bar () +{ + sa my_a; + sb my_b; + + my_a.ptr = (int *) malloc (sizeof (int) * 10); + sc my_c(my_a, my_b); + sc &my_cref = my_c; + + memset (my_cref.a.ptr, 0, sizeof (int) * 10); + + #pragma omp target map (my_cref.a.ptr, my_cref.a.ptr[:10]) + { + for (int i = 0; i < 10; i++) + my_cref.a.ptr[i] = i; + } + + for (int i = 0; i < 10; i++) + assert (my_cref.a.ptr[i] == i); + + memset (my_cref.b.arr, 0, sizeof (int) * 10); + + #pragma omp target map (my_cref.b.arr[:10]) + { + for (int i = 0; i < 10; i++) + my_cref.b.arr[i] = i; + } + + for (int i = 0; i < 10; i++) + assert (my_cref.b.arr[i] == i); + + free (my_a.ptr); +} + +struct scp +{ + sa *&a; + sb *&b; + scp (sa *&my_a, sb *&my_b) : a(my_a), b(my_b) {} +}; + +void +foop () +{ + sa *my_a = new sa; + sb *my_b = new sb; + + my_a->ptr = new int[10]; + scp *my_c = new scp(my_a, my_b); + + memset (my_c->a->ptr, 0, sizeof (int) * 10); + + #pragma omp target map (my_c->a->ptr, my_c->a->ptr[:10]) + { + for (int i = 0; i < 10; i++) + my_c->a->ptr[i] = i; + } + + for (int i = 0; i < 10; i++) + assert (my_c->a->ptr[i] == i); + + memset (my_c->b->arr, 0, sizeof (int) * 10); + +/* FIXME: This currently ICEs. */ +/* #pragma omp target map (my_c->b->arr[:10]) */ + { + for (int i = 0; i < 10; i++) + my_c->b->arr[i] = i; + } + + for (int i = 0; i < 10; i++) + assert (my_c->b->arr[i] == i); + + delete[] my_a->ptr; + delete my_a; + delete my_b; +} + +void +barp () +{ + sa *my_a = new sa; + sb *my_b = new sb; + + my_a->ptr = new int[10]; + scp *my_c = new scp(my_a, my_b); + scp *&my_cref = my_c; + + memset (my_cref->a->ptr, 0, sizeof (int) * 10); + + #pragma omp target map (my_cref->a->ptr, my_cref->a->ptr[:10]) + { + for (int i = 0; i < 10; i++) + my_cref->a->ptr[i] = i; + } + + for (int i = 0; i < 10; i++) + assert (my_cref->a->ptr[i] == i); + + memset (my_cref->b->arr, 0, sizeof (int) * 10); + +/* FIXME: This currently ICEs. */ +/* #pragma omp target map (my_cref->b->arr[:10]) */ + { + for (int i = 0; i < 10; i++) + my_cref->b->arr[i] = i; + } + + for (int i = 0; i < 10; i++) + assert (my_cref->b->arr[i] == i); + + delete my_a->ptr; + delete my_a; + delete my_b; +} + +int main (int argc, char *argv[]) +{ + foo (); + bar (); + foop (); + barp (); + return 0; +} diff --git a/libgomp/testsuite/libgomp.c-c++-common/baseptrs-1.c b/libgomp/testsuite/libgomp.c-c++-common/baseptrs-1.c new file mode 100644 index 00000000000..073615625b7 --- /dev/null +++ b/libgomp/testsuite/libgomp.c-c++-common/baseptrs-1.c @@ -0,0 +1,50 @@ +#include +#include +#include +#include + +#define N 32 + +typedef struct { + int x2[10][N]; +} x1type; + +typedef struct { + x1type x1[10]; +} p2type; + +typedef struct { + p2type *p2; +} p1type; + +typedef struct { + p1type *p1; +} x0type; + +typedef struct { + x0type x0[10]; +} p0type; + +int main(int argc, char *argv[]) +{ + p0type *p0; + int k1 = 0, k2 = 0, k3 = 0, n = N; + + p0 = (p0type *) malloc (sizeof *p0); + p0->x0[0].p1 = (p1type *) malloc (sizeof *p0->x0[0].p1); + p0->x0[0].p1->p2 = (p2type *) malloc (sizeof *p0->x0[0].p1->p2); + memset (p0->x0[0].p1->p2, 0, sizeof *p0->x0[0].p1->p2); + +#pragma omp target map(tofrom: p0->x0[k1].p1->p2[k2].x1[k3].x2[4][0:n]) \ + map(to: p0->x0[k1].p1, p0->x0[k1].p1->p2) \ + map(to: p0->x0[k1].p1[0]) + { + for (int i = 0; i < n; i++) + p0->x0[k1].p1->p2[k2].x1[k3].x2[4][i] = i; + } + + for (int i = 0; i < n; i++) + assert (i == p0->x0[k1].p1->p2[k2].x1[k3].x2[4][i]); + + return 0; +} diff --git a/libgomp/testsuite/libgomp.c-c++-common/baseptrs-2.c b/libgomp/testsuite/libgomp.c-c++-common/baseptrs-2.c new file mode 100644 index 00000000000..e335d7da966 --- /dev/null +++ b/libgomp/testsuite/libgomp.c-c++-common/baseptrs-2.c @@ -0,0 +1,70 @@ +#include +#include +#include + +#define N 32 + +typedef struct { + int arr[N]; + int *ptr; +} sc; + +typedef struct { + sc *c; +} sb; + +typedef struct { + sb *b; + sc *c; +} sa; + +int main (int argc, char *argv[]) +{ + sa *p; + + p = (sa *) malloc (sizeof *p); + p->b = (sb *) malloc (sizeof *p->b); + p->b->c = (sc *) malloc (sizeof *p->b->c); + p->c = (sc *) malloc (sizeof *p->c); + p->b->c->ptr = (int *) malloc (N * sizeof (int)); + p->c->ptr = (int *) malloc (N * sizeof (int)); + + for (int i = 0; i < N; i++) + { + p->b->c->ptr[i] = 0; + p->c->ptr[i] = 0; + p->b->c->arr[i] = 0; + p->c->arr[i] = 0; + } + +#pragma omp target map(to: p->b, p->b[0], p->c, p->c[0], p->b->c, p->b->c[0]) \ + map(to: p->b->c->ptr, p->c->ptr) \ + map(tofrom: p->b->c->ptr[:N], p->c->ptr[:N]) + { + for (int i = 0; i < N; i++) + { + p->b->c->ptr[i] = i; + p->c->ptr[i] = i * 2; + } + } + +#pragma omp target map(to: p->b, p->b[0], p->b->c, p->c) \ + map(tofrom: p->c[0], p->b->c[0]) + { + for (int i = 0; i < N; i++) + { + p->b->c->arr[i] = i * 3; + p->c->arr[i] = i * 4; + } + } + + for (int i = 0; i < N; i++) + { + assert (p->b->c->ptr[i] == i); + assert (p->c->ptr[i] == i * 2); + assert (p->b->c->arr[i] == i * 3); + assert (p->c->arr[i] == i * 4); + } + + return 0; +} From patchwork Thu Nov 25 14:10:10 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Julian Brown X-Patchwork-Id: 1559739 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=gcc.gnu.org (client-ip=2620:52:3:1:0:246e:9693:128c; helo=sourceware.org; envelope-from=gcc-patches-bounces+incoming=patchwork.ozlabs.org@gcc.gnu.org; receiver=) Received: from sourceware.org (server2.sourceware.org [IPv6:2620:52:3:1:0:246e:9693:128c]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by bilbo.ozlabs.org (Postfix) with ESMTPS id 4J0KgD4z7vz9sVc for ; Fri, 26 Nov 2021 01:16:24 +1100 (AEDT) Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 953E6385BF93 for ; Thu, 25 Nov 2021 14:16:22 +0000 (GMT) X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from esa2.mentor.iphmx.com (esa2.mentor.iphmx.com [68.232.141.98]) by sourceware.org (Postfix) with ESMTPS id 4DD353858418 for ; Thu, 25 Nov 2021 14:10:26 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org 4DD353858418 Authentication-Results: sourceware.org; dmarc=none (p=none dis=none) header.from=codesourcery.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=mentor.com IronPort-SDR: wBJ/a52EEZT8Ni1dk1PXUhTaAErLf1lb29iGuleYsdPRYpkYELPxGG9IRblJt30orWWuHl0HQr atbXyLuvuimxUbR6kFUki44D51NCpqr18ghiV7Gi89PN4c9ITvw26dnDOURQMTOMeYBPEGQoTF /Vs4PmoBNdU8UjCkhLePUjuj5KuH0fKwBCTXcw6Bo5PEDshQfnoKhxegvc1EPPPSh0OrJNubLs oMOZKoBinBlqEyzDhlKgiuaewy+Ga8XbQ7ST5T0XgOQEIf48YLfhVyd3W4RSnhzZPvmhh2FCoR nXn58iqwpCrW3+zOc4cgnx7n X-IronPort-AV: E=Sophos;i="5.87,263,1631606400"; d="scan'208";a="68920868" Received: from orw-gwy-02-in.mentorg.com ([192.94.38.167]) by esa2.mentor.iphmx.com with ESMTP; 25 Nov 2021 06:10:24 -0800 IronPort-SDR: sY3cS4w4izBwGPZx1Bze33jCalBwK52uAf1co3QUVtTXyjAuekWoUAchj8jwgPzLHJPNoqBfD7 gWexIY0rryCjE6BmEbCvMA2zuGq7MduryB5Rb3d3XqDiSKrYs0YM/TGkfINvDkAZVnjun8nBwE ZisrdYVhA43dF0cEyj1ycvvzLLnS5VX6K/0LrZlEs9BYIrXCGUKwLydk4SwcI702Ly1/gplpDC b/RGgM1CPWPCfww/QYEnpvRM5qfzTYPTPFXUmxSJg+jHMDdHXfAvzMPbF6icLltxhWLax8wrAT nsA= From: Julian Brown To: Subject: [PATCH 11/16] OpenMP: Handle reference-typed struct members Date: Thu, 25 Nov 2021 06:10:10 -0800 Message-ID: <20211125141013.113782-2-julian@codesourcery.com> X-Mailer: git-send-email 2.29.2 In-Reply-To: <20211125141013.113782-1-julian@codesourcery.com> References: <20211125141013.113782-1-julian@codesourcery.com> MIME-Version: 1.0 X-Originating-IP: [137.202.0.90] X-ClientProxiedBy: svr-ies-mbx-15.mgc.mentorg.com (139.181.222.15) To SVR-IES-MBX-04.mgc.mentorg.com (139.181.222.4) X-Spam-Status: No, score=-11.8 required=5.0 tests=BAYES_00, GIT_PATCH_0, HEADER_FROM_DIFFERENT_DOMAINS, KAM_DMARC_STATUS, KAM_SHORT, SPF_HELO_PASS, SPF_PASS, 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: , Cc: Jakub Jelinek , Thomas Schwinge Errors-To: gcc-patches-bounces+incoming=patchwork.ozlabs.org@gcc.gnu.org Sender: "Gcc-patches" This patch fixes the baseptrs-3.C test case introduced in the patch: https://gcc.gnu.org/pipermail/gcc-patches/2021-October/580729.html The problematic case concerns OpenMP mapping clauses containing struct members of reference type, e.g. "mystruct.myref.myptr[:N]". To be able to access the array slice through the reference in the middle, we need to perform an attach action for that reference, since it is represented internally as a pointer. I don't think the spec allows for this case explicitly. The closest clause is (OpenMP 5.0, "2.19.7.1 map Clause"): "If the type of a list item is a reference to a type T then the reference in the device data environment is initialized to refer to the object in the device data environment that corresponds to the object referenced by the list item. If mapping occurs, it occurs as though the object were mapped through a pointer with an array section of type T and length one." The patch as is allows the mapping to work with just "mystruct.myref.myptr[:N]", without an explicit "mystruct.myref" mapping also (because, would that refer to the hidden pointer used by the reference, or the automatically-dereferenced data itself?). An attach/detach operation is thus synthesised for the reference. OK? Thanks, Julian 2021-10-11 Julian Brown gcc/cp/ * semantics.c (finish_omp_clauses): Handle reference-typed members. gcc/ * gimplify.c (build_struct_group): Arrange for attach/detach nodes to be created for reference-typed struct members for OpenMP. Only create firstprivate_pointer/firstprivate_reference nodes for innermost struct accesses, those with an optionally-indirected DECL_P base. (omp_build_struct_sibling_lists): Handle two-element chain for inner struct component returned from build_struct_group. libgomp/ * testsuite/libgomp.c++/baseptrs-3.C: Remove XFAILs and extend test. --- gcc/cp/semantics.c | 4 + gcc/gimplify.c | 56 +++++++++-- libgomp/testsuite/libgomp.c++/baseptrs-3.C | 109 +++++++++++++++++++-- 3 files changed, 154 insertions(+), 15 deletions(-) diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c index 068c0c69e58..6d30a9ed97d 100644 --- a/gcc/cp/semantics.c +++ b/gcc/cp/semantics.c @@ -7923,6 +7923,8 @@ finish_omp_clauses (tree clauses, enum c_omp_region_type ort) STRIP_NOPS (t); if (TREE_CODE (t) == POINTER_PLUS_EXPR) t = TREE_OPERAND (t, 0); + if (REFERENCE_REF_P (t)) + t = TREE_OPERAND (t, 0); } } while (TREE_CODE (t) == COMPONENT_REF); @@ -8021,6 +8023,8 @@ finish_omp_clauses (tree clauses, enum c_omp_region_type ort) { t = TREE_OPERAND (TREE_OPERAND (t, 0), 0); indir_component_ref_p = true; + if (REFERENCE_REF_P (t)) + t = TREE_OPERAND (t, 0); STRIP_NOPS (t); if (TREE_CODE (t) == POINTER_PLUS_EXPR) t = TREE_OPERAND (t, 0); diff --git a/gcc/gimplify.c b/gcc/gimplify.c index 56f0aaaf979..8f07da8a991 100644 --- a/gcc/gimplify.c +++ b/gcc/gimplify.c @@ -9802,7 +9802,10 @@ build_struct_group (enum omp_region_type region_type, enum tree_code code, /* FIXME: If we're not mapping the base pointer in some other clause on this directive, I think we want to create ALLOC/RELEASE here -- i.e. not early-exit. */ - if (openmp && attach_detach) + if (openmp + && attach_detach + && !(TREE_CODE (TREE_TYPE (ocd)) == REFERENCE_TYPE + && TREE_CODE (TREE_TYPE (TREE_TYPE (ocd))) != POINTER_TYPE)) return NULL; if (!struct_map_to_clause || struct_map_to_clause->get (base) == NULL) @@ -9851,9 +9854,32 @@ build_struct_group (enum omp_region_type region_type, enum tree_code code, tree noind = strip_indirections (base); - if (!openmp + if (openmp + && TREE_CODE (TREE_TYPE (noind)) == REFERENCE_TYPE && (region_type & ORT_TARGET) && TREE_CODE (noind) == COMPONENT_REF) + { + tree c2 = build_omp_clause (OMP_CLAUSE_LOCATION (grp_end), + OMP_CLAUSE_MAP); + OMP_CLAUSE_SET_MAP_KIND (c2, GOMP_MAP_TO); + OMP_CLAUSE_DECL (c2) = unshare_expr (base); + OMP_CLAUSE_SIZE (c2) = TYPE_SIZE_UNIT (TREE_TYPE (noind)); + + tree c3 = build_omp_clause (OMP_CLAUSE_LOCATION (grp_end), + OMP_CLAUSE_MAP); + OMP_CLAUSE_SET_MAP_KIND (c3, GOMP_MAP_ATTACH_DETACH); + OMP_CLAUSE_DECL (c3) = unshare_expr (noind); + OMP_CLAUSE_SIZE (c3) = size_zero_node; + + OMP_CLAUSE_CHAIN (c2) = c3; + OMP_CLAUSE_CHAIN (c3) = NULL_TREE; + + *inner = c2; + return NULL; + } + else if (!openmp + && (region_type & ORT_TARGET) + && TREE_CODE (noind) == COMPONENT_REF) { /* The base for this component access is a struct component access itself. Insert a node to be processed on the next iteration of @@ -9867,13 +9893,30 @@ build_struct_group (enum omp_region_type region_type, enum tree_code code, OMP_CLAUSE_SET_MAP_KIND (c2, GOMP_MAP_FORCE_PRESENT); OMP_CLAUSE_DECL (c2) = unshare_expr (noind); OMP_CLAUSE_SIZE (c2) = TYPE_SIZE_UNIT (TREE_TYPE (noind)); + OMP_CLAUSE_CHAIN (c2) = NULL_TREE; *inner = c2; return NULL; } - tree sdecl = strip_components_and_deref (base); + tree sdecl = base; + /* There are too many places we need to do things like this. */ + if (TREE_CODE (sdecl) == INDIRECT_REF + || TREE_CODE (sdecl) == MEM_REF) + { + sdecl = TREE_OPERAND (sdecl, 0); + if (TREE_CODE (sdecl) == INDIRECT_REF + && (TREE_CODE (TREE_TYPE (TREE_OPERAND (sdecl, 0))) + == REFERENCE_TYPE)) + sdecl = TREE_OPERAND (sdecl, 0); + } - if (POINTER_TYPE_P (TREE_TYPE (sdecl)) && (region_type & ORT_TARGET)) + while (TREE_CODE (sdecl) == COMPONENT_REF + || TREE_CODE (sdecl) == POINTER_PLUS_EXPR) + sdecl = TREE_OPERAND (sdecl, 0); + + if (DECL_P (sdecl) + && POINTER_TYPE_P (TREE_TYPE (sdecl)) + && (region_type & ORT_TARGET)) { tree c2 = build_omp_clause (OMP_CLAUSE_LOCATION (grp_end), OMP_CLAUSE_MAP); @@ -10212,11 +10255,10 @@ omp_build_struct_sibling_lists (enum tree_code code, else *tail = inner; - OMP_CLAUSE_CHAIN (inner) = NULL_TREE; - omp_mapping_group newgrp; newgrp.grp_start = new_next ? new_next : tail; - newgrp.grp_end = inner; + newgrp.grp_end = (OMP_CLAUSE_CHAIN (inner) + ? OMP_CLAUSE_CHAIN (inner) : inner); newgrp.mark = UNVISITED; newgrp.sibling = NULL; newgrp.next = NULL; diff --git a/libgomp/testsuite/libgomp.c++/baseptrs-3.C b/libgomp/testsuite/libgomp.c++/baseptrs-3.C index cabeb7c2b7a..39a48a40920 100644 --- a/libgomp/testsuite/libgomp.c++/baseptrs-3.C +++ b/libgomp/testsuite/libgomp.c++/baseptrs-3.C @@ -1,9 +1,58 @@ -/* { dg-xfail-if "fails to parse correctly" { *-*-* } } */ - #include #include #include +struct sa0 +{ + int *ptr; +}; + +struct sb0 +{ + int arr[10]; +}; + +struct sc0 +{ + sa0 a; + sb0 b; + sc0 (sa0 &my_a, sb0 &my_b) : a(my_a), b(my_b) {} +}; + +void +foo0 () +{ + sa0 my_a; + sb0 my_b; + + my_a.ptr = (int *) malloc (sizeof (int) * 10); + sc0 my_c(my_a, my_b); + + memset (my_c.a.ptr, 0, sizeof (int) * 10); + + #pragma omp target map (my_c.a.ptr, my_c.a.ptr[:10]) + { + for (int i = 0; i < 10; i++) + my_c.a.ptr[i] = i; + } + + for (int i = 0; i < 10; i++) + assert (my_c.a.ptr[i] == i); + + memset (my_c.b.arr, 0, sizeof (int) * 10); + + #pragma omp target map (my_c.b.arr[:10]) + { + for (int i = 0; i < 10; i++) + my_c.b.arr[i] = i; + } + + for (int i = 0; i < 10; i++) + assert (my_c.b.arr[i] == i); + + free (my_a.ptr); +} + struct sa { int *ptr; @@ -90,6 +139,49 @@ bar () free (my_a.ptr); } +struct scp0 +{ + sa *a; + sb *b; + scp0 (sa *my_a, sb *my_b) : a(my_a), b(my_b) {} +}; + +void +foop0 () +{ + sa *my_a = new sa; + sb *my_b = new sb; + + my_a->ptr = new int[10]; + scp0 *my_c = new scp0(my_a, my_b); + + memset (my_c->a->ptr, 0, sizeof (int) * 10); + + #pragma omp target map (my_c->a, my_c->a[:1], my_c->a->ptr, my_c->a->ptr[:10]) + { + for (int i = 0; i < 10; i++) + my_c->a->ptr[i] = i; + } + + for (int i = 0; i < 10; i++) + assert (my_c->a->ptr[i] == i); + + memset (my_c->b->arr, 0, sizeof (int) * 10); + + #pragma omp target map (my_c->b, my_c->b[:1], my_c->b->arr[:10]) + { + for (int i = 0; i < 10; i++) + my_c->b->arr[i] = i; + } + + for (int i = 0; i < 10; i++) + assert (my_c->b->arr[i] == i); + + delete[] my_a->ptr; + delete my_a; + delete my_b; +} + struct scp { sa *&a; @@ -108,7 +200,7 @@ foop () memset (my_c->a->ptr, 0, sizeof (int) * 10); - #pragma omp target map (my_c->a->ptr, my_c->a->ptr[:10]) + #pragma omp target map (my_c->a, my_c->a[:1], my_c->a->ptr, my_c->a->ptr[:10]) { for (int i = 0; i < 10; i++) my_c->a->ptr[i] = i; @@ -119,8 +211,7 @@ foop () memset (my_c->b->arr, 0, sizeof (int) * 10); -/* FIXME: This currently ICEs. */ -/* #pragma omp target map (my_c->b->arr[:10]) */ + #pragma omp target map (my_c->b, my_c->b[:1], my_c->b->arr[:10]) { for (int i = 0; i < 10; i++) my_c->b->arr[i] = i; @@ -146,7 +237,8 @@ barp () memset (my_cref->a->ptr, 0, sizeof (int) * 10); - #pragma omp target map (my_cref->a->ptr, my_cref->a->ptr[:10]) + #pragma omp target map (my_cref->a, my_cref->a[:1], my_cref->a->ptr, \ + my_cref->a->ptr[:10]) { for (int i = 0; i < 10; i++) my_cref->a->ptr[i] = i; @@ -157,8 +249,7 @@ barp () memset (my_cref->b->arr, 0, sizeof (int) * 10); -/* FIXME: This currently ICEs. */ -/* #pragma omp target map (my_cref->b->arr[:10]) */ + #pragma omp target map (my_cref->b, my_cref->b[:1], my_cref->b->arr[:10]) { for (int i = 0; i < 10; i++) my_cref->b->arr[i] = i; @@ -174,8 +265,10 @@ barp () int main (int argc, char *argv[]) { + foo0 (); foo (); bar (); + foop0 (); foop (); barp (); return 0; From patchwork Thu Nov 25 14:10:11 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Julian Brown X-Patchwork-Id: 1559738 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=gcc.gnu.org (client-ip=2620:52:3:1:0:246e:9693:128c; helo=sourceware.org; envelope-from=gcc-patches-bounces+incoming=patchwork.ozlabs.org@gcc.gnu.org; receiver=) Received: from sourceware.org (server2.sourceware.org [IPv6:2620:52:3:1:0:246e:9693:128c]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by bilbo.ozlabs.org (Postfix) with ESMTPS id 4J0Kff6tKnz9sVc for ; Fri, 26 Nov 2021 01:15:54 +1100 (AEDT) Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id D4AB5385AC38 for ; Thu, 25 Nov 2021 14:15:52 +0000 (GMT) X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from esa2.mentor.iphmx.com (esa2.mentor.iphmx.com [68.232.141.98]) by sourceware.org (Postfix) with ESMTPS id 6B3253857C56 for ; Thu, 25 Nov 2021 14:10:26 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org 6B3253857C56 Authentication-Results: sourceware.org; dmarc=none (p=none dis=none) header.from=codesourcery.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=mentor.com IronPort-SDR: Fow0oYugO1V3ccemKnn344gdx7YlQ4iHbYx4gTP+Qk8z7YFj/j95Gsnkd02YHJkKB9q/WIoyVo TTDLxcmLqK0d+Wb0FaJVjUazfWvU+xCcIziR3QUt8LWlYJ5nAsZMR5amiLWMWC/bKpGG4Gg3jb 0nd7jZIqSxWi9cKGTQZ/0c1Crh8XgViMx7qeGctG8rvTfupGjA4QneRXzvYIzNSzen3LBy6iy1 NwQ2nn/laMwcGPewxK+gxf486smoZzePeAunR8N+9g05n+3S9Qg9ZhmIpk/LN8qnlAhIi0l8q7 c9YLPQOY+cDQYwkfy/SNt0Rc X-IronPort-AV: E=Sophos;i="5.87,263,1631606400"; d="scan'208";a="68920869" Received: from orw-gwy-02-in.mentorg.com ([192.94.38.167]) by esa2.mentor.iphmx.com with ESMTP; 25 Nov 2021 06:10:25 -0800 IronPort-SDR: 7w9qsvmn0+prCoYSv1egJfSAZrszMQGfOm7d6Z3t8Lqx7E7rMz5Pl4lbxBHtu0KTmV43U+baoj 5DofdQNCto41polk7hl6+WSK3UuBSrGVwG1LO6bJj6HvXPrM6z3pYlHlo6qAoHQ51JgN6kM9At TKZ59hc3W3GKrqFsG35ZmrcEdtjZ1YuF6uIMWEjZv/geKKrliJJzZqkHbS6zia93Ss9j2KTIHX g2SIhdIoMUBhjcJpC7av9C1iXFNLpgQ9qibS0Y98V9nwRfvN1CMWEOr3Tlhb0dIA0vLxdEBfk3 RzI= From: Julian Brown To: Subject: [PATCH 12/16] OpenACC: Make deep-copy-arrayofstruct.c a libgomp/runtime test Date: Thu, 25 Nov 2021 06:10:11 -0800 Message-ID: <20211125141013.113782-3-julian@codesourcery.com> X-Mailer: git-send-email 2.29.2 In-Reply-To: <20211125141013.113782-1-julian@codesourcery.com> References: <20211125141013.113782-1-julian@codesourcery.com> MIME-Version: 1.0 X-Originating-IP: [137.202.0.90] X-ClientProxiedBy: svr-ies-mbx-15.mgc.mentorg.com (139.181.222.15) To SVR-IES-MBX-04.mgc.mentorg.com (139.181.222.4) X-Spam-Status: No, score=-11.8 required=5.0 tests=BAYES_00, GIT_PATCH_0, HEADER_FROM_DIFFERENT_DOMAINS, KAM_DMARC_STATUS, SPF_HELO_PASS, SPF_PASS, 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: , Cc: Jakub Jelinek , Thomas Schwinge Errors-To: gcc-patches-bounces+incoming=patchwork.ozlabs.org@gcc.gnu.org Sender: "Gcc-patches" I noticed that the test in question now compiles properly, and in fact runs properly too. Thus it's more useful as a runtime test than a passing compilation test that otherwise doesn't do much. This patch moves it to libgomp. OK? Thanks, Julian 2021-10-11 Julian Brown gcc/testsuite/ * c-c++-common/goacc/deep-copy-arrayofstruct.c: Move test from here. libgomp/ * testsuite/libgomp.oacc-c-c++-common/deep-copy-arrayofstruct.c: Move test to here. --- .../libgomp.oacc-c-c++-common}/deep-copy-arrayofstruct.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename {gcc/testsuite/c-c++-common/goacc => libgomp/testsuite/libgomp.oacc-c-c++-common}/deep-copy-arrayofstruct.c (98%) diff --git a/gcc/testsuite/c-c++-common/goacc/deep-copy-arrayofstruct.c b/libgomp/testsuite/libgomp.oacc-c-c++-common/deep-copy-arrayofstruct.c similarity index 98% rename from gcc/testsuite/c-c++-common/goacc/deep-copy-arrayofstruct.c rename to libgomp/testsuite/libgomp.oacc-c-c++-common/deep-copy-arrayofstruct.c index 4247607b61c..a11c64749cc 100644 --- a/gcc/testsuite/c-c++-common/goacc/deep-copy-arrayofstruct.c +++ b/libgomp/testsuite/libgomp.oacc-c-c++-common/deep-copy-arrayofstruct.c @@ -1,4 +1,4 @@ -/* { dg-do compile } */ +/* { dg-do run } */ #include #include From patchwork Thu Nov 25 14:10:12 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Julian Brown X-Patchwork-Id: 1559740 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=gcc.gnu.org (client-ip=8.43.85.97; helo=sourceware.org; envelope-from=gcc-patches-bounces+incoming=patchwork.ozlabs.org@gcc.gnu.org; receiver=) Received: from sourceware.org (server2.sourceware.org [8.43.85.97]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by bilbo.ozlabs.org (Postfix) with ESMTPS id 4J0Kgw5Vtlz9sVc for ; Fri, 26 Nov 2021 01:17:00 +1100 (AEDT) Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 844AD385DC30 for ; Thu, 25 Nov 2021 14:16:58 +0000 (GMT) X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from esa2.mentor.iphmx.com (esa2.mentor.iphmx.com [68.232.141.98]) by sourceware.org (Postfix) with ESMTPS id 22A18385843A for ; Thu, 25 Nov 2021 14:10:31 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org 22A18385843A Authentication-Results: sourceware.org; dmarc=none (p=none dis=none) header.from=codesourcery.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=mentor.com IronPort-SDR: TPVUKMKvEJ5Felj2pS5vIDwn2DBSVc08hQWa/hPqrU2yQ0nsbEU8dlgLzBGR3HtVfHJxGoWrUZ nBanDzeDApGxyH54F3z5bhrvcNA/Q3A8vFyUNTbrjbnzYQGHPyOGEnky2rBW1VbGwCu1p/Dsdf jyA8y+Avh6q1u3sV9M9MYCoHmJGl3MIPGl/PBDaRlfJ3D/LQNNWZlQRPSR8cQlHmoplC7tXlg3 lJo4Tl1GjRsmQBPK+sasiaWy7rg8tim70bCrhUfN5iQxXRQfbY3w8CNNJi0YlXW7q+CZRLBzS1 da9rIM+S9i6oVVaiVV5EuXaz X-IronPort-AV: E=Sophos;i="5.87,263,1631606400"; d="scan'208";a="68920870" Received: from orw-gwy-02-in.mentorg.com ([192.94.38.167]) by esa2.mentor.iphmx.com with ESMTP; 25 Nov 2021 06:10:30 -0800 IronPort-SDR: gwMP/OKGfVWVrh5eisxntX5BTQJAO2Y5YlQEhuiyas87B2WX2wUWSVaJ6R3+VooBKURCGsZqaB 7FJFb8/Vson113iOagsmC6+eUYKHVLqFBqYlwfMTSwEeZlumKQ5Ic+Pyo4KfrPURBcc3JJQwMq 2U19RAOzfIIQqMonn4rBhEO5FkEY2Lylk59CsCP3Xu4zt8Byjk/AshJ3uBZV1l6niQI2qC+FcX DX/KozRhj4VLD9IXqsUvVYiqFk4Syu7GL5ULzvKL9kpWv8DEBDe43RfrE89ujqobeb3CRUAIDk rgk= From: Julian Brown To: Subject: [PATCH 13/16] Add debug_omp_expr Date: Thu, 25 Nov 2021 06:10:12 -0800 Message-ID: <20211125141013.113782-4-julian@codesourcery.com> X-Mailer: git-send-email 2.29.2 In-Reply-To: <20211125141013.113782-1-julian@codesourcery.com> References: <20211125141013.113782-1-julian@codesourcery.com> MIME-Version: 1.0 X-Originating-IP: [137.202.0.90] X-ClientProxiedBy: svr-ies-mbx-15.mgc.mentorg.com (139.181.222.15) To SVR-IES-MBX-04.mgc.mentorg.com (139.181.222.4) X-Spam-Status: No, score=-11.8 required=5.0 tests=BAYES_00, GIT_PATCH_0, HEADER_FROM_DIFFERENT_DOMAINS, KAM_DMARC_STATUS, SPF_HELO_PASS, SPF_PASS, 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: , Cc: Jakub Jelinek , Thomas Schwinge Errors-To: gcc-patches-bounces+incoming=patchwork.ozlabs.org@gcc.gnu.org Sender: "Gcc-patches" The C and C++ front-ends use a TREE_LIST as a 3-tuple representing an OpenMP array section, which tends to crash debug_generic_expr if one wants to print such an expression in the debugger. This little helper function works around that. We might want to adjust the representation of array sections to use the soon-to-be-introduced OMP_ARRAY_SECTION tree code throughout instead, at which point this patch will no longer be necessary. OK? Thanks, Julian 2021-11-15 Julian Brown gcc/ * tree-pretty-print.c (print_omp_expr, debug_omp_expr): New functions. * tree-pretty-print.h (debug_omp_expr): Add prototype. --- gcc/tree-pretty-print.c | 31 +++++++++++++++++++++++++++++++ gcc/tree-pretty-print.h | 1 + 2 files changed, 32 insertions(+) diff --git a/gcc/tree-pretty-print.c b/gcc/tree-pretty-print.c index a81ba401ef9..13b64fd52e1 100644 --- a/gcc/tree-pretty-print.c +++ b/gcc/tree-pretty-print.c @@ -103,6 +103,37 @@ debug_generic_stmt (tree t) fprintf (stderr, "\n"); } +static void +print_omp_expr (tree t) +{ + if (TREE_CODE (t) == TREE_LIST) + { + tree low = TREE_PURPOSE (t); + tree len = TREE_VALUE (t); + tree base = TREE_CHAIN (t); + if (TREE_CODE (base) == TREE_LIST) + print_omp_expr (base); + else + print_generic_expr (stderr, base, TDF_VOPS|TDF_MEMSYMS); + fprintf (stderr, "["); + if (low) + print_generic_expr (stderr, low, TDF_VOPS|TDF_MEMSYMS); + fprintf (stderr, ":"); + if (len) + print_generic_expr (stderr, len, TDF_VOPS|TDF_MEMSYMS); + fprintf (stderr, "]"); + } + else + print_generic_expr (stderr, t, TDF_VOPS|TDF_MEMSYMS); +} + +DEBUG_FUNCTION void +debug_omp_expr (tree t) +{ + print_omp_expr (t); + fprintf (stderr, "\n"); +} + /* Debugging function to print out a chain of trees . */ DEBUG_FUNCTION void diff --git a/gcc/tree-pretty-print.h b/gcc/tree-pretty-print.h index dacd256302b..bc910f9a1b1 100644 --- a/gcc/tree-pretty-print.h +++ b/gcc/tree-pretty-print.h @@ -33,6 +33,7 @@ along with GCC; see the file COPYING3. If not see extern void debug_generic_expr (tree); extern void debug_generic_stmt (tree); +extern void debug_omp_expr (tree); extern void debug_tree_chain (tree); extern void print_generic_decl (FILE *, tree, dump_flags_t); extern void print_generic_stmt (FILE *, tree, dump_flags_t = TDF_NONE); From patchwork Thu Nov 25 14:10:13 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Julian Brown X-Patchwork-Id: 1559741 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=gcc.gnu.org (client-ip=2620:52:3:1:0:246e:9693:128c; helo=sourceware.org; envelope-from=gcc-patches-bounces+incoming=patchwork.ozlabs.org@gcc.gnu.org; receiver=) Received: from sourceware.org (server2.sourceware.org [IPv6:2620:52:3:1:0:246e:9693:128c]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by bilbo.ozlabs.org (Postfix) with ESMTPS id 4J0KhV2wxwz9sVc for ; Fri, 26 Nov 2021 01:17:30 +1100 (AEDT) Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 0FD32385BC23 for ; Thu, 25 Nov 2021 14:17:28 +0000 (GMT) X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from esa2.mentor.iphmx.com (esa2.mentor.iphmx.com [68.232.141.98]) by sourceware.org (Postfix) with ESMTPS id 46A4C385803B for ; Thu, 25 Nov 2021 14:10:33 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org 46A4C385803B Authentication-Results: sourceware.org; dmarc=none (p=none dis=none) header.from=codesourcery.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=mentor.com IronPort-SDR: gQb0DTOAFNerhOvgMxNYG+M7GSTrgVNJdphYcZGDvVV1nS+afSE7PVNHkO3MQRGWwnOadSdkHt ZFckgDMN5OFNvpb8FaAsj7qEyTsjIZC9dCb7Pe5zWxZeNzOBcSPUD1Vy9tnZPi1DCL8EDD1HjY pUXQdIZj44oSd5PXfR3QV2PWiL3c3sqKyCKWWC4SFIsQMlb9MGOSBtHveVha2vqd5eFFCceDyQ ot4u8hDNo/iuZnd49a20Sg86DR3nnmxu8jaGmx+jmWmitz5I1EsDxlJrE2kAerKrE9sId68qmB zB/GarpDa6e1YgxcS/CWTyCF X-IronPort-AV: E=Sophos;i="5.87,263,1631606400"; d="scan'208";a="68920873" Received: from orw-gwy-02-in.mentorg.com ([192.94.38.167]) by esa2.mentor.iphmx.com with ESMTP; 25 Nov 2021 06:10:32 -0800 IronPort-SDR: FB+ZCkXF4KyO6BJCZu1ncOJGfbZIQWke/RK49Uw7Y6FAayqb12x/hnkHJ353NtTqdeURRvpSht eMxMXD9klBntSnEJi7VrVVDJp5SZ2a9STsfOgQ8p0tPzkVUWpAuUkDzs8EuQ7nJhmBeZB3RBXv cl89Ka9RCJbgaBQcjTftUzu1XFN3S+4F7aw0YtrnedB2mIl+3TYh6cHZs/xgeLsaI+ym4BfZA6 F80L7MBowaI54uk9+Fgzt0omN5wU0wdDZNIBvMRxgHkqpTn8o369YlcOSfDICe8hVnMBdLUjJD rnw= From: Julian Brown To: Subject: [PATCH 14/16] OpenMP: Add inspector class to unify mapped address analysis Date: Thu, 25 Nov 2021 06:10:13 -0800 Message-ID: <20211125141013.113782-5-julian@codesourcery.com> X-Mailer: git-send-email 2.29.2 In-Reply-To: <20211125141013.113782-1-julian@codesourcery.com> References: <20211125141013.113782-1-julian@codesourcery.com> MIME-Version: 1.0 X-Originating-IP: [137.202.0.90] X-ClientProxiedBy: svr-ies-mbx-15.mgc.mentorg.com (139.181.222.15) To SVR-IES-MBX-04.mgc.mentorg.com (139.181.222.4) X-Spam-Status: No, score=-11.8 required=5.0 tests=BAYES_00, GIT_PATCH_0, HEADER_FROM_DIFFERENT_DOMAINS, KAM_DMARC_STATUS, SPF_HELO_PASS, SPF_PASS, 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: , Cc: Jakub Jelinek , Thomas Schwinge Errors-To: gcc-patches-bounces+incoming=patchwork.ozlabs.org@gcc.gnu.org Sender: "Gcc-patches" Several places in the C and C++ front-ends dig through OpenMP addresses from "map" clauses (etc.) in order to determine whether they are component accesses that need "attach" operations, check duplicate mapping clauses, and so on. When we're extending support for more kinds of lvalues in map clauses, it seems helpful to bring these all into one place in order to keep all the analyses in sync, and to make it easier to reason about which kinds of expressions are supported. This patch introduces an "address inspector" class for that purpose, and adjusts the C and C++ front-ends to use it. (The adjacent "c_omp_decompose_attachable_address" function could also be moved into the address inspector class, perhaps. That's not been done yet.) OK? Thanks, Julian 2021-11-15 Julian Brown gcc/c-family/ * c-common.h (c_omp_address_inspector): New class. * c-omp.c (c_omp_address_inspector::init, c_omp_address_inspector::analyze_components, c_omp_address_inspector::map_supported_p, c_omp_address_inspector::mappable_type): New methods. gcc/c/ * c-typeck.c (handle_omp_array_sections_1, c_finish_omp_clauses): Use c_omp_address_inspector class. gcc/cp/ * semantics.c (cp_omp_address_inspector): New class, derived from c_omp_address_inspector. (handle_omp_array_sections_1): Use cp_omp_address_inspector class to analyze OpenMP map clause expressions. Support POINTER_PLUS_EXPR. (finish_omp_clauses): Likewise. Support some additional kinds of lvalues in map clauses. gcc/testsuite/ * g++.dg/gomp/unmappable-component-1.C: New test. --- gcc/c-family/c-common.h | 44 +++ gcc/c-family/c-omp.c | 147 ++++++++++ gcc/c/c-typeck.c | 198 +++----------- gcc/cp/semantics.c | 252 ++++++------------ .../g++.dg/gomp/unmappable-component-1.C | 21 ++ 5 files changed, 338 insertions(+), 324 deletions(-) create mode 100644 gcc/testsuite/g++.dg/gomp/unmappable-component-1.C diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h index dd103d8eecd..05d479e4d2f 100644 --- a/gcc/c-family/c-common.h +++ b/gcc/c-family/c-common.h @@ -1253,6 +1253,50 @@ extern const char *c_omp_map_clause_name (tree, bool); extern void c_omp_adjust_map_clauses (tree, bool); extern tree c_omp_decompose_attachable_address (tree t, tree *virtbase); +class c_omp_address_inspector +{ + tree clause; + tree orig; + tree deref_toplevel; + tree outer_virtual_base; + tree root_term; + bool component_access; + bool indirections; + int map_supported; + +protected: + virtual bool reference_ref_p (tree) { return false; } + virtual bool processing_template_decl_p () { return false; } + virtual bool mappable_type (tree t); + virtual void emit_unmappable_type_notes (tree) { } + +public: + c_omp_address_inspector (tree c, tree t) + : clause (c), orig (t), deref_toplevel (NULL_TREE), + outer_virtual_base (NULL_TREE), root_term (NULL_TREE), + component_access (false), indirections (false), map_supported (-1) + { } + + ~c_omp_address_inspector () {} + + virtual void init (); + + tree analyze_components (bool); + + tree get_deref_toplevel () { return deref_toplevel; } + tree get_outer_virtual_base () { return outer_virtual_base; } + tree get_root_term () { gcc_assert (root_term); return root_term; } + bool component_access_p () { return component_access; } + + bool indir_component_ref_p () + { + gcc_assert (!component_access || root_term != NULL_TREE); + return component_access && indirections; + } + + bool map_supported_p (); +}; + enum c_omp_directive_kind { C_OMP_DIR_STANDALONE, C_OMP_DIR_CONSTRUCT, diff --git a/gcc/c-family/c-omp.c b/gcc/c-family/c-omp.c index a90696fe706..5b2fbf6809b 100644 --- a/gcc/c-family/c-omp.c +++ b/gcc/c-family/c-omp.c @@ -3113,6 +3113,153 @@ c_omp_adjust_map_clauses (tree clauses, bool is_target) } } +/* This could just be done in the constructor, but we need to call the + subclass's version of reference_ref_p, etc. */ + +void +c_omp_address_inspector::init () +{ + tree t = orig; + + gcc_assert (TREE_CODE (t) != ARRAY_REF); + + /* We may have a reference-typed component access at the outermost level + that has had convert_from_reference called on it. Look through that + access. */ + if (reference_ref_p (t) + && TREE_CODE (TREE_OPERAND (t, 0)) == COMPONENT_REF) + { + t = TREE_OPERAND (t, 0); + deref_toplevel = t; + } + else + deref_toplevel = t; + + /* Strip off expression nodes that may enclose a COMPONENT_REF. Look through + references, but not indirections through pointers. */ + while (1) + { + if (TREE_CODE (t) == COMPOUND_EXPR) + { + t = TREE_OPERAND (t, 1); + STRIP_NOPS (t); + } + else if (TREE_CODE (t) == POINTER_PLUS_EXPR + || TREE_CODE (t) == SAVE_EXPR) + t = TREE_OPERAND (t, 0); + else if (reference_ref_p (t)) + t = TREE_OPERAND (t, 0); + else + break; + } + + outer_virtual_base = t; + + if (TREE_CODE (t) == COMPONENT_REF) + component_access = true; +} + +tree +c_omp_address_inspector::analyze_components (bool checking) +{ + if (root_term) + return root_term; + + gcc_assert (TREE_CODE (outer_virtual_base) == COMPONENT_REF); + + tree t = outer_virtual_base; + + if (checking + && TREE_CODE (TREE_OPERAND (t, 1)) == FIELD_DECL + && DECL_BIT_FIELD (TREE_OPERAND (t, 1))) + { + error_at (OMP_CLAUSE_LOCATION (clause), + "bit-field %qE in %qs clause", + t, omp_clause_code_name[OMP_CLAUSE_CODE (clause)]); + return error_mark_node; + } + else if (checking + && !processing_template_decl_p () + && !mappable_type (TREE_TYPE (t))) + { + error_at (OMP_CLAUSE_LOCATION (clause), + "%qE does not have a mappable type in %qs clause", + t, omp_clause_code_name[OMP_CLAUSE_CODE (clause)]); + emit_unmappable_type_notes (TREE_TYPE (t)); + return error_mark_node; + } + else if (checking && TREE_TYPE (t) && TYPE_ATOMIC (TREE_TYPE (t))) + { + error_at (OMP_CLAUSE_LOCATION (clause), + "%<_Atomic%> %qE in %qs clause", t, + omp_clause_code_name[OMP_CLAUSE_CODE (clause)]); + return error_mark_node; + } + + while (TREE_CODE (t) == COMPONENT_REF) + { + if (checking + && TREE_TYPE (TREE_OPERAND (t, 0)) + && TREE_CODE (TREE_TYPE (TREE_OPERAND (t, 0))) == UNION_TYPE) + { + error_at (OMP_CLAUSE_LOCATION (clause), + "%qE is a member of a union", t); + return error_mark_node; + } + t = TREE_OPERAND (t, 0); + while (TREE_CODE (t) == MEM_REF + || TREE_CODE (t) == INDIRECT_REF + || TREE_CODE (t) == ARRAY_REF) + { + if (TREE_CODE (t) == MEM_REF + || TREE_CODE (t) == INDIRECT_REF) + indirections = true; + t = TREE_OPERAND (t, 0); + STRIP_NOPS (t); + if (TREE_CODE (t) == POINTER_PLUS_EXPR) + t = TREE_OPERAND (t, 0); + } + } + + root_term = t; + + return t; +} + +bool +c_omp_address_inspector::map_supported_p () +{ + /* If we've already decided if the mapped address is supported, return + that. */ + if (map_supported != -1) + return map_supported; + + /* Get the innermost point recorded so far. */ + tree t = root_term ? root_term : outer_virtual_base; + + while (TREE_CODE (t) == INDIRECT_REF + || TREE_CODE (t) == MEM_REF + || TREE_CODE (t) == ARRAY_REF + || TREE_CODE (t) == COMPONENT_REF + || TREE_CODE (t) == COMPOUND_EXPR + || TREE_CODE (t) == SAVE_EXPR + || TREE_CODE (t) == POINTER_PLUS_EXPR) + if (TREE_CODE (t) == COMPOUND_EXPR) + t = TREE_OPERAND (t, 1); + else + t = TREE_OPERAND (t, 0); + + map_supported = DECL_P (t); + + return map_supported; +} + +bool +c_omp_address_inspector::mappable_type (tree t) +{ + return lang_hooks.types.omp_mappable_type (t); +} + tree c_omp_decompose_attachable_address (tree t, tree *virtbase) { diff --git a/gcc/c/c-typeck.c b/gcc/c/c-typeck.c index cfac7d0a2b5..3a9f129181b 100644 --- a/gcc/c/c-typeck.c +++ b/gcc/c/c-typeck.c @@ -13208,6 +13208,8 @@ handle_omp_array_sections_1 (tree c, tree t, vec &types, { if (error_operand_p (t)) return error_mark_node; + c_omp_address_inspector t_insp (c, t); + t_insp.init (); ret = t; if (OMP_CLAUSE_CODE (c) != OMP_CLAUSE_AFFINITY && OMP_CLAUSE_CODE (c) != OMP_CLAUSE_DEPEND @@ -13217,59 +13219,15 @@ handle_omp_array_sections_1 (tree c, tree t, vec &types, t, omp_clause_code_name[OMP_CLAUSE_CODE (c)]); return error_mark_node; } - while (TREE_CODE (t) == INDIRECT_REF) - { - t = TREE_OPERAND (t, 0); - STRIP_NOPS (t); - if (TREE_CODE (t) == POINTER_PLUS_EXPR) - t = TREE_OPERAND (t, 0); - } - while (TREE_CODE (t) == COMPOUND_EXPR) - { - t = TREE_OPERAND (t, 1); - STRIP_NOPS (t); - } - if (TREE_CODE (t) == COMPONENT_REF + if (t_insp.component_access_p () && (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_MAP || OMP_CLAUSE_CODE (c) == OMP_CLAUSE_TO || OMP_CLAUSE_CODE (c) == OMP_CLAUSE_FROM)) - { - if (DECL_BIT_FIELD (TREE_OPERAND (t, 1))) - { - error_at (OMP_CLAUSE_LOCATION (c), - "bit-field %qE in %qs clause", - t, omp_clause_code_name[OMP_CLAUSE_CODE (c)]); - return error_mark_node; - } - while (TREE_CODE (t) == COMPONENT_REF) - { - if (TREE_CODE (TREE_TYPE (TREE_OPERAND (t, 0))) == UNION_TYPE) - { - error_at (OMP_CLAUSE_LOCATION (c), - "%qE is a member of a union", t); - return error_mark_node; - } - t = TREE_OPERAND (t, 0); - while (TREE_CODE (t) == MEM_REF - || TREE_CODE (t) == INDIRECT_REF - || TREE_CODE (t) == ARRAY_REF) - { - t = TREE_OPERAND (t, 0); - STRIP_NOPS (t); - if (TREE_CODE (t) == POINTER_PLUS_EXPR) - t = TREE_OPERAND (t, 0); - } - if (ort == C_ORT_ACC && TREE_CODE (t) == MEM_REF) - { - if (maybe_ne (mem_ref_offset (t), 0)) - error_at (OMP_CLAUSE_LOCATION (c), - "cannot dereference %qE in %qs clause", t, - omp_clause_code_name[OMP_CLAUSE_CODE (c)]); - else - t = TREE_OPERAND (t, 0); - } - } - } + t = t_insp.analyze_components (true); + else + t = t_insp.get_outer_virtual_base (); + if (t == error_mark_node) + return error_mark_node; if (!VAR_P (t) && TREE_CODE (t) != PARM_DECL) { if (DECL_P (t)) @@ -14917,23 +14875,16 @@ c_finish_omp_clauses (tree clauses, enum c_omp_region_type ort) } while (TREE_CODE (t) == ARRAY_REF) t = TREE_OPERAND (t, 0); - if (TREE_CODE (t) == COMPONENT_REF - && TREE_CODE (TREE_TYPE (t)) == ARRAY_TYPE) + + c_omp_address_inspector t_insp (c, t); + t_insp.init (); + + tree ovb = t_insp.get_outer_virtual_base (); + + if (TREE_CODE (ovb) == COMPONENT_REF + && TREE_CODE (TREE_TYPE (ovb)) == ARRAY_TYPE) { - do - { - t = TREE_OPERAND (t, 0); - if (TREE_CODE (t) == MEM_REF - || TREE_CODE (t) == INDIRECT_REF - || TREE_CODE (t) == ARRAY_REF) - { - t = TREE_OPERAND (t, 0); - STRIP_NOPS (t); - if (TREE_CODE (t) == POINTER_PLUS_EXPR) - t = TREE_OPERAND (t, 0); - } - } - while (TREE_CODE (t) == COMPONENT_REF); + t = t_insp.analyze_components (false); if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_MAP && OMP_CLAUSE_MAP_IMPLICIT (c) @@ -15001,96 +14952,35 @@ c_finish_omp_clauses (tree clauses, enum c_omp_region_type ort) bias) to zero here, so it is not set erroneously to the pointer size later on in gimplify.c. */ OMP_CLAUSE_SIZE (c) = size_zero_node; - while (TREE_CODE (t) == INDIRECT_REF - || TREE_CODE (t) == ARRAY_REF) - { - t = TREE_OPERAND (t, 0); - STRIP_NOPS (t); - if (TREE_CODE (t) == POINTER_PLUS_EXPR) - t = TREE_OPERAND (t, 0); - } - while (TREE_CODE (t) == COMPOUND_EXPR) - { - t = TREE_OPERAND (t, 1); - STRIP_NOPS (t); - } - indir_component_ref_p = false; - if (TREE_CODE (t) == COMPONENT_REF - && (TREE_CODE (TREE_OPERAND (t, 0)) == MEM_REF - || TREE_CODE (TREE_OPERAND (t, 0)) == INDIRECT_REF - || TREE_CODE (TREE_OPERAND (t, 0)) == ARRAY_REF)) - { - t = TREE_OPERAND (TREE_OPERAND (t, 0), 0); - indir_component_ref_p = true; - STRIP_NOPS (t); - if (TREE_CODE (t) == POINTER_PLUS_EXPR) - t = TREE_OPERAND (t, 0); - } - if (TREE_CODE (t) == COMPONENT_REF - && OMP_CLAUSE_CODE (c) != OMP_CLAUSE__CACHE_) - { - if (DECL_BIT_FIELD (TREE_OPERAND (t, 1))) - { - error_at (OMP_CLAUSE_LOCATION (c), - "bit-field %qE in %qs clause", - t, omp_clause_code_name[OMP_CLAUSE_CODE (c)]); - remove = true; - } - else if (!lang_hooks.types.omp_mappable_type (TREE_TYPE (t))) - { - error_at (OMP_CLAUSE_LOCATION (c), - "%qE does not have a mappable type in %qs clause", - t, omp_clause_code_name[OMP_CLAUSE_CODE (c)]); - remove = true; - } - else if (TYPE_ATOMIC (TREE_TYPE (t))) - { - error_at (OMP_CLAUSE_LOCATION (c), - "%<_Atomic%> %qE in %qs clause", t, - omp_clause_code_name[OMP_CLAUSE_CODE (c)]); - remove = true; - } - while (TREE_CODE (t) == COMPONENT_REF) - { - if (TREE_CODE (TREE_TYPE (TREE_OPERAND (t, 0))) - == UNION_TYPE) - { - error_at (OMP_CLAUSE_LOCATION (c), - "%qE is a member of a union", t); - remove = true; - break; - } - t = TREE_OPERAND (t, 0); - if (TREE_CODE (t) == MEM_REF) - { - if (maybe_ne (mem_ref_offset (t), 0)) - error_at (OMP_CLAUSE_LOCATION (c), - "cannot dereference %qE in %qs clause", t, - omp_clause_code_name[OMP_CLAUSE_CODE (c)]); - else - t = TREE_OPERAND (t, 0); - } - while (TREE_CODE (t) == MEM_REF - || TREE_CODE (t) == INDIRECT_REF - || TREE_CODE (t) == ARRAY_REF) - { - t = TREE_OPERAND (t, 0); - STRIP_NOPS (t); - if (TREE_CODE (t) == POINTER_PLUS_EXPR) - t = TREE_OPERAND (t, 0); - } - } - if (remove) + { + c_omp_address_inspector t_insp (c, t); + t_insp.init (); + + if (t_insp.component_access_p () + && OMP_CLAUSE_CODE (c) != OMP_CLAUSE__CACHE_) + t = t_insp.analyze_components (true); + else + t = t_insp.get_outer_virtual_base (); + + if (t == error_mark_node) + { + remove = true; break; - if (VAR_P (t) || TREE_CODE (t) == PARM_DECL) - { - if (bitmap_bit_p (&map_field_head, DECL_UID (t)) - || (ort != C_ORT_ACC - && bitmap_bit_p (&map_head, DECL_UID (t)))) - break; - } - } + } + + indir_component_ref_p = t_insp.indir_component_ref_p (); + + if (t_insp.component_access_p () + && (VAR_P (t) || TREE_CODE (t) == PARM_DECL)) + { + if (bitmap_bit_p (&map_field_head, DECL_UID (t)) + || (ort != C_ORT_ACC + && bitmap_bit_p (&map_head, DECL_UID (t)))) + break; + } + } + if (!VAR_P (t) && TREE_CODE (t) != PARM_DECL) { error_at (OMP_CLAUSE_LOCATION (c), diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c index 6d30a9ed97d..a95eb1adcb5 100644 --- a/gcc/cp/semantics.c +++ b/gcc/cp/semantics.c @@ -4996,6 +4996,39 @@ omp_privatize_field (tree t, bool shared) return v; } +/* C++ specialisation of the c_omp_address_inspector class. */ + +class cp_omp_address_inspector : public c_omp_address_inspector +{ +protected: + bool reference_ref_p (tree t) + { + return REFERENCE_REF_P (t); + } + + bool processing_template_decl_p () + { + return processing_template_decl; + } + + bool mappable_type (tree t) + { + return cp_omp_mappable_type (t); + } + + void emit_unmappable_type_notes (tree t) + { + cp_omp_emit_unmappable_type_notes (t); + } + +public: + cp_omp_address_inspector (tree c, tree t) : c_omp_address_inspector (c, t) + { } + + ~cp_omp_address_inspector () + { } +}; + /* Helper function for handle_omp_array_sections. Called recursively to handle multiple array-section-subscripts. C is the clause, T current expression (initially OMP_CLAUSE_DECL), which is either @@ -5026,59 +5059,18 @@ handle_omp_array_sections_1 (tree c, tree t, vec &types, { if (error_operand_p (t)) return error_mark_node; - if (REFERENCE_REF_P (t) - && TREE_CODE (TREE_OPERAND (t, 0)) == COMPONENT_REF) - t = TREE_OPERAND (t, 0); - ret = t; - while (TREE_CODE (t) == INDIRECT_REF) - { - t = TREE_OPERAND (t, 0); - STRIP_NOPS (t); - if (TREE_CODE (t) == POINTER_PLUS_EXPR) - t = TREE_OPERAND (t, 0); - } - while (TREE_CODE (t) == COMPOUND_EXPR) - { - t = TREE_OPERAND (t, 1); - STRIP_NOPS (t); - } - if (TREE_CODE (t) == COMPONENT_REF + cp_omp_address_inspector t_insp (c, t); + t_insp.init (); + if (t_insp.component_access_p () && (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_MAP || OMP_CLAUSE_CODE (c) == OMP_CLAUSE_TO - || OMP_CLAUSE_CODE (c) == OMP_CLAUSE_FROM) - && !type_dependent_expression_p (t)) - { - if (TREE_CODE (TREE_OPERAND (t, 1)) == FIELD_DECL - && DECL_BIT_FIELD (TREE_OPERAND (t, 1))) - { - error_at (OMP_CLAUSE_LOCATION (c), - "bit-field %qE in %qs clause", - t, omp_clause_code_name[OMP_CLAUSE_CODE (c)]); - return error_mark_node; - } - while (TREE_CODE (t) == COMPONENT_REF) - { - if (TREE_TYPE (TREE_OPERAND (t, 0)) - && TREE_CODE (TREE_TYPE (TREE_OPERAND (t, 0))) == UNION_TYPE) - { - error_at (OMP_CLAUSE_LOCATION (c), - "%qE is a member of a union", t); - return error_mark_node; - } - t = TREE_OPERAND (t, 0); - while (TREE_CODE (t) == MEM_REF - || TREE_CODE (t) == INDIRECT_REF - || TREE_CODE (t) == ARRAY_REF) - { - t = TREE_OPERAND (t, 0); - STRIP_NOPS (t); - if (TREE_CODE (t) == POINTER_PLUS_EXPR) - t = TREE_OPERAND (t, 0); - } - } - if (REFERENCE_REF_P (t)) - t = TREE_OPERAND (t, 0); - } + || OMP_CLAUSE_CODE (c) == OMP_CLAUSE_FROM)) + t = t_insp.analyze_components (true); + else + t = t_insp.get_outer_virtual_base (); + if (t == error_mark_node) + return error_mark_node; + ret = t_insp.get_deref_toplevel (); if (TREE_CODE (t) == FIELD_DECL) ret = finish_non_static_data_member (t, NULL_TREE, NULL_TREE); else if (!VAR_P (t) && TREE_CODE (t) != PARM_DECL) @@ -7907,27 +7899,15 @@ finish_omp_clauses (tree clauses, enum c_omp_region_type ort) } while (TREE_CODE (t) == ARRAY_REF) t = TREE_OPERAND (t, 0); - if (TREE_CODE (t) == COMPONENT_REF - && TREE_CODE (TREE_TYPE (t)) == ARRAY_TYPE) + + cp_omp_address_inspector t_insp (c, t); + t_insp.init (); + tree ovb = t_insp.get_outer_virtual_base (); + + if (TREE_CODE (ovb) == COMPONENT_REF + && TREE_CODE (TREE_TYPE (ovb)) == ARRAY_TYPE) { - do - { - t = TREE_OPERAND (t, 0); - if (REFERENCE_REF_P (t)) - t = TREE_OPERAND (t, 0); - if (TREE_CODE (t) == MEM_REF - || TREE_CODE (t) == INDIRECT_REF - || TREE_CODE (t) == ARRAY_REF) - { - t = TREE_OPERAND (t, 0); - STRIP_NOPS (t); - if (TREE_CODE (t) == POINTER_PLUS_EXPR) - t = TREE_OPERAND (t, 0); - if (REFERENCE_REF_P (t)) - t = TREE_OPERAND (t, 0); - } - } - while (TREE_CODE (t) == COMPONENT_REF); + t = t_insp.analyze_components (false); if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_MAP && OMP_CLAUSE_MAP_IMPLICIT (c) @@ -7995,106 +7975,38 @@ finish_omp_clauses (tree clauses, enum c_omp_region_type ort) bias) to zero here, so it is not set erroneously to the pointer size later on in gimplify.c. */ OMP_CLAUSE_SIZE (c) = size_zero_node; - if (REFERENCE_REF_P (t) - && TREE_CODE (TREE_OPERAND (t, 0)) == COMPONENT_REF) - { - t = TREE_OPERAND (t, 0); - if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_MAP - && OMP_CLAUSE_MAP_KIND (c) != GOMP_MAP_ATTACH_DETACH) - OMP_CLAUSE_DECL (c) = t; - } - while (TREE_CODE (t) == INDIRECT_REF - || TREE_CODE (t) == ARRAY_REF) - { - t = TREE_OPERAND (t, 0); - STRIP_NOPS (t); - if (TREE_CODE (t) == POINTER_PLUS_EXPR) - t = TREE_OPERAND (t, 0); - } - while (TREE_CODE (t) == COMPOUND_EXPR) - { - t = TREE_OPERAND (t, 1); - STRIP_NOPS (t); - } - indir_component_ref_p = false; - if (TREE_CODE (t) == COMPONENT_REF - && (TREE_CODE (TREE_OPERAND (t, 0)) == INDIRECT_REF - || TREE_CODE (TREE_OPERAND (t, 0)) == ARRAY_REF)) - { - t = TREE_OPERAND (TREE_OPERAND (t, 0), 0); - indir_component_ref_p = true; - if (REFERENCE_REF_P (t)) - t = TREE_OPERAND (t, 0); - STRIP_NOPS (t); - if (TREE_CODE (t) == POINTER_PLUS_EXPR) - t = TREE_OPERAND (t, 0); - } - if (TREE_CODE (t) == COMPONENT_REF - && OMP_CLAUSE_CODE (c) != OMP_CLAUSE__CACHE_) - { - if (type_dependent_expression_p (t)) + + { + cp_omp_address_inspector t_insp (c, t); + t_insp.init (); + + if (t_insp.component_access_p () + && OMP_CLAUSE_CODE (c) != OMP_CLAUSE__CACHE_) + t = t_insp.analyze_components (true); + else + t = t_insp.get_outer_virtual_base (); + if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_MAP + && OMP_CLAUSE_MAP_KIND (c) != GOMP_MAP_ATTACH_DETACH) + OMP_CLAUSE_DECL (c) = t_insp.get_deref_toplevel (); + if (type_dependent_expression_p (t_insp.get_deref_toplevel ())) + break; + if (t == error_mark_node) + { + remove = true; break; - if (TREE_CODE (TREE_OPERAND (t, 1)) == FIELD_DECL - && DECL_BIT_FIELD (TREE_OPERAND (t, 1))) - { - error_at (OMP_CLAUSE_LOCATION (c), - "bit-field %qE in %qs clause", - t, omp_clause_code_name[OMP_CLAUSE_CODE (c)]); - remove = true; - } - else if (!cp_omp_mappable_type (TREE_TYPE (t))) - { - error_at (OMP_CLAUSE_LOCATION (c), - "%qE does not have a mappable type in %qs clause", - t, omp_clause_code_name[OMP_CLAUSE_CODE (c)]); - cp_omp_emit_unmappable_type_notes (TREE_TYPE (t)); - remove = true; - } - while (TREE_CODE (t) == COMPONENT_REF) - { - if (TREE_TYPE (TREE_OPERAND (t, 0)) - && (TREE_CODE (TREE_TYPE (TREE_OPERAND (t, 0))) - == UNION_TYPE)) - { - error_at (OMP_CLAUSE_LOCATION (c), - "%qE is a member of a union", t); - remove = true; - break; - } - t = TREE_OPERAND (t, 0); - if (TREE_CODE (t) == MEM_REF) - { - if (maybe_ne (mem_ref_offset (t), 0)) - error_at (OMP_CLAUSE_LOCATION (c), - "cannot dereference %qE in %qs clause", t, - omp_clause_code_name[OMP_CLAUSE_CODE (c)]); - else - t = TREE_OPERAND (t, 0); - } - while (TREE_CODE (t) == MEM_REF - || TREE_CODE (t) == INDIRECT_REF - || TREE_CODE (t) == ARRAY_REF) - { - t = TREE_OPERAND (t, 0); - STRIP_NOPS (t); - if (TREE_CODE (t) == POINTER_PLUS_EXPR) - t = TREE_OPERAND (t, 0); - } - } - if (remove) - break; - if (REFERENCE_REF_P (t)) - t = TREE_OPERAND (t, 0); - if (VAR_P (t) || TREE_CODE (t) == PARM_DECL) - { - if (bitmap_bit_p (&map_field_head, DECL_UID (t)) - || (ort != C_ORT_ACC - && bitmap_bit_p (&map_head, DECL_UID (t)))) - goto handle_map_references; - } - } - if (!processing_template_decl - && TREE_CODE (t) == FIELD_DECL) + } + indir_component_ref_p = t_insp.indir_component_ref_p (); + if (t_insp.component_access_p () + && (VAR_P (t) || TREE_CODE (t) == PARM_DECL)) + { + if (bitmap_bit_p (&map_field_head, DECL_UID (t)) + || (ort != C_ORT_ACC + && bitmap_bit_p (&map_head, DECL_UID (t)))) + goto handle_map_references; + } + } + + if (!processing_template_decl && TREE_CODE (t) == FIELD_DECL) { OMP_CLAUSE_DECL (c) = finish_non_static_data_member (t, NULL_TREE, NULL_TREE); diff --git a/gcc/testsuite/g++.dg/gomp/unmappable-component-1.C b/gcc/testsuite/g++.dg/gomp/unmappable-component-1.C new file mode 100644 index 00000000000..6fbc49616b1 --- /dev/null +++ b/gcc/testsuite/g++.dg/gomp/unmappable-component-1.C @@ -0,0 +1,21 @@ +/* { dg-do compile } */ + +struct A { + static int x[10]; +}; + +struct B { + A a; +}; + +int +main (int argc, char *argv[]) +{ + B *b = new B; +#pragma omp target map(b->a) // { dg-error "'b->B::a' does not have a mappable type in 'map' clause" } + ; + B bb; +#pragma omp target map(bb.a) // { dg-error "'bb\.B::a' does not have a mappable type in 'map' clause" } + ; + delete b; +} From patchwork Thu Nov 25 14:11:15 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Julian Brown X-Patchwork-Id: 1559743 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=gcc.gnu.org (client-ip=2620:52:3:1:0:246e:9693:128c; helo=sourceware.org; envelope-from=gcc-patches-bounces+incoming=patchwork.ozlabs.org@gcc.gnu.org; receiver=) Received: from sourceware.org (server2.sourceware.org [IPv6:2620:52:3:1:0:246e:9693:128c]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by bilbo.ozlabs.org (Postfix) with ESMTPS id 4J0Kjn1Qz6z9sVc for ; Fri, 26 Nov 2021 01:18:37 +1100 (AEDT) Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 1BDA4385E001 for ; Thu, 25 Nov 2021 14:18:35 +0000 (GMT) X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from esa2.mentor.iphmx.com (esa2.mentor.iphmx.com [68.232.141.98]) by sourceware.org (Postfix) with ESMTPS id 1333F3858419 for ; Thu, 25 Nov 2021 14:11:26 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org 1333F3858419 Authentication-Results: sourceware.org; dmarc=none (p=none dis=none) header.from=codesourcery.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=mentor.com IronPort-SDR: N+057FiGzbVMFbWcDDrd45tmWuU8zI3TTPAvOHIc8gW5u3bWFblCJWh7VEaksz+C0HkAPHhYcQ Z8oga8Y3Y5mqlkpb++sxrqMjB0vPUuqd6jaoU7yW+C7LRuA7Cu3Ro0IekxoOGgKs/3S4EgftFD qUY56Um524QQsUMC9nx1F2I3hdQcNjOnZjc0iy+PzWZIj2LEt5P+BVezW/a+jEfbAt4gUcXcoL nhdEuX0hkhbmppxoEHKJKZMAxpGT34UGpjOVG3ibamaDEEgc2QxEt/xca0fsp97LgUip/5jTHD rTugubA5u5jNnyPSXa5xoVB4 X-IronPort-AV: E=Sophos;i="5.87,263,1631606400"; d="scan'208";a="68920911" Received: from orw-gwy-02-in.mentorg.com ([192.94.38.167]) by esa2.mentor.iphmx.com with ESMTP; 25 Nov 2021 06:11:25 -0800 IronPort-SDR: AtX1m5Xa4atFZH7ZGXpn0yV7+a+mIFVc+5oj/Ovu4QvFNennUG+ngQ0dqeAQx0CPEtDad5nlae WTJj14MXbPPMdHeluRxRYeY74vDDckqYGHYgxgTvmsQP0gH8MxjSKFArNcxFnqckzGFuXW5k9B QlOUatEcAIUl83sO3Zxfj2EvpivmeHqUUKW8eHtdx0B6UxW/fOovwSQg/HHI2Q16NZapc7tOUC fm07cEh4vRwfKVE2YF0jlev20nAHy32THQu+y6VQeZufNx9jVPqwpcQipCx0q4+d17dBp6aMg8 W88= From: Julian Brown To: Subject: [PATCH 15/16] OpenMP: lvalue parsing for map clauses (C++) Date: Thu, 25 Nov 2021 06:11:15 -0800 Message-ID: <20211125141116.116128-1-julian@codesourcery.com> X-Mailer: git-send-email 2.29.2 MIME-Version: 1.0 X-Originating-IP: [137.202.0.90] X-ClientProxiedBy: svr-ies-mbx-13.mgc.mentorg.com (139.181.222.13) To SVR-IES-MBX-04.mgc.mentorg.com (139.181.222.4) X-Spam-Status: No, score=-11.9 required=5.0 tests=BAYES_00, GIT_PATCH_0, HEADER_FROM_DIFFERENT_DOMAINS, KAM_DMARC_STATUS, SPF_HELO_PASS, SPF_PASS, 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: , Cc: Jakub Jelinek , Thomas Schwinge Errors-To: gcc-patches-bounces+incoming=patchwork.ozlabs.org@gcc.gnu.org Sender: "Gcc-patches" This patch changes parsing for OpenMP map clauses in C++ to use the generic expression parser, hence adds support for parsing general lvalues (as required by OpenMP 5.0+). So far only a few new types of expression are actually supported throughout compilation (including everything in the testsuite of course, and newly-added tests), and we attempt to reject unsupported expressions in order to avoid surprises for the user. This version of the patch adds a number of additional tests for various expressions accepted as lvalues in C++, many of which are currently rejected as not yet supported -- and really only a handful of the rejected cases would be plausible in the context of an OpenMP "map" clause anyway, IMO. OK? Thanks, Julian 2021-11-24 Julian Brown gcc/c-family/ * c-omp.c (c_omp_decompose_attachable_address): Handle more types of expressions. gcc/cp/ * error.c (dump_expr): Handle OMP_ARRAY_SECTION. * parser.c (cp_parser_new): Initialize parser->omp_array_section_p. (cp_parser_postfix_open_square_expression): Support OMP_ARRAY_SECTION parsing. (cp_parser_omp_var_list_no_open): Remove ALLOW_DEREF parameter, add MAP_LVALUE in its place. Supported generalised lvalue parsing for map clauses. (cp_parser_omp_var_list): Remove ALLOW_DEREF parameter, add MAP_LVALUE. Pass to cp_parser_omp_var_list_no_open. (cp_parser_oacc_data_clause, cp_parser_omp_all_clauses): Update calls to cp_parser_omp_var_list. * parser.h (cp_parser): Add omp_array_section_p field. * semantics.c (handle_omp_array_sections_1): Handle more types of map expression. (handle_omp_array_section): Handle non-DECL_P attachment points. (finish_omp_clauses): Check for supported types of expression. gcc/ * gimplify.c (build_struct_group): Handle reference-typed component accesses. Fix support for non-DECL_P struct bases. (omp_build_struct_sibling_lists): Support length-two group for synthesized inner struct mapping. * tree-pretty-print.c (dump_generic_node): Support OMP_ARRAY_SECTION. * tree.def (OMP_ARRAY_SECTION): New tree code. gcc/testsuite/ * c-c++-common/gomp/map-6.c: Update expected output. * g++.dg/gomp/pr67522.C: Likewise. * g++.dg/gomp/ind-base-3.C: New test. * g++.dg/gomp/map-assignment-1.C: New test. * g++.dg/gomp/map-inc-1.C: New test. * g++.dg/gomp/map-lvalue-ref-1.C: New test. * g++.dg/gomp/map-ptrmem-1.C: New test. * g++.dg/gomp/map-ptrmem-2.C: New test. * g++.dg/gomp/map-static-cast-lvalue-1.C: New test. * g++.dg/gomp/map-ternary-1.C: New test. * g++.dg/gomp/member-array-2.C: New test. libgomp/ * testsuite/libgomp.c++/ind-base-1.C: New test. * testsuite/libgomp.c++/ind-base-2.C: New test. * testsuite/libgomp.c++/map-comma-1.C: New test. * testsuite/libgomp.c++/map-rvalue-ref-1.C: New test. * testsuite/libgomp.c++/member-array-1.C: New test. * testsuite/libgomp.c++/struct-ref-1.C: New test. --- gcc/c-family/c-omp.c | 25 ++- gcc/cp/error.c | 9 + gcc/cp/parser.c | 141 +++++++++++++-- gcc/cp/parser.h | 3 + gcc/cp/semantics.c | 35 +++- gcc/gimplify.c | 37 +++- gcc/testsuite/c-c++-common/gomp/map-6.c | 4 +- gcc/testsuite/g++.dg/gomp/ind-base-3.C | 38 ++++ gcc/testsuite/g++.dg/gomp/map-assignment-1.C | 12 ++ gcc/testsuite/g++.dg/gomp/map-inc-1.C | 10 ++ gcc/testsuite/g++.dg/gomp/map-lvalue-ref-1.C | 19 ++ gcc/testsuite/g++.dg/gomp/map-ptrmem-1.C | 36 ++++ gcc/testsuite/g++.dg/gomp/map-ptrmem-2.C | 39 +++++ .../g++.dg/gomp/map-static-cast-lvalue-1.C | 17 ++ gcc/testsuite/g++.dg/gomp/map-ternary-1.C | 20 +++ gcc/testsuite/g++.dg/gomp/member-array-2.C | 86 ++++++++++ gcc/testsuite/g++.dg/gomp/pr67522.C | 2 +- gcc/tree-pretty-print.c | 14 ++ gcc/tree.def | 3 + libgomp/testsuite/libgomp.c++/ind-base-1.C | 162 ++++++++++++++++++ libgomp/testsuite/libgomp.c++/ind-base-2.C | 49 ++++++ libgomp/testsuite/libgomp.c++/map-comma-1.C | 15 ++ .../testsuite/libgomp.c++/map-rvalue-ref-1.C | 22 +++ .../testsuite/libgomp.c++/member-array-1.C | 89 ++++++++++ libgomp/testsuite/libgomp.c++/struct-ref-1.C | 97 +++++++++++ 25 files changed, 956 insertions(+), 28 deletions(-) create mode 100644 gcc/testsuite/g++.dg/gomp/ind-base-3.C create mode 100644 gcc/testsuite/g++.dg/gomp/map-assignment-1.C create mode 100644 gcc/testsuite/g++.dg/gomp/map-inc-1.C create mode 100644 gcc/testsuite/g++.dg/gomp/map-lvalue-ref-1.C create mode 100644 gcc/testsuite/g++.dg/gomp/map-ptrmem-1.C create mode 100644 gcc/testsuite/g++.dg/gomp/map-ptrmem-2.C create mode 100644 gcc/testsuite/g++.dg/gomp/map-static-cast-lvalue-1.C create mode 100644 gcc/testsuite/g++.dg/gomp/map-ternary-1.C create mode 100644 gcc/testsuite/g++.dg/gomp/member-array-2.C create mode 100644 libgomp/testsuite/libgomp.c++/ind-base-1.C create mode 100644 libgomp/testsuite/libgomp.c++/ind-base-2.C create mode 100644 libgomp/testsuite/libgomp.c++/map-comma-1.C create mode 100644 libgomp/testsuite/libgomp.c++/map-rvalue-ref-1.C create mode 100644 libgomp/testsuite/libgomp.c++/member-array-1.C create mode 100644 libgomp/testsuite/libgomp.c++/struct-ref-1.C diff --git a/gcc/c-family/c-omp.c b/gcc/c-family/c-omp.c index 5b2fbf6809b..808688cac8c 100644 --- a/gcc/c-family/c-omp.c +++ b/gcc/c-family/c-omp.c @@ -3265,12 +3265,18 @@ c_omp_decompose_attachable_address (tree t, tree *virtbase) { *virtbase = t; - /* It's already a pointer. Just use that. */ - if (POINTER_TYPE_P (TREE_TYPE (t))) + /* It's already a non-offset pointer. Just use that. */ + if (POINTER_TYPE_P (TREE_TYPE (t)) + && (DECL_P (t) + || TREE_CODE (t) == COMPONENT_REF + || TREE_CODE (t) == ARRAY_REF)) return NULL_TREE; /* Otherwise, look for a base pointer deeper within the expression. */ + while (TREE_CODE (t) == COMPOUND_EXPR) + t = TREE_OPERAND (t, 1); + while (TREE_CODE (t) == COMPONENT_REF && (TREE_CODE (TREE_OPERAND (t, 0)) == COMPONENT_REF || TREE_CODE (TREE_OPERAND (t, 0)) == ARRAY_REF)) @@ -3280,9 +3286,24 @@ c_omp_decompose_attachable_address (tree t, tree *virtbase) t = TREE_OPERAND (t, 0); } + if (TREE_CODE (t) == POINTER_PLUS_EXPR) + { + t = TREE_OPERAND (t, 0); + if (TREE_CODE (t) == SAVE_EXPR) + t = TREE_OPERAND (t, 0); + } + + if (TREE_CODE (t) == INDIRECT_REF + && TREE_CODE (TREE_TYPE (TREE_OPERAND (t, 0))) == REFERENCE_TYPE) + t = TREE_OPERAND (t, 0); *virtbase = t; + /* If we have a pointer now (e.g. after we've stripped POINTER_PLUS_EXPR), + we have an offset pointer. That's the attachment point. */ + if (POINTER_TYPE_P (TREE_TYPE (t))) + return t; + if (TREE_CODE (t) != COMPONENT_REF) return NULL_TREE; diff --git a/gcc/cp/error.c b/gcc/cp/error.c index 012a4ecddf4..141c959d1bb 100644 --- a/gcc/cp/error.c +++ b/gcc/cp/error.c @@ -2415,6 +2415,15 @@ dump_expr (cxx_pretty_printer *pp, tree t, int flags) pp_cxx_right_bracket (pp); break; + case OMP_ARRAY_SECTION: + dump_expr (pp, TREE_OPERAND (t, 0), flags); + pp_cxx_left_bracket (pp); + dump_expr (pp, TREE_OPERAND (t, 1), flags); + pp_colon (pp); + dump_expr (pp, TREE_OPERAND (t, 2), flags); + pp_cxx_right_bracket (pp); + break; + case UNARY_PLUS_EXPR: dump_unary_op (pp, "+", t, flags); break; diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index ed047022c40..8954e50e065 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -4241,6 +4241,9 @@ cp_parser_new (cp_lexer *lexer) parser->omp_declare_simd = NULL; parser->oacc_routine = NULL; + /* Allow array slice in expression. */ + parser->omp_array_section_p = false; + /* Not declaring an implicit function template. */ parser->auto_is_implicit_function_template_parm_p = false; parser->fully_implicit_function_template_p = false; @@ -7901,6 +7904,7 @@ cp_parser_postfix_open_square_expression (cp_parser *parser, tree index = NULL_TREE; location_t loc = cp_lexer_peek_token (parser->lexer)->location; bool saved_greater_than_is_operator_p; + bool saved_colon_corrects_to_scope_p; /* Consume the `[' token. */ cp_lexer_consume_token (parser->lexer); @@ -7908,6 +7912,9 @@ cp_parser_postfix_open_square_expression (cp_parser *parser, saved_greater_than_is_operator_p = parser->greater_than_is_operator_p; parser->greater_than_is_operator_p = true; + saved_colon_corrects_to_scope_p = parser->colon_corrects_to_scope_p; + parser->colon_corrects_to_scope_p = false; + /* Parse the index expression. */ /* ??? For offsetof, there is a question of what to allow here. If offsetof is not being used in an integral constant expression context, @@ -7918,7 +7925,8 @@ cp_parser_postfix_open_square_expression (cp_parser *parser, constant expressions here. */ if (for_offsetof) index = cp_parser_constant_expression (parser); - else + else if (!parser->omp_array_section_p + || cp_lexer_next_token_is_not (parser->lexer, CPP_COLON)) { if (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_BRACE)) { @@ -7935,6 +7943,32 @@ cp_parser_postfix_open_square_expression (cp_parser *parser, parser->greater_than_is_operator_p = saved_greater_than_is_operator_p; + if (parser->omp_array_section_p + && cp_lexer_next_token_is (parser->lexer, CPP_COLON)) + { + cp_lexer_consume_token (parser->lexer); + tree length = NULL_TREE; + if (cp_lexer_next_token_is_not (parser->lexer, CPP_CLOSE_SQUARE)) + length = cp_parser_expression (parser); + + parser->colon_corrects_to_scope_p = saved_colon_corrects_to_scope_p; + + if ((index && error_operand_p (index)) + || (length && error_operand_p (length))) + return error_mark_node; + + cp_parser_require (parser, CPP_CLOSE_SQUARE, RT_CLOSE_SQUARE); + + /* NOTE: We are reusing using the type of the whole array as the type of + the array section here, which isn't necessarily entirely correct. + Might need revisiting. */ + return build3_loc (input_location, OMP_ARRAY_SECTION, + TREE_TYPE (postfix_expression), + postfix_expression, index, length); + } + + parser->colon_corrects_to_scope_p = saved_colon_corrects_to_scope_p; + /* Look for the closing `]'. */ cp_parser_require (parser, CPP_CLOSE_SQUARE, RT_CLOSE_SQUARE); @@ -36335,7 +36369,7 @@ struct omp_dim static tree cp_parser_omp_var_list_no_open (cp_parser *parser, enum omp_clause_code kind, tree list, bool *colon, - bool allow_deref = false) + bool map_lvalue = false) { auto_vec dims; bool array_section_p; @@ -36346,12 +36380,95 @@ cp_parser_omp_var_list_no_open (cp_parser *parser, enum omp_clause_code kind, parser->colon_corrects_to_scope_p = false; *colon = false; } + begin_scope (sk_omp, NULL); while (1) { tree name, decl; if (kind == OMP_CLAUSE_DEPEND || kind == OMP_CLAUSE_AFFINITY) cp_parser_parse_tentatively (parser); + else if (map_lvalue && kind == OMP_CLAUSE_MAP) + { + auto s = make_temp_override (parser->omp_array_section_p, true); + token = cp_lexer_peek_token (parser->lexer); + location_t loc = token->location; + decl = cp_parser_assignment_expression (parser); + + dims.truncate (0); + if (TREE_CODE (decl) == OMP_ARRAY_SECTION) + { + while (TREE_CODE (decl) == OMP_ARRAY_SECTION) + { + tree low_bound = TREE_OPERAND (decl, 1); + tree length = TREE_OPERAND (decl, 2); + dims.safe_push (omp_dim (low_bound, length, loc, false)); + decl = TREE_OPERAND (decl, 0); + } + + while (TREE_CODE (decl) == ARRAY_REF + || TREE_CODE (decl) == INDIRECT_REF + || TREE_CODE (decl) == COMPOUND_EXPR) + { + if (REFERENCE_REF_P (decl)) + break; + + if (TREE_CODE (decl) == COMPOUND_EXPR) + { + decl = TREE_OPERAND (decl, 1); + STRIP_NOPS (decl); + } + else if (TREE_CODE (decl) == INDIRECT_REF) + { + dims.safe_push (omp_dim (integer_zero_node, + integer_one_node, loc, true)); + decl = TREE_OPERAND (decl, 0); + } + else /* ARRAY_REF. */ + { + tree index = TREE_OPERAND (decl, 1); + dims.safe_push (omp_dim (index, integer_one_node, loc, + true)); + decl = TREE_OPERAND (decl, 0); + } + } + + /* Bare references have their own special handling, so remove + the explicit dereference added by convert_from_reference. */ + if (REFERENCE_REF_P (decl)) + decl = TREE_OPERAND (decl, 0); + + for (int i = dims.length () - 1; i >= 0; i--) + decl = tree_cons (dims[i].low_bound, dims[i].length, decl); + } + else if (TREE_CODE (decl) == INDIRECT_REF) + { + bool ref_p = REFERENCE_REF_P (decl); + + /* Turn *foo into the representation previously used for + foo[0]. */ + decl = TREE_OPERAND (decl, 0); + STRIP_NOPS (decl); + + /* ...but don't add the [0:1] representation for references + (because they have special handling elsewhere). */ + if (!ref_p) + decl = tree_cons (integer_zero_node, integer_one_node, decl); + } + else if (TREE_CODE (decl) == ARRAY_REF) + { + tree idx = TREE_OPERAND (decl, 1); + + decl = TREE_OPERAND (decl, 0); + STRIP_NOPS (decl); + + decl = tree_cons (idx, integer_one_node, decl); + } + else if (TREE_CODE (decl) == NON_LVALUE_EXPR + || CONVERT_EXPR_P (decl)) + decl = TREE_OPERAND (decl, 0); + + goto build_clause; + } token = cp_lexer_peek_token (parser->lexer); if (kind != 0 && cp_parser_is_keyword (token, RID_THIS)) @@ -36421,8 +36538,7 @@ cp_parser_omp_var_list_no_open (cp_parser *parser, enum omp_clause_code kind, case OMP_CLAUSE_TO: start_component_ref: while (cp_lexer_next_token_is (parser->lexer, CPP_DOT) - || (allow_deref - && cp_lexer_next_token_is (parser->lexer, CPP_DEREF))) + || cp_lexer_next_token_is (parser->lexer, CPP_DEREF)) { cpp_ttype ttype = cp_lexer_next_token_is (parser->lexer, CPP_DOT) @@ -36508,9 +36624,7 @@ cp_parser_omp_var_list_no_open (cp_parser *parser, enum omp_clause_code kind, || kind == OMP_CLAUSE_TO) && !array_section_p && (cp_lexer_next_token_is (parser->lexer, CPP_DOT) - || (allow_deref - && cp_lexer_next_token_is (parser->lexer, - CPP_DEREF)))) + || cp_lexer_next_token_is (parser->lexer, CPP_DEREF))) { for (unsigned i = 0; i < dims.length (); i++) { @@ -36546,6 +36660,7 @@ cp_parser_omp_var_list_no_open (cp_parser *parser, enum omp_clause_code kind, cp_parser_parse_definitely (parser); } + build_clause: tree u = build_omp_clause (token->location, kind); OMP_CLAUSE_DECL (u) = decl; OMP_CLAUSE_CHAIN (u) = list; @@ -36567,6 +36682,7 @@ cp_parser_omp_var_list_no_open (cp_parser *parser, enum omp_clause_code kind, { *colon = true; cp_parser_require (parser, CPP_COLON, RT_COLON); + finish_scope (); return list; } @@ -36587,6 +36703,7 @@ cp_parser_omp_var_list_no_open (cp_parser *parser, enum omp_clause_code kind, goto get_comma; } + finish_scope (); return list; } @@ -36595,11 +36712,11 @@ cp_parser_omp_var_list_no_open (cp_parser *parser, enum omp_clause_code kind, static tree cp_parser_omp_var_list (cp_parser *parser, enum omp_clause_code kind, tree list, - bool allow_deref = false) + bool map_lvalue = false) { if (cp_parser_require (parser, CPP_OPEN_PAREN, RT_OPEN_PAREN)) return cp_parser_omp_var_list_no_open (parser, kind, list, NULL, - allow_deref); + map_lvalue); return list; } @@ -36666,7 +36783,7 @@ cp_parser_oacc_data_clause (cp_parser *parser, pragma_omp_clause c_kind, gcc_unreachable (); } tree nl, c; - nl = cp_parser_omp_var_list (parser, OMP_CLAUSE_MAP, list, true); + nl = cp_parser_omp_var_list (parser, OMP_CLAUSE_MAP, list, false); for (c = nl; c != list; c = OMP_CLAUSE_CHAIN (c)) OMP_CLAUSE_SET_MAP_KIND (c, kind); @@ -40028,12 +40145,12 @@ cp_parser_omp_all_clauses (cp_parser *parser, omp_clause_mask mask, clauses); else clauses = cp_parser_omp_var_list (parser, OMP_CLAUSE_TO, clauses, - true); + false); c_name = "to"; break; case PRAGMA_OMP_CLAUSE_FROM: clauses = cp_parser_omp_var_list (parser, OMP_CLAUSE_FROM, clauses, - true); + false); c_name = "from"; break; case PRAGMA_OMP_CLAUSE_UNIFORM: diff --git a/gcc/cp/parser.h b/gcc/cp/parser.h index 3669587cebd..bebf8e6b16a 100644 --- a/gcc/cp/parser.h +++ b/gcc/cp/parser.h @@ -404,6 +404,9 @@ struct GTY(()) cp_parser { /* TRUE if omp::directive or omp::sequence attributes may not appear. */ bool omp_attrs_forbidden_p; + /* TRUE if an OpenMP array section is allowed. */ + bool omp_array_section_p; + /* Tracks the function's template parameter list when declaring a function using generic type parameters. This is either a new chain in the case of a fully implicit function template or an extension of the function's existing diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c index a95eb1adcb5..34e0d84c534 100644 --- a/gcc/cp/semantics.c +++ b/gcc/cp/semantics.c @@ -5073,7 +5073,9 @@ handle_omp_array_sections_1 (tree c, tree t, vec &types, ret = t_insp.get_deref_toplevel (); if (TREE_CODE (t) == FIELD_DECL) ret = finish_non_static_data_member (t, NULL_TREE, NULL_TREE); - else if (!VAR_P (t) && TREE_CODE (t) != PARM_DECL) + else if (!VAR_P (t) + && (ort == C_ORT_ACC || !EXPR_P (t)) + && TREE_CODE (t) != PARM_DECL) { if (processing_template_decl && TREE_CODE (t) != OVERLOAD) return NULL_TREE; @@ -5647,7 +5649,9 @@ handle_omp_array_sections (tree c, enum c_omp_region_type ort) bool reference_always_pointer = true; tree c2 = build_omp_clause (OMP_CLAUSE_LOCATION (c), OMP_CLAUSE_MAP); - if (TREE_CODE (t) == COMPONENT_REF) + if (TREE_CODE (t) == COMPONENT_REF + || (TREE_CODE (t) == POINTER_PLUS_EXPR + && TREE_CODE (TREE_OPERAND (t, 0)) == COMPONENT_REF)) { OMP_CLAUSE_SET_MAP_KIND (c2, GOMP_MAP_ATTACH_DETACH); @@ -5677,6 +5681,13 @@ handle_omp_array_sections (tree c, enum c_omp_region_type ort) } OMP_CLAUSE_SET_MAP_KIND (c2, k); } + else if (ort != C_ORT_ACC && attach_pt && !DECL_P (attach_pt)) + { + if (TREE_CODE (TREE_TYPE (t)) != POINTER_TYPE) + return false; + + OMP_CLAUSE_SET_MAP_KIND (c2, GOMP_MAP_ATTACH_DETACH); + } else OMP_CLAUSE_SET_MAP_KIND (c2, GOMP_MAP_FIRSTPRIVATE_POINTER); OMP_CLAUSE_MAP_IMPLICIT (c2) = OMP_CLAUSE_MAP_IMPLICIT (c); @@ -7909,6 +7920,15 @@ finish_omp_clauses (tree clauses, enum c_omp_region_type ort) { t = t_insp.analyze_components (false); + if (!t_insp.map_supported_p ()) + { + sorry_at (OMP_CLAUSE_LOCATION (c), + "unsupported map expression %qE", + OMP_CLAUSE_DECL (c)); + remove = true; + break; + } + if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_MAP && OMP_CLAUSE_MAP_IMPLICIT (c) && (bitmap_bit_p (&map_head, DECL_UID (t)) @@ -7990,6 +8010,14 @@ finish_omp_clauses (tree clauses, enum c_omp_region_type ort) OMP_CLAUSE_DECL (c) = t_insp.get_deref_toplevel (); if (type_dependent_expression_p (t_insp.get_deref_toplevel ())) break; + if (!t_insp.map_supported_p ()) + { + sorry_at (OMP_CLAUSE_LOCATION (c), + "unsupported map expression %qE", + OMP_CLAUSE_DECL (c)); + remove = true; + break; + } if (t == error_mark_node) { remove = true; @@ -8019,7 +8047,8 @@ finish_omp_clauses (tree clauses, enum c_omp_region_type ort) if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_MAP && (OMP_CLAUSE_MAP_KIND (c) == GOMP_MAP_POINTER || OMP_CLAUSE_MAP_KIND (c) == GOMP_MAP_ALWAYS_POINTER - || OMP_CLAUSE_MAP_KIND (c) == GOMP_MAP_ATTACH_DETACH)) + || OMP_CLAUSE_MAP_KIND (c) == GOMP_MAP_ATTACH_DETACH + || (ort != C_ORT_ACC && EXPR_P (t)))) break; if (DECL_P (t)) error_at (OMP_CLAUSE_LOCATION (c), diff --git a/gcc/gimplify.c b/gcc/gimplify.c index 8f07da8a991..c9f66be3119 100644 --- a/gcc/gimplify.c +++ b/gcc/gimplify.c @@ -9812,6 +9812,7 @@ build_struct_group (enum omp_region_type region_type, enum tree_code code, { tree l = build_omp_clause (OMP_CLAUSE_LOCATION (grp_end), OMP_CLAUSE_MAP); gomp_map_kind k = attach ? GOMP_MAP_FORCE_PRESENT : GOMP_MAP_STRUCT; + tree *tail_chain; OMP_CLAUSE_SET_MAP_KIND (l, k); @@ -9840,9 +9841,13 @@ build_struct_group (enum omp_region_type region_type, enum tree_code code, { OMP_CLAUSE_CHAIN (extra_node) = *insert_node_pos; OMP_CLAUSE_CHAIN (alloc_node) = extra_node; + tail_chain = &OMP_CLAUSE_CHAIN (extra_node); } else - OMP_CLAUSE_CHAIN (alloc_node) = *insert_node_pos; + { + OMP_CLAUSE_CHAIN (alloc_node) = *insert_node_pos; + tail_chain = &OMP_CLAUSE_CHAIN (alloc_node); + } *insert_node_pos = l; } @@ -9850,6 +9855,7 @@ build_struct_group (enum omp_region_type region_type, enum tree_code code, { gcc_assert (*grp_start_p == grp_end); grp_start_p = insert_node_after (l, grp_start_p); + tail_chain = &OMP_CLAUSE_CHAIN (*grp_start_p); } tree noind = strip_indirections (base); @@ -9914,8 +9920,7 @@ build_struct_group (enum omp_region_type region_type, enum tree_code code, || TREE_CODE (sdecl) == POINTER_PLUS_EXPR) sdecl = TREE_OPERAND (sdecl, 0); - if (DECL_P (sdecl) - && POINTER_TYPE_P (TREE_TYPE (sdecl)) + if (POINTER_TYPE_P (TREE_TYPE (sdecl)) && (region_type & ORT_TARGET)) { tree c2 = build_omp_clause (OMP_CLAUSE_LOCATION (grp_end), @@ -9929,8 +9934,12 @@ build_struct_group (enum omp_region_type region_type, enum tree_code code, && (TREE_CODE (TREE_TYPE (TREE_OPERAND (TREE_OPERAND (base, 0), 0))) == REFERENCE_TYPE)))); - enum gomp_map_kind mkind = base_ref ? GOMP_MAP_FIRSTPRIVATE_REFERENCE - : GOMP_MAP_FIRSTPRIVATE_POINTER; + enum gomp_map_kind mkind; + if (DECL_P (sdecl)) + mkind = base_ref ? GOMP_MAP_FIRSTPRIVATE_REFERENCE + : GOMP_MAP_FIRSTPRIVATE_POINTER; + else + mkind = GOMP_MAP_ATTACH; OMP_CLAUSE_SET_MAP_KIND (c2, mkind); OMP_CLAUSE_DECL (c2) = sdecl; tree baddr = build_fold_addr_expr (base); @@ -9946,9 +9955,21 @@ build_struct_group (enum omp_region_type region_type, enum tree_code code, OMP_CLAUSE_SIZE (c2) = fold_build2_loc (OMP_CLAUSE_LOCATION (grp_end), MINUS_EXPR, ptrdiff_type_node, baddr, decladdr); - /* Insert after struct node. */ - OMP_CLAUSE_CHAIN (c2) = OMP_CLAUSE_CHAIN (l); - OMP_CLAUSE_CHAIN (l) = c2; + if (mkind == GOMP_MAP_FIRSTPRIVATE_POINTER + || mkind == GOMP_MAP_FIRSTPRIVATE_REFERENCE) + { + /* Insert after struct node. */ + OMP_CLAUSE_CHAIN (c2) = OMP_CLAUSE_CHAIN (l); + OMP_CLAUSE_CHAIN (l) = c2; + } + else /* GOMP_MAP_ATTACH. */ + { + /* Insert after struct group. */ + OMP_CLAUSE_CHAIN (c2) = *tail_chain; + *tail_chain = c2; + if (*grp_start_p == grp_end) + return &OMP_CLAUSE_CHAIN (*tail_chain); + } } return NULL; diff --git a/gcc/testsuite/c-c++-common/gomp/map-6.c b/gcc/testsuite/c-c++-common/gomp/map-6.c index 6ee59714847..c749db845b0 100644 --- a/gcc/testsuite/c-c++-common/gomp/map-6.c +++ b/gcc/testsuite/c-c++-common/gomp/map-6.c @@ -20,12 +20,12 @@ foo (void) ; #pragma omp target map (close a) /* { dg-error "'close' undeclared" "" { target c } } */ - /* { dg-error "'close' has not been declared" "" { target c++ } .-1 } */ + /* { dg-error "'close' was not declared in this scope" "" { target c++ } .-1 } */ /* { dg-error "expected '\\)' before 'a'" "" { target *-*-* } .-2 } */ ; #pragma omp target map (always a) /* { dg-error "'always' undeclared" "" { target c } } */ - /* { dg-error "'always' has not been declared" "" { target c++ } .-1 } */ + /* { dg-error "'always' was not declared in this scope" "" { target c++ } .-1 } */ /* { dg-error "expected '\\)' before 'a'" "" { target *-*-* } .-2 } */ ; diff --git a/gcc/testsuite/g++.dg/gomp/ind-base-3.C b/gcc/testsuite/g++.dg/gomp/ind-base-3.C new file mode 100644 index 00000000000..dbabaf7680c --- /dev/null +++ b/gcc/testsuite/g++.dg/gomp/ind-base-3.C @@ -0,0 +1,38 @@ +#include + +struct S { + int x[10]; +}; + +S * +choose (S *a, S *b, int c) +{ + if (c < 5) + return a; + else + return b; +} + +int main (int argc, char *argv[]) +{ + S a, b; + + for (int i = 0; i < 10; i++) + a.x[i] = b.x[i] = 0; + + for (int i = 0; i < 10; i++) + { +#pragma omp target map(choose(&a, &b, i)->x[:10]) +/* { dg-message {sorry, unimplemented: unsupported map expression 'choose\(\(& a\), \(& b\), i\)->S::x\[0\]'} "" { target *-*-* } .-1 } */ +/* { dg-message {sorry, unimplemented: unsupported map expression 'choose\(\(& a\), \(& b\), i\)'} "" { target *-*-* } .-2 } */ + for (int j = 0; j < 10; j++) + choose (&a, &b, i)->x[j]++; + } + + for (int i = 0; i < 10; i++) + assert (a.x[i] == 5 && b.x[i] == 5); + + return 0; +} + + diff --git a/gcc/testsuite/g++.dg/gomp/map-assignment-1.C b/gcc/testsuite/g++.dg/gomp/map-assignment-1.C new file mode 100644 index 00000000000..5979ec379f1 --- /dev/null +++ b/gcc/testsuite/g++.dg/gomp/map-assignment-1.C @@ -0,0 +1,12 @@ +#include + +int main (int argc, char *argv[]) +{ + int a = 5, b = 2; +#pragma omp target map(a += b) + /* { dg-message {sorry, unimplemented: unsupported map expression '\(a = \(a \+ b\)\)'} "" { target *-*-* } .-1 } */ + { + a++; + } + return 0; +} diff --git a/gcc/testsuite/g++.dg/gomp/map-inc-1.C b/gcc/testsuite/g++.dg/gomp/map-inc-1.C new file mode 100644 index 00000000000..b469a4bd548 --- /dev/null +++ b/gcc/testsuite/g++.dg/gomp/map-inc-1.C @@ -0,0 +1,10 @@ +int main (int argc, char *argv[]) +{ + int a = 5; +#pragma omp target map(++a) + /* { dg-message {sorry, unimplemented: unsupported map expression '\+\+ a'} "" { target *-*-* } .-1 } */ + { + a++; + } + return 0; +} diff --git a/gcc/testsuite/g++.dg/gomp/map-lvalue-ref-1.C b/gcc/testsuite/g++.dg/gomp/map-lvalue-ref-1.C new file mode 100644 index 00000000000..d720d4318ae --- /dev/null +++ b/gcc/testsuite/g++.dg/gomp/map-lvalue-ref-1.C @@ -0,0 +1,19 @@ +#include + +int glob = 10; + +int& foo () +{ + return glob; +} + +int main (int argc, char *argv[]) +{ +#pragma omp target map(foo()) + /* { dg-message {sorry, unimplemented: unsupported map expression 'foo\(\)'} "" { target *-*-* } .-1 } */ + { + foo()++; + } + assert (glob == 11); + return 0; +} diff --git a/gcc/testsuite/g++.dg/gomp/map-ptrmem-1.C b/gcc/testsuite/g++.dg/gomp/map-ptrmem-1.C new file mode 100644 index 00000000000..f5f5949a1ca --- /dev/null +++ b/gcc/testsuite/g++.dg/gomp/map-ptrmem-1.C @@ -0,0 +1,36 @@ +#include + +struct S { + int x; + int *ptr; +}; + +int +main (int argc, char *argv[]) +{ + S s; + int S::* xp = &S::x; + int* S::* ptrp = &S::ptr; + + s.ptr = new int[64]; + + s.*xp = 6; + for (int i = 0; i < 64; i++) + (s.*ptrp)[i] = i; + +#pragma omp target map(s.*xp, s.*ptrp, (s.*ptrp)[:64]) + /* { dg-message {sorry, unimplemented: unsupported map expression '\(int\*\*\)\(& s\)'} "" { target *-*-* } .-1 } */ + /* { dg-message {sorry, unimplemented: unsupported map expression '\(int\*\)\(& s\)'} "" { target *-*-* } .-2 } */ +#pragma omp teams distribute parallel for + for (int i = 0; i < 64; i++) + { + (s.*xp)++; + (s.*ptrp)[i]++; + } + + assert (s.*xp == 70); + for (int i = 0; i < 64; i++) + assert ((s.*ptrp)[i] == i + 1); + + return 0; +} diff --git a/gcc/testsuite/g++.dg/gomp/map-ptrmem-2.C b/gcc/testsuite/g++.dg/gomp/map-ptrmem-2.C new file mode 100644 index 00000000000..7fdf742b2ca --- /dev/null +++ b/gcc/testsuite/g++.dg/gomp/map-ptrmem-2.C @@ -0,0 +1,39 @@ +#include + +struct S { + int x; + int *ptr; +}; + +int +main (int argc, char *argv[]) +{ + S *s = new S; + int S::* xp = &S::x; + int* S::* ptrp = &S::ptr; + + s->ptr = new int[64]; + + s->*xp = 4; + for (int i = 0; i < 64; i++) + (s->*ptrp)[i] = i; + +#pragma omp target map(s->*xp, s->*ptrp, (s->*ptrp)[:64]) + /* { dg-message {sorry, unimplemented: unsupported map expression '\(int\*\*\)s'} "" { target *-*-* } .-1 } */ + /* { dg-message {sorry, unimplemented: unsupported map expression '\(int\*\)s'} "" { target *-*-* } .-2 } */ +#pragma omp teams distribute parallel for + for (int i = 0; i < 64; i++) + { + (s->*xp)++; + (s->*ptrp)[i]++; + } + + assert (s->*xp == 68); + for (int i = 0; i < 64; i++) + assert ((s->*ptrp)[i] == i + 1); + + delete s->ptr; + delete s; + + return 0; +} diff --git a/gcc/testsuite/g++.dg/gomp/map-static-cast-lvalue-1.C b/gcc/testsuite/g++.dg/gomp/map-static-cast-lvalue-1.C new file mode 100644 index 00000000000..3af9668202c --- /dev/null +++ b/gcc/testsuite/g++.dg/gomp/map-static-cast-lvalue-1.C @@ -0,0 +1,17 @@ +#include + +int foo (int x) +{ +#pragma omp target map(static_cast(x)) + /* { dg-message {sorry, unimplemented: unsupported map expression '& x'} "" { target *-*-* } .-1 } */ + { + x += 3; + } + return x; +} + +int main (int argc, char *argv[]) +{ + assert (foo (5) == 8); + return 0; +} diff --git a/gcc/testsuite/g++.dg/gomp/map-ternary-1.C b/gcc/testsuite/g++.dg/gomp/map-ternary-1.C new file mode 100644 index 00000000000..7b365a909bb --- /dev/null +++ b/gcc/testsuite/g++.dg/gomp/map-ternary-1.C @@ -0,0 +1,20 @@ +#include + +int foo (bool yesno) +{ + int x = 5, y = 7; +#pragma omp target map(yesno ? x : y) + /* { dg-message {sorry, unimplemented: unsupported map expression '\(yesno \? x : y\)'} "" { target *-*-* } .-1 } */ + { + x += 3; + y += 5; + } + return yesno ? x : y; +} + +int main (int argc, char *argv[]) +{ + assert (foo (true) == 8); + assert (foo (false) == 12); + return 0; +} diff --git a/gcc/testsuite/g++.dg/gomp/member-array-2.C b/gcc/testsuite/g++.dg/gomp/member-array-2.C new file mode 100644 index 00000000000..ba931bd585e --- /dev/null +++ b/gcc/testsuite/g++.dg/gomp/member-array-2.C @@ -0,0 +1,86 @@ +#include + +typedef int intarr100[100]; + +class C { + int arr[100]; + int *ptr; + +public: + C(); + ~C(); + void zero (); + void do_operation (); + void check (int, int); + intarr100 &get_arr () { return arr; } + int *get_ptr() { return ptr; } +}; + +C::C() +{ + ptr = new int[100]; + for (int i = 0; i < 100; i++) + arr[i] = 0; +} + +C::~C() +{ + delete ptr; +} + +void +C::zero () +{ + for (int i = 0; i < 100; i++) + arr[i] = ptr[i] = 0; +} + +void +C::do_operation () +{ +#pragma omp target map(arr, ptr, ptr[:100]) +#pragma omp teams distribute parallel for + for (int i = 0; i < 100; i++) + { + arr[i] = arr[i] + 3; + ptr[i] = ptr[i] + 5; + } +} + +void +C::check (int arrval, int ptrval) +{ + for (int i = 0; i < 100; i++) + { + assert (arr[i] == arrval); + assert (ptr[i] == ptrval); + } +} + +int +main (int argc, char *argv[]) +{ + C c; + + c.zero (); + c.do_operation (); + c.check (3, 5); + + #pragma omp target map(c.get_arr()[:100]) + #pragma omp teams distribute parallel for + for (int i = 0; i < 100; i++) + c.get_arr()[i] += 2; + + c.check (5, 5); + + #pragma omp target map(c.get_ptr(), c.get_ptr()[:100]) + /* { dg-message {sorry, unimplemented: unsupported map expression 'c\.C::get_ptr\(\)'} "" { target *-*-* } .-1 } */ + #pragma omp teams distribute parallel for + for (int i = 0; i < 100; i++) + c.get_ptr()[i] += 3; + + c.check (5, 8); + + return 0; +} + diff --git a/gcc/testsuite/g++.dg/gomp/pr67522.C b/gcc/testsuite/g++.dg/gomp/pr67522.C index da8cb74d1fa..4a901ba68c7 100644 --- a/gcc/testsuite/g++.dg/gomp/pr67522.C +++ b/gcc/testsuite/g++.dg/gomp/pr67522.C @@ -12,7 +12,7 @@ foo (void) for (int i = 0; i < 16; i++) ; - #pragma omp target map (S[0:10]) // { dg-error "is not a variable in" } + #pragma omp target map (S[0:10]) // { dg-error "expected primary-expression before '\\\[' token" } ; #pragma omp task depend (inout: S[0:10]) // { dg-error "is not a variable in" } diff --git a/gcc/tree-pretty-print.c b/gcc/tree-pretty-print.c index 13b64fd52e1..387fc3e132c 100644 --- a/gcc/tree-pretty-print.c +++ b/gcc/tree-pretty-print.c @@ -2516,6 +2516,20 @@ dump_generic_node (pretty_printer *pp, tree node, int spc, dump_flags_t flags, } break; + case OMP_ARRAY_SECTION: + op0 = TREE_OPERAND (node, 0); + if (op_prio (op0) < op_prio (node)) + pp_left_paren (pp); + dump_generic_node (pp, op0, spc, flags, false); + if (op_prio (op0) < op_prio (node)) + pp_right_paren (pp); + pp_left_bracket (pp); + dump_generic_node (pp, TREE_OPERAND (node, 1), spc, flags, false); + pp_colon (pp); + dump_generic_node (pp, TREE_OPERAND (node, 2), spc, flags, false); + pp_right_bracket (pp); + break; + case CONSTRUCTOR: { unsigned HOST_WIDE_INT ix; diff --git a/gcc/tree.def b/gcc/tree.def index e27bc3e2b1f..9824840ec00 100644 --- a/gcc/tree.def +++ b/gcc/tree.def @@ -1304,6 +1304,9 @@ DEFTREECODE (OMP_ATOMIC_CAPTURE_NEW, "omp_atomic_capture_new", tcc_statement, 2) /* OpenMP clauses. */ DEFTREECODE (OMP_CLAUSE, "omp_clause", tcc_exceptional, 0) +/* An OpenMP array section. */ +DEFTREECODE (OMP_ARRAY_SECTION, "omp_array_section", tcc_expression, 3) + /* TRANSACTION_EXPR tree code. Operand 0: BODY: contains body of the transaction. */ DEFTREECODE (TRANSACTION_EXPR, "transaction_expr", tcc_expression, 1) diff --git a/libgomp/testsuite/libgomp.c++/ind-base-1.C b/libgomp/testsuite/libgomp.c++/ind-base-1.C new file mode 100644 index 00000000000..4566854e60a --- /dev/null +++ b/libgomp/testsuite/libgomp.c++/ind-base-1.C @@ -0,0 +1,162 @@ +// { dg-do run } +// { dg-options "-fopenmp" } + +#include + +struct S +{ + int x[10]; +}; + +struct T +{ + struct S *s; +}; + +struct U +{ + struct T *t; +}; + +void +foo_siblist (void) +{ + U *u = new U; + u->t = new T; + u->t->s = new S; + for (int i = 0; i < 10; i++) + u->t->s->x[i] = 0; +#pragma omp target map(u->t, *(u->t), u->t->s, *u->t->s) + for (int i = 0; i < 10; i++) + u->t->s->x[i] = i * 3; + for (int i = 0; i < 10; i++) + assert (u->t->s->x[i] == i * 3); + delete u->t->s; + delete u->t; + delete u; +} + +void +foo (void) +{ + U *u = new U; + u->t = new T; + u->t->s = new S; + for (int i = 0; i < 10; i++) + u->t->s->x[i] = 0; +#pragma omp target map(*u, u->t, *(u->t), u->t->s, *u->t->s) + for (int i = 0; i < 10; i++) + u->t->s->x[i] = i * 3; + for (int i = 0; i < 10; i++) + assert (u->t->s->x[i] == i * 3); + delete u->t->s; + delete u->t; + delete u; +} + +void +foo_tofrom (void) +{ + U *u = new U; + u->t = new T; + u->t->s = new S; + for (int i = 0; i < 10; i++) + u->t->s->x[i] = 0; +#pragma omp target map(u, *u, u->t, *(u->t), u->t->s, *u->t->s) + for (int i = 0; i < 10; i++) + u->t->s->x[i] = i * 3; + for (int i = 0; i < 10; i++) + assert (u->t->s->x[i] == i * 3); + delete u->t->s; + delete u->t; + delete u; +} + +void +bar (void) +{ + U *u = new U; + U **up = &u; + u->t = new T; + u->t->s = new S; + for (int i = 0; i < 10; i++) + (*up)->t->s->x[i] = 0; +#pragma omp target map(*up, (*up)->t, *(*up)->t, (*up)->t->s, *(*up)->t->s) + for (int i = 0; i < 10; i++) + (*up)->t->s->x[i] = i * 3; + for (int i = 0; i < 10; i++) + assert ((*up)->t->s->x[i] == i * 3); + delete u->t->s; + delete u->t; + delete u; +} + +void +bar_pp (void) +{ + U *u = new U; + U **up = &u; + u->t = new T; + u->t->s = new S; + for (int i = 0; i < 10; i++) + (*up)->t->s->x[i] = 0; +#pragma omp target map(*up, **up, (*up)->t, *(*up)->t, (*up)->t->s, *(*up)->t->s) + for (int i = 0; i < 10; i++) + (*up)->t->s->x[i] = i * 3; + for (int i = 0; i < 10; i++) + assert ((*up)->t->s->x[i] == i * 3); + delete u->t->s; + delete u->t; + delete u; +} + +void +bar_tofrom (void) +{ + U *u = new U; + U **up = &u; + u->t = new T; + u->t->s = new S; + for (int i = 0; i < 10; i++) + (*up)->t->s->x[i] = 0; +#pragma omp target map(*up, up, (*up)->t, *(*up)->t, (*up)->t->s, *(*up)->t->s) + for (int i = 0; i < 10; i++) + (*up)->t->s->x[i] = i * 3; + for (int i = 0; i < 10; i++) + assert ((*up)->t->s->x[i] == i * 3); + delete u->t->s; + delete u->t; + delete u; +} + +void +bar_tofrom_pp (void) +{ + U *u = new U; + U **up = &u; + u->t = new T; + u->t->s = new S; + for (int i = 0; i < 10; i++) + (*up)->t->s->x[i] = 0; +#pragma omp target map(**up, *up, up, (*up)->t, *(*up)->t, (*up)->t->s, \ + *(*up)->t->s) + for (int i = 0; i < 10; i++) + (*up)->t->s->x[i] = i * 3; + for (int i = 0; i < 10; i++) + assert ((*up)->t->s->x[i] == i * 3); + delete u->t->s; + delete u->t; + delete u; +} + +int main (int argc, char *argv[]) +{ + foo_siblist (); + foo (); + foo_tofrom (); + bar (); + bar_pp (); + bar_tofrom (); + bar_tofrom_pp (); + return 0; +} diff --git a/libgomp/testsuite/libgomp.c++/ind-base-2.C b/libgomp/testsuite/libgomp.c++/ind-base-2.C new file mode 100644 index 00000000000..706a1205c00 --- /dev/null +++ b/libgomp/testsuite/libgomp.c++/ind-base-2.C @@ -0,0 +1,49 @@ +// { dg-do run } +// { dg-options "-fopenmp" } + +#include + +struct S +{ + int x[10]; +}; + +struct T +{ + struct S ***s; +}; + +struct U +{ + struct T **t; +}; + +void +foo (void) +{ + U *u = new U; + T *real_t = new T; + S *real_s = new S; + T **t_pp = &real_t; + S **s_pp = &real_s; + S ***s_ppp = &s_pp; + u->t = t_pp; + (*u->t)->s = s_ppp; + for (int i = 0; i < 10; i++) + (**((*u->t)->s))->x[i] = 0; +#pragma omp target map(u->t, *u->t, (*u->t)->s, *(*u->t)->s, **(*u->t)->s, \ + (**(*u->t)->s)->x[0:10]) + for (int i = 0; i < 10; i++) + (**((*u->t)->s))->x[i] = i * 3; + for (int i = 0; i < 10; i++) + assert ((**((*u->t)->s))->x[i] == i * 3); + delete real_s; + delete real_t; + delete u; +} + +int main (int argc, char *argv[]) +{ + foo (); + return 0; +} diff --git a/libgomp/testsuite/libgomp.c++/map-comma-1.C b/libgomp/testsuite/libgomp.c++/map-comma-1.C new file mode 100644 index 00000000000..ee03c5ac1aa --- /dev/null +++ b/libgomp/testsuite/libgomp.c++/map-comma-1.C @@ -0,0 +1,15 @@ +/* { dg-do run } */ + +#include + +int main (int argc, char *argv[]) +{ + int a = 5, b = 7; +#pragma omp target map((a, b)) + { + a++; + b++; + } + assert (a == 5 && b == 8); + return 0; +} diff --git a/libgomp/testsuite/libgomp.c++/map-rvalue-ref-1.C b/libgomp/testsuite/libgomp.c++/map-rvalue-ref-1.C new file mode 100644 index 00000000000..93811da4000 --- /dev/null +++ b/libgomp/testsuite/libgomp.c++/map-rvalue-ref-1.C @@ -0,0 +1,22 @@ +/* { dg-do run } */ + +#include + +int foo (int &&x) +{ + int y; +#pragma omp target map(x, y) + { + x++; + y = x; + } + return y; +} + +int main (int argc, char *argv[]) +{ + int y = 5; + y = foo (y + 3); + assert (y == 9); + return 0; +} diff --git a/libgomp/testsuite/libgomp.c++/member-array-1.C b/libgomp/testsuite/libgomp.c++/member-array-1.C new file mode 100644 index 00000000000..ee11d45562e --- /dev/null +++ b/libgomp/testsuite/libgomp.c++/member-array-1.C @@ -0,0 +1,89 @@ +/* { dg-do run } */ + +#include + +typedef int intarr100[100]; + +class C { + int arr[100]; + int *ptr; + +public: + C(); + ~C(); + void zero (); + void do_operation (); + void check (int, int); + intarr100 &get_arr () { return arr; } + int *get_ptr() { return ptr; } +}; + +C::C() +{ + ptr = new int[100]; + for (int i = 0; i < 100; i++) + arr[i] = 0; +} + +C::~C() +{ + delete ptr; +} + +void +C::zero () +{ + for (int i = 0; i < 100; i++) + arr[i] = ptr[i] = 0; +} + +void +C::do_operation () +{ +#pragma omp target map(arr, ptr, ptr[:100]) +#pragma omp teams distribute parallel for + for (int i = 0; i < 100; i++) + { + arr[i] = arr[i] + 3; + ptr[i] = ptr[i] + 5; + } +} + +void +C::check (int arrval, int ptrval) +{ + for (int i = 0; i < 100; i++) + { + assert (arr[i] == arrval); + assert (ptr[i] == ptrval); + } +} + +int +main (int argc, char *argv[]) +{ + C c; + + c.zero (); + c.do_operation (); + c.check (3, 5); + + #pragma omp target map(c.get_arr()[:100]) + #pragma omp teams distribute parallel for + for (int i = 0; i < 100; i++) + c.get_arr()[i] += 2; + + c.check (5, 5); + + /* This is currently not supported. See also: + gcc/testsuite/g++.dg/gomp/member-array-2.C. */ + //#pragma omp target map(c.get_ptr(), c.get_ptr()[:100]) + //#pragma omp teams distribute parallel for + for (int i = 0; i < 100; i++) + c.get_ptr()[i] += 3; + + c.check (5, 8); + + return 0; +} + diff --git a/libgomp/testsuite/libgomp.c++/struct-ref-1.C b/libgomp/testsuite/libgomp.c++/struct-ref-1.C new file mode 100644 index 00000000000..d3874650017 --- /dev/null +++ b/libgomp/testsuite/libgomp.c++/struct-ref-1.C @@ -0,0 +1,97 @@ +// { dg-do run } +// { dg-options "-fopenmp" } + +#include + +struct S +{ + int x[10]; +}; + +void +foo (S *s, int x) +{ + S *&r = s; + for (int i = 0; i < x; i++) + s[0].x[i] = s[1].x[i] = 0; + #pragma omp target map (s, x) + ; + #pragma omp target map (s[0], x) + for (int i = 0; i < x; i++) + s[0].x[i] = i; + #pragma omp target map (s[1], x) + for (int i = 0; i < x; i++) + s[1].x[i] = i * 2; + for (int i = 0; i < x; i++) + { + assert (s[0].x[i] == i); + assert (s[1].x[i] == i * 2); + s[0].x[i] = 0; + s[1].x[i] = 0; + } + #pragma omp target map (r, x) + ; + #pragma omp target map (r[0], x) + for (int i = 0; i < x; i++) + r[0].x[i] = i; + #pragma omp target map (r[1], x) + for (int i = 0; i < x; i++) + r[1].x[i] = i * 2; + for (int i = 0; i < x; i++) + { + assert (r[0].x[i] == i); + assert (r[1].x[i] == i * 2); + } +} + +template +struct T +{ + int x[N]; +}; + +template +void +bar (T *t, int x) +{ + T *&r = t; + for (int i = 0; i < x; i++) + t[0].x[i] = t[1].x[i] = 0; + #pragma omp target map (t, x) + ; + #pragma omp target map (t[0], x) + for (int i = 0; i < x; i++) + t[0].x[i] = i; + #pragma omp target map (t[1], x) + for (int i = 0; i < x; i++) + t[1].x[i] = i * 2; + for (int i = 0; i < x; i++) + { + assert (t[0].x[i] == i); + assert (t[1].x[i] == i * 2); + t[0].x[i] = 0; + t[1].x[i] = 0; + } + #pragma omp target map (r, x) + ; + #pragma omp target map (r[0], x) + for (int i = 0; i < x; i++) + r[0].x[i] = i; + #pragma omp target map (r[1], x) + for (int i = 0; i < x; i++) + r[1].x[i] = i * 2; + for (int i = 0; i < x; i++) + { + assert (r[0].x[i] == i); + assert (r[1].x[i] == i * 2); + } +} + +int main (int argc, char *argv[]) +{ + S s[2]; + foo (s, 10); + T<10> t[2]; + bar (t, 10); + return 0; +} From patchwork Thu Nov 25 14:11:16 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Julian Brown X-Patchwork-Id: 1559742 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=gcc.gnu.org (client-ip=8.43.85.97; helo=sourceware.org; envelope-from=gcc-patches-bounces+incoming=patchwork.ozlabs.org@gcc.gnu.org; receiver=) Received: from sourceware.org (server2.sourceware.org [8.43.85.97]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by bilbo.ozlabs.org (Postfix) with ESMTPS id 4J0KjD3CSMz9sVc for ; Fri, 26 Nov 2021 01:18:06 +1100 (AEDT) Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id A3521385842C for ; Thu, 25 Nov 2021 14:18:04 +0000 (GMT) X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from esa2.mentor.iphmx.com (esa2.mentor.iphmx.com [68.232.141.98]) by sourceware.org (Postfix) with ESMTPS id 68C6D3858436 for ; Thu, 25 Nov 2021 14:11:29 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org 68C6D3858436 Authentication-Results: sourceware.org; dmarc=none (p=none dis=none) header.from=codesourcery.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=mentor.com IronPort-SDR: D6IsuL7UEzUWblCqVTE4XhoWzyOdTqBNVhyLESTfKql4XKJ3G3DRj9oiXPajQGGmgYT7oJP8GQ xdIJlS/IVgK2+moo9GlvZBsZqx9WGrGZwZMW83R+L+SEuFBT7ZoI+oGnsI3UkB9Pn7u94Hj7ej Jmcm1yDSgvFEAsRoZcgsOhO+Ny5EOebEhiXQ7PuN6PtY9c8kqzKeujwhh9eUGR/ZHSMVNtQl3v 3nSEIo5jh1f93I8tgCk7XgGQe/HdvgKbDQPkh6u2/H5rrTL8hRt5q8YcCveUSPN7zv8FfIOtJY BpOWNm/HRDd2suQL1ZqTYefm X-IronPort-AV: E=Sophos;i="5.87,263,1631606400"; d="scan'208";a="68920912" Received: from orw-gwy-02-in.mentorg.com ([192.94.38.167]) by esa2.mentor.iphmx.com with ESMTP; 25 Nov 2021 06:11:27 -0800 IronPort-SDR: RhSXEWoYRrRDMii3wg4k0Z01JjBagRTqKWX6yVuu068IjjNseDbQfKlIYpS8iU6ZHwJYMqEo15 Tttu519SK9Odi7E2H1KyOKhUZOjZLX7LAHjuy3EIVmtRtgUoLVS8PCh5pkytUEY7sPkf486GFF SRROqS4c91BOlak/QP1DftNnsAKg8a185OvMI6ZxhNn9Z8LApW9k+nXTZ5zn82e2UabcH2CaYz uHFGe3tBnHDC73g9nt8L3KM2uYERxja4oarPnlAGCTwSpzgKAKbqBDDwGVj9W5PWEM22wHjJa+ XIg= From: Julian Brown To: Subject: [PATCH 16/16] OpenMP: lvalue parsing for map clauses (C) Date: Thu, 25 Nov 2021 06:11:16 -0800 Message-ID: <20211125141116.116128-2-julian@codesourcery.com> X-Mailer: git-send-email 2.29.2 In-Reply-To: <20211125141116.116128-1-julian@codesourcery.com> References: <20211125141116.116128-1-julian@codesourcery.com> MIME-Version: 1.0 X-Originating-IP: [137.202.0.90] X-ClientProxiedBy: svr-ies-mbx-13.mgc.mentorg.com (139.181.222.13) To SVR-IES-MBX-04.mgc.mentorg.com (139.181.222.4) X-Spam-Status: No, score=-11.8 required=5.0 tests=BAYES_00, GIT_PATCH_0, HEADER_FROM_DIFFERENT_DOMAINS, KAM_DMARC_STATUS, SPF_HELO_PASS, SPF_PASS, 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: , Cc: Jakub Jelinek , Thomas Schwinge Errors-To: gcc-patches-bounces+incoming=patchwork.ozlabs.org@gcc.gnu.org Sender: "Gcc-patches" This patch adds support for parsing general lvalues for OpenMP "map" clauses to the C front-end, similar to the previous patch for C++. This version of the patch fixes several omissions regarding non-DECL_P root terms in map clauses (i.e. "*foo" in "(*foo)->ptr->arr[:N]") -- similar to the cp/semantics.c changes in the previous patch -- and adds a couple of new tests. OK? Thanks, Julian 2021-11-24 Julian Brown gcc/c/ * c-parser.c (c_parser_postfix_expression_after_primary): Add support for OpenMP array section parsing. (c_parser_omp_variable_list): Change ALLOW_DEREF parameter to MAP_LVALUE. Support parsing of general lvalues in "map" clauses. (c_parser_omp_var_list_parens): Change ALLOW_DEREF parameter to MAP_LVALUE. Update call to c_parser_omp_variable_list. (c_parser_oacc_data_clause, c_parser_omp_clause_to, c_parser_omp_clause_from): Update calls to c_parser_omp_var_list_parens. * c-tree.h (c_omp_array_section_p): Add extern declaration. * c-typeck.c (c_omp_array_section_p): Add flag. (mark_exp_read): Support OMP_ARRAY_SECTION. (handle_omp_array_sections_1): Handle more kinds of expressions. (handle_omp_array_sections): Handle non-DECL_P attachment points. (c_finish_omp_clauses): Check for supported expression types. Support non-DECL_P root term for map clauses. gcc/testsuite/ * c-c++-common/gomp/map-1.c: Adjust expected output. * c-c++-common/gomp/map-6.c: Likewise. libgomp/ * testsuite/libgomp.c-c++-common/ind-base-4.c: New test. * testsuite/libgomp.c-c++-common/unary-ptr-1.c: New test. --- gcc/c/c-parser.c | 150 +++++++++++++++--- gcc/c/c-tree.h | 1 + gcc/c/c-typeck.c | 45 +++++- gcc/testsuite/c-c++-common/gomp/map-1.c | 3 +- gcc/testsuite/c-c++-common/gomp/map-6.c | 2 + .../libgomp.c-c++-common/ind-base-4.c | 50 ++++++ .../libgomp.c-c++-common/unary-ptr-1.c | 16 ++ 7 files changed, 243 insertions(+), 24 deletions(-) create mode 100644 libgomp/testsuite/libgomp.c-c++-common/ind-base-4.c create mode 100644 libgomp/testsuite/libgomp.c-c++-common/unary-ptr-1.c diff --git a/gcc/c/c-parser.c b/gcc/c/c-parser.c index 322f30c90b4..702a0b7d8a9 100644 --- a/gcc/c/c-parser.c +++ b/gcc/c/c-parser.c @@ -10460,7 +10460,7 @@ c_parser_postfix_expression_after_primary (c_parser *parser, struct c_expr expr) { struct c_expr orig_expr; - tree ident, idx; + tree ident, idx, len; location_t sizeof_arg_loc[3], comp_loc; tree sizeof_arg[3]; unsigned int literal_zero_mask; @@ -10479,15 +10479,44 @@ c_parser_postfix_expression_after_primary (c_parser *parser, case CPP_OPEN_SQUARE: /* Array reference. */ c_parser_consume_token (parser); - idx = c_parser_expression (parser).value; - c_parser_skip_until_found (parser, CPP_CLOSE_SQUARE, - "expected %<]%>"); - start = expr.get_start (); - finish = parser->tokens_buf[0].location; - expr.value = build_array_ref (op_loc, expr.value, idx); - set_c_expr_source_range (&expr, start, finish); - expr.original_code = ERROR_MARK; - expr.original_type = NULL; + idx = len = NULL_TREE; + if (!c_omp_array_section_p + || c_parser_next_token_is_not (parser, CPP_COLON)) + idx = c_parser_expression (parser).value; + + if (c_omp_array_section_p + && c_parser_next_token_is (parser, CPP_COLON)) + { + c_parser_consume_token (parser); + if (c_parser_next_token_is_not (parser, CPP_CLOSE_SQUARE)) + len = c_parser_expression (parser).value; + + c_parser_skip_until_found (parser, CPP_CLOSE_SQUARE, + "expected %<]%>"); + + /* NOTE: We are reusing using the type of the whole array as the + type of the array section here, which isn't necessarily + entirely correct. Might need revisiting. */ + start = expr.get_start (); + finish = parser->tokens_buf[0].location; + expr.value = build3_loc (op_loc, OMP_ARRAY_SECTION, + TREE_TYPE (expr.value), expr.value, + idx, len); + set_c_expr_source_range (&expr, start, finish); + expr.original_code = ERROR_MARK; + expr.original_type = NULL; + } + else + { + c_parser_skip_until_found (parser, CPP_CLOSE_SQUARE, + "expected %<]%>"); + start = expr.get_start (); + finish = parser->tokens_buf[0].location; + expr.value = build_array_ref (op_loc, expr.value, idx); + set_c_expr_source_range (&expr, start, finish); + expr.original_code = ERROR_MARK; + expr.original_type = NULL; + } break; case CPP_OPEN_PAREN: /* Function call. */ @@ -12983,7 +13012,7 @@ static tree c_parser_omp_variable_list (c_parser *parser, location_t clause_loc, enum omp_clause_code kind, tree list, - bool allow_deref = false) + bool map_lvalue = false) { auto_vec tokens; unsigned int tokens_avail = 0; @@ -12993,6 +13022,8 @@ c_parser_omp_variable_list (c_parser *parser, { auto_vec dims; bool array_section_p = false; + tree t = NULL_TREE; + if (kind == OMP_CLAUSE_DEPEND || kind == OMP_CLAUSE_AFFINITY) { if (c_parser_next_token_is_not (parser, CPP_NAME) @@ -13061,8 +13092,84 @@ c_parser_omp_variable_list (c_parser *parser, parser->tokens = tokens.address (); parser->tokens_avail = tokens.length (); } + else if (map_lvalue && kind == OMP_CLAUSE_MAP) + { + location_t loc = c_parser_peek_token (parser)->location; + bool save_c_omp_array_section_p = c_omp_array_section_p; + c_omp_array_section_p = true; + c_expr expr = c_parser_expr_no_commas (parser, NULL); + if (expr.value != error_mark_node) + mark_exp_read (expr.value); + c_omp_array_section_p = save_c_omp_array_section_p; + tree decl = expr.value; - tree t = NULL_TREE; + dims.truncate (0); + if (TREE_CODE (decl) == OMP_ARRAY_SECTION) + { + while (TREE_CODE (decl) == OMP_ARRAY_SECTION) + { + tree low_bound = TREE_OPERAND (decl, 1); + tree length = TREE_OPERAND (decl, 2); + dims.safe_push (omp_dim (low_bound, length, loc, false)); + decl = TREE_OPERAND (decl, 0); + } + + while (TREE_CODE (decl) == ARRAY_REF + || TREE_CODE (decl) == INDIRECT_REF + || TREE_CODE (decl) == COMPOUND_EXPR) + { + if (TREE_CODE (decl) == COMPOUND_EXPR) + { + decl = TREE_OPERAND (decl, 1); + STRIP_NOPS (decl); + } + else if (TREE_CODE (decl) == INDIRECT_REF) + { + dims.safe_push (omp_dim (integer_zero_node, + integer_one_node, loc, true)); + decl = TREE_OPERAND (decl, 0); + } + else /* ARRAY_REF. */ + { + tree index = TREE_OPERAND (decl, 1); + dims.safe_push (omp_dim (index, integer_one_node, loc, + true)); + decl = TREE_OPERAND (decl, 0); + } + } + + for (int i = dims.length () - 1; i >= 0; i--) + decl = tree_cons (dims[i].low_bound, dims[i].length, decl); + } + else if (TREE_CODE (decl) == INDIRECT_REF) + { + /* Turn *foo into the representation previously used for + foo[0]. */ + decl = TREE_OPERAND (decl, 0); + STRIP_NOPS (decl); + + decl = tree_cons (integer_zero_node, integer_one_node, decl); + } + else if (TREE_CODE (decl) == ARRAY_REF) + { + tree idx = TREE_OPERAND (decl, 1); + + decl = TREE_OPERAND (decl, 0); + STRIP_NOPS (decl); + + decl = tree_cons (idx, integer_one_node, decl); + } + else if (TREE_CODE (decl) == NON_LVALUE_EXPR + || CONVERT_EXPR_P (decl)) + decl = TREE_OPERAND (decl, 0); + + tree u = build_omp_clause (clause_loc, kind); + OMP_CLAUSE_DECL (u) = decl; + OMP_CLAUSE_CHAIN (u) = list; + list = u; + + goto next_item; + } if (c_parser_next_token_is (parser, CPP_NAME) && c_parser_peek_token (parser)->id_kind == C_ID_ID) @@ -13113,8 +13220,7 @@ c_parser_omp_variable_list (c_parser *parser, case OMP_CLAUSE_TO: start_component_ref: while (c_parser_next_token_is (parser, CPP_DOT) - || (allow_deref - && c_parser_next_token_is (parser, CPP_DEREF))) + || c_parser_next_token_is (parser, CPP_DEREF)) { location_t op_loc = c_parser_peek_token (parser)->location; if (c_parser_next_token_is (parser, CPP_DEREF)) @@ -13201,9 +13307,7 @@ c_parser_omp_variable_list (c_parser *parser, || kind == OMP_CLAUSE_TO) && !array_section_p && (c_parser_next_token_is (parser, CPP_DOT) - || (allow_deref - && c_parser_next_token_is (parser, - CPP_DEREF)))) + || c_parser_next_token_is (parser, CPP_DEREF))) { for (unsigned i = 0; i < dims.length (); i++) { @@ -13265,6 +13369,8 @@ c_parser_omp_variable_list (c_parser *parser, parser->tokens = &parser->tokens_buf[0]; parser->tokens_avail = tokens_avail; } + + next_item: if (c_parser_next_token_is_not (parser, CPP_COMMA)) break; @@ -13281,7 +13387,7 @@ c_parser_omp_variable_list (c_parser *parser, static tree c_parser_omp_var_list_parens (c_parser *parser, enum omp_clause_code kind, - tree list, bool allow_deref = false) + tree list, bool map_lvalue = false) { /* The clauses location. */ location_t loc = c_parser_peek_token (parser)->location; @@ -13289,7 +13395,7 @@ c_parser_omp_var_list_parens (c_parser *parser, enum omp_clause_code kind, matching_parens parens; if (parens.require_open (parser)) { - list = c_parser_omp_variable_list (parser, loc, kind, list, allow_deref); + list = c_parser_omp_variable_list (parser, loc, kind, list, map_lvalue); parens.skip_until_found_close (parser); } return list; @@ -13358,7 +13464,7 @@ c_parser_oacc_data_clause (c_parser *parser, pragma_omp_clause c_kind, gcc_unreachable (); } tree nl, c; - nl = c_parser_omp_var_list_parens (parser, OMP_CLAUSE_MAP, list, true); + nl = c_parser_omp_var_list_parens (parser, OMP_CLAUSE_MAP, list); for (c = nl; c != list; c = OMP_CLAUSE_CHAIN (c)) OMP_CLAUSE_SET_MAP_KIND (c, kind); @@ -16466,7 +16572,7 @@ c_parser_omp_clause_device_type (c_parser *parser, tree list) static tree c_parser_omp_clause_to (c_parser *parser, tree list) { - return c_parser_omp_var_list_parens (parser, OMP_CLAUSE_TO, list, true); + return c_parser_omp_var_list_parens (parser, OMP_CLAUSE_TO, list); } /* OpenMP 4.0: @@ -16475,7 +16581,7 @@ c_parser_omp_clause_to (c_parser *parser, tree list) static tree c_parser_omp_clause_from (c_parser *parser, tree list) { - return c_parser_omp_var_list_parens (parser, OMP_CLAUSE_FROM, list, true); + return c_parser_omp_var_list_parens (parser, OMP_CLAUSE_FROM, list); } /* OpenMP 4.0: diff --git a/gcc/c/c-tree.h b/gcc/c/c-tree.h index f1dbbd5d573..cd76ea077b9 100644 --- a/gcc/c/c-tree.h +++ b/gcc/c/c-tree.h @@ -673,6 +673,7 @@ extern int in_alignof; extern int in_sizeof; extern int in_typeof; extern bool c_in_omp_for; +extern bool c_omp_array_section_p; extern tree c_last_sizeof_arg; extern location_t c_last_sizeof_loc; diff --git a/gcc/c/c-typeck.c b/gcc/c/c-typeck.c index 3a9f129181b..a27d5e1ef9f 100644 --- a/gcc/c/c-typeck.c +++ b/gcc/c/c-typeck.c @@ -75,6 +75,9 @@ int in_typeof; /* True when parsing OpenMP loop expressions. */ bool c_in_omp_for; +/* True when parsing OpenMP map clause. */ +bool c_omp_array_section_p; + /* The argument of last parsed sizeof expression, only to be tested if expr.original_code == SIZEOF_EXPR. */ tree c_last_sizeof_arg; @@ -2020,6 +2023,13 @@ mark_exp_read (tree exp) case C_MAYBE_CONST_EXPR: mark_exp_read (TREE_OPERAND (exp, 1)); break; + case OMP_ARRAY_SECTION: + mark_exp_read (TREE_OPERAND (exp, 0)); + if (TREE_OPERAND (exp, 1)) + mark_exp_read (TREE_OPERAND (exp, 1)); + if (TREE_OPERAND (exp, 2)) + mark_exp_read (TREE_OPERAND (exp, 2)); + break; default: break; } @@ -13228,7 +13238,9 @@ handle_omp_array_sections_1 (tree c, tree t, vec &types, t = t_insp.get_outer_virtual_base (); if (t == error_mark_node) return error_mark_node; - if (!VAR_P (t) && TREE_CODE (t) != PARM_DECL) + if (!VAR_P (t) + && (ort == C_ORT_ACC || !EXPR_P (t)) + && TREE_CODE (t) != PARM_DECL) { if (DECL_P (t)) error_at (OMP_CLAUSE_LOCATION (c), @@ -13792,6 +13804,13 @@ handle_omp_array_sections (tree c, enum c_omp_region_type ort) tree c2 = build_omp_clause (OMP_CLAUSE_LOCATION (c), OMP_CLAUSE_MAP); if (TREE_CODE (t) == COMPONENT_REF) OMP_CLAUSE_SET_MAP_KIND (c2, GOMP_MAP_ATTACH_DETACH); + else if (ort != C_ORT_ACC && attach_pt && !DECL_P (attach_pt)) + { + if (TREE_CODE (TREE_TYPE (t)) != POINTER_TYPE) + return false; + + OMP_CLAUSE_SET_MAP_KIND (c2, GOMP_MAP_ATTACH_DETACH); + } else OMP_CLAUSE_SET_MAP_KIND (c2, GOMP_MAP_FIRSTPRIVATE_POINTER); OMP_CLAUSE_MAP_IMPLICIT (c2) = OMP_CLAUSE_MAP_IMPLICIT (c); @@ -14886,6 +14905,15 @@ c_finish_omp_clauses (tree clauses, enum c_omp_region_type ort) { t = t_insp.analyze_components (false); + if (!t_insp.map_supported_p ()) + { + sorry_at (OMP_CLAUSE_LOCATION (c), + "unsupported map expression %qE", + OMP_CLAUSE_DECL (c)); + remove = true; + break; + } + if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_MAP && OMP_CLAUSE_MAP_IMPLICIT (c) && (bitmap_bit_p (&map_head, DECL_UID (t)) @@ -14936,6 +14964,9 @@ c_finish_omp_clauses (tree clauses, enum c_omp_region_type ort) } if (t == error_mark_node) { + error_at (OMP_CLAUSE_LOCATION (c), + "unmappable expression in %qs clause", + omp_clause_code_name[OMP_CLAUSE_CODE (c)]); remove = true; break; } @@ -14963,6 +14994,15 @@ c_finish_omp_clauses (tree clauses, enum c_omp_region_type ort) else t = t_insp.get_outer_virtual_base (); + if (!t_insp.map_supported_p ()) + { + sorry_at (OMP_CLAUSE_LOCATION (c), + "unsupported map expression %qE", + OMP_CLAUSE_DECL (c)); + remove = true; + break; + } + if (t == error_mark_node) { remove = true; @@ -14983,6 +15023,9 @@ c_finish_omp_clauses (tree clauses, enum c_omp_region_type ort) if (!VAR_P (t) && TREE_CODE (t) != PARM_DECL) { + if (ort != C_ORT_ACC && EXPR_P (t)) + break; + error_at (OMP_CLAUSE_LOCATION (c), "%qE is not a variable in %qs clause", t, omp_clause_code_name[OMP_CLAUSE_CODE (c)]); diff --git a/gcc/testsuite/c-c++-common/gomp/map-1.c b/gcc/testsuite/c-c++-common/gomp/map-1.c index ed88944da7b..57baa4fd285 100644 --- a/gcc/testsuite/c-c++-common/gomp/map-1.c +++ b/gcc/testsuite/c-c++-common/gomp/map-1.c @@ -39,7 +39,8 @@ foo (int g[3][10], int h[4][8], int i[2][10], int j[][9], ; #pragma omp target map(alloc: s1) /* { dg-error "'s1' does not have a mappable type in 'map' clause" } */ ; - #pragma omp target map(alloc: s2) /* { dg-error "'s2' does not have a mappable type in 'map' clause" } */ + #pragma omp target map(alloc: s2) /* { dg-error "'s2' does not have a mappable type in 'map' clause" "" { target c++ } } */ + /* { dg-error "unmappable expression in 'map' clause" "" { target c } .-1 } */ ; #pragma omp target map(to: a[:][:]) /* { dg-error "array type length expression must be specified" } */ bar (&a[0][0]); /* { dg-error "referenced in target region does not have a mappable type" } */ diff --git a/gcc/testsuite/c-c++-common/gomp/map-6.c b/gcc/testsuite/c-c++-common/gomp/map-6.c index c749db845b0..19db264e805 100644 --- a/gcc/testsuite/c-c++-common/gomp/map-6.c +++ b/gcc/testsuite/c-c++-common/gomp/map-6.c @@ -22,11 +22,13 @@ foo (void) #pragma omp target map (close a) /* { dg-error "'close' undeclared" "" { target c } } */ /* { dg-error "'close' was not declared in this scope" "" { target c++ } .-1 } */ /* { dg-error "expected '\\)' before 'a'" "" { target *-*-* } .-2 } */ + /* { dg-error "unmappable expression in 'map' clause" "" { target c } .-3 } */ ; #pragma omp target map (always a) /* { dg-error "'always' undeclared" "" { target c } } */ /* { dg-error "'always' was not declared in this scope" "" { target c++ } .-1 } */ /* { dg-error "expected '\\)' before 'a'" "" { target *-*-* } .-2 } */ + /* { dg-error "unmappable expression in 'map' clause" "" { target c } .-3 } */ ; #pragma omp target map (close to:a) diff --git a/libgomp/testsuite/libgomp.c-c++-common/ind-base-4.c b/libgomp/testsuite/libgomp.c-c++-common/ind-base-4.c new file mode 100644 index 00000000000..91549ac4d24 --- /dev/null +++ b/libgomp/testsuite/libgomp.c-c++-common/ind-base-4.c @@ -0,0 +1,50 @@ +// { dg-do run } +// { dg-options "-fopenmp" } + +#include +#include + +typedef struct +{ + int x[10]; +} S; + +typedef struct +{ + S ***s; +} T; + +typedef struct +{ + T **t; +} U; + +void +foo (void) +{ + U *u = (U *) malloc (sizeof (U)); + T *real_t = (T *) malloc (sizeof (T)); + S *real_s = (S *) malloc (sizeof (S)); + T **t_pp = &real_t; + S **s_pp = &real_s; + S ***s_ppp = &s_pp; + u->t = t_pp; + (*u->t)->s = s_ppp; + for (int i = 0; i < 10; i++) + (**((*u->t)->s))->x[i] = 0; +#pragma omp target map(u->t, *u->t, (*u->t)->s, *(*u->t)->s, **(*u->t)->s, \ + (**(*u->t)->s)->x[0:10]) + for (int i = 0; i < 10; i++) + (**((*u->t)->s))->x[i] = i * 3; + for (int i = 0; i < 10; i++) + assert ((**((*u->t)->s))->x[i] == i * 3); + free (real_s); + free (real_t); + free (u); +} + +int main (int argc, char *argv[]) +{ + foo (); + return 0; +} diff --git a/libgomp/testsuite/libgomp.c-c++-common/unary-ptr-1.c b/libgomp/testsuite/libgomp.c-c++-common/unary-ptr-1.c new file mode 100644 index 00000000000..3623b269576 --- /dev/null +++ b/libgomp/testsuite/libgomp.c-c++-common/unary-ptr-1.c @@ -0,0 +1,16 @@ +#include + +int main (int argc, char *argv[]) +{ + int y = 0; + int *x = &y; + +#pragma omp target map(*x) + { + (*x)++; + } + + assert (y == 1); + + return 0; +}