From patchwork Wed Dec 18 06:02:26 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Julian Brown X-Patchwork-Id: 1211978 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=209.132.180.131; helo=sourceware.org; envelope-from=gcc-patches-return-516170-incoming=patchwork.ozlabs.org@gcc.gnu.org; receiver=) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=codesourcery.com Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=gcc.gnu.org header.i=@gcc.gnu.org header.b="KYMTqEy6"; dkim-atps=neutral Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 47d4FB69pQz9sRs for ; Wed, 18 Dec 2019 17:03:26 +1100 (AEDT) DomainKey-Signature: a=rsa-sha1; c=nofws; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:from :to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding:content-type; q=dns; s= default; b=IFyX3BPRX+0TW4Ie/teyn0y0rtYUenMz/yhg3ZS+++VZK6ALHT47r g+UxX0lJZAidVSqDiKsCk0/iQwbX6Q+tI9s5i8yyExQMlQUOoJnuvO/kx8mK+8/K VvjZgL9c1HwBCJ+IX0YWh5VYtWBj19vGavSQbp6a+xU49Q95Iny7sY= DKIM-Signature: v=1; a=rsa-sha1; c=relaxed; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:from :to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding:content-type; s=default; bh=csT5Jlhm+UbOsOpQyK2fSpfFS28=; b=KYMTqEy6WlZfEaao3r/QmEoRg02K aSKwBaslEPiYYfTo+V7FQVQMJxB1S+pBwtLL/o/rpMDSVWNf26UZsrHte/CVWXUK cpmTHaM8D6iQId9YD79+gEdtYlHNM0LRpE4VN0SrCkpDii5KYfO+Aa8jXoEo54B8 azG0/sDhCyMHpHY= Received: (qmail 96368 invoked by alias); 18 Dec 2019 06:03:03 -0000 Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Delivered-To: mailing list gcc-patches@gcc.gnu.org Received: (qmail 96265 invoked by uid 89); 18 Dec 2019 06:03:02 -0000 Authentication-Results: sourceware.org; auth=none X-Spam-SWARE-Status: No, score=-23.8 required=5.0 tests=AWL, BAYES_00, GIT_PATCH_0, GIT_PATCH_1, GIT_PATCH_2, GIT_PATCH_3, KAM_SHORT autolearn=ham version=3.3.1 spammy=H*MI:sk:cover.1 X-HELO: esa1.mentor.iphmx.com Received: from esa1.mentor.iphmx.com (HELO esa1.mentor.iphmx.com) (68.232.129.153) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Wed, 18 Dec 2019 06:03:01 +0000 IronPort-SDR: 01DNeH4jRGQxtWpsTPy0cp8w2jZDdg+1BemT5SRDm47y1wXGOvcf4xT2kCWwJlHfPQ9MRMJZ3/ uYn4VdbOUVi8BF/36n9IuPcR+6dp2w+y7gNnahbg8bZ2qLnGWUuu3f0Z2D4Skeu0+uZiDc8KH+ vRddOSe7NwbCkTOM/fZ3YrNYTxiBSbw5Ese5Bh7y85pOGPl/m2tSjfe5qyBFU77RLaYvKDVEtp BZJr25LYkcNXcKiN7G8MZEMB2BjtFtKJpVcm3auqzACoLLOPWSSoAKw0h+M1bdZQt7Au6PLqS9 Qsw= Received: from orw-gwy-01-in.mentorg.com ([192.94.38.165]) by esa1.mentor.iphmx.com with ESMTP; 17 Dec 2019 22:03:00 -0800 IronPort-SDR: vCB3a84NRVeTRTobtV2XkwFmwo4i2AruBNP95NnenmU5EPI7isJKBEJqJ2s1O1QfIFUKhxszal Q5fJ4+oz7G5SApQrd3ZX11PGNd5QKo3snKFWA1d4tHvSABbsAutSiTtAb9/a7K7k5VKraXVv5g jMfDVaFi9fVk8jfACwIBRiuxaSWUTI+Js72D+clZYv2dQ987uu6/AXlLe+2bhrwFmg98RoS8nQ qT00iclz0ppLqEtXDDCAiECh5d3CS+/JDTQNisjL4DRYKpXa+11/JHX6Z1Ff/RnD2LGRTfkxDz v1s= From: Julian Brown To: CC: Thomas Schwinge , Jakub Jelinek , Tobias Burnus , , Subject: [PATCH 01/13] Use aux struct in libgomp for infrequently-used/API-specific data Date: Tue, 17 Dec 2019 22:02:26 -0800 Message-ID: <80e0dba326a4414fd2dbe8401dbd8d8f08445129.1576648001.git.julian@codesourcery.com> In-Reply-To: References: MIME-Version: 1.0 X-IsSubscribed: yes This patch has been broken out of the "OpenACC 2.6 manual deep copy support" patch, last posted here: https://gcc.gnu.org/ml/gcc-patches/2019-11/msg02376.html This part is included for completeness. It is the same as the patch posted by Thomas here: https://gcc.gnu.org/ml/gcc-patches/2019-12/msg01208.html Tested together with other patches in this series with offloading to NVPTX. OK for mainline? Thanks, Julian ChangeLog libgomp/ * libgomp.h (struct splay_tree_aux): New. (struct splay_tree_key_s): Replace link_key field with aux pointer. * target.c (gomp_map_vars_internal): Adjust for link_key being moved to aux struct. (gomp_remove_var_internal): Free aux block if present. (gomp_load_image_to_device): Zero-initialise aux field instead of link_key field. (omp_target_associate_pointer): Zero-initialise aux field. --- libgomp/libgomp.h | 10 ++++++++-- libgomp/target.c | 23 ++++++++++++++++------- 2 files changed, 24 insertions(+), 9 deletions(-) diff --git a/libgomp/libgomp.h b/libgomp/libgomp.h index 36dcca28353..0f1f11284d5 100644 --- a/libgomp/libgomp.h +++ b/libgomp/libgomp.h @@ -989,6 +989,13 @@ struct target_mem_desc { #define OFFSET_POINTER (~(uintptr_t) 1) #define OFFSET_STRUCT (~(uintptr_t) 2) +/* Auxiliary structure for infrequently-used or API-specific data. */ + +struct splay_tree_aux { + /* Pointer to the original mapping of "omp declare target link" object. */ + splay_tree_key link_key; +}; + struct splay_tree_key_s { /* Address of the host object. */ uintptr_t host_start; @@ -1002,8 +1009,7 @@ struct splay_tree_key_s { uintptr_t refcount; /* Dynamic reference count. */ uintptr_t dynamic_refcount; - /* Pointer to the original mapping of "omp declare target link" object. */ - splay_tree_key link_key; + struct splay_tree_aux *aux; }; /* The comparison function. */ diff --git a/libgomp/target.c b/libgomp/target.c index 82ed38c01ec..97c2b5c5e4d 100644 --- a/libgomp/target.c +++ b/libgomp/target.c @@ -907,13 +907,15 @@ gomp_map_vars_internal (struct gomp_device_descr *devicep, kind & typemask, cbufp); else { - k->link_key = NULL; + k->aux = NULL; if (n && n->refcount == REFCOUNT_LINK) { /* Replace target address of the pointer with target address of mapped object in the splay tree. */ splay_tree_remove (mem_map, n); - k->link_key = n; + k->aux + = gomp_malloc_cleared (sizeof (struct splay_tree_aux)); + k->aux->link_key = n; } size_t align = (size_t) 1 << (kind >> rshift); tgt->list[i].key = k; @@ -1031,7 +1033,7 @@ gomp_map_vars_internal (struct gomp_device_descr *devicep, kind); } - if (k->link_key) + if (k->aux && k->aux->link_key) { /* Set link pointer on target to the device address of the mapped object. */ @@ -1146,8 +1148,14 @@ gomp_remove_var_internal (struct gomp_device_descr *devicep, splay_tree_key k, { bool is_tgt_unmapped = false; splay_tree_remove (&devicep->mem_map, k); - if (k->link_key) - splay_tree_insert (&devicep->mem_map, (splay_tree_node) k->link_key); + if (k->aux) + { + if (k->aux->link_key) + splay_tree_insert (&devicep->mem_map, + (splay_tree_node) k->aux->link_key); + free (k->aux); + k->aux = NULL; + } if (aq) devicep->openacc.async.queue_callback_func (aq, gomp_unref_tgt_void, (void *) k->tgt); @@ -1366,7 +1374,7 @@ gomp_load_image_to_device (struct gomp_device_descr *devicep, unsigned version, k->tgt_offset = target_table[i].start; k->refcount = REFCOUNT_INFINITY; k->dynamic_refcount = 0; - k->link_key = NULL; + k->aux = NULL; array->left = NULL; array->right = NULL; splay_tree_insert (&devicep->mem_map, array); @@ -1399,7 +1407,7 @@ gomp_load_image_to_device (struct gomp_device_descr *devicep, unsigned version, k->tgt_offset = target_var->start; k->refcount = target_size & link_bit ? REFCOUNT_LINK : REFCOUNT_INFINITY; k->dynamic_refcount = 0; - k->link_key = NULL; + k->aux = NULL; array->left = NULL; array->right = NULL; splay_tree_insert (&devicep->mem_map, array); @@ -2661,6 +2669,7 @@ omp_target_associate_ptr (const void *host_ptr, const void *device_ptr, k->tgt_offset = (uintptr_t) device_ptr + device_offset; k->refcount = REFCOUNT_INFINITY; k->dynamic_refcount = 0; + k->aux = NULL; array->left = NULL; array->right = NULL; splay_tree_insert (&devicep->mem_map, array); From patchwork Wed Dec 18 06:02:27 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Julian Brown X-Patchwork-Id: 1211979 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=209.132.180.131; helo=sourceware.org; envelope-from=gcc-patches-return-516171-incoming=patchwork.ozlabs.org@gcc.gnu.org; receiver=) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=codesourcery.com Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=gcc.gnu.org header.i=@gcc.gnu.org header.b="yDS9zEv5"; dkim-atps=neutral Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 47d4Fc31Z8z9sRs for ; Wed, 18 Dec 2019 17:03:48 +1100 (AEDT) DomainKey-Signature: a=rsa-sha1; c=nofws; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:from :to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding:content-type; q=dns; s= default; b=wzUQjIvad1sk+DH+ob0Md5aV8evMUHDj4qIzQXZ06TULv8xT/e+Ng BRtkIr3qwJxkb6ZNnzkeJ7PNeu3Lxt5XQo7JBSpG8UEqIp3u5IblVNpKoLU/3n3s 3saijazZp+2E3RLyWyWO4J/b9867JfuN4ZP7DWNbqMSprKpwZaEd7M= DKIM-Signature: v=1; a=rsa-sha1; c=relaxed; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:from :to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding:content-type; s=default; bh=6z/4En2YOyelhcK2ct+uFiJaBWs=; b=yDS9zEv5hgFzztzM5qTu00e9/MRp c9SycnPOkhAQ0jFzOdva42r/jwxSpq8AfMtkTAtgWn9XaEjI+j/WX6Hxe5/9D8BV oazE1gu+ON/zwoZKFUKZRiXv0vAHCHBLh+SVt0fZzvY7iUHahUd7NjVLXvXZHuOM JQloi6RvpFk+ChM= Received: (qmail 97477 invoked by alias); 18 Dec 2019 06:03:12 -0000 Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Delivered-To: mailing list gcc-patches@gcc.gnu.org Received: (qmail 97376 invoked by uid 89); 18 Dec 2019 06:03:12 -0000 Authentication-Results: sourceware.org; auth=none X-Spam-SWARE-Status: No, score=-23.8 required=5.0 tests=AWL, BAYES_00, GIT_PATCH_0, GIT_PATCH_1, GIT_PATCH_2, GIT_PATCH_3, KAM_SHORT autolearn=ham version=3.3.1 spammy=locked, 9397, 4537, 3378 X-HELO: esa1.mentor.iphmx.com Received: from esa1.mentor.iphmx.com (HELO esa1.mentor.iphmx.com) (68.232.129.153) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Wed, 18 Dec 2019 06:03:06 +0000 IronPort-SDR: Zup6xDftxT3er4DDFEB8oON3DP0Ud0aVIT7Bg+1+arFqZ8Inwit8SRMpjwyDiht/UjI5aRGjd4 sGQU58x1+TfP/OI63TMIbljd798h7XOx2N8GwCRddrUcAWodN3d1eN2faf86DmLZHG7wscbhKN NbV9K8WsBGSpxmdsYESL+DtgHnRyzL2YMMQ/bHm9EnqmksW5b5xVfNnsA4c+Qvy+E/LwZHgERM ezaNLzD2sRv0TlBQocDpjYMIa18M3iI2TU+iTj4V4gGIsvUTJY1WgGK02oqEeijojYQ0JW9n0D A3Q= Received: from orw-gwy-01-in.mentorg.com ([192.94.38.165]) by esa1.mentor.iphmx.com with ESMTP; 17 Dec 2019 22:03:04 -0800 IronPort-SDR: J7xdfArSsVz3URfvFCVan1LOk4CVACWpb3Q7uITyurlEztCC2CoCUSTztkCU4HDhC7gsi2dAbx 6o39V/YeWM8rax1t+z9XziiI/k6BoEPAVIZxj/U57za2MO2taqVyguoB2p6raOX35dkaoim1Zs QKbll/l13XeebwbRXNbN+JlSbdrKs2xaz/u/nQEJJVFo3ZrweCOxtGXjBWA4UfHpCmpycmbKq4 561UZtIbSRGxtX6n/iI1Hgzj+C91GXjQKHN+bf3KYlkfLiBVOrOXr//HvhS/5MDiigXIk6cOtj uCM= From: Julian Brown To: CC: Thomas Schwinge , Jakub Jelinek , Tobias Burnus , , Subject: [PATCH 02/13] OpenACC reference count overhaul Date: Tue, 17 Dec 2019 22:02:27 -0800 Message-ID: <491e3ca360313930f8f2f5686ffd386cf2fad04e.1576648001.git.julian@codesourcery.com> In-Reply-To: References: MIME-Version: 1.0 X-IsSubscribed: yes This is a rebased version of the reference-count overhaul patch last posted here: https://gcc.gnu.org/ml/gcc-patches/2019-11/msg02235.html This version omits parts of the above patch already committed upstream and merges some recent REFCOUNT_INFINITY changes. This patch causes the newish PR92843 test to fail, though IMO that test relies on behaviour arising from a rather nuanced reading of the spec. Hopefully we can resolve that problem as a follow-up. Tested alongside other patches in this series with offloading to NVPTX. OK? Julian 2019-11-22 Julian Brown Thomas Schwinge libgomp/ * libgomp.h (struct splay_tree_key_s): Substitute dynamic_refcount field for virtual_refcount. (enum gomp_map_vars_kind): Add GOMP_MAP_VARS_OPENACC_ENTER_DATA. (gomp_free_memmap): Remove prototype. * oacc-init.c (acc_shutdown_1): Iteratively call gomp_remove_var instead of calling gomp_free_memmap. * oacc-mem.c (acc_unmap_data): Open code instead of forcing target_mem_desc's to_free NULL then calling gomp_unmap_vars. Handle REFCOUNT_INFINITY on target blocks. (present_create_copy): Use virtual_refcount instead of dynamic_refcount. Re-do lookup for target pointer return value. (delete_copyout): Update for virtual_refcount semantics. (gomp_acc_insert_pointer, gomp_acc_remove_pointer, find_pointer): Remove functions. (find_group_last, goacc_enter_data_internal, goacc_exit_data_internal): New functions. (GOACC_enter_exit_data): Use goacc_enter_data_internal and goacc_exit_data_internal helper functions. * target.c (gomp_map_vars_internal): Handle GOMP_MAP_VARS_OPENACC_ENTER_DATA. Update for virtual_refcount semantics. (gomp_unmap_vars_internal): Update for virtual_refcount semantics. (gomp_load_image_to_device, omp_target_associate_ptr): Zero-initialise virtual_refcount field instead of dynamic_refcount. (gomp_free_memmap): Remove function. * testsuite/libgomp.oacc-c-c++-common/unmap-infinity-1.c: New test. * testsuite/libgomp.c-c++-common/unmap-infinity-2.c: New test. * testsuite/libgomp.oacc-c-c++-common/subset-subarray-mappings-1-r-p.c: Remove PR92848 TODOs. * testsuite/libgomp.oacc-c-c++-common/pr92843-1.c: Add XFAIL. --- libgomp/libgomp.h | 9 +- libgomp/oacc-init.c | 10 +- libgomp/oacc-mem.c | 399 +++++++----------- libgomp/target.c | 53 +-- .../libgomp.c-c++-common/unmap-infinity-2.c | 19 + .../libgomp.oacc-c-c++-common/pr92843-1.c | 1 + .../subset-subarray-mappings-1-r-p.c | 16 - .../unmap-infinity-1.c | 17 + 8 files changed, 228 insertions(+), 296 deletions(-) create mode 100644 libgomp/testsuite/libgomp.c-c++-common/unmap-infinity-2.c create mode 100644 libgomp/testsuite/libgomp.oacc-c-c++-common/unmap-infinity-1.c diff --git a/libgomp/libgomp.h b/libgomp/libgomp.h index 0f1f11284d5..865b9df2444 100644 --- a/libgomp/libgomp.h +++ b/libgomp/libgomp.h @@ -1007,8 +1007,11 @@ struct splay_tree_key_s { uintptr_t tgt_offset; /* Reference count. */ uintptr_t refcount; - /* Dynamic reference count. */ - uintptr_t dynamic_refcount; + /* Reference counts beyond those that represent genuine references in the + linked splay tree key/target memory structures, e.g. for multiple OpenACC + "present increment" operations (via "acc enter data") referring to the same + host-memory block. */ + uintptr_t virtual_refcount; struct splay_tree_aux *aux; }; @@ -1139,6 +1142,7 @@ struct gomp_device_descr enum gomp_map_vars_kind { GOMP_MAP_VARS_OPENACC, + GOMP_MAP_VARS_OPENACC_ENTER_DATA, GOMP_MAP_VARS_TARGET, GOMP_MAP_VARS_DATA, GOMP_MAP_VARS_ENTER_DATA @@ -1169,7 +1173,6 @@ extern void gomp_unmap_vars_async (struct target_mem_desc *, bool, struct goacc_asyncqueue *); extern void gomp_init_device (struct gomp_device_descr *); extern bool gomp_fini_device (struct gomp_device_descr *); -extern void gomp_free_memmap (struct splay_tree_s *); extern void gomp_unload_device (struct gomp_device_descr *); extern bool gomp_remove_var (struct gomp_device_descr *, splay_tree_key); extern void gomp_remove_var_async (struct gomp_device_descr *, splay_tree_key, diff --git a/libgomp/oacc-init.c b/libgomp/oacc-init.c index a444c604d59..dd88b58a379 100644 --- a/libgomp/oacc-init.c +++ b/libgomp/oacc-init.c @@ -370,7 +370,15 @@ acc_shutdown_1 (acc_device_t d) if (walk->dev) { gomp_mutex_lock (&walk->dev->lock); - gomp_free_memmap (&walk->dev->mem_map); + + while (walk->dev->mem_map.root) + { + splay_tree_key k = &walk->dev->mem_map.root->key; + if (k->aux) + k->aux->link_key = NULL; + gomp_remove_var (walk->dev, k); + } + gomp_mutex_unlock (&walk->dev->lock); walk->dev = NULL; diff --git a/libgomp/oacc-mem.c b/libgomp/oacc-mem.c index 196b7e2a520..2a0e7236b92 100644 --- a/libgomp/oacc-mem.c +++ b/libgomp/oacc-mem.c @@ -406,7 +406,7 @@ acc_map_data (void *h, void *d, size_t s) &kinds, true, GOMP_MAP_VARS_OPENACC); splay_tree_key n = tgt->list[0].key; assert (n->refcount == 1); - assert (n->dynamic_refcount == 0); + assert (n->virtual_refcount == 0); /* Special reference counting behavior. */ n->refcount = REFCOUNT_INFINITY; @@ -434,12 +434,9 @@ acc_unmap_data (void *h) acc_api_info api_info; bool profiling_p = GOACC_PROFILING_SETUP_P (thr, &prof_info, &api_info); - size_t host_size; - gomp_mutex_lock (&acc_dev->lock); splay_tree_key n = lookup_host (acc_dev, h, 1); - struct target_mem_desc *t; if (!n) { @@ -447,7 +444,7 @@ acc_unmap_data (void *h) gomp_fatal ("%p is not a mapped block", (void *)h); } - host_size = n->host_end - n->host_start; + size_t host_size = n->host_end - n->host_start; if (n->host_start != (uintptr_t) h) { @@ -456,7 +453,7 @@ acc_unmap_data (void *h) (void *) n->host_start, (int) host_size, (void *) h); } /* TODO This currently doesn't catch 'REFCOUNT_INFINITY' usage different from - 'acc_map_data'. Maybe 'dynamic_refcount' can be used for disambiguating + 'acc_map_data'. Maybe 'virtual_refcount' can be used for disambiguating the different 'REFCOUNT_INFINITY' cases, or simply separate 'REFCOUNT_INFINITY' values per different usage ('REFCOUNT_ACC_MAP_DATA' etc.)? */ @@ -468,24 +465,25 @@ acc_unmap_data (void *h) (void *) h, (int) host_size); } - /* Mark for removal. */ - n->refcount = 1; + splay_tree_remove (&acc_dev->mem_map, n); - t = n->tgt; + struct target_mem_desc *tgt = n->tgt; - if (t->refcount == 2) + if (tgt->refcount == REFCOUNT_INFINITY) { - /* This is the last reference, so pull the descriptor off the - chain. This avoids gomp_unmap_vars via gomp_unmap_tgt from - freeing the device memory. */ - t->tgt_end = 0; - t->to_free = 0; + gomp_mutex_unlock (&acc_dev->lock); + gomp_fatal ("cannot unmap target block"); + } + else if (tgt->refcount > 1) + tgt->refcount--; + else + { + free (tgt->array); + free (tgt); } gomp_mutex_unlock (&acc_dev->lock); - gomp_unmap_vars (t, true); - if (profiling_p) { thr->prof_info = NULL; @@ -545,8 +543,10 @@ present_create_copy (unsigned f, void *h, size_t s, int async) assert (n->refcount != REFCOUNT_LINK); if (n->refcount != REFCOUNT_INFINITY) - n->refcount++; - n->dynamic_refcount++; + { + n->refcount++; + n->virtual_refcount++; + } gomp_mutex_unlock (&acc_dev->lock); } @@ -557,7 +557,6 @@ present_create_copy (unsigned f, void *h, size_t s, int async) } else { - struct target_mem_desc *tgt; size_t mapnum = 1; unsigned short kinds; void *hostaddrs = h; @@ -571,14 +570,16 @@ present_create_copy (unsigned f, void *h, size_t s, int async) goacc_aq aq = get_goacc_asyncqueue (async); - tgt = gomp_map_vars_async (acc_dev, aq, mapnum, &hostaddrs, NULL, &s, - &kinds, true, GOMP_MAP_VARS_OPENACC); - n = tgt->list[0].key; - assert (n->refcount == 1); - assert (n->dynamic_refcount == 0); - n->dynamic_refcount++; + gomp_map_vars_async (acc_dev, aq, mapnum, &hostaddrs, NULL, &s, &kinds, + true, GOMP_MAP_VARS_OPENACC_ENTER_DATA); - d = tgt->to_free; + gomp_mutex_lock (&acc_dev->lock); + n = lookup_host (acc_dev, h, s); + assert (n != NULL); + assert (n->tgt_offset == 0); + assert ((uintptr_t) h == n->host_start); + d = (void *) n->tgt->tgt_start; + gomp_mutex_unlock (&acc_dev->lock); } if (profiling_p) @@ -696,26 +697,21 @@ delete_copyout (unsigned f, void *h, size_t s, int async, const char *libfnname) (void *) h, (int) s, (void *) n->host_start, (int) host_size); } - assert (n->refcount != REFCOUNT_LINK); - if (n->refcount != REFCOUNT_INFINITY - && n->refcount < n->dynamic_refcount) - { - gomp_mutex_unlock (&acc_dev->lock); - gomp_fatal ("Dynamic reference counting assert fail\n"); - } - if (f & FLAG_FINALIZE) { if (n->refcount != REFCOUNT_INFINITY) - n->refcount -= n->dynamic_refcount; - n->dynamic_refcount = 0; + n->refcount -= n->virtual_refcount; + n->virtual_refcount = 0; } - else if (n->dynamic_refcount) + + if (n->virtual_refcount > 0) { if (n->refcount != REFCOUNT_INFINITY) n->refcount--; - n->dynamic_refcount--; + n->virtual_refcount--; } + else if (n->refcount > 0 && n->refcount != REFCOUNT_INFINITY) + n->refcount--; if (n->refcount == 0) { @@ -870,154 +866,138 @@ acc_update_self_async (void *h, size_t s, int async) update_dev_host (0, h, s, async); } +/* Some types of (pointer) variables use several consecutive mappings, which + must be treated as a group for enter/exit data directives. This function + returns the last mapping in such a group (inclusive), or POS for singleton + mappings. */ -/* OpenACC 'enter data', 'exit data': 'GOACC_enter_exit_data' and its helper - functions. */ - -/* Special handling for 'GOMP_MAP_POINTER', 'GOMP_MAP_TO_PSET'. - - Only the first mapping is considered in reference counting; the following - ones implicitly follow suit. */ - -static void -goacc_insert_pointer (size_t mapnum, void **hostaddrs, size_t *sizes, - void *kinds, int async) +static int +find_group_last (int pos, size_t mapnum, unsigned short *kinds) { - struct target_mem_desc *tgt; - struct goacc_thread *thr = goacc_thread (); - struct gomp_device_descr *acc_dev = thr->dev; - - if (*hostaddrs == NULL) - return; + unsigned char kind0 = kinds[pos] & 0xff; + int first_pos = pos, last_pos = pos; - if (acc_is_present (*hostaddrs, *sizes)) + if (kind0 == GOMP_MAP_TO_PSET) { - splay_tree_key n; - gomp_mutex_lock (&acc_dev->lock); - n = lookup_host (acc_dev, *hostaddrs, *sizes); - assert (n->refcount != REFCOUNT_INFINITY - && n->refcount != REFCOUNT_LINK); - gomp_mutex_unlock (&acc_dev->lock); - - tgt = n->tgt; - for (size_t i = 0; i < tgt->list_count; i++) - if (tgt->list[i].key == n) - { - for (size_t j = 0; j < mapnum; j++) - if (i + j < tgt->list_count && tgt->list[i + j].key) - { - tgt->list[i + j].key->refcount++; - tgt->list[i + j].key->dynamic_refcount++; - } - return; - } - /* Should not reach here. */ - gomp_fatal ("Dynamic refcount incrementing failed for pointer/pset"); + while (pos + 1 < mapnum && (kinds[pos + 1] & 0xff) == GOMP_MAP_POINTER) + last_pos = ++pos; + /* We expect at least one GOMP_MAP_POINTER after a GOMP_MAP_TO_PSET. */ + assert (last_pos > first_pos); + } + else + { + /* GOMP_MAP_ALWAYS_POINTER can only appear directly after some other + mapping. */ + if (pos + 1 < mapnum + && (kinds[pos + 1] & 0xff) == GOMP_MAP_ALWAYS_POINTER) + return pos + 1; + + /* We can have one or several GOMP_MAP_POINTER mappings after a to/from + (etc.) mapping. */ + while (pos + 1 < mapnum && (kinds[pos + 1] & 0xff) == GOMP_MAP_POINTER) + last_pos = ++pos; } - gomp_debug (0, " %s: prepare mappings\n", __FUNCTION__); - goacc_aq aq = get_goacc_asyncqueue (async); - tgt = gomp_map_vars_async (acc_dev, aq, mapnum, hostaddrs, - NULL, sizes, kinds, true, GOMP_MAP_VARS_OPENACC); - splay_tree_key n = tgt->list[0].key; - assert (n->refcount == 1); - assert (n->dynamic_refcount == 0); - n->dynamic_refcount++; - gomp_debug (0, " %s: mappings prepared\n", __FUNCTION__); + return last_pos; } +/* Map variables for OpenACC "enter data". We can't just call + gomp_map_vars_async once, because individual mapped variables might have + "exit data" called for them at different times. */ + static void -goacc_remove_pointer (void *h, size_t s, bool force_copyfrom, int async, - int finalize, int mapnum) +goacc_enter_data_internal (struct gomp_device_descr *acc_dev, size_t mapnum, + void **hostaddrs, size_t *sizes, + unsigned short *kinds, goacc_aq aq) { - struct goacc_thread *thr = goacc_thread (); - struct gomp_device_descr *acc_dev = thr->dev; - splay_tree_key n; - struct target_mem_desc *t; - int minrefs = (mapnum == 1) ? 2 : 3; - - if (!acc_is_present (h, s)) - return; - - gomp_mutex_lock (&acc_dev->lock); - - n = lookup_host (acc_dev, h, 1); - - if (!n) + for (size_t i = 0; i < mapnum; i++) { - gomp_mutex_unlock (&acc_dev->lock); - gomp_fatal ("%p is not a mapped block", (void *)h); - } - - gomp_debug (0, " %s: restore mappings\n", __FUNCTION__); + int group_last = find_group_last (i, mapnum, kinds); - t = n->tgt; + gomp_map_vars_async (acc_dev, aq, + (group_last - i) + 1, + &hostaddrs[i], NULL, + &sizes[i], &kinds[i], true, + GOMP_MAP_VARS_OPENACC_ENTER_DATA); - assert (n->refcount != REFCOUNT_INFINITY - && n->refcount != REFCOUNT_LINK); - if (n->refcount < n->dynamic_refcount) - { - gomp_mutex_unlock (&acc_dev->lock); - gomp_fatal ("Dynamic reference counting assert fail\n"); + i = group_last; } +} - if (finalize) - { - n->refcount -= n->dynamic_refcount; - n->dynamic_refcount = 0; - } - else if (n->dynamic_refcount) - { - n->refcount--; - n->dynamic_refcount--; - } +/* Unmap variables for OpenACC "exit data", with optional finalization + (affecting all mappings in this operation). */ - gomp_mutex_unlock (&acc_dev->lock); +static void +goacc_exit_data_internal (struct gomp_device_descr *acc_dev, size_t mapnum, + void **hostaddrs, size_t *sizes, + unsigned short *kinds, bool finalize, goacc_aq aq) +{ + gomp_mutex_lock (&acc_dev->lock); - if (n->refcount == 0) + for (size_t i = 0; i < mapnum; ++i) { - /* Set refcount to 1 to allow gomp_unmap_vars to unmap it. */ - n->refcount = 1; - t->refcount = minrefs; - for (size_t i = 0; i < t->list_count; i++) - if (t->list[i].key == n) - { - t->list[i].copy_from = force_copyfrom ? 1 : 0; - break; - } + unsigned char kind = kinds[i] & 0xff; + bool copyfrom = false; - /* If running synchronously, unmap immediately. */ - if (async < acc_async_noval) - gomp_unmap_vars (t, true); - else + switch (kind) { - goacc_aq aq = get_goacc_asyncqueue (async); - gomp_unmap_vars_async (t, true, aq); + case GOMP_MAP_FROM: + case GOMP_MAP_FORCE_FROM: + case GOMP_MAP_ALWAYS_FROM: + copyfrom = true; + /* Fallthrough. */ + + case GOMP_MAP_TO_PSET: + case GOMP_MAP_POINTER: + case GOMP_MAP_DELETE: + case GOMP_MAP_RELEASE: + { + struct splay_tree_key_s cur_node; + cur_node.host_start = (uintptr_t) hostaddrs[i]; + cur_node.host_end = cur_node.host_start + + (kind == GOMP_MAP_POINTER + ? sizeof (void *) : sizes[i]); + splay_tree_key n + = splay_tree_lookup (&acc_dev->mem_map, &cur_node); + + if (n == NULL) + continue; + + if (finalize) + { + if (n->refcount != REFCOUNT_INFINITY) + n->refcount -= n->virtual_refcount; + n->virtual_refcount = 0; + } + + if (n->virtual_refcount > 0) + { + if (n->refcount != REFCOUNT_INFINITY) + n->refcount--; + n->virtual_refcount--; + } + else if (n->refcount > 0 && n->refcount != REFCOUNT_INFINITY) + n->refcount--; + + if (copyfrom + && (kind != GOMP_MAP_FROM || n->refcount == 0)) + gomp_copy_dev2host (acc_dev, aq, (void *) cur_node.host_start, + (void *) (n->tgt->tgt_start + n->tgt_offset + + cur_node.host_start + - n->host_start), + cur_node.host_end - cur_node.host_start); + + if (n->refcount == 0) + gomp_remove_var_async (acc_dev, n, aq); + } + break; + default: + gomp_fatal (">>>> goacc_exit_data_internal UNHANDLED kind 0x%.2x", + kind); } } gomp_mutex_unlock (&acc_dev->lock); - - gomp_debug (0, " %s: mappings restored\n", __FUNCTION__); -} - -/* Return the number of mappings associated with 'GOMP_MAP_TO_PSET' or - 'GOMP_MAP_POINTER'. */ - -static int -find_pointer (int pos, size_t mapnum, unsigned short *kinds) -{ - if (pos + 1 >= mapnum) - return 0; - - unsigned char kind = kinds[pos+1] & 0xff; - - if (kind == GOMP_MAP_TO_PSET) - return 3; - else if (kind == GOMP_MAP_POINTER) - return 2; - - return 0; } void @@ -1147,98 +1127,13 @@ GOACC_enter_exit_data (int flags_m, size_t mapnum, void **hostaddrs, va_end (ap); } - /* In c, non-pointers and arrays are represented by a single data clause. - Dynamically allocated arrays and subarrays are represented by a data - clause followed by an internal GOMP_MAP_POINTER. - - In fortran, scalars and not allocated arrays are represented by a - single data clause. Allocated arrays and subarrays have three mappings: - 1) the original data clause, 2) a PSET 3) a pointer to the array data. - */ + goacc_aq aq = get_goacc_asyncqueue (async); if (data_enter) - { - for (i = 0; i < mapnum; i++) - { - unsigned char kind = kinds[i] & 0xff; - - /* Scan for pointers and PSETs. */ - int pointer = find_pointer (i, mapnum, kinds); - - if (!pointer) - { - switch (kind) - { - case GOMP_MAP_ALLOC: - case GOMP_MAP_FORCE_ALLOC: - acc_create_async (hostaddrs[i], sizes[i], async); - break; - case GOMP_MAP_TO: - case GOMP_MAP_FORCE_TO: - acc_copyin_async (hostaddrs[i], sizes[i], async); - break; - default: - gomp_fatal (">>>> GOACC_enter_exit_data UNHANDLED kind 0x%.2x", - kind); - break; - } - } - else - { - goacc_insert_pointer (pointer, &hostaddrs[i], &sizes[i], &kinds[i], - async); - /* Increment 'i' by two because OpenACC requires fortran - arrays to be contiguous, so each PSET is associated with - one of MAP_FORCE_ALLOC/MAP_FORCE_PRESET/MAP_FORCE_TO, and - one MAP_POINTER. */ - i += pointer - 1; - } - } - } + goacc_enter_data_internal (acc_dev, mapnum, hostaddrs, sizes, kinds, aq); else - for (i = 0; i < mapnum; ++i) - { - unsigned char kind = kinds[i] & 0xff; - - int pointer = find_pointer (i, mapnum, kinds); - - if (!pointer) - { - switch (kind) - { - case GOMP_MAP_RELEASE: - case GOMP_MAP_DELETE: - if (acc_is_present (hostaddrs[i], sizes[i])) - { - if (finalize) - acc_delete_finalize_async (hostaddrs[i], sizes[i], async); - else - acc_delete_async (hostaddrs[i], sizes[i], async); - } - break; - case GOMP_MAP_FROM: - case GOMP_MAP_FORCE_FROM: - if (finalize) - acc_copyout_finalize_async (hostaddrs[i], sizes[i], async); - else - acc_copyout_async (hostaddrs[i], sizes[i], async); - break; - default: - gomp_fatal (">>>> GOACC_enter_exit_data UNHANDLED kind 0x%.2x", - kind); - break; - } - } - else - { - bool copyfrom = (kind == GOMP_MAP_FORCE_FROM - || kind == GOMP_MAP_FROM); - goacc_remove_pointer (hostaddrs[i], sizes[i], copyfrom, async, - finalize, pointer); - /* See the above comment. */ - i += pointer - 1; - } - } + goacc_exit_data_internal (acc_dev, mapnum, hostaddrs, sizes, kinds, + finalize, aq); out_prof: if (profiling_p) diff --git a/libgomp/target.c b/libgomp/target.c index 97c2b5c5e4d..23f9e1618ca 100644 --- a/libgomp/target.c +++ b/libgomp/target.c @@ -536,8 +536,10 @@ gomp_map_vars_internal (struct gomp_device_descr *devicep, struct target_mem_desc *tgt = gomp_malloc (sizeof (*tgt) + sizeof (tgt->list[0]) * mapnum); tgt->list_count = mapnum; - tgt->refcount = pragma_kind == GOMP_MAP_VARS_ENTER_DATA ? 0 : 1; + tgt->refcount = (pragma_kind == GOMP_MAP_VARS_ENTER_DATA + || pragma_kind == GOMP_MAP_VARS_OPENACC_ENTER_DATA) ? 0 : 1; tgt->device_descr = devicep; + tgt->prev = NULL; struct gomp_coalesce_buf cbuf, *cbufp = NULL; if (mapnum == 0) @@ -939,7 +941,7 @@ gomp_map_vars_internal (struct gomp_device_descr *devicep, tgt->list[i].offset = 0; tgt->list[i].length = k->host_end - k->host_start; k->refcount = 1; - k->dynamic_refcount = 0; + k->virtual_refcount = 0; tgt->refcount++; array->left = NULL; array->right = NULL; @@ -1077,8 +1079,20 @@ gomp_map_vars_internal (struct gomp_device_descr *devicep, /* If the variable from "omp target enter data" map-list was already mapped, tgt is not needed. Otherwise tgt will be freed by gomp_unmap_vars or gomp_exit_data. */ - if (pragma_kind == GOMP_MAP_VARS_ENTER_DATA && tgt->refcount == 0) - { + if ((pragma_kind == GOMP_MAP_VARS_ENTER_DATA + || pragma_kind == GOMP_MAP_VARS_OPENACC_ENTER_DATA) + && tgt->refcount == 0) + { + /* If we're about to discard a target_mem_desc with no "structural" + references (tgt->refcount == 0), any splay keys linked in the tgt's + list must have their virtual refcount incremented to represent that + "lost" reference in order to implement the semantics of the OpenACC + "present increment" operation properly. */ + if (pragma_kind == GOMP_MAP_VARS_OPENACC_ENTER_DATA) + for (i = 0; i < tgt->list_count; i++) + if (tgt->list[i].key) + tgt->list[i].key->virtual_refcount++; + free (tgt); tgt = NULL; } @@ -1216,7 +1230,14 @@ gomp_unmap_vars_internal (struct target_mem_desc *tgt, bool do_copyfrom, continue; bool do_unmap = false; - if (k->refcount > 1 && k->refcount != REFCOUNT_INFINITY) + if (k->tgt == tgt + && k->virtual_refcount > 0 + && k->refcount != REFCOUNT_INFINITY) + { + k->virtual_refcount--; + k->refcount--; + } + else if (k->refcount > 1 && k->refcount != REFCOUNT_INFINITY) k->refcount--; else if (k->refcount == 1) { @@ -1373,7 +1394,7 @@ gomp_load_image_to_device (struct gomp_device_descr *devicep, unsigned version, k->tgt = tgt; k->tgt_offset = target_table[i].start; k->refcount = REFCOUNT_INFINITY; - k->dynamic_refcount = 0; + k->virtual_refcount = 0; k->aux = NULL; array->left = NULL; array->right = NULL; @@ -1406,7 +1427,7 @@ gomp_load_image_to_device (struct gomp_device_descr *devicep, unsigned version, k->tgt = tgt; k->tgt_offset = target_var->start; k->refcount = target_size & link_bit ? REFCOUNT_LINK : REFCOUNT_INFINITY; - k->dynamic_refcount = 0; + k->virtual_refcount = 0; k->aux = NULL; array->left = NULL; array->right = NULL; @@ -1641,22 +1662,6 @@ gomp_unload_device (struct gomp_device_descr *devicep) } } -/* Free address mapping tables. MM must be locked on entry, and remains locked - on return. */ - -attribute_hidden void -gomp_free_memmap (struct splay_tree_s *mem_map) -{ - while (mem_map->root) - { - struct target_mem_desc *tgt = mem_map->root->key.tgt; - - splay_tree_remove (mem_map, &mem_map->root->key); - free (tgt->array); - free (tgt); - } -} - /* Host fallback for GOMP_target{,_ext} routines. */ static void @@ -2668,7 +2673,7 @@ omp_target_associate_ptr (const void *host_ptr, const void *device_ptr, k->tgt = tgt; k->tgt_offset = (uintptr_t) device_ptr + device_offset; k->refcount = REFCOUNT_INFINITY; - k->dynamic_refcount = 0; + k->virtual_refcount = 0; k->aux = NULL; array->left = NULL; array->right = NULL; diff --git a/libgomp/testsuite/libgomp.c-c++-common/unmap-infinity-2.c b/libgomp/testsuite/libgomp.c-c++-common/unmap-infinity-2.c new file mode 100644 index 00000000000..3931c5aba25 --- /dev/null +++ b/libgomp/testsuite/libgomp.c-c++-common/unmap-infinity-2.c @@ -0,0 +1,19 @@ +int foo[16]; +#pragma omp declare target (foo) + +__attribute__((used)) void bar (void) +{ + #pragma omp target parallel for + for (int i = 0; i < 16; i++) + foo[i] = i; +} + +int +main (int argc, char *argv[]) +{ + int *foo_copy = foo; + /* Try to trigger the unmapping of a REFCOUNT_INFINITY target block. This + does nothing at the time of writing. */ + #pragma omp target exit data map(delete: foo_copy[0:16]) + return 0; +} diff --git a/libgomp/testsuite/libgomp.oacc-c-c++-common/pr92843-1.c b/libgomp/testsuite/libgomp.oacc-c-c++-common/pr92843-1.c index db5b35b08d9..f16c46a37bf 100644 --- a/libgomp/testsuite/libgomp.oacc-c-c++-common/pr92843-1.c +++ b/libgomp/testsuite/libgomp.oacc-c-c++-common/pr92843-1.c @@ -1,6 +1,7 @@ /* Verify that 'acc_copyout' etc. is a no-op if there's still a structured reference count. */ +/* { dg-xfail-run-if "TODO PR92843" { *-*-* } } */ /* { dg-skip-if "" { *-*-* } { "*" } { "-DACC_MEM_SHARED=0" } } */ #include diff --git a/libgomp/testsuite/libgomp.oacc-c-c++-common/subset-subarray-mappings-1-r-p.c b/libgomp/testsuite/libgomp.oacc-c-c++-common/subset-subarray-mappings-1-r-p.c index 9b5d83c66dd..907b8587773 100644 --- a/libgomp/testsuite/libgomp.oacc-c-c++-common/subset-subarray-mappings-1-r-p.c +++ b/libgomp/testsuite/libgomp.oacc-c-c++-common/subset-subarray-mappings-1-r-p.c @@ -156,20 +156,16 @@ f1 (void) assert (acc_is_present (&myblock[i], SUBSET)); assert (acc_is_present (myblock, SIZE)); -#if 0 //TODO PR92848 if (last) cb_ev_free_expected = true; -#endif #if OPENACC_RUNTIME acc_delete (&myblock[i], SUBSET); #else # pragma acc exit data delete (myblock[i:SUBSET]) #endif -#if 0 //TODO PR92848 assert (!cb_ev_free_expected); if (last) assert (cb_ev_free_device_ptr == cb_ev_alloc_device_ptr); -#endif assert (acc_is_present (&myblock[i], SUBSET) != last); assert (acc_is_present (myblock, SIZE) != last); } @@ -331,9 +327,7 @@ f3 () assert (acc_is_present (h, SIZE)); assert (acc_is_present (&h[2], SIZE - 2)); -#if 0 //TODO PR92848 cb_ev_free_expected = true; -#endif #if OPENACC_RUNTIME acc_delete (h, SIZE); #else @@ -343,10 +337,8 @@ f3 () # pragma acc exit data delete (h) # endif #endif -#if 0 //TODO PR92848 assert (!cb_ev_free_expected); assert (cb_ev_free_device_ptr == cb_ev_alloc_device_ptr); -#endif assert (!acc_is_present (h, SIZE)); assert (!acc_is_present (&h[2], SIZE - 2)); @@ -401,19 +393,15 @@ f_lib_22 (void) memset (h, c1, SIZE); /* Now 'copyout' not the whole but only a "subset" subarray, missing one SUBSET at the beginning, and half a SUBSET at the end... */ -#if 0 //TODO PR92848 cb_ev_free_expected = true; -#endif #if OPENACC_RUNTIME acc_copyout (h + SUBSET, SIZE - SUBSET - SUBSET / 2); #else # pragma acc exit data copyout (h[SUBSET:SIZE - SUBSET - SUBSET / 2]) #endif -#if 0 //TODO PR92848 /* ..., yet, expect the device memory object to be 'free'd... */ assert (!cb_ev_free_expected); assert (cb_ev_free_device_ptr == cb_ev_alloc_device_ptr); -#endif /* ..., and the mapping to be removed... */ assert (!acc_is_present (h, SIZE)); assert (!acc_is_present (&h[SUBSET], SIZE - SUBSET - SUBSET / 2)); @@ -474,19 +462,15 @@ f_lib_30 (void) assert (aligned_address (cb_ev_alloc_device_ptr) == d); /* We 'delete' not the whole but only a "subset" subarray... */ -#if 0 //TODO PR92848 cb_ev_free_expected = true; -#endif #if OPENACC_RUNTIME acc_delete (h, SIZE - SUBSET); #else # pragma acc exit data delete (h[0:SIZE - SUBSET]) #endif -#if 0 //TODO PR92848 /* ..., yet, expect the device memory object to be 'free'd... */ assert (!cb_ev_free_expected); assert (cb_ev_free_device_ptr == cb_ev_alloc_device_ptr); -#endif /* ..., and the mapping to be removed. */ assert (!acc_is_present (h, SIZE)); assert (!acc_is_present (h, SIZE - SUBSET)); diff --git a/libgomp/testsuite/libgomp.oacc-c-c++-common/unmap-infinity-1.c b/libgomp/testsuite/libgomp.oacc-c-c++-common/unmap-infinity-1.c new file mode 100644 index 00000000000..872f0c1de5c --- /dev/null +++ b/libgomp/testsuite/libgomp.oacc-c-c++-common/unmap-infinity-1.c @@ -0,0 +1,17 @@ +/* { dg-skip-if "" { *-*-* } { "*" } { "-DACC_MEM_SHARED=0" } } */ + +#include + +int foo[16]; +#pragma acc declare device_resident(foo) + +int +main (int argc, char *argv[]) +{ + acc_init (acc_device_default); + acc_unmap_data ((void *) foo); +/* { dg-output "libgomp: cannot unmap target block" } */ + return 0; +} + +/* { dg-shouldfail "" } */ From patchwork Wed Dec 18 06:02:28 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Julian Brown X-Patchwork-Id: 1211980 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=209.132.180.131; helo=sourceware.org; envelope-from=gcc-patches-return-516172-incoming=patchwork.ozlabs.org@gcc.gnu.org; receiver=) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=codesourcery.com Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=gcc.gnu.org header.i=@gcc.gnu.org header.b="mWF5ygFZ"; dkim-atps=neutral Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 47d4Fx6GWfz9sS6 for ; Wed, 18 Dec 2019 17:04:05 +1100 (AEDT) DomainKey-Signature: a=rsa-sha1; c=nofws; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:from :to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding:content-type; q=dns; s= default; b=UnFl//enQMuuXK3fImrfFRjzNMNW7U99RIJVZT7s+23PjXeHwC28m 7uXWJ/YIHPFsHJXrxC46F0gmeWHi4T4WL7dpOA9rlgSGbwN3/y5Ceflt+blYykpe qepBN3v0HVIJlLoq0uMdKXtz2wkdJLw/uJuWVCy5LlB3ojR64Gf5Nw= DKIM-Signature: v=1; a=rsa-sha1; c=relaxed; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:from :to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding:content-type; s=default; bh=/3YISoqhCssp3hhfANWANeT36Zg=; b=mWF5ygFZ0RFDibUZ5u0aW4aFgeSf h9o/gKmc3hbH3FDMGbZgZ6G/0yyFBdxPK/I1/hv1gEVVqbDE7REWzSdhfa5x1x1F w4WI2wQl+K04RJLGMmuTPY04h7XSMPkwWxoUsWQH/wutw5L1uoBKZDeOmPVAC0Xj heNRV5EPffCkqvY= Received: (qmail 97611 invoked by alias); 18 Dec 2019 06:03:13 -0000 Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Delivered-To: mailing list gcc-patches@gcc.gnu.org Received: (qmail 97466 invoked by uid 89); 18 Dec 2019 06:03:12 -0000 Authentication-Results: sourceware.org; auth=none X-Spam-SWARE-Status: No, score=-23.8 required=5.0 tests=AWL, BAYES_00, GIT_PATCH_0, GIT_PATCH_1, GIT_PATCH_2, GIT_PATCH_3, KAM_SHORT, SPF_PASS autolearn=ham version=3.3.1 spammy=locked, 9549 X-HELO: esa1.mentor.iphmx.com Received: from esa1.mentor.iphmx.com (HELO esa1.mentor.iphmx.com) (68.232.129.153) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Wed, 18 Dec 2019 06:03:09 +0000 IronPort-SDR: KPiYinUIYThntLe3TCTZ9aRKsn/8HXfhxi5JGdFIMSu73uDIIf5VJ0sgPQQOnbp/ZSl7GWduJA sfys871t0P71k6P/Ezc5p49sCYKP/cNB5k6bGskhulw/tgyRFyubtE5NZKp6cnkwO7g8hFyAXK rMqsXLAkhvuZRxZTnjbdt3HHRVHx9aHHMpbvq8dHo6cyKFE6jrD3DAfSv1I4ump0zAat0HMDVL HOaopyZ/q2yiCQErCGTLmGrf42QPGceR7BON/BydXj7oaaFrGlDBE4wSt+pRy4K3jrcDod2liA vG0= Received: from orw-gwy-01-in.mentorg.com ([192.94.38.165]) by esa1.mentor.iphmx.com with ESMTP; 17 Dec 2019 22:03:07 -0800 IronPort-SDR: vDSaM8ECs2VEBlfw9bwczvUHh6G4gHwUormg5KUz1t3eFqtFIddE0cq4kKuu4yqIp/5y/SfWct hZdqBvfbaX5Xva9a1L/x6UPfoS5yNVl0UbMSHX9+KFy1GkwPHsbECbhBI8OQo0PrJLPp4ZohGJ ctCRziJs52Rjb/CyRHtZhIgBUZZFaMMC50ET3kSk4C0jB5mOqycbVwKiQ5tHTdf7UoRkDlwx3O vuM5p/eiQPCOmb2ojwSxA9NExVFazVOHxT3cYi/AzUpuckkbtcokss/NNJl63FpyJGK55vQ0QD IGs= From: Julian Brown To: CC: Thomas Schwinge , Jakub Jelinek , Tobias Burnus , , Subject: [PATCH 03/13] OpenACC reference count consistency checking Date: Tue, 17 Dec 2019 22:02:28 -0800 Message-ID: In-Reply-To: References: MIME-Version: 1.0 X-IsSubscribed: yes This is a rebased version of the reference count consistency checking patch last posted upstream here: https://gcc.gnu.org/ml/gcc-patches/2019-10/msg00239.html This is not necessary for proper operation of the rest of the patches in this series, but has proved useful in development. Tested (with RC_CHECKING enabled and alongside other patches in this series) with offloading to NVPTX. OK? Julian ChangeLog libgomp/ * libgomp.h (RC_CHECKING): New macro, disabled by default, guarding all hunks in this patch. (target_mem_desc): Add refcount_chk, mark fields. (splay_tree_key_s): Add refcount_chk field. (dump_tgt, gomp_rc_check): Add prototypes. * oacc-mem.c (GOACC_enter_exit_data): Add refcount self-check code. * oacc-parallel.c (GOACC_parallel_keyed): Add refcount self-check code. (GOACC_data_start, GOACC_data_end): Likewise. * target.c (stdio.h): Include. (dump_tgt, rc_check_clear, rc_check_count, rc_check_verify, gomp_rc_check): New functions to consistency-check reference counts. --- libgomp/libgomp.h | 18 ++++ libgomp/oacc-mem.c | 6 ++ libgomp/oacc-parallel.c | 27 ++++++ libgomp/target.c | 181 ++++++++++++++++++++++++++++++++++++++++ 4 files changed, 232 insertions(+) diff --git a/libgomp/libgomp.h b/libgomp/libgomp.h index 865b9df2444..d20194bafbb 100644 --- a/libgomp/libgomp.h +++ b/libgomp/libgomp.h @@ -954,9 +954,17 @@ struct target_var_desc { uintptr_t length; }; +/* Uncomment to enable reference-count consistency checking (for development + use only). */ +//#define RC_CHECKING 1 + struct target_mem_desc { /* Reference count. */ uintptr_t refcount; +#ifdef RC_CHECKING + uintptr_t refcount_chk; + bool mark; +#endif /* All the splay nodes allocated together. */ splay_tree_node array; /* Start of the target region. */ @@ -1012,6 +1020,10 @@ struct splay_tree_key_s { "present increment" operations (via "acc enter data") referring to the same host-memory block. */ uintptr_t virtual_refcount; +#ifdef RC_CHECKING + /* The recalculated reference count, for verification. */ + uintptr_t refcount_chk; +#endif struct splay_tree_aux *aux; }; @@ -1158,6 +1170,12 @@ extern void gomp_copy_dev2host (struct gomp_device_descr *, struct goacc_asyncqueue *, void *, const void *, size_t); +#ifdef RC_CHECKING +extern void dump_tgt (const char *, struct target_mem_desc *); +extern void gomp_rc_check (struct gomp_device_descr *, + struct target_mem_desc *); +#endif + extern struct target_mem_desc *gomp_map_vars (struct gomp_device_descr *, size_t, void **, void **, size_t *, void *, bool, diff --git a/libgomp/oacc-mem.c b/libgomp/oacc-mem.c index 2a0e7236b92..4a2185c58ad 100644 --- a/libgomp/oacc-mem.c +++ b/libgomp/oacc-mem.c @@ -1147,4 +1147,10 @@ GOACC_enter_exit_data (int flags_m, size_t mapnum, void **hostaddrs, thr->prof_info = NULL; thr->api_info = NULL; } + +#ifdef RC_CHECKING + gomp_mutex_lock (&acc_dev->lock); + gomp_rc_check (acc_dev, thr->mapped_data); + gomp_mutex_unlock (&acc_dev->lock); +#endif } diff --git a/libgomp/oacc-parallel.c b/libgomp/oacc-parallel.c index 5c13a7e4348..eb281db323c 100644 --- a/libgomp/oacc-parallel.c +++ b/libgomp/oacc-parallel.c @@ -301,6 +301,15 @@ GOACC_parallel_keyed (int flags_m, void (*fn) (void *), &api_info); } +#ifdef RC_CHECKING + gomp_mutex_lock (&acc_dev->lock); + assert (tgt); + dump_tgt (__FUNCTION__, tgt); + tgt->prev = thr->mapped_data; + gomp_rc_check (acc_dev, tgt); + gomp_mutex_unlock (&acc_dev->lock); +#endif + devaddrs = gomp_alloca (sizeof (void *) * mapnum); for (i = 0; i < mapnum; i++) if (tgt->list[i].key != NULL) @@ -351,6 +360,12 @@ GOACC_parallel_keyed (int flags_m, void (*fn) (void *), thr->prof_info = NULL; thr->api_info = NULL; } + +#ifdef RC_CHECKING + gomp_mutex_lock (&acc_dev->lock); + gomp_rc_check (acc_dev, thr->mapped_data); + gomp_mutex_unlock (&acc_dev->lock); +#endif } /* Legacy entry point (GCC 5). Only provide host fallback execution. */ @@ -484,6 +499,12 @@ GOACC_data_start (int flags_m, size_t mapnum, thr->prof_info = NULL; thr->api_info = NULL; } + +#ifdef RC_CHECKING + gomp_mutex_lock (&acc_dev->lock); + gomp_rc_check (acc_dev, thr->mapped_data); + gomp_mutex_unlock (&acc_dev->lock); +#endif } void @@ -557,6 +578,12 @@ GOACC_data_end (void) thr->prof_info = NULL; thr->api_info = NULL; } + +#ifdef RC_CHECKING + gomp_mutex_lock (&thr->dev->lock); + gomp_rc_check (thr->dev, thr->mapped_data); + gomp_mutex_unlock (&thr->dev->lock); +#endif } void diff --git a/libgomp/target.c b/libgomp/target.c index 23f9e1618ca..5712da5b64e 100644 --- a/libgomp/target.c +++ b/libgomp/target.c @@ -38,6 +38,9 @@ #include #include #include +#ifdef RC_CHECKING +#include +#endif #ifdef PLUGIN_SUPPORT #include @@ -346,6 +349,184 @@ gomp_free_device_memory (struct gomp_device_descr *devicep, void *devptr) } } +#ifdef RC_CHECKING +void +dump_tgt (const char *where, struct target_mem_desc *tgt) +{ + if (!getenv ("GOMP_DEBUG_TGT")) + return; + + fprintf (stderr, "%s: %s: tgt=%p\n", __FUNCTION__, where, (void*) tgt); + fprintf (stderr, "refcount=%d\n", (int) tgt->refcount); + fprintf (stderr, "tgt_start=%p\n", (void*) tgt->tgt_start); + fprintf (stderr, "tgt_end=%p\n", (void*) tgt->tgt_end); + fprintf (stderr, "to_free=%p\n", tgt->to_free); + fprintf (stderr, "list_count=%d\n", (int) tgt->list_count); + for (int i = 0; i < tgt->list_count; i++) + { + fprintf (stderr, "list item %d:\n", i); + fprintf (stderr, " key: %p\n", (void*) tgt->list[i].key); + if (tgt->list[i].key) + { + fprintf (stderr, " key.host_start=%p\n", + (void*) tgt->list[i].key->host_start); + fprintf (stderr, " key.host_end=%p\n", + (void*) tgt->list[i].key->host_end); + fprintf (stderr, " key.tgt=%p\n", (void*) tgt->list[i].key->tgt); + fprintf (stderr, " key.offset=%d\n", + (int) tgt->list[i].key->tgt_offset); + fprintf (stderr, " key.refcount=%d\n", + (int) tgt->list[i].key->refcount); + fprintf (stderr, " key.virtual_refcount=%d\n", + (int) tgt->list[i].key->virtual_refcount); + if (tgt->list[i].key->aux) + { + fprintf (stderr, " key.aux->link_key=%p\n", + (void*) tgt->list[i].key->aux->link_key); + fprintf (stderr, " key.aux->attach_count=%p\n", + (void*) tgt->list[i].key->aux->attach_count); + } + } + } + fprintf (stderr, "\n"); +} + +static void +rc_check_clear (splay_tree_node node) +{ + splay_tree_key k = &node->key; + + k->refcount_chk = 0; + k->tgt->refcount_chk = 0; + k->tgt->mark = false; + + if (node->left) + rc_check_clear (node->left); + if (node->right) + rc_check_clear (node->right); +} + +static void +rc_check_count (splay_tree_node node) +{ + splay_tree_key k = &node->key; + struct target_mem_desc *t; + + /* Add virtual reference counts ("acc enter data", etc.) for this key. */ + k->refcount_chk += k->virtual_refcount; + + t = k->tgt; + t->refcount_chk++; + + if (!t->mark) + { + for (int i = 0; i < t->list_count; i++) + if (t->list[i].key) + t->list[i].key->refcount_chk++; + + t->mark = true; + } + + if (node->left) + rc_check_count (node->left); + if (node->right) + rc_check_count (node->right); +} + +static bool +rc_check_verify (splay_tree_node node, bool noisy, bool errors) +{ + splay_tree_key k = &node->key; + struct target_mem_desc *t; + + if (k->refcount != REFCOUNT_INFINITY) + { + if (noisy) + fprintf (stderr, "key %p (%p..+%d): rc=%d/%d, virt_rc=%d\n", k, + (void *) k->host_start, (int) (k->host_end - k->host_start), + (int) k->refcount, (int) k->refcount_chk, + (int) k->virtual_refcount); + + if (k->refcount != k->refcount_chk) + { + if (noisy) + fprintf (stderr, " -- key refcount mismatch!\n"); + errors = true; + } + + t = k->tgt; + + if (noisy) + fprintf (stderr, "tgt %p: rc=%d/%d\n", t, (int) t->refcount, + (int) t->refcount_chk); + + if (t->refcount != t->refcount_chk) + { + if (noisy) + fprintf (stderr, + " -- target memory descriptor refcount mismatch!\n"); + errors = true; + } + } + + if (node->left) + errors |= rc_check_verify (node->left, noisy, errors); + if (node->right) + errors |= rc_check_verify (node->right, noisy, errors); + + return errors; +} + +/* Call with device locked. */ + +attribute_hidden void +gomp_rc_check (struct gomp_device_descr *devicep, struct target_mem_desc *tgt) +{ + splay_tree sp = &devicep->mem_map; + + bool noisy = getenv ("GOMP_DEBUG_TGT") != 0; + + if (noisy) + fprintf (stderr, "\n*** GOMP_RC_CHECK ***\n\n"); + + if (sp->root) + { + rc_check_clear (sp->root); + + for (struct target_mem_desc *t = tgt; t; t = t->prev) + { + t->refcount_chk = 0; + t->mark = false; + } + + /* Add references for interconnected splay-tree keys. */ + rc_check_count (sp->root); + + /* Add references for the tgt for a currently-executing kernel and/or + any enclosing data directives. */ + for (struct target_mem_desc *t = tgt; t; t = t->prev) + { + t->refcount_chk++; + + if (!t->mark) + { + for (int i = 0; i < t->list_count; i++) + if (t->list[i].key) + t->list[i].key->refcount_chk++; + + t->mark = true; + } + } + + if (rc_check_verify (sp->root, noisy, false)) + { + gomp_mutex_unlock (&devicep->lock); + gomp_fatal ("refcount checking failure"); + } + } +} +#endif + /* Handle the case where gomp_map_lookup, splay_tree_lookup or gomp_map_0len_lookup found oldn for newn. Helper function of gomp_map_vars. */ From patchwork Wed Dec 18 06:02:29 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Julian Brown X-Patchwork-Id: 1211981 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=209.132.180.131; helo=sourceware.org; envelope-from=gcc-patches-return-516173-incoming=patchwork.ozlabs.org@gcc.gnu.org; receiver=) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=codesourcery.com Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=gcc.gnu.org header.i=@gcc.gnu.org header.b="KCo4lnPY"; dkim-atps=neutral Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 47d4GB0Wbbz9sS9 for ; Wed, 18 Dec 2019 17:04:17 +1100 (AEDT) DomainKey-Signature: a=rsa-sha1; c=nofws; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:from :to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding:content-type; q=dns; s= default; b=SirmbPeMkctZqg3nEcCgfmdjLm+0dFpsWN4norEZnl1RvVpE1MAq9 2Yr9OBMQocQ+lZAnYlHib5yI+RE4+n2OBH4W0gItwiZsbkOj5y21M/Z/z6FXJ0eC yyJtJmYaj9DTohoO1aW8pgUJ4DjmOiFgRHi47YbHgsyAGhz9bnr/fI= DKIM-Signature: v=1; a=rsa-sha1; c=relaxed; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:from :to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding:content-type; s=default; bh=8wkJCgbZpbN2kcvuca8hja+RP2g=; b=KCo4lnPYZM4dHUzhzT2z1VV5964z 5Iuze8NaI00QQvyRoY0HeWzIFO7gKlkc209VcMCi4TANlJoGc0QS2rkbn7VqyMek Edmtoer7kg8zlvNQVfFbwh2qKuCbc284ynsA26ARkgD9Eiellm01RmQW5lk96z/E urIsofoRDLXhXIA= Received: (qmail 97987 invoked by alias); 18 Dec 2019 06:03:14 -0000 Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Delivered-To: mailing list gcc-patches@gcc.gnu.org Received: (qmail 97759 invoked by uid 89); 18 Dec 2019 06:03:14 -0000 Authentication-Results: sourceware.org; auth=none X-Spam-SWARE-Status: No, score=-23.9 required=5.0 tests=AWL, BAYES_00, GIT_PATCH_0, GIT_PATCH_1, GIT_PATCH_2, GIT_PATCH_3, KAM_SHORT, SPF_PASS autolearn=ham version=3.3.1 spammy=3128 X-HELO: esa1.mentor.iphmx.com Received: from esa1.mentor.iphmx.com (HELO esa1.mentor.iphmx.com) (68.232.129.153) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Wed, 18 Dec 2019 06:03:12 +0000 IronPort-SDR: kURVk9ZYw3SiUSRJ9rxFW8npz9ycLZiCZHQ/iD48iLk+yRWTybxWkSS02JgxJwvIPE1i8b56qu WIESiD27x+a6qfiLK8JKsiAxZCH4lV8J68BmmMCiZXs5ty7oIO16+6QOlvU4vTktPh1T3gJgI1 +1LeI+JnZAJS1fCjG420MLAyr8lVvq38IRJqSvFfF/aKLloeFISDcMm4sqxs6t4E0v6Z7xF2kb GzyML0GtfNA0Xs8Gf6WSU4eV5uzdzpOlQ62eI6Hu/7Vna/NMsGjlT9l3wz9SsqA10vdL4bUKHR cGo= Received: from orw-gwy-01-in.mentorg.com ([192.94.38.165]) by esa1.mentor.iphmx.com with ESMTP; 17 Dec 2019 22:03:11 -0800 IronPort-SDR: IljwDV2B7lZsZrPA0da8pm4bq6uCd+5kV7iJVvgExSfnTJYlCxdXhxOx6GlBKz+fVg3t1HzQ17 zJxYfl+ltcfivoCn1WMEdHRPbN43pwIu8PYzbHeqBtmQygbVt3gm23PBhujpBz/IUOg3Y9cYxx 75pQFgnp64UM1xFMVPhL3JMTuJE3Er7S5TMg+5bbQs7+PJXYHZt2YyR58JQLgWmhHVu4ol/4ZF 0uTJrql+rndYf9/XvlXCPrHJBco/vHyoDJNcFJj50NaVLI8wSBZ9t9ScPzcJPByjOTXBNigtnD gws= From: Julian Brown To: CC: Thomas Schwinge , Jakub Jelinek , Tobias Burnus , , Subject: [PATCH 04/13] Use gomp_map_val for OpenACC host-to-device address translation Date: Tue, 17 Dec 2019 22:02:29 -0800 Message-ID: In-Reply-To: References: MIME-Version: 1.0 X-IsSubscribed: yes This patch was previously approved here, but I have not committed it yet (without the other patches in this series): https://gcc.gnu.org/ml/gcc-patches/2019-10/msg01156.html Included for completeness. I will commit this alongside other patches if they are approved (or it could probably go in by itself anyway). Thanks, Julian ChangeLog libgomp/ * libgomp.h (gomp_map_val): Add prototype. * oacc-parallel.c (GOACC_parallel_keyed): Use gomp_map_val instead of open-coding device-address calculation. * target.c (gomp_map_val): Make global. --- libgomp/libgomp.h | 1 + libgomp/oacc-parallel.c | 8 ++------ libgomp/target.c | 2 +- 3 files changed, 4 insertions(+), 7 deletions(-) diff --git a/libgomp/libgomp.h b/libgomp/libgomp.h index d20194bafbb..248d8dc5d63 100644 --- a/libgomp/libgomp.h +++ b/libgomp/libgomp.h @@ -1169,6 +1169,7 @@ extern void gomp_copy_host2dev (struct gomp_device_descr *, extern void gomp_copy_dev2host (struct gomp_device_descr *, struct goacc_asyncqueue *, void *, const void *, size_t); +extern uintptr_t gomp_map_val (struct target_mem_desc *, void **, size_t); #ifdef RC_CHECKING extern void dump_tgt (const char *, struct target_mem_desc *); diff --git a/libgomp/oacc-parallel.c b/libgomp/oacc-parallel.c index eb281db323c..4cc0636aae1 100644 --- a/libgomp/oacc-parallel.c +++ b/libgomp/oacc-parallel.c @@ -312,12 +312,8 @@ GOACC_parallel_keyed (int flags_m, void (*fn) (void *), devaddrs = gomp_alloca (sizeof (void *) * mapnum); for (i = 0; i < mapnum; i++) - if (tgt->list[i].key != NULL) - devaddrs[i] = (void *) (tgt->list[i].key->tgt->tgt_start - + tgt->list[i].key->tgt_offset - + tgt->list[i].offset); - else - devaddrs[i] = NULL; + devaddrs[i] = (void *) gomp_map_val (tgt, hostaddrs, i); + if (aq == NULL) acc_dev->openacc.exec_func (tgt_fn, mapnum, hostaddrs, devaddrs, dims, tgt); diff --git a/libgomp/target.c b/libgomp/target.c index 5712da5b64e..46b20c04865 100644 --- a/libgomp/target.c +++ b/libgomp/target.c @@ -673,7 +673,7 @@ gomp_map_fields_existing (struct target_mem_desc *tgt, (void *) cur_node.host_end); } -static inline uintptr_t +attribute_hidden uintptr_t gomp_map_val (struct target_mem_desc *tgt, void **hostaddrs, size_t i) { if (tgt->list[i].key != NULL) From patchwork Wed Dec 18 06:03:45 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Julian Brown X-Patchwork-Id: 1211982 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=209.132.180.131; helo=sourceware.org; envelope-from=gcc-patches-return-516174-incoming=patchwork.ozlabs.org@gcc.gnu.org; receiver=) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=codesourcery.com Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=gcc.gnu.org header.i=@gcc.gnu.org header.b="fjWipiHf"; dkim-atps=neutral Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 47d4Gc0R5dz9sS6 for ; Wed, 18 Dec 2019 17:04:39 +1100 (AEDT) DomainKey-Signature: a=rsa-sha1; c=nofws; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:from :to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding:content-type; q=dns; s= default; b=uVyxNFJjPkOHeJmLTpapw16Z0WGP92Pdshoa01oABbCpzk5lnU4SJ pWelmGptTNavxyA0SfP0uruWrv2+50p/m/VRTg04BQKrmvgBSqBHLZaHaeQ0WSpI GTO0R7YRlF8WQK+fP68voRdtRPdijTQkaMapfOdAr++tcBVRabPIMM= DKIM-Signature: v=1; a=rsa-sha1; c=relaxed; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:from :to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding:content-type; s=default; bh=8vfQlOk0zVIn/0I+xXq5be2MhuU=; b=fjWipiHfDIYr+cLxqiH+P9ZU4Ukp 3rn64SuVAFhbK4hIABG8XRqDIi8xFlRr+vMAuJseK8IRxpeVeVG+YW/IzOon/PY7 eVEIV3uL34n/LyAbPBZoxZ9VGD97gDdjPjvDrxpBOsU8QIQ//p3ZJQGDvJPSPYYT X+NRcdw+bX7g+N8= Received: (qmail 104957 invoked by alias); 18 Dec 2019 06:04:16 -0000 Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Delivered-To: mailing list gcc-patches@gcc.gnu.org Received: (qmail 104862 invoked by uid 89); 18 Dec 2019 06:04:16 -0000 Authentication-Results: sourceware.org; auth=none X-Spam-SWARE-Status: No, score=-23.9 required=5.0 tests=AWL, BAYES_00, GIT_PATCH_0, GIT_PATCH_1, GIT_PATCH_2, GIT_PATCH_3, KAM_SHORT, SPF_PASS autolearn=ham version=3.3.1 spammy=RELEASE, integer_zerop X-HELO: esa4.mentor.iphmx.com Received: from esa4.mentor.iphmx.com (HELO esa4.mentor.iphmx.com) (68.232.137.252) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Wed, 18 Dec 2019 06:04:13 +0000 IronPort-SDR: i4tIvobunJx+RzOmG6fzxYpzOgQ5ogDb6w1954JPGybrvaDb6BUAkegS+1zh+8zTq7STFp/8NG Ak2iqPfIednWvNABy/Wlkr+RlgzVuZUA9CyNUc6flw6l5Ui1vxvM1zPAnRxR+k5LKUu/08myDM 2xQWBf+Zxkqge8lrCuFy/VGiE8nrx2XHmjMwABzNDZFy3IVN/GIdc4DS0gn1RdsjDXhZfcNtM4 t2gizZgxWgImuXYycscokLgyXXf9F42GICOs5cGzIc3AHR/8wf25a03thJgaxPtGCZ+VXfXShH +WU= Received: from orw-gwy-01-in.mentorg.com ([192.94.38.165]) by esa4.mentor.iphmx.com with ESMTP; 17 Dec 2019 22:04:03 -0800 IronPort-SDR: jTojofNzmIUefekyjX86mPqxZJHKLjKIzAtqpXr8gy9TGRn251+Ycy3d6D86Hc07devKRtGgS2 e99Fb9RTNH4vqLdZnq3pcmdf7p8jN4D65Oo7y9eJDN27KAh2U/T6Z6bsV5VVb2jlCv/W5wL9o2 TqJG4v96e+Qjg5SGFInRTEU/EYKH2sLXUKBAteVxpxrcComAzL13JdLUQti3p+l6ECldsPhXEJ k8XNczUd7LIB9cjL9TZZ67Ss6D/nxBBvvXgFd2B5HQjBCJqTCGUv92+usyqV/1ztVlxwsjHeGU /9Y= From: Julian Brown To: CC: Thomas Schwinge , Jakub Jelinek , Tobias Burnus , , Subject: [PATCH 05/13] Factor out duplicate code in gimplify_scan_omp_clauses Date: Tue, 17 Dec 2019 22:03:45 -0800 Message-ID: <1dde668834b06a6eab964b12099a811de5d412c4.1576648001.git.julian@codesourcery.com> In-Reply-To: References: MIME-Version: 1.0 X-IsSubscribed: yes This patch was previously posted here: https://gcc.gnu.org/ml/gcc-patches/2019-11/msg00321.html This version is the same as the last-posted version. The middle-end patch later in the series depends on this. Tested alongside other patches in this series with offloading to NVPTX. OK? Thanks, Julian ChangeLog gcc/ * gimplify.c (insert_struct_comp_map, extract_base_bit_offset): New. (gimplify_scan_omp_clauses): Outline duplicated code into calls to above two functions. --- gcc/gimplify.c | 290 ++++++++++++++++++++++++++----------------------- 1 file changed, 157 insertions(+), 133 deletions(-) diff --git a/gcc/gimplify.c b/gcc/gimplify.c index 9073680cb31..e3088dcbe05 100644 --- a/gcc/gimplify.c +++ b/gcc/gimplify.c @@ -8186,6 +8186,138 @@ 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. */ + +static tree +insert_struct_comp_map (enum tree_code code, tree c, tree struct_node, + tree prev_node, tree *scp) +{ + enum gomp_map_kind mkind + = code == OMP_TARGET_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; + 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; + 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++). */ + if (OMP_CLAUSE_CHAIN (prev_node) != c) + { + tree c4 = OMP_CLAUSE_CHAIN (prev_node); + tree c3 = build_omp_clause (OMP_CLAUSE_LOCATION (c), OMP_CLAUSE_MAP); + OMP_CLAUSE_SET_MAP_KIND (c3, mkind); + OMP_CLAUSE_DECL (c3) = unshare_expr (OMP_CLAUSE_DECL (c4)); + 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; + } + + if (scp) + *scp = c2; + + return cl; +} + +/* Strip ARRAY_REFS or an indirect ref off BASE, find the containing object, + and set *BITPOSP and *POFFSETP to the bit offset of the access. + If BASE_REF is non-NULL and the containing object is a reference, set + *BASE_REF to that reference before dereferencing the object. + If BASE_REF is NULL, check that the containing object is a COMPONENT_REF or + 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 offset; + poly_int64 bitsize, bitpos; + machine_mode mode; + int unsignedp, reversep, volatilep = 0; + 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 = get_inner_reference (base, &bitsize, &bitpos, &offset, &mode, + &unsignedp, &reversep, &volatilep); + + tree orig_base = base; + + 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); + + gcc_assert (offset == NULL_TREE || poly_int_tree_p (offset)); + + if (offset) + poffset = wi::to_poly_offset (offset); + else + poffset = 0; + + if (maybe_ne (bitpos, 0)) + poffset += bits_to_bytes_round_down (bitpos); + + *bitposp = bitpos; + *poffsetp = poffset; + + /* Set *BASE_REF if BASE was a dereferenced reference variable. */ + if (base_ref && orig_base != base) + *base_ref = orig_base; + + return base; +} + /* Scan the OMP clauses in *LIST_P, installing mappings into a new and previous omp contexts. */ @@ -8738,29 +8870,15 @@ gimplify_scan_omp_clauses (tree *list_p, gimple_seq *pre_p, } } - tree offset; - poly_int64 bitsize, bitpos; - machine_mode mode; - int unsignedp, reversep, volatilep = 0; - tree base = OMP_CLAUSE_DECL (c); - while (TREE_CODE (base) == ARRAY_REF) - base = TREE_OPERAND (base, 0); - if (TREE_CODE (base) == INDIRECT_REF) - base = TREE_OPERAND (base, 0); - base = get_inner_reference (base, &bitsize, &bitpos, &offset, - &mode, &unsignedp, &reversep, - &volatilep); - tree orig_base = base; - 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); - gcc_assert (base == decl - && (offset == NULL_TREE - || poly_int_tree_p (offset))); + poly_offset_int offset1; + poly_int64 bitpos1; + tree base_ref; + + tree base + = extract_base_bit_offset (OMP_CLAUSE_DECL (c), &base_ref, + &bitpos1, &offset1); + + gcc_assert (base == decl); splay_tree_node n = splay_tree_lookup (ctx->variables, (splay_tree_key)decl); @@ -8771,8 +8889,8 @@ gimplify_scan_omp_clauses (tree *list_p, gimple_seq *pre_p, tree l = build_omp_clause (OMP_CLAUSE_LOCATION (c), OMP_CLAUSE_MAP); OMP_CLAUSE_SET_MAP_KIND (l, GOMP_MAP_STRUCT); - if (orig_base != base) - OMP_CLAUSE_DECL (l) = unshare_expr (orig_base); + if (base_ref) + OMP_CLAUSE_DECL (l) = unshare_expr (base_ref); else OMP_CLAUSE_DECL (l) = decl; OMP_CLAUSE_SIZE (l) = size_int (1); @@ -8781,32 +8899,8 @@ gimplify_scan_omp_clauses (tree *list_p, gimple_seq *pre_p, struct_map_to_clause->put (decl, l); if (ptr) { - enum gomp_map_kind mkind - = code == OMP_TARGET_EXIT_DATA - ? GOMP_MAP_RELEASE : GOMP_MAP_ALLOC; - tree c2 = build_omp_clause (OMP_CLAUSE_LOCATION (c), - OMP_CLAUSE_MAP); - OMP_CLAUSE_SET_MAP_KIND (c2, mkind); - OMP_CLAUSE_DECL (c2) - = unshare_expr (OMP_CLAUSE_DECL (c)); - OMP_CLAUSE_CHAIN (c2) = *prev_list_p; - OMP_CLAUSE_SIZE (c2) - = TYPE_SIZE_UNIT (ptr_type_node); - OMP_CLAUSE_CHAIN (l) = c2; - if (OMP_CLAUSE_CHAIN (*prev_list_p) != c) - { - tree c4 = OMP_CLAUSE_CHAIN (*prev_list_p); - tree c3 - = build_omp_clause (OMP_CLAUSE_LOCATION (c), - OMP_CLAUSE_MAP); - OMP_CLAUSE_SET_MAP_KIND (c3, mkind); - OMP_CLAUSE_DECL (c3) - = unshare_expr (OMP_CLAUSE_DECL (c4)); - OMP_CLAUSE_SIZE (c3) - = TYPE_SIZE_UNIT (ptr_type_node); - OMP_CLAUSE_CHAIN (c3) = *prev_list_p; - OMP_CLAUSE_CHAIN (c2) = c3; - } + insert_struct_comp_map (code, c, l, *prev_list_p, + NULL); *prev_list_p = l; prev_list_p = NULL; } @@ -8816,7 +8910,7 @@ gimplify_scan_omp_clauses (tree *list_p, gimple_seq *pre_p, *list_p = l; list_p = &OMP_CLAUSE_CHAIN (l); } - if (orig_base != base && code == OMP_TARGET) + if (base_ref && code == OMP_TARGET) { tree c2 = build_omp_clause (OMP_CLAUSE_LOCATION (c), OMP_CLAUSE_MAP); @@ -8839,13 +8933,6 @@ gimplify_scan_omp_clauses (tree *list_p, gimple_seq *pre_p, tree *sc = NULL, *scp = NULL; if (GOMP_MAP_ALWAYS_P (OMP_CLAUSE_MAP_KIND (c)) || ptr) n->value |= GOVD_SEEN; - poly_offset_int o1, o2; - if (offset) - o1 = wi::to_poly_offset (offset); - else - o1 = 0; - if (maybe_ne (bitpos, 0)) - o1 += bits_to_bytes_round_down (bitpos); sc = &OMP_CLAUSE_CHAIN (*osc); if (*sc != c && (OMP_CLAUSE_MAP_KIND (*sc) @@ -8863,44 +8950,16 @@ gimplify_scan_omp_clauses (tree *list_p, gimple_seq *pre_p, break; else { - tree offset2; - poly_int64 bitsize2, bitpos2; - base = OMP_CLAUSE_DECL (*sc); - 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)) - break; - } - 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 = get_inner_reference (base, &bitsize2, - &bitpos2, &offset2, - &mode, &unsignedp, - &reversep, &volatilep); - 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); + tree sc_decl = OMP_CLAUSE_DECL (*sc); + poly_offset_int offsetn; + poly_int64 bitposn; + tree base + = extract_base_bit_offset (sc_decl, NULL, + &bitposn, &offsetn); if (base != decl) break; if (scp) continue; - gcc_assert (offset2 == NULL_TREE - || poly_int_tree_p (offset2)); tree d1 = OMP_CLAUSE_DECL (*sc); tree d2 = OMP_CLAUSE_DECL (c); while (TREE_CODE (d1) == ARRAY_REF) @@ -8929,14 +8988,9 @@ gimplify_scan_omp_clauses (tree *list_p, gimple_seq *pre_p, remove = true; break; } - if (offset2) - o2 = wi::to_poly_offset (offset2); - else - o2 = 0; - o2 += bits_to_bytes_round_down (bitpos2); - if (maybe_lt (o1, o2) - || (known_eq (o1, o2) - && maybe_lt (bitpos, bitpos2))) + if (maybe_lt (offset1, offsetn) + || (known_eq (offset1, offsetn) + && maybe_lt (bitpos1, bitposn))) { if (ptr) scp = sc; @@ -8951,38 +9005,8 @@ gimplify_scan_omp_clauses (tree *list_p, gimple_seq *pre_p, size_one_node); if (ptr) { - tree c2 = build_omp_clause (OMP_CLAUSE_LOCATION (c), - OMP_CLAUSE_MAP); - tree cl = NULL_TREE; - enum gomp_map_kind mkind - = code == OMP_TARGET_EXIT_DATA - ? GOMP_MAP_RELEASE : GOMP_MAP_ALLOC; - OMP_CLAUSE_SET_MAP_KIND (c2, mkind); - OMP_CLAUSE_DECL (c2) - = unshare_expr (OMP_CLAUSE_DECL (c)); - OMP_CLAUSE_CHAIN (c2) = scp ? *scp : *prev_list_p; - OMP_CLAUSE_SIZE (c2) - = TYPE_SIZE_UNIT (ptr_type_node); - cl = scp ? *prev_list_p : c2; - if (OMP_CLAUSE_CHAIN (*prev_list_p) != c) - { - tree c4 = OMP_CLAUSE_CHAIN (*prev_list_p); - tree c3 - = build_omp_clause (OMP_CLAUSE_LOCATION (c), - OMP_CLAUSE_MAP); - OMP_CLAUSE_SET_MAP_KIND (c3, mkind); - OMP_CLAUSE_DECL (c3) - = unshare_expr (OMP_CLAUSE_DECL (c4)); - OMP_CLAUSE_SIZE (c3) - = TYPE_SIZE_UNIT (ptr_type_node); - OMP_CLAUSE_CHAIN (c3) = *prev_list_p; - if (!scp) - OMP_CLAUSE_CHAIN (c2) = c3; - else - cl = c3; - } - if (scp) - *scp = c2; + tree cl = insert_struct_comp_map (code, c, NULL, + *prev_list_p, scp); if (sc == prev_list_p) { *sc = cl; From patchwork Wed Dec 18 06:03:46 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Julian Brown X-Patchwork-Id: 1211983 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=209.132.180.131; helo=sourceware.org; envelope-from=gcc-patches-return-516175-incoming=patchwork.ozlabs.org@gcc.gnu.org; receiver=) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=codesourcery.com Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=gcc.gnu.org header.i=@gcc.gnu.org header.b="DbdfD9Te"; dkim-atps=neutral Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 47d4Gz2PWzz9sS9 for ; Wed, 18 Dec 2019 17:04:59 +1100 (AEDT) DomainKey-Signature: a=rsa-sha1; c=nofws; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:from :to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding:content-type; q=dns; s= default; b=d9UV6J58mtYJr92tVYCytImOPGjhTLp3BITcSAdSfkFrGMqs5JPix +9dCNPdKuj7WxTt6NYEUKBWTrghXy+nsaDgFEsOZMopxGx/fXwwvXiDClLB4N9Pn EuJJvmNuWoXqJkAsXqUxl0o/Uuk1MO4abpOU+Q9PXuRZIMjI2FdgBI= DKIM-Signature: v=1; a=rsa-sha1; c=relaxed; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:from :to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding:content-type; s=default; bh=MekZMaFfmzng1bVexcO/VSjWHF8=; b=DbdfD9Tes+851vLZanvXpdKKZlR7 /XUOHN13KVTsb+bYq2cWXIqEqxYXc93FoQeR0RJdzYRbVPBRfoNR7wiHK+TDG8nk UTw/wXBtYsqNkU8/LKRCXe8mIvvbuueArYQy8Yk5akVPdPycNQw4ElpAob+26u3N fWGV/wtdubVe23g= Received: (qmail 105539 invoked by alias); 18 Dec 2019 06:04:21 -0000 Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Delivered-To: mailing list gcc-patches@gcc.gnu.org Received: (qmail 105418 invoked by uid 89); 18 Dec 2019 06:04:20 -0000 Authentication-Results: sourceware.org; auth=none X-Spam-SWARE-Status: No, score=-24.0 required=5.0 tests=AWL, BAYES_00, GIT_PATCH_0, GIT_PATCH_1, GIT_PATCH_2, GIT_PATCH_3, KAM_SHORT, SPF_PASS autolearn=ham version=3.3.1 spammy=8666, 6736 X-HELO: esa4.mentor.iphmx.com Received: from esa4.mentor.iphmx.com (HELO esa4.mentor.iphmx.com) (68.232.137.252) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Wed, 18 Dec 2019 06:04:16 +0000 IronPort-SDR: EfQ/KgOMNYnXLkNod/2XkSF3AtB94AdhFxWebSWICSfYCKCKkDsVLE6F0itkgVtVestJPAw4aG nkGe9FkzwUKYC4eh59UjKLUojLCSJxxhDYx+cCfl+7lgLLyKqlynFmUVOuU7VUzP4QkLsEBChp nIiSsbacfwD1//OgUlPSxCrU2zi6j604ynuEGpLCVExfjTCG+7PjjCm+gXgul4j8v8qeE8Of5i ITfo8nVv7oYq0StkEiGMQVySsm3Ju2RoBC63hLGjmvhhiX9QxhwfO6Yo0jpybCXaq/b3S/5Boy mRE= Received: from orw-gwy-01-in.mentorg.com ([192.94.38.165]) by esa4.mentor.iphmx.com with ESMTP; 17 Dec 2019 22:04:07 -0800 IronPort-SDR: iTYtqQJ4MVBDkJTuuARjh4XldMs3F2Q5cYRgfa56HU1rlAYE5NmHhO1vd8PoYgiwap7vlcO76s ZfDIuSMFiJR/gd2pVOd2teTrN/wY2UuexLzOAphwtZJDE23zzoeqDiPLZ1vmGC4VzNaKQ+zXUn sVxhgD97PIdO4XJK/UhwruEPDARERX8iVkQeYOsqaT6zkiVTmkbVs3jBDhk0yDXl82swXYfDe4 UoSShur9bwmG3V4CjgszstkerVBAPIVvScBi236ySq3f/3x7rmMxlBQTza2jXEpytTUKuweNh8 2TU= From: Julian Brown To: CC: Thomas Schwinge , Jakub Jelinek , Tobias Burnus , , Subject: [PATCH 06/13] OpenACC 2.6 deep copy: attach/detach API routines Date: Tue, 17 Dec 2019 22:03:46 -0800 Message-ID: In-Reply-To: References: MIME-Version: 1.0 X-IsSubscribed: yes This patch has been broken out of the "OpenACC 2.6 manual deep copy support" patch, last posted here: https://gcc.gnu.org/ml/gcc-patches/2019-11/msg02376.html It contains just the minimal libgomp bits necessary to support the OpenACC runtime API routines (acc_attach, acc_detach and async/finalize versions of same). This is essentially the same as the version posted by Thomas here, modulo rebasing: https://gcc.gnu.org/ml/gcc-patches/2019-12/msg01212.html Tested alongside other patches in this series with offloading to NVPTX. OK? Thanks, Julian ChangeLog libgomp/ * libgomp.h (struct splay_tree_aux): Add attach_count field. (gomp_attach_pointer, gomp_detach_pointer): Add prototypes. * libgomp.map (OACC_2.6): New section. Add acc_attach, acc_attach_async, acc_detach, acc_detach_async, acc_detach_finalize, acc_detach_finalize_async. * oacc-mem.c (acc_attach_async, acc_attach, goacc_detach_internal, acc_detach, acc_detach_async, acc_detach_finalize, acc_detach_finalize_async): New functions. * openacc.h (acc_attach, acc_attach_async, acc_detach, (acc_detach_async, acc_detach_finalize, acc_detach_finalize_async): Add prototypes. * target.c (gomp_attach_pointer, gomp_detach_pointer): New functions. (gomp_remove_var_internal): Free attachment counts if present. * testsuite/libgomp.oacc-c-c++-common/deep-copy-3.c: New test. * testsuite/libgomp.oacc-c-c++-common/deep-copy-5.c: New test. --- libgomp/libgomp.h | 10 ++ libgomp/libgomp.map | 10 ++ libgomp/oacc-mem.c | 84 +++++++++++ libgomp/openacc.h | 6 + libgomp/target.c | 130 ++++++++++++++++++ .../libgomp.oacc-c-c++-common/deep-copy-3.c | 34 +++++ .../libgomp.oacc-c-c++-common/deep-copy-5.c | 81 +++++++++++ 7 files changed, 355 insertions(+) create mode 100644 libgomp/testsuite/libgomp.oacc-c-c++-common/deep-copy-3.c create mode 100644 libgomp/testsuite/libgomp.oacc-c-c++-common/deep-copy-5.c diff --git a/libgomp/libgomp.h b/libgomp/libgomp.h index 248d8dc5d63..2017991b59c 100644 --- a/libgomp/libgomp.h +++ b/libgomp/libgomp.h @@ -1002,6 +1002,9 @@ struct target_mem_desc { struct splay_tree_aux { /* Pointer to the original mapping of "omp declare target link" object. */ splay_tree_key link_key; + /* For a block with attached pointers, the attachment counters for each. + Only used for OpenACC. */ + uintptr_t *attach_count; }; struct splay_tree_key_s { @@ -1170,6 +1173,13 @@ extern void gomp_copy_dev2host (struct gomp_device_descr *, struct goacc_asyncqueue *, void *, const void *, size_t); extern uintptr_t gomp_map_val (struct target_mem_desc *, void **, size_t); +extern void gomp_attach_pointer (struct gomp_device_descr *, + struct goacc_asyncqueue *, splay_tree, + splay_tree_key, uintptr_t, size_t, + struct gomp_coalesce_buf *); +extern void gomp_detach_pointer (struct gomp_device_descr *, + struct goacc_asyncqueue *, splay_tree_key, + uintptr_t, bool, struct gomp_coalesce_buf *); #ifdef RC_CHECKING extern void dump_tgt (const char *, struct target_mem_desc *); diff --git a/libgomp/libgomp.map b/libgomp/libgomp.map index c79430f8d8d..63276f7d29b 100644 --- a/libgomp/libgomp.map +++ b/libgomp/libgomp.map @@ -484,6 +484,16 @@ OACC_2.5.1 { acc_register_library; } OACC_2.5; +OACC_2.6 { + global: + acc_attach; + acc_attach_async; + acc_detach; + acc_detach_async; + acc_detach_finalize; + acc_detach_finalize_async; +} OACC_2.5.1; + GOACC_2.0 { global: GOACC_data_end; diff --git a/libgomp/oacc-mem.c b/libgomp/oacc-mem.c index 4a2185c58ad..08507791399 100644 --- a/libgomp/oacc-mem.c +++ b/libgomp/oacc-mem.c @@ -866,6 +866,90 @@ acc_update_self_async (void *h, size_t s, int async) update_dev_host (0, h, s, async); } +void +acc_attach_async (void **hostaddr, int async) +{ + struct goacc_thread *thr = goacc_thread (); + struct gomp_device_descr *acc_dev = thr->dev; + goacc_aq aq = get_goacc_asyncqueue (async); + + struct splay_tree_key_s cur_node; + splay_tree_key n; + + if (thr->dev->capabilities & GOMP_OFFLOAD_CAP_SHARED_MEM) + return; + + gomp_mutex_lock (&acc_dev->lock); + + cur_node.host_start = (uintptr_t) hostaddr; + cur_node.host_end = cur_node.host_start + sizeof (void *); + n = splay_tree_lookup (&acc_dev->mem_map, &cur_node); + + if (n == NULL) + gomp_fatal ("struct not mapped for acc_attach"); + + gomp_attach_pointer (acc_dev, aq, &acc_dev->mem_map, n, (uintptr_t) hostaddr, + 0, NULL); + + gomp_mutex_unlock (&acc_dev->lock); +} + +void +acc_attach (void **hostaddr) +{ + acc_attach_async (hostaddr, acc_async_sync); +} + +static void +goacc_detach_internal (void **hostaddr, int async, bool finalize) +{ + struct goacc_thread *thr = goacc_thread (); + struct gomp_device_descr *acc_dev = thr->dev; + struct splay_tree_key_s cur_node; + splay_tree_key n; + struct goacc_asyncqueue *aq = get_goacc_asyncqueue (async); + + if (thr->dev->capabilities & GOMP_OFFLOAD_CAP_SHARED_MEM) + return; + + gomp_mutex_lock (&acc_dev->lock); + + cur_node.host_start = (uintptr_t) hostaddr; + cur_node.host_end = cur_node.host_start + sizeof (void *); + n = splay_tree_lookup (&acc_dev->mem_map, &cur_node); + + if (n == NULL) + gomp_fatal ("struct not mapped for acc_detach"); + + gomp_detach_pointer (acc_dev, aq, n, (uintptr_t) hostaddr, finalize, NULL); + + gomp_mutex_unlock (&acc_dev->lock); +} + +void +acc_detach (void **hostaddr) +{ + goacc_detach_internal (hostaddr, acc_async_sync, false); +} + +void +acc_detach_async (void **hostaddr, int async) +{ + goacc_detach_internal (hostaddr, async, false); +} + +void +acc_detach_finalize (void **hostaddr) +{ + goacc_detach_internal (hostaddr, acc_async_sync, true); +} + +void +acc_detach_finalize_async (void **hostaddr, int async) +{ + goacc_detach_internal (hostaddr, async, true); +} + /* Some types of (pointer) variables use several consecutive mappings, which must be treated as a group for enter/exit data directives. This function returns the last mapping in such a group (inclusive), or POS for singleton diff --git a/libgomp/openacc.h b/libgomp/openacc.h index 42c861caabf..d2e5c101f7f 100644 --- a/libgomp/openacc.h +++ b/libgomp/openacc.h @@ -109,12 +109,18 @@ void *acc_hostptr (void *) __GOACC_NOTHROW; int acc_is_present (void *, size_t) __GOACC_NOTHROW; void acc_memcpy_to_device (void *, void *, size_t) __GOACC_NOTHROW; void acc_memcpy_from_device (void *, void *, size_t) __GOACC_NOTHROW; +void acc_attach (void **) __GOACC_NOTHROW; +void acc_attach_async (void **, int) __GOACC_NOTHROW; +void acc_detach (void **) __GOACC_NOTHROW; +void acc_detach_async (void **, int) __GOACC_NOTHROW; /* Finalize versions of copyout/delete functions, specified in OpenACC 2.5. */ void acc_copyout_finalize (void *, size_t) __GOACC_NOTHROW; void acc_copyout_finalize_async (void *, size_t, int) __GOACC_NOTHROW; void acc_delete_finalize (void *, size_t) __GOACC_NOTHROW; void acc_delete_finalize_async (void *, size_t, int) __GOACC_NOTHROW; +void acc_detach_finalize (void **) __GOACC_NOTHROW; +void acc_detach_finalize_async (void **, int) __GOACC_NOTHROW; /* Async functions, specified in OpenACC 2.5. */ void acc_copyin_async (void *, size_t, int) __GOACC_NOTHROW; diff --git a/libgomp/target.c b/libgomp/target.c index 46b20c04865..1f429900113 100644 --- a/libgomp/target.c +++ b/libgomp/target.c @@ -673,6 +673,134 @@ gomp_map_fields_existing (struct target_mem_desc *tgt, (void *) cur_node.host_end); } +attribute_hidden void +gomp_attach_pointer (struct gomp_device_descr *devicep, + struct goacc_asyncqueue *aq, splay_tree mem_map, + splay_tree_key n, uintptr_t attach_to, size_t bias, + struct gomp_coalesce_buf *cbufp) +{ + struct splay_tree_key_s s; + size_t size, idx; + + if (n == NULL) + { + gomp_mutex_unlock (&devicep->lock); + gomp_fatal ("enclosing struct not mapped for attach"); + } + + size = (n->host_end - n->host_start + sizeof (void *) - 1) / sizeof (void *); + /* We might have a pointer in a packed struct: however we cannot have more + than one such pointer in each pointer-sized portion of the struct, so + this is safe. */ + idx = (attach_to - n->host_start) / sizeof (void *); + + if (!n->aux) + n->aux = gomp_malloc_cleared (sizeof (struct splay_tree_aux)); + + if (!n->aux->attach_count) + n->aux->attach_count + = gomp_malloc_cleared (sizeof (*n->aux->attach_count) * size); + + if (n->aux->attach_count[idx] < UINTPTR_MAX) + n->aux->attach_count[idx]++; + else + { + gomp_mutex_unlock (&devicep->lock); + gomp_fatal ("attach count overflow"); + } + + if (n->aux->attach_count[idx] == 1) + { + uintptr_t devptr = n->tgt->tgt_start + n->tgt_offset + attach_to + - n->host_start; + uintptr_t target = (uintptr_t) *(void **) attach_to; + splay_tree_key tn; + uintptr_t data; + + if ((void *) target == NULL) + { + gomp_mutex_unlock (&devicep->lock); + gomp_fatal ("attempt to attach null pointer"); + } + + s.host_start = target + bias; + s.host_end = s.host_start + 1; + tn = splay_tree_lookup (mem_map, &s); + + if (!tn) + { + gomp_mutex_unlock (&devicep->lock); + gomp_fatal ("pointer target not mapped for attach"); + } + + data = tn->tgt->tgt_start + tn->tgt_offset + target - tn->host_start; + + gomp_debug (1, + "%s: attaching host %p, target %p (struct base %p) to %p\n", + __FUNCTION__, (void *) attach_to, (void *) devptr, + (void *) (n->tgt->tgt_start + n->tgt_offset), (void *) data); + + gomp_copy_host2dev (devicep, aq, (void *) devptr, (void *) &data, + sizeof (void *), cbufp); + } + else + gomp_debug (1, "%s: attach count for %p -> %u\n", __FUNCTION__, + (void *) attach_to, (int) n->aux->attach_count[idx]); +} + +attribute_hidden void +gomp_detach_pointer (struct gomp_device_descr *devicep, + struct goacc_asyncqueue *aq, splay_tree_key n, + uintptr_t detach_from, bool finalize, + struct gomp_coalesce_buf *cbufp) +{ + size_t idx; + + if (n == NULL) + { + gomp_mutex_unlock (&devicep->lock); + gomp_fatal ("enclosing struct not mapped for detach"); + } + + idx = (detach_from - n->host_start) / sizeof (void *); + + if (!n->aux || !n->aux->attach_count) + { + gomp_mutex_unlock (&devicep->lock); + gomp_fatal ("no attachment counters for struct"); + } + + if (finalize) + n->aux->attach_count[idx] = 1; + + if (n->aux->attach_count[idx] == 0) + { + gomp_mutex_unlock (&devicep->lock); + gomp_fatal ("attach count underflow"); + } + else + n->aux->attach_count[idx]--; + + if (n->aux->attach_count[idx] == 0) + { + uintptr_t devptr = n->tgt->tgt_start + n->tgt_offset + detach_from + - n->host_start; + uintptr_t target = (uintptr_t) *(void **) detach_from; + + gomp_debug (1, + "%s: detaching host %p, target %p (struct base %p) to %p\n", + __FUNCTION__, (void *) detach_from, (void *) devptr, + (void *) (n->tgt->tgt_start + n->tgt_offset), + (void *) target); + + gomp_copy_host2dev (devicep, aq, (void *) devptr, (void *) &target, + sizeof (void *), cbufp); + } + else + gomp_debug (1, "%s: attach count for %p -> %u\n", __FUNCTION__, + (void *) detach_from, (int) n->aux->attach_count[idx]); +} + attribute_hidden uintptr_t gomp_map_val (struct target_mem_desc *tgt, void **hostaddrs, size_t i) { @@ -1348,6 +1476,8 @@ gomp_remove_var_internal (struct gomp_device_descr *devicep, splay_tree_key k, if (k->aux->link_key) splay_tree_insert (&devicep->mem_map, (splay_tree_node) k->aux->link_key); + if (k->aux->attach_count) + free (k->aux->attach_count); free (k->aux); k->aux = NULL; } diff --git a/libgomp/testsuite/libgomp.oacc-c-c++-common/deep-copy-3.c b/libgomp/testsuite/libgomp.oacc-c-c++-common/deep-copy-3.c new file mode 100644 index 00000000000..cec764bd3e7 --- /dev/null +++ b/libgomp/testsuite/libgomp.oacc-c-c++-common/deep-copy-3.c @@ -0,0 +1,34 @@ +#include +#include +#include + +int +main () +{ + int n = 100, i; + int *a = (int *) malloc (sizeof (int) * n); + int *b; + + for (i = 0; i < n; i++) + a[i] = i+1; + +#pragma acc enter data copyin(a[:n]) create(b) + + b = a; + acc_attach ((void **)&b); + +#pragma acc parallel loop present (b[:n]) + for (i = 0; i < n; i++) + b[i] = i+1; + + acc_detach ((void **)&b); + +#pragma acc exit data copyout(a[:n], b) + + for (i = 0; i < 10; i++) + assert (a[i] == b[i]); + + free (a); + + return 0; +} diff --git a/libgomp/testsuite/libgomp.oacc-c-c++-common/deep-copy-5.c b/libgomp/testsuite/libgomp.oacc-c-c++-common/deep-copy-5.c new file mode 100644 index 00000000000..89cafbb62ab --- /dev/null +++ b/libgomp/testsuite/libgomp.oacc-c-c++-common/deep-copy-5.c @@ -0,0 +1,81 @@ +#include +#include +#include + +struct node +{ + struct node *next; + int val; +}; + +int +sum_nodes (struct node *head) +{ + int i = 0, sum = 0; + +#pragma acc parallel reduction(+:sum) present(head[:1]) + { + for (; head != NULL; head = head->next) + sum += head->val; + } + + return sum; +} + +void +insert (struct node *head, int val) +{ + struct node *n = (struct node *) malloc (sizeof (struct node)); + + if (head->next) + acc_detach ((void **) &head->next); + + n->val = val; + n->next = head->next; + head->next = n; + + acc_copyin (n, sizeof (struct node)); + acc_attach((void **) &head->next); + + if (n->next) + acc_attach ((void **) &n->next); +} + +void +destroy (struct node *head) +{ + while (head->next != NULL) + { + acc_detach ((void **) &head->next); + struct node * n = head->next; + head->next = n->next; + if (n->next) + acc_detach ((void **) &n->next); + + acc_delete (n, sizeof (struct node)); + if (head->next) + acc_attach((void **) &head->next); + + free (n); + } +} + +int +main () +{ + struct node list = { .next = NULL, .val = 0 }; + int i; + + acc_copyin (&list, sizeof (struct node)); + + for (i = 0; i < 10; i++) + insert (&list, 2); + + assert (sum_nodes (&list) == 10 * 2); + + destroy (&list); + + acc_delete (&list, sizeof (struct node)); + + return 0; +} From patchwork Wed Dec 18 06:03:47 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Julian Brown X-Patchwork-Id: 1211984 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=209.132.180.131; helo=sourceware.org; envelope-from=gcc-patches-return-516176-incoming=patchwork.ozlabs.org@gcc.gnu.org; receiver=) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=codesourcery.com Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=gcc.gnu.org header.i=@gcc.gnu.org header.b="XxfaS9tM"; dkim-atps=neutral Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 47d4HS6BH1z9sS6 for ; Wed, 18 Dec 2019 17:05:24 +1100 (AEDT) DomainKey-Signature: a=rsa-sha1; c=nofws; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:from :to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding:content-type; q=dns; s= default; b=Gq+OZsxIsbHrlHDiv5E8wHdXBBPvOpSGCEdjVHbIlpoeRl/IRlA/1 QbQD/8IqOlyFkTs6/02DzZxAwkIWfDfG0kPX60YUgyyp94Rj9I766MWm02mAlghF lHh0pBxAglVELCecdY52vcFwkrXGuf2Ui0pfAlQnMirDJ8gaJj5+1s= DKIM-Signature: v=1; a=rsa-sha1; c=relaxed; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:from :to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding:content-type; s=default; bh=EcyeOcqwVckeFDYJEJaJLvkwoSk=; b=XxfaS9tMfT4RQBfYLE+gWHPEhNLT D3GXglNMZPTsGUltNOuUqa8R6TymeYm5lbxuekO5JiBcgkJBaiWsz/1z5BtjM1PG VySI2RK05MEJH/7gdIWoM91JFtnbQILdHFX+lCSDPLLH9y+pwRfNbBdwE7jgA0PX lp3Z4Zm0KHM9810= Received: (qmail 105579 invoked by alias); 18 Dec 2019 06:04:21 -0000 Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Delivered-To: mailing list gcc-patches@gcc.gnu.org Received: (qmail 105477 invoked by uid 89); 18 Dec 2019 06:04:20 -0000 Authentication-Results: sourceware.org; auth=none X-Spam-SWARE-Status: No, score=-24.0 required=5.0 tests=AWL, BAYES_00, GIT_PATCH_0, GIT_PATCH_1, GIT_PATCH_2, GIT_PATCH_3, KAM_SHORT, SPF_PASS autolearn=ham version=3.3.1 spammy=Actual, tidy X-HELO: esa4.mentor.iphmx.com Received: from esa4.mentor.iphmx.com (HELO esa4.mentor.iphmx.com) (68.232.137.252) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Wed, 18 Dec 2019 06:04:17 +0000 IronPort-SDR: dmxCB30PGv/lm6iMkYqPUkL45YS1iyFhcA0AqTwp3b4jEwGJXwAYFMxaGF6Du3hLN1Sp13ltQn 9V1cUMOue3l1yq5zB9RBhI89wjugydRg6PszQNvBnboYCt1FporHEzaCDuZ/ykuyC2ZFpqo8H3 P0h71n4wxDIhFB2ZB1tSmUL2QNUk6Zv3hEUUw9csnMnhDZ59bv8/K/BlWNdWu+FmvRgkhq98mz /hmAAexCHeNuNn5YqCkWmAHh7m1uzgjjLy3+FA4LUfEBRRIiNui1LeHy312/F7IKGZZ0WLX0tE AZo= Received: from orw-gwy-01-in.mentorg.com ([192.94.38.165]) by esa4.mentor.iphmx.com with ESMTP; 17 Dec 2019 22:04:10 -0800 IronPort-SDR: uwZ5gLdXs1bthwZ8KJ4rEMk//PJLPCAWyjfoOhFEgSoynjOHxKelYXigfgaLBZ5bweAI8WykeK I7oGL98+Z5ArSp6K2XqX3NKdRW87rhDPVc5f7vajJQJWy9KCp/xjhf89IkF+TLhO5JX/bZ49GU nyQlmVuVRvtkjNJA0xesBRAG5gHO5fohyyYTd99iATwW4zQLBNcVmldGoeNK4Yj+sR21jBtjhO QKL+NPHnUBovdEfAZUjWAFuNQW+Hk2k7Bi4BIeegk2XmvThUc8uJ/HV554y4ijd0T6UW5GwFK+ Bl8= From: Julian Brown To: CC: Thomas Schwinge , Jakub Jelinek , Tobias Burnus , , Subject: [PATCH 07/13] OpenACC 2.6 deep copy: libgomp parts Date: Tue, 17 Dec 2019 22:03:47 -0800 Message-ID: <65540b92dff74db1f15af930f87f7096d03e7efe.1576648001.git.julian@codesourcery.com> In-Reply-To: References: MIME-Version: 1.0 X-IsSubscribed: yes This patch has been broken out of the "OpenACC 2.6 manual deep copy support" patch, last posted here: https://gcc.gnu.org/ml/gcc-patches/2019-11/msg02376.html This part contains the libgomp runtime support for the GOMP_MAP_ATTACH and GOMP_MAP_DETACH mapping kinds (etc.), as introduced by the front-end patches following in this series. Tested alongside other patches in this series with offloading to NVPTX. OK? Thanks, Julian ChangeLog include/ * gomp-constants.h (GOMP_MAP_FLAG_SPECIAL_4, GOMP_MAP_DEEP_COPY): Define. (gomp_map_kind): Add GOMP_MAP_ATTACH, GOMP_MAP_DETACH, GOMP_MAP_FORCE_DETACH. libgomp/ * libgomp.h (struct target_var_desc): Add do_detach flag. * oacc-init.c (acc_shutdown_1): Free aux block if present. * oacc-mem.c (find_group_last): Add SIZES parameter. Support struct components. Tidy up and add some new checks. (goacc_enter_data_internal): Update call to find_group_last. (goacc_exit_data_internal): Support detach operations and GOMP_MAP_STRUCT. (GOACC_enter_exit_data): Handle initial GOMP_MAP_STRUCT or GOMP_MAP_FORCE_PRESENT in finalization detection code. Handle attach/detach in enter/exit data detection code. * target.c (gomp_map_vars_existing): Initialise do_detach field of tgt_var_desc. (gomp_map_vars_internal): Support attach. (gomp_unmap_vars_internal): Support detach. --- include/gomp-constants.h | 10 ++++ libgomp/libgomp.h | 2 + libgomp/oacc-mem.c | 121 +++++++++++++++++++++++++++++++++------ libgomp/target.c | 51 ++++++++++++++++- 4 files changed, 166 insertions(+), 18 deletions(-) diff --git a/include/gomp-constants.h b/include/gomp-constants.h index 9e356cdfeec..e8bd52e81bd 100644 --- a/include/gomp-constants.h +++ b/include/gomp-constants.h @@ -40,8 +40,11 @@ #define GOMP_MAP_FLAG_SPECIAL_0 (1 << 2) #define GOMP_MAP_FLAG_SPECIAL_1 (1 << 3) #define GOMP_MAP_FLAG_SPECIAL_2 (1 << 4) +#define GOMP_MAP_FLAG_SPECIAL_4 (1 << 6) #define GOMP_MAP_FLAG_SPECIAL (GOMP_MAP_FLAG_SPECIAL_1 \ | GOMP_MAP_FLAG_SPECIAL_0) +#define GOMP_MAP_DEEP_COPY (GOMP_MAP_FLAG_SPECIAL_4 \ + | GOMP_MAP_FLAG_SPECIAL_2) /* Flag to force a specific behavior (or else, trigger a run-time error). */ #define GOMP_MAP_FLAG_FORCE (1 << 7) @@ -127,6 +130,13 @@ enum gomp_map_kind /* Decrement usage count and deallocate if zero. */ GOMP_MAP_RELEASE = (GOMP_MAP_FLAG_SPECIAL_2 | GOMP_MAP_DELETE), + /* In OpenACC, attach a pointer to a mapped struct field. */ + GOMP_MAP_ATTACH = (GOMP_MAP_DEEP_COPY | 0), + /* In OpenACC, detach a pointer to a mapped struct field. */ + GOMP_MAP_DETACH = (GOMP_MAP_DEEP_COPY | 1), + /* In OpenACC, detach a pointer to a mapped struct field. */ + GOMP_MAP_FORCE_DETACH = (GOMP_MAP_DEEP_COPY + | GOMP_MAP_FLAG_FORCE | 1), /* Internal to GCC, not used in libgomp. */ /* Do not map, but pointer assign a pointer instead. */ diff --git a/libgomp/libgomp.h b/libgomp/libgomp.h index 2017991b59c..6141cc117bc 100644 --- a/libgomp/libgomp.h +++ b/libgomp/libgomp.h @@ -948,6 +948,8 @@ struct target_var_desc { bool copy_from; /* True if data always should be copied from device to host at the end. */ bool always_copy_from; + /* True if variable should be detached at end of region. */ + bool do_detach; /* Relative offset against key host_start. */ uintptr_t offset; /* Actual length. */ diff --git a/libgomp/oacc-mem.c b/libgomp/oacc-mem.c index 08507791399..ce9f2759dfa 100644 --- a/libgomp/oacc-mem.c +++ b/libgomp/oacc-mem.c @@ -956,33 +956,48 @@ acc_detach_finalize_async (void **hostaddr, int async) mappings. */ static int -find_group_last (int pos, size_t mapnum, unsigned short *kinds) +find_group_last (int pos, size_t mapnum, size_t *sizes, unsigned short *kinds) { unsigned char kind0 = kinds[pos] & 0xff; - int first_pos = pos, last_pos = pos; + int first_pos = pos; - if (kind0 == GOMP_MAP_TO_PSET) + switch (kind0) { + case GOMP_MAP_TO_PSET: while (pos + 1 < mapnum && (kinds[pos + 1] & 0xff) == GOMP_MAP_POINTER) - last_pos = ++pos; + pos++; /* We expect at least one GOMP_MAP_POINTER after a GOMP_MAP_TO_PSET. */ - assert (last_pos > first_pos); - } - else - { + assert (pos > first_pos); + break; + + case GOMP_MAP_STRUCT: + pos += sizes[pos]; + break; + + case GOMP_MAP_POINTER: + case GOMP_MAP_ALWAYS_POINTER: + /* These mappings are only expected after some other mapping. If we + see one by itself, something has gone wrong. */ + gomp_fatal ("unexpected mapping"); + break; + + default: /* GOMP_MAP_ALWAYS_POINTER can only appear directly after some other mapping. */ - if (pos + 1 < mapnum - && (kinds[pos + 1] & 0xff) == GOMP_MAP_ALWAYS_POINTER) - return pos + 1; + if (pos + 1 < mapnum) + { + unsigned char kind1 = kinds[pos + 1] & 0xff; + if (kind1 == GOMP_MAP_ALWAYS_POINTER) + return pos + 1; + } - /* We can have one or several GOMP_MAP_POINTER mappings after a to/from + /* We can have zero or more GOMP_MAP_POINTER mappings after a to/from (etc.) mapping. */ while (pos + 1 < mapnum && (kinds[pos + 1] & 0xff) == GOMP_MAP_POINTER) - last_pos = ++pos; + pos++; } - return last_pos; + return pos; } /* Map variables for OpenACC "enter data". We can't just call @@ -996,7 +1011,7 @@ goacc_enter_data_internal (struct gomp_device_descr *acc_dev, size_t mapnum, { for (size_t i = 0; i < mapnum; i++) { - int group_last = find_group_last (i, mapnum, kinds); + int group_last = find_group_last (i, mapnum, sizes, kinds); gomp_map_vars_async (acc_dev, aq, (group_last - i) + 1, @@ -1018,6 +1033,33 @@ goacc_exit_data_internal (struct gomp_device_descr *acc_dev, size_t mapnum, { gomp_mutex_lock (&acc_dev->lock); + /* Handle "detach" before copyback/deletion of mapped data. */ + for (size_t i = 0; i < mapnum; ++i) + { + unsigned char kind = kinds[i] & 0xff; + switch (kind) + { + case GOMP_MAP_DETACH: + case GOMP_MAP_FORCE_DETACH: + { + struct splay_tree_key_s cur_node; + uintptr_t hostaddr = (uintptr_t) hostaddrs[i]; + cur_node.host_start = hostaddr; + cur_node.host_end = cur_node.host_start + sizeof (void *); + splay_tree_key n + = splay_tree_lookup (&acc_dev->mem_map, &cur_node); + + if (n == NULL) + gomp_fatal ("struct not mapped for detach operation"); + + gomp_detach_pointer (acc_dev, aq, n, hostaddr, finalize, NULL); + } + break; + default: + ; + } + } + for (size_t i = 0; i < mapnum; ++i) { unsigned char kind = kinds[i] & 0xff; @@ -1035,6 +1077,8 @@ goacc_exit_data_internal (struct gomp_device_descr *acc_dev, size_t mapnum, case GOMP_MAP_POINTER: case GOMP_MAP_DELETE: case GOMP_MAP_RELEASE: + case GOMP_MAP_DETACH: + case GOMP_MAP_FORCE_DETACH: { struct splay_tree_key_s cur_node; cur_node.host_start = (uintptr_t) hostaddrs[i]; @@ -1075,6 +1119,39 @@ goacc_exit_data_internal (struct gomp_device_descr *acc_dev, size_t mapnum, gomp_remove_var_async (acc_dev, n, aq); } break; + + case GOMP_MAP_STRUCT: + { + int elems = sizes[i]; + for (int j = 1; j <= elems; j++) + { + struct splay_tree_key_s k; + k.host_start = (uintptr_t) hostaddrs[i + j]; + k.host_end = k.host_start + sizes[i + j]; + splay_tree_key str; + str = splay_tree_lookup (&acc_dev->mem_map, &k); + if (str) + { + if (finalize) + { + str->refcount -= str->virtual_refcount; + str->virtual_refcount = 0; + } + if (str->virtual_refcount > 0) + { + str->refcount--; + str->virtual_refcount--; + } + else if (str->refcount > 0) + str->refcount--; + if (str->refcount == 0) + gomp_remove_var_async (acc_dev, str, aq); + } + } + i += elems; + } + break; + default: gomp_fatal (">>>> goacc_exit_data_internal UNHANDLED kind 0x%.2x", kind); @@ -1107,8 +1184,13 @@ GOACC_enter_exit_data (int flags_m, size_t mapnum, void **hostaddrs, if (mapnum > 0) { unsigned char kind = kinds[0] & 0xff; + + if (kind == GOMP_MAP_STRUCT || kind == GOMP_MAP_FORCE_PRESENT) + kind = kinds[1] & 0xff; + if (kind == GOMP_MAP_DELETE - || kind == GOMP_MAP_FORCE_FROM) + || kind == GOMP_MAP_FORCE_FROM + || kind == GOMP_MAP_FORCE_DETACH) finalize = true; } @@ -1117,11 +1199,14 @@ GOACC_enter_exit_data (int flags_m, size_t mapnum, void **hostaddrs, { unsigned char kind = kinds[i] & 0xff; - if (kind == GOMP_MAP_POINTER || kind == GOMP_MAP_TO_PSET) + if (kind == GOMP_MAP_POINTER + || kind == GOMP_MAP_TO_PSET + || kind == GOMP_MAP_STRUCT) continue; if (kind == GOMP_MAP_FORCE_ALLOC || kind == GOMP_MAP_FORCE_PRESENT + || kind == GOMP_MAP_ATTACH || kind == GOMP_MAP_FORCE_TO || kind == GOMP_MAP_TO || kind == GOMP_MAP_ALLOC) @@ -1132,6 +1217,8 @@ GOACC_enter_exit_data (int flags_m, size_t mapnum, void **hostaddrs, if (kind == GOMP_MAP_RELEASE || kind == GOMP_MAP_DELETE + || kind == GOMP_MAP_DETACH + || kind == GOMP_MAP_FORCE_DETACH || kind == GOMP_MAP_FROM || kind == GOMP_MAP_FORCE_FROM) break; diff --git a/libgomp/target.c b/libgomp/target.c index 1f429900113..6fa94dec6ce 100644 --- a/libgomp/target.c +++ b/libgomp/target.c @@ -540,6 +540,7 @@ gomp_map_vars_existing (struct gomp_device_descr *devicep, tgt_var->key = oldn; tgt_var->copy_from = GOMP_MAP_COPY_FROM_P (kind); tgt_var->always_copy_from = GOMP_MAP_ALWAYS_FROM_P (kind); + tgt_var->do_detach = kind == GOMP_MAP_ATTACH; tgt_var->offset = newn->host_start - oldn->host_start; tgt_var->length = newn->host_end - newn->host_start; @@ -978,8 +979,15 @@ gomp_map_vars_internal (struct gomp_device_descr *devicep, has_firstprivate = true; continue; } + else if ((kind & typemask) == GOMP_MAP_ATTACH) + { + tgt->list[i].key = NULL; + has_firstprivate = true; + continue; + } cur_node.host_start = (uintptr_t) hostaddrs[i]; - if (!GOMP_MAP_POINTER_P (kind & typemask)) + if (!GOMP_MAP_POINTER_P (kind & typemask) + && (kind & typemask) != GOMP_MAP_ATTACH) cur_node.host_end = cur_node.host_start + sizes[i]; else cur_node.host_end = cur_node.host_start + sizeof (void *); @@ -1203,6 +1211,32 @@ gomp_map_vars_internal (struct gomp_device_descr *devicep, cur_node.tgt_offset = n->tgt->tgt_start + n->tgt_offset + cur_node.host_start - n->host_start; continue; + case GOMP_MAP_ATTACH: + { + cur_node.host_start = (uintptr_t) hostaddrs[i]; + cur_node.host_end = cur_node.host_start + sizeof (void *); + splay_tree_key n = splay_tree_lookup (mem_map, &cur_node); + if (n != NULL) + { + tgt->list[i].key = n; + tgt->list[i].offset = cur_node.host_start - n->host_start; + tgt->list[i].length = n->host_end - n->host_start; + tgt->list[i].copy_from = false; + tgt->list[i].always_copy_from = false; + tgt->list[i].do_detach + = (pragma_kind != GOMP_MAP_VARS_OPENACC_ENTER_DATA); + n->refcount++; + } + else + { + gomp_mutex_unlock (&devicep->lock); + gomp_fatal ("outer struct not mapped for attach"); + } + gomp_attach_pointer (devicep, aq, mem_map, n, + (uintptr_t) hostaddrs[i], sizes[i], + cbufp); + continue; + } default: break; } @@ -1247,10 +1281,12 @@ gomp_map_vars_internal (struct gomp_device_descr *devicep, tgt->list[i].copy_from = GOMP_MAP_COPY_FROM_P (kind & typemask); tgt->list[i].always_copy_from = GOMP_MAP_ALWAYS_FROM_P (kind & typemask); + tgt->list[i].do_detach = false; tgt->list[i].offset = 0; tgt->list[i].length = k->host_end - k->host_start; k->refcount = 1; k->virtual_refcount = 0; + k->aux = NULL; tgt->refcount++; array->left = NULL; array->right = NULL; @@ -1301,6 +1337,7 @@ gomp_map_vars_internal (struct gomp_device_descr *devicep, tgt->list[j].key = k; tgt->list[j].copy_from = false; tgt->list[j].always_copy_from = false; + tgt->list[j].do_detach = false; if (k->refcount != REFCOUNT_INFINITY) k->refcount++; gomp_map_pointer (tgt, aq, @@ -1534,6 +1571,18 @@ gomp_unmap_vars_internal (struct target_mem_desc *tgt, bool do_copyfrom, } size_t i; + + /* We must perform detachments before any copies back to the host. */ + for (i = 0; i < tgt->list_count; i++) + { + splay_tree_key k = tgt->list[i].key; + + if (k != NULL && tgt->list[i].do_detach) + gomp_detach_pointer (devicep, aq, k, tgt->list[i].key->host_start + + tgt->list[i].offset, + k->refcount == 1, NULL); + } + for (i = 0; i < tgt->list_count; i++) { splay_tree_key k = tgt->list[i].key; From patchwork Wed Dec 18 06:03:48 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Julian Brown X-Patchwork-Id: 1211985 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=209.132.180.131; helo=sourceware.org; envelope-from=gcc-patches-return-516177-incoming=patchwork.ozlabs.org@gcc.gnu.org; receiver=) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=codesourcery.com Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=gcc.gnu.org header.i=@gcc.gnu.org header.b="esSrVec0"; dkim-atps=neutral Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 47d4Hp1JRTz9sS6 for ; Wed, 18 Dec 2019 17:05:41 +1100 (AEDT) DomainKey-Signature: a=rsa-sha1; c=nofws; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:from :to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding:content-type; q=dns; s= default; b=oIf3dEdNj9WDI1Jk5cDffsiUYPoKt/TyzxthAqRXJN0IqttykC/Lh go2kte2OVrm5dCMTzsCoceDfBm6fce9zPATM1TO+9+0wedM77rYJ8IcCna7i+U/v x98QYRNXvaXUNBO97RHoez06d3ykrjKtMzjCNk9I+8LHE9aIuANp6U= DKIM-Signature: v=1; a=rsa-sha1; c=relaxed; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:from :to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding:content-type; s=default; bh=DYsfvPA3xNJHBaDtyp3HeT9cudY=; b=esSrVec0nGUJ3cWI540k3VRFq2k9 8VoIqnqsowEsUGvZBVQWxp+lcuD12pTEjbOmwPO2excxbTTHQwlU8dZtc+bVOHns njdUt0/ndRwAcshiSKZmPiw6uuxiuY3U9Ax8cXXbU/j9ZL9o+8pKfOoLLcJFxxiZ u0ZV/25WZuzsDUA= Received: (qmail 106208 invoked by alias); 18 Dec 2019 06:04:25 -0000 Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Delivered-To: mailing list gcc-patches@gcc.gnu.org Received: (qmail 106145 invoked by uid 89); 18 Dec 2019 06:04:24 -0000 Authentication-Results: sourceware.org; auth=none X-Spam-SWARE-Status: No, score=-24.0 required=5.0 tests=AWL, BAYES_00, GIT_PATCH_0, GIT_PATCH_1, GIT_PATCH_2, GIT_PATCH_3, KAM_SHORT, SPF_PASS autolearn=ham version=3.3.1 spammy=beware, 8496 X-HELO: esa4.mentor.iphmx.com Received: from esa4.mentor.iphmx.com (HELO esa4.mentor.iphmx.com) (68.232.137.252) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Wed, 18 Dec 2019 06:04:20 +0000 IronPort-SDR: /HKbA0CRhb4Mv1oviJjIaKa7TFBLhopBIPLnSs55uyWOQTmTZaHU02R4IVJKryvnoGFoqtohSq OoDGgtZ27g94FNVFPqM3Afp0e/ke9fao+sBivnhV6GO8zlmgRlehczi3x04GOqrWTojwCgj443 4mC2KOSdq5XDLBpIocs2GcPexE+/E7uJo7dhMiiC4CStDYG6pknACIHNcdulqAMO+o1P+06CMq m05BjQbLBtGQw7EExydKcZyqBHVBK+OhF5/AH5tv8lcPcpgSpOs7ZDHC3Rw1bECyhv7uDSxhzk T9Q= Received: from orw-gwy-01-in.mentorg.com ([192.94.38.165]) by esa4.mentor.iphmx.com with ESMTP; 17 Dec 2019 22:04:14 -0800 IronPort-SDR: MCkBFM2c4lDhRoEHgtIV8cwQE57nPxGJMpjtdEgaoRvKEEWhkBtXlNWZ5A81NmDM94+DFxxc6W QYBWkGLEtFaXTilY5fMVIgTMbjQViyVoTpb+/UB2kXk5IcgSPQ+PKb1Xv043BkBGfcWfWrNbe+ WHEkDWqDMQzYRAH0I43zAlVXfBqNcgELtCZjWsovNFhksTGwbVJEMC6PtjcLHrvrPYF+JJjr99 995qga4wj7FPrTFMsYqGHNifx0T6aI1VzLSochTpaGoVChNZ5i8mXiXDaz2OxEQMwIqvHy8qH3 X34= From: Julian Brown To: CC: Thomas Schwinge , Jakub Jelinek , Tobias Burnus , , Subject: [PATCH 08/13] OpenACC 2.6 deep copy: middle-end parts Date: Tue, 17 Dec 2019 22:03:48 -0800 Message-ID: <62e541dadce16450ba0da2bad66caf9bf443cd6e.1576648001.git.julian@codesourcery.com> In-Reply-To: References: MIME-Version: 1.0 X-IsSubscribed: yes This patch has been broken out of the "OpenACC 2.6 manual deep copy support" patch, last posted here: https://gcc.gnu.org/ml/gcc-patches/2019-11/msg02376.html This part contains the middle-end support for OpenACC 2.6 attach and detach operations, either as standalone clauses or as "attach/detach" actions triggered by other (data movement) clauses, as detailed in the specification. Tested alongside other patches in this series with offloading to NVPTX. OK? Thanks, Julian ChangeLog gcc/ * gimplify.c (gimplify_omp_var_data): Add GOVD_MAP_HAS_ATTACHMENTS. (insert_struct_comp_map): Support derived-type member mappings for arrays with descriptors which use GOMP_MAP_TO_PSET. Support GOMP_MAP_ATTACH_DETACH. (gimplify_scan_omp_clauses): Tidy up OACC_ENTER_DATA/OACC_EXIT_DATA mappings. Handle attach/detach clauses and component references. (gimplify_adjust_omp_clauses_1): Skip adjustments for explicit attach/detach clauses. (gimplify_omp_target_update): Handle finalize for detach. * omp-low.c (lower_omp_target): Support GOMP_MAP_ATTACH, GOMP_MAP_DETACH, GOMP_MAP_FORCE_DETACH. * tree-pretty-print.c (dump_omp_clause): Likewise, plus GOMP_MAP_ATTACH_DETACH. include/ * gomp-constants.h (gomp_map_kind): Add GOMP_MAP_ATTACH_DETACH. --- gcc/gimplify.c | 232 ++++++++++++++++++++++++++++++++++----- gcc/omp-low.c | 3 + gcc/tree-pretty-print.c | 18 +++ include/gomp-constants.h | 6 +- 4 files changed, 229 insertions(+), 30 deletions(-) diff --git a/gcc/gimplify.c b/gcc/gimplify.c index e3088dcbe05..e3d5bc83c4f 100644 --- a/gcc/gimplify.c +++ b/gcc/gimplify.c @@ -123,6 +123,10 @@ 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 = 8388608, + GOVD_DATA_SHARE_CLASS = (GOVD_SHARED | GOVD_PRIVATE | GOVD_FIRSTPRIVATE | GOVD_LASTPRIVATE | GOVD_REDUCTION | GOVD_LINEAR | GOVD_LOCAL) @@ -8209,20 +8213,33 @@ insert_struct_comp_map (enum tree_code code, tree c, tree struct_node, tree prev_node, tree *scp) { enum gomp_map_kind mkind - = code == OMP_TARGET_EXIT_DATA ? GOMP_MAP_RELEASE : GOMP_MAP_ALLOC; + = (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; 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; - OMP_CLAUSE_SIZE (c2) = TYPE_SIZE_UNIT (ptr_type_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)); + 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++). */ - if (OMP_CLAUSE_CHAIN (prev_node) != c) + 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))) { tree c4 = OMP_CLAUSE_CHAIN (prev_node); tree c3 = build_omp_clause (OMP_CLAUSE_LOCATION (c), OMP_CLAUSE_MAP); @@ -8329,6 +8346,7 @@ 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_set *struct_deref_set = NULL; tree *prev_list_p = NULL, *orig_list_p = list_p; int handled_depend_iterators = -1; int nowait = -1; @@ -8731,8 +8749,6 @@ gimplify_scan_omp_clauses (tree *list_p, gimple_seq *pre_p, case OMP_TARGET_DATA: case OMP_TARGET_ENTER_DATA: case OMP_TARGET_EXIT_DATA: - case OACC_ENTER_DATA: - case OACC_EXIT_DATA: case OACC_HOST_DATA: if (OMP_CLAUSE_MAP_KIND (c) == GOMP_MAP_FIRSTPRIVATE_POINTER || (OMP_CLAUSE_MAP_KIND (c) @@ -8741,6 +8757,15 @@ gimplify_scan_omp_clauses (tree *list_p, gimple_seq *pre_p, mapped, but not the pointer to it. */ remove = true; break; + case OACC_ENTER_DATA: + case OACC_EXIT_DATA: + if (OMP_CLAUSE_MAP_KIND (c) == GOMP_MAP_POINTER + || OMP_CLAUSE_MAP_KIND (c) == GOMP_MAP_TO_PSET + || OMP_CLAUSE_MAP_KIND (c) == GOMP_MAP_FIRSTPRIVATE_POINTER + || (OMP_CLAUSE_MAP_KIND (c) + == GOMP_MAP_FIRSTPRIVATE_REFERENCE)) + remove = true; + break; default: break; } @@ -8814,7 +8839,35 @@ gimplify_scan_omp_clauses (tree *list_p, gimple_seq *pre_p, pd = &TREE_OPERAND (decl, 0); decl = TREE_OPERAND (decl, 0); } - if (TREE_CODE (decl) == COMPONENT_REF) + bool indir_p = false; + tree orig_decl = decl; + tree decl_ref = NULL_TREE; + if ((region_type & ORT_ACC) != 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); + if ((TREE_CODE (decl) == MEM_REF + && integer_zerop (TREE_OPERAND (decl, 1))) + || INDIRECT_REF_P (decl)) + { + indir_p = true; + 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_ref = decl; + decl = TREE_OPERAND (decl, 0); + } + } + } + else if (TREE_CODE (decl) == COMPONENT_REF) { while (TREE_CODE (decl) == COMPONENT_REF) decl = TREE_OPERAND (decl, 0); @@ -8824,13 +8877,76 @@ gimplify_scan_omp_clauses (tree *list_p, gimple_seq *pre_p, == REFERENCE_TYPE)) decl = TREE_OPERAND (decl, 0); } + if (decl != orig_decl && DECL_P (decl) && indir_p) + { + gomp_map_kind k = (code == OACC_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 + && (!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))) + { + 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 + depends on the previous mapping. */ + if (code == OACC_UPDATE + && OMP_CLAUSE_MAP_KIND (c) == GOMP_MAP_ATTACH_DETACH) + OMP_CLAUSE_SET_MAP_KIND (c, GOMP_MAP_ALWAYS_POINTER); if (gimplify_expr (pd, pre_p, NULL, is_gimple_lvalue, fb_lvalue) == GS_ERROR) { remove = true; break; } - if (DECL_P (decl)) + if (DECL_P (decl) + && 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) { if (error_operand_p (decl)) { @@ -8851,7 +8967,8 @@ gimplify_scan_omp_clauses (tree *list_p, gimple_seq *pre_p, break; } - if (OMP_CLAUSE_MAP_KIND (c) == GOMP_MAP_ALWAYS_POINTER) + 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) @@ -8884,20 +9001,47 @@ gimplify_scan_omp_clauses (tree *list_p, gimple_seq *pre_p, = splay_tree_lookup (ctx->variables, (splay_tree_key)decl); 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) != 0) + { + /* 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) ? GOMP_MAP_DETACH + : GOMP_MAP_ATTACH; + OMP_CLAUSE_SET_MAP_KIND (c, k); + has_attachments = true; + } if (n == NULL || (n->value & GOVD_MAP) == 0) { tree l = build_omp_clause (OMP_CLAUSE_LOCATION (c), OMP_CLAUSE_MAP); - OMP_CLAUSE_SET_MAP_KIND (l, GOMP_MAP_STRUCT); + 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) = decl; - OMP_CLAUSE_SIZE (l) = size_int (1); + 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) + if (ptr || attach_detach) { insert_struct_comp_map (code, c, l, *prev_list_p, NULL); @@ -8923,23 +9067,31 @@ gimplify_scan_omp_clauses (tree *list_p, gimple_seq *pre_p, OMP_CLAUSE_CHAIN (l) = c2; } flags = GOVD_MAP | GOVD_EXPLICIT; - if (GOMP_MAP_ALWAYS_P (OMP_CLAUSE_MAP_KIND (c)) || ptr) + if (GOMP_MAP_ALWAYS_P (OMP_CLAUSE_MAP_KIND (c)) + || ptr + || attach_detach) flags |= GOVD_SEEN; + if (has_attachments) + flags |= GOVD_MAP_HAS_ATTACHMENTS; goto do_add_decl; } - else + else if (struct_map_to_clause) { tree *osc = struct_map_to_clause->get (decl); tree *sc = NULL, *scp = NULL; - if (GOMP_MAP_ALWAYS_P (OMP_CLAUSE_MAP_KIND (c)) || ptr) + if (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)) + == 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 && sc == prev_list_p) + if ((ptr || attach_detach) && sc == prev_list_p) break; else if (TREE_CODE (OMP_CLAUSE_DECL (*sc)) != COMPONENT_REF @@ -8992,7 +9144,7 @@ gimplify_scan_omp_clauses (tree *list_p, gimple_seq *pre_p, || (known_eq (offset1, offsetn) && maybe_lt (bitpos1, bitposn))) { - if (ptr) + if (ptr || attach_detach) scp = sc; else break; @@ -9000,10 +9152,11 @@ gimplify_scan_omp_clauses (tree *list_p, gimple_seq *pre_p, } if (remove) break; - OMP_CLAUSE_SIZE (*osc) - = size_binop (PLUS_EXPR, OMP_CLAUSE_SIZE (*osc), - size_one_node); - if (ptr) + 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); @@ -9033,11 +9186,18 @@ gimplify_scan_omp_clauses (tree *list_p, gimple_seq *pre_p, } if (!remove && 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_TO_PSET && OMP_CLAUSE_CHAIN (c) && OMP_CLAUSE_CODE (OMP_CLAUSE_CHAIN (c)) == OMP_CLAUSE_MAP - && (OMP_CLAUSE_MAP_KIND (OMP_CLAUSE_CHAIN (c)) - == GOMP_MAP_ALWAYS_POINTER)) + && ((OMP_CLAUSE_MAP_KIND (OMP_CLAUSE_CHAIN (c)) + == GOMP_MAP_ALWAYS_POINTER) + || (OMP_CLAUSE_MAP_KIND (OMP_CLAUSE_CHAIN (c)) + == GOMP_MAP_ATTACH_DETACH) + || (OMP_CLAUSE_MAP_KIND (OMP_CLAUSE_CHAIN (c)) + == GOMP_MAP_TO_PSET))) prev_list_p = list_p; + break; } flags = GOVD_MAP | GOVD_EXPLICIT; @@ -9561,6 +9721,8 @@ gimplify_scan_omp_clauses (tree *list_p, gimple_seq *pre_p, gimplify_omp_ctxp = ctx; 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 @@ -9708,6 +9870,8 @@ 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); @@ -12762,8 +12926,9 @@ gimplify_omp_target_update (tree *expr_p, gimple_seq *pre_p) && omp_find_clause (OMP_STANDALONE_CLAUSES (expr), OMP_CLAUSE_FINALIZE)) { - /* Use GOMP_MAP_DELETE/GOMP_MAP_FORCE_FROM to denote that "finalize" - semantics apply to all mappings of this OpenACC directive. */ + /* Use GOMP_MAP_DELETE, GOMP_MAP_FORCE_DETACH, and + GOMP_MAP_FORCE_FROM to denote that "finalize" semantics apply + to all mappings of this OpenACC directive. */ bool finalize_marked = false; for (tree c = OMP_STANDALONE_CLAUSES (expr); c; c = OMP_CLAUSE_CHAIN (c)) if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_MAP) @@ -12777,10 +12942,19 @@ gimplify_omp_target_update (tree *expr_p, gimple_seq *pre_p) OMP_CLAUSE_SET_MAP_KIND (c, GOMP_MAP_DELETE); finalize_marked = true; break; + case GOMP_MAP_DETACH: + OMP_CLAUSE_SET_MAP_KIND (c, GOMP_MAP_FORCE_DETACH); + finalize_marked = true; + break; + case GOMP_MAP_STRUCT: + case GOMP_MAP_FORCE_PRESENT: + /* Skip over an initial struct or force_present mapping. */ + break; default: - /* Check consistency: libgomp relies on the very first data - mapping clause being marked, so make sure we did that before - any other mapping clauses. */ + /* Check consistency: libgomp relies on the very first + non-struct, non-force-present data mapping clause being + marked, so make sure we did that before any other mapping + clauses. */ gcc_assert (finalize_marked); break; } diff --git a/gcc/omp-low.c b/gcc/omp-low.c index d422c205836..3eb7815449a 100644 --- a/gcc/omp-low.c +++ b/gcc/omp-low.c @@ -11439,6 +11439,9 @@ lower_omp_target (gimple_stmt_iterator *gsi_p, omp_context *ctx) case GOMP_MAP_FORCE_DEVICEPTR: case GOMP_MAP_DEVICE_RESIDENT: case GOMP_MAP_LINK: + case GOMP_MAP_ATTACH: + case GOMP_MAP_DETACH: + case GOMP_MAP_FORCE_DETACH: gcc_assert (is_gimple_omp_oacc (stmt)); break; default: diff --git a/gcc/tree-pretty-print.c b/gcc/tree-pretty-print.c index 1cf7a912133..379858d0f1f 100644 --- a/gcc/tree-pretty-print.c +++ b/gcc/tree-pretty-print.c @@ -849,6 +849,18 @@ dump_omp_clause (pretty_printer *pp, tree clause, int spc, dump_flags_t flags) case GOMP_MAP_LINK: pp_string (pp, "link"); break; + case GOMP_MAP_ATTACH: + pp_string (pp, "attach"); + break; + case GOMP_MAP_DETACH: + pp_string (pp, "detach"); + break; + case GOMP_MAP_FORCE_DETACH: + pp_string (pp, "force_detach"); + break; + case GOMP_MAP_ATTACH_DETACH: + pp_string (pp, "attach_detach"); + break; default: gcc_unreachable (); } @@ -870,6 +882,12 @@ dump_omp_clause (pretty_printer *pp, tree clause, int spc, dump_flags_t flags) case GOMP_MAP_TO_PSET: pp_string (pp, " [pointer set, len: "); break; + case GOMP_MAP_ATTACH: + case GOMP_MAP_DETACH: + case GOMP_MAP_FORCE_DETACH: + case GOMP_MAP_ATTACH_DETACH: + pp_string (pp, " [bias: "); + break; default: pp_string (pp, " [len: "); break; diff --git a/include/gomp-constants.h b/include/gomp-constants.h index e8bd52e81bd..f40d6069582 100644 --- a/include/gomp-constants.h +++ b/include/gomp-constants.h @@ -142,7 +142,11 @@ enum gomp_map_kind /* Do not map, but pointer assign a pointer instead. */ GOMP_MAP_FIRSTPRIVATE_POINTER = (GOMP_MAP_LAST | 1), /* Do not map, but pointer assign a reference instead. */ - GOMP_MAP_FIRSTPRIVATE_REFERENCE = (GOMP_MAP_LAST | 2) + GOMP_MAP_FIRSTPRIVATE_REFERENCE = (GOMP_MAP_LAST | 2), + /* An attach or detach operation. Rewritten to the appropriate type during + gimplification, depending on directive (i.e. "enter data" or + parallel/kernels region vs. "exit data"). */ + GOMP_MAP_ATTACH_DETACH = (GOMP_MAP_LAST | 3) }; #define GOMP_MAP_COPY_TO_P(X) \ From patchwork Wed Dec 18 06:03:49 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Julian Brown X-Patchwork-Id: 1211986 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=209.132.180.131; helo=sourceware.org; envelope-from=gcc-patches-return-516178-incoming=patchwork.ozlabs.org@gcc.gnu.org; receiver=) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=codesourcery.com Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=gcc.gnu.org header.i=@gcc.gnu.org header.b="lYvKcxav"; dkim-atps=neutral Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 47d4J96h5Pz9sS6 for ; Wed, 18 Dec 2019 17:06:01 +1100 (AEDT) DomainKey-Signature: a=rsa-sha1; c=nofws; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:from :to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding:content-type; q=dns; s= default; b=Yl4bPo+O44StJ6Bhi7Z7tkFXyx7MXi0zJ4XN+uHrG5B7mdAaOJQ6F QYdVDhWVt26gidxmEQQsl/fvtApAtHFSKa5w8QQkO+ZIa5bVYWLU6lEvrtiggA0T 0MO6xJpWkhr11+5bQs68z9J7nq+XfGsxuB+dM/4YYWb/F/tJu9v2i8= DKIM-Signature: v=1; a=rsa-sha1; c=relaxed; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:from :to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding:content-type; s=default; bh=MZye2vXjqf6Mmf4jbHcdpUERTRw=; b=lYvKcxav/zoCt2hR+b6x8RNu4Sff 54u7G3Q3sU3M0CM6DZu8rOvoyRMqYhzQ19M5i9N1wMvrM5/V6iWrcW/8tjhLhr5T Ub17S2WzxvLLuBVCAOlQK9CnZ8ZyW0JOTs03B9igzW6gAkSttNqsuzaF7sSbi2yh rwwlTrGK18AEdkA= Received: (qmail 106744 invoked by alias); 18 Dec 2019 06:04:28 -0000 Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Delivered-To: mailing list gcc-patches@gcc.gnu.org Received: (qmail 106634 invoked by uid 89); 18 Dec 2019 06:04:28 -0000 Authentication-Results: sourceware.org; auth=none X-Spam-SWARE-Status: No, score=-24.1 required=5.0 tests=AWL, BAYES_00, GIT_PATCH_0, GIT_PATCH_1, GIT_PATCH_2, GIT_PATCH_3, KAM_SHORT, SPF_PASS autolearn=ham version=3.3.1 spammy=se, sa, s.a, collapse X-HELO: esa4.mentor.iphmx.com Received: from esa4.mentor.iphmx.com (HELO esa4.mentor.iphmx.com) (68.232.137.252) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Wed, 18 Dec 2019 06:04:20 +0000 IronPort-SDR: yUJkBB6yX+XwjmQXPD9ym3GIWdBKTL5qu7je7hwdi6Kauecm74VEARKlC44UY1VQH5xL1Zf9UT 2CZAfuDvQVMg1rHvChvQwe2Vz3KzqcOpdByFdjlUvLODMKdEHgx657ypGRx1JxM+nBD9vdde/k j6OSoT1GFnchXo+jsZBwiVYE4ds3xofp0lIFaWailK++X5/dwWyCtKkCUhdkjHKbBTXWE1cwVO RDljbKkpxBxg7EcQnUCtVJIbgdBmBCykToMteWabsWSxv7BnDg0olNx9bKQ+h2k8D6FEzzDaGk biA= Received: from orw-gwy-01-in.mentorg.com ([192.94.38.165]) by esa4.mentor.iphmx.com with ESMTP; 17 Dec 2019 22:04:18 -0800 IronPort-SDR: YP6Kpi0IPXc8vR5A+EXDdBVY/qLLS+VeCo5oZh/br6IyAvOTdC9x5V/4sGScqKuJ3HKv4pV0XY krQYyTZY6BdO6sgy1XXMckTBhzORXNTdbvN4KjbN+OQKU99QXfB239wP7mjHQDa7ya89OV6Bfi h/+FoBOlm1jBdYlSjPDePrx4A4QIz85bPtRlr68UH9jX/CTosfvphVi57Ku6GJ+RV9zfaN+c8F vK0oLkkg5bqp1qvqx+HBQ4ODm3VODt4vbVKOinEuupQ+N1nbTI6TzZ3HulINwE5MX/a/qa3kJf hzM= From: Julian Brown To: CC: Thomas Schwinge , Jakub Jelinek , Tobias Burnus , , Subject: [PATCH 09/13] OpenACC 2.6 deep copy: C and C++ front-end parts Date: Tue, 17 Dec 2019 22:03:49 -0800 Message-ID: <5dfedf23eedbf91e58142a2bc853922c8502cba4.1576648001.git.julian@codesourcery.com> In-Reply-To: References: MIME-Version: 1.0 X-IsSubscribed: yes This patch has been broken out of the "OpenACC 2.6 manual deep copy support" patch, last posted here: https://gcc.gnu.org/ml/gcc-patches/2019-11/msg02376.html This part contains the C and C++ changes to parse attach and detach clauses and struct member accesses via "." or "->" on other data-movement clauses (copyin, copyout, etc.). Tested alongside other patches in this series with offloading to NVPTX. OK? Thanks, Julian ChangeLog gcc/c-family/ * c-common.h (c_omp_map_clause_name): Add prototype. * c-omp.c (c_omp_map_clause_name): New function. * c-pragma.h (pragma_omp_clause): Add PRAGMA_OACC_CLAUSE_ATTACH and PRAGMA_OACC_CLAUSE_DETACH. gcc/c/ * c-parser.c (c_parser_omp_clause_name): Add parsing of attach and detach clauses. (c_parser_omp_variable_list): Add ALLOW_DEREF optional parameter. Allow deref (->) in variable lists if true. (c_parser_omp_var_list_parens): Add ALLOW_DEREF optional parameter. Pass to c_parser_omp_variable_list. (c_parser_oacc_data_clause): Support attach and detach clauses. Update call to c_parser_omp_variable_list. (c_parser_oacc_all_clauses): Support attach and detach clauses. (OACC_DATA_CLAUSE_MASK, OACC_ENTER_DATA_CLAUSE_MASK, OACC_KERNELS_CLAUSE_MASK, OACC_PARALLEL_CLAUSE_MASK, OACC_SERIAL_CLAUSE_MASK): Add PRAGMA_OACC_CLAUSE_ATTACH. (OACC_EXIT_DATA_CLAUSE_MASK): Add PRAGMA_OACC_CLAUSE_DETACH. * c-typeck.c (handle_omp_array_sections_1): Reject subarrays for attach and detach. Support deref. (handle_omp_array_sections): Use GOMP_MAP_ATTACH_DETACH instead of GOMP_MAP_ALWAYS_POINTER for OpenACC. (c_oacc_check_attachments): New function. (c_finish_omp_clauses): Check attach/detach arguments for being pointers using above. Support deref. gcc/cp/ * parser.c (cp_parser_omp_clause_name): Support attach and detach clauses. (cp_parser_omp_var_list_no_open): Add ALLOW_DEREF optional parameter. Parse deref if true. (cp_parser_omp_var_list): Add ALLOW_DEREF optional parameter. Pass to cp_parser_omp_var_list_no_open. (cp_parser_oacc_data_clause): Support attach and detach clauses. Update call to cp_parser_omp_var_list_no_open. (cp_parser_oacc_all_clauses): Support attach and detach. (OACC_DATA_CLAUSE_MASK, OACC_ENTER_DATA_CLAUSE_MASK, OACC_KERNELS_CLAUSE_MASK, OACC_PARALLEL_CLAUSE_MASK, OACC_SERIAL_CLAUSE_MASK): Add PRAGMA_OACC_CLAUSE_ATTACH. (OACC_EXIT_DATA_CLAUSE_MASK): Add PRAGMA_OACC_CLAUSE_DETACH. * semantics.c (handle_omp_array_sections_1): Reject subarrays for attach and detach. (handle_omp_array_sections): Use GOMP_MAP_ATTACH_DETACH instead of GOMP_MAP_ALWAYS_POINTER for OpenACC. (cp_oacc_check_attachments): New function. (finish_omp_clauses): Use above function. Allow structure fields and class members to appear in OpenACC data clauses. Support GOMP_MAP_ATTACH_DETACH. Support deref. gcc/testsuite/ * c-c++-common/goacc/deep-copy-arrayofstruct.c: New test. * c-c++-common/goacc/mdc-1.c: New test. * c-c++-common/goacc/mdc-2.c: New test. * gcc.dg/goacc/mdc.C: New test. --- gcc/c-family/c-common.h | 1 + gcc/c-family/c-omp.c | 33 +++++++ gcc/c-family/c-pragma.h | 2 + gcc/c/c-parser.c | 53 ++++++++-- gcc/c/c-typeck.c | 76 +++++++++++++- gcc/cp/parser.c | 56 +++++++++-- gcc/cp/semantics.c | 98 ++++++++++++++++--- .../goacc/deep-copy-arrayofstruct.c | 84 ++++++++++++++++ gcc/testsuite/c-c++-common/goacc/mdc-1.c | 55 +++++++++++ gcc/testsuite/c-c++-common/goacc/mdc-2.c | 62 ++++++++++++ gcc/testsuite/g++.dg/goacc/mdc.C | 68 +++++++++++++ 11 files changed, 554 insertions(+), 34 deletions(-) create mode 100644 gcc/testsuite/c-c++-common/goacc/deep-copy-arrayofstruct.c create mode 100644 gcc/testsuite/c-c++-common/goacc/mdc-1.c create mode 100644 gcc/testsuite/c-c++-common/goacc/mdc-2.c create mode 100644 gcc/testsuite/g++.dg/goacc/mdc.C diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h index 2bcb54f66b9..2d89451b693 100644 --- a/gcc/c-family/c-common.h +++ b/gcc/c-family/c-common.h @@ -1205,6 +1205,7 @@ extern bool c_omp_predefined_variable (tree); extern enum omp_clause_default_kind c_omp_predetermined_sharing (tree); 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); /* Return next tree in the chain for chain_next walking of tree nodes. */ static inline tree diff --git a/gcc/c-family/c-omp.c b/gcc/c-family/c-omp.c index a4be2d68b9a..04f2c0b0682 100644 --- a/gcc/c-family/c-omp.c +++ b/gcc/c-family/c-omp.c @@ -2259,3 +2259,36 @@ c_omp_mark_declare_variant (location_t loc, tree variant, tree construct) error_at (loc, "%qD used as a variant with incompatible % " "selector sets", variant); } + +/* For OpenACC, the OMP_CLAUSE_MAP_KIND of an OMP_CLAUSE_MAP is used internally + to distinguish clauses as seen by the user. Return the "friendly" clause + name for error messages etc., where possible. See also + c/c-parser.c:c_parser_oacc_data_clause and + cp/parser.c:cp_parser_oacc_data_clause. */ + +const char * +c_omp_map_clause_name (tree clause, bool oacc) +{ + if (oacc && OMP_CLAUSE_CODE (clause) == OMP_CLAUSE_MAP) + switch (OMP_CLAUSE_MAP_KIND (clause)) + { + case GOMP_MAP_FORCE_ALLOC: + case GOMP_MAP_ALLOC: return "create"; + case GOMP_MAP_FORCE_TO: + case GOMP_MAP_TO: return "copyin"; + case GOMP_MAP_FORCE_FROM: + case GOMP_MAP_FROM: return "copyout"; + case GOMP_MAP_FORCE_TOFROM: + case GOMP_MAP_TOFROM: return "copy"; + case GOMP_MAP_RELEASE: return "delete"; + case GOMP_MAP_FORCE_PRESENT: return "present"; + case GOMP_MAP_ATTACH: return "attach"; + case GOMP_MAP_FORCE_DETACH: + case GOMP_MAP_DETACH: return "detach"; + case GOMP_MAP_DEVICE_RESIDENT: return "device_resident"; + case GOMP_MAP_LINK: return "link"; + case GOMP_MAP_FORCE_DEVICEPTR: return "deviceptr"; + default: break; + } + return omp_clause_code_name[OMP_CLAUSE_CODE (clause)]; +} diff --git a/gcc/c-family/c-pragma.h b/gcc/c-family/c-pragma.h index bfe681bb430..8a04e611bc7 100644 --- a/gcc/c-family/c-pragma.h +++ b/gcc/c-family/c-pragma.h @@ -143,11 +143,13 @@ enum pragma_omp_clause { /* Clauses for OpenACC. */ PRAGMA_OACC_CLAUSE_ASYNC, + PRAGMA_OACC_CLAUSE_ATTACH, PRAGMA_OACC_CLAUSE_AUTO, PRAGMA_OACC_CLAUSE_COPY, PRAGMA_OACC_CLAUSE_COPYOUT, PRAGMA_OACC_CLAUSE_CREATE, PRAGMA_OACC_CLAUSE_DELETE, + PRAGMA_OACC_CLAUSE_DETACH, PRAGMA_OACC_CLAUSE_DEVICEPTR, PRAGMA_OACC_CLAUSE_DEVICE_RESIDENT, PRAGMA_OACC_CLAUSE_FINALIZE, diff --git a/gcc/c/c-parser.c b/gcc/c/c-parser.c index bfe56998996..3839636f6ef 100644 --- a/gcc/c/c-parser.c +++ b/gcc/c/c-parser.c @@ -12564,6 +12564,8 @@ c_parser_omp_clause_name (c_parser *parser) result = PRAGMA_OMP_CLAUSE_ALIGNED; else if (!strcmp ("async", p)) result = PRAGMA_OACC_CLAUSE_ASYNC; + else if (!strcmp ("attach", p)) + result = PRAGMA_OACC_CLAUSE_ATTACH; break; case 'b': if (!strcmp ("bind", p)) @@ -12590,6 +12592,8 @@ c_parser_omp_clause_name (c_parser *parser) result = PRAGMA_OACC_CLAUSE_DELETE; else if (!strcmp ("depend", p)) result = PRAGMA_OMP_CLAUSE_DEPEND; + else if (!strcmp ("detach", p)) + result = PRAGMA_OACC_CLAUSE_DETACH; else if (!strcmp ("device", p)) result = PRAGMA_OMP_CLAUSE_DEVICE; else if (!strcmp ("deviceptr", p)) @@ -12833,12 +12837,16 @@ c_parser_oacc_wait_list (c_parser *parser, location_t clause_loc, tree list) If KIND is nonzero, CLAUSE_LOC is the location of the clause. If KIND is zero, create a TREE_LIST with the decl in TREE_PURPOSE; - return the list created. */ + return the list created. + + The optional ALLOW_DEREF argument is true if list items can use the deref + (->) operator. */ static tree c_parser_omp_variable_list (c_parser *parser, location_t clause_loc, - enum omp_clause_code kind, tree list) + enum omp_clause_code kind, tree list, + bool allow_deref = false) { auto_vec tokens; unsigned int tokens_avail = 0; @@ -12965,9 +12973,13 @@ c_parser_omp_variable_list (c_parser *parser, case OMP_CLAUSE_MAP: case OMP_CLAUSE_FROM: case OMP_CLAUSE_TO: - while (c_parser_next_token_is (parser, CPP_DOT)) + while (c_parser_next_token_is (parser, CPP_DOT) + || (allow_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)) + t = build_simple_mem_ref (t); c_parser_consume_token (parser); if (!c_parser_next_token_is (parser, CPP_NAME)) { @@ -13089,11 +13101,12 @@ c_parser_omp_variable_list (c_parser *parser, } /* Similarly, but expect leading and trailing parenthesis. This is a very - common case for OpenACC and OpenMP clauses. */ + common case for OpenACC and OpenMP clauses. The optional ALLOW_DEREF + argument is true if list items can use the deref (->) operator. */ static tree c_parser_omp_var_list_parens (c_parser *parser, enum omp_clause_code kind, - tree list) + tree list, bool allow_deref = false) { /* The clauses location. */ location_t loc = c_parser_peek_token (parser)->location; @@ -13101,18 +13114,20 @@ 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); + list = c_parser_omp_variable_list (parser, loc, kind, list, allow_deref); parens.skip_until_found_close (parser); } return list; } -/* OpenACC 2.0: +/* OpenACC 2.0+: + attach ( variable-list ) copy ( variable-list ) copyin ( variable-list ) copyout ( variable-list ) create ( variable-list ) delete ( variable-list ) + detach ( variable-list ) present ( variable-list ) */ static tree @@ -13122,6 +13137,9 @@ c_parser_oacc_data_clause (c_parser *parser, pragma_omp_clause c_kind, enum gomp_map_kind kind; switch (c_kind) { + case PRAGMA_OACC_CLAUSE_ATTACH: + kind = GOMP_MAP_ATTACH; + break; case PRAGMA_OACC_CLAUSE_COPY: kind = GOMP_MAP_TOFROM; break; @@ -13137,6 +13155,9 @@ c_parser_oacc_data_clause (c_parser *parser, pragma_omp_clause c_kind, case PRAGMA_OACC_CLAUSE_DELETE: kind = GOMP_MAP_RELEASE; break; + case PRAGMA_OACC_CLAUSE_DETACH: + kind = GOMP_MAP_DETACH; + break; case PRAGMA_OACC_CLAUSE_DEVICE: kind = GOMP_MAP_FORCE_TO; break; @@ -13156,7 +13177,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); + nl = c_parser_omp_var_list_parens (parser, OMP_CLAUSE_MAP, list, true); for (c = nl; c != list; c = OMP_CLAUSE_CHAIN (c)) OMP_CLAUSE_SET_MAP_KIND (c, kind); @@ -15871,6 +15892,10 @@ c_parser_oacc_all_clauses (c_parser *parser, omp_clause_mask mask, clauses); c_name = "auto"; break; + case PRAGMA_OACC_CLAUSE_ATTACH: + clauses = c_parser_oacc_data_clause (parser, c_kind, clauses); + c_name = "attach"; + break; case PRAGMA_OACC_CLAUSE_COLLAPSE: clauses = c_parser_omp_clause_collapse (parser, clauses); c_name = "collapse"; @@ -15899,6 +15924,10 @@ c_parser_oacc_all_clauses (c_parser *parser, omp_clause_mask mask, clauses = c_parser_omp_clause_default (parser, clauses, true); c_name = "default"; break; + case PRAGMA_OACC_CLAUSE_DETACH: + clauses = c_parser_oacc_data_clause (parser, c_kind, clauses); + c_name = "detach"; + break; case PRAGMA_OACC_CLAUSE_DEVICE: clauses = c_parser_oacc_data_clause (parser, c_kind, clauses); c_name = "device"; @@ -16409,7 +16438,8 @@ c_parser_oacc_cache (location_t loc, c_parser *parser) */ #define OACC_DATA_CLAUSE_MASK \ - ( (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_COPY) \ + ( (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_ATTACH) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_COPY) \ | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_COPYIN) \ | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_COPYOUT) \ | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_CREATE) \ @@ -16592,6 +16622,7 @@ c_parser_oacc_declare (c_parser *parser) #define OACC_ENTER_DATA_CLAUSE_MASK \ ( (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_IF) \ | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_ASYNC) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_ATTACH) \ | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_COPYIN) \ | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_CREATE) \ | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_WAIT) ) @@ -16601,6 +16632,7 @@ c_parser_oacc_declare (c_parser *parser) | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_ASYNC) \ | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_COPYOUT) \ | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_DELETE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_DETACH) \ | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_FINALIZE) \ | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_WAIT) ) @@ -16740,6 +16772,7 @@ c_parser_oacc_loop (location_t loc, c_parser *parser, char *p_name, #define OACC_KERNELS_CLAUSE_MASK \ ( (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_ASYNC) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_ATTACH) \ | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_COPY) \ | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_COPYIN) \ | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_COPYOUT) \ @@ -16755,6 +16788,7 @@ c_parser_oacc_loop (location_t loc, c_parser *parser, char *p_name, #define OACC_PARALLEL_CLAUSE_MASK \ ( (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_ASYNC) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_ATTACH) \ | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_COPY) \ | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_COPYIN) \ | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_COPYOUT) \ @@ -16773,6 +16807,7 @@ c_parser_oacc_loop (location_t loc, c_parser *parser, char *p_name, #define OACC_SERIAL_CLAUSE_MASK \ ( (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_ASYNC) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_ATTACH) \ | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_COPY) \ | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_COPYIN) \ | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_COPYOUT) \ diff --git a/gcc/c/c-typeck.c b/gcc/c/c-typeck.c index 36aedc063d2..db03b3c97d4 100644 --- a/gcc/c/c-typeck.c +++ b/gcc/c/c-typeck.c @@ -12897,7 +12897,6 @@ handle_omp_array_sections_1 (tree c, tree t, vec &types, return error_mark_node; } if (TREE_CODE (t) == COMPONENT_REF - && ort == C_ORT_OMP && (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_MAP || OMP_CLAUSE_CODE (c) == OMP_CLAUSE_TO || OMP_CLAUSE_CODE (c) == OMP_CLAUSE_FROM)) @@ -12918,6 +12917,15 @@ handle_omp_array_sections_1 (tree c, tree t, vec &types, return error_mark_node; } 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); + } } } if (!VAR_P (t) && TREE_CODE (t) != PARM_DECL) @@ -13003,7 +13011,18 @@ handle_omp_array_sections_1 (tree c, tree t, vec &types, length = fold_convert (sizetype, length); if (low_bound == NULL_TREE) low_bound = integer_zero_node; - + if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_MAP + && (OMP_CLAUSE_MAP_KIND (c) == GOMP_MAP_ATTACH + || OMP_CLAUSE_MAP_KIND (c) == GOMP_MAP_DETACH)) + { + if (length != integer_one_node) + { + error_at (OMP_CLAUSE_LOCATION (c), + "expected single pointer in %qs clause", + c_omp_map_clause_name (c, ort == C_ORT_ACC)); + return error_mark_node; + } + } if (length != NULL_TREE) { if (!integer_nonzerop (length)) @@ -13443,7 +13462,11 @@ handle_omp_array_sections (tree c, enum c_omp_region_type ort) if (ort != C_ORT_OMP && ort != C_ORT_ACC) OMP_CLAUSE_SET_MAP_KIND (c2, GOMP_MAP_POINTER); else if (TREE_CODE (t) == COMPONENT_REF) - OMP_CLAUSE_SET_MAP_KIND (c2, GOMP_MAP_ALWAYS_POINTER); + { + gomp_map_kind k = (ort == C_ORT_ACC) ? GOMP_MAP_ATTACH_DETACH + : GOMP_MAP_ALWAYS_POINTER; + OMP_CLAUSE_SET_MAP_KIND (c2, k); + } else OMP_CLAUSE_SET_MAP_KIND (c2, GOMP_MAP_FIRSTPRIVATE_POINTER); if (OMP_CLAUSE_MAP_KIND (c2) != GOMP_MAP_FIRSTPRIVATE_POINTER @@ -13680,6 +13703,35 @@ c_omp_finish_iterators (tree iter) return ret; } +/* Ensure that pointers are used in OpenACC attach and detach clauses. + Return true if an error has been detected. */ + +static bool +c_oacc_check_attachments (tree c) +{ + if (OMP_CLAUSE_CODE (c) != OMP_CLAUSE_MAP) + return false; + + /* OpenACC attach / detach clauses must be pointers. */ + if (OMP_CLAUSE_MAP_KIND (c) == GOMP_MAP_ATTACH + || OMP_CLAUSE_MAP_KIND (c) == GOMP_MAP_DETACH) + { + tree t = OMP_CLAUSE_DECL (c); + + while (TREE_CODE (t) == TREE_LIST) + t = TREE_CHAIN (t); + + if (TREE_CODE (TREE_TYPE (t)) != POINTER_TYPE) + { + error_at (OMP_CLAUSE_LOCATION (c), "expected pointer in %qs clause", + c_omp_map_clause_name (c, true)); + return true; + } + } + + return false; +} + /* For all elements of CLAUSES, validate them against their constraints. Remove any elements from the list that are invalid. */ @@ -14433,6 +14485,8 @@ c_finish_omp_clauses (tree clauses, enum c_omp_region_type ort) } } } + if (c_oacc_check_attachments (c)) + remove = true; break; } if (t == error_mark_node) @@ -14440,8 +14494,13 @@ c_finish_omp_clauses (tree clauses, enum c_omp_region_type ort) remove = true; break; } + /* OpenACC attach / detach clauses must be pointers. */ + if (c_oacc_check_attachments (c)) + { + remove = true; + break; + } if (TREE_CODE (t) == COMPONENT_REF - && (ort & C_ORT_OMP) && OMP_CLAUSE_CODE (c) != OMP_CLAUSE__CACHE_) { if (DECL_BIT_FIELD (TREE_OPERAND (t, 1))) @@ -14476,6 +14535,15 @@ c_finish_omp_clauses (tree clauses, enum c_omp_region_type ort) break; } 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); + } } if (remove) break; diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index 16d1359c47d..c7aa071088d 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -33124,6 +33124,8 @@ cp_parser_omp_clause_name (cp_parser *parser) result = PRAGMA_OMP_CLAUSE_ALIGNED; else if (!strcmp ("async", p)) result = PRAGMA_OACC_CLAUSE_ASYNC; + else if (!strcmp ("attach", p)) + result = PRAGMA_OACC_CLAUSE_ATTACH; break; case 'b': if (!strcmp ("bind", p)) @@ -33148,6 +33150,8 @@ cp_parser_omp_clause_name (cp_parser *parser) result = PRAGMA_OMP_CLAUSE_DEFAULTMAP; else if (!strcmp ("depend", p)) result = PRAGMA_OMP_CLAUSE_DEPEND; + else if (!strcmp ("detach", p)) + result = PRAGMA_OACC_CLAUSE_DETACH; else if (!strcmp ("device", p)) result = PRAGMA_OMP_CLAUSE_DEVICE; else if (!strcmp ("deviceptr", p)) @@ -33350,11 +33354,15 @@ check_no_duplicate_clause (tree clauses, enum omp_clause_code code, COLON can be NULL if only closing parenthesis should end the list, or pointer to bool which will receive false if the list is terminated - by closing parenthesis or true if the list is terminated by colon. */ + by closing parenthesis or true if the list is terminated by colon. + + The optional ALLOW_DEREF argument is true if list items can use the deref + (->) operator. */ static tree cp_parser_omp_var_list_no_open (cp_parser *parser, enum omp_clause_code kind, - tree list, bool *colon) + tree list, bool *colon, + bool allow_deref = false) { cp_token *token; bool saved_colon_corrects_to_scope_p = parser->colon_corrects_to_scope_p; @@ -33435,15 +33443,20 @@ cp_parser_omp_var_list_no_open (cp_parser *parser, enum omp_clause_code kind, case OMP_CLAUSE_MAP: case OMP_CLAUSE_FROM: case OMP_CLAUSE_TO: - while (cp_lexer_next_token_is (parser->lexer, CPP_DOT)) + while (cp_lexer_next_token_is (parser->lexer, CPP_DOT) + || (allow_deref + && cp_lexer_next_token_is (parser->lexer, CPP_DEREF))) { + cpp_ttype ttype + = cp_lexer_next_token_is (parser->lexer, CPP_DOT) + ? CPP_DOT : CPP_DEREF; location_t loc = cp_lexer_peek_token (parser->lexer)->location; cp_id_kind idk = CP_ID_KIND_NONE; cp_lexer_consume_token (parser->lexer); decl = convert_from_reference (decl); decl - = cp_parser_postfix_dot_deref_expression (parser, CPP_DOT, + = cp_parser_postfix_dot_deref_expression (parser, ttype, decl, false, &idk, loc); } @@ -33561,19 +33574,23 @@ cp_parser_omp_var_list_no_open (cp_parser *parser, enum omp_clause_code kind, common case for omp clauses. */ static tree -cp_parser_omp_var_list (cp_parser *parser, enum omp_clause_code kind, tree list) +cp_parser_omp_var_list (cp_parser *parser, enum omp_clause_code kind, tree list, + bool allow_deref = false) { if (cp_parser_require (parser, CPP_OPEN_PAREN, RT_OPEN_PAREN)) - return cp_parser_omp_var_list_no_open (parser, kind, list, NULL); + return cp_parser_omp_var_list_no_open (parser, kind, list, NULL, + allow_deref); return list; } -/* OpenACC 2.0: +/* OpenACC 2.0+: + attach ( variable-list ) copy ( variable-list ) copyin ( variable-list ) copyout ( variable-list ) create ( variable-list ) delete ( variable-list ) + detach ( variable-list ) present ( variable-list ) */ static tree @@ -33583,6 +33600,9 @@ cp_parser_oacc_data_clause (cp_parser *parser, pragma_omp_clause c_kind, enum gomp_map_kind kind; switch (c_kind) { + case PRAGMA_OACC_CLAUSE_ATTACH: + kind = GOMP_MAP_ATTACH; + break; case PRAGMA_OACC_CLAUSE_COPY: kind = GOMP_MAP_TOFROM; break; @@ -33598,6 +33618,9 @@ cp_parser_oacc_data_clause (cp_parser *parser, pragma_omp_clause c_kind, case PRAGMA_OACC_CLAUSE_DELETE: kind = GOMP_MAP_RELEASE; break; + case PRAGMA_OACC_CLAUSE_DETACH: + kind = GOMP_MAP_DETACH; + break; case PRAGMA_OACC_CLAUSE_DEVICE: kind = GOMP_MAP_FORCE_TO; break; @@ -33617,7 +33640,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); + nl = cp_parser_omp_var_list (parser, OMP_CLAUSE_MAP, list, true); for (c = nl; c != list; c = OMP_CLAUSE_CHAIN (c)) OMP_CLAUSE_SET_MAP_KIND (c, kind); @@ -36095,6 +36118,10 @@ cp_parser_oacc_all_clauses (cp_parser *parser, omp_clause_mask mask, clauses); c_name = "auto"; break; + case PRAGMA_OACC_CLAUSE_ATTACH: + clauses = cp_parser_oacc_data_clause (parser, c_kind, clauses); + c_name = "attach"; + break; case PRAGMA_OACC_CLAUSE_COLLAPSE: clauses = cp_parser_omp_clause_collapse (parser, clauses, here); c_name = "collapse"; @@ -36123,6 +36150,10 @@ cp_parser_oacc_all_clauses (cp_parser *parser, omp_clause_mask mask, clauses = cp_parser_omp_clause_default (parser, clauses, here, true); c_name = "default"; break; + case PRAGMA_OACC_CLAUSE_DETACH: + clauses = cp_parser_oacc_data_clause (parser, c_kind, clauses); + c_name = "detach"; + break; case PRAGMA_OACC_CLAUSE_DEVICE: clauses = cp_parser_oacc_data_clause (parser, c_kind, clauses); c_name = "device"; @@ -39971,10 +40002,12 @@ cp_parser_oacc_cache (cp_parser *parser, cp_token *pragma_tok) structured-block */ #define OACC_DATA_CLAUSE_MASK \ - ( (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_COPY) \ + ( (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_ATTACH) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_COPY) \ | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_COPYIN) \ | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_COPYOUT) \ | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_CREATE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_DETACH) \ | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_DEVICEPTR) \ | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_IF) \ | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_PRESENT) ) @@ -40174,6 +40207,7 @@ cp_parser_oacc_declare (cp_parser *parser, cp_token *pragma_tok) #define OACC_ENTER_DATA_CLAUSE_MASK \ ( (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_IF) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_ATTACH) \ | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_ASYNC) \ | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_COPYIN) \ | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_CREATE) \ @@ -40184,6 +40218,7 @@ cp_parser_oacc_declare (cp_parser *parser, cp_token *pragma_tok) | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_ASYNC) \ | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_COPYOUT) \ | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_DELETE) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_DETACH) \ | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_FINALIZE) \ | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_WAIT) ) @@ -40291,6 +40326,7 @@ cp_parser_oacc_loop (cp_parser *parser, cp_token *pragma_tok, char *p_name, #define OACC_KERNELS_CLAUSE_MASK \ ( (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_ASYNC) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_ATTACH) \ | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_COPY) \ | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_COPYIN) \ | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_COPYOUT) \ @@ -40306,6 +40342,7 @@ cp_parser_oacc_loop (cp_parser *parser, cp_token *pragma_tok, char *p_name, #define OACC_PARALLEL_CLAUSE_MASK \ ( (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_ASYNC) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_ATTACH) \ | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_COPY) \ | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_COPYIN) \ | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_COPYOUT) \ @@ -40324,6 +40361,7 @@ cp_parser_oacc_loop (cp_parser *parser, cp_token *pragma_tok, char *p_name, #define OACC_SERIAL_CLAUSE_MASK \ ( (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_ASYNC) \ + | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_ATTACH) \ | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_COPY) \ | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_COPYIN) \ | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_COPYOUT) \ diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c index 42611682549..dec22494cd9 100644 --- a/gcc/cp/semantics.c +++ b/gcc/cp/semantics.c @@ -4740,7 +4740,6 @@ handle_omp_array_sections_1 (tree c, tree t, vec &types, t = TREE_OPERAND (t, 0); ret = t; if (TREE_CODE (t) == COMPONENT_REF - && ort == C_ORT_OMP && (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_MAP || OMP_CLAUSE_CODE (c) == OMP_CLAUSE_TO || OMP_CLAUSE_CODE (c) == OMP_CLAUSE_FROM) @@ -4764,6 +4763,8 @@ handle_omp_array_sections_1 (tree c, tree t, vec &types, return error_mark_node; } t = TREE_OPERAND (t, 0); + if (ort == C_ORT_ACC && TREE_CODE (t) == INDIRECT_REF) + t = TREE_OPERAND (t, 0); } if (REFERENCE_REF_P (t)) t = TREE_OPERAND (t, 0); @@ -4863,6 +4864,18 @@ handle_omp_array_sections_1 (tree c, tree t, vec &types, if (low_bound == NULL_TREE) low_bound = integer_zero_node; + if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_MAP + && (OMP_CLAUSE_MAP_KIND (c) == GOMP_MAP_ATTACH + || OMP_CLAUSE_MAP_KIND (c) == GOMP_MAP_DETACH)) + { + if (length != integer_one_node) + { + error_at (OMP_CLAUSE_LOCATION (c), + "expected single pointer in %qs clause", + c_omp_map_clause_name (c, ort == C_ORT_ACC)); + return error_mark_node; + } + } if (length != NULL_TREE) { if (!integer_nonzerop (length)) @@ -5310,12 +5323,18 @@ handle_omp_array_sections (tree c, enum c_omp_region_type ort) if ((ort & C_ORT_OMP_DECLARE_SIMD) != C_ORT_OMP && ort != C_ORT_ACC) OMP_CLAUSE_SET_MAP_KIND (c2, GOMP_MAP_POINTER); else if (TREE_CODE (t) == COMPONENT_REF) - OMP_CLAUSE_SET_MAP_KIND (c2, GOMP_MAP_ALWAYS_POINTER); + { + gomp_map_kind k = (ort == C_ORT_ACC) ? GOMP_MAP_ATTACH_DETACH + : GOMP_MAP_ALWAYS_POINTER; + OMP_CLAUSE_SET_MAP_KIND (c2, k); + } else if (REFERENCE_REF_P (t) && TREE_CODE (TREE_OPERAND (t, 0)) == COMPONENT_REF) { t = TREE_OPERAND (t, 0); - OMP_CLAUSE_SET_MAP_KIND (c2, GOMP_MAP_ALWAYS_POINTER); + gomp_map_kind k = (ort == C_ORT_ACC) ? GOMP_MAP_ATTACH_DETACH + : GOMP_MAP_ALWAYS_POINTER; + OMP_CLAUSE_SET_MAP_KIND (c2, k); } else OMP_CLAUSE_SET_MAP_KIND (c2, GOMP_MAP_FIRSTPRIVATE_POINTER); @@ -6238,6 +6257,41 @@ cp_omp_finish_iterators (tree iter) return ret; } +/* Ensure that pointers are used in OpenACC attach and detach clauses. + Return true if an error has been detected. */ + +static bool +cp_oacc_check_attachments (tree c) +{ + if (OMP_CLAUSE_CODE (c) != OMP_CLAUSE_MAP) + return false; + + /* OpenACC attach / detach clauses must be pointers. */ + if (OMP_CLAUSE_MAP_KIND (c) == GOMP_MAP_ATTACH + || OMP_CLAUSE_MAP_KIND (c) == GOMP_MAP_DETACH) + { + tree t = OMP_CLAUSE_DECL (c); + tree type; + + while (TREE_CODE (t) == TREE_LIST) + t = TREE_CHAIN (t); + + type = TREE_TYPE (t); + + if (TREE_CODE (type) == REFERENCE_TYPE) + type = TREE_TYPE (type); + + if (TREE_CODE (type) != POINTER_TYPE) + { + error_at (OMP_CLAUSE_LOCATION (c), "expected pointer in %qs clause", + c_omp_map_clause_name (c, true)); + return true; + } + } + + return false; +} + /* For all elements of CLAUSES, validate them vs OpenMP constraints. Remove any elements from the list that are invalid. */ @@ -6502,7 +6556,7 @@ finish_omp_clauses (tree clauses, enum c_omp_region_type ort) t = OMP_CLAUSE_DECL (c); check_dup_generic_t: if (t == current_class_ptr - && (ort != C_ORT_OMP_DECLARE_SIMD + && ((ort != C_ORT_OMP_DECLARE_SIMD && ort != C_ORT_ACC) || (OMP_CLAUSE_CODE (c) != OMP_CLAUSE_LINEAR && OMP_CLAUSE_CODE (c) != OMP_CLAUSE_UNIFORM))) { @@ -6572,8 +6626,7 @@ finish_omp_clauses (tree clauses, enum c_omp_region_type ort) handle_field_decl: if (!remove && TREE_CODE (t) == FIELD_DECL - && t == OMP_CLAUSE_DECL (c) - && ort != C_ORT_ACC) + && t == OMP_CLAUSE_DECL (c)) { OMP_CLAUSE_DECL (c) = omp_privatize_field (t, (OMP_CLAUSE_CODE (c) @@ -6640,7 +6693,7 @@ finish_omp_clauses (tree clauses, enum c_omp_region_type ort) omp_note_field_privatization (t, OMP_CLAUSE_DECL (c)); else t = OMP_CLAUSE_DECL (c); - if (t == current_class_ptr) + if (ort != C_ORT_ACC && t == current_class_ptr) { error_at (OMP_CLAUSE_LOCATION (c), "% allowed in OpenMP only in %" @@ -7129,7 +7182,7 @@ finish_omp_clauses (tree clauses, enum c_omp_region_type ort) } if (t == error_mark_node) remove = true; - else if (t == current_class_ptr) + else if (ort != C_ORT_ACC && t == current_class_ptr) { error_at (OMP_CLAUSE_LOCATION (c), "% allowed in OpenMP only in %" @@ -7261,6 +7314,8 @@ finish_omp_clauses (tree clauses, enum c_omp_region_type ort) } } } + if (cp_oacc_check_attachments (c)) + remove = true; break; } if (t == error_mark_node) @@ -7268,14 +7323,25 @@ finish_omp_clauses (tree clauses, enum c_omp_region_type ort) remove = true; break; } + /* OpenACC attach / detach clauses must be pointers. */ + if (cp_oacc_check_attachments (c)) + { + remove = true; + break; + } if (REFERENCE_REF_P (t) && TREE_CODE (TREE_OPERAND (t, 0)) == COMPONENT_REF) { t = TREE_OPERAND (t, 0); OMP_CLAUSE_DECL (c) = t; } + if (ort == C_ORT_ACC + && TREE_CODE (t) == COMPONENT_REF + && TREE_CODE (TREE_OPERAND (t, 0)) == INDIRECT_REF) + t = TREE_OPERAND (TREE_OPERAND (t, 0), 0); if (TREE_CODE (t) == COMPONENT_REF - && (ort & C_ORT_OMP_DECLARE_SIMD) == C_ORT_OMP + && ((ort & C_ORT_OMP_DECLARE_SIMD) == C_ORT_OMP + || ort == C_ORT_ACC) && OMP_CLAUSE_CODE (c) != OMP_CLAUSE__CACHE_) { if (type_dependent_expression_p (t)) @@ -7325,7 +7391,8 @@ finish_omp_clauses (tree clauses, enum c_omp_region_type ort) break; 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_ALWAYS_POINTER + || OMP_CLAUSE_MAP_KIND (c) == GOMP_MAP_ATTACH_DETACH)) break; if (DECL_P (t)) error_at (OMP_CLAUSE_LOCATION (c), @@ -7407,7 +7474,9 @@ finish_omp_clauses (tree clauses, enum c_omp_region_type ort) else bitmap_set_bit (&generic_head, DECL_UID (t)); } - else if (bitmap_bit_p (&map_head, DECL_UID (t))) + else if (bitmap_bit_p (&map_head, DECL_UID (t)) + && (ort != C_ORT_ACC + || !bitmap_bit_p (&map_field_head, DECL_UID (t)))) { if (OMP_CLAUSE_CODE (c) != OMP_CLAUSE_MAP) error_at (OMP_CLAUSE_LOCATION (c), @@ -7462,7 +7531,12 @@ finish_omp_clauses (tree clauses, 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_ALWAYS_POINTER); + { + gomp_map_kind k + = (ort == C_ORT_ACC) ? GOMP_MAP_ATTACH_DETACH + : GOMP_MAP_ALWAYS_POINTER; + OMP_CLAUSE_SET_MAP_KIND (c2, k); + } else OMP_CLAUSE_SET_MAP_KIND (c2, GOMP_MAP_FIRSTPRIVATE_REFERENCE); diff --git a/gcc/testsuite/c-c++-common/goacc/deep-copy-arrayofstruct.c b/gcc/testsuite/c-c++-common/goacc/deep-copy-arrayofstruct.c new file mode 100644 index 00000000000..d411bcfa8e7 --- /dev/null +++ b/gcc/testsuite/c-c++-common/goacc/deep-copy-arrayofstruct.c @@ -0,0 +1,84 @@ +/* { dg-do compile } */ + +#include +#include + +typedef struct { + int *a; + int *b; + int *c; +} mystruct; + +int main(int argc, char* argv[]) +{ + const int N = 1024; + const int S = 32; + mystruct *m = (mystruct *) calloc (S, sizeof (*m)); + int i, j; + + for (i = 0; i < S; i++) + { + m[i].a = (int *) malloc (N * sizeof (int)); + m[i].b = (int *) malloc (N * sizeof (int)); + m[i].c = (int *) malloc (N * sizeof (int)); + } + + for (j = 0; j < S; j++) + for (i = 0; i < N; i++) + { + m[j].a[i] = 0; + m[j].b[i] = 0; + m[j].c[i] = 0; + } + +#pragma acc enter data copyin(m[0:1]) + + for (int i = 0; i < 99; i++) + { + int j, k; + for (k = 0; k < S; k++) +#pragma acc parallel loop copy(m[k].a[0:N]) /* { dg-error "expected .\\\). before .\\\.. token" } */ + for (j = 0; j < N; j++) + m[k].a[j]++; + + for (k = 0; k < S; k++) +#pragma acc parallel loop copy(m[k].b[0:N], m[k].c[5:N-10]) /* { dg-error "expected .\\\). before .\\\.. token" } */ + /* { dg-error ".m. appears more than once in data clauses" "" { target c++ } .-1 } */ + for (j = 0; j < N; j++) + { + m[k].b[j]++; + if (j > 5 && j < N - 5) + m[k].c[j]++; + } + } + +#pragma acc exit data copyout(m[0:1]) + + for (j = 0; j < S; j++) + { + for (i = 0; i < N; i++) + { + if (m[j].a[i] != 99) + abort (); + if (m[j].b[i] != 99) + abort (); + if (i > 5 && i < N-5) + { + if (m[j].c[i] != 99) + abort (); + } + else + { + if (m[j].c[i] != 0) + abort (); + } + } + + free (m[j].a); + free (m[j].b); + free (m[j].c); + } + free (m); + + return 0; +} diff --git a/gcc/testsuite/c-c++-common/goacc/mdc-1.c b/gcc/testsuite/c-c++-common/goacc/mdc-1.c new file mode 100644 index 00000000000..6c6a81ea73a --- /dev/null +++ b/gcc/testsuite/c-c++-common/goacc/mdc-1.c @@ -0,0 +1,55 @@ +/* Test OpenACC's support for manual deep copy, including the attach + and detach clauses. */ + +/* { dg-do compile { target int32 } } */ +/* { dg-additional-options "-fdump-tree-omplower" } */ + +void +t1 () +{ + struct foo { + int *a, *b, c, d, *e; + } s; + + int *a, *z; + +#pragma acc enter data copyin(s) + { +#pragma acc data copy(s.a[0:10]) copy(z[0:10]) + { + s.e = z; +#pragma acc parallel loop attach(s.e) + for (int i = 0; i < 10; i++) + s.a[i] = s.e[i]; + + + a = s.e; +#pragma acc enter data attach(a) +#pragma acc exit data detach(a) + } + +#pragma acc enter data copyin(a) +#pragma acc acc enter data attach(s.e) +#pragma acc exit data detach(s.e) + +#pragma acc data attach(s.e) + { + } +#pragma acc exit data delete(a) + +#pragma acc exit data detach(a) finalize +#pragma acc exit data detach(s.a) finalize + } +} + +/* { dg-final { scan-tree-dump-times "pragma omp target oacc_enter_exit_data map.to:s .len: 32.." 1 "omplower" } } */ +/* { dg-final { scan-tree-dump-times "pragma omp target oacc_data map.tofrom:.z .len: 40.. map.struct:s .len: 1.. map.alloc:s.a .len: 8.. map.tofrom:._1 .len: 40.. map.attach:s.a .bias: 0.." 1 "omplower" } } */ +/* { dg-final { scan-tree-dump-times "pragma omp target oacc_parallel map.attach:s.e .bias: 8.. map.tofrom:s .len: 32" 1 "omplower" } } */ +/* { dg-final { scan-tree-dump-times "pragma omp target oacc_enter_exit_data map.attach:a .bias: 8.." 1 "omplower" } } */ +/* { dg-final { scan-tree-dump-times "pragma omp target oacc_enter_exit_data map.detach:a .bias: 8.." 1 "omplower" } } */ +/* { dg-final { scan-tree-dump-times "pragma omp target oacc_enter_exit_data map.to:a .len: 8.." 1 "omplower" } } */ +/* { dg-final { scan-tree-dump-times "pragma omp target oacc_enter_exit_data map.detach:s.e .bias: 8.." 1 "omplower" } } */ +/* { dg-final { scan-tree-dump-times "pragma omp target oacc_data map.attach:s.e .bias: 8.." 1 "omplower" } } */ +/* { dg-final { scan-tree-dump-times "pragma omp target oacc_enter_exit_data map.release:a .len: 8.." 1 "omplower" } } */ +/* { dg-final { scan-tree-dump-times "pragma omp target oacc_enter_exit_data finalize map.force_detach:a .bias: 8.." 1 "omplower" } } */ +/* { dg-final { scan-tree-dump-times "pragma omp target oacc_enter_exit_data finalize map.force_detach:s.a .bias: 8.." 1 "omplower" } } */ diff --git a/gcc/testsuite/c-c++-common/goacc/mdc-2.c b/gcc/testsuite/c-c++-common/goacc/mdc-2.c new file mode 100644 index 00000000000..fae86671fc9 --- /dev/null +++ b/gcc/testsuite/c-c++-common/goacc/mdc-2.c @@ -0,0 +1,62 @@ +/* Test OpenACC's support for manual deep copy, including the attach + and detach clauses. */ + +void +t1 () +{ + struct foo { + int *a, *b, c, d, *e; + } s; + + int *a, *z, scalar, **y; + +#pragma acc enter data copyin(s) detach(z) /* { dg-error ".detach. is not valid for" } */ + { +#pragma acc data copy(s.a[0:10]) copy(z[0:10]) + { + s.e = z; +#pragma acc parallel loop attach(s.e) detach(s.b) /* { dg-error ".detach. is not valid for" } */ + for (int i = 0; i < 10; i++) + s.a[i] = s.e[i]; + + a = s.e; +#pragma acc enter data attach(a) detach(s.c) /* { dg-error ".detach. is not valid for" } */ +#pragma acc exit data detach(a) + } + +#pragma acc enter data attach(z[:5]) /* { dg-error "expected single pointer in .attach. clause" } */ +/* { dg-error "has no data movement clause" "" { target *-*-* } .-1 } */ +#pragma acc exit data detach(z[:5]) /* { dg-error "expected single pointer in .detach. clause" } */ +/* { dg-error "has no data movement clause" "" { target *-*-* } .-1 } */ +#pragma acc enter data attach(z[1:]) /* { dg-error "expected single pointer in .attach. clause" } */ +/* { dg-error "has no data movement clause" "" { target *-*-* } .-1 } */ +#pragma acc exit data detach(z[1:]) /* { dg-error "expected single pointer in .detach. clause" } */ +/* { dg-error "has no data movement clause" "" { target *-*-* } .-1 } */ +#pragma acc enter data attach(z[:]) /* { dg-error "expected single pointer in .attach. clause" } */ +/* { dg-error "has no data movement clause" "" { target *-*-* } .-1 } */ +#pragma acc exit data detach(z[:]) /* { dg-error "expected single pointer in .detach. clause" } */ +/* { dg-error "has no data movement clause" "" { target *-*-* } .-1 } */ +#pragma acc enter data attach(z[3]) /* { dg-error "expected pointer in .attach. clause" } */ +#pragma acc exit data detach(z[3]) /* { dg-error "expected pointer in .detach. clause" } */ + +#pragma acc acc enter data attach(s.e) +#pragma acc exit data detach(s.e) attach(z) /* { dg-error ".attach. is not valid for" } */ + +#pragma acc data attach(s.e) + { + } +#pragma acc exit data delete(a) attach(s.a) /* { dg-error ".attach. is not valid for" } */ + +#pragma acc enter data attach(scalar) /* { dg-error "expected pointer in .attach. clause" } */ +/* { dg-error "has no data movement clause" "" { target *-*-* } .-1 } */ +#pragma acc exit data detach(scalar) /* { dg-error "expected pointer in .detach. clause" } */ +/* { dg-error "has no data movement clause" "" { target *-*-* } .-1 } */ +#pragma acc enter data attach(s) /* { dg-error "expected pointer in .attach. clause" } */ +/* { dg-error "has no data movement clause" "" { target *-*-* } .-1 } */ +#pragma acc exit data detach(s) /* { dg-error "expected pointer in .detach. clause" } */ +/* { dg-error "has no data movement clause" "" { target *-*-* } .-1 } */ + } + +#pragma acc enter data attach(y[10]) +#pragma acc exit data detach(y[10]) +} diff --git a/gcc/testsuite/g++.dg/goacc/mdc.C b/gcc/testsuite/g++.dg/goacc/mdc.C new file mode 100644 index 00000000000..b3abab30423 --- /dev/null +++ b/gcc/testsuite/g++.dg/goacc/mdc.C @@ -0,0 +1,68 @@ +/* Test OpenACC's support for manual deep copy, including the attach + and detach clauses. */ + +void +t1 () +{ + struct foo { + int *a, *b, c, d, *e; + } s; + + struct foo& rs = s; + + int *a, *z, scalar, **y; + int* const &ra = a; + int* const &rz = z; + int& rscalar = scalar; + int** const &ry = y; + +#pragma acc enter data copyin(rs) detach(rz) /* { dg-error ".detach. is not valid for" } */ + { +#pragma acc data copy(rs.a[0:10]) copy(rz[0:10]) + { + s.e = z; +#pragma acc parallel loop attach(rs.e) detach(rs.b) /* { dg-error ".detach. is not valid for" } */ + for (int i = 0; i < 10; i++) + s.a[i] = s.e[i]; + + a = s.e; +#pragma acc enter data attach(ra) detach(rs.c) /* { dg-error ".detach. is not valid for" } */ +#pragma acc exit data detach(ra) + } + +#pragma acc enter data attach(rz[:5]) /* { dg-error "expected single pointer in .attach. clause" } */ +/* { dg-error "has no data movement clause" "" { target *-*-* } .-1 } */ +#pragma acc exit data detach(rz[:5]) /* { dg-error "expected single pointer in .detach. clause" } */ +/* { dg-error "has no data movement clause" "" { target *-*-* } .-1 } */ +#pragma acc enter data attach(rz[1:]) /* { dg-error "expected single pointer in .attach. clause" } */ +/* { dg-error "has no data movement clause" "" { target *-*-* } .-1 } */ +#pragma acc exit data detach(rz[1:]) /* { dg-error "expected single pointer in .detach. clause" } */ +/* { dg-error "has no data movement clause" "" { target *-*-* } .-1 } */ +#pragma acc enter data attach(rz[:]) /* { dg-error "expected single pointer in .attach. clause" } */ +/* { dg-error "has no data movement clause" "" { target *-*-* } .-1 } */ +#pragma acc exit data detach(rz[:]) /* { dg-error "expected single pointer in .detach. clause" } */ +/* { dg-error "has no data movement clause" "" { target *-*-* } .-1 } */ +#pragma acc enter data attach(rz[3]) /* { dg-error "expected pointer in .attach. clause" } */ +#pragma acc exit data detach(rz[3]) /* { dg-error "expected pointer in .detach. clause" } */ + +#pragma acc acc enter data attach(rs.e) +#pragma acc exit data detach(rs.e) attach(rz) /* { dg-error ".attach. is not valid for" } */ + +#pragma acc data attach(rs.e) + { + } +#pragma acc exit data delete(ra) attach(rs.a) /* { dg-error ".attach. is not valid for" } */ + +#pragma acc enter data attach(rscalar) /* { dg-error "expected pointer in .attach. clause" } */ +/* { dg-error "has no data movement clause" "" { target *-*-* } .-1 } */ +#pragma acc exit data detach(rscalar) /* { dg-error "expected pointer in .detach. clause" } */ +/* { dg-error "has no data movement clause" "" { target *-*-* } .-1 } */ +#pragma acc enter data attach(rs) /* { dg-error "expected pointer in .attach. clause" } */ +/* { dg-error "has no data movement clause" "" { target *-*-* } .-1 } */ +#pragma acc exit data detach(rs) /* { dg-error "expected pointer in .detach. clause" } */ +/* { dg-error "has no data movement clause" "" { target *-*-* } .-1 } */ + } + +#pragma acc enter data attach(ry[10]) +#pragma acc exit data detach(ry[10]) +} From patchwork Wed Dec 18 06:04:53 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Julian Brown X-Patchwork-Id: 1211988 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=209.132.180.131; helo=sourceware.org; envelope-from=gcc-patches-return-516180-incoming=patchwork.ozlabs.org@gcc.gnu.org; receiver=) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=codesourcery.com Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=gcc.gnu.org header.i=@gcc.gnu.org header.b="D4DDpATA"; dkim-atps=neutral Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 47d4K26tK6z9sS3 for ; Wed, 18 Dec 2019 17:06:46 +1100 (AEDT) DomainKey-Signature: a=rsa-sha1; c=nofws; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:from :to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding:content-type; q=dns; s= default; b=QfuhiT99NRTA/fHhRCN+toDAfCbX2egXas9R2iyS25+WnT7Bj0umt kNtCJHXu2NeXqj/pykM7unkM4pytxQOiRHY0cnLwQQ7io57gDHDZlym1Jvdbc1g4 ubnGh0OWCDS5TN2c/eZ2uEFRSMVYDdstHrJLXLjHkZBsezQewKrD5A= DKIM-Signature: v=1; a=rsa-sha1; c=relaxed; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:from :to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding:content-type; s=default; bh=gtl0Pr7CSE6mknFHPaRjw7jY6Ig=; b=D4DDpATAMUx3MZqGpE47Ol4fHe7W vw++xsFIDa7L1Y7ayhKtAtfJWk4FCizb7Kl4x8UgvGx9uokY4krE4/Vga7ZGmqCQ TKNNw8TkpAejBSWR4iUOen+QEvZcCQ7D+penGXGhkWLu0Tt98pvetvQWdqM0jge2 lhytWr1vrZ8An/4= Received: (qmail 112241 invoked by alias); 18 Dec 2019 06:05:21 -0000 Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Delivered-To: mailing list gcc-patches@gcc.gnu.org Received: (qmail 112076 invoked by uid 89); 18 Dec 2019 06:05:20 -0000 Authentication-Results: sourceware.org; auth=none X-Spam-SWARE-Status: No, score=-24.1 required=5.0 tests=AWL, BAYES_00, GIT_PATCH_0, GIT_PATCH_1, GIT_PATCH_2, GIT_PATCH_3, KAM_SHORT, SPF_PASS autolearn=ham version=3.3.1 spammy=UD:ar X-HELO: esa1.mentor.iphmx.com Received: from esa1.mentor.iphmx.com (HELO esa1.mentor.iphmx.com) (68.232.129.153) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Wed, 18 Dec 2019 06:05:11 +0000 IronPort-SDR: LZBvGqcKJxGftn0s24cTAiNbH6gdBnm9GBjwwoo0oE+1/nmLfNyFksniytCx+eE0KMopYCnhWD ItdXWkvpOhVCOAw4Y5EaEqFDx3tmXkWcxdGhNIcAduKqWC9Y2k8op6fBZoj3ERzeSBfiSXTV1x Wf47PD9DW1fHO9T2n231Qjr6CaSu4v6/zUoQV+Iz7DPArt1TyrN4cAZuX0KevlVKzba7o8dsEd 35P/Cc72XjY3HfqOWqzBlvt456Ah40P6dd14y5m86XIiMSWXP3h9AUkSGlfFqOL4I/orcpqyzm a6U= Received: from orw-gwy-01-in.mentorg.com ([192.94.38.165]) by esa1.mentor.iphmx.com with ESMTP; 17 Dec 2019 22:05:09 -0800 IronPort-SDR: hKifNTqRtCVZB+z52bB3A3Ct6/yDzOglruQqskpF5FQYFA08eVBCDG/hoY3wnsyO0Ogicpw0pu ViDUjgRDntROFl91yKGLn7zwagEFPr9HEZqlSBAAYNdzZuuaWzda9xAq7JVzB+veNhITgeV4Is OJl6gDQI0M1u7ka0Pi+YZpPZgED4Q67EBWQV/DT3kNZcSv/72Q0Zk4BtwzCEyaqwELirTiA1cu hrFyk1YS0RFwpPkUMKJZfb1IOcZHBQzU9HDYGE86HltGVRYNRdn856Kb5h0dSWCOqcBUiICbFW I64= From: Julian Brown To: CC: Thomas Schwinge , Jakub Jelinek , Tobias Burnus , , Subject: [PATCH 10/13] OpenACC 2.6 deep copy: Fortran front-end parts Date: Tue, 17 Dec 2019 22:04:53 -0800 Message-ID: In-Reply-To: References: MIME-Version: 1.0 X-IsSubscribed: yes This patch has been broken out of the "OpenACC 2.6 manual deep copy support" patch, last posted here: https://gcc.gnu.org/ml/gcc-patches/2019-11/msg02376.html This part contains the Fortran front-end support for parsing the new attach and detach clauses, as well as derived-type members on other data-movement clauses (copyin, copyout, etc.). Tested alongside other patches in this series with offloading to NVPTX. OK? Thanks, Julian ChangeLog gcc/fortran/ * gfortran.h (gfc_omp_map_op): Add OMP_MAP_ATTACH, OMP_MAP_DETACH. * openmp.c (gfc_match_omp_variable_list): Add allow_derived parameter. Parse derived-type member accesses if true. (omp_mask2): Add OMP_CLAUSE_ATTACH and OMP_CLAUSE_DETACH. (gfc_match_omp_map_clause): Add allow_derived parameter. Pass to gfc_match_omp_variable_list. (gfc_match_omp_clauses): Support attach and detach. Support derived types for appropriate OpenACC directives. (OACC_PARALLEL_CLAUSES, OACC_SERIAL_CLAUSES, OACC_KERNELS_CLAUSES, OACC_DATA_CLAUSES, OACC_ENTER_DATA_CLAUSES): Add OMP_CLAUSE_ATTACH. (OACC_EXIT_DATA_CLAUSES): Add OMP_CLAUSE_DETACH. (check_symbol_not_pointer): Don't disallow pointer objects of derived type. (resolve_oacc_data_clauses): Don't disallow allocatable derived types. (resolve_omp_clauses): Perform duplicate checking only for non-derived type component accesses (plain variables and arrays or array sections). Support component refs. * trans-expr.c (gfc_conv_component_ref, conv_parent_component_references): Make global. (gfc_auto_dereference_var): New function, broken out of... (gfc_conv_variable): ...here. Call above function. * trans-openmp.c (gfc_omp_privatize_by_reference): Support component refs. (gfc_trans_omp_array_section): New function, broken out of... (gfc_trans_omp_clauses): ...here. Support component refs/derived types, attach and detach clauses. * trans.h (gfc_conv_component_ref, conv_parent_component_references, gfc_auto_dereference_var): Add prototypes. gcc/testsuite/ * gfortran.dg/goacc/derived-types.f90: New test. * gfortran.dg/goacc/derived-types-2.f90: New test. * gfortran.dg/goacc/data-clauses.f95: Adjust for expected errors. * gfortran.dg/goacc/enter-exit-data.f95: Likewise. --- gcc/fortran/gfortran.h | 2 + gcc/fortran/openmp.c | 160 +++++++--- gcc/fortran/trans-expr.c | 184 +++++------ gcc/fortran/trans-openmp.c | 287 ++++++++++++++---- gcc/fortran/trans.h | 8 + .../gfortran.dg/goacc/data-clauses.f95 | 38 +-- .../gfortran.dg/goacc/derived-types-2.f90 | 14 + .../gfortran.dg/goacc/derived-types.f90 | 77 +++++ .../gfortran.dg/goacc/enter-exit-data.f95 | 24 +- 9 files changed, 561 insertions(+), 233 deletions(-) create mode 100644 gcc/testsuite/gfortran.dg/goacc/derived-types-2.f90 create mode 100644 gcc/testsuite/gfortran.dg/goacc/derived-types.f90 diff --git a/gcc/fortran/gfortran.h b/gcc/fortran/gfortran.h index f4a2b99bdc4..d3c0d0be217 100644 --- a/gcc/fortran/gfortran.h +++ b/gcc/fortran/gfortran.h @@ -1192,10 +1192,12 @@ enum gfc_omp_depend_op enum gfc_omp_map_op { OMP_MAP_ALLOC, + OMP_MAP_ATTACH, OMP_MAP_TO, OMP_MAP_FROM, OMP_MAP_TOFROM, OMP_MAP_DELETE, + OMP_MAP_DETACH, OMP_MAP_FORCE_ALLOC, OMP_MAP_FORCE_TO, OMP_MAP_FORCE_FROM, diff --git a/gcc/fortran/openmp.c b/gcc/fortran/openmp.c index dc0521b40f0..d79f4a90271 100644 --- a/gcc/fortran/openmp.c +++ b/gcc/fortran/openmp.c @@ -233,7 +233,8 @@ static match gfc_match_omp_variable_list (const char *str, gfc_omp_namelist **list, bool allow_common, bool *end_colon = NULL, gfc_omp_namelist ***headp = NULL, - bool allow_sections = false) + bool allow_sections = false, + bool allow_derived = false) { gfc_omp_namelist *head, *tail, *p; locus old_loc, cur_loc; @@ -259,7 +260,8 @@ gfc_match_omp_variable_list (const char *str, gfc_omp_namelist **list, case MATCH_YES: gfc_expr *expr; expr = NULL; - if (allow_sections && gfc_peek_ascii_char () == '(') + if ((allow_sections && gfc_peek_ascii_char () == '(') + || (allow_derived && gfc_peek_ascii_char () == '%')) { gfc_current_locus = cur_loc; m = gfc_match_variable (&expr, 0); @@ -797,7 +799,7 @@ enum omp_mask1 OMP_MASK1_LAST }; -/* OpenACC 2.0 specific clauses. */ +/* OpenACC 2.0+ specific clauses. */ enum omp_mask2 { OMP_CLAUSE_ASYNC, @@ -823,6 +825,8 @@ enum omp_mask2 OMP_CLAUSE_TILE, OMP_CLAUSE_IF_PRESENT, OMP_CLAUSE_FINALIZE, + OMP_CLAUSE_ATTACH, + OMP_CLAUSE_DETACH, /* This must come last. */ OMP_MASK2_LAST }; @@ -927,10 +931,11 @@ omp_inv_mask::omp_inv_mask (const omp_mask &m) : omp_mask (m) static bool gfc_match_omp_map_clause (gfc_omp_namelist **list, gfc_omp_map_op map_op, - bool allow_common) + bool allow_common, bool allow_derived) { gfc_omp_namelist **head = NULL; - if (gfc_match_omp_variable_list ("", list, allow_common, NULL, &head, true) + if (gfc_match_omp_variable_list ("", list, allow_common, NULL, &head, true, + allow_derived) == MATCH_YES) { gfc_omp_namelist *n; @@ -952,6 +957,14 @@ gfc_match_omp_clauses (gfc_omp_clauses **cp, const omp_mask mask, { gfc_omp_clauses *c = gfc_get_omp_clauses (); locus old_loc; + /* Determine whether we're dealing with an OpenACC directive that permits + derived type member accesses. This in particular disallows + "!$acc declare" from using such accesses, because it's not clear if/how + that should work. */ + bool allow_derived = (openacc + && ((mask & OMP_CLAUSE_ATTACH) + || (mask & OMP_CLAUSE_DETACH) + || (mask & OMP_CLAUSE_HOST_SELF))); gcc_checking_assert (OMP_MASK1_LAST <= 64 && OMP_MASK2_LAST <= 64); *cp = NULL; @@ -1025,6 +1038,12 @@ gfc_match_omp_clauses (gfc_omp_clauses **cp, const omp_mask mask, needs_space = true; continue; } + if ((mask & OMP_CLAUSE_ATTACH) + && gfc_match ("attach ( ") == MATCH_YES + && gfc_match_omp_map_clause (&c->lists[OMP_LIST_MAP], + OMP_MAP_ATTACH, false, + allow_derived)) + continue; break; case 'c': if ((mask & OMP_CLAUSE_COLLAPSE) @@ -1052,7 +1071,8 @@ gfc_match_omp_clauses (gfc_omp_clauses **cp, const omp_mask mask, if ((mask & OMP_CLAUSE_COPY) && gfc_match ("copy ( ") == MATCH_YES && gfc_match_omp_map_clause (&c->lists[OMP_LIST_MAP], - OMP_MAP_TOFROM, true)) + OMP_MAP_TOFROM, true, + allow_derived)) continue; if (mask & OMP_CLAUSE_COPYIN) { @@ -1060,7 +1080,8 @@ gfc_match_omp_clauses (gfc_omp_clauses **cp, const omp_mask mask, { if (gfc_match ("copyin ( ") == MATCH_YES && gfc_match_omp_map_clause (&c->lists[OMP_LIST_MAP], - OMP_MAP_TO, true)) + OMP_MAP_TO, true, + allow_derived)) continue; } else if (gfc_match_omp_variable_list ("copyin (", @@ -1071,7 +1092,7 @@ gfc_match_omp_clauses (gfc_omp_clauses **cp, const omp_mask mask, if ((mask & OMP_CLAUSE_COPYOUT) && gfc_match ("copyout ( ") == MATCH_YES && gfc_match_omp_map_clause (&c->lists[OMP_LIST_MAP], - OMP_MAP_FROM, true)) + OMP_MAP_FROM, true, allow_derived)) continue; if ((mask & OMP_CLAUSE_COPYPRIVATE) && gfc_match_omp_variable_list ("copyprivate (", @@ -1081,7 +1102,7 @@ gfc_match_omp_clauses (gfc_omp_clauses **cp, const omp_mask mask, if ((mask & OMP_CLAUSE_CREATE) && gfc_match ("create ( ") == MATCH_YES && gfc_match_omp_map_clause (&c->lists[OMP_LIST_MAP], - OMP_MAP_ALLOC, true)) + OMP_MAP_ALLOC, true, allow_derived)) continue; break; case 'd': @@ -1117,7 +1138,8 @@ gfc_match_omp_clauses (gfc_omp_clauses **cp, const omp_mask mask, if ((mask & OMP_CLAUSE_DELETE) && gfc_match ("delete ( ") == MATCH_YES && gfc_match_omp_map_clause (&c->lists[OMP_LIST_MAP], - OMP_MAP_RELEASE, true)) + OMP_MAP_RELEASE, true, + allow_derived)) continue; if ((mask & OMP_CLAUSE_DEPEND) && gfc_match ("depend ( ") == MATCH_YES) @@ -1160,6 +1182,12 @@ gfc_match_omp_clauses (gfc_omp_clauses **cp, const omp_mask mask, else gfc_current_locus = old_loc; } + if ((mask & OMP_CLAUSE_DETACH) + && gfc_match ("detach ( ") == MATCH_YES + && gfc_match_omp_map_clause (&c->lists[OMP_LIST_MAP], + OMP_MAP_DETACH, false, + allow_derived)) + continue; if ((mask & OMP_CLAUSE_DEVICE) && !openacc && c->device == NULL @@ -1169,12 +1197,14 @@ gfc_match_omp_clauses (gfc_omp_clauses **cp, const omp_mask mask, && openacc && gfc_match ("device ( ") == MATCH_YES && gfc_match_omp_map_clause (&c->lists[OMP_LIST_MAP], - OMP_MAP_FORCE_TO, true)) + OMP_MAP_FORCE_TO, true, + allow_derived)) continue; if ((mask & OMP_CLAUSE_DEVICEPTR) && gfc_match ("deviceptr ( ") == MATCH_YES && gfc_match_omp_map_clause (&c->lists[OMP_LIST_MAP], - OMP_MAP_FORCE_DEVICEPTR, false)) + OMP_MAP_FORCE_DEVICEPTR, false, + allow_derived)) continue; if ((mask & OMP_CLAUSE_DEVICE_RESIDENT) && gfc_match_omp_variable_list @@ -1252,7 +1282,8 @@ gfc_match_omp_clauses (gfc_omp_clauses **cp, const omp_mask mask, if ((mask & OMP_CLAUSE_HOST_SELF) && gfc_match ("host ( ") == MATCH_YES && gfc_match_omp_map_clause (&c->lists[OMP_LIST_MAP], - OMP_MAP_FORCE_FROM, true)) + OMP_MAP_FORCE_FROM, true, + allow_derived)) continue; break; case 'i': @@ -1524,47 +1555,49 @@ gfc_match_omp_clauses (gfc_omp_clauses **cp, const omp_mask mask, if ((mask & OMP_CLAUSE_COPY) && gfc_match ("pcopy ( ") == MATCH_YES && gfc_match_omp_map_clause (&c->lists[OMP_LIST_MAP], - OMP_MAP_TOFROM, true)) + OMP_MAP_TOFROM, true, allow_derived)) continue; if ((mask & OMP_CLAUSE_COPYIN) && gfc_match ("pcopyin ( ") == MATCH_YES && gfc_match_omp_map_clause (&c->lists[OMP_LIST_MAP], - OMP_MAP_TO, true)) + OMP_MAP_TO, true, allow_derived)) continue; if ((mask & OMP_CLAUSE_COPYOUT) && gfc_match ("pcopyout ( ") == MATCH_YES && gfc_match_omp_map_clause (&c->lists[OMP_LIST_MAP], - OMP_MAP_FROM, true)) + OMP_MAP_FROM, true, allow_derived)) continue; if ((mask & OMP_CLAUSE_CREATE) && gfc_match ("pcreate ( ") == MATCH_YES && gfc_match_omp_map_clause (&c->lists[OMP_LIST_MAP], - OMP_MAP_ALLOC, true)) + OMP_MAP_ALLOC, true, allow_derived)) continue; if ((mask & OMP_CLAUSE_PRESENT) && gfc_match ("present ( ") == MATCH_YES && gfc_match_omp_map_clause (&c->lists[OMP_LIST_MAP], - OMP_MAP_FORCE_PRESENT, false)) + OMP_MAP_FORCE_PRESENT, false, + allow_derived)) continue; if ((mask & OMP_CLAUSE_COPY) && gfc_match ("present_or_copy ( ") == MATCH_YES && gfc_match_omp_map_clause (&c->lists[OMP_LIST_MAP], - OMP_MAP_TOFROM, true)) + OMP_MAP_TOFROM, true, + allow_derived)) continue; if ((mask & OMP_CLAUSE_COPYIN) && gfc_match ("present_or_copyin ( ") == MATCH_YES && gfc_match_omp_map_clause (&c->lists[OMP_LIST_MAP], - OMP_MAP_TO, true)) + OMP_MAP_TO, true, allow_derived)) continue; if ((mask & OMP_CLAUSE_COPYOUT) && gfc_match ("present_or_copyout ( ") == MATCH_YES && gfc_match_omp_map_clause (&c->lists[OMP_LIST_MAP], - OMP_MAP_FROM, true)) + OMP_MAP_FROM, true, allow_derived)) continue; if ((mask & OMP_CLAUSE_CREATE) && gfc_match ("present_or_create ( ") == MATCH_YES && gfc_match_omp_map_clause (&c->lists[OMP_LIST_MAP], - OMP_MAP_ALLOC, true)) + OMP_MAP_ALLOC, true, allow_derived)) continue; if ((mask & OMP_CLAUSE_PRIORITY) && c->priority == NULL @@ -1682,8 +1715,8 @@ gfc_match_omp_clauses (gfc_omp_clauses **cp, const omp_mask mask, if (gfc_match_omp_variable_list (" :", &c->lists[OMP_LIST_REDUCTION], - false, NULL, &head, - openacc) == MATCH_YES) + false, NULL, &head, openacc, + allow_derived) == MATCH_YES) { gfc_omp_namelist *n; if (rop == OMP_REDUCTION_NONE) @@ -1782,7 +1815,8 @@ gfc_match_omp_clauses (gfc_omp_clauses **cp, const omp_mask mask, if ((mask & OMP_CLAUSE_HOST_SELF) && gfc_match ("self ( ") == MATCH_YES && gfc_match_omp_map_clause (&c->lists[OMP_LIST_MAP], - OMP_MAP_FORCE_FROM, true)) + OMP_MAP_FORCE_FROM, true, + allow_derived)) continue; if ((mask & OMP_CLAUSE_SEQ) && !c->seq @@ -1957,23 +1991,23 @@ gfc_match_omp_clauses (gfc_omp_clauses **cp, const omp_mask mask, | OMP_CLAUSE_COPY | OMP_CLAUSE_COPYIN | OMP_CLAUSE_COPYOUT \ | OMP_CLAUSE_CREATE | OMP_CLAUSE_PRESENT | OMP_CLAUSE_DEVICEPTR \ | OMP_CLAUSE_PRIVATE | OMP_CLAUSE_FIRSTPRIVATE | OMP_CLAUSE_DEFAULT \ - | OMP_CLAUSE_WAIT) + | OMP_CLAUSE_WAIT | OMP_CLAUSE_ATTACH) #define OACC_KERNELS_CLAUSES \ (omp_mask (OMP_CLAUSE_IF) | OMP_CLAUSE_ASYNC | OMP_CLAUSE_NUM_GANGS \ | OMP_CLAUSE_NUM_WORKERS | OMP_CLAUSE_VECTOR_LENGTH | OMP_CLAUSE_DEVICEPTR \ | OMP_CLAUSE_COPY | OMP_CLAUSE_COPYIN | OMP_CLAUSE_COPYOUT \ | OMP_CLAUSE_CREATE | OMP_CLAUSE_PRESENT | OMP_CLAUSE_DEFAULT \ - | OMP_CLAUSE_WAIT) + | OMP_CLAUSE_WAIT | OMP_CLAUSE_ATTACH) #define OACC_SERIAL_CLAUSES \ (omp_mask (OMP_CLAUSE_IF) | OMP_CLAUSE_ASYNC | OMP_CLAUSE_REDUCTION \ | OMP_CLAUSE_COPY | OMP_CLAUSE_COPYIN | OMP_CLAUSE_COPYOUT \ | OMP_CLAUSE_CREATE | OMP_CLAUSE_PRESENT | OMP_CLAUSE_DEVICEPTR \ | OMP_CLAUSE_PRIVATE | OMP_CLAUSE_FIRSTPRIVATE | OMP_CLAUSE_DEFAULT \ - | OMP_CLAUSE_WAIT) + | OMP_CLAUSE_WAIT | OMP_CLAUSE_ATTACH) #define OACC_DATA_CLAUSES \ (omp_mask (OMP_CLAUSE_IF) | OMP_CLAUSE_DEVICEPTR | OMP_CLAUSE_COPY \ | OMP_CLAUSE_COPYIN | OMP_CLAUSE_COPYOUT | OMP_CLAUSE_CREATE \ - | OMP_CLAUSE_PRESENT) + | OMP_CLAUSE_PRESENT | OMP_CLAUSE_ATTACH) #define OACC_LOOP_CLAUSES \ (omp_mask (OMP_CLAUSE_COLLAPSE) | OMP_CLAUSE_GANG | OMP_CLAUSE_WORKER \ | OMP_CLAUSE_VECTOR | OMP_CLAUSE_SEQ | OMP_CLAUSE_INDEPENDENT \ @@ -1996,10 +2030,11 @@ gfc_match_omp_clauses (gfc_omp_clauses **cp, const omp_mask mask, | OMP_CLAUSE_DEVICE | OMP_CLAUSE_WAIT | OMP_CLAUSE_IF_PRESENT) #define OACC_ENTER_DATA_CLAUSES \ (omp_mask (OMP_CLAUSE_IF) | OMP_CLAUSE_ASYNC | OMP_CLAUSE_WAIT \ - | OMP_CLAUSE_COPYIN | OMP_CLAUSE_CREATE) + | OMP_CLAUSE_COPYIN | OMP_CLAUSE_CREATE | OMP_CLAUSE_ATTACH) #define OACC_EXIT_DATA_CLAUSES \ (omp_mask (OMP_CLAUSE_IF) | OMP_CLAUSE_ASYNC | OMP_CLAUSE_WAIT \ - | OMP_CLAUSE_COPYOUT | OMP_CLAUSE_DELETE | OMP_CLAUSE_FINALIZE) + | OMP_CLAUSE_COPYOUT | OMP_CLAUSE_DELETE | OMP_CLAUSE_FINALIZE \ + | OMP_CLAUSE_DETACH) #define OACC_WAIT_CLAUSES \ omp_mask (OMP_CLAUSE_ASYNC) #define OACC_ROUTINE_CLAUSES \ @@ -3847,9 +3882,6 @@ resolve_nonnegative_int_expr (gfc_expr *expr, const char *clause) static void check_symbol_not_pointer (gfc_symbol *sym, locus loc, const char *name) { - if (sym->ts.type == BT_DERIVED && sym->attr.pointer) - gfc_error ("POINTER object %qs of derived type in %s clause at %L", - sym->name, name, &loc); if (sym->ts.type == BT_DERIVED && sym->attr.cray_pointer) gfc_error ("Cray pointer object %qs of derived type in %s clause at %L", sym->name, name, &loc); @@ -3890,9 +3922,6 @@ check_array_not_assumed (gfc_symbol *sym, locus loc, const char *name) static void resolve_oacc_data_clauses (gfc_symbol *sym, locus loc, const char *name) { - if (sym->ts.type == BT_DERIVED && sym->attr.allocatable) - gfc_error ("ALLOCATABLE object %qs of derived type in %s clause at %L", - sym->name, name, &loc); if ((sym->ts.type == BT_ASSUMED && sym->attr.allocatable) || (sym->ts.type == BT_CLASS && CLASS_DATA (sym) && CLASS_DATA (sym)->attr.allocatable)) @@ -4275,11 +4304,26 @@ resolve_omp_clauses (gfc_code *code, gfc_omp_clauses *omp_clauses, && (list != OMP_LIST_REDUCTION || !openacc)) for (n = omp_clauses->lists[list]; n; n = n->next) { - if (n->sym->mark) - gfc_error ("Symbol %qs present on multiple clauses at %L", - n->sym->name, &n->where); - else - n->sym->mark = 1; + bool array_only_p = true; + /* Disallow duplicate bare variable references and multiple + subarrays of the same array here, but allow multiple components of + the same (e.g. derived-type) variable. For the latter, duplicate + components are detected elsewhere. */ + if (openacc && n->expr && n->expr->expr_type == EXPR_VARIABLE) + for (gfc_ref *ref = n->expr->ref; ref; ref = ref->next) + if (ref->type != REF_ARRAY) + { + array_only_p = false; + break; + } + if (array_only_p) + { + if (n->sym->mark) + gfc_error ("Symbol %qs present on multiple clauses at %L", + n->sym->name, &n->where); + else + n->sym->mark = 1; + } } gcc_assert (OMP_LIST_LASTPRIVATE == OMP_LIST_FIRSTPRIVATE + 1); @@ -4470,23 +4514,43 @@ resolve_omp_clauses (gfc_code *code, gfc_omp_clauses *omp_clauses, "are allowed on ORDERED directive at %L", &n->where); } + gfc_ref *array_ref = NULL; + bool resolved = false; if (n->expr) { - if (!gfc_resolve_expr (n->expr) + array_ref = n->expr->ref; + resolved = gfc_resolve_expr (n->expr); + + /* Look through component refs to find last array + reference. */ + if (openacc) + while (resolved + && array_ref + && (array_ref->type == REF_COMPONENT + || (array_ref->type == REF_ARRAY + && array_ref->next + && (array_ref->next->type + == REF_COMPONENT)))) + array_ref = array_ref->next; + } + if (array_ref + || (n->expr + && (!resolved || n->expr->expr_type != EXPR_VARIABLE))) + { + if (!resolved || n->expr->expr_type != EXPR_VARIABLE - || n->expr->ref == NULL - || n->expr->ref->next - || n->expr->ref->type != REF_ARRAY) + || array_ref->next + || array_ref->type != REF_ARRAY) gfc_error ("%qs in %s clause at %L is not a proper " "array section", n->sym->name, name, &n->where); - else if (n->expr->ref->u.ar.codimen) + else if (array_ref->u.ar.codimen) gfc_error ("Coarrays not supported in %s clause at %L", name, &n->where); else { int i; - gfc_array_ref *ar = &n->expr->ref->u.ar; + gfc_array_ref *ar = &array_ref->u.ar; for (i = 0; i < ar->dimen; i++) if (ar->stride[i]) { diff --git a/gcc/fortran/trans-expr.c b/gcc/fortran/trans-expr.c index fe89c7b02ed..90fbe0ab74f 100644 --- a/gcc/fortran/trans-expr.c +++ b/gcc/fortran/trans-expr.c @@ -2423,7 +2423,7 @@ gfc_conv_substring (gfc_se * se, gfc_ref * ref, int kind, /* Convert a derived type component reference. */ -static void +void gfc_conv_component_ref (gfc_se * se, gfc_ref * ref) { gfc_component *c; @@ -2513,7 +2513,7 @@ gfc_conv_component_ref (gfc_se * se, gfc_ref * ref) /* This function deals with component references to components of the parent type for derived type extensions. */ -static void +void conv_parent_component_references (gfc_se * se, gfc_ref * ref) { gfc_component *c; @@ -2579,6 +2579,95 @@ conv_inquiry (gfc_se * se, gfc_ref * ref, gfc_expr *expr, gfc_typespec *ts) se->expr = res; } +/* Transparently dereference VAR if it is a pointer, reference, etc. + according to Fortran semantics. */ + +tree +gfc_auto_dereference_var (gfc_symbol *sym, tree var, bool descriptor_only_p, + bool is_classarray) +{ + /* Characters are entirely different from other types, they are treated + separately. */ + if (sym->ts.type == BT_CHARACTER) + { + /* Dereference character pointer dummy arguments + or results. */ + if ((sym->attr.pointer || sym->attr.allocatable) + && (sym->attr.dummy + || sym->attr.function + || sym->attr.result)) + var = build_fold_indirect_ref_loc (input_location, var); + } + else if (!sym->attr.value) + { + /* Dereference temporaries for class array dummy arguments. */ + if (sym->attr.dummy && is_classarray + && GFC_ARRAY_TYPE_P (TREE_TYPE (var))) + { + if (!descriptor_only_p) + var = GFC_DECL_SAVED_DESCRIPTOR (var); + + var = build_fold_indirect_ref_loc (input_location, var); + } + + /* Dereference non-character scalar dummy arguments. */ + if (sym->attr.dummy && !sym->attr.dimension + && !(sym->attr.codimension && sym->attr.allocatable) + && (sym->ts.type != BT_CLASS + || (!CLASS_DATA (sym)->attr.dimension + && !(CLASS_DATA (sym)->attr.codimension + && CLASS_DATA (sym)->attr.allocatable)))) + var = build_fold_indirect_ref_loc (input_location, var); + + /* Dereference scalar hidden result. */ + if (flag_f2c && sym->ts.type == BT_COMPLEX + && (sym->attr.function || sym->attr.result) + && !sym->attr.dimension && !sym->attr.pointer + && !sym->attr.always_explicit) + var = build_fold_indirect_ref_loc (input_location, var); + + /* Dereference non-character, non-class pointer variables. + These must be dummies, results, or scalars. */ + if (!is_classarray + && (sym->attr.pointer || sym->attr.allocatable + || gfc_is_associate_pointer (sym) + || (sym->as && sym->as->type == AS_ASSUMED_RANK)) + && (sym->attr.dummy + || sym->attr.function + || sym->attr.result + || (!sym->attr.dimension + && (!sym->attr.codimension || !sym->attr.allocatable)))) + var = build_fold_indirect_ref_loc (input_location, var); + /* Now treat the class array pointer variables accordingly. */ + else if (sym->ts.type == BT_CLASS + && sym->attr.dummy + && (CLASS_DATA (sym)->attr.dimension + || CLASS_DATA (sym)->attr.codimension) + && ((CLASS_DATA (sym)->as + && CLASS_DATA (sym)->as->type == AS_ASSUMED_RANK) + || CLASS_DATA (sym)->attr.allocatable + || CLASS_DATA (sym)->attr.class_pointer)) + var = build_fold_indirect_ref_loc (input_location, var); + /* And the case where a non-dummy, non-result, non-function, + non-allotable and non-pointer classarray is present. This case was + previously covered by the first if, but with introducing the + condition !is_classarray there, that case has to be covered + explicitly. */ + else if (sym->ts.type == BT_CLASS + && !sym->attr.dummy + && !sym->attr.function + && !sym->attr.result + && (CLASS_DATA (sym)->attr.dimension + || CLASS_DATA (sym)->attr.codimension) + && (sym->assoc + || !CLASS_DATA (sym)->attr.allocatable) + && !CLASS_DATA (sym)->attr.class_pointer) + var = build_fold_indirect_ref_loc (input_location, var); + } + + return var; +} + /* Return the contents of a variable. Also handles reference/pointer variables (all Fortran pointer references are implicit). */ @@ -2685,94 +2774,9 @@ gfc_conv_variable (gfc_se * se, gfc_expr * expr) return; } - - /* Dereference the expression, where needed. Since characters - are entirely different from other types, they are treated - separately. */ - if (sym->ts.type == BT_CHARACTER) - { - /* Dereference character pointer dummy arguments - or results. */ - if ((sym->attr.pointer || sym->attr.allocatable) - && (sym->attr.dummy - || sym->attr.function - || sym->attr.result)) - se->expr = build_fold_indirect_ref_loc (input_location, - se->expr); - - } - else if (!sym->attr.value) - { - /* Dereference temporaries for class array dummy arguments. */ - if (sym->attr.dummy && is_classarray - && GFC_ARRAY_TYPE_P (TREE_TYPE (se->expr))) - { - if (!se->descriptor_only) - se->expr = GFC_DECL_SAVED_DESCRIPTOR (se->expr); - - se->expr = build_fold_indirect_ref_loc (input_location, - se->expr); - } - - /* Dereference non-character scalar dummy arguments. */ - if (sym->attr.dummy && !sym->attr.dimension - && !(sym->attr.codimension && sym->attr.allocatable) - && (sym->ts.type != BT_CLASS - || (!CLASS_DATA (sym)->attr.dimension - && !(CLASS_DATA (sym)->attr.codimension - && CLASS_DATA (sym)->attr.allocatable)))) - se->expr = build_fold_indirect_ref_loc (input_location, - se->expr); - - /* Dereference scalar hidden result. */ - if (flag_f2c && sym->ts.type == BT_COMPLEX - && (sym->attr.function || sym->attr.result) - && !sym->attr.dimension && !sym->attr.pointer - && !sym->attr.always_explicit) - se->expr = build_fold_indirect_ref_loc (input_location, - se->expr); - - /* Dereference non-character, non-class pointer variables. - These must be dummies, results, or scalars. */ - if (!is_classarray - && (sym->attr.pointer || sym->attr.allocatable - || gfc_is_associate_pointer (sym) - || (sym->as && sym->as->type == AS_ASSUMED_RANK)) - && (sym->attr.dummy - || sym->attr.function - || sym->attr.result - || (!sym->attr.dimension - && (!sym->attr.codimension || !sym->attr.allocatable)))) - se->expr = build_fold_indirect_ref_loc (input_location, - se->expr); - /* Now treat the class array pointer variables accordingly. */ - else if (sym->ts.type == BT_CLASS - && sym->attr.dummy - && (CLASS_DATA (sym)->attr.dimension - || CLASS_DATA (sym)->attr.codimension) - && ((CLASS_DATA (sym)->as - && CLASS_DATA (sym)->as->type == AS_ASSUMED_RANK) - || CLASS_DATA (sym)->attr.allocatable - || CLASS_DATA (sym)->attr.class_pointer)) - se->expr = build_fold_indirect_ref_loc (input_location, - se->expr); - /* And the case where a non-dummy, non-result, non-function, - non-allotable and non-pointer classarray is present. This case was - previously covered by the first if, but with introducing the - condition !is_classarray there, that case has to be covered - explicitly. */ - else if (sym->ts.type == BT_CLASS - && !sym->attr.dummy - && !sym->attr.function - && !sym->attr.result - && (CLASS_DATA (sym)->attr.dimension - || CLASS_DATA (sym)->attr.codimension) - && (sym->assoc - || !CLASS_DATA (sym)->attr.allocatable) - && !CLASS_DATA (sym)->attr.class_pointer) - se->expr = build_fold_indirect_ref_loc (input_location, - se->expr); - } + /* Dereference the expression, where needed. */ + se->expr = gfc_auto_dereference_var (sym, se->expr, se->descriptor_only, + is_classarray); ref = expr->ref; } diff --git a/gcc/fortran/trans-openmp.c b/gcc/fortran/trans-openmp.c index b6da7b983d5..d091b6a6d62 100644 --- a/gcc/fortran/trans-openmp.c +++ b/gcc/fortran/trans-openmp.c @@ -174,6 +174,9 @@ gfc_omp_privatize_by_reference (const_tree decl) if (TREE_CODE (type) == POINTER_TYPE) { + while (TREE_CODE (decl) == COMPONENT_REF) + decl = TREE_OPERAND (decl, 1); + /* Array POINTER/ALLOCATABLE have aggregate types, all user variables that have POINTER_TYPE type and aren't scalar pointers, scalar allocatables, Cray pointees or C pointers are supposed to be @@ -2058,6 +2061,92 @@ gfc_convert_expr_to_tree (stmtblock_t *block, gfc_expr *expr) static vec *doacross_steps; + +/* Translate an array section or array element. */ + +static void +gfc_trans_omp_array_section (stmtblock_t *block, gfc_omp_namelist *n, + tree decl, bool element, gomp_map_kind ptr_kind, + tree node, tree &node2, tree &node3, tree &node4) +{ + gfc_se se; + tree ptr, ptr2; + + gfc_init_se (&se, NULL); + + if (element) + { + gfc_conv_expr_reference (&se, n->expr); + gfc_add_block_to_block (block, &se.pre); + ptr = se.expr; + OMP_CLAUSE_SIZE (node) + = TYPE_SIZE_UNIT (TREE_TYPE (ptr)); + } + else + { + gfc_conv_expr_descriptor (&se, n->expr); + ptr = gfc_conv_array_data (se.expr); + tree type = TREE_TYPE (se.expr); + gfc_add_block_to_block (block, &se.pre); + OMP_CLAUSE_SIZE (node) = gfc_full_array_size (block, se.expr, + GFC_TYPE_ARRAY_RANK (type)); + tree elemsz = TYPE_SIZE_UNIT (gfc_get_element_type (type)); + elemsz = fold_convert (gfc_array_index_type, elemsz); + OMP_CLAUSE_SIZE (node) = fold_build2 (MULT_EXPR, gfc_array_index_type, + OMP_CLAUSE_SIZE (node), elemsz); + } + gfc_add_block_to_block (block, &se.post); + ptr = fold_convert (build_pointer_type (char_type_node), ptr); + OMP_CLAUSE_DECL (node) = build_fold_indirect_ref (ptr); + + if (POINTER_TYPE_P (TREE_TYPE (decl)) + && GFC_DESCRIPTOR_TYPE_P (TREE_TYPE (TREE_TYPE (decl))) + && ptr_kind == GOMP_MAP_POINTER) + { + 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); + } + ptr = fold_convert (sizetype, ptr); + if (GFC_DESCRIPTOR_TYPE_P (TREE_TYPE (decl))) + { + tree type = TREE_TYPE (decl); + ptr2 = gfc_conv_descriptor_data_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, ptr_kind); + OMP_CLAUSE_DECL (node3) + = gfc_conv_descriptor_data_get (decl); + if (ptr_kind == GOMP_MAP_ATTACH_DETACH) + STRIP_NOPS (OMP_CLAUSE_DECL (node3)); + } + else + { + if (TREE_CODE (TREE_TYPE (decl)) == ARRAY_TYPE) + ptr2 = build_fold_addr_expr (decl); + else + { + gcc_assert (POINTER_TYPE_P (TREE_TYPE (decl))); + ptr2 = decl; + } + node3 = build_omp_clause (input_location, + OMP_CLAUSE_MAP); + OMP_CLAUSE_SET_MAP_KIND (node3, ptr_kind); + OMP_CLAUSE_DECL (node3) = decl; + } + ptr2 = fold_convert (sizetype, ptr2); + OMP_CLAUSE_SIZE (node3) + = fold_build2 (MINUS_EXPR, sizetype, ptr, ptr2); +} + static tree gfc_trans_omp_clauses (stmtblock_t *block, gfc_omp_clauses *clauses, locus where, bool declare_simd = false) @@ -2389,7 +2478,8 @@ gfc_trans_omp_clauses (stmtblock_t *block, gfc_omp_clauses *clauses, || GFC_DECL_GET_SCALAR_ALLOCATABLE (decl) || GFC_DECL_CRAY_POINTEE (decl) || GFC_DESCRIPTOR_TYPE_P - (TREE_TYPE (TREE_TYPE (decl))))) + (TREE_TYPE (TREE_TYPE (decl))) + || n->sym->ts.type == BT_DERIVED)) { tree orig_decl = decl; node4 = build_omp_clause (input_location, @@ -2411,7 +2501,9 @@ gfc_trans_omp_clauses (stmtblock_t *block, gfc_omp_clauses *clauses, decl = build_fold_indirect_ref (decl); } } - if (GFC_DESCRIPTOR_TYPE_P (TREE_TYPE (decl))) + if (GFC_DESCRIPTOR_TYPE_P (TREE_TYPE (decl)) + && n->u.map_op != OMP_MAP_ATTACH + && n->u.map_op != OMP_MAP_DETACH) { tree type = TREE_TYPE (decl); tree ptr = gfc_conv_descriptor_data_get (decl); @@ -2542,88 +2634,152 @@ gfc_trans_omp_clauses (stmtblock_t *block, gfc_omp_clauses *clauses, else OMP_CLAUSE_DECL (node) = decl; } - else + else if (n->expr + && n->expr->expr_type == EXPR_VARIABLE + && n->expr->ref->type == REF_COMPONENT) { - tree ptr, ptr2; + gfc_ref *lastcomp; + + for (gfc_ref *ref = n->expr->ref; ref; ref = ref->next) + if (ref->type == REF_COMPONENT) + lastcomp = ref; + + symbol_attribute sym_attr; + + sym_attr = lastcomp->u.c.component->attr; + gfc_init_se (&se, NULL); - if (n->expr->ref->u.ar.type == AR_ELEMENT) + + if (!sym_attr.dimension + && lastcomp->u.c.component->ts.type != BT_DERIVED) { - gfc_conv_expr_reference (&se, n->expr); + /* Last component is a scalar. */ + gfc_conv_expr (&se, n->expr); gfc_add_block_to_block (block, &se.pre); - ptr = se.expr; - OMP_CLAUSE_SIZE (node) - = TYPE_SIZE_UNIT (TREE_TYPE (ptr)); + OMP_CLAUSE_DECL (node) = se.expr; + gfc_add_block_to_block (block, &se.post); + goto finalize_map_clause; } - else - { - gfc_conv_expr_descriptor (&se, n->expr); - ptr = gfc_conv_array_data (se.expr); - tree type = TREE_TYPE (se.expr); - gfc_add_block_to_block (block, &se.pre); - OMP_CLAUSE_SIZE (node) - = gfc_full_array_size (block, se.expr, - GFC_TYPE_ARRAY_RANK (type)); - tree elemsz - = TYPE_SIZE_UNIT (gfc_get_element_type (type)); - elemsz = fold_convert (gfc_array_index_type, elemsz); - OMP_CLAUSE_SIZE (node) - = fold_build2 (MULT_EXPR, gfc_array_index_type, - OMP_CLAUSE_SIZE (node), elemsz); - } - gfc_add_block_to_block (block, &se.post); - ptr = fold_convert (build_pointer_type (char_type_node), - ptr); - OMP_CLAUSE_DECL (node) = build_fold_indirect_ref (ptr); - if (POINTER_TYPE_P (TREE_TYPE (decl)) - && GFC_DESCRIPTOR_TYPE_P (TREE_TYPE (TREE_TYPE (decl)))) + se.expr = gfc_auto_dereference_var (n->sym, decl); + + for (gfc_ref *ref = n->expr->ref; + ref && ref != lastcomp->next; + ref = ref->next) { - 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); + if (ref->type == REF_COMPONENT) + { + if (ref->u.c.sym->attr.extension) + conv_parent_component_references (&se, ref); + + gfc_conv_component_ref (&se, ref); + } + else + sorry ("unhandled derived-type component"); } - ptr = fold_convert (sizetype, ptr); - if (GFC_DESCRIPTOR_TYPE_P (TREE_TYPE (decl))) + + tree inner = se.expr; + + /* Last component is a derived type. */ + if (lastcomp->u.c.component->ts.type == BT_DERIVED) { - tree type = TREE_TYPE (decl); - ptr2 = gfc_conv_descriptor_data_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_POINTER); - OMP_CLAUSE_DECL (node3) - = gfc_conv_descriptor_data_get (decl); + if (sym_attr.allocatable || sym_attr.pointer) + { + tree data = inner; + tree size = TYPE_SIZE_UNIT (TREE_TYPE (inner)); + + OMP_CLAUSE_DECL (node) + = build_fold_indirect_ref (data); + OMP_CLAUSE_SIZE (node) = size; + node2 = build_omp_clause (input_location, + OMP_CLAUSE_MAP); + OMP_CLAUSE_SET_MAP_KIND (node2, + GOMP_MAP_ATTACH_DETACH); + OMP_CLAUSE_DECL (node2) = data; + OMP_CLAUSE_SIZE (node2) = size_int (0); + } + else + { + OMP_CLAUSE_DECL (node) = decl; + OMP_CLAUSE_SIZE (node) + = TYPE_SIZE_UNIT (TREE_TYPE (decl)); + } } - else + else if (lastcomp->next + && lastcomp->next->type == REF_ARRAY + && lastcomp->next->u.ar.type == AR_FULL) { - if (TREE_CODE (TREE_TYPE (decl)) == ARRAY_TYPE) - ptr2 = build_fold_addr_expr (decl); - else + /* Just pass the (auto-dereferenced) decl through for + bare attach and detach clauses. */ + if (n->u.map_op == OMP_MAP_ATTACH + || n->u.map_op == OMP_MAP_DETACH) { - gcc_assert (POINTER_TYPE_P (TREE_TYPE (decl))); - ptr2 = decl; + OMP_CLAUSE_DECL (node) = inner; + OMP_CLAUSE_SIZE (node) = size_zero_node; + goto finalize_map_clause; } - node3 = build_omp_clause (input_location, - OMP_CLAUSE_MAP); - OMP_CLAUSE_SET_MAP_KIND (node3, GOMP_MAP_POINTER); - OMP_CLAUSE_DECL (node3) = decl; + + if (GFC_DESCRIPTOR_TYPE_P (TREE_TYPE (inner))) + { + tree type = TREE_TYPE (inner); + tree ptr = gfc_conv_descriptor_data_get (inner); + ptr = build_fold_indirect_ref (ptr); + OMP_CLAUSE_DECL (node) = ptr; + node2 = build_omp_clause (input_location, + OMP_CLAUSE_MAP); + OMP_CLAUSE_SET_MAP_KIND (node2, GOMP_MAP_TO_PSET); + OMP_CLAUSE_DECL (node2) = inner; + 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_conv_descriptor_data_get (inner); + STRIP_NOPS (OMP_CLAUSE_DECL (node3)); + OMP_CLAUSE_SIZE (node3) = size_int (0); + int rank = GFC_TYPE_ARRAY_RANK (type); + OMP_CLAUSE_SIZE (node) + = gfc_full_array_size (block, inner, rank); + tree elemsz + = TYPE_SIZE_UNIT (gfc_get_element_type (type)); + elemsz = fold_convert (gfc_array_index_type, elemsz); + OMP_CLAUSE_SIZE (node) + = fold_build2 (MULT_EXPR, gfc_array_index_type, + OMP_CLAUSE_SIZE (node), elemsz); + } + else + OMP_CLAUSE_DECL (node) = inner; } - ptr2 = fold_convert (sizetype, ptr2); - OMP_CLAUSE_SIZE (node3) - = fold_build2 (MINUS_EXPR, sizetype, ptr, ptr2); + else /* An array element or section. */ + { + bool element + = (lastcomp->next + && lastcomp->next->type == REF_ARRAY + && lastcomp->next->u.ar.type == AR_ELEMENT); + + gfc_trans_omp_array_section (block, n, inner, element, + GOMP_MAP_ATTACH_DETACH, + node, node2, node3, node4); + } + } + else /* An array element or array section. */ + { + bool element = n->expr->ref->u.ar.type == AR_ELEMENT; + gfc_trans_omp_array_section (block, n, decl, element, + GOMP_MAP_POINTER, node, node2, + node3, node4); } + + finalize_map_clause: switch (n->u.map_op) { case OMP_MAP_ALLOC: OMP_CLAUSE_SET_MAP_KIND (node, GOMP_MAP_ALLOC); break; + case OMP_MAP_ATTACH: + OMP_CLAUSE_SET_MAP_KIND (node, GOMP_MAP_ATTACH); + break; case OMP_MAP_TO: OMP_CLAUSE_SET_MAP_KIND (node, GOMP_MAP_TO); break; @@ -2648,6 +2804,9 @@ gfc_trans_omp_clauses (stmtblock_t *block, gfc_omp_clauses *clauses, case OMP_MAP_DELETE: OMP_CLAUSE_SET_MAP_KIND (node, GOMP_MAP_DELETE); break; + case OMP_MAP_DETACH: + OMP_CLAUSE_SET_MAP_KIND (node, GOMP_MAP_DETACH); + break; case OMP_MAP_FORCE_ALLOC: OMP_CLAUSE_SET_MAP_KIND (node, GOMP_MAP_FORCE_ALLOC); break; diff --git a/gcc/fortran/trans.h b/gcc/fortran/trans.h index d3c057278f3..18683427060 100644 --- a/gcc/fortran/trans.h +++ b/gcc/fortran/trans.h @@ -565,6 +565,14 @@ tree gfc_conv_expr_present (gfc_symbol *); /* Convert a missing, dummy argument into a null or zero. */ void gfc_conv_missing_dummy (gfc_se *, gfc_expr *, gfc_typespec, int); +/* Lowering of component references. */ +void gfc_conv_component_ref (gfc_se * se, gfc_ref * ref); +void conv_parent_component_references (gfc_se * se, gfc_ref * ref); + +/* Automatically dereference var. */ +tree gfc_auto_dereference_var (gfc_symbol *, tree, bool desc_only = false, + bool is_classarray = false); + /* Generate code to allocate a string temporary. */ tree gfc_conv_string_tmp (gfc_se *, tree, tree); /* Get the string length variable belonging to an expression. */ diff --git a/gcc/testsuite/gfortran.dg/goacc/data-clauses.f95 b/gcc/testsuite/gfortran.dg/goacc/data-clauses.f95 index b94214e8b63..1a4a6719987 100644 --- a/gcc/testsuite/gfortran.dg/goacc/data-clauses.f95 +++ b/gcc/testsuite/gfortran.dg/goacc/data-clauses.f95 @@ -39,9 +39,9 @@ contains !$acc end data - !$acc parallel copy (tip) ! { dg-error "POINTER" } + !$acc parallel copy (tip) !$acc end parallel - !$acc parallel copy (tia) ! { dg-error "ALLOCATABLE" } + !$acc parallel copy (tia) !$acc end parallel !$acc parallel deviceptr (i) copy (i) ! { dg-error "multiple clauses" } !$acc end parallel @@ -54,9 +54,9 @@ contains !$acc end data - !$acc parallel copyin (tip) ! { dg-error "POINTER" } + !$acc parallel copyin (tip) !$acc end parallel - !$acc parallel copyin (tia) ! { dg-error "ALLOCATABLE" } + !$acc parallel copyin (tia) !$acc end parallel !$acc parallel deviceptr (i) copyin (i) ! { dg-error "multiple clauses" } !$acc end parallel @@ -71,9 +71,9 @@ contains !$acc end data - !$acc parallel copyout (tip) ! { dg-error "POINTER" } + !$acc parallel copyout (tip) !$acc end parallel - !$acc parallel copyout (tia) ! { dg-error "ALLOCATABLE" } + !$acc parallel copyout (tia) !$acc end parallel !$acc parallel deviceptr (i) copyout (i) ! { dg-error "multiple clauses" } !$acc end parallel @@ -90,9 +90,9 @@ contains !$acc end data - !$acc parallel create (tip) ! { dg-error "POINTER" } + !$acc parallel create (tip) !$acc end parallel - !$acc parallel create (tia) ! { dg-error "ALLOCATABLE" } + !$acc parallel create (tia) !$acc end parallel !$acc parallel deviceptr (i) create (i) ! { dg-error "multiple clauses" } !$acc end parallel @@ -111,9 +111,9 @@ contains !$acc end data - !$acc parallel present (tip) ! { dg-error "POINTER" } + !$acc parallel present (tip) !$acc end parallel - !$acc parallel present (tia) ! { dg-error "ALLOCATABLE" } + !$acc parallel present (tia) !$acc end parallel !$acc parallel deviceptr (i) present (i) ! { dg-error "multiple clauses" } !$acc end parallel @@ -144,9 +144,9 @@ contains !$acc end parallel - !$acc parallel present_or_copy (tip) ! { dg-error "POINTER" } + !$acc parallel present_or_copy (tip) !$acc end parallel - !$acc parallel present_or_copy (tia) ! { dg-error "ALLOCATABLE" } + !$acc parallel present_or_copy (tia) !$acc end parallel !$acc parallel deviceptr (i) present_or_copy (i) ! { dg-error "multiple clauses" } !$acc end parallel @@ -169,9 +169,9 @@ contains !$acc end data - !$acc parallel present_or_copyin (tip) ! { dg-error "POINTER" } + !$acc parallel present_or_copyin (tip) !$acc end parallel - !$acc parallel present_or_copyin (tia) ! { dg-error "ALLOCATABLE" } + !$acc parallel present_or_copyin (tia) !$acc end parallel !$acc parallel deviceptr (i) present_or_copyin (i) ! { dg-error "multiple clauses" } !$acc end parallel @@ -196,9 +196,9 @@ contains !$acc end data - !$acc parallel present_or_copyout (tip) ! { dg-error "POINTER" } + !$acc parallel present_or_copyout (tip) !$acc end parallel - !$acc parallel present_or_copyout (tia) ! { dg-error "ALLOCATABLE" } + !$acc parallel present_or_copyout (tia) !$acc end parallel !$acc parallel deviceptr (i) present_or_copyout (i) ! { dg-error "multiple clauses" } !$acc end parallel @@ -225,9 +225,9 @@ contains !$acc end data - !$acc parallel present_or_create (tip) ! { dg-error "POINTER" } + !$acc parallel present_or_create (tip) !$acc end parallel - !$acc parallel present_or_create (tia) ! { dg-error "ALLOCATABLE" } + !$acc parallel present_or_create (tia) !$acc end parallel !$acc parallel deviceptr (i) present_or_create (i) ! { dg-error "multiple clauses" } !$acc end parallel @@ -256,4 +256,4 @@ contains !$acc end data end subroutine foo -end module test \ No newline at end of file +end module test diff --git a/gcc/testsuite/gfortran.dg/goacc/derived-types-2.f90 b/gcc/testsuite/gfortran.dg/goacc/derived-types-2.f90 new file mode 100644 index 00000000000..d01583fac89 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/goacc/derived-types-2.f90 @@ -0,0 +1,14 @@ +module bar + type :: type1 + real(8), pointer, public :: p(:) => null() + end type + type :: type2 + class(type1), pointer :: p => null() + end type +end module + +subroutine foo (var) + use bar + type(type2), intent(inout) :: var + !$acc enter data create(var%p%p) +end subroutine diff --git a/gcc/testsuite/gfortran.dg/goacc/derived-types.f90 b/gcc/testsuite/gfortran.dg/goacc/derived-types.f90 new file mode 100644 index 00000000000..5fb29816c42 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/goacc/derived-types.f90 @@ -0,0 +1,77 @@ +! Test ACC UPDATE with derived types. + +module dt + integer, parameter :: n = 10 + type inner + integer :: d(n) + end type inner + type dtype + integer(8) :: a, b, c(n) + type(inner) :: in + end type dtype +end module dt + +program derived_acc + use dt + + implicit none + type(dtype):: var + integer i + !$acc declare create(var) + !$acc declare pcopy(var%a) ! { dg-error "Syntax error in OpenMP" } + + !$acc update host(var) + !$acc update host(var%a) + !$acc update device(var) + !$acc update device(var%a) + !$acc update self(var) + !$acc update self(var%a) + + !$acc enter data copyin(var) + !$acc enter data copyin(var%a) + + !$acc exit data copyout(var) + !$acc exit data copyout(var%a) + + !$acc data copy(var) + !$acc end data + + !$acc data copyout(var%a) + !$acc end data + + !$acc parallel loop pcopyout(var) + do i = 1, 10 + end do + !$acc end parallel loop + + !$acc parallel loop copyout(var%a) + do i = 1, 10 + end do + !$acc end parallel loop + + !$acc parallel pcopy(var) + !$acc end parallel + + !$acc parallel pcopy(var%a) + do i = 1, 10 + end do + !$acc end parallel + + !$acc kernels pcopyin(var) + !$acc end kernels + + !$acc kernels pcopy(var%a) + do i = 1, 10 + end do + !$acc end kernels + + !$acc kernels loop pcopyin(var) + do i = 1, 10 + end do + !$acc end kernels loop + + !$acc kernels loop pcopy(var%a) + do i = 1, 10 + end do + !$acc end kernels loop +end program derived_acc diff --git a/gcc/testsuite/gfortran.dg/goacc/enter-exit-data.f95 b/gcc/testsuite/gfortran.dg/goacc/enter-exit-data.f95 index a414df8d439..c2a49796318 100644 --- a/gcc/testsuite/gfortran.dg/goacc/enter-exit-data.f95 +++ b/gcc/testsuite/gfortran.dg/goacc/enter-exit-data.f95 @@ -44,14 +44,14 @@ contains !$acc enter data wait (i, 1) !$acc enter data wait (a) ! { dg-error "INTEGER" } !$acc enter data wait (b(5:6)) ! { dg-error "INTEGER" } - !$acc enter data copyin (tip) ! { dg-error "POINTER" } - !$acc enter data copyin (tia) ! { dg-error "ALLOCATABLE" } - !$acc enter data create (tip) ! { dg-error "POINTER" } - !$acc enter data create (tia) ! { dg-error "ALLOCATABLE" } - !$acc enter data present_or_copyin (tip) ! { dg-error "POINTER" } - !$acc enter data present_or_copyin (tia) ! { dg-error "ALLOCATABLE" } - !$acc enter data present_or_create (tip) ! { dg-error "POINTER" } - !$acc enter data present_or_create (tia) ! { dg-error "ALLOCATABLE" } + !$acc enter data copyin (tip) + !$acc enter data copyin (tia) + !$acc enter data create (tip) + !$acc enter data create (tia) + !$acc enter data present_or_copyin (tip) + !$acc enter data present_or_copyin (tia) + !$acc enter data present_or_create (tip) + !$acc enter data present_or_create (tia) !$acc enter data copyin (i) create (i) ! { dg-error "multiple clauses" } !$acc enter data copyin (i) present_or_copyin (i) ! { dg-error "multiple clauses" } !$acc enter data create (i) present_or_copyin (i) ! { dg-error "multiple clauses" } @@ -79,10 +79,10 @@ contains !$acc exit data wait (i, 1) !$acc exit data wait (a) ! { dg-error "INTEGER" } !$acc exit data wait (b(5:6)) ! { dg-error "INTEGER" } - !$acc exit data copyout (tip) ! { dg-error "POINTER" } - !$acc exit data copyout (tia) ! { dg-error "ALLOCATABLE" } - !$acc exit data delete (tip) ! { dg-error "POINTER" } - !$acc exit data delete (tia) ! { dg-error "ALLOCATABLE" } + !$acc exit data copyout (tip) + !$acc exit data copyout (tia) + !$acc exit data delete (tip) + !$acc exit data delete (tia) !$acc exit data copyout (i) delete (i) ! { dg-error "multiple clauses" } !$acc exit data finalize !$acc exit data finalize copyout (i) From patchwork Wed Dec 18 06:04:54 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Julian Brown X-Patchwork-Id: 1211987 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=209.132.180.131; helo=sourceware.org; envelope-from=gcc-patches-return-516179-incoming=patchwork.ozlabs.org@gcc.gnu.org; receiver=) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=codesourcery.com Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=gcc.gnu.org header.i=@gcc.gnu.org header.b="KoJVmPL7"; dkim-atps=neutral Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 47d4Jf6l3Zz9sS6 for ; Wed, 18 Dec 2019 17:06:26 +1100 (AEDT) DomainKey-Signature: a=rsa-sha1; c=nofws; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:from :to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding:content-type; q=dns; s= default; b=g8xW9BZY1GYOEqTuom5YzyJkN39eOIMlkmheFVbRTvisVSeXalSCE cEqDIbOgVTFyyuwrupUmoRz0Q4KDf0GJJF1qxsgNI51bdQJxNHza+Zd2Nsd/qARe OicudS84iqDc78IxRvCZQvPxEACauAy7kLVtmkk74hKzXOeX/yqSAg= DKIM-Signature: v=1; a=rsa-sha1; c=relaxed; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:from :to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding:content-type; s=default; bh=mazDNZUxlTY92ic3+kgZifnG/0E=; b=KoJVmPL7R0RmFdRZF3V30xmXsFwD KV1JDGGXYgzMqnGC7/yZoXLCicrocwzQxtL+rKd4njcaof4eRfJ7wPyv0hXHdSUy vj03Ax7i7DwwT8vXsPtwKoHYAaGWAWhnR1uqO5WB4OobfeFag9vauAs0vqIHL92v /rbLUadXdGqjbKE= Received: (qmail 111948 invoked by alias); 18 Dec 2019 06:05:19 -0000 Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Delivered-To: mailing list gcc-patches@gcc.gnu.org Received: (qmail 111866 invoked by uid 89); 18 Dec 2019 06:05:18 -0000 Authentication-Results: sourceware.org; auth=none X-Spam-SWARE-Status: No, score=-24.1 required=5.0 tests=AWL, BAYES_00, GIT_PATCH_0, GIT_PATCH_1, GIT_PATCH_2, GIT_PATCH_3, KAM_SHORT, SPF_PASS autolearn=ham version=3.3.1 spammy=ma, vc, slices, se X-HELO: esa1.mentor.iphmx.com Received: from esa1.mentor.iphmx.com (HELO esa1.mentor.iphmx.com) (68.232.129.153) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Wed, 18 Dec 2019 06:05:14 +0000 IronPort-SDR: mLoY5O7oyEzWG0uGtVCG8M4blB6DPo2W/PJZ8q1jYerwUAlBAC46gu9Udx9JlAszHMvHYkc4dD Q2CzdsVomfu1/9oGXZQyco5rWsAhVqInek4otD+dIs6A1Cbi1cILdwQyvbHAAgihj4XteZHh+F e2A53mWNObuPGjRBxUPWHd/RCrWf3EhzJn9IuWAypTMJ0wDQS6m3N8vSxd19Lpe1z/EbC7foM/ NpewKbQveZZ4EzP1UGJh0s335IQGUZus84rGNFf5etSbbfSjSsaVA3VId3HEvjisMjAPc+feGn Cek= Received: from orw-gwy-01-in.mentorg.com ([192.94.38.165]) by esa1.mentor.iphmx.com with ESMTP; 17 Dec 2019 22:05:12 -0800 IronPort-SDR: pO0wZyIRmcCgUmHkQS9ggdJdRfVSy6DtT4C59+53njP9nj9u8cPCUv4i4azuR5S7ypQNY1gMvW dGjdeqyaPgTDdpGG7t989ssgS4wVyse0unKYgWfxSdVQgDQ8KJC7LTE/W+qaawZF36qyOfcpfp LdQVF5QRy9fp0cB4TCvuXn0Ybq2yrY6FdCGaLRKoneytjGanrB3ZzAyF99ZQTqU5AZ0/lDUM2d 8pZKjcfsCd1Cf1044MyIcWtfrmCKUCLe+s8aJDdRniYuYmA2RYFftEymkdffx4BN3B5jVHpVtM QZI= From: Julian Brown To: CC: Thomas Schwinge , Jakub Jelinek , Tobias Burnus , , Subject: [PATCH 11/13] OpenACC 2.6 deep copy: C and C++ execution tests Date: Tue, 17 Dec 2019 22:04:54 -0800 Message-ID: In-Reply-To: References: MIME-Version: 1.0 X-IsSubscribed: yes This patch has been broken out of the "OpenACC 2.6 manual deep copy support" patch, last posted here: https://gcc.gnu.org/ml/gcc-patches/2019-11/msg02376.html This part adds C and C++ execution tests to libgomp. Tested alongside other patches in this series with offloading to NVPTX. OK? Thanks, Julian ChangeLog libgomp/ * testsuite/libgomp.oacc-c-c++-common/deep-copy-1.c: New test. * testsuite/libgomp.oacc-c-c++-common/deep-copy-2.c: New test. * testsuite/libgomp.oacc-c-c++-common/deep-copy-4.c: New test. * testsuite/libgomp.oacc-c-c++-common/deep-copy-6.c: New test. * testsuite/libgomp.oacc-c-c++-common/deep-copy-7.c: New test. * testsuite/libgomp.oacc-c-c++-common/deep-copy-8.c: New test. * testsuite/libgomp.oacc-c-c++-common/deep-copy-9.c: New test. * testsuite/libgomp.oacc-c-c++-common/deep-copy-10.c: New test. * testsuite/libgomp.oacc-c-c++-common/deep-copy-11.c: New test. * testsuite/libgomp.oacc-c-c++-common/deep-copy-14.c: New test. * testsuite/libgomp.oacc-c++/deep-copy-12.C: New test. * testsuite/libgomp.oacc-c++/deep-copy-13.C: New test. --- .../testsuite/libgomp.oacc-c++/deep-copy-12.C | 72 +++++++++++++++ .../testsuite/libgomp.oacc-c++/deep-copy-13.C | 72 +++++++++++++++ .../libgomp.oacc-c-c++-common/deep-copy-1.c | 24 +++++ .../libgomp.oacc-c-c++-common/deep-copy-10.c | 53 +++++++++++ .../libgomp.oacc-c-c++-common/deep-copy-11.c | 72 +++++++++++++++ .../libgomp.oacc-c-c++-common/deep-copy-14.c | 63 ++++++++++++++ .../libgomp.oacc-c-c++-common/deep-copy-2.c | 29 +++++++ .../libgomp.oacc-c-c++-common/deep-copy-4.c | 87 +++++++++++++++++++ .../libgomp.oacc-c-c++-common/deep-copy-6.c | 59 +++++++++++++ .../libgomp.oacc-c-c++-common/deep-copy-7.c | 45 ++++++++++ .../libgomp.oacc-c-c++-common/deep-copy-8.c | 54 ++++++++++++ .../libgomp.oacc-c-c++-common/deep-copy-9.c | 53 +++++++++++ 12 files changed, 683 insertions(+) create mode 100644 libgomp/testsuite/libgomp.oacc-c++/deep-copy-12.C create mode 100644 libgomp/testsuite/libgomp.oacc-c++/deep-copy-13.C create mode 100644 libgomp/testsuite/libgomp.oacc-c-c++-common/deep-copy-1.c create mode 100644 libgomp/testsuite/libgomp.oacc-c-c++-common/deep-copy-10.c create mode 100644 libgomp/testsuite/libgomp.oacc-c-c++-common/deep-copy-11.c create mode 100644 libgomp/testsuite/libgomp.oacc-c-c++-common/deep-copy-14.c create mode 100644 libgomp/testsuite/libgomp.oacc-c-c++-common/deep-copy-2.c create mode 100644 libgomp/testsuite/libgomp.oacc-c-c++-common/deep-copy-4.c create mode 100644 libgomp/testsuite/libgomp.oacc-c-c++-common/deep-copy-6.c create mode 100644 libgomp/testsuite/libgomp.oacc-c-c++-common/deep-copy-7.c create mode 100644 libgomp/testsuite/libgomp.oacc-c-c++-common/deep-copy-8.c create mode 100644 libgomp/testsuite/libgomp.oacc-c-c++-common/deep-copy-9.c diff --git a/libgomp/testsuite/libgomp.oacc-c++/deep-copy-12.C b/libgomp/testsuite/libgomp.oacc-c++/deep-copy-12.C new file mode 100644 index 00000000000..a512008685d --- /dev/null +++ b/libgomp/testsuite/libgomp.oacc-c++/deep-copy-12.C @@ -0,0 +1,72 @@ +#include + +/* Test attach/detach with dereferences of reference to pointer to struct. */ + +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)); + mystruct *&mref = m; + int i; + + mref->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++) + { + mref->a[i] = 0; + m->b[i] = 0; + m->c[i] = 0; + } + +#pragma acc enter data copyin(m[0:1]) + + for (int i = 0; i < 99; i++) + { + int j; +#pragma acc parallel loop copy(mref->a[0:N]) + for (j = 0; j < N; j++) + mref->a[j]++; +#pragma acc parallel loop copy(mref->b[0:N], m->c[5:N-10]) + for (j = 0; j < N; j++) + { + mref->b[j]++; + if (j > 5 && j < N - 5) + m->c[j]++; + } + } + +#pragma acc exit data copyout(m[0:1]) + + 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++/deep-copy-13.C b/libgomp/testsuite/libgomp.oacc-c++/deep-copy-13.C new file mode 100644 index 00000000000..a5194568603 --- /dev/null +++ b/libgomp/testsuite/libgomp.oacc-c++/deep-copy-13.C @@ -0,0 +1,72 @@ +#include + +/* Test array slice with reference to pointer. */ + +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; + } + +#pragma acc enter data copyin(m[0:1]) + + for (int i = 0; i < 99; i++) + { + int j; + int *&ptr = m->a; +#pragma acc parallel loop copy(ptr[0:N]) + for (j = 0; j < N; j++) + ptr[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]++; + } + } + +#pragma acc exit data copyout(m[0:1]) + + 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-1.c b/libgomp/testsuite/libgomp.oacc-c-c++-common/deep-copy-1.c new file mode 100644 index 00000000000..d8d7067e452 --- /dev/null +++ b/libgomp/testsuite/libgomp.oacc-c-c++-common/deep-copy-1.c @@ -0,0 +1,24 @@ +#include +#include + +struct dc +{ + int a; + int *b; +}; + +int +main () +{ + int n = 100, i; + struct dc v = { .a = 3, .b = (int *) malloc (sizeof (int) * n) }; + +#pragma acc parallel loop copy(v.a, v.b[:n]) + for (i = 0; i < n; i++) + v.b[i] = v.a; + + for (i = 0; i < 10; i++) + assert (v.b[i] == v.a); + + return 0; +} diff --git a/libgomp/testsuite/libgomp.oacc-c-c++-common/deep-copy-10.c b/libgomp/testsuite/libgomp.oacc-c-c++-common/deep-copy-10.c new file mode 100644 index 00000000000..573a8214bf0 --- /dev/null +++ b/libgomp/testsuite/libgomp.oacc-c-c++-common/deep-copy-10.c @@ -0,0 +1,53 @@ +#include + +/* Test asyncronous attach and detach operation. */ + +typedef struct { + int *a; + int *b; +} mystruct; + +int +main (int argc, char* argv[]) +{ + const int N = 1024; + mystruct m; + int i; + + m.a = (int *) malloc (N * sizeof (int)); + m.b = (int *) malloc (N * sizeof (int)); + + for (i = 0; i < N; i++) + { + m.a[i] = 0; + m.b[i] = 0; + } + +#pragma acc enter data copyin(m) + + for (int i = 0; i < 99; i++) + { + int j; +#pragma acc parallel loop copy(m.a[0:N]) async(i % 2) + for (j = 0; j < N; j++) + m.a[j]++; +#pragma acc parallel loop copy(m.b[0:N]) async((i + 1) % 2) + for (j = 0; j < N; j++) + m.b[j]++; + } + +#pragma acc exit data copyout(m) wait(0, 1) + + for (i = 0; i < N; i++) + { + if (m.a[i] != 99) + abort (); + if (m.b[i] != 99) + abort (); + } + + free (m.a); + free (m.b); + + return 0; +} diff --git a/libgomp/testsuite/libgomp.oacc-c-c++-common/deep-copy-11.c b/libgomp/testsuite/libgomp.oacc-c-c++-common/deep-copy-11.c new file mode 100644 index 00000000000..db6012fb352 --- /dev/null +++ b/libgomp/testsuite/libgomp.oacc-c-c++-common/deep-copy-11.c @@ -0,0 +1,72 @@ +#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; + } + +#pragma acc enter data copyin(m[0:1]) + + 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]++; + } + } + +#pragma acc exit data copyout(m[0:1]) + + 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-14.c b/libgomp/testsuite/libgomp.oacc-c-c++-common/deep-copy-14.c new file mode 100644 index 00000000000..275fa9ae256 --- /dev/null +++ b/libgomp/testsuite/libgomp.oacc-c-c++-common/deep-copy-14.c @@ -0,0 +1,63 @@ +#include +#include + +/* Test attach/detach operation with chained dereferences. */ + +typedef struct mystruct { + int *a; + struct mystruct *next; +} 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->next = (mystruct *) malloc (sizeof (*m)); + m->next->a = (int *) malloc (N * sizeof (int)); + m->next->next = NULL; + + for (i = 0; i < N; i++) + { + m->a[i] = 0; + m->next->a[i] = 0; + } + +#pragma acc enter data copyin(m[0:1]) + acc_copyin (m->next, sizeof (*m)); + + for (int i = 0; i < 99; i++) + { + int j; + acc_copyin (m->next->a, N * sizeof (int)); + acc_attach ((void **) &m->next); + /* This will attach only the innermost pointer, i.e. "a[0:N]". That's + why we have to attach the "m->next" pointer manually above. */ +#pragma acc parallel loop copy(m->next->a[0:N]) + for (j = 0; j < N; j++) + m->next->a[j]++; + acc_detach ((void **) &m->next); + acc_copyout (m->next->a, N * sizeof (int)); + } + + acc_copyout (m->next, sizeof (*m)); +#pragma acc exit data copyout(m[0:1]) + + for (i = 0; i < N; i++) + { + if (m->a[i] != 0) + abort (); + if (m->next->a[i] != 99) + abort (); + } + + free (m->next->a); + free (m->next); + free (m->a); + free (m); + + return 0; +} diff --git a/libgomp/testsuite/libgomp.oacc-c-c++-common/deep-copy-2.c b/libgomp/testsuite/libgomp.oacc-c-c++-common/deep-copy-2.c new file mode 100644 index 00000000000..7e26e9aa8b9 --- /dev/null +++ b/libgomp/testsuite/libgomp.oacc-c-c++-common/deep-copy-2.c @@ -0,0 +1,29 @@ +#include +#include + +int +main(int argc, char* argv[]) +{ + struct foo { + int *a, *b, c, d, *e; + } s; + + s.a = (int *) malloc (16 * sizeof (int)); + s.b = (int *) malloc (16 * sizeof (int)); + s.e = (int *) malloc (16 * sizeof (int)); + + #pragma acc data copy(s) + { + #pragma acc data copy(s.a[0:10]) + { + #pragma acc parallel loop attach(s.a) + for (int i = 0; i < 10; i++) + s.a[i] = i; + } + } + + for (int i = 0; i < 10; i++) + assert (s.a[i] == i); + + return 0; +} diff --git a/libgomp/testsuite/libgomp.oacc-c-c++-common/deep-copy-4.c b/libgomp/testsuite/libgomp.oacc-c-c++-common/deep-copy-4.c new file mode 100644 index 00000000000..8874ca0a504 --- /dev/null +++ b/libgomp/testsuite/libgomp.oacc-c-c++-common/deep-copy-4.c @@ -0,0 +1,87 @@ +#include +#include + +#define LIST_LENGTH 10 + +struct node +{ + struct node *next; + int val; +}; + +int +sum_nodes (struct node *head) +{ + int i = 0, sum = 0; + +#pragma acc parallel reduction(+:sum) present(head[:1]) + { + for (; head != NULL; head = head->next) + sum += head->val; + } + + return sum; +} + +void +insert (struct node *head, int val) +{ + struct node *n = (struct node *) malloc (sizeof (struct node)); + + if (head->next) + { +#pragma acc exit data detach(head->next) + } + + n->val = val; + n->next = head->next; + head->next = n; + +#pragma acc enter data copyin(n[:1]) +#pragma acc enter data attach(head->next) + if (n->next) + { +#pragma acc enter data attach(n->next) + } +} + +void +destroy (struct node *head) +{ + while (head->next != NULL) + { +#pragma acc exit data detach(head->next) + struct node * n = head->next; + head->next = n->next; + if (n->next) + { +#pragma acc exit data detach(n->next) + } +#pragma acc exit data delete (n[:1]) + if (head->next) + { +#pragma acc enter data attach(head->next) + } + free (n); + } +} + +int +main () +{ + struct node list = { .next = NULL, .val = 0 }; + int i; + +#pragma acc enter data copyin(list) + + for (i = 0; i < LIST_LENGTH; i++) + insert (&list, i + 1); + + assert (sum_nodes (&list) == (LIST_LENGTH * LIST_LENGTH + LIST_LENGTH) / 2); + + destroy (&list); + +#pragma acc exit data delete(list) + + return 0; +} diff --git a/libgomp/testsuite/libgomp.oacc-c-c++-common/deep-copy-6.c b/libgomp/testsuite/libgomp.oacc-c-c++-common/deep-copy-6.c new file mode 100644 index 00000000000..391149459c9 --- /dev/null +++ b/libgomp/testsuite/libgomp.oacc-c-c++-common/deep-copy-6.c @@ -0,0 +1,59 @@ +/* { dg-do run { target { ! openacc_host_selected } } } */ + +#include +#include +#include + +struct dc +{ + int a; + int **b; +}; + +int +main () +{ + int n = 100, i, j, k; + struct dc v = { .a = 3 }; + + v.b = (int **) malloc (sizeof (int *) * n); + for (i = 0; i < n; i++) + v.b[i] = (int *) malloc (sizeof (int) * n); + + for (k = 0; k < 16; k++) + { +#pragma acc data copy(v) + { +#pragma acc data copy(v.b[:n]) + { + for (i = 0; i < n; i++) + { + acc_copyin (v.b[i], sizeof (int) * n); + acc_attach ((void **) &v.b[i]); + } + +#pragma acc parallel loop + for (i = 0; i < n; i++) + for (j = 0; j < n; j++) + v.b[i][j] = v.a + i + j; + + for (i = 0; i < n; i++) + { + acc_detach ((void **) &v.b[i]); + acc_copyout (v.b[i], sizeof (int) * n); + } + } + } + + for (i = 0; i < n; i++) + for (j = 0; j < n; j++) + assert (v.b[i][j] == v.a + i + j); + + assert (!acc_is_present (&v, sizeof (v))); + assert (!acc_is_present (v.b, sizeof (int *) * n)); + for (i = 0; i < n; i++) + assert (!acc_is_present (v.b[i], sizeof (int) * n)); + } + + return 0; +} diff --git a/libgomp/testsuite/libgomp.oacc-c-c++-common/deep-copy-7.c b/libgomp/testsuite/libgomp.oacc-c-c++-common/deep-copy-7.c new file mode 100644 index 00000000000..a59047af520 --- /dev/null +++ b/libgomp/testsuite/libgomp.oacc-c-c++-common/deep-copy-7.c @@ -0,0 +1,45 @@ +/* { dg-do run { target { ! openacc_host_selected } } } */ + +#include +#include +#include + +struct dc +{ + int a; + int *b; +}; + +int +main () +{ + int n = 100, i, j, k; + struct dc v = { .a = 3 }; + + v.b = (int *) malloc (sizeof (int) * n); + + for (k = 0; k < 16; k++) + { + /* Here, we do not explicitly copy the enclosing structure, but work + with fields directly. Make sure attachment counters and reference + counters work properly in that case. */ +#pragma acc enter data copyin(v.a, v.b[0:n]) +#pragma acc enter data pcopyin(v.b[0:n]) +#pragma acc enter data pcopyin(v.b[0:n]) + +#pragma acc parallel loop present(v.a, v.b) + for (i = 0; i < n; i++) + v.b[i] = v.a + i; + +#pragma acc exit data copyout(v.b[:n]) finalize +#pragma acc exit data delete(v.a) + + for (i = 0; i < n; i++) + assert (v.b[i] == v.a + i); + + assert (!acc_is_present (&v, sizeof (v))); + assert (!acc_is_present (v.b, sizeof (int *) * n)); + } + + return 0; +} diff --git a/libgomp/testsuite/libgomp.oacc-c-c++-common/deep-copy-8.c b/libgomp/testsuite/libgomp.oacc-c-c++-common/deep-copy-8.c new file mode 100644 index 00000000000..0ca5990b377 --- /dev/null +++ b/libgomp/testsuite/libgomp.oacc-c-c++-common/deep-copy-8.c @@ -0,0 +1,54 @@ +/* { dg-do run { target { ! openacc_host_selected } } } */ + +#include +#include +#include + +struct dc +{ + int a; + int *b; + int *c; + int *d; +}; + +int +main () +{ + int n = 100, i, j, k; + struct dc v = { .a = 3 }; + + v.b = (int *) malloc (sizeof (int) * n); + v.c = (int *) malloc (sizeof (int) * n); + v.d = (int *) malloc (sizeof (int) * n); + +#pragma acc enter data copyin(v) + + for (k = 0; k < 16; k++) + { +#pragma acc enter data copyin(v.a, v.b[:n], v.c[:n], v.d[:n]) + +#pragma acc parallel loop + for (i = 0; i < n; i++) + v.b[i] = v.a + i; + +#pragma acc exit data copyout(v.b[:n]) +#pragma acc exit data copyout(v.c[:n]) +#pragma acc exit data copyout(v.d[:n]) +#pragma acc exit data copyout(v.a) + + for (i = 0; i < n; i++) + assert (v.b[i] == v.a + i); + + assert (acc_is_present (&v, sizeof (v))); + assert (!acc_is_present (v.b, sizeof (int *) * n)); + assert (!acc_is_present (v.c, sizeof (int *) * n)); + assert (!acc_is_present (v.d, sizeof (int *) * n)); + } + +#pragma acc exit data copyout(v) + + assert (!acc_is_present (&v, sizeof (v))); + + return 0; +} diff --git a/libgomp/testsuite/libgomp.oacc-c-c++-common/deep-copy-9.c b/libgomp/testsuite/libgomp.oacc-c-c++-common/deep-copy-9.c new file mode 100644 index 00000000000..e86a46bd84a --- /dev/null +++ b/libgomp/testsuite/libgomp.oacc-c-c++-common/deep-copy-9.c @@ -0,0 +1,53 @@ +#include + +typedef struct { + int *a; + int *b; +} 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)); + + for (i = 0; i < N; i++) + { + m->a[i] = 0; + m->b[i] = 0; + } + +#pragma acc enter data copyin(m[0:1]) + + for (int i = 0; i < 99; i++) + { + int j; + int *ptr = m->a; +#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]) + for (j = 0; j < N; j++) + m->b[j]++; + } + +#pragma acc exit data copyout(m[0:1]) + + for (i = 0; i < N; i++) + { + if (m->a[i] != 99) + abort (); + if (m->b[i] != 99) + abort (); + } + + free (m->a); + free (m->b); + free (m); + + return 0; +} From patchwork Wed Dec 18 06:04:55 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Julian Brown X-Patchwork-Id: 1211989 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=209.132.180.131; helo=sourceware.org; envelope-from=gcc-patches-return-516181-incoming=patchwork.ozlabs.org@gcc.gnu.org; receiver=) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=codesourcery.com Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=gcc.gnu.org header.i=@gcc.gnu.org header.b="KSeImSGj"; dkim-atps=neutral Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 47d4KY3Z0nz9sSF for ; Wed, 18 Dec 2019 17:07:13 +1100 (AEDT) DomainKey-Signature: a=rsa-sha1; c=nofws; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:from :to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding:content-type; q=dns; s= default; b=nFHP+oXfQhiCxfmxqK8apoZkZi1fD7uTCsmluowxa2ZT+XbDfdqNq 1ePwligQfiMASJutb6KLItAUB2QYX3BlN3+YUEyaTrgpbW+24iWC9l/5W5+syD8T kc12rEhdEGy9LKL3vxK87Tyg7qERxcqWwkTsLRP8veJ0yhGf8Dl9BQ= DKIM-Signature: v=1; a=rsa-sha1; c=relaxed; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:from :to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding:content-type; s=default; bh=BHZHfDpla3Pg5fqVbnStpEKsHdk=; b=KSeImSGjZprv1/ntnzLKqns+2UEI eeNtrMiTmhF6c3DkLZgh30btO6dDM6kzKUFRRrAqwtgi6i2dxh5/hLLxLqDzZAma w9hIiq3XeWhvrNtozXp+n0iFo06ix2rSprdsNu3agRLjywvKESXtEb1YDQwMvYIc r1KfpV0hJ1BObmE= Received: (qmail 112569 invoked by alias); 18 Dec 2019 06:05:23 -0000 Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Delivered-To: mailing list gcc-patches@gcc.gnu.org Received: (qmail 112495 invoked by uid 89); 18 Dec 2019 06:05:22 -0000 Authentication-Results: sourceware.org; auth=none X-Spam-SWARE-Status: No, score=-24.2 required=5.0 tests=AWL, BAYES_00, GIT_PATCH_0, GIT_PATCH_1, GIT_PATCH_2, GIT_PATCH_3, KAM_SHORT, SPF_PASS autolearn=ham version=3.3.1 spammy=1n X-HELO: esa1.mentor.iphmx.com Received: from esa1.mentor.iphmx.com (HELO esa1.mentor.iphmx.com) (68.232.129.153) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Wed, 18 Dec 2019 06:05:17 +0000 IronPort-SDR: HLYZjegxMh4wx+seGv7P8JN9/QNLGSEKe/oPCALtQPdOBpBhgT1XrGnQ8QEUHdjFWBeRMjgqTO gjfZAVZVKN/S9CP+BVuwg8gc7SgVlBS0NZEXt9DrZegWq3ox8DwIgXP55yOFmRQCuDzjCyfaRy jEBu3yW1LPgDt5ZFgPZRlObwxYPTsv9JFChChmo2T0/hgwcZiQ8Ns4sWLJTbHIrf8pW3JG2IEG QfiUobo+iap8PJIwHUKqzPNQMrsG52tgIA0zVNDUISbijKGKzu1s1Su/UrLjPTJV+CQibe6YpY LzM= Received: from orw-gwy-01-in.mentorg.com ([192.94.38.165]) by esa1.mentor.iphmx.com with ESMTP; 17 Dec 2019 22:05:15 -0800 IronPort-SDR: o/tYaq0yqpraORqU/+Pt0BzqYPPwPmU7BwMDofcYd+wCC4LxqusdDw0U/XsWz1KitETmzJPUwN 0UVZicHnog5O/4H3iKdn7Xcz3iPEnpU4VhR0cft3kD69X3M2fESkoC4/FxH5FTNythrgYuIkT6 kCdO7ZQAPyhsCZj4WPAyOAoDArA/zAkFNqDGz7jGoZ7CYnjjja9LHLWN6JAEF4EDmWct+vAJiU 0ORDA16Hqv+yWBbwvufgK3G8oNCHXLJ02URchVZvzqE/yIho13pQcgmTaesp1or04BZw7XCQ77 R7g= From: Julian Brown To: CC: Thomas Schwinge , Jakub Jelinek , Tobias Burnus , , Subject: [PATCH 12/13] OpenACC 2.6 deep copy: Fortran execution tests Date: Tue, 17 Dec 2019 22:04:55 -0800 Message-ID: <1d88faf3d1c0d02302585be476f2c9081582f30e.1576648001.git.julian@codesourcery.com> In-Reply-To: References: MIME-Version: 1.0 X-IsSubscribed: yes This patch has been broken out of the "OpenACC 2.6 manual deep copy support" patch, last posted here: https://gcc.gnu.org/ml/gcc-patches/2019-11/msg02376.html This part adds Fortran execution tests to libgomp. Tested alongside other patches in this series with offloading to NVPTX. OK? Thanks, Julian ChangeLog libgomp/ * testsuite/libgomp.oacc-fortran/deep-copy-1.f90: New test. * testsuite/libgomp.oacc-fortran/deep-copy-2.f90: New test. * testsuite/libgomp.oacc-fortran/deep-copy-3.f90: New test. * testsuite/libgomp.oacc-fortran/deep-copy-4.f90: New test. * testsuite/libgomp.oacc-fortran/deep-copy-5.f90: New test. * testsuite/libgomp.oacc-fortran/deep-copy-6.f90: New test. * testsuite/libgomp.oacc-fortran/deep-copy-7.f90: New test. * testsuite/libgomp.oacc-fortran/deep-copy-8.f90: New test. * testsuite/libgomp.oacc-fortran/derived-type-1.f90: New test. * testsuite/libgomp.oacc-fortran/derivedtype-1.f95: New test. * testsuite/libgomp.oacc-fortran/derivedtype-2.f95: New test. * testsuite/libgomp.oacc-fortran/multidim-slice.f95: New test. * testsuite/libgomp.oacc-fortran/update-2.f90: New test. --- .../libgomp.oacc-fortran/deep-copy-1.f90 | 35 +++ .../libgomp.oacc-fortran/deep-copy-2.f90 | 33 ++ .../libgomp.oacc-fortran/deep-copy-3.f90 | 34 +++ .../libgomp.oacc-fortran/deep-copy-4.f90 | 49 +++ .../libgomp.oacc-fortran/deep-copy-5.f90 | 57 ++++ .../libgomp.oacc-fortran/deep-copy-6.f90 | 61 ++++ .../libgomp.oacc-fortran/deep-copy-7.f90 | 89 ++++++ .../libgomp.oacc-fortran/deep-copy-8.f90 | 41 +++ .../libgomp.oacc-fortran/derived-type-1.f90 | 28 ++ .../libgomp.oacc-fortran/derivedtype-1.f95 | 30 ++ .../libgomp.oacc-fortran/derivedtype-2.f95 | 41 +++ .../libgomp.oacc-fortran/multidim-slice.f95 | 50 +++ .../libgomp.oacc-fortran/update-2.f90 | 284 ++++++++++++++++++ 13 files changed, 832 insertions(+) create mode 100644 libgomp/testsuite/libgomp.oacc-fortran/deep-copy-1.f90 create mode 100644 libgomp/testsuite/libgomp.oacc-fortran/deep-copy-2.f90 create mode 100644 libgomp/testsuite/libgomp.oacc-fortran/deep-copy-3.f90 create mode 100644 libgomp/testsuite/libgomp.oacc-fortran/deep-copy-4.f90 create mode 100644 libgomp/testsuite/libgomp.oacc-fortran/deep-copy-5.f90 create mode 100644 libgomp/testsuite/libgomp.oacc-fortran/deep-copy-6.f90 create mode 100644 libgomp/testsuite/libgomp.oacc-fortran/deep-copy-7.f90 create mode 100644 libgomp/testsuite/libgomp.oacc-fortran/deep-copy-8.f90 create mode 100644 libgomp/testsuite/libgomp.oacc-fortran/derived-type-1.f90 create mode 100644 libgomp/testsuite/libgomp.oacc-fortran/derivedtype-1.f95 create mode 100644 libgomp/testsuite/libgomp.oacc-fortran/derivedtype-2.f95 create mode 100644 libgomp/testsuite/libgomp.oacc-fortran/multidim-slice.f95 create mode 100644 libgomp/testsuite/libgomp.oacc-fortran/update-2.f90 diff --git a/libgomp/testsuite/libgomp.oacc-fortran/deep-copy-1.f90 b/libgomp/testsuite/libgomp.oacc-fortran/deep-copy-1.f90 new file mode 100644 index 00000000000..c4cea11b571 --- /dev/null +++ b/libgomp/testsuite/libgomp.oacc-fortran/deep-copy-1.f90 @@ -0,0 +1,35 @@ +! { dg-do run } + +! Test of attach/detach with "acc data". + +program dtype + implicit none + integer, parameter :: n = 512 + type mytype + integer, allocatable :: a(:) + end type mytype + integer i + + type(mytype) :: var + + allocate(var%a(1:n)) + +!$acc data copy(var) +!$acc data copy(var%a) + +!$acc parallel loop + do i = 1,n + var%a(i) = i + end do +!$acc end parallel loop + +!$acc end data +!$acc end data + + do i = 1,n + if (i .ne. var%a(i)) stop 1 + end do + + deallocate(var%a) + +end program dtype diff --git a/libgomp/testsuite/libgomp.oacc-fortran/deep-copy-2.f90 b/libgomp/testsuite/libgomp.oacc-fortran/deep-copy-2.f90 new file mode 100644 index 00000000000..35936617b87 --- /dev/null +++ b/libgomp/testsuite/libgomp.oacc-fortran/deep-copy-2.f90 @@ -0,0 +1,33 @@ +! { dg-do run } + +! Test of attach/detach with "acc data", two clauses at once. + +program dtype + implicit none + integer, parameter :: n = 512 + type mytype + integer, allocatable :: a(:) + end type mytype + integer i + + type(mytype) :: var + + allocate(var%a(1:n)) + +!$acc data copy(var) copy(var%a) + +!$acc parallel loop + do i = 1,n + var%a(i) = i + end do +!$acc end parallel loop + +!$acc end data + + do i = 1,n + if (i .ne. var%a(i)) stop 1 + end do + + deallocate(var%a) + +end program dtype diff --git a/libgomp/testsuite/libgomp.oacc-fortran/deep-copy-3.f90 b/libgomp/testsuite/libgomp.oacc-fortran/deep-copy-3.f90 new file mode 100644 index 00000000000..667d944fecb --- /dev/null +++ b/libgomp/testsuite/libgomp.oacc-fortran/deep-copy-3.f90 @@ -0,0 +1,34 @@ +! { dg-do run } + +! Test of attach/detach with "acc parallel". + +program dtype + implicit none + integer, parameter :: n = 512 + type mytype + integer, allocatable :: a(:) + integer, allocatable :: b(:) + end type mytype + integer i + + type(mytype) :: var + + allocate(var%a(1:n)) + allocate(var%b(1:n)) + +!$acc parallel loop copy(var) copy(var%a(1:n)) copy(var%b(1:n)) + do i = 1,n + var%a(i) = i + var%b(i) = i + end do +!$acc end parallel loop + + do i = 1,n + if (i .ne. var%a(i)) stop 1 + if (i .ne. var%b(i)) stop 2 + end do + + deallocate(var%a) + deallocate(var%b) + +end program dtype diff --git a/libgomp/testsuite/libgomp.oacc-fortran/deep-copy-4.f90 b/libgomp/testsuite/libgomp.oacc-fortran/deep-copy-4.f90 new file mode 100644 index 00000000000..6949e120c9f --- /dev/null +++ b/libgomp/testsuite/libgomp.oacc-fortran/deep-copy-4.f90 @@ -0,0 +1,49 @@ +! { dg-do run } + +! Test of attach/detach with "acc enter/exit data". + +program dtype + implicit none + integer, parameter :: n = 512 + type mytype + integer, allocatable :: a(:) + integer, allocatable :: b(:) + end type mytype + integer, allocatable :: r(:) + integer i + + type(mytype) :: var + + allocate(var%a(1:n)) + allocate(var%b(1:n)) + allocate(r(1:n)) + +!$acc enter data copyin(var) + +!$acc enter data copyin(var%a, var%b, r) + +!$acc parallel loop + do i = 1,n + var%a(i) = i + var%b(i) = i * 2 + r(i) = i * 3 + end do +!$acc end parallel loop + +!$acc exit data copyout(var%a) +!$acc exit data copyout(var%b) +!$acc exit data copyout(r) + + do i = 1,n + if (i .ne. var%a(i)) stop 1 + if (i * 2 .ne. var%b(i)) stop 2 + if (i * 3 .ne. r(i)) stop 3 + end do + +!$acc exit data delete(var) + + deallocate(var%a) + deallocate(var%b) + deallocate(r) + +end program dtype diff --git a/libgomp/testsuite/libgomp.oacc-fortran/deep-copy-5.f90 b/libgomp/testsuite/libgomp.oacc-fortran/deep-copy-5.f90 new file mode 100644 index 00000000000..6843cf1d0fa --- /dev/null +++ b/libgomp/testsuite/libgomp.oacc-fortran/deep-copy-5.f90 @@ -0,0 +1,57 @@ +! { dg-do run } + +! Test of attach/detach, "enter data" inside "data", and subarray. + +program dtype + implicit none + integer, parameter :: n = 512 + type mytype + integer, allocatable :: a(:) + integer, allocatable :: b(:) + end type mytype + integer i + + type(mytype) :: var + + allocate(var%a(1:n)) + allocate(var%b(1:n)) + +!$acc data copy(var) + + do i = 1, n + var%a(i) = 0 + var%b(i) = 0 + end do + +!$acc enter data copyin(var%a(5:n - 5), var%b(5:n - 5)) + +!$acc parallel loop + do i = 5,n - 5 + var%a(i) = i + var%b(i) = i * 2 + end do +!$acc end parallel loop + +!$acc exit data copyout(var%a(5:n - 5), var%b(5:n - 5)) + +!$acc end data + + do i = 1,4 + if (var%a(i) .ne. 0) stop 1 + if (var%b(i) .ne. 0) stop 2 + end do + + do i = 5,n - 5 + if (i .ne. var%a(i)) stop 3 + if (i * 2 .ne. var%b(i)) stop 4 + end do + + do i = n - 4,n + if (var%a(i) .ne. 0) stop 5 + if (var%b(i) .ne. 0) stop 6 + end do + + deallocate(var%a) + deallocate(var%b) + +end program dtype diff --git a/libgomp/testsuite/libgomp.oacc-fortran/deep-copy-6.f90 b/libgomp/testsuite/libgomp.oacc-fortran/deep-copy-6.f90 new file mode 100644 index 00000000000..12910d0d655 --- /dev/null +++ b/libgomp/testsuite/libgomp.oacc-fortran/deep-copy-6.f90 @@ -0,0 +1,61 @@ +! { dg-do run } + +! Test of attachment counters and finalize. + +program dtype + implicit none + integer, parameter :: n = 512 + type mytype + integer, allocatable :: a(:) + integer, allocatable :: b(:) + end type mytype + integer i + + type(mytype) :: var + + allocate(var%a(1:n)) + allocate(var%b(1:n)) + +!$acc data copy(var) + + do i = 1, n + var%a(i) = 0 + var%b(i) = 0 + end do + +!$acc enter data copyin(var%a(5:n - 5), var%b(5:n - 5)) + + do i = 1,20 + !$acc enter data attach(var%a) + end do + +!$acc parallel loop + do i = 5,n - 5 + var%a(i) = i + var%b(i) = i * 2 + end do +!$acc end parallel loop + +!$acc exit data copyout(var%a(5:n - 5), var%b(5:n - 5)) finalize + +!$acc end data + + do i = 1,4 + if (var%a(i) .ne. 0) stop 1 + if (var%b(i) .ne. 0) stop 2 + end do + + do i = 5,n - 5 + if (i .ne. var%a(i)) stop 3 + if (i * 2 .ne. var%b(i)) stop 4 + end do + + do i = n - 4,n + if (var%a(i) .ne. 0) stop 5 + if (var%b(i) .ne. 0) stop 6 + end do + + deallocate(var%a) + deallocate(var%b) + +end program dtype diff --git a/libgomp/testsuite/libgomp.oacc-fortran/deep-copy-7.f90 b/libgomp/testsuite/libgomp.oacc-fortran/deep-copy-7.f90 new file mode 100644 index 00000000000..ab44f0a73b9 --- /dev/null +++ b/libgomp/testsuite/libgomp.oacc-fortran/deep-copy-7.f90 @@ -0,0 +1,89 @@ +! { dg-do run } + +! Test of attach/detach with scalar elements and nested derived types. + +program dtype + implicit none + integer, parameter :: n = 512 + type subtype + integer :: g, h + integer, allocatable :: q(:) + end type subtype + type mytype + integer, allocatable :: a(:) + integer, allocatable :: c, d + integer, allocatable :: b(:) + integer :: f + type(subtype) :: s + end type mytype + integer i + + type(mytype) :: var + + allocate(var%a(1:n)) + allocate(var%b(1:n)) + allocate(var%c) + allocate(var%d) + allocate(var%s%q(1:n)) + + var%c = 16 + var%d = 20 + var%f = 7 + var%s%g = 21 + var%s%h = 38 + +!$acc enter data copyin(var) + + do i = 1, n + var%a(i) = 0 + var%b(i) = 0 + var%s%q(i) = 0 + end do + +!$acc data copy(var%a(5:n - 5), var%b(5:n - 5), var%c, var%d) & +!$acc & copy(var%s%q) + +!$acc parallel loop default(none) present(var) + do i = 5,n - 5 + var%a(i) = i + var%b(i) = i * 2 + var%s%q(i) = i * 3 + var%s%g = 100 + var%s%h = 101 + end do +!$acc end parallel loop + +!$acc end data + +!$acc exit data copyout(var) + + do i = 1,4 + if (var%a(i) .ne. 0) stop 1 + if (var%b(i) .ne. 0) stop 2 + if (var%s%q(i) .ne. 0) stop 3 + end do + + do i = 5,n - 5 + if (i .ne. var%a(i)) stop 4 + if (i * 2 .ne. var%b(i)) stop 5 + if (i * 3 .ne. var%s%q(i)) stop 6 + end do + + do i = n - 4,n + if (var%a(i) .ne. 0) stop 7 + if (var%b(i) .ne. 0) stop 8 + if (var%s%q(i) .ne. 0) stop 9 + end do + + if (var%c .ne. 16) stop 10 + if (var%d .ne. 20) stop 11 + if (var%s%g .ne. 100 .or. var%s%h .ne. 101) stop 12 + if (var%f .ne. 7) stop 13 + + deallocate(var%a) + deallocate(var%b) + deallocate(var%c) + deallocate(var%d) + deallocate(var%s%q) + +end program dtype diff --git a/libgomp/testsuite/libgomp.oacc-fortran/deep-copy-8.f90 b/libgomp/testsuite/libgomp.oacc-fortran/deep-copy-8.f90 new file mode 100644 index 00000000000..d142763ae59 --- /dev/null +++ b/libgomp/testsuite/libgomp.oacc-fortran/deep-copy-8.f90 @@ -0,0 +1,41 @@ +! { dg-do run } + +! Test of explicit attach/detach clauses and attachment counters. There are no +! acc_attach/acc_detach API routines in Fortran. + +program dtype + use openacc + implicit none + integer, parameter :: n = 512 + type mytype + integer, allocatable :: a(:) + end type mytype + integer i + + type(mytype) :: var + + allocate(var%a(1:n)) + + call acc_copyin(var) + call acc_copyin(var%a) + + !$acc enter data attach(var%a) + +!$acc parallel loop attach(var%a) + do i = 1,n + var%a(i) = i + end do +!$acc end parallel loop + + !$acc exit data detach(var%a) + + call acc_copyout(var%a) + call acc_copyout(var) + + do i = 1,n + if (i .ne. var%a(i)) stop 1 + end do + + deallocate(var%a) + +end program dtype diff --git a/libgomp/testsuite/libgomp.oacc-fortran/derived-type-1.f90 b/libgomp/testsuite/libgomp.oacc-fortran/derived-type-1.f90 new file mode 100644 index 00000000000..eb7812d541e --- /dev/null +++ b/libgomp/testsuite/libgomp.oacc-fortran/derived-type-1.f90 @@ -0,0 +1,28 @@ +! Test derived types with subarrays + +! { dg-do run } + + implicit none + type dtype + integer :: a, b, c + end type dtype + integer, parameter :: n = 100 + integer i + type (dtype), dimension(n) :: d + + !$acc data copy(d(1:n)) + !$acc parallel loop + do i = 1, n + d(i)%a = i + d(i)%b = i-1 + d(i)%c = i+1 + end do + !$acc end data + + do i = 1, n + if (d(i)%a /= i) stop 1 + if (d(i)%b /= i-1) stop 2 + if (d(i)%c /= i+1) stop 3 + end do +end program + diff --git a/libgomp/testsuite/libgomp.oacc-fortran/derivedtype-1.f95 b/libgomp/testsuite/libgomp.oacc-fortran/derivedtype-1.f95 new file mode 100644 index 00000000000..75ce48ddca2 --- /dev/null +++ b/libgomp/testsuite/libgomp.oacc-fortran/derivedtype-1.f95 @@ -0,0 +1,30 @@ +! { dg-do run } + +program main + implicit none + + type mytype + integer :: a, b, c + end type mytype + + type(mytype) :: myvar + integer :: i + + myvar%a = 0 + myvar%b = 0 + myvar%c = 0 + +!$acc enter data copyin(myvar) + +!$acc parallel present(myvar) + myvar%a = 1 + myvar%b = 2 + myvar%c = 3 +!$acc end parallel + +!$acc exit data copyout(myvar) + + if (myvar%a .ne. 1) stop 1 + if (myvar%b .ne. 2) stop 2 + if (myvar%c .ne. 3) stop 3 +end program main diff --git a/libgomp/testsuite/libgomp.oacc-fortran/derivedtype-2.f95 b/libgomp/testsuite/libgomp.oacc-fortran/derivedtype-2.f95 new file mode 100644 index 00000000000..3088b832957 --- /dev/null +++ b/libgomp/testsuite/libgomp.oacc-fortran/derivedtype-2.f95 @@ -0,0 +1,41 @@ +! { dg-do run } + +program main + implicit none + + type tnest + integer :: ia, ib, ic + end type tnest + + type mytype + type(tnest) :: nest + integer :: a, b, c + end type mytype + + type(mytype) :: myvar + integer :: i + + myvar%a = 0 + myvar%b = 0 + myvar%c = 0 + myvar%nest%ia = 0 + myvar%nest%ib = 0 + myvar%nest%ic = 0 + +!$acc enter data copyin(myvar%nest) + +!$acc parallel present(myvar%nest) + myvar%nest%ia = 4 + myvar%nest%ib = 5 + myvar%nest%ic = 6 +!$acc end parallel + +!$acc exit data copyout(myvar%nest) + + if (myvar%a .ne. 0) stop 1 + if (myvar%b .ne. 0) stop 2 + if (myvar%c .ne. 0) stop 3 + if (myvar%nest%ia .ne. 4) stop 4 + if (myvar%nest%ib .ne. 5) stop 5 + if (myvar%nest%ic .ne. 6) stop 6 +end program main diff --git a/libgomp/testsuite/libgomp.oacc-fortran/multidim-slice.f95 b/libgomp/testsuite/libgomp.oacc-fortran/multidim-slice.f95 new file mode 100644 index 00000000000..a9b40eeab4c --- /dev/null +++ b/libgomp/testsuite/libgomp.oacc-fortran/multidim-slice.f95 @@ -0,0 +1,50 @@ +! { dg-do run } + +program main + implicit none + real, allocatable :: myarr(:,:,:,:,:) + integer i, j, k, l, m + + allocate(myarr(1:10,1:10,1:10,1:10,1:10)) + + do i=1,10 + do j=1,10 + do k=1,10 + do l=1,10 + do m=1,10 + myarr(m,l,k,j,i) = i+j+k+l+m + end do + end do + end do + end do + end do + + do i=1,10 + !$acc data copy(myarr(:,:,:,:,i)) + !$acc parallel loop collapse(4) present(myarr(:,:,:,:,i)) + do j=1,10 + do k=1,10 + do l=1,10 + do m=1,10 + myarr(m,l,k,j,i) = myarr(m,l,k,j,i) + 1 + end do + end do + end do + end do + !$acc end parallel loop + !$acc end data + end do + + do i=1,10 + do j=1,10 + do k=1,10 + do l=1,10 + do m=1,10 + if (myarr(m,l,k,j,i) .ne. i+j+k+l+m+1) stop 1 + end do + end do + end do + end do + end do + +end program main diff --git a/libgomp/testsuite/libgomp.oacc-fortran/update-2.f90 b/libgomp/testsuite/libgomp.oacc-fortran/update-2.f90 new file mode 100644 index 00000000000..c3c8a07868f --- /dev/null +++ b/libgomp/testsuite/libgomp.oacc-fortran/update-2.f90 @@ -0,0 +1,284 @@ +! Test ACC UPDATE with derived types. + +! { dg-do run } + +module dt + integer, parameter :: n = 10 + type inner + integer :: d(n) + end type inner + type mytype + integer(8) :: a, b, c(n) + type(inner) :: in + end type mytype +end module dt + +program derived_acc + use dt + + implicit none + integer i, res + type(mytype) :: var + + var%a = 0 + var%b = 1 + var%c(:) = 10 + var%in%d(:) = 100 + + var%c(:) = 10 + + !$acc enter data copyin(var) + + !$acc parallel loop present(var) + do i = 1, 1 + var%a = var%b + end do + !$acc end parallel loop + + !$acc update host(var%a) + + if (var%a /= var%b) stop 1 + + var%b = 100 + + !$acc update device(var%b) + + !$acc parallel loop present(var) + do i = 1, 1 + var%a = var%b + end do + !$acc end parallel loop + + !$acc update host(var%a) + + if (var%a /= var%b) stop 2 + + !$acc parallel loop present (var) + do i = 1, n + var%c(i) = i + end do + !$acc end parallel loop + + !$acc update host(var%c) + + var%a = -1 + + do i = 1, n + if (var%c(i) /= i) stop 3 + var%c(i) = var%a + end do + + !$acc update device(var%a) + !$acc update device(var%c) + + res = 0 + + !$acc parallel loop present(var) reduction(+:res) + do i = 1, n + if (var%c(i) /= var%a) res = res + 1 + end do + + if (res /= 0) stop 4 + + var%c(:) = 0 + + !$acc update device(var%c) + + !$acc parallel loop present(var) + do i = 5, 5 + var%c(i) = 1 + end do + !$acc end parallel loop + + !$acc update host(var%c(5)) + + do i = 1, n + if (i /= 5 .and. var%c(i) /= 0) stop 5 + if (i == 5 .and. var%c(i) /= 1) stop 6 + end do + + !$acc parallel loop present(var) + do i = 1, n + var%in%d = var%a + end do + !$acc end parallel loop + + !$acc update host(var%in%d) + + do i = 1, n + if (var%in%d(i) /= var%a) stop 7 + end do + + var%c(:) = 0 + + !$acc update device(var%c) + + var%c(:) = -1 + + !$acc parallel loop present(var) + do i = n/2, n + var%c(i) = i + end do + !$acc end parallel loop + + !$acc update host(var%c(n/2:n)) + + do i = 1,n + if (i < n/2 .and. var%c(i) /= -1) stop 8 + if (i >= n/2 .and. var%c(i) /= i) stop 9 + end do + + var%in%d(:) = 0 + !$acc update device(var%in%d) + + !$acc parallel loop present(var) + do i = 5, 5 + var%in%d(i) = 1 + end do + !$acc end parallel loop + + !$acc update host(var%in%d(5)) + + do i = 1, n + if (i /= 5 .and. var%in%d(i) /= 0) stop 10 + if (i == 5 .and. var%in%d(i) /= 1) stop 11 + end do + + !$acc exit data delete(var) + + call derived_acc_subroutine(var) +end program derived_acc + +subroutine derived_acc_subroutine(var) + use dt + + implicit none + integer i, res + type(mytype) :: var + + var%a = 0 + var%b = 1 + var%c(:) = 10 + var%in%d(:) = 100 + + var%c(:) = 10 + + !$acc enter data copyin(var) + + !$acc parallel loop present(var) + do i = 1, 1 + var%a = var%b + end do + !$acc end parallel loop + + !$acc update host(var%a) + + if (var%a /= var%b) stop 12 + + var%b = 100 + + !$acc update device(var%b) + + !$acc parallel loop present(var) + do i = 1, 1 + var%a = var%b + end do + !$acc end parallel loop + + !$acc update host(var%a) + + if (var%a /= var%b) stop 13 + + !$acc parallel loop present (var) + do i = 1, n + var%c(i) = i + end do + !$acc end parallel loop + + !$acc update host(var%c) + + var%a = -1 + + do i = 1, n + if (var%c(i) /= i) stop 14 + var%c(i) = var%a + end do + + !$acc update device(var%a) + !$acc update device(var%c) + + res = 0 + + !$acc parallel loop present(var) reduction(+:res) + do i = 1, n + if (var%c(i) /= var%a) res = res + 1 + end do + + if (res /= 0) stop 15 + + var%c(:) = 0 + + !$acc update device(var%c) + + !$acc parallel loop present(var) + do i = 5, 5 + var%c(i) = 1 + end do + !$acc end parallel loop + + !$acc update host(var%c(5)) + + do i = 1, n + if (i /= 5 .and. var%c(i) /= 0) stop 16 + if (i == 5 .and. var%c(i) /= 1) stop 17 + end do + + !$acc parallel loop present(var) + do i = 1, n + var%in%d = var%a + end do + !$acc end parallel loop + + !$acc update host(var%in%d) + + do i = 1, n + if (var%in%d(i) /= var%a) stop 18 + end do + + var%c(:) = 0 + + !$acc update device(var%c) + + var%c(:) = -1 + + !$acc parallel loop present(var) + do i = n/2, n + var%c(i) = i + end do + !$acc end parallel loop + + !$acc update host(var%c(n/2:n)) + + do i = 1,n + if (i < n/2 .and. var%c(i) /= -1) stop 19 + if (i >= n/2 .and. var%c(i) /= i) stop 20 + end do + + var%in%d(:) = 0 + !$acc update device(var%in%d) + + !$acc parallel loop present(var) + do i = 5, 5 + var%in%d(i) = 1 + end do + !$acc end parallel loop + + !$acc update host(var%in%d(5)) + + do i = 1, n + if (i /= 5 .and. var%in%d(i) /= 0) stop 21 + if (i == 5 .and. var%in%d(i) /= 1) stop 22 + end do + + !$acc exit data delete(var) +end subroutine derived_acc_subroutine From patchwork Wed Dec 18 06:04:56 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Julian Brown X-Patchwork-Id: 1211990 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=209.132.180.131; helo=sourceware.org; envelope-from=gcc-patches-return-516182-incoming=patchwork.ozlabs.org@gcc.gnu.org; receiver=) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=codesourcery.com Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=gcc.gnu.org header.i=@gcc.gnu.org header.b="Dnz4EIau"; dkim-atps=neutral Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 47d4Kw45bGz9sS3 for ; Wed, 18 Dec 2019 17:07:32 +1100 (AEDT) DomainKey-Signature: a=rsa-sha1; c=nofws; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:from :to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding:content-type; q=dns; s= default; b=IGX3diifqpFKJYnPi6+nHFx/pFe1BmCXFW/PdGAuGHrwBQEDGZXfr icf4WYa9ZSzST78ZizQOL5mTXQ0AxqJoYyL90CfaQ/xexbSTzKsz8L7ByQ17twKh CNUoQ6BjPlEvh5qg4O98jS8GwqaeqxoZwairzn2r8N/y++2hCOhcOg= DKIM-Signature: v=1; a=rsa-sha1; c=relaxed; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:from :to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding:content-type; s=default; bh=M4jOxJsivgZc8okLtEMDegiT43E=; b=Dnz4EIauH9aibk0ex/s6lpCovqLI NDzAep+HMrHbdaG8aOlJkpbYmryqX/Yq+KLc4zf3ev0od3InpWNn2VkO4nunY7RG KsTMXV9JJviBb6uxHhQn6hSkgtQAgAbzXUryCHP4UvuFwflkaiitWNjoQmxG1cIA FHicMB+ta/2NmZw= Received: (qmail 112608 invoked by alias); 18 Dec 2019 06:05:23 -0000 Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Delivered-To: mailing list gcc-patches@gcc.gnu.org Received: (qmail 112508 invoked by uid 89); 18 Dec 2019 06:05:22 -0000 Authentication-Results: sourceware.org; auth=none X-Spam-SWARE-Status: No, score=-24.2 required=5.0 tests=AWL, BAYES_00, GIT_PATCH_0, GIT_PATCH_1, GIT_PATCH_2, GIT_PATCH_3, KAM_SHORT, SPF_PASS autolearn=ham version=3.3.1 spammy=largely, ij, sk:attral X-HELO: esa1.mentor.iphmx.com Received: from esa1.mentor.iphmx.com (HELO esa1.mentor.iphmx.com) (68.232.129.153) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Wed, 18 Dec 2019 06:05:19 +0000 IronPort-SDR: rTiTHnmG9hmYEqhL5dYp6MYG91COdMPAH7Q+u43Kamaj9f1y7yi9zx5IuFW3sy20gtbblnXnN4 r5+4kRM5bwD5+Vwrw9Da/YP5I3x+yj4YvkkUQbQSltHNuxdnFWVwQBf1FO0PLTR54augNLAacM /ID5X/nEfYHBGMzjbHkEUIsjiq8g8WzZwwpF6jmbiYShoRf7hF/qVaylLOvt6bWa6WkAqpxqQJ hvS8wRiYSEazv9pHSlzDH35c9qvfveiIqJEE80tZkHjqEK0RMQk2Ol9rLAImfQdJlLkGm4oINK gSM= Received: from orw-gwy-01-in.mentorg.com ([192.94.38.165]) by esa1.mentor.iphmx.com with ESMTP; 17 Dec 2019 22:05:19 -0800 IronPort-SDR: 8yYcimoWNKvuzuXaqpzWORGAuEph5eRvU3zpJ7gF1eccXNzyif0SvaGIr8PNDV1orHsQB7YZxP Cw9j/x7g5yWB6RmitFj3hgMzyz9KRUZvOhaavd9SIdfAihWvxNWo49V9XLFOds+Vj3avUoXbja A5z6NuIklZm1W7wYsSmfLW8AotEPxGX5jzUw+Vf38Uulstcmya/K+EMjzP1bmUg1TcDp9WkS71 pDZT0g8vcFeGX37t9jnI++840UV0+h1Yqia/foK+5omzEFrXAzQMdE6QqWj237TGIgv9VZrJdG bj8= From: Julian Brown To: CC: Thomas Schwinge , Jakub Jelinek , Tobias Burnus , , Subject: [PATCH 13/13] Fortran polymorphic class-type support for OpenACC Date: Tue, 17 Dec 2019 22:04:56 -0800 Message-ID: <349a9c45db241c946bb17ea0a3b620308abc3a14.1576648001.git.julian@codesourcery.com> In-Reply-To: References: MIME-Version: 1.0 X-IsSubscribed: yes This patch builds on the Fortran front-end support posted earlier in this series to enable polymorphic class pointers to be used in OpenACC directives as well. It was last posted here: https://gcc.gnu.org/ml/gcc-patches/2019-10/msg00541.html This version is largely the same as the previous posted version, modulo rebasing. Tested alongside other patches in this series with offloading to NVPTX. OK? Thanks, Julian ChangeLog gcc/fortran/ * openmp.c (resolve_oacc_data_clauses): Don't disallow allocatable polymorphic types for OpenACC. * trans-openmp.c (gfc_trans_omp_clauses): Support polymorphic class types. libgomp/ * testsuite/libgomp.oacc-fortran/class-ptr-param.f95: New test. * testsuite/libgomp.oacc-fortran/classtypes-1.f95: New test. * testsuite/libgomp.oacc-fortran/classtypes-2.f95: New test. --- gcc/fortran/openmp.c | 6 - gcc/fortran/trans-openmp.c | 69 +++++++++--- .../libgomp.oacc-fortran/class-ptr-param.f95 | 34 ++++++ .../libgomp.oacc-fortran/classtypes-1.f95 | 48 ++++++++ .../libgomp.oacc-fortran/classtypes-2.f95 | 106 ++++++++++++++++++ 5 files changed, 244 insertions(+), 19 deletions(-) create mode 100644 libgomp/testsuite/libgomp.oacc-fortran/class-ptr-param.f95 create mode 100644 libgomp/testsuite/libgomp.oacc-fortran/classtypes-1.f95 create mode 100644 libgomp/testsuite/libgomp.oacc-fortran/classtypes-2.f95 diff --git a/gcc/fortran/openmp.c b/gcc/fortran/openmp.c index d79f4a90271..d1a6f2eddca 100644 --- a/gcc/fortran/openmp.c +++ b/gcc/fortran/openmp.c @@ -3922,12 +3922,6 @@ check_array_not_assumed (gfc_symbol *sym, locus loc, const char *name) static void resolve_oacc_data_clauses (gfc_symbol *sym, locus loc, const char *name) { - if ((sym->ts.type == BT_ASSUMED && sym->attr.allocatable) - || (sym->ts.type == BT_CLASS && CLASS_DATA (sym) - && CLASS_DATA (sym)->attr.allocatable)) - gfc_error ("ALLOCATABLE object %qs of polymorphic type " - "in %s clause at %L", sym->name, name, &loc); - check_symbol_not_pointer (sym, loc, name); check_array_not_assumed (sym, loc, name); } diff --git a/gcc/fortran/trans-openmp.c b/gcc/fortran/trans-openmp.c index d091b6a6d62..7ef573479b3 100644 --- a/gcc/fortran/trans-openmp.c +++ b/gcc/fortran/trans-openmp.c @@ -2472,14 +2472,42 @@ gfc_trans_omp_clauses (stmtblock_t *block, gfc_omp_clauses *clauses, tree present = (gfc_omp_is_optional_argument (decl) ? gfc_omp_check_optional_argument (decl, true) : NULL_TREE); - if (POINTER_TYPE_P (TREE_TYPE (decl)) - && (gfc_omp_privatize_by_reference (decl) - || GFC_DECL_GET_SCALAR_POINTER (decl) - || GFC_DECL_GET_SCALAR_ALLOCATABLE (decl) - || GFC_DECL_CRAY_POINTEE (decl) - || GFC_DESCRIPTOR_TYPE_P - (TREE_TYPE (TREE_TYPE (decl))) - || n->sym->ts.type == BT_DERIVED)) + if (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); + goto finalize_map_clause; + } + else if (POINTER_TYPE_P (TREE_TYPE (decl)) + && (gfc_omp_privatize_by_reference (decl) + || GFC_DECL_GET_SCALAR_POINTER (decl) + || GFC_DECL_GET_SCALAR_ALLOCATABLE (decl) + || GFC_DECL_CRAY_POINTEE (decl) + || GFC_DESCRIPTOR_TYPE_P + (TREE_TYPE (TREE_TYPE (decl))) + || n->sym->ts.type == BT_DERIVED)) { tree orig_decl = decl; node4 = build_omp_clause (input_location, @@ -2646,11 +2674,15 @@ gfc_trans_omp_clauses (stmtblock_t *block, gfc_omp_clauses *clauses, symbol_attribute sym_attr; - sym_attr = lastcomp->u.c.component->attr; + if (lastcomp->u.c.component->ts.type == BT_CLASS) + sym_attr = CLASS_DATA (lastcomp->u.c.component)->attr; + else + sym_attr = lastcomp->u.c.component->attr; gfc_init_se (&se, NULL); if (!sym_attr.dimension + && lastcomp->u.c.component->ts.type != BT_CLASS && lastcomp->u.c.component->ts.type != BT_DERIVED) { /* Last component is a scalar. */ @@ -2680,13 +2712,24 @@ gfc_trans_omp_clauses (stmtblock_t *block, gfc_omp_clauses *clauses, tree inner = se.expr; - /* Last component is a derived type. */ - if (lastcomp->u.c.component->ts.type == BT_DERIVED) + /* Last component is a derived type or class pointer. */ + if (lastcomp->u.c.component->ts.type == BT_DERIVED + || lastcomp->u.c.component->ts.type == BT_CLASS) { if (sym_attr.allocatable || sym_attr.pointer) { - tree data = inner; - tree size = TYPE_SIZE_UNIT (TREE_TYPE (inner)); + tree data, size; + + if (lastcomp->u.c.component->ts.type == BT_CLASS) + { + data = gfc_class_data_get (inner); + size = gfc_class_vtab_size_get (inner); + } + else /* BT_DERIVED. */ + { + data = inner; + size = TYPE_SIZE_UNIT (TREE_TYPE (inner)); + } OMP_CLAUSE_DECL (node) = build_fold_indirect_ref (data); diff --git a/libgomp/testsuite/libgomp.oacc-fortran/class-ptr-param.f95 b/libgomp/testsuite/libgomp.oacc-fortran/class-ptr-param.f95 new file mode 100644 index 00000000000..80147337c9d --- /dev/null +++ b/libgomp/testsuite/libgomp.oacc-fortran/class-ptr-param.f95 @@ -0,0 +1,34 @@ +! { dg-do run } + +module typemod + +type mytype + integer :: a +end type mytype + +contains + +subroutine mysub(c) + implicit none + + class(mytype), allocatable :: c + +!$acc parallel copy(c) + c%a = 5 +!$acc end parallel +end subroutine mysub + +end module typemod + +program main + use typemod + implicit none + + class(mytype), allocatable :: myvar + allocate(mytype :: myvar) + + myvar%a = 0 + call mysub(myvar) + + if (myvar%a .ne. 5) stop 1 +end program main diff --git a/libgomp/testsuite/libgomp.oacc-fortran/classtypes-1.f95 b/libgomp/testsuite/libgomp.oacc-fortran/classtypes-1.f95 new file mode 100644 index 00000000000..f16f42fc3af --- /dev/null +++ b/libgomp/testsuite/libgomp.oacc-fortran/classtypes-1.f95 @@ -0,0 +1,48 @@ +! { dg-do run } + +module typemod + +type :: typeimpl + real, pointer :: p(:) => null() +end type typeimpl + +type :: basictype + class(typeimpl), pointer :: p => null() +end type basictype + +type, extends(basictype) :: regulartype + character :: void +end type regulartype + +end module typemod + +program main + use typemod + implicit none + type(regulartype), pointer :: myvar + integer :: i + real :: j, k + + allocate(myvar) + allocate(myvar%p) + allocate(myvar%p%p(1:100)) + + do i=1,100 + myvar%p%p(i) = -1.0 + end do + +!$acc enter data copyin(myvar, myvar%p) create(myvar%p%p) + +!$acc parallel loop present(myvar%p%p) + do i=1,100 + myvar%p%p(i) = i * 2 + end do +!$acc end parallel loop + +!$acc exit data copyout(myvar%p%p) delete(myvar, myvar%p) + + do i=1,100 + if (myvar%p%p(i) .ne. i * 2) stop 1 + end do + +end program main diff --git a/libgomp/testsuite/libgomp.oacc-fortran/classtypes-2.f95 b/libgomp/testsuite/libgomp.oacc-fortran/classtypes-2.f95 new file mode 100644 index 00000000000..ad80ec2a0ef --- /dev/null +++ b/libgomp/testsuite/libgomp.oacc-fortran/classtypes-2.f95 @@ -0,0 +1,106 @@ +! { dg-do run } + +module wrapper_mod + +type compute + integer, allocatable :: block(:,:) +contains + procedure :: initialize +end type compute + +type, extends(compute) :: cpu_compute + integer :: blocksize +contains + procedure :: setblocksize +end type cpu_compute + +type, extends(compute) :: gpu_compute + integer :: numgangs + integer :: numworkers + integer :: vectorsize + integer, allocatable :: gpu_block(:,:) +contains + procedure :: setdims +end type gpu_compute + +contains + +subroutine initialize(c, length, width) + implicit none + class(compute) :: c + integer :: length + integer :: width + integer :: i + integer :: j + + allocate (c%block(length, width)) + + do i=1,length + do j=1, width + c%block(i,j) = i + j + end do + end do +end subroutine initialize + +subroutine setdims(c, g, w, v) + implicit none + class(gpu_compute) :: c + integer :: g + integer :: w + integer :: v + c%numgangs = g + c%numworkers = w + c%vectorsize = v +end subroutine setdims + +subroutine setblocksize(c, bs) + implicit none + class(cpu_compute) :: c + integer :: bs + c%blocksize = bs +end subroutine setblocksize + +end module wrapper_mod + +program main + use wrapper_mod + implicit none + class(compute), allocatable, target :: mycomp + integer :: i, j + + allocate(gpu_compute::mycomp) + + call mycomp%initialize(1024,1024) + + !$acc enter data copyin(mycomp) + + select type (mycomp) + type is (cpu_compute) + call mycomp%setblocksize(32) + type is (gpu_compute) + call mycomp%setdims(32,32,32) + allocate(mycomp%gpu_block(1024,1024)) + !$acc update device(mycomp) + !$acc parallel copyin(mycomp%block) copyout(mycomp%gpu_block) + !$acc loop gang worker vector collapse(2) + do i=1,1024 + do j=1,1024 + mycomp%gpu_block(i,j) = mycomp%block(i,j) + 1 + end do + end do + !$acc end parallel + end select + + !$acc exit data copyout(mycomp) + + select type (g => mycomp) + type is (gpu_compute) + do i = 1, 1024 + do j = 1, 1024 + if (g%gpu_block(i,j) .ne. i + j + 1) stop 1 + end do + end do + end select + + deallocate(mycomp) +end program main