Patch Detail
get:
Show a patch.
patch:
Update a patch.
put:
Update a patch.
GET /api/patches/2218664/?format=api
{ "id": 2218664, "url": "http://patchwork.ozlabs.org/api/patches/2218664/?format=api", "web_url": "http://patchwork.ozlabs.org/project/gcc/patch/4596ca92-75bc-4085-982e-3305002265cf@baylibre.com/", "project": { "id": 17, "url": "http://patchwork.ozlabs.org/api/projects/17/?format=api", "name": "GNU Compiler Collection", "link_name": "gcc", "list_id": "gcc-patches.gcc.gnu.org", "list_email": "gcc-patches@gcc.gnu.org", "web_url": null, "scm_url": null, "webscm_url": null, "list_archive_url": "", "list_archive_url_format": "", "commit_url_format": "" }, "msgid": "<4596ca92-75bc-4085-982e-3305002265cf@baylibre.com>", "list_archive_url": null, "date": "2026-04-01T15:58:47", "name": "[OpenMP,v2] uses_allocators support", "commit_ref": null, "pull_url": null, "state": "new", "archived": false, "hash": "cd7cb79edfa4036083e3632df5d87eded6fd9378", "submitter": { "id": 87913, "url": "http://patchwork.ozlabs.org/api/people/87913/?format=api", "name": "Chung-Lin Tang", "email": "cltang@baylibre.com" }, "delegate": null, "mbox": "http://patchwork.ozlabs.org/project/gcc/patch/4596ca92-75bc-4085-982e-3305002265cf@baylibre.com/mbox/", "series": [ { "id": 498355, "url": "http://patchwork.ozlabs.org/api/series/498355/?format=api", "web_url": "http://patchwork.ozlabs.org/project/gcc/list/?series=498355", "date": "2026-04-01T15:58:47", "name": "[OpenMP,v2] uses_allocators support", "version": 2, "mbox": "http://patchwork.ozlabs.org/series/498355/mbox/" } ], "comments": "http://patchwork.ozlabs.org/api/patches/2218664/comments/", "check": "pending", "checks": "http://patchwork.ozlabs.org/api/patches/2218664/checks/", "tags": {}, "related": [], "headers": { "Return-Path": "<gcc-patches-bounces~incoming=patchwork.ozlabs.org@gcc.gnu.org>", "X-Original-To": [ "incoming@patchwork.ozlabs.org", "gcc-patches@gcc.gnu.org" ], "Delivered-To": [ "patchwork-incoming@legolas.ozlabs.org", "gcc-patches@gcc.gnu.org" ], "Authentication-Results": [ "legolas.ozlabs.org;\n\tdkim=pass (2048-bit key;\n unprotected) header.d=baylibre-com.20230601.gappssmtp.com\n header.i=@baylibre-com.20230601.gappssmtp.com header.a=rsa-sha256\n header.s=20230601 header.b=DeEYcRpm;\n\tdkim-atps=neutral", "legolas.ozlabs.org;\n spf=pass (sender SPF authorized) smtp.mailfrom=gcc.gnu.org\n (client-ip=2620:52:6:3111::32; helo=vm01.sourceware.org;\n envelope-from=gcc-patches-bounces~incoming=patchwork.ozlabs.org@gcc.gnu.org;\n receiver=patchwork.ozlabs.org)", "sourceware.org;\n\tdkim=pass (2048-bit key,\n unprotected) header.d=baylibre-com.20230601.gappssmtp.com\n header.i=@baylibre-com.20230601.gappssmtp.com header.a=rsa-sha256\n header.s=20230601 header.b=DeEYcRpm", "sourceware.org;\n dmarc=none (p=none dis=none) header.from=baylibre.com", "sourceware.org; spf=pass smtp.mailfrom=baylibre.com", "server2.sourceware.org;\n arc=none smtp.remote-ip=209.85.215.169" ], "Received": [ "from vm01.sourceware.org (vm01.sourceware.org\n [IPv6:2620:52:6:3111::32])\n\t(using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)\n\t key-exchange x25519 server-signature ECDSA (secp384r1) server-digest SHA384)\n\t(No client certificate requested)\n\tby legolas.ozlabs.org (Postfix) with ESMTPS id 4fm8nK3fsqz1yFv\n\tfor <incoming@patchwork.ozlabs.org>; Thu, 02 Apr 2026 02:59:33 +1100 (AEDT)", "from vm01.sourceware.org (localhost [127.0.0.1])\n\tby sourceware.org (Postfix) with ESMTP id 708D04BA23E5\n\tfor <incoming@patchwork.ozlabs.org>; Wed, 1 Apr 2026 15:59:31 +0000 (GMT)", "from mail-pg1-f169.google.com (mail-pg1-f169.google.com\n [209.85.215.169])\n by sourceware.org (Postfix) with ESMTPS id 5FE8C4BA543C\n for <gcc-patches@gcc.gnu.org>; Wed, 1 Apr 2026 15:58:53 +0000 (GMT)", "by mail-pg1-f169.google.com with SMTP id\n 41be03b00d2f7-c6e2355739dso2986404a12.2\n for <gcc-patches@gcc.gnu.org>; Wed, 01 Apr 2026 08:58:53 -0700 (PDT)", "from [192.168.50.226] (112-104-14-82.adsl.dynamic.seed.net.tw.\n [112.104.14.82]) by smtp.gmail.com with ESMTPSA id\n 41be03b00d2f7-c76c657e5f3sm260943a12.23.2026.04.01.08.58.49\n (version=TLS1_3 cipher=TLS_AES_128_GCM_SHA256 bits=128/128);\n Wed, 01 Apr 2026 08:58:51 -0700 (PDT)" ], "DKIM-Filter": [ "OpenDKIM Filter v2.11.0 sourceware.org 708D04BA23E5", "OpenDKIM Filter v2.11.0 sourceware.org 5FE8C4BA543C" ], "DMARC-Filter": "OpenDMARC Filter v1.4.2 sourceware.org 5FE8C4BA543C", "ARC-Filter": "OpenARC Filter v1.0.0 sourceware.org 5FE8C4BA543C", "ARC-Seal": "i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1775059133; cv=none;\n b=whr2QcTiM0aMGoCwGyhrYdXrIu2/Zn0KpgaTG8KyJlrmMCFHncivjHC+4L3PVTIQJLGfzl5kOZcgi19OzvENUv/Qo4NoOn7Puf+Z02cVDIqNwbp+2AdXWVxD5+msUbzu9UGDFB+BYkav0VSpikl+jgsXgK/OVYm8BW/U0t1aUNc=", "ARC-Message-Signature": "i=1; a=rsa-sha256; d=sourceware.org; s=key;\n t=1775059133; c=relaxed/simple;\n bh=WX3xE+2T4il5mxeQPCTIxLRHncxW37pYdhrdLg+5uUk=;\n h=DKIM-Signature:Message-ID:Date:MIME-Version:Subject:From:To;\n b=drr/K2frOzBSwIBGIys4rL7VBXmOZehKOwlkehSDMFmfeGOomloJKnl/8EZmPZcGvJBJg8Yru4lbJUbTm5waScHReUkAEFk9+kqp6vANf+lf44pKzhngbFD8J8G9Dmln2QHpY+yCZvJg6Qbflhhvi+AtC+/0w30LUDOkd0pnrZQ=", "ARC-Authentication-Results": "i=1; server2.sourceware.org", "DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed;\n d=baylibre-com.20230601.gappssmtp.com; s=20230601; t=1775059132;\n x=1775663932;\n darn=gcc.gnu.org;\n h=in-reply-to:content-language:references:to:from:subject:user-agent\n :mime-version:date:message-id:from:to:cc:subject:date:message-id\n :reply-to; bh=eLDj8604EdE0u7iomkCtvSpbotZm9XbdvpErIlIAth8=;\n b=DeEYcRpmOOy3vZAMZl58OMXFsDSbT9nY9p+eV5cI9XZ3qtbg8IqQSCdWnngpN3W4sE\n rFdVfHCZvQ1uxY76I8DfPB0vliJzbsJlT0IfyqZ2o+4rZkO0G/1K2GCvaALQCpIdiPNM\n /CKANUoL3AZnQ/aXIFOCC/rA5sxYy9jNIzUQJSOIWrVct5H76AxnXZSCDTGp6rbckWN1\n IWvPve0kDoW3MG+ck5OvgLFCPBixAwKF3V/E+oP1u/NJg384oigR2CYPNxejDK+e86qk\n WDNbY4PtStLuLlxfvdWJSKbNulqP5zKBsOV5lwmOY1WQYkN5bRKXhJY0wD2LdHhcL6DQ\n cXIQ==", "X-Google-DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed;\n d=1e100.net; s=20251104; t=1775059132; x=1775663932;\n h=in-reply-to:content-language:references:to:from:subject:user-agent\n :mime-version:date:message-id:x-gm-gg:x-gm-message-state:from:to:cc\n :subject:date:message-id:reply-to;\n bh=eLDj8604EdE0u7iomkCtvSpbotZm9XbdvpErIlIAth8=;\n b=rFlgGoLWWIQuvn+Fr6rTW2BCLjL3ZwNpslrtEelr98yK+oEQDrjQRLvINTDG0NEgzC\n bxW5MvxfF2GMJ4xv3YIKe0KTfVBPxadTr4r2zeB0z1IjFeTRJkdvxs3fkXG1/I8/ePVO\n cKUXkOiHY7wRKaVFji+rl0/atzY+LY2DaJc4Ryr3XLOZNLFf/GeY2z9Dy2cG2myjOqQe\n O9EqUcCPP4KXzjUvwnVv01bgh7mm191H5+FS66mspa6BZPLUqrEwmG/Bavsa5KYg+nsc\n AQXDpwN+Bym60NaBD2/ZsGX8wolI2KXzfBoxXmQuU2vXrcv5a5rjU83UgP6nahLbekBl\n ne5Q==", "X-Gm-Message-State": "AOJu0Yx1fdmLvPBnRByKimvQep6EEaul5gAo3O63aRaCjBB8o7c7e6JG\n 0sF59ZrQohiWtqZpYgZW+hSKH77Wbyhbqp4pngezYtl2vwhQsHjbOnHhmOsse2z57LubCeW+AuA\n 2vZyLt1vwtA==", "X-Gm-Gg": "ATEYQzxUnxBIYHuCAWSkrLsyHZ0l9K8muv+EOoOe1//NG6eQgtHnshUPMPj/Z8fzJtj\n YIkcqIhQ9JzJ56BVgBn5Y9YU1kqaA7UU33jU+qtsbdKrFF0V6b2JSLX1CKFo4w0McdKSLTF5qvX\n S5AUqfyl3v/UbeC0kMCjhM2WkoTeM5qLyRjNATpGiwriwJZ8Uby48l+K35pQ9LooNeLgCkdX1Bf\n od3gFGmdwZFbPTBxywjToNqOnAISy6XdYqlXeg5R8AnSe0EjrRwWgtKhK9v+Yr2UOPexxBxu6l4\n 9syhecjRTjUTDolrjzR4Ty7Vz/6097miB2t+lfs4lkvbmdXIAiRrV1R6c5CO+j7ztIL9UEL7+TH\n FXapzADDHcH30ONts14xQlEUvCzR6yQkLzneM6zkokpXNR8LFMkwonw2FycqaJ+JidFO37idvTu\n TJexMSmDpZ3Rq9ci1NPhbHGtTwqmn+hdcRTQ5erLbqk5sDym+Paj8Vx2mmtRg3BPN1J/5AfYyLA\n 2Tidqn8eIzEMfBOkM0=", "X-Received": "by 2002:a05:6a20:918c:b0:39b:c3a0:9f31 with SMTP id\n adf61e73a8af0-39ef73d5cd2mr4648476637.21.1775059131774;\n Wed, 01 Apr 2026 08:58:51 -0700 (PDT)", "Content-Type": "multipart/mixed; boundary=\"------------o3FJ0omHD5WL8NlluOzlnVxX\"", "Message-ID": "<4596ca92-75bc-4085-982e-3305002265cf@baylibre.com>", "Date": "Wed, 1 Apr 2026 23:58:47 +0800", "MIME-Version": "1.0", "User-Agent": "Mozilla Thunderbird", "Subject": "[PATCH, OpenMP, v2] uses_allocators support", "From": "Chung-Lin Tang <cltang@baylibre.com>", "To": "gcc-patches <gcc-patches@gcc.gnu.org>,\n Tobias Burnus <tburnus@baylibre.com>, Andrew Stubbs <ams@baylibre.com>,\n Thomas Schwinge <tschwinge@baylibre.com>, Jakub Jelinek <jakub@redhat.com>", "References": "<0f1188cd-fa04-46f8-a56e-329635902c80@baylibre.com>", "Content-Language": "en-US", "In-Reply-To": "<0f1188cd-fa04-46f8-a56e-329635902c80@baylibre.com>", "X-BeenThere": "gcc-patches@gcc.gnu.org", "X-Mailman-Version": "2.1.30", "Precedence": "list", "List-Id": "Gcc-patches mailing list <gcc-patches.gcc.gnu.org>", "List-Unsubscribe": "<https://gcc.gnu.org/mailman/options/gcc-patches>,\n <mailto:gcc-patches-request@gcc.gnu.org?subject=unsubscribe>", "List-Archive": "<https://gcc.gnu.org/pipermail/gcc-patches/>", "List-Post": "<mailto:gcc-patches@gcc.gnu.org>", "List-Help": "<mailto:gcc-patches-request@gcc.gnu.org?subject=help>", "List-Subscribe": "<https://gcc.gnu.org/mailman/listinfo/gcc-patches>,\n <mailto:gcc-patches-request@gcc.gnu.org?subject=subscribe>", "Errors-To": "gcc-patches-bounces~incoming=patchwork.ozlabs.org@gcc.gnu.org" }, "content": "On 11/12/25 11:21 PM, Chung-Lin Tang wrote:\n> This is a new updated patch for OpenMP uses_allocators support.\n> The last one was submitted by Tobias:\n> https://gcc.gnu.org/pipermail/gcc-patches/2023-November/637415.html\n> \n> This new version is a combination of all our patches and fixes during this\n> period, now including:\n> \n> 1. C/C++ front-end parts re-written, to be more like established style.\n> \n> 2. The target teams issue has been solved by a host-side implementation:\n> omp_init_allocator() is called on host side, and mapped to target,\n> with the allocator passed in as a firstprivate variable.\n> Some adjustments where made to ensure that host/device side must have\n> same omp_allocator_data format.\n> \n> 3. Various other fixes, e.g. ntraits now using array_type_nelts, don't crash on VLAs,\n> omp_null_allocator, etc.\n\nAfter Tobias has committed the front-end parts, here are the middle-end parts.\n\nThe implementation has be revised to use a libgomp map kind (GOMP_MAP_USES_ALLOCATORS)\nto implement the call to omp_init_allocators.\n\nThis should resolve all the issues raised (hiding omp_allocator_data as opaque, nowait, etc.)\n\nThe sole libgomp uses_allocators-7.f90 test (which seemed to raise several issues) has\nbeen moved to a compiler test.\n\nThanks,\nChung-Lin", "diff": "diff --git a/gcc/c/c-typeck.cc b/gcc/c/c-typeck.cc\nindex 4452bb32728..4902a0fee98 100644\n--- a/gcc/c/c-typeck.cc\n+++ b/gcc/c/c-typeck.cc\n@@ -17396,7 +17396,7 @@ c_finish_omp_clauses (tree clauses, enum c_omp_region_type ort)\n \t else if (TREE_CODE (t) == CONST_DECL)\n \t {\n \t /* omp_null_allocator is ignored and for predefined allocators,\n-\t\t not special handling is required; thus, remove them removed. */\n+\t\t no special handling is required; thus, mark them removed. */\n \t remove = true;\n \n \t if (OMP_CLAUSE_USES_ALLOCATORS_MEMSPACE (c)\ndiff --git a/gcc/fortran/trans-array.cc b/gcc/fortran/trans-array.cc\nindex a2da4fe7c7d..477210f2a08 100644\n--- a/gcc/fortran/trans-array.cc\n+++ b/gcc/fortran/trans-array.cc\n@@ -7117,10 +7117,7 @@ gfc_conv_array_initializer (tree type, gfc_expr * expr)\n \t\t\t &expr->where, flag_max_array_constructor);\n \t return NULL_TREE;\n \t }\n- if (mpz_cmp_si (c->offset, 0) != 0)\n- index = gfc_conv_mpz_to_tree (c->offset, gfc_index_integer_kind);\n- else\n- index = NULL_TREE;\n+\t index = gfc_conv_mpz_to_tree (c->offset, gfc_index_integer_kind);\n \n \t if (mpz_cmp_si (c->repeat, 1) > 0)\n \t {\n@@ -7191,7 +7188,7 @@ gfc_conv_array_initializer (tree type, gfc_expr * expr)\n \t CONSTRUCTOR_APPEND_ELT (v, index, se.expr);\n \t else\n \t {\n-\t if (index != NULL_TREE)\n+\t if (!integer_zerop (index))\n \t\tCONSTRUCTOR_APPEND_ELT (v, index, se.expr);\n \t CONSTRUCTOR_APPEND_ELT (v, range, se.expr);\n \t }\ndiff --git a/gcc/fortran/trans-openmp.cc b/gcc/fortran/trans-openmp.cc\nindex 230395f9d2c..4d819bbe94e 100644\n--- a/gcc/fortran/trans-openmp.cc\n+++ b/gcc/fortran/trans-openmp.cc\n@@ -3943,7 +3943,12 @@ gfc_trans_omp_clauses (stmtblock_t *block, gfc_omp_clauses *clauses,\n \t\t\t gfc_init_se (&se, NULL);\n \t\t\t gfc_conv_expr (&se, n->u2.allocator);\n \t\t\t gfc_add_block_to_block (block, &se.pre);\n-\t\t\t allocator_ = gfc_evaluate_now (se.expr, block);\n+\t\t\t t = se.expr;\n+\t\t\t if (DECL_P (t) && se.post.head == NULL_TREE)\n+\t\t\t\tallocator_ = (POINTER_TYPE_P (TREE_TYPE (t))\n+\t\t\t\t\t ? build_fold_indirect_ref (t): t);\n+\t\t\t else\n+\t\t\t\tallocator_ = gfc_evaluate_now (t, block);\n \t\t\t gfc_add_block_to_block (block, &se.post);\n \t\t\t }\n \t\t\t OMP_CLAUSE_ALLOCATE_ALLOCATOR (node) = allocator_;\n@@ -5225,14 +5230,36 @@ gfc_trans_omp_clauses (stmtblock_t *block, gfc_omp_clauses *clauses,\n \t }\n \t break;\n \tcase OMP_LIST_USES_ALLOCATORS:\n-\t /* Ignore omp_null_allocator and pre-defined allocators as no\n-\t special treatment is needed. */\n \t for (; n != NULL; n = n->next)\n-\t if (n->sym->attr.flavor == FL_VARIABLE)\n-\t break;\n-\t if (n != NULL)\n-\t sorry_at (input_location, \"%<uses_allocators%> clause with traits \"\n-\t\t\t\t \"and memory spaces\");\n+\t {\n+\t if (!n->sym->attr.referenced)\n+\t\tcontinue;\n+\t tree node = build_omp_clause (input_location,\n+\t\t\t\t\t OMP_CLAUSE_USES_ALLOCATORS);\n+\t tree t;\n+\t if (n->sym->attr.flavor == FL_VARIABLE)\n+\t\tt = gfc_get_symbol_decl (n->sym);\n+\t else\n+\t\t{\n+\t\t t = gfc_conv_mpz_to_tree (n->sym->value->value.integer,\n+\t\t\t\t\t n->sym->ts.kind);\n+\t\t t = fold_convert (ptr_type_node, t);\n+\t\t}\n+\t OMP_CLAUSE_USES_ALLOCATORS_ALLOCATOR(node) = t;\n+\t if (n->u.memspace_sym)\n+\t\t{\n+\t\t n->u.memspace_sym->attr.referenced = true;\n+\t\t OMP_CLAUSE_USES_ALLOCATORS_MEMSPACE (node)\n+\t\t = gfc_get_symbol_decl (n->u.memspace_sym);\n+\t\t}\n+\t if (n->u2.traits_sym)\n+\t\t{\n+\t\t n->u2.traits_sym->attr.referenced = true;\n+\t\t OMP_CLAUSE_USES_ALLOCATORS_TRAITS (node)\n+\t\t = gfc_get_symbol_decl (n->u2.traits_sym);\n+\t\t}\n+\t omp_clauses = gfc_trans_add_clause (node, omp_clauses);\n+\t }\n \t break;\n \tdefault:\n \t break;\ndiff --git a/gcc/gimplify.cc b/gcc/gimplify.cc\nindex 8bfc71315f9..585032d0960 100644\n--- a/gcc/gimplify.cc\n+++ b/gcc/gimplify.cc\n@@ -184,6 +184,9 @@ enum gimplify_omp_var_data\n /* Flag for GOVD_FIRSTPRIVATE: OMP_CLAUSE_FIRSTPRIVATE_IMPLICIT. */\n GOVD_FIRSTPRIVATE_IMPLICIT = 0x4000000,\n \n+ /* Flag to indicate this an allocator for the uses_allocators clause. */\n+ GOVD_USES_ALLOCATORS_ALLOCATOR = 0x8000000,\n+\n GOVD_DATA_SHARE_CLASS = (GOVD_SHARED | GOVD_PRIVATE | GOVD_FIRSTPRIVATE\n \t\t\t | GOVD_LASTPRIVATE | GOVD_REDUCTION | GOVD_LINEAR\n \t\t\t | GOVD_LOCAL)\n@@ -1450,18 +1453,46 @@ gimplify_bind_expr (tree *expr_p, gimple_seq *pre_p)\n \t\t dynamic_allocators clause is present in the same compilation\n \t\t unit. */\n \t bool missing_dyn_alloc = false;\n-\t if (alloc == NULL_TREE\n-\t\t && ((omp_requires_mask & OMP_REQUIRES_DYNAMIC_ALLOCATORS)\n-\t\t == 0))\n+\t if ((omp_requires_mask & OMP_REQUIRES_DYNAMIC_ALLOCATORS) == 0)\n \t\t{\n \t\t /* This comes too early for omp_discover_declare_target...,\n \t\t but should at least catch the most common cases. */\n \t\t missing_dyn_alloc\n-\t\t = cgraph_node::get (current_function_decl)->offloadable;\n+\t\t = (alloc == NULL_TREE\n+\t\t && cgraph_node::get (current_function_decl)->offloadable);\n \t\t for (struct gimplify_omp_ctx *ctx2 = ctx;\n \t\t ctx2 && !missing_dyn_alloc; ctx2 = ctx2->outer_context)\n \t\t if (ctx2->code == OMP_TARGET)\n-\t\t missing_dyn_alloc = true;\n+\t\t {\n+\t\t\tif (alloc == NULL_TREE)\n+\t\t\t missing_dyn_alloc = true;\n+\t\t\telse if (TREE_CODE (alloc) != INTEGER_CST)\n+\t\t\t {\n+\t\t\t tree alloc2 = alloc;\n+\t\t\t if (TREE_CODE (alloc2) == MEM_REF\n+\t\t\t\t|| TREE_CODE (alloc2) == INDIRECT_REF)\n+\t\t\t alloc2 = TREE_OPERAND (alloc2, 0);\n+\t\t\t tree c2;\n+\t\t\t for (c2 = ctx2->clauses; c2;\n+\t\t\t\t c2 = OMP_CLAUSE_CHAIN (c2))\n+\t\t\t if (OMP_CLAUSE_CODE (c2)\n+\t\t\t\t == OMP_CLAUSE_USES_ALLOCATORS)\n+\t\t\t\t{\n+\t\t\t\t tree t2\n+\t\t\t\t = OMP_CLAUSE_USES_ALLOCATORS_ALLOCATOR (c2);\n+\t\t\t\t if (operand_equal_p (alloc2, t2))\n+\t\t\t\t break;\n+\t\t\t\t}\n+\t\t\t if (c2 == NULL_TREE)\n+\t\t\t error_at (EXPR_LOC_OR_LOC (\n+\t\t\t\t\t alloc, DECL_SOURCE_LOCATION (t)),\n+\t\t\t\t\t\"%qE in %<allocator%> clause inside a \"\n+\t\t\t\t\t\"target region must be specified in an \"\n+\t\t\t\t\t\"%<uses_allocators%> clause on the \"\n+\t\t\t\t\t\"%<target%> directive\", alloc2);\n+\t\t\t }\n+\t\t\tbreak;\n+\t\t }\n \t\t}\n \t if (missing_dyn_alloc)\n \t\terror_at (DECL_SOURCE_LOCATION (t),\n@@ -10982,6 +11013,7 @@ omp_get_attachment (omp_mapping_group *grp)\n \t case GOMP_MAP_FIRSTPRIVATE_POINTER:\n \t case GOMP_MAP_FIRSTPRIVATE_REFERENCE:\n \t case GOMP_MAP_POINTER_TO_ZERO_LENGTH_ARRAY_SECTION:\n+\t case GOMP_MAP_USES_ALLOCATORS:\n \t return NULL_TREE;\n \n \t case GOMP_MAP_ATTACH_DETACH:\n@@ -11026,6 +11058,7 @@ omp_get_attachment (omp_mapping_group *grp)\n case GOMP_MAP_FIRSTPRIVATE_INT:\n case GOMP_MAP_USE_DEVICE_PTR:\n case GOMP_MAP_ATTACH_ZERO_LENGTH_ARRAY_SECTION:\n+ case GOMP_MAP_USES_ALLOCATORS:\n return NULL_TREE;\n \n default:\n@@ -11314,6 +11347,7 @@ omp_group_base (omp_mapping_group *grp, unsigned int *chained,\n case GOMP_MAP_FIRSTPRIVATE_INT:\n case GOMP_MAP_USE_DEVICE_PTR:\n case GOMP_MAP_ATTACH_ZERO_LENGTH_ARRAY_SECTION:\n+ case GOMP_MAP_USES_ALLOCATORS:\n return NULL_TREE;\n \n case GOMP_MAP_FIRSTPRIVATE_POINTER:\n@@ -14931,8 +14965,15 @@ gimplify_scan_omp_clauses (tree *list_p, gimple_seq *pre_p,\n \t break;\n \n \tcase OMP_CLAUSE_USES_ALLOCATORS:\n-\t sorry_at (OMP_CLAUSE_LOCATION (c), \"%<uses_allocators%> clause\");\n-\t remove = 1;\n+\t if (TREE_CODE (OMP_CLAUSE_USES_ALLOCATORS_ALLOCATOR (c))\n+\t != INTEGER_CST)\n+\t {\n+\t decl = OMP_CLAUSE_USES_ALLOCATORS_ALLOCATOR (c);\n+\t omp_add_variable (ctx, decl,\n+\t\t\t\tGOVD_SEEN | GOVD_USES_ALLOCATORS_ALLOCATOR);\n+\t }\n+\t else\n+\t remove = true;\n \t break;\n \n \tcase OMP_CLAUSE_ORDERED:\n@@ -15091,6 +15132,49 @@ gimplify_scan_omp_clauses (tree *list_p, gimple_seq *pre_p,\n \t remove = true;\n \t break;\n \t }\n+\t if ((omp_requires_mask & OMP_REQUIRES_DYNAMIC_ALLOCATORS) == 0\n+\t && OMP_CLAUSE_ALLOCATE_ALLOCATOR (c)\n+\t && TREE_CODE (OMP_CLAUSE_ALLOCATE_ALLOCATOR (c)) != INTEGER_CST)\n+\t {\n+\t tree allocator = OMP_CLAUSE_ALLOCATE_ALLOCATOR (c);\n+\t tree clauses = NULL_TREE;\n+\n+\t /* Get clause list of the nearest enclosing target construct. */\n+\t if (ctx->code == OMP_TARGET)\n+\t\tclauses = *orig_list_p;\n+\t else\n+\t\t{\n+\t\t struct gimplify_omp_ctx *tctx = ctx->outer_context;\n+\t\t while (tctx && tctx->code != OMP_TARGET)\n+\t\t tctx = tctx->outer_context;\n+\t\t if (tctx)\n+\t\t clauses = tctx->clauses;\n+\t\t}\n+\n+\t if (clauses)\n+\t\t{\n+\t\t tree uc;\n+\t\t if (TREE_CODE (allocator) == MEM_REF\n+\t\t || TREE_CODE (allocator) == INDIRECT_REF)\n+\t\t allocator = TREE_OPERAND (allocator, 0);\n+\t\t for (uc = clauses; uc; uc = OMP_CLAUSE_CHAIN (uc))\n+\t\t if (OMP_CLAUSE_CODE (uc) == OMP_CLAUSE_USES_ALLOCATORS)\n+\t\t {\n+\t\t\ttree uc_allocator\n+\t\t\t = OMP_CLAUSE_USES_ALLOCATORS_ALLOCATOR (uc);\n+\t\t\tif (operand_equal_p (allocator, uc_allocator))\n+\t\t\t break;\n+\t\t }\n+\t\t if (uc == NULL_TREE)\n+\t\t {\n+\t\t error_at (OMP_CLAUSE_LOCATION (c), \"allocator %qE \"\n+\t\t\t\t\"requires %<uses_allocators(%E)%> clause in \"\n+\t\t\t\t\"target region\", allocator, allocator);\n+\t\t remove = true;\n+\t\t break;\n+\t\t }\n+\t\t}\n+\t }\n \t if (gimplify_expr (&OMP_CLAUSE_ALLOCATE_ALLOCATOR (c), pre_p, NULL,\n \t\t\t is_gimple_val, fb_rvalue) == GS_ERROR)\n \t {\n@@ -15409,6 +15493,8 @@ gimplify_adjust_omp_clauses_1 (splay_tree_node n, void *data)\n code = OMP_CLAUSE__CONDTEMP_;\n gimple_add_tmp_var (decl);\n }\n+ else if (flags & GOVD_USES_ALLOCATORS_ALLOCATOR)\n+ return 0;\n else\n gcc_unreachable ();\n \ndiff --git a/gcc/omp-low.cc b/gcc/omp-low.cc\nindex b93012107f1..990c46ecfff 100644\n--- a/gcc/omp-low.cc\n+++ b/gcc/omp-low.cc\n@@ -1177,6 +1177,36 @@ scan_sharing_clauses (tree clauses, omp_context *ctx)\n \t && omp_maybe_offloaded_ctx (ctx))\n \t error_at (OMP_CLAUSE_LOCATION (c), \"%<allocate%> clause must\"\n \t\t \" specify an allocator here\");\n+\tif ((omp_requires_mask & OMP_REQUIRES_DYNAMIC_ALLOCATORS) == 0\n+\t && OMP_CLAUSE_ALLOCATE_ALLOCATOR (c) != NULL_TREE\n+\t && DECL_P (OMP_CLAUSE_ALLOCATE_ALLOCATOR (c))\n+\t && !DECL_ARTIFICIAL (OMP_CLAUSE_ALLOCATE_ALLOCATOR (c)))\n+\t {\n+\t tree alloc2 = OMP_CLAUSE_ALLOCATE_ALLOCATOR (c);\n+\t if (TREE_CODE (alloc2) == MEM_REF\n+\t\t|| TREE_CODE (alloc2) == INDIRECT_REF)\n+\t alloc2 = TREE_OPERAND (alloc2, 0);\n+\t omp_context *ctx2 = ctx;\n+\t for (; ctx2; ctx2 = ctx2->outer)\n+\t if (is_gimple_omp_offloaded (ctx2->stmt))\n+\t\tbreak;\n+\t if (ctx2 != NULL)\n+\t {\n+\t\ttree c2 = gimple_omp_target_clauses (ctx2->stmt);\n+\t\tfor (; c2; c2 = OMP_CLAUSE_CHAIN (c2))\n+\t\t if (OMP_CLAUSE_CODE (c2) == OMP_CLAUSE_USES_ALLOCATORS\n+\t\t && operand_equal_p (\n+\t\t\t alloc2, OMP_CLAUSE_USES_ALLOCATORS_ALLOCATOR (c2)))\n+\t\t break;\n+\t\tif (c2 == NULL_TREE)\n+\t\t error_at (EXPR_LOC_OR_LOC (OMP_CLAUSE_ALLOCATE_ALLOCATOR (c),\n+\t\t\t\t\t OMP_CLAUSE_LOCATION (c)),\n+\t\t\t \"allocator %qE in %<allocate%> clause inside a \"\n+\t\t\t \"target region must be specified in an \"\n+\t\t\t \"%<uses_allocators%> clause on the %<target%> \"\n+\t\t\t \"directive\", alloc2);\n+\t }\n+\t }\n \tif (ctx->allocate_map == NULL)\n \t ctx->allocate_map = new hash_map<tree, tree>;\n \ttree val = integer_zero_node;\n@@ -1775,6 +1805,14 @@ scan_sharing_clauses (tree clauses, omp_context *ctx)\n \tcase OMP_CLAUSE_DEVICE_TYPE:\n \t break;\n \n+\tcase OMP_CLAUSE_USES_ALLOCATORS:\n+\t decl = OMP_CLAUSE_USES_ALLOCATORS_ALLOCATOR (c);\n+\t gcc_assert (DECL_P (decl));\n+\t gcc_assert (is_gimple_omp_offloaded (ctx->stmt));\n+\t install_var_field (decl, false, 3, ctx);\n+\t install_var_local (decl, ctx);\n+\t break;\n+\n \tcase OMP_CLAUSE_ALIGNED:\n \t decl = OMP_CLAUSE_DECL (c);\n \t if (is_global_var (decl)\n@@ -2000,6 +2038,7 @@ scan_sharing_clauses (tree clauses, omp_context *ctx)\n \tcase OMP_CLAUSE_USE:\n \tcase OMP_CLAUSE_DESTROY:\n \tcase OMP_CLAUSE_DEVICE_TYPE:\n+\tcase OMP_CLAUSE_USES_ALLOCATORS:\n \t break;\n \n \tcase OMP_CLAUSE__CACHE_:\n@@ -13173,6 +13212,14 @@ lower_omp_target (gimple_stmt_iterator *gsi_p, omp_context *ctx)\n \t sorry_at (OMP_CLAUSE_LOCATION (c),\n \t\t \"only the %<device_type(any)%> is supported\");\n \t break;\n+ case OMP_CLAUSE_USES_ALLOCATORS:\n+\tallocator = OMP_CLAUSE_USES_ALLOCATORS_ALLOCATOR (c);\n+\ttree new_allocator = lookup_decl (allocator, ctx);\n+\tx = build_receiver_ref (allocator, false, ctx);\n+\tSET_DECL_VALUE_EXPR (new_allocator, x);\n+\tDECL_HAS_VALUE_EXPR_P (new_allocator) = 1;\n+\tmap_cnt++;\n+\tbreak;\n }\n \n if (offloaded)\n@@ -13905,6 +13952,80 @@ lower_omp_target (gimple_stmt_iterator *gsi_p, omp_context *ctx)\n \t CONSTRUCTOR_APPEND_ELT (vkind, purpose,\n \t\t\t\t build_int_cstu (tkind_type, tkind));\n \t break;\n+\n+\t case OMP_CLAUSE_USES_ALLOCATORS:\n+\t tree allocator = OMP_CLAUSE_USES_ALLOCATORS_ALLOCATOR (c);\n+\t tree memspace = OMP_CLAUSE_USES_ALLOCATORS_MEMSPACE (c);\n+\t tree traits = OMP_CLAUSE_USES_ALLOCATORS_TRAITS (c);\n+\n+\t tree ntraits, traits_var;\n+\t if (traits == NULL_TREE)\n+\t {\n+\t\tntraits = integer_zero_node;\n+\t\ttraits_var = null_pointer_node;\n+\t }\n+\t else if (DECL_INITIAL (traits))\n+\t {\n+\t\tlocation_t loc = OMP_CLAUSE_LOCATION (c);\n+\t\tntraits = array_type_nelts_top (TREE_TYPE (traits));\n+\t\ttree t = DECL_INITIAL (traits);\n+\t\tt = get_initialized_tmp_var (t, &ilist, NULL);\n+\t\ttraits_var = build_fold_addr_expr_loc (loc, t);\n+\t }\n+\t else\n+\t {\n+\t\t/* This happens for VLAs, which probably aren't useful\n+\t\t because they can't be const initialized in the same\n+\t\t scope.... is there something else? */\n+\t\tlocation_t loc = OMP_CLAUSE_LOCATION (c);\n+\t\tgcc_assert (TREE_CODE (TREE_TYPE (traits)) == ARRAY_TYPE);\n+\t\tntraits = array_type_nelts_top (TREE_TYPE (traits));\n+\t\ttraits_var = build_fold_addr_expr_loc (loc, traits);\n+\t }\n+\n+\t if (memspace == NULL_TREE)\n+\t memspace = build_int_cst (pointer_sized_int_node, 0);\n+\t else\n+\t memspace = fold_convert (pointer_sized_int_node, memspace);\n+\n+\t tree arr_type\n+\t = build_array_type_nelts (pointer_sized_int_node, 3);\n+\t tree uses_allocators_descr\n+\t = create_tmp_var (arr_type, \"uses_allocator_descr\");\n+\t tree ua_descr[3];\n+\t for (int i = 0; i < 3; i++)\n+\t ua_descr[i] = build4 (ARRAY_REF, pointer_sized_int_node,\n+\t\t\t\t uses_allocators_descr,\n+\t\t\t\t build_int_cst (size_type_node, i),\n+\t\t\t\t NULL_TREE, NULL_TREE);\n+\t gimplify_assign (ua_descr[0],\n+\t\t\t fold_convert (pointer_sized_int_node, memspace),\n+\t\t\t &ilist);\n+\t gimplify_assign (ua_descr[1],\n+\t\t\t fold_convert (pointer_sized_int_node, ntraits),\n+\t\t\t &ilist);\n+\t gimplify_assign (ua_descr[2],\n+\t\t\t fold_convert (pointer_sized_int_node, traits_var),\n+\t\t\t &ilist);\n+\n+\t x = build_sender_ref (allocator, ctx);\n+\t tree ptr = build_fold_addr_expr (uses_allocators_descr);\n+\t gimplify_assign (x, fold_convert (TREE_TYPE (x), ptr), &ilist);\n+\n+\t s = size_int (0);\n+\t purpose = size_int (map_idx++);\n+\t CONSTRUCTOR_APPEND_ELT (vsize, purpose, s);\n+\t tkind = GOMP_MAP_USES_ALLOCATORS;\n+\t gcc_checking_assert (tkind\n+\t\t\t\t < (HOST_WIDE_INT_C (1U) << talign_shift));\n+\t talign = TYPE_ALIGN_UNIT (pointer_sized_int_node);\n+\t talign = ceil_log2 (talign);\n+\t tkind |= talign << talign_shift;\n+\t gcc_checking_assert (tkind\n+\t\t\t\t <= tree_to_uhwi (TYPE_MAX_VALUE (tkind_type)));\n+\t CONSTRUCTOR_APPEND_ELT (vkind, purpose,\n+\t\t\t\t build_int_cstu (tkind_type, tkind));\n+\t break;\n \t }\n \n gcc_assert (map_idx == map_cnt);\ndiff --git a/gcc/testsuite/c-c++-common/gomp/uses_allocators-1.c b/gcc/testsuite/c-c++-common/gomp/uses_allocators-1.c\nindex df82cbbcba9..ec2f56e21d0 100644\n--- a/gcc/testsuite/c-c++-common/gomp/uses_allocators-1.c\n+++ b/gcc/testsuite/c-c++-common/gomp/uses_allocators-1.c\n@@ -1,3 +1,4 @@\n+/*\n typedef enum omp_allocator_handle_t\n #if __cplusplus >= 201103L\n : __UINTPTR_TYPE__\n@@ -15,17 +16,19 @@ typedef struct omp_alloctrait_t\n } omp_alloctrait_t;\n \n extern void *omp_alloc (__SIZE_TYPE__, omp_allocator_handle_t);\n+*/\n+#include <omp.h>\n \n void\n f (omp_allocator_handle_t my_alloc)\n {\n #pragma omp target\n {\n- int a; /* { dg-error \"'my_alloc' in 'allocator' clause inside a target region must be specified in an 'uses_allocators' clause on the 'target' directive\" \"not yet implemented\" { xfail *-*-* } } */\n+ int a; /* { dg-error \"'my_alloc' in 'allocator' clause inside a target region must be specified in an 'uses_allocators' clause on the 'target' directive\" \"\" { target c } } */\n #pragma omp allocate(a) allocator(my_alloc) /* { dg-message \"sorry, unimplemented: '#pragma omp allocate' not yet supported\" \"\" { target c++ } } */\n a = 5;\n void *prt = omp_alloc(32, my_alloc);\n- #pragma omp parallel allocate(allocator(my_alloc) : a) firstprivate(a) /* { dg-error \"allocator 'my_alloc' in 'allocate' clause inside a target region must be specified in an 'uses_allocators' clause on the 'target' directive\" \"not yet implemented\" { xfail *-*-* } } */\n+ #pragma omp parallel allocate(allocator(my_alloc) : a) firstprivate(a) /* { dg-error \"allocator 'my_alloc' in 'allocate' clause inside a target region must be specified in an 'uses_allocators' clause on the 'target' directive\" } */\n a = 7;\n }\n }\n@@ -44,5 +47,3 @@ g (omp_allocator_handle_t my_alloc)\n a = 7;\n }\n }\n-\n-// { dg-message \"sorry, unimplemented: 'uses_allocators' clause\" \"\" { target *-*-* } 37 }\ndiff --git a/gcc/testsuite/c-c++-common/gomp/uses_allocators-2.c b/gcc/testsuite/c-c++-common/gomp/uses_allocators-2.c\nindex c766ea3559d..4dd1f13100a 100644\n--- a/gcc/testsuite/c-c++-common/gomp/uses_allocators-2.c\n+++ b/gcc/testsuite/c-c++-common/gomp/uses_allocators-2.c\n@@ -31,5 +31,3 @@ g ()\n #pragma omp target uses_allocators(traits(trait) : my_alloc)\n ;\n }\n-\n-// { dg-message \"sorry, unimplemented: 'uses_allocators' clause\" \"\" { target *-*-* } 31 }\ndiff --git a/gcc/testsuite/c-c++-common/gomp/uses_allocators-3.c b/gcc/testsuite/c-c++-common/gomp/uses_allocators-3.c\nnew file mode 100644\nindex 00000000000..1e4699d99c2\n--- /dev/null\n+++ b/gcc/testsuite/c-c++-common/gomp/uses_allocators-3.c\n@@ -0,0 +1,53 @@\n+/* { dg-do compile } */\n+/* { dg-additional-options \"-fdump-tree-original -fdump-tree-gimple\" } */\n+\n+#include <omp.h>\n+\n+omp_alloctrait_key_t k;\n+omp_alloctrait_value_t v;\n+\n+int n = 2;\n+\n+int main (void)\n+{\n+ omp_allocator_handle_t foo, bar;\n+ const omp_alloctrait_t foo_traits[] = { { omp_atk_pinned, omp_atv_true },\n+ \t\t\t\t\t { omp_atk_partition, omp_atv_nearest } };\n+\n+ #pragma omp target\n+ ;\n+ #pragma omp target uses_allocators (bar)\n+ ;\n+ #pragma omp target uses_allocators (foo (foo_traits)) /* { dg-warning \"the specification of arguments to 'uses_allocators' where each item is of the form 'allocator\\\\(traits\\\\)' is deprecated since OpenMP 5.2 \\\\\\[-Wdeprecated-openmp\\\\\\]\" } */\n+ ;\n+ #pragma omp target uses_allocators (foo (foo_traits), bar (foo_traits)) /* { dg-warning \"the specification of arguments to 'uses_allocators' where each item is of the form 'allocator\\\\(traits\\\\)' is deprecated since OpenMP 5.2 \\\\\\[-Wdeprecated-openmp\\\\\\]\" } */\n+ ;\n+ #pragma omp target uses_allocators (memspace(omp_high_bw_mem_space) : foo)\n+ ;\n+ #pragma omp target uses_allocators (traits(foo_traits) : bar)\n+ ;\n+ #pragma omp target parallel uses_allocators (memspace(omp_high_bw_mem_space), traits(foo_traits) : bar)\n+ ;\n+ #pragma omp target parallel uses_allocators (traits(foo_traits), memspace(omp_high_bw_mem_space) : bar) uses_allocators(foo)\n+ {\n+ void *p = omp_alloc ((unsigned long) 32, bar);\n+ omp_free (p, bar);\n+ }\n+ return 0;\n+}\n+\n+/* { dg-final { scan-tree-dump \"pragma omp target uses_allocators\\\\(memspace\\\\(\\\\), traits\\\\(\\\\) : bar\\\\)\" \"original\" } } */\n+/* { dg-final { scan-tree-dump \"pragma omp target uses_allocators\\\\(memspace\\\\(\\\\), traits\\\\(foo_traits\\\\) : foo\\\\)\" \"original\" } } */\n+/* { dg-final { scan-tree-dump \"pragma omp target uses_allocators\\\\(memspace\\\\(\\\\), traits\\\\(foo_traits\\\\) : bar\\\\) uses_allocators\\\\(memspace\\\\(\\\\), traits\\\\(foo_traits\\\\) : foo\\\\)\" \"original\" } } */\n+/* { dg-final { scan-tree-dump \"pragma omp target uses_allocators\\\\(memspace\\\\(.+\\\\), traits\\\\(\\\\) : foo\\\\)\" \"original\" } } */\n+/* { dg-final { scan-tree-dump \"pragma omp target uses_allocators\\\\(memspace\\\\(\\\\), traits\\\\(foo_traits\\\\) : bar\\\\)\" \"original\" } } */\n+/* { dg-final { scan-tree-dump \"pragma omp target uses_allocators\\\\(memspace\\\\(.+\\\\), traits\\\\(foo_traits\\\\) : bar\\\\)\" \"original\" } } */\n+/* { dg-final { scan-tree-dump \"pragma omp target uses_allocators\\\\(memspace\\\\(.+\\\\), traits\\\\(foo_traits\\\\) : bar\\\\) uses_allocators\\\\(memspace\\\\(\\\\), traits\\\\(\\\\) : foo\\\\)\" \"original\" } } */\n+\n+/* { dg-final { scan-tree-dump \"pragma omp target num_teams\\\\(-2\\\\) thread_limit\\\\(0\\\\) uses_allocators\\\\(memspace\\\\(\\\\), traits\\\\(\\\\) : bar\\\\)\" \"gimple\" } } */\n+/* { dg-final { scan-tree-dump \"pragma omp target num_teams\\\\(-2\\\\) thread_limit\\\\(0\\\\) uses_allocators\\\\(memspace\\\\(\\\\), traits\\\\(foo_traits\\\\) : foo\\\\)\" \"gimple\" } } */\n+/* { dg-final { scan-tree-dump \"pragma omp target num_teams\\\\(-2\\\\) thread_limit\\\\(0\\\\) uses_allocators\\\\(memspace\\\\(\\\\), traits\\\\(foo_traits\\\\) : bar\\\\) uses_allocators\\\\(memspace\\\\(\\\\), traits\\\\(foo_traits\\\\) : foo\\\\)\" \"gimple\" } } */\n+/* { dg-final { scan-tree-dump \"pragma omp target num_teams\\\\(-2\\\\) thread_limit\\\\(0\\\\) uses_allocators\\\\(memspace\\\\(.+\\\\), traits\\\\(\\\\) : foo\\\\)\" \"gimple\" } } */\n+/* { dg-final { scan-tree-dump \"pragma omp target num_teams\\\\(-2\\\\) thread_limit\\\\(0\\\\) uses_allocators\\\\(memspace\\\\(\\\\), traits\\\\(foo_traits\\\\) : bar\\\\)\" \"gimple\" } } */\n+/* { dg-final { scan-tree-dump \"pragma omp target num_teams\\\\(-2\\\\) thread_limit\\\\(0\\\\) uses_allocators\\\\(memspace\\\\(.+\\\\), traits\\\\(foo_traits\\\\) : bar\\\\)\" \"gimple\" } } */\n+/* { dg-final { scan-tree-dump \"pragma omp target num_teams\\\\(-2\\\\) thread_limit\\\\(0\\\\) uses_allocators\\\\(memspace\\\\(.+\\\\), traits\\\\(foo_traits\\\\) : bar\\\\) uses_allocators\\\\(memspace\\\\(\\\\), traits\\\\(\\\\) : foo\\\\)\" \"gimple\" } } */\ndiff --git a/gcc/testsuite/c-c++-common/gomp/uses_allocators-4.c b/gcc/testsuite/c-c++-common/gomp/uses_allocators-4.c\nindex 5f3650157fc..a27e7208473 100644\n--- a/gcc/testsuite/c-c++-common/gomp/uses_allocators-4.c\n+++ b/gcc/testsuite/c-c++-common/gomp/uses_allocators-4.c\n@@ -135,10 +135,3 @@ int f (const omp_alloctrait_t arg_traits[], int n)\n /* { dg-error \"legacy 'foo\\\\\\(foo_traits\\\\\\)' traits syntax not allowed in 'uses_allocators' clause when using modifiers\" \"\" { target *-*-* } .-2 } */\n return 0;\n }\n-\n-// { dg-message \"sorry, unimplemented: 'uses_allocators' clause\" \"\" { target *-*-* } 103 }\n-// { dg-message \"sorry, unimplemented: 'uses_allocators' clause\" \"\" { target c } 111 }\n-// { dg-message \"sorry, unimplemented: 'uses_allocators' clause\" \"\" { target c } 113 }\n-// { dg-message \"sorry, unimplemented: 'uses_allocators' clause\" \"\" { target c } 117 }\n-// { dg-message \"sorry, unimplemented: 'uses_allocators' clause\" \"\" { target c } 119 }\n-// { dg-message \"sorry, unimplemented: 'uses_allocators' clause\" \"\" { target *-*-* } 131 }\ndiff --git a/gcc/testsuite/c-c++-common/gomp/uses_allocators-5.c b/gcc/testsuite/c-c++-common/gomp/uses_allocators-5.c\nnew file mode 100644\nindex 00000000000..eeac5f097cb\n--- /dev/null\n+++ b/gcc/testsuite/c-c++-common/gomp/uses_allocators-5.c\n@@ -0,0 +1,34 @@\n+/* { dg-do compile } */\n+/* { dg-additional-options \"-fdump-tree-original -fdump-tree-gimple\" } */\n+\n+#include <omp.h>\n+\n+int main (void)\n+{\n+ omp_allocator_handle_t memspace, traits;\n+ const omp_alloctrait_t mytraits[] = { { omp_atk_pinned, omp_atv_true },\n+\t\t\t\t\t{ omp_atk_partition, omp_atv_nearest } };\n+ #pragma omp target uses_allocators (memspace)\n+ ;\n+ #pragma omp target uses_allocators (traits)\n+ ;\n+ #pragma omp target uses_allocators (traits, memspace)\n+ ;\n+ #pragma omp target uses_allocators (traits (mytraits)) /* { dg-warning \"the specification of arguments to 'uses_allocators' where each item is of the form 'allocator\\\\(traits\\\\)' is deprecated since OpenMP 5.2\" } */\n+ ;\n+ #pragma omp target uses_allocators (memspace (mytraits), omp_default_mem_alloc) /* { dg-warning \"the specification of arguments to 'uses_allocators' where each item is of the form 'allocator\\\\(traits\\\\)' is deprecated since OpenMP 5.2\" } */\n+ ;\n+ return 0;\n+}\n+\n+/* { dg-final { scan-tree-dump \"pragma omp target uses_allocators\\\\(memspace\\\\(\\\\), traits\\\\(\\\\) : memspace\\\\)\" \"original\" } } */\n+/* { dg-final { scan-tree-dump \"pragma omp target uses_allocators\\\\(memspace\\\\(\\\\), traits\\\\(\\\\) : traits\\\\)\" \"original\" } } */\n+/* { dg-final { scan-tree-dump \"pragma omp target uses_allocators\\\\(memspace\\\\(\\\\), traits\\\\(\\\\) : memspace\\\\) uses_allocators\\\\(memspace\\\\(\\\\), traits\\\\(\\\\) : traits\\\\)\" \"original\" } } */\n+/* { dg-final { scan-tree-dump \"pragma omp target uses_allocators\\\\(memspace\\\\(\\\\), traits\\\\(mytraits\\\\) : traits\\\\)\" \"original\" } } */\n+/* { dg-final { scan-tree-dump \"pragma omp target uses_allocators\\\\(memspace\\\\(\\\\), traits\\\\(mytraits\\\\) : memspace\\\\)\" \"original\" } } */\n+\n+/* { dg-final { scan-tree-dump \"pragma omp target num_teams\\\\(-2\\\\) thread_limit\\\\(0\\\\) uses_allocators\\\\(memspace\\\\(\\\\), traits\\\\(\\\\) : memspace\\\\)\" \"gimple\" } } */\n+/* { dg-final { scan-tree-dump \"pragma omp target num_teams\\\\(-2\\\\) thread_limit\\\\(0\\\\) uses_allocators\\\\(memspace\\\\(\\\\), traits\\\\(\\\\) : traits\\\\)\" \"gimple\" } } */\n+/* { dg-final { scan-tree-dump \"pragma omp target num_teams\\\\(-2\\\\) thread_limit\\\\(0\\\\) uses_allocators\\\\(memspace\\\\(\\\\), traits\\\\(\\\\) : memspace\\\\) uses_allocators\\\\(memspace\\\\(\\\\), traits\\\\(\\\\) : traits\\\\)\" \"gimple\" } } */\n+/* { dg-final { scan-tree-dump \"pragma omp target num_teams\\\\(-2\\\\) thread_limit\\\\(0\\\\) uses_allocators\\\\(memspace\\\\(\\\\), traits\\\\(mytraits\\\\) : traits\\\\)\" \"gimple\" } } */\n+/* { dg-final { scan-tree-dump \"pragma omp target num_teams\\\\(-2\\\\) thread_limit\\\\(0\\\\) uses_allocators\\\\(memspace\\\\(\\\\), traits\\\\(mytraits\\\\) : memspace\\\\)\" \"gimple\" } } */\ndiff --git a/gcc/testsuite/c-c++-common/gomp/uses_allocators-6.c b/gcc/testsuite/c-c++-common/gomp/uses_allocators-6.c\nnew file mode 100644\nindex 00000000000..23a831e8ba9\n--- /dev/null\n+++ b/gcc/testsuite/c-c++-common/gomp/uses_allocators-6.c\n@@ -0,0 +1,53 @@\n+/* { dg-additional-options \"-fdump-tree-gimple\" } */\n+\n+#include <stdint.h>\n+#include <omp.h>\n+\n+int\n+main ()\n+{\n+ int x, *xbuf[10];\n+ omp_allocator_handle_t my_alloc;\n+ const omp_alloctrait_t trait[1]= {{omp_atk_alignment,128}};\n+\n+ #pragma omp target uses_allocators(omp_low_lat_mem_alloc) map(tofrom: x, xbuf) defaultmap(none)\n+ #pragma omp parallel allocate(allocator(omp_low_lat_mem_alloc), align(128): x, xbuf) if(0) firstprivate(x, xbuf)\n+ {\n+\tif ((uintptr_t) &x % 128 != 0)\n+\t __builtin_abort ();\n+\tif ((uintptr_t) xbuf % 128 != 0)\n+\t __builtin_abort ();\n+ }\n+\n+ my_alloc = (omp_allocator_handle_t) 0xABCD;\n+\n+ #pragma omp target uses_allocators(traits(trait): my_alloc) defaultmap(none) map(tofrom: x, xbuf)\n+ #pragma omp parallel allocate(allocator(my_alloc): x, xbuf) if(0) firstprivate(x, xbuf)\n+ {\n+\tif ((uintptr_t) &x % 128 != 0)\n+\t __builtin_abort ();\n+\tif ((uintptr_t) xbuf % 128 != 0)\n+\t __builtin_abort ();\n+ }\n+\n+ if (my_alloc != (omp_allocator_handle_t) 0xABCD)\n+ __builtin_abort ();\n+\n+ /* The following creates an allocator with empty traits + default mem space. */\n+ #pragma omp target uses_allocators(my_alloc) map(tofrom: x, xbuf) defaultmap(none)\n+ #pragma omp parallel allocate(allocator(my_alloc), align(128): x, xbuf) if(0) firstprivate(x, xbuf)\n+ {\n+\tif ((uintptr_t) &x % 128 != 0)\n+\t __builtin_abort ();\n+\tif ((uintptr_t) xbuf % 128 != 0)\n+\t __builtin_abort ();\n+ }\n+\n+ if (my_alloc != (omp_allocator_handle_t) 0xABCD)\n+ __builtin_abort ();\n+\n+ return 0;\n+}\n+\n+/* { dg-final { scan-tree-dump-times \"#pragma omp target .* uses_allocators\\\\(memspace\\\\(\\\\), traits\\\\(trait\\\\) : my_alloc\\\\)\" 1 \"gimple\" } } */\n+/* { dg-final { scan-tree-dump-times \"#pragma omp target .* uses_allocators\\\\(memspace\\\\(\\\\), traits\\\\(\\\\) : my_alloc\\\\)\" 1 \"gimple\" } } */\ndiff --git a/gcc/testsuite/c-c++-common/gomp/uses_allocators-7.c b/gcc/testsuite/c-c++-common/gomp/uses_allocators-7.c\nindex ce43d70ecf2..66b257c7fbb 100644\n--- a/gcc/testsuite/c-c++-common/gomp/uses_allocators-7.c\n+++ b/gcc/testsuite/c-c++-common/gomp/uses_allocators-7.c\n@@ -76,8 +76,3 @@ const omp_alloctrait_t t[] = {};\n #pragma omp target uses_allocators(memspace(omp_default_mem_space) : my, my(t)) // { dg-error \"legacy 'my\\\\(t\\\\)' traits syntax not allowed in 'uses_allocators' clause when using modifiers\" }\n ;\n }\n-\n-// { dg-message \"sorry, unimplemented: 'uses_allocators' clause\" \"\" { target *-*-* } 57 }\n-// { dg-message \"sorry, unimplemented: 'uses_allocators' clause\" \"\" { target *-*-* } 61 }\n-// { dg-message \"sorry, unimplemented: 'uses_allocators' clause\" \"\" { target *-*-* } 63 }\n-// { dg-message \"sorry, unimplemented: 'uses_allocators' clause\" \"\" { target *-*-* } 76 }\ndiff --git a/gcc/testsuite/c-c++-common/gomp/uses_allocators-8.c b/gcc/testsuite/c-c++-common/gomp/uses_allocators-8.c\nindex 3ab87576c41..f03a52ef4ce 100644\n--- a/gcc/testsuite/c-c++-common/gomp/uses_allocators-8.c\n+++ b/gcc/testsuite/c-c++-common/gomp/uses_allocators-8.c\n@@ -56,6 +56,3 @@ const omp_alloctrait_t t2[] = {};\n \n // { dg-final { scan-tree-dump \"#pragma omp target uses_allocators\\\\(memspace\\\\(1\\\\), traits\\\\(\\\\) : my4\\\\) uses_allocators\\\\(memspace\\\\(\\\\), traits\\\\(t2\\\\) : my3\\\\) uses_allocators\\\\(memspace\\\\(\\\\), traits\\\\(\\\\) : my2\\\\) uses_allocators\\\\(memspace\\\\(3\\\\), traits\\\\(t\\\\) : my\\\\)\" \"original\" { target c } } }\n // { dg-final { scan-tree-dump \"#pragma omp target uses_allocators\\\\(memspace\\\\(omp_large_cap_mem_space\\\\), traits\\\\(\\\\) : my4\\\\) uses_allocators\\\\(memspace\\\\(\\\\), traits\\\\(t2\\\\) : my3\\\\) uses_allocators\\\\(memspace\\\\(\\\\), traits\\\\(\\\\) : my2\\\\) uses_allocators\\\\(memspace\\\\(omp_high_bw_mem_space\\\\), traits\\\\(t\\\\) : my\\\\)\" \"original\" { target c++ } } }\n-\n-\n-// { dg-message \"sorry, unimplemented: 'uses_allocators' clause\" \"\" { target *-*-* } 53 }\ndiff --git a/gcc/testsuite/g++.dg/gomp/uses_allocators-1.C b/gcc/testsuite/g++.dg/gomp/uses_allocators-1.C\nindex 79e51638534..b4f9fe772f8 100644\n--- a/gcc/testsuite/g++.dg/gomp/uses_allocators-1.C\n+++ b/gcc/testsuite/g++.dg/gomp/uses_allocators-1.C\n@@ -99,7 +99,3 @@ void use2()\n \n g2<omp_allocator_handle_t, const omp_alloctrait_t[]>(my); // OK\n }\n-\n-// { dg-message \"sorry, unimplemented: 'uses_allocators' clause\" \"\" { target *-*-* } 51 }\n-// { dg-message \"sorry, unimplemented: 'uses_allocators' clause\" \"\" { target *-*-* } 58 }\n-// { dg-message \"sorry, unimplemented: 'uses_allocators' clause\" \"\" { target *-*-* } 89 }\ndiff --git a/gcc/testsuite/gcc.dg/gomp/deprecate-2.c b/gcc/testsuite/gcc.dg/gomp/deprecate-2.c\nindex 46d286141ef..b7689dd1554 100644\n--- a/gcc/testsuite/gcc.dg/gomp/deprecate-2.c\n+++ b/gcc/testsuite/gcc.dg/gomp/deprecate-2.c\n@@ -42,6 +42,3 @@ void f()\n \n // { dg-warning \"42: the specification of arguments to 'uses_allocators' where each item is of the form 'allocator\\\\(traits\\\\)' is deprecated since OpenMP 5.2 \\\\\\[-Wdeprecated-openmp\\\\\\]\" \"\" { target *-*-* } 34 }\n }\n-\n-// { dg-excess-errors \"sorry, unimplemented: 'uses_allocators' clause\" }\n-// { dg-excess-errors \"sorry, unimplemented: 'uses_allocators' clause\" }\ndiff --git a/gcc/testsuite/gfortran.dg/gomp/allocate-1.f90 b/gcc/testsuite/gfortran.dg/gomp/allocate-1.f90\nindex 8bc6b768778..0463f0e0af9 100644\n--- a/gcc/testsuite/gfortran.dg/gomp/allocate-1.f90\n+++ b/gcc/testsuite/gfortran.dg/gomp/allocate-1.f90\n@@ -24,6 +24,10 @@ module omp_lib_kinds\n parameter :: omp_pteam_mem_alloc = 7\n integer (kind=omp_allocator_handle_kind), &\n parameter :: omp_thread_mem_alloc = 8\n+\n+ integer, parameter :: omp_memspace_handle_kind = c_intptr_t\n+ integer (omp_memspace_handle_kind), &\n+ parameter :: omp_default_mem_space = 0\n end module\n \n subroutine bar (a, b, c)\n@@ -80,7 +84,8 @@ subroutine foo(x, y)\n \n !$omp target teams distribute parallel do private (x) firstprivate (y) &\n !$omp allocate ((omp_default_mem_alloc + 0):z) allocate &\n- !$omp (omp_default_mem_alloc: x, y) allocate (h: r) lastprivate (z) reduction(+:r)\n+ !$omp (omp_default_mem_alloc: x, y) allocate (h: r) lastprivate (z) reduction(+:r) &\n+ !$omp uses_allocators(memspace(omp_default_mem_space) : h)\n do i = 1, 10\n call bar (0, x, z);\n call bar2 (1, y, r);\ndiff --git a/gcc/testsuite/gfortran.dg/gomp/scope-6.f90 b/gcc/testsuite/gfortran.dg/gomp/scope-6.f90\nindex 4c4f5e034f7..39a65904c33 100644\n--- a/gcc/testsuite/gfortran.dg/gomp/scope-6.f90\n+++ b/gcc/testsuite/gfortran.dg/gomp/scope-6.f90\n@@ -20,4 +20,4 @@ contains\n end\n end\n \n-! { dg-final { scan-tree-dump \"omp scope private\\\\(a\\\\) firstprivate\\\\(b\\\\) reduction\\\\(\\\\+:c\\\\) allocate\\\\(allocator\\\\(D\\\\.\\[0-9\\]+\\\\):a\\\\) allocate\\\\(allocator\\\\(D\\\\.\\[0-9\\]+\\\\):b\\\\) allocate\\\\(allocator\\\\(D\\\\.\\[0-9\\]+\\\\):c\\\\)\" \"original\" } }\n+! { dg-final { scan-tree-dump \"omp scope private\\\\(a\\\\) firstprivate\\\\(b\\\\) reduction\\\\(\\\\+:c\\\\) allocate\\\\(allocator\\\\(h\\\\):a\\\\) allocate\\\\(allocator\\\\(h\\\\):b\\\\) allocate\\\\(allocator\\\\(h\\\\):c\\\\)\" \"original\" } }\ndiff --git a/gcc/testsuite/gfortran.dg/gomp/uses_allocators-1.f90 b/gcc/testsuite/gfortran.dg/gomp/uses_allocators-1.f90\nnew file mode 100644\nindex 00000000000..0c6c5495729\n--- /dev/null\n+++ b/gcc/testsuite/gfortran.dg/gomp/uses_allocators-1.f90\n@@ -0,0 +1,17 @@\n+use iso_c_binding\n+use omp_lib\n+implicit none\n+contains\n+subroutine x\n+integer :: mem\n+type(omp_alloctrait), parameter:: mem2(1) = [omp_alloctrait(1,1)]\n+integer(omp_allocator_handle_kind) :: var\n+!$omp target uses_allocators(memspace(omp_default_mem_space), traits(mem2) : var) defaultmap(none)\n+block;\n+type(c_ptr) ::c\n+c = omp_alloc(omp_default_mem_space, 20_8)\n+end block\n+!$omp target uses_allocators(omp_default_mem_alloc, var(mem2)) ! { dg-warning \"The specification of arguments to 'uses_allocators' at \\\\(1\\\\) where each item is of the form 'allocator\\\\(traits\\\\)' is deprecated since OpenMP 5.2; instead use 'uses_allocators\\\\(traits\\\\(mem2\\\\): var\\\\)' \\\\\\[-Wdeprecated-openmp\\\\\\]\" }\n+block; end block\n+end\n+end\ndiff --git a/libgomp/testsuite/libgomp.fortran/uses_allocators_1.f90 b/gcc/testsuite/gfortran.dg/gomp/uses_allocators-2.f90\nsimilarity index 100%\nrename from libgomp/testsuite/libgomp.fortran/uses_allocators_1.f90\nrename to gcc/testsuite/gfortran.dg/gomp/uses_allocators-2.f90\ndiff --git a/libgomp/testsuite/libgomp.fortran/uses_allocators_2.f90 b/gcc/testsuite/gfortran.dg/gomp/uses_allocators-3.f90\nsimilarity index 70%\nrename from libgomp/testsuite/libgomp.fortran/uses_allocators_2.f90\nrename to gcc/testsuite/gfortran.dg/gomp/uses_allocators-3.f90\nindex 0ab09975f49..005ead56ee4 100644\n--- a/libgomp/testsuite/libgomp.fortran/uses_allocators_2.f90\n+++ b/gcc/testsuite/gfortran.dg/gomp/uses_allocators-3.f90\n@@ -3,8 +3,6 @@\n ! Minimal test for valid code:\n ! - predefined allocators do not need any special treatment in uses_allocators\n ! (as 'requires dynamic_allocators' is the default).\n-!\n-! - Non-predefined allocators are currently rejected ('sorry)'\n \n subroutine test\n use omp_lib\n@@ -35,22 +33,22 @@ subroutine non_predef\n \n integer(kind=omp_allocator_handle_kind) :: a1, a2, a3\n \n- !$omp target uses_allocators(omp_default_mem_alloc, a1(trait), a2(trait2)) ! { dg-message \"sorry, unimplemented: 'uses_allocators' clause with traits and memory spaces\" }\n+ !$omp target uses_allocators(omp_default_mem_alloc, a1(trait), a2(trait2))\n block; end block\n \n- !$omp target parallel uses_allocators(omp_default_mem_alloc, a1(trait), a2(trait2)) ! { dg-message \"sorry, unimplemented: 'uses_allocators' clause with traits and memory spaces\" }\n+ !$omp target parallel uses_allocators(omp_default_mem_alloc, a1(trait), a2(trait2))\n block; end block\n \n \n !$omp target uses_allocators(traits(trait):a1) &\n- !$omp& uses_allocators ( memspace ( omp_low_lat_mem_space ) , traits ( trait2 ) : a2 , a3) ! { dg-message \"sorry, unimplemented: 'uses_allocators' clause with traits and memory spaces\" }\n+ !$omp& uses_allocators ( memspace ( omp_low_lat_mem_space ) , traits ( trait2 ) : a2 , a3)\n block; end block\n \n !$omp target parallel uses_allocators(traits(trait):a1) &\n- !$omp& uses_allocators ( memspace ( omp_low_lat_mem_space ) , traits ( trait2 ) : a2 , a3) ! { dg-message \"sorry, unimplemented: 'uses_allocators' clause with traits and memory spaces\" }\n+ !$omp& uses_allocators ( memspace ( omp_low_lat_mem_space ) , traits ( trait2 ) : a2 , a3)\n block; end block\n \n- !$omp target uses_allocators ( traits(trait2) , memspace ( omp_low_lat_mem_space ) : a2 , a3) ! { dg-message \"sorry, unimplemented: 'uses_allocators' clause with traits and memory spaces\" }\n+ !$omp target uses_allocators ( traits(trait2) , memspace ( omp_low_lat_mem_space ) : a2 , a3)\n block; end block\n end subroutine\n \n@@ -62,7 +60,7 @@ subroutine trait_present\n integer(kind=omp_allocator_handle_kind) :: a1\n \n ! Invalid in OpenMP 5.0 / 5.1, but valid since 5.2 the same as omp_default_mem_space + emptry traits array\n- !$omp target uses_allocators ( a1 ) ! { dg-message \"sorry, unimplemented: 'uses_allocators' clause with traits and memory spaces\" }\n+ !$omp target uses_allocators ( a1 )\n block; end block\n end\n \n@@ -76,13 +74,13 @@ subroutine odd_names\n integer(kind=omp_allocator_handle_kind) :: traits\n integer(kind=omp_allocator_handle_kind) :: memspace\n \n- !$omp target uses_allocators ( traits(trait1), memspace(trait1) ) ! { dg-message \"sorry, unimplemented: 'uses_allocators' clause with traits and memory spaces\" }\n+ !$omp target uses_allocators ( traits(trait1), memspace(trait1) )\n block; end block\n \n- !$omp target uses_allocators ( traits(trait1), memspace(omp_low_lat_mem_space) : traits) ! { dg-message \"sorry, unimplemented: 'uses_allocators' clause with traits and memory spaces\" }\n+ !$omp target uses_allocators ( traits(trait1), memspace(omp_low_lat_mem_space) : traits)\n block; end block\n \n- !$omp target uses_allocators ( memspace(omp_low_lat_mem_space), traits(trait1) : memspace) ! { dg-message \"sorry, unimplemented: 'uses_allocators' clause with traits and memory spaces\" }\n+ !$omp target uses_allocators ( memspace(omp_low_lat_mem_space), traits(trait1) : memspace)\n block; end block\n end\n \n@@ -94,6 +92,6 @@ subroutine more_checks\n integer(kind=omp_allocator_handle_kind) :: a1, a2(4)\n integer(kind=1) :: a3\n \n- !$omp target uses_allocators(memspace (omp_low_lat_mem_space) : a1 ) ! { dg-message \"sorry, unimplemented: 'uses_allocators' clause with traits and memory spaces\" }\n+ !$omp target uses_allocators(memspace (omp_low_lat_mem_space) : a1 )\n block; end block\n end\ndiff --git a/gcc/testsuite/gfortran.dg/gomp/uses_allocators-4.f90 b/gcc/testsuite/gfortran.dg/gomp/uses_allocators-4.f90\nnew file mode 100644\nindex 00000000000..0efdc9ef54b\n--- /dev/null\n+++ b/gcc/testsuite/gfortran.dg/gomp/uses_allocators-4.f90\n@@ -0,0 +1,59 @@\n+! { dg-do compile }\n+! { dg-additional-options \"-fdump-tree-original -fdump-tree-gimple\" }\n+\n+program main\n+ use omp_lib\n+ implicit none\n+ integer, allocatable :: arr(:)\n+ integer (omp_allocator_handle_kind) :: bar, foo\n+\n+ type (omp_alloctrait), parameter :: traits_array(*) = &\n+ [omp_alloctrait(omp_atk_pinned,omp_atv_true),&\n+ omp_alloctrait(omp_atk_partition,omp_atv_nearest)]\n+\n+ !$omp target allocate(bar : arr) uses_allocators(bar)\n+ block\n+ allocate(arr(100))\n+ end block\n+\n+ !$omp target uses_allocators(omp_default_mem_alloc)\n+ block\n+ end block\n+\n+ !$omp target uses_allocators(bar(traits_array), foo (traits_array)) ! { dg-warning \"The specification of arguments to 'uses_allocators' at \\\\(1\\\\) where each item is of the form 'allocator\\\\(traits\\\\)' is deprecated since OpenMP 5.2; instead use 'uses_allocators\\\\(traits\\\\(traits_array\\\\): foo\\\\)' \\\\\\[-Wdeprecated-openmp\\\\\\]\" }\n+ block\n+ if (foo == 0) stop 1\n+ end block\n+\n+ !$omp target uses_allocators(traits(traits_array) : bar)\n+ block\n+ end block\n+\n+ !$omp target parallel uses_allocators(memspace (omp_low_lat_mem_space) : bar)\n+ block\n+ end block\n+\n+ !$omp target parallel uses_allocators(memspace (omp_high_bw_mem_space), traits(traits_array) : bar)\n+ block\n+ use iso_c_binding\n+ type(c_ptr) :: ptr\n+ integer(c_size_t) :: sz = 32\n+ ptr = omp_alloc (sz, bar)\n+ call omp_free (ptr, bar)\n+ end block\n+\n+end program main\n+\n+! { dg-final { scan-tree-dump \"pragma omp target allocate\\\\(allocator\\\\(bar\\\\):arr\\\\) uses_allocators\\\\(memspace\\\\(\\\\), traits\\\\(\\\\) : bar\\\\)\" \"original\" } }\n+! { dg-final { scan-tree-dump \"pragma omp target\" \"original\" } }\n+! { dg-final { scan-tree-dump \"pragma omp target uses_allocators\\\\(memspace\\\\(\\\\), traits\\\\(traits_array\\\\) : bar\\\\) uses_allocators\\\\(memspace\\\\(\\\\), traits\\\\(traits_array\\\\) : foo\\\\)\" \"original\" } }\n+! { dg-final { scan-tree-dump \"pragma omp target uses_allocators\\\\(memspace\\\\(\\\\), traits\\\\(traits_array\\\\) : bar\\\\)\" \"original\" } }\n+! { dg-final { scan-tree-dump \"pragma omp target uses_allocators\\\\(memspace\\\\(omp_low_lat_mem_space\\\\), traits\\\\(\\\\) : bar\\\\)\" \"original\" } }\n+! { dg-final { scan-tree-dump \"pragma omp target uses_allocators\\\\(memspace\\\\(omp_high_bw_mem_space\\\\), traits\\\\(traits_array\\\\) : bar\\\\)\" \"original\" } }\n+\n+! { dg-final { scan-tree-dump \"pragma omp target num_teams\\\\(-2\\\\) thread_limit\\\\(0\\\\) allocate\\\\(allocator\\\\(bar\\\\):arr\\\\) uses_allocators\\\\(memspace\\\\(\\\\), traits\\\\(\\\\) : bar\\\\)\" \"gimple\" } }\n+! { dg-final { scan-tree-dump \"pragma omp target\" \"gimple\" } }\n+! { dg-final { scan-tree-dump \"pragma omp target num_teams\\\\(-2\\\\) thread_limit\\\\(0\\\\) uses_allocators\\\\(memspace\\\\(\\\\), traits\\\\(traits_array\\\\) : bar\\\\) uses_allocators\\\\(memspace\\\\(\\\\), traits\\\\(traits_array\\\\) : foo\\\\)\" \"gimple\" } }\n+! { dg-final { scan-tree-dump \"pragma omp target num_teams\\\\(-2\\\\) thread_limit\\\\(0\\\\) uses_allocators\\\\(memspace\\\\(\\\\), traits\\\\(traits_array\\\\) : bar\\\\)\" \"gimple\" } }\n+! { dg-final { scan-tree-dump \"pragma omp target num_teams\\\\(-2\\\\) thread_limit\\\\(0\\\\) uses_allocators\\\\(memspace\\\\(omp_low_lat_mem_space\\\\), traits\\\\(\\\\) : bar\\\\)\" \"gimple\" } }\n+! { dg-final { scan-tree-dump \"pragma omp target num_teams\\\\(-2\\\\) thread_limit\\\\(0\\\\) uses_allocators\\\\(memspace\\\\(omp_high_bw_mem_space\\\\), traits\\\\(traits_array\\\\) : bar\\\\)\" \"gimple\" } }\ndiff --git a/gcc/testsuite/gfortran.dg/gomp/uses_allocators-5.f90 b/gcc/testsuite/gfortran.dg/gomp/uses_allocators-5.f90\nnew file mode 100644\nindex 00000000000..86a86a08bf0\n--- /dev/null\n+++ b/gcc/testsuite/gfortran.dg/gomp/uses_allocators-5.f90\n@@ -0,0 +1,54 @@\n+! { dg-do compile }\n+\n+program main\n+ use omp_lib\n+ implicit none\n+ integer (omp_allocator_handle_kind) :: bar, foo\n+\n+ type (omp_alloctrait), parameter :: traits_array(*) = &\n+ [omp_alloctrait(omp_atk_pinned,omp_atv_true),&\n+ omp_alloctrait(omp_atk_partition,omp_atv_nearest)]\n+\n+ !$omp target uses_allocators(omp_non_existant_alloc) ! { dg-error \"Allocator 'omp_non_existant_alloc' at .1. in USES_ALLOCATORS must be a scalar integer of kind 'omp_allocator_handle_kind'\" }\n+ block ! { dg-error \"Symbol 'omp_non_existant_alloc' at .1. has no IMPLICIT type; did you mean 'omp_const_mem_alloc'\\?\" \"\" { target *-*-* } .-1 }\n+ end block\n+\n+ !$omp target uses_allocators(bar(traits_array), foo (traits_array), ) ! { dg-error \"Invalid character in name\" }\n+ block\n+ end block\n+\n+ !$omp target uses_allocators(traits(xyz) : bar) ! { dg-error \"Symbol 'xyz' at .1. has no IMPLICIT type\" }\n+ block ! { dg-error \"Traits array 'xyz' in USES_ALLOCATORS .1. must be a one-dimensional named constant array of type 'omp_alloctrait'\" \"\" { target *-*-* } .-1 }\n+ end block\n+\n+ !$omp target uses_allocators(memspace(omp_non_existant_mem_space) : foo) ! { dg-error \"Symbol 'omp_non_existant_mem_space' at .1. has no IMPLICIT type; did you mean 'omp_const_mem_space'\\?\" }\n+ ! { dg-error \"Memspace 'omp_non_existant_mem_space' at .1. in USES_ALLOCATORS must be a predefined memory space\" \"\" { target *-*-* } .-1 }\n+\n+ block\n+ end block\n+\n+ !$omp target uses_allocators(traits(traits_array), traits(traits_array) : bar) ! { dg-error \"Duplicate TRAITS modifier at .1. in USES_ALLOCATORS clause\" }\n+ block\n+ end block\n+\n+ !$omp target uses_allocators(memspace(omp_default_mem_space), memspace(omp_default_mem_space) : foo) ! { dg-error \"Duplicate MEMSPACE modifier at .1. in USES_ALLOCATORS clause\" }\n+ block\n+ end block\n+\n+ !$omp target uses_allocators(memspace(omp_default_mem_space), traits(traits_array), traits(traits_array) : foo) ! { dg-error \"Duplicate TRAITS modifier at .1. in USES_ALLOCATORS clause\" }\n+ block\n+ end block\n+\n+ !$omp target uses_allocators (omp_null_allocator)\n+ block\n+ end block\n+\n+ !$omp target uses_allocators (memspace(omp_high_bw_mem_space) : foo, bar)\n+ block\n+ end block\n+\n+ !$omp target uses_allocators (memspace(omp_high_bw_mem_space) : foo(foo_traits)) ! { dg-error \"70:Unexpected '\\\\(' at .1.\" }\n+ block\n+ end block\n+\n+end program main\ndiff --git a/gcc/testsuite/gfortran.dg/gomp/uses_allocators-6.f90 b/gcc/testsuite/gfortran.dg/gomp/uses_allocators-6.f90\nnew file mode 100644\nindex 00000000000..00f87109d2c\n--- /dev/null\n+++ b/gcc/testsuite/gfortran.dg/gomp/uses_allocators-6.f90\n@@ -0,0 +1,14 @@\n+! { dg-do compile }\n+\n+program main\n+ use omp_lib\n+ implicit none\n+ integer, allocatable :: arr(:)\n+ integer (omp_allocator_handle_kind) :: bar\n+\n+ !$omp target allocate(bar : arr) ! { dg-error \"allocator 'bar' requires 'uses_allocators.bar.' clause in target region\" }\n+ block\n+ allocate(arr(100))\n+ end block\n+\n+end program main\ndiff --git a/libgomp/testsuite/libgomp.fortran/uses_allocators-7.f90 b/gcc/testsuite/gfortran.dg/gomp/uses_allocators-7.f90\nsimilarity index 65%\nrename from libgomp/testsuite/libgomp.fortran/uses_allocators-7.f90\nrename to gcc/testsuite/gfortran.dg/gomp/uses_allocators-7.f90\nindex 65e2fca082e..5ca636e7c79 100644\n--- a/libgomp/testsuite/libgomp.fortran/uses_allocators-7.f90\n+++ b/gcc/testsuite/gfortran.dg/gomp/uses_allocators-7.f90\n@@ -1,5 +1,4 @@\n-! { dg-do compile }\n-! { dg-additional-options \"-fdump-tree-gimple\" }\n+! { dg-additional-options \"-fdump-tree-original -fdump-tree-gimple\" }\n \n program main\n use iso_c_binding\n@@ -12,7 +11,7 @@ program main\n type(omp_alloctrait), parameter :: t(*) = [omp_alloctrait:: ]\n type(omp_alloctrait), parameter :: t2(*) = [omp_alloctrait:: ]\n \n- ! FIXME - improve check that that ';' is handled\n+ !! FIXME - improve check that that ';' is handled\n !$omp target uses_allocators(traits(t), memspace(omp_high_bw_mem_space) : my; omp_default_mem_alloc, omp_null_allocator; my2; traits(t2) : my3; memspace(omp_large_cap_mem_space) : my4)\n block\n end block\n@@ -54,16 +53,6 @@ program main\n stop 8\n end\n \n-\n-! FIXME ENABLE: 'dg FIXME final' -> 'dg-final'\n-! { dg FIXME final { scan-tree-dump-times \"#pragma omp target .*private\\\\(my_alloc\\\\).*uses_allocators\\\\(my_alloc: memspace\\\\(\\\\), traits\\\\(trait\\\\)\\\\)\" 1 \"gimple\" } }\n-! { dg FIXME final { scan-tree-dump-times \"#pragma omp target .*private\\\\(my_alloc\\\\).*uses_allocators\\\\(my_alloc: memspace\\\\(\\\\), traits\\\\(\\\\)\\\\)\" 1 \"gimple\" } }\n-! { dg FIXME final { scan-tree-dump \"#pragma omp target uses_allocators\\\\(memspace\\\\(1\\\\), traits\\\\(\\\\) : my4\\\\) uses_allocators\\\\(memspace\\\\(\\\\), traits\\\\(t2\\\\) : my3\\\\) uses_allocators\\\\(memspace\\\\(\\\\), traits\\\\(\\\\) : my2\\\\) uses_allocators\\\\(memspace\\\\(3\\\\), traits\\\\(t\\\\) : my\\\\)\" 1 \"original\" } }\n-\n-\n-! FIXME ENABLE code above for \"gimple\" once it has been implemented:\n-! { dg-message \"sorry, unimplemented: 'uses_allocators' clause with traits and memory spaces\" \"\" { target *-*-* } 16 }\n-! { dg-message \"sorry, unimplemented: 'uses_allocators' clause with traits and memory spaces\" \"\" { target *-*-* } 31 }\n-! { dg-message \"sorry, unimplemented: 'uses_allocators' clause with traits and memory spaces\" \"\" { target *-*-* } 44 }\n-! { dg-bogus \"'my_alloc' not specified in enclosing 'target'\" \"bogus issue because clause is ignored\" { xfail *-*-* } 32 }\n-! { dg-bogus \"'my_alloc' not specified in enclosing 'target'\" \"bogus issue because clause is ignored\" { xfail *-*-* } 45 }\n+! { dg-final { scan-tree-dump-times \"#pragma omp target .*uses_allocators\\\\(memspace\\\\(\\\\), traits\\\\(trait\\\\) : my_alloc\\\\)\" 1 \"gimple\" } }\n+! { dg-final { scan-tree-dump-times \"#pragma omp target .*uses_allocators\\\\(memspace\\\\(\\\\), traits\\\\(\\\\) : my_alloc\\\\)\" 1 \"gimple\" } }\n+! { dg-final { scan-tree-dump-times \"#pragma omp target .*uses_allocators\\\\(memspace\\\\(1\\\\), traits\\\\(\\\\) : my4\\\\) uses_allocators\\\\(memspace\\\\(\\\\), traits\\\\(t2\\\\) : my3\\\\) uses_allocators\\\\(memspace\\\\(\\\\), traits\\\\(\\\\) : my2\\\\) uses_allocators\\\\(memspace\\\\(3\\\\), traits\\\\(t\\\\) : my\\\\)\" 1 \"original\" } }\ndiff --git a/gcc/tree-pretty-print.cc b/gcc/tree-pretty-print.cc\nindex 79e0a734dbb..f678f44f243 100644\n--- a/gcc/tree-pretty-print.cc\n+++ b/gcc/tree-pretty-print.cc\n@@ -1154,6 +1154,9 @@ dump_omp_clause (pretty_printer *pp, tree clause, int spc, dump_flags_t flags)\n \tcase GOMP_MAP_POP_MAPPER_NAME:\n \t pp_string (pp, \"pop_mapper\");\n \t break;\n+\tcase GOMP_MAP_USES_ALLOCATORS:\n+\t pp_string (pp, \"uses_allocators\");\n+\t break;\n \tdefault:\n \t gcc_unreachable ();\n \t}\ndiff --git a/include/gomp-constants.h b/include/gomp-constants.h\nindex 0a0761043f9..072e7a571bc 100644\n--- a/include/gomp-constants.h\n+++ b/include/gomp-constants.h\n@@ -195,6 +195,11 @@ enum gomp_map_kind\n GOMP_MAP_ATTACH_ZERO_LENGTH_ARRAY_SECTION\n =\t\t\t\t\t(GOMP_MAP_DEEP_COPY | 2),\n \n+ /* Used to pass a descriptor for an OpenMP uses_allocators clause,\n+ also serves as an effective 'firstprivate' clause for the allocator\n+ variable. */\n+ GOMP_MAP_USES_ALLOCATORS =\t\t(GOMP_MAP_DEEP_COPY | 3),\n+\n /* Internal to GCC, not used in libgomp. */\n /* Do not map, but pointer assign a pointer instead. */\n GOMP_MAP_FIRSTPRIVATE_POINTER =\t(GOMP_MAP_LAST | 1),\ndiff --git a/libgomp/allocator.c b/libgomp/allocator.c\nindex 8fdaf9bd198..cbfbd6d0333 100644\n--- a/libgomp/allocator.c\n+++ b/libgomp/allocator.c\n@@ -243,14 +243,24 @@ struct omp_allocator_data\n unsigned int fallback : 8;\n unsigned int pinned : 1;\n unsigned int partition : 7;\n-#if defined(LIBGOMP_USE_MEMKIND) || defined(LIBGOMP_USE_LIBNUMA)\n+ /* To unify the format of this type across host/accelerator, enable\n+ this field unconditionally when offload is enabled. */\n+ #if defined(LIBGOMP_USE_MEMKIND) || defined(LIBGOMP_USE_LIBNUMA) ||\t\\\n+ defined(LIBGOMP_OFFLOAD_HOST) || defined(LIBGOMP_OFFLOADED_ONLY)\n unsigned int memkind : 8;\n #endif\n+ /* Note: we now require __sync builtins for offload host/accelerator,\n+ checked during configuration. This lock should never be enabled\n+ for offload configs. */\n #ifndef HAVE_SYNC_BUILTINS\n gomp_mutex_t lock;\n #endif\n };\n \n+/* Size of allocator data, exported within libgomp. */\n+const size_t gomp_omp_allocator_data_size attribute_hidden\n+ = sizeof (struct omp_allocator_data);\n+\n struct omp_mem_header\n {\n void *ptr;\n@@ -400,38 +410,44 @@ gomp_get_memkind (void)\n }\n #endif\n \n-omp_allocator_handle_t\n-omp_init_allocator (omp_memspace_handle_t memspace, int ntraits,\n-\t\t const omp_alloctrait_t traits[])\n+static omp_allocator_handle_t\n+gomp_init_allocator_data (struct omp_allocator_data *data,\n+\t\t\t omp_memspace_handle_t memspace, int ntraits,\n+\t\t\t const omp_alloctrait_t traits[])\n {\n- struct omp_allocator_data data\n- = { memspace, 1, ~(uintptr_t) 0, 0, 0, omp_atv_contended, omp_atv_all,\n-\tomp_atv_default_mem_fb, omp_atv_false, omp_atv_environment,\n-#if defined(LIBGOMP_USE_MEMKIND) || defined(LIBGOMP_USE_LIBNUMA)\n-\tGOMP_MEMKIND_NONE\n+ data->memspace = memspace;\n+ data->alignment = 1;\n+ data->pool_size = ~(uintptr_t) 0;\n+ data->used_pool_size = 0;\n+ data->fb_data = 0;\n+ data->sync_hint = omp_atv_contended;\n+ data->access = omp_atv_all;\n+ data->fallback = omp_atv_default_mem_fb;\n+ data->pinned = omp_atv_false;\n+ data->partition = omp_atv_environment;\n+#if defined(LIBGOMP_USE_MEMKIND) || defined(LIBGOMP_USE_LIBNUMA) ||\t\\\n+ defined(LIBGOMP_OFFLOAD_HOST) || defined(LIBGOMP_OFFLOADED_ONLY)\n+ data->memkind = GOMP_MEMKIND_NONE;\n #endif\n- };\n- struct omp_allocator_data *ret;\n- int i;\n \n if (memspace > omp_max_predefined_mem_space\n && (memspace < ompx_gnu_min_predefined_mem_space\n \t || memspace > ompx_gnu_max_predefined_mem_space))\n return omp_null_allocator;\n- for (i = 0; i < ntraits; i++)\n+ for (int i = 0; i < ntraits; i++)\n switch (traits[i].key)\n {\n case omp_atk_sync_hint:\n \tswitch (traits[i].value)\n \t {\n \t case omp_atv_default:\n-\t data.sync_hint = omp_atv_contended;\n+\t data->sync_hint = omp_atv_contended;\n \t break;\n \t case omp_atv_contended:\n \t case omp_atv_uncontended:\n \t case omp_atv_serialized:\n \t case omp_atv_private:\n-\t data.sync_hint = traits[i].value;\n+\t data->sync_hint = traits[i].value;\n \t break;\n \t default:\n \t return omp_null_allocator;\n@@ -440,25 +456,25 @@ omp_init_allocator (omp_memspace_handle_t memspace, int ntraits,\n case omp_atk_alignment:\n if (traits[i].value == omp_atv_default)\n \t {\n-\t data.alignment = 1;\n+\t data->alignment = 1;\n \t break;\n \t }\n \tif ((traits[i].value & (traits[i].value - 1)) != 0\n \t || !traits[i].value)\n \t return omp_null_allocator;\n-\tdata.alignment = traits[i].value;\n+\tdata->alignment = traits[i].value;\n \tbreak;\n case omp_atk_access:\n \tswitch (traits[i].value)\n \t {\n \t case omp_atv_default:\n-\t data.access = omp_atv_all;\n+\t data->access = omp_atv_all;\n \t break;\n \t case omp_atv_all:\n \t case omp_atv_cgroup:\n \t case omp_atv_pteam:\n \t case omp_atv_thread:\n-\t data.access = traits[i].value;\n+\t data->access = traits[i].value;\n \t break;\n \t default:\n \t return omp_null_allocator;\n@@ -466,38 +482,38 @@ omp_init_allocator (omp_memspace_handle_t memspace, int ntraits,\n \tbreak;\n case omp_atk_pool_size:\n \tif (traits[i].value == omp_atv_default)\n-\t data.pool_size = ~(uintptr_t) 0;\n+\t data->pool_size = ~(uintptr_t) 0;\n \telse\n-\t data.pool_size = traits[i].value;\n+\t data->pool_size = traits[i].value;\n \tbreak;\n case omp_atk_fallback:\n \tswitch (traits[i].value)\n \t {\n \t case omp_atv_default:\n-\t data.fallback = omp_atv_default_mem_fb;\n+\t data->fallback = omp_atv_default_mem_fb;\n \t break;\n \t case omp_atv_default_mem_fb:\n \t case omp_atv_null_fb:\n \t case omp_atv_abort_fb:\n \t case omp_atv_allocator_fb:\n-\t data.fallback = traits[i].value;\n+\t data->fallback = traits[i].value;\n \t break;\n \t default:\n \t return omp_null_allocator;\n \t }\n \tbreak;\n case omp_atk_fb_data:\n-\tdata.fb_data = traits[i].value;\n+\tdata->fb_data = traits[i].value;\n \tbreak;\n case omp_atk_pinned:\n \tswitch (traits[i].value)\n \t {\n \t case omp_atv_default:\n \t case omp_atv_false:\n-\t data.pinned = omp_atv_false;\n+\t data->pinned = omp_atv_false;\n \t break;\n \t case omp_atv_true:\n-\t data.pinned = omp_atv_true;\n+\t data->pinned = omp_atv_true;\n \t break;\n \t default:\n \t return omp_null_allocator;\n@@ -507,13 +523,13 @@ omp_init_allocator (omp_memspace_handle_t memspace, int ntraits,\n \tswitch (traits[i].value)\n \t {\n \t case omp_atv_default:\n-\t data.partition = omp_atv_environment;\n+\t data->partition = omp_atv_environment;\n \t break;\n \t case omp_atv_environment:\n \t case omp_atv_nearest:\n \t case omp_atv_blocked:\n \t case omp_atv_interleaved:\n-\t data.partition = traits[i].value;\n+\t data->partition = traits[i].value;\n \t break;\n \t default:\n \t return omp_null_allocator;\n@@ -523,8 +539,8 @@ omp_init_allocator (omp_memspace_handle_t memspace, int ntraits,\n \treturn omp_null_allocator;\n }\n \n- if (data.alignment < sizeof (void *))\n- data.alignment = sizeof (void *);\n+ if (data->alignment < sizeof (void *))\n+ data->alignment = sizeof (void *);\n \n switch (memspace)\n {\n@@ -532,57 +548,68 @@ omp_init_allocator (omp_memspace_handle_t memspace, int ntraits,\n case omp_high_bw_mem_space:\n struct gomp_memkind_data *memkind_data;\n memkind_data = gomp_get_memkind ();\n- if (data.partition == omp_atv_interleaved\n+ if (data->partition == omp_atv_interleaved\n \t && memkind_data->kinds[GOMP_MEMKIND_HBW_INTERLEAVE])\n \t{\n-\t data.memkind = GOMP_MEMKIND_HBW_INTERLEAVE;\n+\t data->memkind = GOMP_MEMKIND_HBW_INTERLEAVE;\n \t break;\n \t}\n else if (memkind_data->kinds[GOMP_MEMKIND_HBW_PREFERRED])\n \t{\n-\t data.memkind = GOMP_MEMKIND_HBW_PREFERRED;\n+\t data->memkind = GOMP_MEMKIND_HBW_PREFERRED;\n \t break;\n \t}\n break;\n case omp_large_cap_mem_space:\n memkind_data = gomp_get_memkind ();\n if (memkind_data->kinds[GOMP_MEMKIND_DAX_KMEM_ALL])\n-\tdata.memkind = GOMP_MEMKIND_DAX_KMEM_ALL;\n+\tdata->memkind = GOMP_MEMKIND_DAX_KMEM_ALL;\n else if (memkind_data->kinds[GOMP_MEMKIND_DAX_KMEM])\n-\tdata.memkind = GOMP_MEMKIND_DAX_KMEM;\n+\tdata->memkind = GOMP_MEMKIND_DAX_KMEM;\n break;\n #endif\n default:\n #ifdef LIBGOMP_USE_MEMKIND\n- if (data.partition == omp_atv_interleaved)\n+ if (data->partition == omp_atv_interleaved)\n \t{\n \t memkind_data = gomp_get_memkind ();\n \t if (memkind_data->kinds[GOMP_MEMKIND_INTERLEAVE])\n-\t data.memkind = GOMP_MEMKIND_INTERLEAVE;\n+\t data->memkind = GOMP_MEMKIND_INTERLEAVE;\n \t}\n #endif\n break;\n }\n \n #ifdef LIBGOMP_USE_LIBNUMA\n- if (data.memkind == GOMP_MEMKIND_NONE && data.partition == omp_atv_nearest)\n+ if (data->memkind == GOMP_MEMKIND_NONE && data->partition == omp_atv_nearest)\n {\n libnuma_data = gomp_get_libnuma ();\n if (libnuma_data->numa_alloc_local != NULL)\n-\tdata.memkind = GOMP_MEMKIND_LIBNUMA;\n+\tdata->memkind = GOMP_MEMKIND_LIBNUMA;\n }\n #endif\n \n /* Reject unsupported memory spaces. */\n- if (!MEMSPACE_VALIDATE (data.memspace, data.access, data.pinned))\n+ if (!MEMSPACE_VALIDATE (data->memspace, data->access, data->pinned))\n return omp_null_allocator;\n \n- ret = gomp_malloc (sizeof (struct omp_allocator_data));\n- *ret = data;\n-#ifndef HAVE_SYNC_BUILTINS\n- gomp_mutex_init (&ret->lock);\n-#endif\n- return (omp_allocator_handle_t) ret;\n+ return (omp_allocator_handle_t) data;\n+}\n+\n+omp_allocator_handle_t\n+omp_init_allocator (omp_memspace_handle_t memspace, int ntraits,\n+\t\t const omp_alloctrait_t traits[])\n+{\n+ struct omp_allocator_data *data\n+ = gomp_malloc (sizeof (struct omp_allocator_data));\n+\n+ omp_allocator_handle_t ret\n+ = gomp_init_allocator_data (data, memspace, ntraits, traits);\n+\n+ if (ret != omp_null_allocator)\n+ free (data);\n+\n+ return ret;\n }\n \n void\n@@ -1496,3 +1523,51 @@ fail:;\n }\n return NULL;\n }\n+\n+#if !defined(LIBGOMP_OFFLOADED_ONLY)\n+\n+/* Called from gomp_maps_vars, used to implement the effective\n+ omp_init_allocator() call in an uses_allocators clause.\n+\n+ The memspace_validate hook is also used here to check things for\n+ the offload accelerator on the host side.\n+*/\n+attribute_hidden uintptr_t\n+gomp_map_omp_init_allocator (struct gomp_device_descr *devicep,\n+\t\t\t struct goacc_asyncqueue *aq,\n+\t\t\t struct gomp_coalesce_buf *cbuf,\n+\t\t\t void *allocator_data_devaddr, void *descr_ptr)\n+{\n+ uintptr_t *descr = (uintptr_t *) descr_ptr;\n+\n+ omp_memspace_handle_t memspace = (omp_memspace_handle_t) descr[0];\n+ int ntraits = (int) descr[1];\n+ omp_alloctrait_t *traits = (omp_alloctrait_t *) descr[2];\n+\n+ struct omp_allocator_data data;\n+ omp_allocator_handle_t ret = gomp_init_allocator_data (&data, memspace,\n+\t\t\t\t\t\t\t ntraits, traits);\n+ if (ret != omp_null_allocator)\n+ {\n+ if (devicep)\n+\t{\n+\t /* Do memspace validation for the offload target, using the\n+\t offload plugin. */\n+\t if (devicep->memspace_validate_func\n+\t && !devicep->memspace_validate_func (data.memspace, data.access))\n+\t return (uintptr_t) omp_null_allocator;\n+\n+\t /* Copy to device. This is now the device-side omp_allocator_data. */\n+\t gomp_copy_host2dev (devicep, aq, allocator_data_devaddr, &data,\n+\t\t\t sizeof (struct omp_allocator_data), true, cbuf);\n+\t}\n+ else\n+\t/* Used for host fallback case. */\n+\tmemcpy (allocator_data_devaddr, &data,\n+\t\tsizeof (struct omp_allocator_data));\n+\n+ ret = (omp_allocator_handle_t) allocator_data_devaddr;\n+ }\n+ return (uintptr_t) ret;\n+}\n+#endif\ndiff --git a/libgomp/config/nvptx/allocator.c b/libgomp/config/nvptx/allocator.c\nindex ebbe9816909..8bb18daa0d2 100644\n--- a/libgomp/config/nvptx/allocator.c\n+++ b/libgomp/config/nvptx/allocator.c\n@@ -54,6 +54,9 @@ asm (\".extern .shared .u8 __nvptx_lowlat_pool[];\\n\");\n static void *\n nvptx_memspace_alloc (omp_memspace_handle_t memspace, size_t size)\n {\n+#if __PTX_ISA_VERSION_MAJOR__ > 4\t\t\t\t\t\\\n+ || (__PTX_ISA_VERSION_MAJOR__ == 4 && __PTX_ISA_VERSION_MINOR >= 1)\n+ /* Low-latency memory is not available before PTX 4.1. */\n if (memspace == omp_low_lat_mem_space)\n {\n char *shared_pool;\n@@ -65,12 +68,16 @@ nvptx_memspace_alloc (omp_memspace_handle_t memspace, size_t size)\n /* No non-standard memspaces are implemented for device-side nvptx. */\n return NULL;\n else\n+#endif\n return malloc (size);\n }\n \n static void *\n nvptx_memspace_calloc (omp_memspace_handle_t memspace, size_t size)\n {\n+#if __PTX_ISA_VERSION_MAJOR__ > 4\t\t\t\t\t\\\n+ || (__PTX_ISA_VERSION_MAJOR__ == 4 && __PTX_ISA_VERSION_MINOR >= 1)\n+ /* Low-latency memory is not available before PTX 4.1. */\n if (memspace == omp_low_lat_mem_space)\n {\n char *shared_pool;\n@@ -82,12 +89,16 @@ nvptx_memspace_calloc (omp_memspace_handle_t memspace, size_t size)\n /* No non-standard memspaces are implemented for device-side nvptx. */\n return NULL;\n else\n+#endif\n return calloc (1, size);\n }\n \n static void\n nvptx_memspace_free (omp_memspace_handle_t memspace, void *addr, size_t size)\n {\n+#if __PTX_ISA_VERSION_MAJOR__ > 4\t\t\t\t\t\\\n+ || (__PTX_ISA_VERSION_MAJOR__ == 4 && __PTX_ISA_VERSION_MINOR >= 1)\n+ /* Low-latency memory is not available before PTX 4.1. */\n if (memspace == omp_low_lat_mem_space)\n {\n char *shared_pool;\n@@ -96,6 +107,7 @@ nvptx_memspace_free (omp_memspace_handle_t memspace, void *addr, size_t size)\n __nvptx_lowlat_free (shared_pool, addr, size);\n }\n else\n+#endif\n free (addr);\n }\n \n@@ -103,6 +115,9 @@ static void *\n nvptx_memspace_realloc (omp_memspace_handle_t memspace, void *addr,\n \t\t\tsize_t oldsize, size_t size)\n {\n+#if __PTX_ISA_VERSION_MAJOR__ > 4 \\\n+ || (__PTX_ISA_VERSION_MAJOR__ == 4 && __PTX_ISA_VERSION_MINOR >= 1)\n+ /* Low-latency memory is not available before PTX 4.1. */\n if (memspace == omp_low_lat_mem_space)\n {\n char *shared_pool;\n@@ -110,11 +125,15 @@ nvptx_memspace_realloc (omp_memspace_handle_t memspace, void *addr,\n \n return __nvptx_lowlat_realloc (shared_pool, addr, oldsize, size);\n }\n- else if (memspace > GOMP_OMP_PREDEF_MEMSPACE_MAX)\n- /* No non-standard memspaces are implemented for device-side nvptx. */\n- return NULL;\n else\n- return realloc (addr, size);\n+#endif\n+ {\n+ if (memspace > GOMP_OMP_PREDEF_MEMSPACE_MAX)\n+\t/* No non-standard memspaces are implemented for device-side nvptx. */\n+\treturn NULL;\n+ else\n+\treturn realloc (addr, size);\n+ }\n }\n \n static inline int\ndiff --git a/libgomp/configure b/libgomp/configure\nindex 56cffe79634..3a9d6a76eef 100755\n--- a/libgomp/configure\n+++ b/libgomp/configure\n@@ -15782,6 +15782,12 @@ fi\n \n \n \n+if test x\"$offload_plugins\" != x; then\n+\n+$as_echo \"#define LIBGOMP_OFFLOAD_HOST 1\" >>confdefs.h\n+\n+fi\n+\n # Check for functions needed.\n for ac_func in getloadavg clock_gettime strtoull\n do :\n@@ -17120,6 +17126,17 @@ $as_echo \"#define HAVE_SYNC_BUILTINS 1\" >>confdefs.h\n \n fi\n \n+if test x$libgomp_cv_have_sync_builtins = xno; then\n+ # We require accelerator targets to support __sync_* builtins.\n+ if test x$libgomp_offloaded_only = xyes; then\n+ as_fn_error $? \"accelerator targets require __sync_val_compare_and_swap to build libgomp.\" \"$LINENO\" 5\n+ fi\n+ # Same for offload hosts.\n+ if test x\"$offload_plugins\" = x; then\n+ as_fn_error $? \"offload hosts require __sync_val_compare_and_swap to build libgomp.\" \"$LINENO\" 5\n+ fi\n+fi\n+\n XCFLAGS=\"$XCFLAGS$XPCFLAGS\"\n \n # Add CET specific flags if CET is enabled\ndiff --git a/libgomp/configure.ac b/libgomp/configure.ac\nindex 1730c62c74c..7f6df0bfe85 100644\n--- a/libgomp/configure.ac\n+++ b/libgomp/configure.ac\n@@ -233,6 +233,11 @@ AC_CHECK_SIZEOF([void *])\n \n m4_include([plugin/configfrag.ac])\n \n+if test x\"$offload_plugins\" != x; then\n+ AC_DEFINE(LIBGOMP_OFFLOAD_HOST, 1,\n+ [Define to 1 if building libgomp for a offload host])\n+fi\n+\n # Check for functions needed.\n AC_CHECK_FUNCS(getloadavg clock_gettime strtoull)\n AC_CHECK_FUNCS(aligned_alloc posix_memalign memalign _aligned_malloc)\n@@ -365,6 +370,17 @@ CFLAGS=\"$save_CFLAGS $XCFLAGS\"\n # had a chance to set XCFLAGS.\n LIBGOMP_CHECK_SYNC_BUILTINS\n \n+if test x$libgomp_cv_have_sync_builtins = xno; then\n+ # We require accelerator targets to support __sync_* builtins.\n+ if test x$libgomp_offloaded_only = xyes; then\n+ AC_MSG_ERROR([accelerator targets require __sync_val_compare_and_swap to build libgomp.])\n+ fi\n+ # Same for offload hosts.\n+ if test x\"$offload_plugins\" = x; then\n+ AC_MSG_ERROR([offload hosts require __sync_val_compare_and_swap to build libgomp.])\n+ fi\n+fi\n+\n XCFLAGS=\"$XCFLAGS$XPCFLAGS\"\n \n # Add CET specific flags if CET is enabled\ndiff --git a/libgomp/libgomp-plugin.h b/libgomp/libgomp-plugin.h\nindex bb4d577b66d..358c188516c 100644\n--- a/libgomp/libgomp-plugin.h\n+++ b/libgomp/libgomp-plugin.h\n@@ -187,6 +187,7 @@ extern int GOMP_OFFLOAD_memcpy3d (int, int, size_t, size_t, size_t, void *,\n \t\t\t\t const void *, size_t, size_t, size_t, size_t,\n \t\t\t\t size_t);\n extern bool GOMP_OFFLOAD_memset (int, void *, int, size_t);\n+extern int GOMP_OFFLOAD_memspace_validate (omp_memspace_handle_t, unsigned int);\n extern bool GOMP_OFFLOAD_can_run (void *);\n extern void GOMP_OFFLOAD_run (int, void *, void *, void **);\n extern void GOMP_OFFLOAD_async_run (int, void *, void *, void **, void *);\ndiff --git a/libgomp/libgomp.h b/libgomp/libgomp.h\nindex 42f32439295..e8a8fb3e727 100644\n--- a/libgomp/libgomp.h\n+++ b/libgomp/libgomp.h\n@@ -614,6 +614,7 @@ extern bool gomp_display_affinity_var;\n extern char *gomp_affinity_format_var;\n extern size_t gomp_affinity_format_len;\n extern uintptr_t gomp_def_allocator;\n+extern const size_t gomp_omp_allocator_data_size;\n extern const struct gomp_default_icv gomp_default_icv_values;\n extern struct gomp_icv_list *gomp_initial_icv_list;\n extern struct gomp_offload_icv_list *gomp_offload_icv_list;\n@@ -1434,6 +1435,7 @@ struct gomp_device_descr\n __typeof (GOMP_OFFLOAD_memcpy2d) *memcpy2d_func;\n __typeof (GOMP_OFFLOAD_memcpy3d) *memcpy3d_func;\n __typeof (GOMP_OFFLOAD_memset) *memset_func;\n+ __typeof (GOMP_OFFLOAD_memspace_validate) *memspace_validate_func;\n __typeof (GOMP_OFFLOAD_can_run) *can_run_func;\n __typeof (GOMP_OFFLOAD_run) *run_func;\n __typeof (GOMP_OFFLOAD_async_run) *async_run_func;\n@@ -1503,6 +1505,13 @@ extern bool gomp_remove_var (struct gomp_device_descr *, splay_tree_key);\n extern void gomp_remove_var_async (struct gomp_device_descr *, splay_tree_key,\n \t\t\t\t struct goacc_asyncqueue *);\n \n+/* allocator.c */\n+\n+extern uintptr_t gomp_map_omp_init_allocator (struct gomp_device_descr *,\n+\t\t\t\t\t struct goacc_asyncqueue *,\n+\t\t\t\t\t struct gomp_coalesce_buf *,\n+\t\t\t\t\t void *, void *);\n+\n /* work.c */\n \n extern void gomp_init_work_share (struct gomp_work_share *, size_t, unsigned);\ndiff --git a/libgomp/oacc-host.c b/libgomp/oacc-host.c\nindex 028a5c943b7..77dec471fee 100644\n--- a/libgomp/oacc-host.c\n+++ b/libgomp/oacc-host.c\n@@ -286,6 +286,7 @@ static struct gomp_device_descr host_dispatch =\n .host2dev_func = host_host2dev,\n .memcpy2d_func = NULL,\n .memcpy3d_func = NULL,\n+ .memspace_validate_func = NULL,\n .run_func = host_run,\n \n .mem_map = { NULL },\ndiff --git a/libgomp/plugin/plugin-gcn.c b/libgomp/plugin/plugin-gcn.c\nindex 32f573f1b7f..f52e4ac8092 100644\n--- a/libgomp/plugin/plugin-gcn.c\n+++ b/libgomp/plugin/plugin-gcn.c\n@@ -4718,6 +4718,19 @@ unlock:\n return retval;\n }\n \n+int\n+GOMP_OFFLOAD_memspace_validate (omp_memspace_handle_t memspace, unsigned access)\n+{\n+ /* Disallow use of low-latency memory when it must be accessible by\n+ all threads. */\n+ return (memspace != omp_low_lat_mem_space\n+\t || access != omp_atv_all);\n+\n+ /* Otherwise, standard memspaces are accepted, even when we don't have\n+ anything special to do with them, and non-standard memspaces are assumed\n+ to need explicit support. */\n+ return (memspace <= GOMP_OMP_PREDEF_MEMSPACE_MAX);\n+}\n \n static bool\n init_hip_runtime_functions (void)\ndiff --git a/libgomp/plugin/plugin-nvptx.c b/libgomp/plugin/plugin-nvptx.c\nindex a540e9d4cce..914b33f35d4 100644\n--- a/libgomp/plugin/plugin-nvptx.c\n+++ b/libgomp/plugin/plugin-nvptx.c\n@@ -2468,6 +2468,21 @@ GOMP_OFFLOAD_memset (int ord, void *ptr, int val, size_t count)\n return true;\n }\n \n+int\n+GOMP_OFFLOAD_memspace_validate (omp_memspace_handle_t memspace, unsigned access)\n+{\n+ /* Disallow use of low-latency memory when it must be accessible by\n+ all threads. */\n+ if (memspace == omp_low_lat_mem_space\n+ && access == omp_atv_all)\n+ return false;\n+\n+ /* Otherwise, standard memspaces are accepted, even when we don't have\n+ anything special to do with them, and non-standard memspaces are assumed\n+ to need explicit support. */\n+ return (memspace <= GOMP_OMP_PREDEF_MEMSPACE_MAX);\n+}\n+\n bool\n GOMP_OFFLOAD_openacc_async_host2dev (int ord, void *dst, const void *src,\n \t\t\t\t size_t n, struct goacc_asyncqueue *aq)\ndiff --git a/libgomp/target.c b/libgomp/target.c\nindex d562b0493ea..4fb2aaa222e 100644\n--- a/libgomp/target.c\n+++ b/libgomp/target.c\n@@ -1249,6 +1249,23 @@ gomp_map_vars_internal (struct gomp_device_descr *devicep,\n \t{\n \t tgt->list[i].key = NULL;\n \t tgt->list[i].offset = OFFSET_INLINED;\n+\t has_firstprivate = true;\n+\t continue;\n+\t}\n+ else if ((kind & typemask) == GOMP_MAP_USES_ALLOCATORS)\n+\t{\n+\t tgt->list[i].key = NULL;\n+\t tgt->list[i].offset = OFFSET_INLINED;\n+\n+\t size_t align = (size_t) 1 << (kind >> rshift);\n+\t if (tgt_align < align)\n+\t tgt_align = align;\n+\t tgt_size = (tgt_size + align - 1) & ~(align - 1);\n+\n+\t /* Allocate space for omp_allocator_data. */\n+\t tgt_size += gomp_omp_allocator_data_size;\n+\n+\t has_firstprivate = true;\n \t continue;\n \t}\n else if ((kind & typemask) == GOMP_MAP_USE_DEVICE_PTR\n@@ -1680,6 +1697,21 @@ gomp_map_vars_internal (struct gomp_device_descr *devicep,\n \t\t tgt->list[i].offset = OFFSET_INLINED;\n \t\t }\n \t\tcontinue;\n+\n+\t case GOMP_MAP_USES_ALLOCATORS:\n+\t\talign = (size_t) 1 << (kind >> rshift);\n+\t\ttgt_size = (tgt_size + align - 1) & ~(align - 1);\n+\t\ttgt->list[i].offset = tgt_size;\n+\n+\t\tvoid *descr_ptr = hostaddrs[i];\n+\t\tvoid *devaddr = (void *) (tgt->tgt_start + tgt_size);\n+\t\tuintptr_t dev_allocator\n+\t\t = gomp_map_omp_init_allocator (devicep, aq, cbufp, devaddr,\n+\t\t\t\t\t\t descr_ptr);\n+\t\thostaddrs[i] = (void *) dev_allocator;\n+\t\ttgt_size += gomp_omp_allocator_data_size;\n+\t\tcontinue;\n+\n \t case GOMP_MAP_STRUCT_UNORD:\n \t\tif (sizes[i] > 1)\n \t\t {\n@@ -3116,6 +3148,14 @@ calculate_firstprivate_requirements (size_t mapnum, size_t *sizes,\n \t*tgt_size = (*tgt_size + align - 1) & ~(align - 1);\n \t*tgt_size += sizes[i];\n }\n+ else if ((kinds[i] & 0xff) == GOMP_MAP_USES_ALLOCATORS)\n+ {\n+\tsize_t align = (size_t) 1 << (kinds[i] >> 8);\n+\tif (*tgt_align < align)\n+\t *tgt_align = align;\n+\t*tgt_size = (*tgt_size + align - 1) & ~(align - 1);\n+\t*tgt_size += gomp_omp_allocator_data_size;\n+ }\n }\n \n /* Copy data shared as GOMP_MAP_FIRSTPRIVATE to DST. */\n@@ -3138,12 +3178,23 @@ copy_firstprivate_data (char *tgt, size_t mapnum, void **hostaddrs,\n \tmemcpy (tgt + tgt_size, hostaddrs[i], sizes[i]);\n \thostaddrs[i] = tgt + tgt_size;\n \ttgt_size = tgt_size + sizes[i];\n-\tif (i + 1 < mapnum && (kinds[i+1] & 0xff) == GOMP_MAP_ATTACH)\n+\tif (i + 1 < mapnum && (kinds[i + 1] & 0xff) == GOMP_MAP_ATTACH)\n \t {\n-\t *(*(uintptr_t**) hostaddrs[i+1] + sizes[i+1]) = (uintptr_t) hostaddrs[i];\n+\t *(*(uintptr_t**) hostaddrs[i + 1] + sizes[i + 1])\n+\t = (uintptr_t) hostaddrs[i];\n \t ++i;\n \t }\n }\n+ else if ((kinds[i] & 0xff) == GOMP_MAP_USES_ALLOCATORS)\n+ {\n+\tassert (hostaddrs[i] != NULL);\n+\tsize_t align = (size_t) 1 << (kinds[i] >> 8);\n+\ttgt_size = (tgt_size + align - 1) & ~(align - 1);\n+\tuintptr_t allocator = gomp_map_omp_init_allocator (NULL, NULL, NULL,\n+\t\t\t\t\t\t\t tgt + tgt_size,\n+\t\t\t\t\t\t\t hostaddrs[i]);\n+\thostaddrs[i] = (void *) allocator;\n+ }\n }\n \n /* Helper function of GOMP_target{,_ext} routines. */\n@@ -6056,6 +6107,7 @@ gomp_load_plugin_for_device (struct gomp_device_descr *device,\n DLSYM (host2dev);\n DLSYM_OPT (memcpy2d, memcpy2d);\n DLSYM_OPT (memcpy3d, memcpy3d);\n+ DLSYM_OPT (memspace_validate, memspace_validate);\n if (DLSYM_OPT (interop, interop))\n {\n DLSYM (get_interop_int);\n", "prefixes": [ "OpenMP", "v2" ] }