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: 48150 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 657BC385E037 for ; Thu, 25 Nov 2021 14:16:27 +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+patchwork=sourceware.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;